private ProjectFilesystem( FileSystem vfs, final Path root, Optional<ImmutableSet<Path>> whiteListedPaths, ImmutableSet<PathOrGlobMatcher> blackListedPaths) { Preconditions.checkArgument(Files.isDirectory(root)); Preconditions.checkState(vfs.equals(root.getFileSystem())); Preconditions.checkArgument(root.isAbsolute()); this.projectRoot = root.normalize(); this.pathAbsolutifier = new Function<Path, Path>() { @Override public Path apply(Path path) { return resolve(path); } }; this.pathRelativizer = new Function<Path, Path>() { @Override public Path apply(Path input) { return projectRoot.relativize(input); } }; this.whiteListedPaths = whiteListedPaths.transform( new Function<ImmutableSet<Path>, ImmutableSet<Path>>() { @Override public ImmutableSet<Path> apply(ImmutableSet<Path> input) { return MorePaths.filterForSubpaths(input, ProjectFilesystem.this.projectRoot); } }); this.ignoreValidityOfPaths = false; this.blackListedPaths = blackListedPaths; this.blackListedDirectories = FluentIterable.from(this.blackListedPaths) .filter( new Predicate<PathOrGlobMatcher>() { @Override public boolean apply(PathOrGlobMatcher matcher) { return matcher.getType() == PathOrGlobMatcher.Type.PATH; } }) .transform( new Function<PathOrGlobMatcher, Path>() { @Override public Path apply(PathOrGlobMatcher matcher) { Path path = matcher.getPath(); ImmutableSet<Path> filtered = MorePaths.filterForSubpaths(ImmutableSet.<Path>of(path), root); if (filtered.isEmpty()) { return path; } return Iterables.getOnlyElement(filtered); } }) // So we claim to ignore this path to preserve existing behaviour .append(root.getFileSystem().getPath(BuckConstant.BUCK_OUTPUT_DIRECTORY)) // "Path" is Iterable, so avoid adding each segment. // We use the default value here because that's what we've always done. .append(ImmutableSet.of(getCacheDir(root, Optional.of(BuckConstant.DEFAULT_CACHE_DIR)))) .toSortedSet(Ordering.<Path>natural()); }