aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/extra
diff options
context:
space:
mode:
authorGravatar ulfjack <ulfjack@google.com>2017-08-10 12:29:25 +0200
committerGravatar Marcel Hlopko <hlopko@google.com>2017-08-10 13:48:24 +0200
commit9220eec3c8359907284edd78191467b6df7ae4d0 (patch)
tree708e5137e89439b413b516cd2d6aea4cb3158a09 /src/main/java/com/google/devtools/build/lib/rules/extra
parent3a5002f119fe1d37d897445f21f3ad650caf83c6 (diff)
Move extra action stuff to analysis.extra
This is part of splitting up the build-base library into separate libraries for analysis, exec, and rules. PiperOrigin-RevId: 164835678
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/extra')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/extra/ExtraAction.java182
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionInfoFileWriteAction.java61
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionMapProvider.java38
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionSpec.java245
6 files changed, 3 insertions, 526 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java
index 1505e44054..105c4b7a52 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java
@@ -23,6 +23,8 @@ import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.Runfiles;
import com.google.devtools.build.lib.analysis.RunfilesProvider;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.extra.ExtraActionMapProvider;
+import com.google.devtools.build.lib.analysis.extra.ExtraActionSpec;
import com.google.devtools.build.lib.collect.ImmutableSortedKeyListMultimap;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.syntax.Type;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraAction.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraAction.java
deleted file mode 100644
index 41ba32c5fd..0000000000
--- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraAction.java
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.lib.rules.extra;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import com.google.devtools.build.lib.actions.AbstractAction;
-import com.google.devtools.build.lib.actions.Action;
-import com.google.devtools.build.lib.actions.ActionEnvironment;
-import com.google.devtools.build.lib.actions.ActionExecutionContext;
-import com.google.devtools.build.lib.actions.ActionExecutionException;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.CompositeRunfilesSupplier;
-import com.google.devtools.build.lib.actions.RunfilesSupplier;
-import com.google.devtools.build.lib.actions.SpawnActionContext;
-import com.google.devtools.build.lib.analysis.actions.CommandLine;
-import com.google.devtools.build.lib.analysis.actions.SpawnAction;
-import com.google.devtools.build.lib.collect.nestedset.NestedSet;
-import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
-import com.google.devtools.build.lib.collect.nestedset.Order;
-import com.google.devtools.build.lib.util.Preconditions;
-import com.google.devtools.build.lib.vfs.FileSystemUtils;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Map;
-import javax.annotation.Nullable;
-
-/**
- * Action used by extra_action rules to create an action that shadows an existing action. Runs a
- * command-line using {@link SpawnActionContext} for executions.
- */
-public final class ExtraAction extends SpawnAction {
- private final Action shadowedAction;
- private final boolean createDummyOutput;
- private final ImmutableSet<Artifact> extraActionInputs;
-
- /**
- * A long way to say (ExtraAction xa) -> xa.getShadowedAction().
- */
- public static final Function<ExtraAction, Action> GET_SHADOWED_ACTION =
- new Function<ExtraAction, Action>() {
- @Nullable
- @Override
- public Action apply(@Nullable ExtraAction extraAction) {
- return extraAction != null ? extraAction.getShadowedAction() : null;
- }
- };
-
- ExtraAction(
- ImmutableSet<Artifact> extraActionInputs,
- RunfilesSupplier runfilesSupplier,
- Collection<Artifact> outputs,
- Action shadowedAction,
- boolean createDummyOutput,
- CommandLine argv,
- ActionEnvironment env,
- Map<String, String> executionInfo,
- CharSequence progressMessage,
- String mnemonic) {
- super(
- shadowedAction.getOwner(),
- ImmutableList.<Artifact>of(),
- createInputs(shadowedAction.getInputs(), ImmutableList.<Artifact>of(), extraActionInputs),
- outputs,
- AbstractAction.DEFAULT_RESOURCE_SET,
- argv,
- false,
- env,
- ImmutableMap.copyOf(executionInfo),
- progressMessage,
- new CompositeRunfilesSupplier(shadowedAction.getRunfilesSupplier(), runfilesSupplier),
- mnemonic,
- false,
- null);
- this.shadowedAction = shadowedAction;
- this.createDummyOutput = createDummyOutput;
-
- this.extraActionInputs = extraActionInputs;
- if (createDummyOutput) {
- // Expecting just a single dummy file in the outputs.
- Preconditions.checkArgument(outputs.size() == 1, outputs);
- }
- }
-
- @Override
- public boolean discoversInputs() {
- return shadowedAction.discoversInputs();
- }
-
- @Nullable
- @Override
- public Iterable<Artifact> discoverInputs(ActionExecutionContext actionExecutionContext)
- throws ActionExecutionException, InterruptedException {
- Preconditions.checkState(discoversInputs(), this);
- // We depend on the outputs of actions doing input discovery and they should know their inputs
- // after having been executed
- Preconditions.checkState(shadowedAction.inputsDiscovered());
-
- // We need to update our inputs to take account of any additional
- // inputs the shadowed action may need to do its work.
- Iterable<Artifact> oldInputs = getInputs();
- updateInputs(
- createInputs(
- shadowedAction.getInputs(),
- shadowedAction.getInputFilesForExtraAction(actionExecutionContext),
- extraActionInputs));
- return Sets.<Artifact>difference(
- ImmutableSet.<Artifact>copyOf(getInputs()), ImmutableSet.<Artifact>copyOf(oldInputs));
- }
-
- private static NestedSet<Artifact> createInputs(
- Iterable<Artifact> shadowedActionInputs,
- Iterable<Artifact> inputFilesForExtraAction,
- ImmutableSet<Artifact> extraActionInputs) {
- NestedSetBuilder<Artifact> result = new NestedSetBuilder<>(Order.STABLE_ORDER);
- for (Iterable<Artifact> inputSet : ImmutableList.of(
- shadowedActionInputs, inputFilesForExtraAction)) {
- if (inputSet instanceof NestedSet) {
- result.addTransitive((NestedSet<Artifact>) inputSet);
- } else {
- result.addAll(inputSet);
- }
- }
- return result.addAll(extraActionInputs).build();
- }
-
- @Override
- public Iterable<Artifact> getAllowedDerivedInputs() {
- return shadowedAction.getAllowedDerivedInputs();
- }
-
- /**
- * @InheritDoc
- *
- * This method calls in to {@link AbstractAction#getInputFilesForExtraAction} and
- * {@link Action#getExtraActionInfo} of the action being shadowed from the thread executing this
- * ExtraAction. It assumes these methods are safe to call from a different thread than the thread
- * responsible for the execution of the action being shadowed.
- */
- @Override
- public void execute(ActionExecutionContext actionExecutionContext)
- throws ActionExecutionException, InterruptedException {
- // PHASE 2: execution of extra_action.
-
- super.execute(actionExecutionContext);
-
- // PHASE 3: create dummy output.
- // If the user didn't specify output, we need to create dummy output
- // to make blaze schedule this action.
- if (createDummyOutput) {
- for (Artifact output : getOutputs()) {
- try {
- FileSystemUtils.touchFile(output.getPath());
- } catch (IOException e) {
- throw new ActionExecutionException(e.getMessage(), e, this, false);
- }
- }
- }
- }
-
- /**
- * Returns the action this extra action is 'shadowing'.
- */
- public Action getShadowedAction() {
- return shadowedAction;
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java
index 1d0def104f..c3fe6b940b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java
@@ -29,6 +29,7 @@ import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.Runfiles;
import com.google.devtools.build.lib.analysis.RunfilesProvider;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.extra.ExtraActionSpec;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.TargetUtils;
import com.google.devtools.build.lib.syntax.Type;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionInfoFileWriteAction.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionInfoFileWriteAction.java
deleted file mode 100644
index 36fee0385f..0000000000
--- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionInfoFileWriteAction.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.google.devtools.build.lib.rules.extra;
-
-import com.google.common.collect.ImmutableList;
-import com.google.devtools.build.lib.actions.Action;
-import com.google.devtools.build.lib.actions.ActionExecutionContext;
-import com.google.devtools.build.lib.actions.ActionOwner;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.ExecException;
-import com.google.devtools.build.lib.analysis.actions.AbstractFileWriteAction;
-import com.google.devtools.build.lib.analysis.actions.ProtoDeterministicWriter;
-import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.util.Fingerprint;
-import com.google.devtools.build.lib.util.Preconditions;
-import java.io.IOException;
-
-/**
- * Requests extra action info from shadowed action and writes it, in protocol buffer format, to an
- * .xa file for use by an extra action. This can only be done at execution time because actions may
- * store information only known at execution time into the protocol buffer.
- */
-@Immutable // if shadowedAction is immutable
-public final class ExtraActionInfoFileWriteAction extends AbstractFileWriteAction {
- private static final String UUID = "1759f81d-e72e-477d-b182-c4532bdbaeeb";
-
- private final Action shadowedAction;
-
- ExtraActionInfoFileWriteAction(ActionOwner owner, Artifact extraActionInfoFile,
- Action shadowedAction) {
- super(owner, ImmutableList.<Artifact>of(), extraActionInfoFile, false);
-
- this.shadowedAction = Preconditions.checkNotNull(shadowedAction, extraActionInfoFile);
- }
-
- @Override
- public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx)
- throws IOException, InterruptedException, ExecException {
- return new ProtoDeterministicWriter(shadowedAction.getExtraActionInfo().build());
- }
-
- @Override
- protected String computeKey() {
- Fingerprint f = new Fingerprint();
- f.addString(UUID);
- f.addString(shadowedAction.getKey());
- f.addBytes(shadowedAction.getExtraActionInfo().build().toByteArray());
- return f.hexDigestAndReset();
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionMapProvider.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionMapProvider.java
deleted file mode 100644
index 50e6c800d1..0000000000
--- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionMapProvider.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.google.devtools.build.lib.rules.extra;
-
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.Multimap;
-import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
-import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-
-/**
- * Provides an action type -> set of extra actions to run map.
- */
-@Immutable
-public final class ExtraActionMapProvider implements TransitiveInfoProvider {
- private final ImmutableMultimap<String, ExtraActionSpec> extraActionMap;
-
- public ExtraActionMapProvider(Multimap<String, ExtraActionSpec> extraActionMap) {
- this.extraActionMap = ImmutableMultimap.copyOf(extraActionMap);
- }
-
- /**
- * Returns the extra action map.
- */
- public ImmutableMultimap<String, ExtraActionSpec> getExtraActionMap() {
- return extraActionMap;
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionSpec.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionSpec.java
deleted file mode 100644
index 3ccda08af2..0000000000
--- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionSpec.java
+++ /dev/null
@@ -1,245 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.google.devtools.build.lib.rules.extra;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.devtools.build.lib.actions.Action;
-import com.google.devtools.build.lib.actions.ActionOwner;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.RunfilesSupplier;
-import com.google.devtools.build.lib.analysis.CommandHelper;
-import com.google.devtools.build.lib.analysis.RuleContext;
-import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
-import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
-import com.google.devtools.build.lib.analysis.actions.CommandLine;
-import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
-import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.AspectDescriptor;
-import com.google.devtools.build.lib.util.Fingerprint;
-import com.google.devtools.build.lib.vfs.PathFragment;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-
-/**
- * The specification for a particular extra action type.
- */
-@Immutable
-public final class ExtraActionSpec implements TransitiveInfoProvider {
- private final ImmutableList<Artifact> resolvedTools;
- private final RunfilesSupplier runfilesSupplier;
- private final ImmutableList<Artifact> resolvedData;
- private final ImmutableList<String> outputTemplates;
- private final ImmutableMap<String, String> executionInfo;
- private final String command;
- private final boolean requiresActionOutput;
- private final Label label;
-
- ExtraActionSpec(
- Iterable<Artifact> resolvedTools,
- RunfilesSupplier runfilesSupplier,
- Iterable<Artifact> resolvedData,
- Iterable<String> outputTemplates,
- String command,
- Label label,
- Map<String, String> executionInfo,
- boolean requiresActionOutput) {
- this.resolvedTools = ImmutableList.copyOf(resolvedTools);
- this.runfilesSupplier = runfilesSupplier;
- this.resolvedData = ImmutableList.copyOf(resolvedData);
- this.outputTemplates = ImmutableList.copyOf(outputTemplates);
- this.command = command;
- this.label = label;
- this.executionInfo = ImmutableMap.copyOf(executionInfo);
- this.requiresActionOutput = requiresActionOutput;
- }
-
- public Label getLabel() {
- return label;
- }
-
- /**
- * Adds an extra_action to the action graph based on the action to shadow.
- */
- public Collection<Artifact> addExtraAction(RuleContext owningRule, Action actionToShadow) {
- Collection<Artifact> extraActionOutputs = new LinkedHashSet<>();
- Collection<Artifact> protoOutputs = new ArrayList<>();
- NestedSetBuilder<Artifact> extraActionInputs = NestedSetBuilder.stableOrder();
-
- Label ownerLabel = owningRule.getLabel();
- if (requiresActionOutput || actionToShadow.discoversInputs()) {
- extraActionInputs.addAll(actionToShadow.getOutputs());
- }
-
- extraActionInputs.addAll(resolvedTools);
- extraActionInputs.addAll(resolvedData);
-
- boolean createDummyOutput = false;
-
- for (String outputTemplate : outputTemplates) {
- // We create output for the extra_action based on the 'out_template' attribute.
- // See {link #getExtraActionOutputArtifact} for supported variables.
- extraActionOutputs.add(getExtraActionOutputArtifact(
- owningRule, actionToShadow, outputTemplate));
- }
- // extra_action has no output, we need to create some dummy output to keep the build up-to-date.
- if (extraActionOutputs.isEmpty()) {
- createDummyOutput = true;
- extraActionOutputs.add(getExtraActionOutputArtifact(
- owningRule, actionToShadow, "$(ACTION_ID).dummy"));
- }
-
- // We generate a file containing a protocol buffer describing the action that is being shadowed.
- // It is up to each action being shadowed to decide what contents to store here.
- Artifact extraActionInfoFile = getExtraActionOutputArtifact(
- owningRule, actionToShadow, "$(ACTION_ID).xa");
- owningRule.registerAction(new ExtraActionInfoFileWriteAction(
- actionToShadow.getOwner(), extraActionInfoFile, actionToShadow));
- extraActionInputs.add(extraActionInfoFile);
- protoOutputs.add(extraActionInfoFile);
-
- // Expand extra_action specific variables from the provided command-line.
- // See {@link #createExpandedCommand} for list of supported variables.
- String command = createExpandedCommand(owningRule, actionToShadow, extraActionInfoFile);
-
- CommandHelper commandHelper =
- new CommandHelper(
- owningRule,
- ImmutableList.<TransitiveInfoCollection>of(),
- ImmutableMap.<Label, Iterable<Artifact>>of());
-
- // Multiple actions in the same configured target need to have different names for the artifact
- // that might be created here, so we append something that should be unique for each action.
- String actionUniquifier = actionToShadow.getPrimaryOutput().getExecPath().getBaseName() + "."
- + actionToShadow.getKey();
- List<String> argv = commandHelper.buildCommandLine(command, extraActionInputs,
- "." + actionUniquifier + ".extra_action_script.sh", executionInfo);
-
- String commandMessage = String.format("Executing extra_action %s on %s", label, ownerLabel);
- owningRule.registerAction(
- new ExtraAction(
- ImmutableSet.copyOf(extraActionInputs.build()),
- runfilesSupplier,
- extraActionOutputs,
- actionToShadow,
- createDummyOutput,
- CommandLine.of(argv),
- owningRule.getConfiguration().getActionEnvironment(),
- executionInfo,
- commandMessage,
- label.getName()));
-
- return ImmutableSet.<Artifact>builder().addAll(extraActionOutputs).addAll(protoOutputs).build();
- }
-
- /**
- * Expand extra_action specific variables:
- * $(EXTRA_ACTION_FILE): expands to a path of the file containing a protocol buffer
- * describing the action being shadowed.
- * $(output <out_template>): expands the output template to the execPath of the file.
- * e.g. $(output $(ACTION_ID).out) ->
- * <build_path>/extra_actions/bar/baz/devtools/build/test_A41234.out
- */
- private String createExpandedCommand(RuleContext owningRule,
- Action action, Artifact extraActionInfoFile) {
- String realCommand = command.replace(
- "$(EXTRA_ACTION_FILE)", extraActionInfoFile.getExecPathString());
-
- for (String outputTemplate : outputTemplates) {
- String outFile = getExtraActionOutputArtifact(owningRule, action, outputTemplate)
- .getExecPathString();
- realCommand = realCommand.replace("$(output " + outputTemplate + ")", outFile);
- }
- return realCommand;
- }
-
- /**
- * Creates an output artifact for the extra_action based on the output_template.
- * The path will be in the following form:
- * <output dir>/<target-configuration-specific-path>/extra_actions/<extra_action_label>/ +
- * <configured_target_label>/<expanded_template>
- *
- * The template can use the following variables:
- * $(ACTION_ID): a unique id for the extra_action.
- *
- * Sample:
- * extra_action: foo/bar:extra
- * template: $(ACTION_ID).analysis
- * target: foo/bar:main
- * expands to: output/configuration/extra_actions/\
- * foo/bar/extra/foo/bar/4683026f7ac1dd1a873ccc8c3d764132.analysis
- */
- private Artifact getExtraActionOutputArtifact(
- RuleContext ruleContext, Action action, String template) {
- String actionId = getActionId(ruleContext.getActionOwner(), action);
-
- template = template.replace("$(ACTION_ID)", actionId);
- template = template.replace("$(OWNER_LABEL_DIGEST)", getOwnerDigest(ruleContext));
-
- return getRootRelativePath(template, ruleContext);
- }
-
- private Artifact getRootRelativePath(String template, RuleContext ruleContext) {
- PathFragment extraActionPackageFragment = label.getPackageIdentifier().getSourceRoot();
- PathFragment extraActionPrefix = extraActionPackageFragment.getRelative(label.getName());
- PathFragment rootRelativePath = PathFragment.create("extra_actions")
- .getRelative(extraActionPrefix)
- .getRelative(ruleContext.getPackageDirectory())
- .getRelative(template);
- // We need to use getDerivedArtifact here because extra actions are at
- // <EXTRA ACTION LABEL> / <RULE LABEL> instead of <RULE LABEL> / <EXTRA ACTION LABEL>. Bummer.
- return ruleContext.getAnalysisEnvironment().getDerivedArtifact(rootRelativePath,
- ruleContext.getConfiguration().getOutputDirectory(ruleContext.getRule().getRepository()));
- }
-
- /**
- * Calculates a digest representing the rule context. We use the digest instead of the
- * original value as the original value might lead to a filename that is too long.
- * By using a digest, tools can deterministically find all extra_action outputs for a given
- * target, without having to open every file in the package.
- */
- private static String getOwnerDigest(RuleContext ruleContext) {
- Fingerprint f = new Fingerprint();
- f.addString(ruleContext.getLabel().toString());
- return f.hexDigestAndReset();
- }
-
- /**
- * Creates a unique id for the action shadowed by this extra_action.
- *
- * We need to have a unique id for the extra_action to use. We build this
- * from the owner's label and the shadowed action id (which is only
- * guaranteed to be unique per target). Together with the subfolder
- * matching the original target's package name, we believe this is enough
- * of a uniqueness guarantee.
- */
- @VisibleForTesting
- public static String getActionId(ActionOwner owner, Action action) {
- Fingerprint f = new Fingerprint();
- f.addString(owner.getLabel().toString());
- ImmutableList<AspectDescriptor> aspectDescriptors = owner.getAspectDescriptors();
- f.addInt(aspectDescriptors.size());
- for (AspectDescriptor aspectDescriptor : aspectDescriptors) {
- f.addString(aspectDescriptor.getDescription());
- }
- f.addString(action.getKey());
- return f.hexDigestAndReset();
- }
-}