static OwnersReport buildOwnersReport( CommandRunnerParams params, ParserConfig parserConfig, BuildFileTree buildFileTree, Iterable<String> arguments, boolean guessForDeletedEnabled) throws IOException, InterruptedException, BuildFileParseException, BuildTargetException { final Path rootPath = params.getCell().getFilesystem().getRootPath(); Preconditions.checkState(rootPath.isAbsolute()); Map<Path, List<TargetNode<?>>> targetNodes = Maps.newHashMap(); OwnersReport report = OwnersReport.emptyReport(); for (Path filePath : getArgumentsAsPaths(rootPath, arguments)) { Optional<Path> basePath = buildFileTree.getBasePathOfAncestorTarget(filePath); if (!basePath.isPresent()) { report = report.updatedWith( new OwnersReport( ImmutableSetMultimap.<TargetNode<?>, Path>of(), /* inputWithNoOwners */ ImmutableSet.of(filePath), Sets.<String>newHashSet(), Sets.<String>newHashSet())); continue; } Path buckFile = basePath.get().resolve(parserConfig.getBuildFileName()); Preconditions.checkState(params.getCell().getFilesystem().exists(buckFile)); // Parse buck files and load target nodes. if (!targetNodes.containsKey(buckFile)) { try { targetNodes.put( buckFile, params .getParser() .getOrLoadTargetNodes( buckFile, parserConfig, params.getBuckEventBus(), params.getConsole(), params.getEnvironment())); } catch (BuildFileParseException | BuildTargetException e) { Path targetBasePath = MorePaths.relativize(rootPath, rootPath.resolve(basePath.get())); String targetBaseName = "//" + MorePaths.pathWithUnixSeparators(targetBasePath); params .getConsole() .getStdErr() .format("Could not parse build targets for %s", targetBaseName); throw e; } } for (TargetNode<?> targetNode : targetNodes.get(buckFile)) { report = report.updatedWith( generateOwnersReport( params, targetNode, ImmutableList.of(filePath.toString()), guessForDeletedEnabled)); } } return report; }
@VisibleForTesting static String createQuery( ObjectMapper objectMapper, String watchRoot, Optional<String> watchPrefix, String uuid, Iterable<Path> ignorePaths, Iterable<String> ignoreGlobs, Set<Capability> watchmanCapabilities) { List<Object> queryParams = new ArrayList<>(); queryParams.add("query"); queryParams.add(watchRoot); // Note that we use LinkedHashMap so insertion order is preserved. That // helps us write tests that don't depend on the undefined order of HashMap. Map<String, Object> sinceParams = new LinkedHashMap<>(); sinceParams.put("since", new StringBuilder("n:buckd").append(uuid).toString()); // Exclude any expressions added to this list. List<Object> excludeAnyOf = Lists.<Object>newArrayList("anyof"); // Exclude all directories. excludeAnyOf.add(Lists.newArrayList("type", "d")); Path projectRoot = Paths.get(watchRoot); if (watchPrefix.isPresent()) { projectRoot = projectRoot.resolve(watchPrefix.get()); } // Exclude all files under directories in project.ignorePaths. // // Note that it's OK to exclude .git in a query (event though it's // not currently OK to exclude .git in .watchmanconfig). This id // because watchman's .git cookie magic is done before the query // is applied. for (Path ignorePath : ignorePaths) { if (ignorePath.isAbsolute()) { ignorePath = MorePaths.relativize(projectRoot, ignorePath); } if (watchmanCapabilities.contains(Capability.DIRNAME)) { excludeAnyOf.add(Lists.newArrayList("dirname", ignorePath.toString())); } else { excludeAnyOf.add(Lists.newArrayList("match", ignorePath.toString() + "/*", "wholename")); } } // Exclude all filenames matching globs. We explicitly don't match // against the full path ("wholename"), just the filename. for (String ignoreGlob : ignoreGlobs) { excludeAnyOf.add(Lists.newArrayList("match", ignoreGlob)); } sinceParams.put("expression", Lists.newArrayList("not", excludeAnyOf)); sinceParams.put("empty_on_fresh_instance", true); sinceParams.put("fields", Lists.newArrayList("name", "exists", "new")); if (watchPrefix.isPresent()) { sinceParams.put("relative_root", watchPrefix.get()); } queryParams.add(sinceParams); try { return objectMapper.writeValueAsString(queryParams); } catch (IOException e) { throw Throwables.propagate(e); } }