@Override public ListenableFuture<Map<String, Object>> getNodeJob( final Cell cell, final BuildTarget buildTarget) throws BuildTargetException { return Futures.transformAsync( getAllNodesJob(cell, cell.getAbsolutePathToBuildFile(buildTarget)), input -> { for (Map<String, Object> rawNode : input) { Object shortName = rawNode.get("name"); if (buildTarget.getShortName().equals(shortName)) { return Futures.immediateFuture(rawNode); } } throw NoSuchBuildTargetException.createForMissingBuildRule( buildTarget, BuildTargetPatternParser.forBaseName(buildTarget.getBaseName()), cell.getBuildFileName(), "Defined in file: " + cell.getAbsolutePathToBuildFile(buildTarget)); }, executorService); }
/** * @param buildTargetName either a fully-qualified name or relative to the {@link ParseContext}. * For example, inside {@code first-party/orca/orcaapp/BUILD}, which can be obtained by * calling {@code ParseContext.forBaseName("first-party/orca/orcaapp")}, {@code * //first-party/orca/orcaapp:assets} and {@code :assets} refer to the same target. However, * from the command line the context is obtained by calling {@link * ParseContext#fullyQualified()} and relative names are not recognized. * @param parseContext how targets should be interpreted, such in the context of a specific build * file or only as fully-qualified names (as is the case for targets from the command line). */ public BuildTarget parse(String buildTargetName, ParseContext parseContext) throws NoSuchBuildTargetException { Preconditions.checkNotNull(buildTargetName); Preconditions.checkNotNull(parseContext); for (String invalidSubstring : INVALID_BUILD_RULE_SUBSTRINGS) { if (buildTargetName.contains(invalidSubstring)) { throw new BuildTargetParseException( String.format("%s cannot contain %s", buildTargetName, invalidSubstring)); } } if (buildTargetName.endsWith(BUILD_RULE_SEPARATOR) && parseContext.getType() != ParseContext.Type.VISIBILITY) { throw new BuildTargetParseException( String.format("%s cannot end with a colon", buildTargetName)); } List<String> parts = ImmutableList.copyOf(BUILD_RULE_SEPARATOR_SPLITTER.split(buildTargetName)); if (parts.size() != 2) { throw new BuildTargetParseException( String.format( "%s must contain exactly one colon (found %d)", buildTargetName, parts.size() - 1)); } String baseName = parts.get(0).isEmpty() ? parseContext.getBaseName() : parts.get(0); String shortName = parts.get(1); String fullyQualifiedName = String.format("%s:%s", baseName, shortName); if (!fullyQualifiedName.startsWith(BUILD_RULE_PREFIX)) { throw new BuildTargetParseException( String.format("%s must start with %s", fullyQualifiedName, BUILD_RULE_PREFIX)); } // Make sure the directory that contains the build file exists. String buildFileDirectory = baseName.substring(BUILD_RULE_PREFIX.length()); String buildFilePath = (buildFileDirectory.isEmpty() ? "" : buildFileDirectory + "/") + BUILD_RULES_FILE_NAME; if (!projectFilesystem.exists(buildFileDirectory)) { if (parseContext.getType() == ParseContext.Type.BUILD_FILE && baseName.equals(parseContext.getBaseName())) { throw new BuildTargetParseException( String.format( "Internal error: Parsing in the context of %s, but %s does not exist", buildFilePath, buildFileDirectory)); } else { throw NoSuchBuildTargetException.createForMissingDirectory( buildFileDirectory, buildTargetName, parseContext); } } // Make sure the build file exists. if (!projectFilesystem.exists(buildFilePath)) { if (parseContext.getType() == ParseContext.Type.BUILD_FILE && baseName.equals(parseContext.getBaseName())) { throw new BuildTargetParseException( String.format( "Internal error: Parsing in the context of %s, but %s does not exist", buildFilePath, buildFilePath)); } else { throw NoSuchBuildTargetException.createForMissingBuildFile( buildFilePath, buildTargetName, parseContext); } } return new BuildTarget(baseName, shortName); }