blob: b8afb21ad93b6cbf1a5c754f0c48106b5b4383f5 [file] [log] [blame]
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +00001// Copyright 2015 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.skyframe;
Janak Ramakrishnana5578af2017-03-21 17:28:39 +000015
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000016import static com.google.common.truth.Truth.assertThat;
17import static com.google.devtools.build.lib.skyframe.FileArtifactValue.create;
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +000018import static org.junit.Assert.fail;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000019
Michajlo Matijkiw528957e2016-01-19 21:17:45 +000020import com.google.common.base.Predicate;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000021import com.google.common.collect.ImmutableList;
22import com.google.common.collect.ImmutableMap;
23import com.google.common.collect.ImmutableSet;
24import com.google.common.collect.Iterables;
25import com.google.common.testing.EqualsTester;
26import com.google.devtools.build.lib.actions.Action;
Rumou Duan33bab462016-04-25 17:55:12 +000027import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
28import com.google.devtools.build.lib.actions.ActionAnalysisMetadata.MiddlemanType;
Rumou Duan73876202016-06-06 18:52:08 +000029import com.google.devtools.build.lib.actions.ActionInputHelper;
janakr93e3eea2017-03-30 22:09:37 +000030import com.google.devtools.build.lib.actions.ActionLookupData;
31import com.google.devtools.build.lib.actions.ActionLookupValue;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000032import com.google.devtools.build.lib.actions.Artifact;
Rumou Duan73876202016-06-06 18:52:08 +000033import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
34import com.google.devtools.build.lib.actions.Artifact.SpecialArtifactType;
35import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000036import com.google.devtools.build.lib.actions.MissingInputFileException;
37import com.google.devtools.build.lib.actions.Root;
Rumou Duan73876202016-06-06 18:52:08 +000038import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000039import com.google.devtools.build.lib.actions.util.TestAction.DummyAction;
40import com.google.devtools.build.lib.events.NullEventHandler;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000041import com.google.devtools.build.lib.util.Pair;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000042import com.google.devtools.build.lib.vfs.FileStatus;
43import com.google.devtools.build.lib.vfs.FileSystemUtils;
44import com.google.devtools.build.lib.vfs.Path;
45import com.google.devtools.build.lib.vfs.PathFragment;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000046import com.google.devtools.build.skyframe.EvaluationResult;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000047import com.google.devtools.build.skyframe.SkyFunction;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000048import com.google.devtools.build.skyframe.SkyKey;
49import com.google.devtools.build.skyframe.SkyValue;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000050import java.io.IOException;
Michajlo Matijkiw528957e2016-01-19 21:17:45 +000051import java.nio.charset.StandardCharsets;
52import java.security.MessageDigest;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000053import java.util.Arrays;
54import java.util.HashMap;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000055import java.util.Map;
Janak Ramakrishnanad77f972016-07-29 20:58:42 +000056import org.junit.Before;
57import org.junit.Test;
58import org.junit.runner.RunWith;
59import org.junit.runners.JUnit4;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000060
61/**
62 * Tests for {@link ArtifactFunction}.
63 */
64// Doesn't actually need any particular Skyframe, but is only relevant to Skyframe full mode.
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +000065@RunWith(JUnit4.class)
Michael Thvedt8d5a7bb2016-02-09 03:06:34 +000066public class ArtifactFunctionTest extends ArtifactFunctionTestCase {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000067
Michajlo Matijkiw528957e2016-01-19 21:17:45 +000068 private PathFragment allowedMissingInput = null;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000069
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +000070 @Before
Florian Weikert92b22362015-12-03 10:17:18 +000071 public final void setUp() throws Exception {
Michael Thvedt8d5a7bb2016-02-09 03:06:34 +000072 delegateActionExecutionFunction = new SimpleActionExecutionFunction();
73 allowedMissingInputsPredicate = new Predicate<PathFragment>() {
74 @Override
75 public boolean apply(PathFragment input) {
76 return input.equals(allowedMissingInput);
77 }
78 };
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000079 }
80
81 private void assertFileArtifactValueMatches(boolean expectDigest) throws Throwable {
82 Artifact output = createDerivedArtifact("output");
83 Path path = output.getPath();
84 file(path, "contents");
85 assertValueMatches(path.stat(), expectDigest ? path.getMD5Digest() : null, evaluateFAN(output));
86 }
87
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +000088 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000089 public void testBasicArtifact() throws Throwable {
90 fastDigest = false;
91 assertFileArtifactValueMatches(/*expectDigest=*/ true);
92 }
93
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +000094 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000095 public void testBasicArtifactWithXattr() throws Throwable {
96 fastDigest = true;
97 assertFileArtifactValueMatches(/*expectDigest=*/ true);
98 }
99
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000100 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000101 public void testMissingNonMandatoryArtifact() throws Throwable {
102 Artifact input = createSourceArtifact("input1");
lberkie355e772017-05-31 14:34:53 +0200103 assertThat(evaluateArtifactValue(input, /*mandatory=*/ false)).isNotNull();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000104 }
105
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000106 @Test
Michajlo Matijkiw528957e2016-01-19 21:17:45 +0000107 public void testMissingMandatoryAllowedMissingArtifact() throws Throwable {
108 Artifact input = createSourceArtifact("allowedMissing");
109 allowedMissingInput = input.getRootRelativePath();
110 assertThat(evaluateArtifactValue(input, /*mandatory=*/ true))
111 .isEqualTo(FileArtifactValue.MISSING_FILE_MARKER);
112 }
113
114 @Test
115 public void testUnreadableMandatoryAllowedMissingArtifact() throws Throwable {
116 Artifact input = createSourceArtifact("allowedMissing");
117 file(input.getPath(), "allowedMissing");
118 input.getPath().chmod(0);
119
120 allowedMissingInput = input.getRootRelativePath();
121 assertThat(evaluateArtifactValue(input, /*mandatory=*/ true))
122 .isEqualTo(FileArtifactValue.MISSING_FILE_MARKER);
123 }
124
125 @Test
126 public void testUnreadableInputWithFsWithAvailableDigest() throws Throwable {
127 final byte[] expectedDigest = MessageDigest.getInstance("md5").digest(
128 "someunreadablecontent".getBytes(StandardCharsets.UTF_8));
129 setupRoot(
130 new CustomInMemoryFs() {
131 @Override
132 public byte[] getMD5Digest(Path path) throws IOException {
133 return path.getBaseName().equals("unreadable")
134 ? expectedDigest
135 : super.getMD5Digest(path);
136 }
137 });
138
139 Artifact input = createSourceArtifact("unreadable");
140 Path inputPath = input.getPath();
141 file(inputPath, "dummynotused");
142 inputPath.chmod(0);
143
144 FileArtifactValue value =
145 (FileArtifactValue) evaluateArtifactValue(input, /*mandatory=*/ true);
146
147 FileStatus stat = inputPath.stat();
148 assertThat(value.getSize()).isEqualTo(stat.getSize());
149 assertThat(value.getDigest()).isEqualTo(expectedDigest);
150 }
151
152 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000153 public void testMissingMandatoryArtifact() throws Throwable {
154 Artifact input = createSourceArtifact("input1");
155 try {
156 evaluateArtifactValue(input, /*mandatory=*/ true);
157 fail();
158 } catch (MissingInputFileException ex) {
159 // Expected.
160 }
161 }
162
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000163 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000164 public void testMiddlemanArtifact() throws Throwable {
Janak Ramakrishnana5578af2017-03-21 17:28:39 +0000165 Artifact output = createMiddlemanArtifact("output");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000166 Artifact input1 = createSourceArtifact("input1");
167 Artifact input2 = createDerivedArtifact("input2");
168 Action action =
169 new DummyAction(
170 ImmutableList.of(input1, input2), output, MiddlemanType.AGGREGATING_MIDDLEMAN);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000171 actions.add(action);
172 file(input2.getPath(), "contents");
173 file(input1.getPath(), "source contents");
174 evaluate(
175 Iterables.toArray(
Janak Ramakrishnanad77f972016-07-29 20:58:42 +0000176 ArtifactSkyKey.mandatoryKeys(ImmutableSet.of(input2, input1, input2)), SkyKey.class));
177 SkyValue value = evaluateArtifactValue(output);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000178 assertThat(((AggregatingArtifactValue) value).getInputs())
179 .containsExactly(Pair.of(input1, create(input1)), Pair.of(input2, create(input2)));
180 }
181
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000182 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000183 public void testIOException() throws Exception {
184 fastDigest = false;
185 final IOException exception = new IOException("beep");
186 setupRoot(
187 new CustomInMemoryFs() {
188 @Override
189 public byte[] getMD5Digest(Path path) throws IOException {
190 throw exception;
191 }
192 });
193 Artifact artifact = createDerivedArtifact("no-read");
194 writeFile(artifact.getPath(), "content");
195 try {
196 create(createDerivedArtifact("no-read"));
197 fail();
198 } catch (IOException e) {
lberkiaea56b32017-05-30 12:35:33 +0200199 assertThat(e).isSameAs(exception);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000200 }
201 }
202
203 /**
204 * Tests that ArtifactFunction rethrows transitive {@link IOException}s as
205 * {@link MissingInputFileException}s.
206 */
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000207 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000208 public void testIOException_EndToEnd() throws Throwable {
209 final IOException exception = new IOException("beep");
210 setupRoot(
211 new CustomInMemoryFs() {
212 @Override
213 public FileStatus stat(Path path, boolean followSymlinks) throws IOException {
214 if (path.getBaseName().equals("bad")) {
215 throw exception;
216 }
217 return super.stat(path, followSymlinks);
218 }
219 });
220 try {
221 evaluateArtifactValue(createSourceArtifact("bad"));
222 fail();
223 } catch (MissingInputFileException e) {
lberkiaea56b32017-05-30 12:35:33 +0200224 assertThat(e).hasMessageThat().contains(exception.getMessage());
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000225 }
226 }
227
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000228 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000229 public void testNoMtimeIfNonemptyFile() throws Exception {
230 Artifact artifact = createDerivedArtifact("no-digest");
231 Path path = artifact.getPath();
232 writeFile(path, "hello"); //Non-empty file.
233 FileArtifactValue value = create(artifact);
lberkiaea56b32017-05-30 12:35:33 +0200234 assertThat(value.getDigest()).isEqualTo(path.getMD5Digest());
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000235 try {
236 value.getModifiedTime();
237 fail("mtime for non-empty file should not be stored.");
Janak Ramakrishnanad77f972016-07-29 20:58:42 +0000238 } catch (UnsupportedOperationException e) {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000239 // Expected.
240 }
241 }
242
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000243 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000244 public void testDirectory() throws Exception {
245 Artifact artifact = createDerivedArtifact("dir");
246 Path path = artifact.getPath();
247 FileSystemUtils.createDirectoryAndParents(path);
248 path.setLastModifiedTime(1L);
249 FileArtifactValue value = create(artifact);
lberkiaea56b32017-05-30 12:35:33 +0200250 assertThat(value.getDigest()).isNull();
251 assertThat(value.getModifiedTime()).isEqualTo(1L);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000252 }
253
Janak Ramakrishnan08b0f7f2016-07-13 17:00:59 +0000254 // Empty files are the same as normal files -- mtime is not stored.
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000255 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000256 public void testEmptyFile() throws Exception {
257 Artifact artifact = createDerivedArtifact("empty");
258 Path path = artifact.getPath();
259 writeFile(path, "");
260 path.setLastModifiedTime(1L);
261 FileArtifactValue value = create(artifact);
lberkiaea56b32017-05-30 12:35:33 +0200262 assertThat(value.getDigest()).isEqualTo(path.getMD5Digest());
263 assertThat(value.getSize()).isEqualTo(0L);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000264 }
265
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000266 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000267 public void testEquality() throws Exception {
268 Artifact artifact1 = createDerivedArtifact("artifact1");
269 Artifact artifact2 = createDerivedArtifact("artifact2");
270 Artifact diffDigest = createDerivedArtifact("diffDigest");
271 Artifact diffMtime = createDerivedArtifact("diffMtime");
272 Artifact empty1 = createDerivedArtifact("empty1");
273 Artifact empty2 = createDerivedArtifact("empty2");
274 Artifact empty3 = createDerivedArtifact("empty3");
275 Artifact dir1 = createDerivedArtifact("dir1");
276 Artifact dir2 = createDerivedArtifact("dir2");
277 Artifact dir3 = createDerivedArtifact("dir3");
278 Path path1 = artifact1.getPath();
279 Path path2 = artifact2.getPath();
280 Path digestPath = diffDigest.getPath();
281 Path mtimePath = diffMtime.getPath();
282 writeFile(artifact1.getPath(), "content");
283 writeFile(artifact2.getPath(), "content");
284 path1.setLastModifiedTime(0);
285 path2.setLastModifiedTime(0);
286 writeFile(diffDigest.getPath(), "1234567"); // Same size as artifact1.
287 digestPath.setLastModifiedTime(0);
288 writeFile(mtimePath, "content");
289 mtimePath.setLastModifiedTime(1);
290 Path emptyPath1 = empty1.getPath();
291 Path emptyPath2 = empty2.getPath();
292 Path emptyPath3 = empty3.getPath();
293 writeFile(emptyPath1, "");
294 writeFile(emptyPath2, "");
295 writeFile(emptyPath3, "");
296 emptyPath1.setLastModifiedTime(0L);
297 emptyPath2.setLastModifiedTime(1L);
298 emptyPath3.setLastModifiedTime(1L);
299 Path dirPath1 = dir1.getPath();
300 Path dirPath2 = dir2.getPath();
301 Path dirPath3 = dir3.getPath();
302 FileSystemUtils.createDirectoryAndParents(dirPath1);
303 FileSystemUtils.createDirectoryAndParents(dirPath2);
304 FileSystemUtils.createDirectoryAndParents(dirPath3);
305 dirPath1.setLastModifiedTime(0L);
306 dirPath2.setLastModifiedTime(1L);
307 dirPath3.setLastModifiedTime(1L);
308 EqualsTester equalsTester = new EqualsTester();
309 equalsTester
310 .addEqualityGroup(create(artifact1), create(artifact2), create(diffMtime))
Janak Ramakrishnan08b0f7f2016-07-13 17:00:59 +0000311 .addEqualityGroup(create(empty1), create(empty2), create(empty3))
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000312 .addEqualityGroup(create(dir1))
313 .addEqualityGroup(create(dir2), create(dir3))
314 .testEquals();
315 }
316
Rumou Duan73876202016-06-06 18:52:08 +0000317 @Test
318 public void testActionTreeArtifactOutput() throws Throwable {
319 Artifact artifact = createDerivedTreeArtifactWithAction("treeArtifact");
320 TreeFileArtifact treeFileArtifact1 = createFakeTreeFileArtifact(artifact, "child1", "hello1");
321 TreeFileArtifact treeFileArtifact2 = createFakeTreeFileArtifact(artifact, "child2", "hello2");
322
323 TreeArtifactValue value = (TreeArtifactValue) evaluateArtifactValue(artifact);
lberkiaea56b32017-05-30 12:35:33 +0200324 assertThat(value.getChildValues().get(treeFileArtifact1)).isNotNull();
325 assertThat(value.getChildValues().get(treeFileArtifact2)).isNotNull();
326 assertThat(value.getChildValues().get(treeFileArtifact1).getDigest()).isNotNull();
327 assertThat(value.getChildValues().get(treeFileArtifact2).getDigest()).isNotNull();
Rumou Duan73876202016-06-06 18:52:08 +0000328 }
329
330 @Test
331 public void testSpawnActionTemplate() throws Throwable {
332 // artifact1 is a tree artifact generated by normal action.
333 Artifact artifact1 = createDerivedTreeArtifactWithAction("treeArtifact1");
334 createFakeTreeFileArtifact(artifact1, "child1", "hello1");
335 createFakeTreeFileArtifact(artifact1, "child2", "hello2");
336
337
338 // artifact2 is a tree artifact generated by action template.
339 Artifact artifact2 = createDerivedTreeArtifactOnly("treeArtifact2");
340 TreeFileArtifact treeFileArtifact1 = createFakeTreeFileArtifact(artifact2, "child1", "hello1");
341 TreeFileArtifact treeFileArtifact2 = createFakeTreeFileArtifact(artifact2, "child2", "hello2");
342
343 actions.add(
344 ActionsTestUtil.createDummySpawnActionTemplate(artifact1, artifact2));
345
346 TreeArtifactValue value = (TreeArtifactValue) evaluateArtifactValue(artifact2);
lberkiaea56b32017-05-30 12:35:33 +0200347 assertThat(value.getChildValues().get(treeFileArtifact1)).isNotNull();
348 assertThat(value.getChildValues().get(treeFileArtifact2)).isNotNull();
349 assertThat(value.getChildValues().get(treeFileArtifact1).getDigest()).isNotNull();
350 assertThat(value.getChildValues().get(treeFileArtifact2).getDigest()).isNotNull();
Rumou Duan73876202016-06-06 18:52:08 +0000351 }
352
353 @Test
354 public void testConsecutiveSpawnActionTemplates() throws Throwable {
355 // artifact1 is a tree artifact generated by normal action.
356 Artifact artifact1 = createDerivedTreeArtifactWithAction("treeArtifact1");
357 createFakeTreeFileArtifact(artifact1, "child1", "hello1");
358 createFakeTreeFileArtifact(artifact1, "child2", "hello2");
359
360 // artifact2 is a tree artifact generated by action template.
361 Artifact artifact2 = createDerivedTreeArtifactOnly("treeArtifact2");
362 createFakeTreeFileArtifact(artifact2, "child1", "hello1");
363 createFakeTreeFileArtifact(artifact2, "child2", "hello2");
364 actions.add(
365 ActionsTestUtil.createDummySpawnActionTemplate(artifact1, artifact2));
366
367 // artifact3 is a tree artifact generated by action template.
368 Artifact artifact3 = createDerivedTreeArtifactOnly("treeArtifact3");
369 TreeFileArtifact treeFileArtifact1 = createFakeTreeFileArtifact(artifact3, "child1", "hello1");
370 TreeFileArtifact treeFileArtifact2 = createFakeTreeFileArtifact(artifact3, "child2", "hello2");
371 actions.add(
372 ActionsTestUtil.createDummySpawnActionTemplate(artifact2, artifact3));
373
374 TreeArtifactValue value = (TreeArtifactValue) evaluateArtifactValue(artifact3);
lberkiaea56b32017-05-30 12:35:33 +0200375 assertThat(value.getChildValues().get(treeFileArtifact1)).isNotNull();
376 assertThat(value.getChildValues().get(treeFileArtifact2)).isNotNull();
377 assertThat(value.getChildValues().get(treeFileArtifact1).getDigest()).isNotNull();
378 assertThat(value.getChildValues().get(treeFileArtifact2).getDigest()).isNotNull();
Rumou Duan73876202016-06-06 18:52:08 +0000379 }
380
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000381 private void file(Path path, String contents) throws Exception {
382 FileSystemUtils.createDirectoryAndParents(path.getParentDirectory());
383 writeFile(path, contents);
384 }
385
386 private Artifact createSourceArtifact(String path) {
nharmatab4060b62017-04-04 17:11:39 +0000387 return new Artifact(PathFragment.create(path), Root.asSourceRoot(root));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000388 }
389
390 private Artifact createDerivedArtifact(String path) {
nharmatab4060b62017-04-04 17:11:39 +0000391 PathFragment execPath = PathFragment.create("out").getRelative(path);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000392 Path fullPath = root.getRelative(execPath);
393 Artifact output =
394 new Artifact(
395 fullPath, Root.asDerivedRoot(root, root.getRelative("out")), execPath, ALL_OWNER);
396 actions.add(new DummyAction(ImmutableList.<Artifact>of(), output));
397 return output;
398 }
399
Janak Ramakrishnana5578af2017-03-21 17:28:39 +0000400 private Artifact createMiddlemanArtifact(String path) {
401 Root middlemanRoot = Root.middlemanRoot(middlemanPath, middlemanPath.getRelative("out"));
402 Path fullPath = middlemanRoot.getPath().getRelative(path);
403 return new Artifact(
404 fullPath, middlemanRoot, fullPath.relativeTo(middlemanRoot.getExecRoot()), ALL_OWNER);
405 }
406
Rumou Duan73876202016-06-06 18:52:08 +0000407 private Artifact createDerivedTreeArtifactWithAction(String path) {
408 Artifact treeArtifact = createDerivedTreeArtifactOnly(path);
409 actions.add(new DummyAction(ImmutableList.<Artifact>of(), treeArtifact));
410 return treeArtifact;
411 }
412
413 private Artifact createDerivedTreeArtifactOnly(String path) {
nharmatab4060b62017-04-04 17:11:39 +0000414 PathFragment execPath = PathFragment.create("out").getRelative(path);
Rumou Duan73876202016-06-06 18:52:08 +0000415 Path fullPath = root.getRelative(execPath);
416 return new SpecialArtifact(
417 fullPath,
418 Root.asDerivedRoot(root, root.getRelative("out")),
419 execPath,
420 ALL_OWNER,
421 SpecialArtifactType.TREE);
422 }
423
424 private TreeFileArtifact createFakeTreeFileArtifact(Artifact treeArtifact,
425 String parentRelativePath, String content) throws Exception {
426 TreeFileArtifact treeFileArtifact = ActionInputHelper.treeFileArtifact(
nharmatab4060b62017-04-04 17:11:39 +0000427 treeArtifact, PathFragment.create(parentRelativePath));
Rumou Duan73876202016-06-06 18:52:08 +0000428 Path path = treeFileArtifact.getPath();
429 FileSystemUtils.createDirectoryAndParents(path.getParentDirectory());
430 writeFile(path, content);
431 return treeFileArtifact;
432 }
433
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000434 private void assertValueMatches(FileStatus file, byte[] digest, FileArtifactValue value)
435 throws IOException {
lberkiaea56b32017-05-30 12:35:33 +0200436 assertThat(value.getSize()).isEqualTo(file.getSize());
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000437 if (digest == null) {
lberkiaea56b32017-05-30 12:35:33 +0200438 assertThat(value.getDigest()).isNull();
439 assertThat(value.getModifiedTime()).isEqualTo(file.getLastModifiedTime());
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000440 } else {
lberkiaea56b32017-05-30 12:35:33 +0200441 assertThat(value.getDigest()).isEqualTo(digest);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000442 }
443 }
444
445 private FileArtifactValue evaluateFAN(Artifact artifact) throws Throwable {
446 return ((FileArtifactValue) evaluateArtifactValue(artifact));
447 }
448
Janak Ramakrishnanad77f972016-07-29 20:58:42 +0000449 private SkyValue evaluateArtifactValue(Artifact artifact) throws Throwable {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000450 return evaluateArtifactValue(artifact, /*isMandatory=*/ true);
451 }
452
Janak Ramakrishnanad77f972016-07-29 20:58:42 +0000453 private SkyValue evaluateArtifactValue(Artifact artifact, boolean mandatory) throws Throwable {
454 SkyKey key = ArtifactSkyKey.key(artifact, mandatory);
455 EvaluationResult<SkyValue> result = evaluate(ImmutableList.of(key).toArray(new SkyKey[0]));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000456 if (result.hasError()) {
457 throw result.getError().getException();
458 }
459 return result.get(key);
460 }
461
462 private void setGeneratingActions() {
463 if (evaluator.getExistingValueForTesting(OWNER_KEY) == null) {
janakr93e3eea2017-03-30 22:09:37 +0000464 differencer.inject(
465 ImmutableMap.of(
466 OWNER_KEY,
467 new ActionLookupValue(ImmutableList.<ActionAnalysisMetadata>copyOf(actions), false)));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000468 }
469 }
470
471 private <E extends SkyValue> EvaluationResult<E> evaluate(SkyKey... keys)
472 throws InterruptedException {
473 setGeneratingActions();
474 return driver.evaluate(
Rumou Duan73876202016-06-06 18:52:08 +0000475 Arrays.asList(keys),
476 /*keepGoing=*/false,
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000477 SkyframeExecutor.DEFAULT_THREAD_COUNT,
478 NullEventHandler.INSTANCE);
479 }
480
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000481 /** Value Builder for actions that just stats and stores the output file (which must exist). */
Rumou Duan73876202016-06-06 18:52:08 +0000482 private static class SimpleActionExecutionFunction implements SkyFunction {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000483 @Override
janakr93e3eea2017-03-30 22:09:37 +0000484 public SkyValue compute(SkyKey skyKey, Environment env) throws InterruptedException {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000485 Map<Artifact, FileValue> artifactData = new HashMap<>();
Rumou Duan73876202016-06-06 18:52:08 +0000486 Map<Artifact, TreeArtifactValue> treeArtifactData = new HashMap<>();
487 Map<Artifact, FileArtifactValue> additionalOutputData = new HashMap<>();
janakr93e3eea2017-03-30 22:09:37 +0000488 ActionLookupData actionLookupData = (ActionLookupData) skyKey.argument();
489 ActionLookupValue actionLookupValue =
490 (ActionLookupValue) env.getValue(actionLookupData.getActionLookupNode());
491 Action action = actionLookupValue.getAction(actionLookupData.getActionIndex());
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000492 Artifact output = Iterables.getOnlyElement(action.getOutputs());
Rumou Duan73876202016-06-06 18:52:08 +0000493
494 try {
495 if (output.isTreeArtifact()) {
496 TreeFileArtifact treeFileArtifact1 = ActionInputHelper.treeFileArtifact(
nharmatab4060b62017-04-04 17:11:39 +0000497 output, PathFragment.create("child1"));
Rumou Duan73876202016-06-06 18:52:08 +0000498 TreeFileArtifact treeFileArtifact2 = ActionInputHelper.treeFileArtifact(
nharmatab4060b62017-04-04 17:11:39 +0000499 output, PathFragment.create("child2"));
Rumou Duan73876202016-06-06 18:52:08 +0000500 TreeArtifactValue treeArtifactValue = TreeArtifactValue.create(ImmutableMap.of(
501 treeFileArtifact1, FileArtifactValue.create(treeFileArtifact1),
502 treeFileArtifact2, FileArtifactValue.create(treeFileArtifact2)));
503 treeArtifactData.put(output, treeArtifactValue);
504 } else if (action.getActionType() == MiddlemanType.NORMAL) {
Rumou Duana77f32c2016-04-13 21:59:21 +0000505 FileValue fileValue = ActionMetadataHandler.fileValueFromArtifact(output, null, null);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000506 artifactData.put(output, fileValue);
Rumou Duan73876202016-06-06 18:52:08 +0000507 additionalOutputData.put(output, FileArtifactValue.create(output, fileValue));
508 } else {
509 additionalOutputData.put(output, FileArtifactValue.DEFAULT_MIDDLEMAN);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000510 }
Rumou Duan73876202016-06-06 18:52:08 +0000511 } catch (IOException e) {
512 throw new IllegalStateException(e);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000513 }
Michael Thvedt8d5a7bb2016-02-09 03:06:34 +0000514 return new ActionExecutionValue(
515 artifactData,
Rumou Duan73876202016-06-06 18:52:08 +0000516 treeArtifactData,
517 additionalOutputData);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000518 }
519
520 @Override
521 public String extractTag(SkyKey skyKey) {
522 return null;
523 }
524 }
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000525}