grunt plugin to refresh eclipse java project

孤者浪人 提交于 2019-12-10 16:02:51

问题


Background:

I have a java project that uses lesscss. I am using grunt with grunt-contrib-watch and grunt-contrib-less to compile my.lessfiles to.css`.

It all works nicely.

The issue is that to get the eclipse tomcat server to start serving the updated .css files I need to refresh the project in eclipse.

I was wandering if there is a way to force eclipse to refresh as part of the watch cycle in grunt ? or actually, is there a way to cause the currently open eclipse project ( given that I know its path if it helps ) to refresh using grunt.

Connecting it to the watch cycle is not hard and can be probably done by changing my Gruntfile.js from:

    watch: {
        styles: {
            // Which files to watch (all .less files recursively in the less directory)
            files: ['../WebContent/less/**/*.less'],
            tasks: ['less'],
            options: {
              nospawn: true
            }
        },

to:

    watch: {
        styles: {
            // Which files to watch (all .less files recursively in the less directory)
            files: ['../WebContent/less/**/*.less'],
            tasks: ['less','updateEclipseTask'],
            options: {
              nospawn: true
            }
        },

回答1:


Try enabling Preferences > General > Workspace > Refresh using native hooks or polling. Depending on what OS you're using it will refresh more or less quickly. It's not exactly what you want but it might solve the problem.

Another option that I haven't tried myself but that looks like it could be made to work is to use eclipse-remote-control to trigger an external command you have set up in Eclipse (Run > External Tools > External Tools Configurations...), if you create a new "Program" configuration there you can in the "Refresh" tab set Eclipse to refresh the workspace when that external tool config is executed.

To run eclipse-remote-control from grunt you could use grunt-shell.




回答2:


I recently became fed up with waiting for Eclipse to refresh files and folders that were changing due to Grunt tasks running outside of Eclipse.

I ended up writing my own plugin for Eclipse that would speed up the refresh interval so that external filesystem changes would be detected and the Tomcat instances running in Eclipse would serve those changes almost instantaneously.

While it is true that you can enable the setting 'Refresh using native hooks and polling', I found that file changes still took too long to appear in Eclipse and newly created files still required manual refreshing.

Here are the details and code, so that you can do something like this for yourself.

Overview

  1. First, create a new Eclipse plugin project within Eclipse. I named mine RapidFileRefresher.
  2. Modify or create all of the files below.
  3. Customize the files below to track the projects you want (by adding your project names to PROJECT_NAMES in RapidRefreshProvider) and the folders your want to monitor by adding the folder names to FOLDERS in ProjectMonitorJob.
  4. Double click Manifest.MF, open the overview tab, and click "Export Wizard". Click "Install into host repository" and select a folder to server as the host repository. I don't think the folder matters.
  5. Click Finish. Eclipse should automatically install the local plugin.
  6. Make sure that your have the "Refresh using native hooks or polling" setting enabled under Settings > General > Workspace

To make changes to the plugin, uninstall it by going to Help > About Eclipse, click "Installation details", search for the plugin under "Installed Software", uninstall it, make the code changes, and then re-export it using the steps above.

Essentially what the code below does is:

  1. Uses the RefreshProvider extension point to register a new refresh provider (RapidRefreshProvider) for all of the desired projects in the workspace
  2. Create a new RefreshMonitor for each desired project
  3. Create a Job that runs every 350ms (this value can be changed) to loop through all of the resources in the specified folders, until a resource that is out of sync is discovered. Said resource is then refreshed.

I created this plugin for myself for a very specific use-case, so please keep that in mind.

Update

I threw all of the code below into a Github repo: https://github.com/peterjkirby/RapidFileRefreshPlugin

Results

After grunt tasks run and modify my filesystem (whether it be creating, updating, or deleting files), the changes are reflected in Eclipse within in under a second. The updates resources are served by the Tomcat instance I have running through Eclipse usually in under a second.

Files

Manifest.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: RapidFileRefresher
Bundle-SymbolicName: rfr.RapidFileRefresher;singleton:=true
Bundle-Version: 1.0.2
Bundle-Activator: rfr.core.Activator
Require-Bundle: org.eclipse.core.runtime
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Import-Package: org.eclipse.core.internal.refresh,
 org.eclipse.core.internal.resources.mapping,
 org.eclipse.core.resources,
 org.eclipse.core.resources.refresh
Bundle-Vendor: PeterKirby
Export-Package: rfr.core

plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         id="RapidFileRefresher"
         point="org.eclipse.core.resources.refreshProviders">
      <refreshProvider
            class="rfr.core.RapidFileRefresher"
            name="RapidFileRefresher">
      </refreshProvider>   </extension>

</plugin>

Activator.java

public class Activator extends Plugin {

    private static Activator INSTANCE;

    public static final String PLUGIN_ID = "RapidFileRefresher";

    public Activator() {
        super();
        INSTANCE = this;
    }

    public static Activator getInstance() {
        return INSTANCE;
    }

    @Override
    public void start(BundleContext context) throws Exception {
        super.start(context);
    }

    @Override
    public void stop(BundleContext context) throws Exception {
        super.stop(context);
    }

}

RapidRefreshProvider.java

public class RapidRefreshProvider extends RefreshProvider {

    private static final String[] PROJECTS_NAMES = {
        "YOUR_PROJECT_NAMES"
    };

    private Set<String> projects = new HashSet<>();

    public RapidRefreshProvider() {
        projects.addAll(Arrays.asList(PROJECTS_NAMES));
    }


    @Override
    public IRefreshMonitor installMonitor(IResource resource, IRefreshResult result) {

        // only monitor resources that are projects
        if (resource.getType() != IResource.PROJECT) return null;

        IProject project = (IProject) resource;

        // only monitor the projects in PROJECT_NAMES
        if (!projects.contains(project.getName())) return null; 

        RapidRefreshMonitor monitor = new RapidRefreshMonitor(resource, result);
        monitor.start();

        return monitor;
    }

}

RapidRefreshMonitor.java

public class RapidRefreshMonitor implements IRefreshMonitor {

    // wait INITIAL_DELAY seconds before starting to track changes 
    // in order to allow eclipse to startup faster.
    private static final int INITIAL_DELAY = 1000 * 20;
    private ProjectMonitorJob job;
    private IResource resource;
    private IRefreshResult result;

    public RapidRefreshMonitor(IResource resource, IRefreshResult result) {
        this.resource = resource;
        this.result = result;       
    }

    public void start() {
        job = new ProjectMonitorJob(resource, result);
        job.schedule(INITIAL_DELAY);
    }


    @Override
    public void unmonitor(IResource resource) {
        job.stop();     
    }

}

ProjectMonitorJob.java

public class ProjectMonitorJob extends Job {

    private static final String JOB_NAME = "ProjectMonitorJob";
    private static final String[] FOLDERS = {
            "src/main/webapp/resources"
    };
    // fires about 3 times per second.
    private static final int DELAY = 350;
    private boolean RUNNING = true;

    private IResource resource;
    private IRefreshResult result;

    public ProjectMonitorJob(IResource resource, IRefreshResult result) {
        super(Activator.PLUGIN_ID + " - " + JOB_NAME);
        this.resource = resource;
        this.result = result;

    }

    @Override
    protected IStatus run(IProgressMonitor monitor) {

        if (RUNNING) {

            IProject project = (IProject) resource;

            for (String folderPath : FOLDERS) {
                monitor(project, folderPath);
            }

            // schedule the next run
            schedule(DELAY);
        }

        return Status.OK_STATUS;
    }

    private void monitor(IProject project, String folderPath) {
        IFolder folder = project.getFolder(new Path(folderPath));

        if (folder.exists()) {
            ResourceTraverser traverser = new ResourceTraverser(new ResourceChangeEvaluator());

            try {
                traverser.traverse(folder, result);
            } catch (CoreException e) {}
        }
    }

    public void stop() {
        RUNNING = false;
    }

}

ResourceChangeEvaluator.java

public class ResourceChangeEvaluator {

    public ResourceChangeEvaluator() {}     

    public boolean changed(IFolder folder) {
        if (folder == null) return false;
        return !folder.isSynchronized(IResource.DEPTH_ONE);
    }

    public boolean changed(IFile file) throws CoreException {
        if (file == null) return false;
        if (!file.exists()) return false;
        if (file.isSynchronized(IResource.DEPTH_ZERO)) return false;

        return true;
    }

}

ResourceTraverser.java

public class ResourceTraverser {

    private ResourceChangeEvaluator resourceChangeEvaluator;

    public ResourceTraverser(ResourceChangeEvaluator resourceChangeEvaluator) {
        this.resourceChangeEvaluator = resourceChangeEvaluator;
    }

    public void traverse(IFolder folder, IRefreshResult refreshResult) throws CoreException {

        IResource[] contents = folder.members();
        Activator activator = Activator.getInstance();

        if (resourceChangeEvaluator.changed(folder)) {
            refreshResult.refresh(folder);
        }

        for (IResource resource : contents) {                                   
            if (resource.getType() == IResource.FILE) {
                IFile file = (IFile) resource;              

                    if (resourceChangeEvaluator.changed(file)) {
                        refreshResult.refresh(file);
                        activator.getLog().log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "File change detected. Refreshing " + file.getName()));
                    }


            } else if (resource.getType() == IResource.FOLDER) {
                IFolder subfolder = (IFolder) resource;

                // only continue traversing if a folder has not changed. If a folder has changed
                // the refresh event at that folder should be enough to force synchronization 
                // Plus, other changes at a depth > 1 will be detected on the next pass.
                // This is more a performance optimization than anything else. 
                if (resourceChangeEvaluator.changed(subfolder)) {
                    refreshResult.refresh(subfolder);
                    activator.getLog().log(new Status(IStatus.INFO, Activator.PLUGIN_ID, "Folder change detected. Refreshing " + subfolder.getName()));
                } else {
                    traverse((IFolder) resource, refreshResult);
                }
            }
        }
    }

}


来源:https://stackoverflow.com/questions/22129029/grunt-plugin-to-refresh-eclipse-java-project

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!