下面列出了com.google.common.collect.ImmutableSortedMap#get ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Create a progress message for the ninja action.
*
* <ul>
* <li>If the target has a "description" variable, use that. It has been expanded at parse time
* with file variables.
* <li>If the rule for the target has a description, use that. It has been expanded with rule,
* build and file variables.
* <li>Else, generate a pretty-printed progress message at runtime, using the rule name and
* output filenames for a general idea on what the action is doing, without printing the
* full command line (which can be surfaced with --subcommands, anyway).
*/
private static String createProgressMessage(
NinjaTarget target,
ImmutableSortedMap<NinjaRuleVariable, String> ruleVariables,
List<Artifact> outputs) {
String ruleDescription = ruleVariables.get(NinjaRuleVariable.DESCRIPTION);
if (ruleDescription != null) {
return ruleDescription;
}
String ruleName = target.getRuleName();
StringBuilder messageBuilder = new StringBuilder();
if (!ruleName.isEmpty()) {
messageBuilder.append("[rule ").append(ruleName).append("] ");
}
messageBuilder.append("Outputs: ");
messageBuilder.append(outputs.stream().map(Artifact::getFilename).collect(joining(", ")));
return messageBuilder.toString();
}
/**
* Convert {@link SourcePath} to a mapping of {@code include path -> file path}.
*
* <p>{@code include path} is the path that can be referenced in {@code #include} directives.
* {@code file path} is the actual path to the file on disk.
*
* @throws HumanReadableException when two {@code SourcePath} yields the same IncludePath.
*/
@VisibleForTesting
static ImmutableSortedMap<String, SourcePath> convertToFlatCxxHeaders(
BuildTarget buildTarget,
Path headerPathPrefix,
Function<SourcePath, Path> sourcePathResolver,
Set<SourcePath> headerPaths) {
Set<String> includeToFile = new HashSet<String>(headerPaths.size());
ImmutableSortedMap.Builder<String, SourcePath> builder = ImmutableSortedMap.naturalOrder();
for (SourcePath headerPath : headerPaths) {
Path fileName = sourcePathResolver.apply(headerPath).getFileName();
String key = headerPathPrefix.resolve(fileName).toString();
if (includeToFile.contains(key)) {
ImmutableSortedMap<String, SourcePath> result = builder.build();
throw new HumanReadableException(
"In target '%s', '%s' maps to the following header files:\n"
+ "- %s\n"
+ "- %s\n\n"
+ "Please rename one of them or export one of them to a different path.",
buildTarget, key, headerPath, result.get(key));
}
includeToFile.add(key);
builder.put(key, headerPath);
}
return builder.build();
}
public CommandAlias(
BuildTarget buildTarget,
ProjectFilesystem projectFilesystem,
Optional<BuildRule> genericDelegate,
ImmutableSortedMap<Platform, BuildRule> platformDelegates,
ImmutableList<Arg> args,
ImmutableSortedMap<String, Arg> env,
Platform platform) {
super(buildTarget, projectFilesystem);
this.genericDelegate = genericDelegate;
this.platformDelegates = platformDelegates;
this.args = args;
this.env = env;
this.platform = platform;
BuildRule exe = platformDelegates.get(platform);
this.exe = exe != null ? exe : genericDelegate.orElse(null);
}
/**
* We expand the rule's variables with the following assumptions: Rule variables can refer to
* target's variables (and file variables). Interdependence between rule variables can happen
* only for 'command' variable, for now we ignore other possible dependencies between rule
* variables (seems the only other variable which can meaningfully depend on sibling variables
* is description, and currently we are ignoring it).
*
* <p>Also, for resolving rule's variables we are using scope+offset of target, according to
* specification (https://ninja-build.org/manual.html#_variable_expansion).
*
* <p>See {@link NinjaRuleVariable} for the list.
*/
private static ImmutableSortedMap<NinjaRuleVariable, NinjaVariableValue> reduceRuleVariables(
NinjaScope targetScope,
long targetOffset,
Map<NinjaRuleVariable, NinjaVariableValue> ruleVariables,
ImmutableSortedMap<String, String> targetVariables,
Interner<String> interner) {
ImmutableSortedMap.Builder<String, List<Pair<Long, String>>> variablesBuilder =
ImmutableSortedMap.naturalOrder();
targetVariables.forEach(
(key, value) -> variablesBuilder.put(key, ImmutableList.of(Pair.of(0L, value))));
NinjaScope scopeWithVariables =
targetScope.createScopeFromExpandedValues(variablesBuilder.build());
ImmutableSortedMap.Builder<NinjaRuleVariable, NinjaVariableValue> builder =
ImmutableSortedMap.naturalOrder();
// Description is taken from the "build" statement (instead of the referenced rule)
// if it's available.
boolean targetHasDescription = false;
String targetVariable = targetVariables.get("description");
if (targetVariable != null) {
builder.put(
NinjaRuleVariable.DESCRIPTION, NinjaVariableValue.createPlainText(targetVariable));
targetHasDescription = true;
}
for (Map.Entry<NinjaRuleVariable, NinjaVariableValue> entry : ruleVariables.entrySet()) {
NinjaRuleVariable type = entry.getKey();
if (type.equals(NinjaRuleVariable.DESCRIPTION) && targetHasDescription) {
// Don't use the rule description, as the target defined a specific description.
continue;
}
NinjaVariableValue reducedValue =
scopeWithVariables.getReducedValue(
targetOffset, entry.getValue(), INPUTS_OUTPUTS_VARIABLES, interner);
builder.put(type, reducedValue);
}
return builder.build();
}
private void createNinjaAction(NinjaTarget target) throws GenericParsingException {
NestedSetBuilder<Artifact> inputsBuilder = NestedSetBuilder.stableOrder();
NestedSetBuilder<Artifact> orderOnlyInputsBuilder = NestedSetBuilder.stableOrder();
ImmutableList.Builder<Artifact> outputsBuilder = ImmutableList.builder();
boolean isAlwaysDirty =
fillArtifacts(target, inputsBuilder, orderOnlyInputsBuilder, outputsBuilder);
ImmutableSortedMap<NinjaRuleVariable, String> resolvedMap = target.computeRuleVariables();
String command = resolvedMap.get(NinjaRuleVariable.COMMAND);
maybeCreateRspFile(target.getRuleName(), inputsBuilder, resolvedMap);
if (!artifactsHelper.getWorkingDirectory().isEmpty()) {
command = String.format("cd %s && ", artifactsHelper.getWorkingDirectory()) + command;
}
CommandLines commandLines =
CommandLines.of(ImmutableList.of(shellExecutable.getPathString(), "-c", command));
Artifact depFile = getDepfile(resolvedMap);
if (depFile != null) {
outputsBuilder.add(depFile);
}
List<Artifact> outputs = outputsBuilder.build();
ruleContext.registerAction(
new NinjaAction(
ruleContext.getActionOwner(),
artifactsHelper.getSourceRoot(),
NestedSetBuilder.emptySet(Order.STABLE_ORDER),
inputsBuilder.build(),
orderOnlyInputsBuilder.build(),
outputs,
commandLines,
Preconditions.checkNotNull(ruleContext.getConfiguration()).getActionEnvironment(),
executionInfo,
createProgressMessage(target, resolvedMap, outputs),
EmptyRunfilesSupplier.INSTANCE,
isAlwaysDirty,
depFile,
artifactsHelper.getDerivedOutputRoot()));
}
@Nullable
private Artifact getDepfile(ImmutableSortedMap<NinjaRuleVariable, String> ruleVariables)
throws GenericParsingException {
String depfileName = ruleVariables.get(NinjaRuleVariable.DEPFILE);
if (depfileName != null) {
if (!depfileName.trim().isEmpty()) {
return artifactsHelper.createOutputArtifact(PathFragment.create(depfileName));
}
}
return null;
}
private void maybeCreateRspFile(
String ruleName,
NestedSetBuilder<Artifact> inputsBuilder,
ImmutableSortedMap<NinjaRuleVariable, String> ruleVariables)
throws GenericParsingException {
String fileName = ruleVariables.get(NinjaRuleVariable.RSPFILE);
String contentString = ruleVariables.get(NinjaRuleVariable.RSPFILE_CONTENT);
if (fileName == null && contentString == null) {
return;
}
if (fileName == null || contentString == null) {
ruleContext.ruleError(
String.format(
"Both rspfile and rspfile_content should be defined for rule '%s'.", ruleName));
return;
}
if (!fileName.trim().isEmpty()) {
DerivedArtifact rspArtifact =
artifactsHelper.createOutputArtifact(PathFragment.create(fileName));
FileWriteAction fileWriteAction =
FileWriteAction.create(ruleContext, rspArtifact, contentString, false);
ruleContext.registerAction(fileWriteAction);
inputsBuilder.add(rspArtifact);
}
}
private static void checkMapping(
ImmutableSortedMap<PathFragment, PhonyTarget> pathsMap,
String key,
boolean isAlwaysDirty,
String... values) {
Set<PathFragment> expectedPaths =
Arrays.stream(values).map(PathFragment::create).collect(Collectors.toSet());
PhonyTarget phonyTarget = pathsMap.get(PathFragment.create(key));
assertThat(phonyTarget).isNotNull();
assertThat(phonyTarget.isAlwaysDirty()).isEqualTo(isAlwaysDirty);
ImmutableSortedSet.Builder<PathFragment> paths = ImmutableSortedSet.naturalOrder();
pathsMap.get(PathFragment.create(key)).visitExplicitInputs(pathsMap, paths::addAll);
assertThat(paths.build()).containsExactlyElementsIn(expectedPaths);
}
/**
* For the given phony NinjaTarget, return a list of all phony NinjaTargets, composing its subtree
* (direct and transitive inputs). The list is ordered from leaves to their dependents; for any
* node all its direct and transitive inputs are preceding it in the list.
*
* <p>Function does DFS starting from the NinjaTarget, with two phases: in initial processing: 1)
* if the target was already computed, nothing happens 2) the target is checked for cycle and
* marked in cycleProtection set, its phony inputs are queued (put in the beginning of the queue)
* for initial processing 3) the target is queued after its inputs for post-processing in
* post-processing, the target is recorded into resulting list; all its inputs should have been
* already written to that list on the previous steps
*/
private static List<NinjaTarget> topoOrderSubGraph(
ImmutableSortedMap<PathFragment, NinjaTarget> phonyTargets,
Set<NinjaTarget> alreadyVisited,
NinjaTarget target)
throws GenericParsingException {
Set<NinjaTarget> cycleProtection = Sets.newHashSet();
List<NinjaTarget> fragment = Lists.newArrayList();
ArrayDeque<Pair<NinjaTarget, Boolean>> queue = new ArrayDeque<>();
queue.add(Pair.of(target, true));
while (!queue.isEmpty()) {
Pair<NinjaTarget, Boolean> pair = queue.remove();
NinjaTarget currentTarget = pair.getFirst();
if (pair.getSecond()) {
// Initial processing: checking all the phony inputs of the current target.
if (alreadyVisited.contains(currentTarget)) {
continue;
}
if (!cycleProtection.add(currentTarget)) {
throw new GenericParsingException(
String.format(
"Detected a dependency cycle involving the phony target '%s'",
Iterables.getOnlyElement(currentTarget.getAllOutputs())));
}
// Adding <phony-inputs-of-current-target> for initial processing in front of
// <current-target>
// for post-processing into the queue.
queue.addFirst(Pair.of(currentTarget, false));
for (PathFragment input : currentTarget.getAllInputs()) {
NinjaTarget phonyInput = phonyTargets.get(input);
if (phonyInput != null) {
queue.addFirst(Pair.of(phonyInput, true));
}
}
} else {
// Post processing: all inputs should have been processed and added to fragment.
cycleProtection.remove(currentTarget);
alreadyVisited.add(currentTarget);
fragment.add(currentTarget);
}
}
return fragment;
}