BulkFileListener behavior with out of process files

Answered

I've implemented the BulkFileListener and am listening to VirtualFileManager.VFS_CHANGES in order to pick up changed files and upload them to a WebDav server. This approach has worked well for files that have been edited in the IDE. However, this approach does not seem to pick up files that were modified in a separate process (gulp, webpack) until you tab away from the IDE to another application and back. This seems to refresh the file system and the files that were created in the separate process are now found and uploaded.

Is there a way to capture the changes of these files that are created in a separate process without having to trigger a virtual file system refresh? Or another listener I could use that would make more sense to want all the project files for changes?

package com.binarysushi.studio.webdav;

import com.binarysushi.studio.configuration.StudioConfigurationProvider;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.PerformInBackgroundOption;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NotNull;

import java.util.List;

public class StudioBulkFileListener implements BulkFileListener, Disposable {
    private MessageBusConnection connection;
    private static Logger LOG = Logger.getInstance(StudioBulkFileListener.class);

    public StudioBulkFileListener() {
        connection = ApplicationManager.getApplication().getMessageBus().connect();
        connection.subscribe(VirtualFileManager.VFS_CHANGES, this);
    }

    @Override
    public void dispose() {
        connection.disconnect();
    }

    @NotNull
    public String getComponentName() {
        return "StudioBulkFileListener";
    }

    @Override
    public void before(@NotNull List<? extends VFileEvent> events) {
    }

    @Override
    public void after(@NotNull List<? extends VFileEvent> events) {
        Project[] projects = ProjectManager.getInstance().getOpenProjects();

        for (VFileEvent event : events) {
            VirtualFile eventFile = event.getFile();

            if (eventFile != null && !eventFile.isDirectory()) {
                for (Project project : projects) {
                    StudioConfigurationProvider configurationProvider = StudioConfigurationProvider.getInstance(project);

                    // Bail out if auto uploads are not enabled.
                    if (!StudioConfigurationProvider.getInstance(project).getAutoUploadEnabled()) {
                        return;
                    }

                    if (configurationProvider.getCartridgeRoots().size() < 1) {
                        return;
                    }

                    for (String cartridgeRoot : configurationProvider.getCartridgeRoots()) {
                        if (eventFile.getPath().contains(cartridgeRoot)) {
                            ProgressManager.getInstance().run(
                                    new StudioUpdateFileTask(
                                            project,
                                            "Syncing files to: " + StudioConfigurationProvider.getInstance(project).getHostname(),
                                            true,
                                            PerformInBackgroundOption.ALWAYS_BACKGROUND,
                                            cartridgeRoot,
                                            eventFile.getPath()
                                    )
                            );
                        }
                    }
                }
            }
        }
    }
}
4 comments
Comment actions Permalink

You'll need to refresh VFS with any "outside" changes as described here http://www.jetbrains.org/intellij/sdk/docs/basics/virtual_file_system.html

0
Comment actions Permalink

Hi Yann,

 

Thanks for the help. That makes sense I'm just not 100% sure how to go about that. I had actually read through that doc first before posting, however I'm not sure how I could watch a sub process without polling the filesystem in some way.

 

This particular section says there is a native file watcher created. Why would this not pick up on changes in the project directory?

 

"On Windows, Mac and Linux, IntelliJ Platform starts a native file watcher process that receives file change notifications from the file system and reports them to IntelliJ Platform. If a file watcher is available, a refresh operation looks only at the files that have been reported as changed by the file watcher. If no file watcher is present, a refresh operation walks through all directories and files in the refresh scope."

 

0
Comment actions Permalink

Please try using com.intellij.openapi.vfs.VfsUtil#markDirtyAndRefresh

1
Comment actions Permalink

Did you find a way to ignore those false positives from a linter or external tools? I ran into this one as well. Intellij XML linter seems to be triggering a subsequent write to remove single empty spaces. At first, I thought my implementation was incorrect, until I read this. Thanks!

0

Please sign in to leave a comment.