Skyframe changes to support SpawnActionTemplate.
1. Adds ActionTemplateExpansion{Function, Value} for ActionTemplate expansion.
2. Changes ArtifactFunction to support evaluating TreeFileArtifacts and TreeArtifacts generated by ActionTemplate.
--
MOS_MIGRATED_REVID=124160939
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
index d7433ac..789e2b1 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
@@ -30,9 +30,14 @@
import com.google.devtools.build.lib.actions.Action;
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata.MiddlemanType;
+import com.google.devtools.build.lib.actions.ActionInputHelper;
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;
+import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
import com.google.devtools.build.lib.actions.MissingInputFileException;
import com.google.devtools.build.lib.actions.Root;
+import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
import com.google.devtools.build.lib.actions.util.TestAction.DummyAction;
import com.google.devtools.build.lib.events.NullEventHandler;
import com.google.devtools.build.lib.util.Pair;
@@ -169,7 +174,7 @@
new DummyAction(
ImmutableList.of(input1, input2), output, MiddlemanType.AGGREGATING_MIDDLEMAN);
// Overwrite default generating action with this one.
- for (Iterator<Action> it = actions.iterator(); it.hasNext(); ) {
+ for (Iterator<ActionAnalysisMetadata> it = actions.iterator(); it.hasNext(); ) {
if (it.next().getOutputs().contains(output)) {
it.remove();
break;
@@ -324,6 +329,70 @@
.testEquals();
}
+ @Test
+ public void testActionTreeArtifactOutput() throws Throwable {
+ Artifact artifact = createDerivedTreeArtifactWithAction("treeArtifact");
+ TreeFileArtifact treeFileArtifact1 = createFakeTreeFileArtifact(artifact, "child1", "hello1");
+ TreeFileArtifact treeFileArtifact2 = createFakeTreeFileArtifact(artifact, "child2", "hello2");
+
+ TreeArtifactValue value = (TreeArtifactValue) evaluateArtifactValue(artifact);
+ assertNotNull(value.getChildValue(treeFileArtifact1));
+ assertNotNull(value.getChildValue(treeFileArtifact2));
+ assertNotNull(value.getChildValue(treeFileArtifact1).getDigest());
+ assertNotNull(value.getChildValue(treeFileArtifact2).getDigest());
+ }
+
+ @Test
+ public void testSpawnActionTemplate() throws Throwable {
+ // artifact1 is a tree artifact generated by normal action.
+ Artifact artifact1 = createDerivedTreeArtifactWithAction("treeArtifact1");
+ createFakeTreeFileArtifact(artifact1, "child1", "hello1");
+ createFakeTreeFileArtifact(artifact1, "child2", "hello2");
+
+
+ // artifact2 is a tree artifact generated by action template.
+ Artifact artifact2 = createDerivedTreeArtifactOnly("treeArtifact2");
+ TreeFileArtifact treeFileArtifact1 = createFakeTreeFileArtifact(artifact2, "child1", "hello1");
+ TreeFileArtifact treeFileArtifact2 = createFakeTreeFileArtifact(artifact2, "child2", "hello2");
+
+ actions.add(
+ ActionsTestUtil.createDummySpawnActionTemplate(artifact1, artifact2));
+
+ TreeArtifactValue value = (TreeArtifactValue) evaluateArtifactValue(artifact2);
+ assertNotNull(value.getChildValue(treeFileArtifact1));
+ assertNotNull(value.getChildValue(treeFileArtifact2));
+ assertNotNull(value.getChildValue(treeFileArtifact1).getDigest());
+ assertNotNull(value.getChildValue(treeFileArtifact2).getDigest());
+ }
+
+ @Test
+ public void testConsecutiveSpawnActionTemplates() throws Throwable {
+ // artifact1 is a tree artifact generated by normal action.
+ Artifact artifact1 = createDerivedTreeArtifactWithAction("treeArtifact1");
+ createFakeTreeFileArtifact(artifact1, "child1", "hello1");
+ createFakeTreeFileArtifact(artifact1, "child2", "hello2");
+
+ // artifact2 is a tree artifact generated by action template.
+ Artifact artifact2 = createDerivedTreeArtifactOnly("treeArtifact2");
+ createFakeTreeFileArtifact(artifact2, "child1", "hello1");
+ createFakeTreeFileArtifact(artifact2, "child2", "hello2");
+ actions.add(
+ ActionsTestUtil.createDummySpawnActionTemplate(artifact1, artifact2));
+
+ // artifact3 is a tree artifact generated by action template.
+ Artifact artifact3 = createDerivedTreeArtifactOnly("treeArtifact3");
+ TreeFileArtifact treeFileArtifact1 = createFakeTreeFileArtifact(artifact3, "child1", "hello1");
+ TreeFileArtifact treeFileArtifact2 = createFakeTreeFileArtifact(artifact3, "child2", "hello2");
+ actions.add(
+ ActionsTestUtil.createDummySpawnActionTemplate(artifact2, artifact3));
+
+ TreeArtifactValue value = (TreeArtifactValue) evaluateArtifactValue(artifact3);
+ assertNotNull(value.getChildValue(treeFileArtifact1));
+ assertNotNull(value.getChildValue(treeFileArtifact2));
+ assertNotNull(value.getChildValue(treeFileArtifact1).getDigest());
+ assertNotNull(value.getChildValue(treeFileArtifact2).getDigest());
+ }
+
private void file(Path path, String contents) throws Exception {
FileSystemUtils.createDirectoryAndParents(path.getParentDirectory());
writeFile(path, contents);
@@ -343,6 +412,33 @@
return output;
}
+ private Artifact createDerivedTreeArtifactWithAction(String path) {
+ Artifact treeArtifact = createDerivedTreeArtifactOnly(path);
+ actions.add(new DummyAction(ImmutableList.<Artifact>of(), treeArtifact));
+ return treeArtifact;
+ }
+
+ private Artifact createDerivedTreeArtifactOnly(String path) {
+ PathFragment execPath = new PathFragment("out").getRelative(path);
+ Path fullPath = root.getRelative(execPath);
+ return new SpecialArtifact(
+ fullPath,
+ Root.asDerivedRoot(root, root.getRelative("out")),
+ execPath,
+ ALL_OWNER,
+ SpecialArtifactType.TREE);
+ }
+
+ private TreeFileArtifact createFakeTreeFileArtifact(Artifact treeArtifact,
+ String parentRelativePath, String content) throws Exception {
+ TreeFileArtifact treeFileArtifact = ActionInputHelper.treeFileArtifact(
+ treeArtifact, new PathFragment(parentRelativePath));
+ Path path = treeFileArtifact.getPath();
+ FileSystemUtils.createDirectoryAndParents(path.getParentDirectory());
+ writeFile(path, content);
+ return treeFileArtifact;
+ }
+
private void assertValueMatches(FileStatus file, byte[] digest, FileArtifactValue value)
throws IOException {
assertEquals(file.getSize(), value.getSize());
@@ -384,35 +480,46 @@
throws InterruptedException {
setGeneratingActions();
return driver.evaluate(
- Arrays.asList(keys), /*keepGoing=*/
- false,
+ Arrays.asList(keys),
+ /*keepGoing=*/false,
SkyframeExecutor.DEFAULT_THREAD_COUNT,
NullEventHandler.INSTANCE);
}
/** Value Builder for actions that just stats and stores the output file (which must exist). */
- private class SimpleActionExecutionFunction implements SkyFunction {
+ private static class SimpleActionExecutionFunction implements SkyFunction {
@Override
public SkyValue compute(SkyKey skyKey, Environment env) {
Map<Artifact, FileValue> artifactData = new HashMap<>();
+ Map<Artifact, TreeArtifactValue> treeArtifactData = new HashMap<>();
+ Map<Artifact, FileArtifactValue> additionalOutputData = new HashMap<>();
Action action = (Action) skyKey.argument();
Artifact output = Iterables.getOnlyElement(action.getOutputs());
- FileArtifactValue value;
- if (action.getActionType() == MiddlemanType.NORMAL) {
- try {
+
+ try {
+ if (output.isTreeArtifact()) {
+ TreeFileArtifact treeFileArtifact1 = ActionInputHelper.treeFileArtifact(
+ output, new PathFragment("child1"));
+ TreeFileArtifact treeFileArtifact2 = ActionInputHelper.treeFileArtifact(
+ output, new PathFragment("child2"));
+ TreeArtifactValue treeArtifactValue = TreeArtifactValue.create(ImmutableMap.of(
+ treeFileArtifact1, FileArtifactValue.create(treeFileArtifact1),
+ treeFileArtifact2, FileArtifactValue.create(treeFileArtifact2)));
+ treeArtifactData.put(output, treeArtifactValue);
+ } else if (action.getActionType() == MiddlemanType.NORMAL) {
FileValue fileValue = ActionMetadataHandler.fileValueFromArtifact(output, null, null);
artifactData.put(output, fileValue);
- value = FileArtifactValue.create(output, fileValue);
- } catch (IOException e) {
- throw new IllegalStateException(e);
+ additionalOutputData.put(output, FileArtifactValue.create(output, fileValue));
+ } else {
+ additionalOutputData.put(output, FileArtifactValue.DEFAULT_MIDDLEMAN);
}
- } else {
- value = FileArtifactValue.DEFAULT_MIDDLEMAN;
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
}
return new ActionExecutionValue(
artifactData,
- ImmutableMap.<Artifact, TreeArtifactValue>of(),
- ImmutableMap.of(output, value));
+ treeArtifactData,
+ additionalOutputData);
}
@Override