@Override public void onTextAvailable(ProcessEvent event, Key outputType) { if (outputType == ProcessOutputTypes.STDERR) { LOG.warn(event.getText().trim()); } if (outputType != ProcessOutputTypes.STDOUT) { return; } final String line = event.getText().trim(); if (LOG.isDebugEnabled()) { LOG.debug(">> " + line); } if (myLastOp == null) { final WatcherOp watcherOp; try { watcherOp = WatcherOp.valueOf(line); } catch (IllegalArgumentException e) { LOG.error("Illegal watcher command: " + line); return; } if (watcherOp == WatcherOp.GIVEUP) { notifyOnFailure(ApplicationBundle.message("watcher.gave.up"), null); myIsShuttingDown = true; } else if (watcherOp == WatcherOp.RESET) { reset(); } else { myLastOp = watcherOp; } } else if (myLastOp == WatcherOp.MESSAGE) { notifyOnFailure(line, NotificationListener.URL_OPENING_LISTENER); myLastOp = null; } else if (myLastOp == WatcherOp.REMAP || myLastOp == WatcherOp.UNWATCHEABLE) { if ("#".equals(line)) { if (myLastOp == WatcherOp.REMAP) { processRemap(); } else { mySettingRoots.decrementAndGet(); processUnwatchable(); } myLines.clear(); myLastOp = null; } else { myLines.add(line); } } else { String path = line.replace('\0', '\n'); // unescape processChange(path, myLastOp); myLastOp = null; } }
@Override public void processTerminated(ProcessEvent event) { LOG.warn("Watcher terminated with exit code " + event.getExitCode()); myProcessHandler = null; try { startupProcess(true); } catch (IOException e) { shutdownProcess(); LOG.warn( "Watcher terminated and attempt to restart has failed. Exiting watching thread.", e); } }
private void processChange(String path, WatcherOp op) { if (SystemInfo.isWindows && op == WatcherOp.RECDIRTY && path.length() == 3 && Character.isLetter(path.charAt(0))) { VirtualFile root = LocalFileSystem.getInstance().findFileByPath(path); if (root != null) { myNotificationSink.notifyPathsRecursive(list(root.getPresentableUrl())); } notifyOnAnyEvent(); return; } if (op == WatcherOp.CHANGE) { // collapse subsequent change file change notifications that happen once we copy large file, // this allows reduction of path checks at least 20% for Windows synchronized (myLock) { for (int i = 0; i < myLastChangedPaths.length; ++i) { int last = myLastChangedPathIndex - i - 1; if (last < 0) last += myLastChangedPaths.length; String lastChangedPath = myLastChangedPaths[last]; if (lastChangedPath != null && lastChangedPath.equals(path)) { return; } } myLastChangedPaths[myLastChangedPathIndex++] = path; if (myLastChangedPathIndex == myLastChangedPaths.length) myLastChangedPathIndex = 0; } } int length = path.length(); if (length > 1 && path.charAt(length - 1) == '/') path = path.substring(0, length - 1); boolean exactPath = op != WatcherOp.DIRTY && op != WatcherOp.RECDIRTY; Collection<String> paths = checkWatchable(path, exactPath, false); if (paths.isEmpty()) { if (LOG.isDebugEnabled()) { LOG.debug("Not watchable, filtered: " + path); } return; } switch (op) { case STATS: case CHANGE: myNotificationSink.notifyDirtyPaths(paths); break; case CREATE: case DELETE: myNotificationSink.notifyPathsCreatedOrDeleted(paths); break; case DIRTY: myNotificationSink.notifyDirtyDirectories(paths); break; case RECDIRTY: myNotificationSink.notifyPathsRecursive(paths); break; default: LOG.error("Unexpected op: " + op); } notifyOnAnyEvent(); }