Add #getKey to SpawnActionTemplate by just creating a dummy SpawnAction and computing its key. That should be sufficient. As a result, we can move #getKey up to ActionAnalysisMetadata.
Can we use this tactic for CppCompileActionTemplate as well?
PiperOrigin-RevId: 244746907
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionAnalysisMetadata.java b/src/main/java/com/google/devtools/build/lib/actions/ActionAnalysisMetadata.java
index 1e5da6d..e076912 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionAnalysisMetadata.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionAnalysisMetadata.java
@@ -47,6 +47,36 @@
String getMnemonic();
/**
+ * Returns a string encoding all of the significant behaviour of this Action that might affect the
+ * output. The general contract of <code>getKey</code> is this: if the work to be performed by the
+ * execution of this action changes, the key must change.
+ *
+ * <p>As a corollary, the build system is free to omit the execution of an Action <code>a1</code>
+ * if (a) at some time in the past, it has already executed an Action <code>a0</code> with the
+ * same key as <code>a1</code>, (b) the names and contents of the input files listed by <code>
+ * a1.getInputs()</code> are identical to the names and contents of the files listed by <code>
+ * a0.getInputs()</code>, and (c) the names and values in the client environment of the variables
+ * listed by <code>a1.getClientEnvironmentVariables()</code> are identical to those listed by
+ * <code>a0.getClientEnvironmentVariables()</code>.
+ *
+ * <p>Examples of changes that should affect the key are:
+ *
+ * <ul>
+ * <li>Changes to the BUILD file that materially affect the rule which gave rise to this Action.
+ * <li>Changes to the command-line options, environment, or other global configuration resources
+ * which affect the behaviour of this kind of Action (other than changes to the names of the
+ * input/output files, which are handled externally).
+ * <li>An upgrade to the build tools which changes the program logic of this kind of Action
+ * (typically this is achieved by incorporating a UUID into the key, which is changed each
+ * time the program logic of this action changes).
+ * </ul>
+ *
+ * <p>Note the following exception: for actions that discover inputs, the key must change if any
+ * input names change or else action validation may falsely validate.
+ */
+ String getKey(ActionKeyContext actionKeyContext);
+
+ /**
* Returns a pretty string representation of this action, suitable for use in
* progress messages or error messages.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionMetadata.java b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionMetadata.java
index c83cea9..255074f 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionMetadata.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionMetadata.java
@@ -45,36 +45,6 @@
String getProgressMessage();
/**
- * Returns a string encoding all of the significant behaviour of this Action that might affect the
- * output. The general contract of <code>getKey</code> is this: if the work to be performed by the
- * execution of this action changes, the key must change.
- *
- * <p>As a corollary, the build system is free to omit the execution of an Action <code>a1</code>
- * if (a) at some time in the past, it has already executed an Action <code>a0</code> with the
- * same key as <code>a1</code>, (b) the names and contents of the input files listed by <code>
- * a1.getInputs()</code> are identical to the names and contents of the files listed by <code>
- * a0.getInputs()</code>, and (c) the names and values in the client environment of the variables
- * listed by <code>a1.getClientEnvironmentVariables()</code> are identical to those listed by
- * <code>a0.getClientEnvironmentVariables()</code>.
- *
- * <p>Examples of changes that should affect the key are:
- *
- * <ul>
- * <li>Changes to the BUILD file that materially affect the rule which gave rise to this Action.
- * <li>Changes to the command-line options, environment, or other global configuration resources
- * which affect the behaviour of this kind of Action (other than changes to the names of the
- * input/output files, which are handled externally).
- * <li>An upgrade to the build tools which changes the program logic of this kind of Action
- * (typically this is achieved by incorporating a UUID into the key, which is changed each
- * time the program logic of this action changes).
- * </ul>
- *
- * <p>Note the following exception: for actions that discover inputs, the key must change if any
- * input names change or else action validation may falsely validate.
- */
- String getKey(ActionKeyContext actionKeyContext);
-
- /**
* Returns a human-readable description of the inputs to {@link #getKey(ActionKeyContext)}. Used
* in the output from '--explain', and in error messages for '--check_up_to_date' and
* '--check_tests_up_to_date'. May return null, meaning no extra information is available.
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java
index ab54b4f..c3716e1 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplate.java
@@ -19,6 +19,7 @@
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.actions.ActionExecutionContext;
import com.google.devtools.build.lib.actions.ActionInputHelper;
+import com.google.devtools.build.lib.actions.ActionKeyContext;
import com.google.devtools.build.lib.actions.ActionOwner;
import com.google.devtools.build.lib.actions.ActionTemplate;
import com.google.devtools.build.lib.actions.Artifact;
@@ -46,6 +47,7 @@
private final OutputPathMapper outputPathMapper;
private final SpawnAction.Builder spawnActionBuilder;
private final CustomCommandLine commandLineTemplate;
+ private String cachedKey;
/**
* Interface providing mapping between expanded input files under the input TreeArtifact and
@@ -112,6 +114,21 @@
return expandedActions.build();
}
+ @Override
+ public synchronized String getKey(ActionKeyContext actionKeyContext) {
+ if (cachedKey != null) {
+ return cachedKey;
+ }
+ TreeFileArtifact inputTreeFileArtifact =
+ ActionInputHelper.treeFileArtifact(inputTreeArtifact, "dummy_for_key");
+ TreeFileArtifact outputTreeFileArtifact =
+ ActionInputHelper.treeFileArtifact(
+ outputTreeArtifact, outputPathMapper.parentRelativeOutputPath(inputTreeFileArtifact));
+ SpawnAction dummyAction = createAction(inputTreeFileArtifact, outputTreeFileArtifact);
+ cachedKey = dummyAction.getKey(actionKeyContext);
+ return cachedKey;
+ }
+
/**
* Returns a SpawnAction that takes inputTreeFileArtifact as input and generates
* outputTreeFileArtifact.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionTemplate.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionTemplate.java
index 21310b0..3ce146e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionTemplate.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionTemplate.java
@@ -142,7 +142,7 @@
return expandedActions.build();
}
- // TODO(jhorvitz): Move getKey to ActionAnalysisMetadata once all action templates implement it.
+ @Override
public synchronized String getKey(ActionKeyContext actionKeyContext) {
if (cachedKey != null) {
return cachedKey;
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplateTest.java b/src/test/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplateTest.java
index d9cd78d..56ed076 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplateTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTemplateTest.java
@@ -19,6 +19,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.actions.ActionInputHelper;
+import com.google.devtools.build.lib.actions.ActionKeyContext;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
import com.google.devtools.build.lib.actions.Artifact.SpecialArtifactType;
@@ -139,6 +140,62 @@
}
@Test
+ public void getKey_same() {
+ ActionKeyContext keyContext = new ActionKeyContext();
+ SpecialArtifact inputTreeArtifact = createInputTreeArtifact();
+ SpecialArtifact outputTreeArtifact = createOutputTreeArtifact();
+ Artifact executable = createDerivedArtifact("bin/cp");
+
+ // Use two different builders because the same builder would share the underlying
+ // SpawnActionBuilder.
+ SpawnActionTemplate actionTemplate =
+ builder(inputTreeArtifact, outputTreeArtifact)
+ .setExecutable(executable)
+ .setCommandLineTemplate(
+ createSimpleCommandLineTemplate(inputTreeArtifact, outputTreeArtifact))
+ .setOutputPathMapper(IDENTITY_MAPPER)
+ .setMnemonics("ActionTemplate", "ExpandedAction")
+ .build(ActionsTestUtil.NULL_ACTION_OWNER);
+ SpawnActionTemplate actionTemplate2 =
+ builder(inputTreeArtifact, outputTreeArtifact)
+ .setExecutable(executable)
+ .setCommandLineTemplate(
+ createSimpleCommandLineTemplate(inputTreeArtifact, outputTreeArtifact))
+ .setOutputPathMapper(IDENTITY_MAPPER)
+ .setMnemonics("ActionTemplate", "ExpandedAction")
+ .build(ActionsTestUtil.NULL_ACTION_OWNER);
+ assertThat(actionTemplate2.getKey(keyContext)).isEqualTo(actionTemplate.getKey(keyContext));
+ }
+
+ @Test
+ public void getKey_differs() {
+ ActionKeyContext keyContext = new ActionKeyContext();
+ SpecialArtifact inputTreeArtifact = createInputTreeArtifact();
+ SpecialArtifact outputTreeArtifact = createOutputTreeArtifact();
+ Artifact executable = createDerivedArtifact("bin/cp");
+
+ // Use two different builders because the same builder would share the underlying
+ // SpawnActionBuilder.
+ SpawnActionTemplate actionTemplate =
+ builder(inputTreeArtifact, outputTreeArtifact)
+ .setExecutable(executable)
+ .setCommandLineTemplate(
+ createSimpleCommandLineTemplate(inputTreeArtifact, outputTreeArtifact))
+ .setOutputPathMapper(IDENTITY_MAPPER)
+ .setMnemonics("ActionTemplate", "ExpandedAction")
+ .build(ActionsTestUtil.NULL_ACTION_OWNER);
+ SpawnActionTemplate actionTemplate2 =
+ builder(inputTreeArtifact, outputTreeArtifact)
+ .setExecutable(executable)
+ .setCommandLineTemplate(
+ createSimpleCommandLineTemplate(inputTreeArtifact, outputTreeArtifact))
+ .setOutputPathMapper(IDENTITY_MAPPER)
+ .setMnemonics("ActionTemplate", "ExpandedAction2")
+ .build(ActionsTestUtil.NULL_ACTION_OWNER);
+ assertThat(actionTemplate2.getKey(keyContext)).isNotEqualTo(actionTemplate.getKey(keyContext));
+ }
+
+ @Test
public void testExpandedAction_inputAndOutputTreeFileArtifacts() throws Exception {
SpawnActionTemplate actionTemplate = createSimpleSpawnActionTemplate();
SpecialArtifact inputTreeArtifact = createInputTreeArtifact();