|
19 | 19 | import com.google.common.base.Preconditions; |
20 | 20 | import com.google.common.collect.ImmutableList; |
21 | 21 | import com.google.common.collect.ImmutableMap; |
| 22 | +import com.google.common.collect.ImmutableSet; |
22 | 23 | import com.google.common.collect.Iterables; |
23 | 24 | import com.google.devtools.build.lib.actions.Action; |
24 | 25 | import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; |
25 | 26 | import com.google.devtools.build.lib.actions.ActionConflictException; |
| 27 | +import com.google.devtools.build.lib.actions.ActionExecutionContext; |
| 28 | +import com.google.devtools.build.lib.actions.ActionKeyContext; |
26 | 29 | import com.google.devtools.build.lib.actions.ActionLookupData; |
| 30 | +import com.google.devtools.build.lib.actions.ActionLookupKey; |
27 | 31 | import com.google.devtools.build.lib.actions.ActionLookupValue; |
| 32 | +import com.google.devtools.build.lib.actions.ActionOwner; |
28 | 33 | import com.google.devtools.build.lib.actions.ActionTemplate; |
29 | 34 | import com.google.devtools.build.lib.actions.Actions; |
30 | 35 | import com.google.devtools.build.lib.actions.Artifact; |
|
36 | 41 | import com.google.devtools.build.lib.actions.ArtifactRoot.RootType; |
37 | 42 | import com.google.devtools.build.lib.actions.BasicActionLookupValue; |
38 | 43 | import com.google.devtools.build.lib.actions.FileArtifactValue; |
| 44 | +import com.google.devtools.build.lib.actions.InputMetadataProvider; |
39 | 45 | import com.google.devtools.build.lib.actions.util.ActionsTestUtil; |
40 | 46 | import com.google.devtools.build.lib.actions.util.TestAction.DummyAction; |
41 | 47 | import com.google.devtools.build.lib.analysis.actions.SpawnActionTemplate; |
| 48 | +import com.google.devtools.build.lib.collect.nestedset.NestedSet; |
42 | 49 | import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; |
43 | 50 | import com.google.devtools.build.lib.collect.nestedset.Order; |
44 | 51 | import com.google.devtools.build.lib.events.NullEventHandler; |
45 | 52 | import com.google.devtools.build.lib.skyframe.ArtifactFunction.SourceArtifactException; |
| 53 | +import com.google.devtools.build.lib.util.Fingerprint; |
46 | 54 | import com.google.devtools.build.lib.vfs.FileStatus; |
47 | 55 | import com.google.devtools.build.lib.vfs.FileStatusWithDigestAdapter; |
48 | 56 | import com.google.devtools.build.lib.vfs.Path; |
|
61 | 69 | import java.util.Arrays; |
62 | 70 | import java.util.HashMap; |
63 | 71 | import java.util.Map; |
| 72 | +import javax.annotation.Nullable; |
64 | 73 | import org.junit.Before; |
65 | 74 | import org.junit.Test; |
66 | 75 | import org.junit.runner.RunWith; |
@@ -221,6 +230,50 @@ public void testConsecutiveSpawnActionTemplates() throws Throwable { |
221 | 230 | assertThat(value.getChildValues().get(treeFileArtifact2).getDigest()).isNotNull(); |
222 | 231 | } |
223 | 232 |
|
| 233 | + @Test |
| 234 | + public void testActionTemplateGeneratesMultipleOutputTreesFromDifferentActions() |
| 235 | + throws Throwable { |
| 236 | + // `inputTree` is a tree artifact generated by normal action. |
| 237 | + SpecialArtifact inputTree = createDerivedTreeArtifactWithAction("treeArtifact1"); |
| 238 | + createFakeTreeFileArtifact(inputTree, "child1", "hello1"); |
| 239 | + createFakeTreeFileArtifact(inputTree, "child2", "hello2"); |
| 240 | + SpecialArtifact outputTree1 = createDerivedTreeArtifactOnly("treeArtifact2"); |
| 241 | + SpecialArtifact outputTree2 = createDerivedTreeArtifactOnly("treeArtifact3"); |
| 242 | + ActionTemplate<DummyAction> template = |
| 243 | + new TestActionTemplate( |
| 244 | + ImmutableList.of(inputTree), ImmutableSet.of(outputTree1, outputTree2)) { |
| 245 | + @Override |
| 246 | + public ImmutableList<DummyAction> generateActionsForInputArtifacts( |
| 247 | + ImmutableList<TreeFileArtifact> inputTreeFileArtifacts, |
| 248 | + ActionLookupKey artifactOwner) { |
| 249 | + ImmutableList.Builder<DummyAction> actions = ImmutableList.builder(); |
| 250 | + for (SpecialArtifact outputTree : ImmutableSet.of(outputTree1, outputTree2)) { |
| 251 | + TreeFileArtifact output = |
| 252 | + TreeFileArtifact.createTemplateExpansionOutput( |
| 253 | + outputTree, "child", artifactOwner); |
| 254 | + actions.add(new DummyAction(NestedSetBuilder.emptySet(Order.STABLE_ORDER), output)); |
| 255 | + } |
| 256 | + return actions.build(); |
| 257 | + } |
| 258 | + }; |
| 259 | + actions.add(template); |
| 260 | + TreeFileArtifact treeFileArtifact1 = |
| 261 | + createFakeExpansionTreeFileArtifact(template, outputTree1, "child", "hello"); |
| 262 | + TreeFileArtifact treeFileArtifact2 = |
| 263 | + createFakeExpansionTreeFileArtifact(template, outputTree2, "child", "hello"); |
| 264 | + TreeArtifactValue value = (TreeArtifactValue) evaluateArtifactValue(outputTree1); |
| 265 | + TreeArtifactValue value2 = (TreeArtifactValue) evaluateArtifactValue(outputTree2); |
| 266 | + |
| 267 | + assertThat(value.getChildValues()).containsKey(treeFileArtifact1); |
| 268 | + assertThat(value2.getChildValues()).containsKey(treeFileArtifact2); |
| 269 | + // The TreeArtifactValue for outputTree1 should not contain the child from outputTree2 and vice |
| 270 | + // versa. |
| 271 | + assertThat(value.getChildValues()).doesNotContainKey(treeFileArtifact2); |
| 272 | + assertThat(value2.getChildValues()).doesNotContainKey(treeFileArtifact1); |
| 273 | + assertThat(value.getChildValues().get(treeFileArtifact1).getDigest()).isNotNull(); |
| 274 | + assertThat(value2.getChildValues().get(treeFileArtifact2).getDigest()).isNotNull(); |
| 275 | + } |
| 276 | + |
224 | 277 | private static void file(Path path, String contents) throws Exception { |
225 | 278 | path.getParentDirectory().createDirectoryAndParents(); |
226 | 279 | writeFile(path, contents); |
@@ -395,4 +448,116 @@ public SkyValue compute(SkyKey skyKey, Environment env) throws InterruptedExcept |
395 | 448 | ImmutableMap.copyOf(artifactData), ImmutableMap.copyOf(treeArtifactData)); |
396 | 449 | } |
397 | 450 | } |
| 451 | + |
| 452 | + private abstract static class TestActionTemplate implements ActionTemplate<DummyAction> { |
| 453 | + private final ImmutableList<SpecialArtifact> inputTreeArtifacts; |
| 454 | + private final ImmutableSet<SpecialArtifact> outputTreeArtifacts; |
| 455 | + |
| 456 | + TestActionTemplate( |
| 457 | + ImmutableList<SpecialArtifact> inputTreeArtifacts, |
| 458 | + ImmutableSet<SpecialArtifact> outputTreeArtifacts) { |
| 459 | + for (SpecialArtifact inputTreeArtifact : inputTreeArtifacts) { |
| 460 | + Preconditions.checkArgument(inputTreeArtifact.isTreeArtifact(), inputTreeArtifact); |
| 461 | + } |
| 462 | + for (SpecialArtifact outputTreeArtifact : outputTreeArtifacts) { |
| 463 | + Preconditions.checkArgument(outputTreeArtifact.isTreeArtifact(), outputTreeArtifact); |
| 464 | + } |
| 465 | + this.inputTreeArtifacts = inputTreeArtifacts; |
| 466 | + this.outputTreeArtifacts = outputTreeArtifacts; |
| 467 | + } |
| 468 | + |
| 469 | + @Override |
| 470 | + public ImmutableList<SpecialArtifact> getInputTreeArtifacts() { |
| 471 | + return inputTreeArtifacts; |
| 472 | + } |
| 473 | + |
| 474 | + @Override |
| 475 | + public ImmutableSet<Artifact> getOutputs() { |
| 476 | + return ImmutableSet.copyOf(outputTreeArtifacts); |
| 477 | + } |
| 478 | + |
| 479 | + @Override |
| 480 | + public ActionOwner getOwner() { |
| 481 | + return ActionsTestUtil.NULL_ACTION_OWNER; |
| 482 | + } |
| 483 | + |
| 484 | + @Override |
| 485 | + public boolean isShareable() { |
| 486 | + return false; |
| 487 | + } |
| 488 | + |
| 489 | + @Override |
| 490 | + public String getMnemonic() { |
| 491 | + return "TestActionTemplate"; |
| 492 | + } |
| 493 | + |
| 494 | + @Override |
| 495 | + public String getKey( |
| 496 | + ActionKeyContext actionKeyContext, @Nullable InputMetadataProvider inputMetadataProvider) { |
| 497 | + Fingerprint fp = new Fingerprint(); |
| 498 | + for (SpecialArtifact inputTreeArtifact : inputTreeArtifacts) { |
| 499 | + fp.addPath(inputTreeArtifact.getPath()); |
| 500 | + } |
| 501 | + for (SpecialArtifact outputTreeArtifact : outputTreeArtifacts) { |
| 502 | + fp.addPath(outputTreeArtifact.getPath()); |
| 503 | + } |
| 504 | + return fp.hexDigestAndReset(); |
| 505 | + } |
| 506 | + |
| 507 | + @Override |
| 508 | + public String prettyPrint() { |
| 509 | + return "TestActionTemplate for " + outputTreeArtifacts; |
| 510 | + } |
| 511 | + |
| 512 | + @Override |
| 513 | + public String describe() { |
| 514 | + return prettyPrint(); |
| 515 | + } |
| 516 | + |
| 517 | + @Override |
| 518 | + public NestedSet<Artifact> getTools() { |
| 519 | + return NestedSetBuilder.emptySet(Order.STABLE_ORDER); |
| 520 | + } |
| 521 | + |
| 522 | + @Override |
| 523 | + public NestedSet<Artifact> getInputs() { |
| 524 | + return NestedSetBuilder.wrap(Order.STABLE_ORDER, inputTreeArtifacts); |
| 525 | + } |
| 526 | + |
| 527 | + @Override |
| 528 | + public NestedSet<Artifact> getOriginalInputs() { |
| 529 | + return getInputs(); |
| 530 | + } |
| 531 | + |
| 532 | + @Override |
| 533 | + public NestedSet<Artifact> getSchedulingDependencies() { |
| 534 | + return NestedSetBuilder.emptySet(Order.STABLE_ORDER); |
| 535 | + } |
| 536 | + |
| 537 | + @Override |
| 538 | + public ImmutableList<String> getClientEnvironmentVariables() { |
| 539 | + return ImmutableList.of(); |
| 540 | + } |
| 541 | + |
| 542 | + @Override |
| 543 | + public NestedSet<Artifact> getInputFilesForExtraAction( |
| 544 | + ActionExecutionContext actionExecutionContext) { |
| 545 | + return NestedSetBuilder.emptySet(Order.STABLE_ORDER); |
| 546 | + } |
| 547 | + |
| 548 | + @Override |
| 549 | + public ImmutableSet<Artifact> getMandatoryOutputs() { |
| 550 | + return ImmutableSet.of(); |
| 551 | + } |
| 552 | + |
| 553 | + @Override |
| 554 | + public NestedSet<Artifact> getMandatoryInputs() { |
| 555 | + return NestedSetBuilder.wrap(Order.STABLE_ORDER, inputTreeArtifacts); |
| 556 | + } |
| 557 | + |
| 558 | + @Override |
| 559 | + public String toString() { |
| 560 | + return prettyPrint(); |
| 561 | + } |
| 562 | + } |
398 | 563 | } |
0 commit comments