/** * Remove the targets and rules defined by {@code path} from the cache and recursively remove the * targets and rules defined by files that transitively include {@code path} from the cache. * * @param path The File that has changed. */ private synchronized void invalidateDependents(Path path) { // Normalize path to ensure it hashes equally with map keys. path = normalize(path); if (parsedBuildFiles.containsKey(path)) { if (console.getVerbosity() == Verbosity.ALL) { console.getStdErr().printf("Parser invalidating %s cache\n", path.toAbsolutePath()); } // Remove all targets defined by path from cache. for (Map<String, Object> rawRule : parsedBuildFiles.get(path)) { BuildTarget target = parseBuildTargetFromRawRule(rawRule); knownBuildTargets.remove(target); } // Remove all rules defined in path from cache. parsedBuildFiles.removeAll(path); // All targets have no longer been parsed and cached. allBuildFilesParsed = false; } // Recursively invalidate dependents. for (Path dependent : buildFileDependents.get(path)) { if (!dependent.equals(path)) { invalidateDependents(dependent); } } // Dependencies will be repopulated when files are re-parsed. buildFileDependents.removeAll(path); }
/** * Finds the build file responsible for the given {@link Path} and invalidates all of the cached * rules dependent on it. * * @param path A {@link Path} "contained" within the build file to find and invalidate. */ private void invalidateContainingBuildFile(Path path) throws IOException { String packageBuildFilePath = buildFileTreeCache .getInput() .getBasePathOfAncestorTarget( projectFilesystem.getProjectRoot().toPath().relativize(path).toString()); invalidateDependents( projectFilesystem .getFileForRelativePath(packageBuildFilePath + '/' + BuckConstant.BUILD_RULES_FILE_NAME) .toPath()); }
/** * Called when file change events are posted to the file change EventBus to invalidate cached * build rules if required. */ @Subscribe public synchronized void onFileSystemChange(WatchEvent<?> event) throws IOException { if (console.getVerbosity() == Verbosity.ALL) { console .getStdErr() .printf( "Parser watched event %s %s\n", event.kind(), projectFilesystem.createContextString(event)); } if (projectFilesystem.isPathChangeEvent(event)) { Path path = (Path) event.context(); if (isPathCreateOrDeleteEvent(event)) { if (path.endsWith(BuckConstant.BUILD_RULES_FILE_NAME)) { // If a build file has been added or removed, reconstruct the build file tree. buildFileTreeCache.invalidate(); } // Added or removed files can affect globs, so invalidate the package build file // "containing" {@code path} unless its filename matches a temp file pattern. if (!isTempFile(path)) { invalidateContainingBuildFile(path); } } // Invalidate the raw rules and targets dependent on this file. invalidateDependents(path); } else { // Non-path change event, likely an overflow due to many change events: invalidate everything. buildFileTreeCache.invalidate(); invalidateCache(); } }