blob: 846d51593f6d484df71bd2c778533687e267b7fc [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;
15
16import static com.google.common.truth.Truth.assertThat;
lberkiaea56b32017-05-30 12:35:33 +020017import static com.google.common.truth.Truth.assertWithMessage;
jcater83130f42019-04-30 14:29:28 -070018import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000019
20import com.google.common.collect.ImmutableList;
21import com.google.common.collect.ImmutableMap;
22import com.google.common.collect.ImmutableSet;
buchgr4992ae22019-03-20 04:23:32 -070023import com.google.common.hash.HashCode;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000024import com.google.common.util.concurrent.Runnables;
25import com.google.devtools.build.lib.actions.Action;
buchgr4992ae22019-03-20 04:23:32 -070026import com.google.devtools.build.lib.actions.ActionInputHelper;
janakrefb3f152019-06-05 17:42:34 -070027import com.google.devtools.build.lib.actions.ActionLookupData;
janakr93e3eea2017-03-30 22:09:37 +000028import com.google.devtools.build.lib.actions.ActionLookupValue.ActionLookupKey;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000029import com.google.devtools.build.lib.actions.Artifact;
Michael Thvedte4a7b0792016-02-09 12:15:53 +000030import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
31import com.google.devtools.build.lib.actions.Artifact.SpecialArtifactType;
Rumou Duana77f32c2016-04-13 21:59:21 +000032import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
janakr0c42fc82018-09-14 10:37:25 -070033import com.google.devtools.build.lib.actions.ArtifactFileMetadata;
tomlu1cdcdf92018-01-16 11:07:51 -080034import com.google.devtools.build.lib.actions.ArtifactRoot;
shahan602cc852018-06-06 20:09:57 -070035import com.google.devtools.build.lib.actions.FileArtifactValue;
buchgr4992ae22019-03-20 04:23:32 -070036import com.google.devtools.build.lib.actions.FileArtifactValue.RemoteFileArtifactValue;
shahan602cc852018-06-06 20:09:57 -070037import com.google.devtools.build.lib.actions.FileStateValue;
38import com.google.devtools.build.lib.actions.FileValue;
janakraea05602019-05-22 15:41:29 -070039import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000040import com.google.devtools.build.lib.actions.util.TestAction;
Kristina Chodorowf9fdc8d2015-12-08 12:49:31 +000041import com.google.devtools.build.lib.analysis.BlazeDirectories;
janakr3b63a4e2017-09-14 09:55:40 +020042import com.google.devtools.build.lib.analysis.ServerDirectories;
Kristina Chodorowf9fdc8d2015-12-08 12:49:31 +000043import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000044import com.google.devtools.build.lib.events.NullEventHandler;
janakr15e15c22019-01-30 11:24:49 -080045import com.google.devtools.build.lib.packages.WorkspaceFileValue;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000046import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
47import com.google.devtools.build.lib.skyframe.DirtinessCheckerUtils.BasicFilesystemDirtinessChecker;
Nathan Harmatad4f75942016-10-18 08:55:17 +000048import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction;
John Cater5e9ce942016-10-12 17:23:30 +000049import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy;
Luis Fernando Pino Duquebe102182016-05-23 14:03:55 +000050import com.google.devtools.build.lib.testutil.TestConstants;
Kristina Chodorowf9fdc8d2015-12-08 12:49:31 +000051import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
laszlocsomor29bdf632018-03-13 02:50:46 -070052import com.google.devtools.build.lib.testutil.TimestampGranularityUtils;
Laszlo Csomora278aec2018-03-09 04:07:31 -080053import com.google.devtools.build.lib.util.io.OutErr;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000054import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
55import com.google.devtools.build.lib.vfs.BatchStat;
buchgr4992ae22019-03-20 04:23:32 -070056import com.google.devtools.build.lib.vfs.DigestHashFunction;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000057import com.google.devtools.build.lib.vfs.FileStatus;
58import com.google.devtools.build.lib.vfs.FileStatusWithDigest;
59import com.google.devtools.build.lib.vfs.FileStatusWithDigestAdapter;
60import com.google.devtools.build.lib.vfs.FileSystemUtils;
Eric Fellheimere6590722015-11-17 17:07:48 +000061import com.google.devtools.build.lib.vfs.ModifiedFileSet;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000062import com.google.devtools.build.lib.vfs.Path;
63import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080064import com.google.devtools.build.lib.vfs.Root;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000065import com.google.devtools.build.lib.vfs.RootedPath;
66import com.google.devtools.build.lib.vfs.Symlinks;
djasper7faa0ef2019-03-28 10:00:00 -070067import com.google.devtools.build.lib.vfs.UnixGlob;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000068import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
69import com.google.devtools.build.skyframe.Differencer.Diff;
Googler10028672018-10-25 12:14:34 -070070import com.google.devtools.build.skyframe.EvaluationContext;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000071import com.google.devtools.build.skyframe.EvaluationResult;
72import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator;
73import com.google.devtools.build.skyframe.MemoizingEvaluator;
74import com.google.devtools.build.skyframe.RecordingDifferencer;
janakr1cde8722017-10-10 03:22:21 +020075import com.google.devtools.build.skyframe.SequencedRecordingDifferencer;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000076import com.google.devtools.build.skyframe.SequentialBuildDriver;
77import com.google.devtools.build.skyframe.SkyFunction;
78import com.google.devtools.build.skyframe.SkyFunctionName;
79import com.google.devtools.build.skyframe.SkyKey;
80import com.google.devtools.build.skyframe.SkyValue;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000081import java.io.IOException;
82import java.util.ArrayList;
83import java.util.Arrays;
84import java.util.Collection;
buchgr4992ae22019-03-20 04:23:32 -070085import java.util.Collections;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000086import java.util.HashMap;
87import java.util.List;
88import java.util.Map;
89import java.util.UUID;
90import java.util.concurrent.atomic.AtomicReference;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000091import javax.annotation.Nullable;
Janak Ramakrishnancba16452016-07-29 02:17:02 +000092import org.junit.Before;
93import org.junit.Test;
94import org.junit.runner.RunWith;
95import org.junit.runners.JUnit4;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +000096
97/**
98 * Tests for {@link FilesystemValueChecker}.
99 */
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000100@RunWith(JUnit4.class)
101public class FilesystemValueCheckerTest {
Googler10028672018-10-25 12:14:34 -0700102 private static final EvaluationContext EVALUATION_OPTIONS =
103 EvaluationContext.newBuilder()
104 .setKeepGoing(false)
105 .setNumThreads(SkyframeExecutor.DEFAULT_THREAD_COUNT)
106 .setEventHander(NullEventHandler.INSTANCE)
107 .build();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000108
109 private RecordingDifferencer differencer;
110 private MemoizingEvaluator evaluator;
111 private SequentialBuildDriver driver;
112 private MockFileSystem fs;
113 private Path pkgRoot;
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000114
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000115 @Before
Florian Weikert92b22362015-12-03 10:17:18 +0000116 public final void setUp() throws Exception {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000117 ImmutableMap.Builder<SkyFunctionName, SkyFunction> skyFunctions = ImmutableMap.builder();
118
119 fs = new MockFileSystem();
120 pkgRoot = fs.getPath("/testroot");
Kristina Chodorowf9fdc8d2015-12-08 12:49:31 +0000121 FileSystemUtils.createDirectoryAndParents(pkgRoot);
122 FileSystemUtils.createEmptyFile(pkgRoot.getRelative("WORKSPACE"));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000123
John Catere0d1d0e2017-11-28 20:47:41 -0800124 AtomicReference<PathPackageLocator> pkgLocator =
125 new AtomicReference<>(
126 new PathPackageLocator(
127 fs.getPath("/output_base"),
tomluee6a6862018-01-17 14:36:26 -0800128 ImmutableList.of(Root.fromPath(pkgRoot)),
John Catere0d1d0e2017-11-28 20:47:41 -0800129 BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY));
janakr3b63a4e2017-09-14 09:55:40 +0200130 BlazeDirectories directories =
131 new BlazeDirectories(
cushon849df362018-05-14 01:51:45 -0700132 new ServerDirectories(pkgRoot, pkgRoot, pkgRoot),
133 pkgRoot,
134 /* defaultSystemJavabase= */ null,
135 TestConstants.PRODUCT_NAME);
nharmata3fb7d342018-02-23 11:37:51 -0800136 ExternalFilesHelper externalFilesHelper = ExternalFilesHelper.createForTesting(
Nathan Harmatad4f75942016-10-18 08:55:17 +0000137 pkgLocator, ExternalFileAction.DEPEND_ON_EXTERNAL_PKG_FOR_EXTERNAL_REPO_PATHS, directories);
shahan602cc852018-06-06 20:09:57 -0700138 skyFunctions.put(
139 FileStateValue.FILE_STATE,
140 new FileStateFunction(
djasper7faa0ef2019-03-28 10:00:00 -0700141 new AtomicReference<TimestampGranularityMonitor>(),
142 new AtomicReference<>(UnixGlob.DEFAULT_SYSCALLS),
143 externalFilesHelper));
shahan602cc852018-06-06 20:09:57 -0700144 skyFunctions.put(FileValue.FILE, new FileFunction(pkgLocator));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000145 skyFunctions.put(
146 SkyFunctions.FILE_SYMLINK_CYCLE_UNIQUENESS, new FileSymlinkCycleUniquenessFunction());
147 skyFunctions.put(
148 SkyFunctions.FILE_SYMLINK_INFINITE_EXPANSION_UNIQUENESS,
149 new FileSymlinkInfiniteExpansionUniquenessFunction());
Kristina Chodorowf9fdc8d2015-12-08 12:49:31 +0000150 skyFunctions.put(SkyFunctions.PACKAGE,
151 new PackageFunction(null, null, null, null, null, null, null));
John Cater5e9ce942016-10-12 17:23:30 +0000152 skyFunctions.put(
153 SkyFunctions.PACKAGE_LOOKUP,
154 new PackageLookupFunction(
155 new AtomicReference<>(ImmutableSet.<PackageIdentifier>of()),
John Cater0c0735a2016-11-11 01:52:02 +0000156 CrossRepositoryLabelViolationStrategy.ERROR,
John Catere0d1d0e2017-11-28 20:47:41 -0800157 BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY));
Damien Martin-Guillerez4ecfe512016-01-22 11:03:23 +0000158 skyFunctions.put(SkyFunctions.WORKSPACE_AST,
159 new WorkspaceASTFunction(TestRuleClassProvider.getRuleClassProvider()));
carmid6a98282018-03-13 19:19:16 -0700160 skyFunctions.put(
janakr15e15c22019-01-30 11:24:49 -0800161 WorkspaceFileValue.WORKSPACE_FILE,
carmid6a98282018-03-13 19:19:16 -0700162 new WorkspaceFileFunction(
163 TestRuleClassProvider.getRuleClassProvider(),
164 TestConstants.PACKAGE_FACTORY_BUILDER_FACTORY_FOR_TESTING
165 .builder(directories)
nharmatafde0bd2f2018-12-21 10:17:56 -0800166 .build(TestRuleClassProvider.getRuleClassProvider(), fs),
mjhalupkaf0e48112019-01-14 13:01:56 -0800167 directories,
168 /*skylarkImportLookupFunctionForInlining=*/ null));
Damien Martin-Guillerezbc8b5e02016-02-05 22:09:09 +0000169 skyFunctions.put(SkyFunctions.EXTERNAL_PACKAGE, new ExternalPackageFunction());
Kristina Chodorowf9fdc8d2015-12-08 12:49:31 +0000170
janakr1cde8722017-10-10 03:22:21 +0200171 differencer = new SequencedRecordingDifferencer();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000172 evaluator = new InMemoryMemoizingEvaluator(skyFunctions.build(), differencer);
173 driver = new SequentialBuildDriver(evaluator);
174 PrecomputedValue.BUILD_ID.set(differencer, UUID.randomUUID());
Kristina Chodorowf9fdc8d2015-12-08 12:49:31 +0000175 PrecomputedValue.PATH_PACKAGE_LOCATOR.set(differencer, pkgLocator.get());
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000176 }
177
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000178 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000179 public void testEmpty() throws Exception {
Ulf Adamsc73051c62016-03-23 09:18:13 +0000180 FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
Nathan Harmata8cd29782015-11-10 03:24:01 +0000181 assertEmptyDiff(getDirtyFilesystemKeys(evaluator, checker));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000182 }
183
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000184 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000185 public void testSimple() throws Exception {
Ulf Adamsc73051c62016-03-23 09:18:13 +0000186 FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000187
188 Path path = fs.getPath("/foo");
189 FileSystemUtils.createEmptyFile(path);
Nathan Harmata8cd29782015-11-10 03:24:01 +0000190 assertEmptyDiff(getDirtyFilesystemKeys(evaluator, checker));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000191
tomluee6a6862018-01-17 14:36:26 -0800192 SkyKey skyKey =
193 FileStateValue.key(
tomlu4c9fafd2018-01-18 10:29:11 -0800194 RootedPath.toRootedPath(Root.absoluteRoot(fs), PathFragment.create("/foo")));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000195 EvaluationResult<SkyValue> result =
Googler10028672018-10-25 12:14:34 -0700196 driver.evaluate(ImmutableList.of(skyKey), EVALUATION_OPTIONS);
lberkiaea56b32017-05-30 12:35:33 +0200197 assertThat(result.hasError()).isFalse();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000198
Nathan Harmata8cd29782015-11-10 03:24:01 +0000199 assertEmptyDiff(getDirtyFilesystemKeys(evaluator, checker));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000200
201 FileSystemUtils.writeContentAsLatin1(path, "hello");
Nathan Harmata8cd29782015-11-10 03:24:01 +0000202 assertDiffWithNewValues(getDirtyFilesystemKeys(evaluator, checker), skyKey);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000203
204 // The dirty bits are not reset until the FileValues are actually revalidated.
Nathan Harmata8cd29782015-11-10 03:24:01 +0000205 assertDiffWithNewValues(getDirtyFilesystemKeys(evaluator, checker), skyKey);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000206
207 differencer.invalidate(ImmutableList.of(skyKey));
Googler10028672018-10-25 12:14:34 -0700208 result = driver.evaluate(ImmutableList.of(skyKey), EVALUATION_OPTIONS);
lberkiaea56b32017-05-30 12:35:33 +0200209 assertThat(result.hasError()).isFalse();
Nathan Harmata8cd29782015-11-10 03:24:01 +0000210 assertEmptyDiff(getDirtyFilesystemKeys(evaluator, checker));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000211 }
212
213 /**
214 * Tests that an already-invalidated value can still be marked changed: symlink points at sym1.
215 * Invalidate symlink by changing sym1 from pointing at path to point to sym2. This only dirties
216 * (rather than changes) symlink because sym2 still points at path, so all symlink stats remain
217 * the same. Then do a null build, change sym1 back to point at path, and change symlink to not be
218 * a symlink anymore. The fact that it is not a symlink should be detected.
219 */
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000220 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000221 public void testDirtySymlink() throws Exception {
Ulf Adamsc73051c62016-03-23 09:18:13 +0000222 FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000223
224 Path path = fs.getPath("/foo");
225 FileSystemUtils.writeContentAsLatin1(path, "foo contents");
226 // We need the intermediate sym1 and sym2 so that we can dirty a child of symlink without
227 // actually changing the FileValue calculated for symlink (if we changed the contents of foo,
Laszlo Csomora278aec2018-03-09 04:07:31 -0800228 // the FileValue created for symlink would notice, since it stats foo).
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000229 Path sym1 = fs.getPath("/sym1");
230 Path sym2 = fs.getPath("/sym2");
231 Path symlink = fs.getPath("/bar");
232 FileSystemUtils.ensureSymbolicLink(symlink, sym1);
233 FileSystemUtils.ensureSymbolicLink(sym1, path);
234 FileSystemUtils.ensureSymbolicLink(sym2, path);
235 SkyKey fooKey =
tomlu4c9fafd2018-01-18 10:29:11 -0800236 FileValue.key(RootedPath.toRootedPath(Root.absoluteRoot(fs), PathFragment.create("/foo")));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000237 RootedPath symlinkRootedPath =
tomlu4c9fafd2018-01-18 10:29:11 -0800238 RootedPath.toRootedPath(Root.absoluteRoot(fs), PathFragment.create("/bar"));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000239 SkyKey symlinkKey = FileValue.key(symlinkRootedPath);
240 SkyKey symlinkFileStateKey = FileStateValue.key(symlinkRootedPath);
241 RootedPath sym1RootedPath =
tomlu4c9fafd2018-01-18 10:29:11 -0800242 RootedPath.toRootedPath(Root.absoluteRoot(fs), PathFragment.create("/sym1"));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000243 SkyKey sym1FileStateKey = FileStateValue.key(sym1RootedPath);
244 Iterable<SkyKey> allKeys = ImmutableList.of(symlinkKey, fooKey);
245
246 // First build -- prime the graph.
Googler10028672018-10-25 12:14:34 -0700247 EvaluationResult<FileValue> result = driver.evaluate(allKeys, EVALUATION_OPTIONS);
lberkiaea56b32017-05-30 12:35:33 +0200248 assertThat(result.hasError()).isFalse();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000249 FileValue symlinkValue = result.get(symlinkKey);
250 FileValue fooValue = result.get(fooKey);
lberkiaea56b32017-05-30 12:35:33 +0200251 assertWithMessage(symlinkValue.toString()).that(symlinkValue.isSymlink()).isTrue();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000252 // Digest is not always available, so use size as a proxy for contents.
lberkiaea56b32017-05-30 12:35:33 +0200253 assertThat(symlinkValue.getSize()).isEqualTo(fooValue.getSize());
Nathan Harmata8cd29782015-11-10 03:24:01 +0000254 assertEmptyDiff(getDirtyFilesystemKeys(evaluator, checker));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000255
256 // Before second build, move sym1 to point to sym2.
lberkiaea56b32017-05-30 12:35:33 +0200257 assertThat(sym1.delete()).isTrue();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000258 FileSystemUtils.ensureSymbolicLink(sym1, sym2);
Nathan Harmata8cd29782015-11-10 03:24:01 +0000259 assertDiffWithNewValues(getDirtyFilesystemKeys(evaluator, checker), sym1FileStateKey);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000260
261 differencer.invalidate(ImmutableList.of(sym1FileStateKey));
Googler10028672018-10-25 12:14:34 -0700262 result = driver.evaluate(ImmutableList.<SkyKey>of(), EVALUATION_OPTIONS);
lberkiaea56b32017-05-30 12:35:33 +0200263 assertThat(result.hasError()).isFalse();
Nathan Harmata8cd29782015-11-10 03:24:01 +0000264 assertDiffWithNewValues(getDirtyFilesystemKeys(evaluator, checker), sym1FileStateKey);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000265
266 // Before third build, move sym1 back to original (so change pruning will prevent signaling of
267 // its parents, but change symlink for real.
lberkiaea56b32017-05-30 12:35:33 +0200268 assertThat(sym1.delete()).isTrue();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000269 FileSystemUtils.ensureSymbolicLink(sym1, path);
lberkiaea56b32017-05-30 12:35:33 +0200270 assertThat(symlink.delete()).isTrue();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000271 FileSystemUtils.writeContentAsLatin1(symlink, "new symlink contents");
Nathan Harmata8cd29782015-11-10 03:24:01 +0000272 assertDiffWithNewValues(getDirtyFilesystemKeys(evaluator, checker), symlinkFileStateKey);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000273 differencer.invalidate(ImmutableList.of(symlinkFileStateKey));
Googler10028672018-10-25 12:14:34 -0700274 result = driver.evaluate(allKeys, EVALUATION_OPTIONS);
lberkiaea56b32017-05-30 12:35:33 +0200275 assertThat(result.hasError()).isFalse();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000276 symlinkValue = result.get(symlinkKey);
lberkiaea56b32017-05-30 12:35:33 +0200277 assertWithMessage(symlinkValue.toString()).that(symlinkValue.isSymlink()).isFalse();
278 assertThat(result.get(fooKey)).isEqualTo(fooValue);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000279 assertThat(symlinkValue.getSize()).isNotEqualTo(fooValue.getSize());
Nathan Harmata8cd29782015-11-10 03:24:01 +0000280 assertEmptyDiff(getDirtyFilesystemKeys(evaluator, checker));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000281 }
282
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000283 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000284 public void testExplicitFiles() throws Exception {
Ulf Adamsc73051c62016-03-23 09:18:13 +0000285 FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000286
287 Path path1 = fs.getPath("/foo1");
288 Path path2 = fs.getPath("/foo2");
289 FileSystemUtils.createEmptyFile(path1);
290 FileSystemUtils.createEmptyFile(path2);
Nathan Harmata8cd29782015-11-10 03:24:01 +0000291 assertEmptyDiff(getDirtyFilesystemKeys(evaluator, checker));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000292
293 SkyKey key1 =
294 FileStateValue.key(
tomlu4c9fafd2018-01-18 10:29:11 -0800295 RootedPath.toRootedPath(Root.absoluteRoot(fs), PathFragment.create("/foo1")));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000296 SkyKey key2 =
297 FileStateValue.key(
tomlu4c9fafd2018-01-18 10:29:11 -0800298 RootedPath.toRootedPath(Root.absoluteRoot(fs), PathFragment.create("/foo2")));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000299 Iterable<SkyKey> skyKeys = ImmutableList.of(key1, key2);
Googler10028672018-10-25 12:14:34 -0700300 EvaluationResult<SkyValue> result = driver.evaluate(skyKeys, EVALUATION_OPTIONS);
lberkiaea56b32017-05-30 12:35:33 +0200301 assertThat(result.hasError()).isFalse();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000302
Nathan Harmata8cd29782015-11-10 03:24:01 +0000303 assertEmptyDiff(getDirtyFilesystemKeys(evaluator, checker));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000304
Laszlo Csomora278aec2018-03-09 04:07:31 -0800305 // Wait for the timestamp granularity to elapse, so updating the files will observably advance
306 // their ctime.
laszlocsomor29bdf632018-03-13 02:50:46 -0700307 TimestampGranularityUtils.waitForTimestampGranularity(
308 System.currentTimeMillis(), OutErr.SYSTEM_OUT_ERR);
Laszlo Csomora278aec2018-03-09 04:07:31 -0800309 // Update path1's contents and mtime. This will update the file's ctime.
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000310 FileSystemUtils.writeContentAsLatin1(path1, "hello1");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000311 path1.setLastModifiedTime(27);
Laszlo Csomora278aec2018-03-09 04:07:31 -0800312 // Update path2's mtime but not its contents. We expect that an mtime change suffices to update
313 // the ctime.
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000314 path2.setLastModifiedTime(42);
Laszlo Csomora278aec2018-03-09 04:07:31 -0800315 // Assert that both files changed. The change detection relies, among other things, on ctime
316 // change.
Nathan Harmata8cd29782015-11-10 03:24:01 +0000317 assertDiffWithNewValues(getDirtyFilesystemKeys(evaluator, checker), key1, key2);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000318
319 differencer.invalidate(skyKeys);
Googler10028672018-10-25 12:14:34 -0700320 result = driver.evaluate(skyKeys, EVALUATION_OPTIONS);
lberkiaea56b32017-05-30 12:35:33 +0200321 assertThat(result.hasError()).isFalse();
Nathan Harmata8cd29782015-11-10 03:24:01 +0000322 assertEmptyDiff(getDirtyFilesystemKeys(evaluator, checker));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000323 }
324
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000325 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000326 public void testFileWithIOExceptionNotConsideredDirty() throws Exception {
327 Path path = fs.getPath("/testroot/foo");
328 path.getParentDirectory().createDirectory();
nharmatab4060b62017-04-04 17:11:39 +0000329 path.createSymbolicLink(PathFragment.create("bar"));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000330
331 fs.readlinkThrowsIoException = true;
tomluee6a6862018-01-17 14:36:26 -0800332 SkyKey fileKey =
333 FileStateValue.key(
334 RootedPath.toRootedPath(Root.fromPath(pkgRoot), PathFragment.create("foo")));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000335 EvaluationResult<SkyValue> result =
Googler10028672018-10-25 12:14:34 -0700336 driver.evaluate(ImmutableList.of(fileKey), EVALUATION_OPTIONS);
lberkiaea56b32017-05-30 12:35:33 +0200337 assertThat(result.hasError()).isTrue();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000338
339 fs.readlinkThrowsIoException = false;
Ulf Adamsc73051c62016-03-23 09:18:13 +0000340 FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
Nathan Harmata8cd29782015-11-10 03:24:01 +0000341 Diff diff = getDirtyFilesystemKeys(evaluator, checker);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000342 assertThat(diff.changedKeysWithoutNewValues()).isEmpty();
343 assertThat(diff.changedKeysWithNewValues()).isEmpty();
344 }
345
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000346 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000347 public void testFilesInCycleNotConsideredDirty() throws Exception {
348 Path path1 = pkgRoot.getRelative("foo1");
349 Path path2 = pkgRoot.getRelative("foo2");
350 Path path3 = pkgRoot.getRelative("foo3");
351 FileSystemUtils.ensureSymbolicLink(path1, path2);
352 FileSystemUtils.ensureSymbolicLink(path2, path3);
353 FileSystemUtils.ensureSymbolicLink(path3, path1);
tomluee6a6862018-01-17 14:36:26 -0800354 SkyKey fileKey1 = FileValue.key(RootedPath.toRootedPath(Root.fromPath(pkgRoot), path1));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000355
356 EvaluationResult<SkyValue> result =
Googler10028672018-10-25 12:14:34 -0700357 driver.evaluate(ImmutableList.of(fileKey1), EVALUATION_OPTIONS);
lberkiaea56b32017-05-30 12:35:33 +0200358 assertThat(result.hasError()).isTrue();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000359
Ulf Adamsc73051c62016-03-23 09:18:13 +0000360 FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
Nathan Harmata8cd29782015-11-10 03:24:01 +0000361 Diff diff = getDirtyFilesystemKeys(evaluator, checker);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000362 assertThat(diff.changedKeysWithoutNewValues()).isEmpty();
363 assertThat(diff.changedKeysWithNewValues()).isEmpty();
364 }
365
366 public void checkDirtyActions(BatchStat batchStatter, boolean forceDigests) throws Exception {
367 Artifact out1 = createDerivedArtifact("fiz");
368 Artifact out2 = createDerivedArtifact("pop");
369
370 FileSystemUtils.writeContentAsLatin1(out1.getPath(), "hello");
371 FileSystemUtils.writeContentAsLatin1(out2.getPath(), "fizzlepop");
372
janakrbaf52ae2018-02-14 09:03:18 -0800373 ActionLookupKey actionLookupKey =
janakr573807d2018-01-11 14:02:35 -0800374 new ActionLookupKey() {
375 @Override
376 public SkyFunctionName functionName() {
377 return SkyFunctionName.FOR_TESTING;
378 }
379 };
janakrefb3f152019-06-05 17:42:34 -0700380 SkyKey actionKey1 = ActionLookupData.create(actionLookupKey, 0);
381 SkyKey actionKey2 = ActionLookupData.create(actionLookupKey, 1);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000382 differencer.inject(
383 ImmutableMap.<SkyKey, SkyValue>of(
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000384 actionKey1,
385 actionValue(
386 new TestAction(
387 Runnables.doNothing(), ImmutableSet.<Artifact>of(), ImmutableSet.of(out1)),
388 forceDigests),
389 actionKey2,
390 actionValue(
391 new TestAction(
392 Runnables.doNothing(), ImmutableSet.<Artifact>of(), ImmutableSet.of(out2)),
393 forceDigests)));
Googler10028672018-10-25 12:14:34 -0700394 EvaluationContext evaluationContext =
395 EvaluationContext.newBuilder()
396 .setKeepGoing(false)
397 .setNumThreads(1)
398 .setEventHander(NullEventHandler.INSTANCE)
399 .build();
400 assertThat(driver.evaluate(ImmutableList.<SkyKey>of(), evaluationContext).hasError()).isFalse();
Ulf Adamsc73051c62016-03-23 09:18:13 +0000401 assertThat(new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
Eric Fellheimere6590722015-11-17 17:07:48 +0000402 batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED)).isEmpty();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000403
404 FileSystemUtils.writeContentAsLatin1(out1.getPath(), "goodbye");
Eric Fellheimere6590722015-11-17 17:07:48 +0000405 assertThat(
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000406 new FilesystemValueChecker(null, null)
407 .getDirtyActionValues(
408 evaluator.getValues(), batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED))
409 .containsExactly(actionKey1);
Ulf Adamsc73051c62016-03-23 09:18:13 +0000410 assertThat(
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000411 new FilesystemValueChecker(null, null)
412 .getDirtyActionValues(
413 evaluator.getValues(),
414 batchStatter,
415 new ModifiedFileSet.Builder().modify(out1.getExecPath()).build()))
416 .containsExactly(actionKey1);
Ulf Adamsc73051c62016-03-23 09:18:13 +0000417 assertThat(
418 new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
Eric Fellheimere6590722015-11-17 17:07:48 +0000419 batchStatter,
420 new ModifiedFileSet.Builder().modify(
421 out1.getExecPath().getParentDirectory()).build())).isEmpty();
422 assertThat(
Ulf Adamsc73051c62016-03-23 09:18:13 +0000423 new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
Eric Fellheimere6590722015-11-17 17:07:48 +0000424 batchStatter, ModifiedFileSet.NOTHING_MODIFIED)).isEmpty();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000425 }
426
janakrefb3f152019-06-05 17:42:34 -0700427 private void checkDirtyTreeArtifactActions(BatchStat batchStatter) throws Exception {
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000428 // Normally, an Action specifies the contents of a TreeArtifact when it executes.
429 // To decouple FileSystemValueTester checking from Action execution, we inject TreeArtifact
430 // contents into ActionExecutionValues.
431
cpeyserac09f0a2018-02-05 09:33:15 -0800432 SpecialArtifact out1 = createTreeArtifact("one");
janakrefb3f152019-06-05 17:42:34 -0700433 TreeFileArtifact file11 =
434 ActionsTestUtil.createTreeFileArtifactWithNoGeneratingAction(out1, "fizz");
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000435 FileSystemUtils.createDirectoryAndParents(out1.getPath());
436 FileSystemUtils.writeContentAsLatin1(file11.getPath(), "buzz");
437
cpeyserac09f0a2018-02-05 09:33:15 -0800438 SpecialArtifact out2 = createTreeArtifact("two");
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000439 FileSystemUtils.createDirectoryAndParents(out2.getPath().getChild("subdir"));
janakrefb3f152019-06-05 17:42:34 -0700440 TreeFileArtifact file21 =
441 ActionsTestUtil.createTreeFileArtifactWithNoGeneratingAction(out2, "moony");
442 TreeFileArtifact file22 =
443 ActionsTestUtil.createTreeFileArtifactWithNoGeneratingAction(out2, "subdir/wormtail");
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000444 FileSystemUtils.writeContentAsLatin1(file21.getPath(), "padfoot");
445 FileSystemUtils.writeContentAsLatin1(file22.getPath(), "prongs");
446
cpeyserac09f0a2018-02-05 09:33:15 -0800447 SpecialArtifact outEmpty = createTreeArtifact("empty");
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000448 FileSystemUtils.createDirectoryAndParents(outEmpty.getPath());
449
cpeyserac09f0a2018-02-05 09:33:15 -0800450 SpecialArtifact outUnchanging = createTreeArtifact("untouched");
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000451 FileSystemUtils.createDirectoryAndParents(outUnchanging.getPath());
452
cpeyserac09f0a2018-02-05 09:33:15 -0800453 SpecialArtifact last = createTreeArtifact("zzzzzzzzzz");
Rumou Duan45e8e572016-06-17 16:43:44 +0000454 FileSystemUtils.createDirectoryAndParents(last.getPath());
455
janakrbaf52ae2018-02-14 09:03:18 -0800456 ActionLookupKey actionLookupKey =
janakr573807d2018-01-11 14:02:35 -0800457 new ActionLookupKey() {
458 @Override
459 public SkyFunctionName functionName() {
460 return SkyFunctionName.FOR_TESTING;
461 }
462 };
janakrefb3f152019-06-05 17:42:34 -0700463 SkyKey actionKey1 = ActionLookupData.create(actionLookupKey, 0);
464 SkyKey actionKey2 = ActionLookupData.create(actionLookupKey, 1);
465 SkyKey actionKeyEmpty = ActionLookupData.create(actionLookupKey, 2);
466 SkyKey actionKeyUnchanging = ActionLookupData.create(actionLookupKey, 3);
467 SkyKey actionKeyLast = ActionLookupData.create(actionLookupKey, 4);
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000468 differencer.inject(
469 ImmutableMap.<SkyKey, SkyValue>of(
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000470 actionKey1,
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000471 actionValueWithTreeArtifacts(ImmutableList.of(file11)),
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000472 actionKey2,
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000473 actionValueWithTreeArtifacts(ImmutableList.of(file21, file22)),
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000474 actionKeyEmpty,
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000475 actionValueWithEmptyDirectory(outEmpty),
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000476 actionKeyUnchanging,
Rumou Duan45e8e572016-06-17 16:43:44 +0000477 actionValueWithEmptyDirectory(outUnchanging),
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000478 actionKeyLast,
Rumou Duan45e8e572016-06-17 16:43:44 +0000479 actionValueWithEmptyDirectory(last)));
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000480
Googler10028672018-10-25 12:14:34 -0700481 EvaluationContext evaluationContext =
482 EvaluationContext.newBuilder()
483 .setKeepGoing(false)
484 .setNumThreads(1)
485 .setEventHander(NullEventHandler.INSTANCE)
486 .build();
487 assertThat(driver.evaluate(ImmutableList.<SkyKey>of(), evaluationContext).hasError()).isFalse();
Ulf Adamsc73051c62016-03-23 09:18:13 +0000488 assertThat(new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000489 batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED)).isEmpty();
490
491 // Touching the TreeArtifact directory should have no effect
492 FileSystemUtils.touchFile(out1.getPath());
493 assertThat(
Ulf Adamsc73051c62016-03-23 09:18:13 +0000494 new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000495 batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED)).isEmpty();
496 // Neither should touching a subdirectory.
497 FileSystemUtils.touchFile(out2.getPath().getChild("subdir"));
498 assertThat(
Ulf Adamsc73051c62016-03-23 09:18:13 +0000499 new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000500 batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED)).isEmpty();
501
502 /* **** Tests for directories **** */
503
504 // Removing a directory (even if empty) should have an effect
505 outEmpty.getPath().delete();
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000506 assertThat(
507 new FilesystemValueChecker(null, null)
508 .getDirtyActionValues(
509 evaluator.getValues(),
510 batchStatter,
511 new ModifiedFileSet.Builder().modify(outEmpty.getExecPath()).build()))
512 .containsExactly(actionKeyEmpty);
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000513 // Symbolic links should count as dirty
514 Path dummyEmptyDir = fs.getPath("/bin").getRelative("symlink");
515 FileSystemUtils.createDirectoryAndParents(dummyEmptyDir);
516 FileSystemUtils.ensureSymbolicLink(outEmpty.getPath(), dummyEmptyDir);
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000517 assertThat(
518 new FilesystemValueChecker(null, null)
519 .getDirtyActionValues(
520 evaluator.getValues(),
521 batchStatter,
522 new ModifiedFileSet.Builder().modify(outEmpty.getExecPath()).build()))
523 .containsExactly(actionKeyEmpty);
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000524
525 // We're done fiddling with this... restore the original state
526 outEmpty.getPath().delete();
jmmv5cc1f652019-03-20 09:34:08 -0700527 dummyEmptyDir.deleteTree();
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000528 FileSystemUtils.createDirectoryAndParents(outEmpty.getPath());
529
530 /* **** Tests for files and directory contents ****/
531
532 // Test that file contents matter. This is covered by existing tests already,
533 // so it's just a sanity check.
534 FileSystemUtils.writeContentAsLatin1(file11.getPath(), "goodbye");
Ulf Adamsc73051c62016-03-23 09:18:13 +0000535 assertThat(
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000536 new FilesystemValueChecker(null, null)
537 .getDirtyActionValues(
538 evaluator.getValues(),
539 batchStatter,
540 new ModifiedFileSet.Builder().modify(file11.getExecPath()).build()))
541 .containsExactly(actionKey1);
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000542
543 // Test that directory contents (and nested contents) matter
janakrefb3f152019-06-05 17:42:34 -0700544 Artifact out1new =
545 ActionsTestUtil.createTreeFileArtifactWithNoGeneratingAction(out1, "julius/caesar");
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000546 FileSystemUtils.createDirectoryAndParents(out1.getPath().getChild("julius"));
547 FileSystemUtils.writeContentAsLatin1(out1new.getPath(), "octavian");
548 // even for empty directories
janakrefb3f152019-06-05 17:42:34 -0700549 Artifact outEmptyNew =
550 ActionsTestUtil.createTreeFileArtifactWithNoGeneratingAction(outEmpty, "marcus");
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000551 FileSystemUtils.writeContentAsLatin1(outEmptyNew.getPath(), "aurelius");
552 // so does removing
553 file21.getPath().delete();
554 // now, let's test our changes are actually visible
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000555 assertThat(
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000556 new FilesystemValueChecker(null, null)
557 .getDirtyActionValues(
558 evaluator.getValues(), batchStatter, ModifiedFileSet.EVERYTHING_MODIFIED))
559 .containsExactly(actionKey1, actionKey2, actionKeyEmpty);
560 assertThat(
561 new FilesystemValueChecker(null, null)
562 .getDirtyActionValues(
563 evaluator.getValues(),
564 batchStatter,
565 new ModifiedFileSet.Builder()
566 .modify(file21.getExecPath())
567 .modify(out1new.getExecPath())
568 .modify(outEmptyNew.getExecPath())
569 .build()))
570 .containsExactly(actionKey1, actionKey2, actionKeyEmpty);
Rumou Duan45e8e572016-06-17 16:43:44 +0000571 // We also check that if the modified file set does not contain our modified files on disk,
572 // we are not going to check and return them.
573 assertThat(
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000574 new FilesystemValueChecker(null, null)
575 .getDirtyActionValues(
576 evaluator.getValues(),
577 batchStatter,
578 new ModifiedFileSet.Builder()
579 .modify(file21.getExecPath())
580 .modify(outEmptyNew.getExecPath())
581 .build()))
582 .containsExactly(actionKey2, actionKeyEmpty);
Rumou Duan45e8e572016-06-17 16:43:44 +0000583 assertThat(
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000584 new FilesystemValueChecker(null, null)
585 .getDirtyActionValues(
586 evaluator.getValues(),
587 batchStatter,
588 new ModifiedFileSet.Builder()
589 .modify(file21.getExecPath())
590 .modify(out1new.getExecPath())
591 .build()))
592 .containsExactly(actionKey1, actionKey2);
Rumou Duan45e8e572016-06-17 16:43:44 +0000593 // Check modifying the last (lexicographically) tree artifact.
594 last.getPath().delete();
595 assertThat(
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000596 new FilesystemValueChecker(null, null)
597 .getDirtyActionValues(
598 evaluator.getValues(),
599 batchStatter,
600 new ModifiedFileSet.Builder()
601 .modify(file21.getExecPath())
602 .modify(out1new.getExecPath())
603 .modify(last.getExecPath())
604 .build()))
605 .containsExactly(actionKey1, actionKey2, actionKeyLast);
Rumou Duan45e8e572016-06-17 16:43:44 +0000606 // Check ModifiedFileSet without the last (lexicographically) tree artifact.
607 assertThat(
Janak Ramakrishnan5d152692017-03-20 22:07:14 +0000608 new FilesystemValueChecker(null, null)
609 .getDirtyActionValues(
610 evaluator.getValues(),
611 batchStatter,
612 new ModifiedFileSet.Builder()
613 .modify(file21.getExecPath())
614 .modify(out1new.getExecPath())
615 .build()))
616 .containsExactly(actionKey1, actionKey2);
Rumou Duan45e8e572016-06-17 16:43:44 +0000617 // Restore
618 last.getPath().delete();
619 FileSystemUtils.createDirectoryAndParents(last.getPath());
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000620 // We add a test for NOTHING_MODIFIED, because FileSystemValueChecker doesn't
621 // pay attention to file sets for TreeArtifact directory listings.
622 assertThat(
Ulf Adamsc73051c62016-03-23 09:18:13 +0000623 new FilesystemValueChecker(null, null).getDirtyActionValues(evaluator.getValues(),
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000624 batchStatter, ModifiedFileSet.NOTHING_MODIFIED)).isEmpty();
625 }
626
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000627 private Artifact createDerivedArtifact(String relPath) throws IOException {
628 Path outputPath = fs.getPath("/bin");
629 outputPath.createDirectory();
janakraea05602019-05-22 15:41:29 -0700630 return ActionsTestUtil.createArtifact(
631 ArtifactRoot.asDerivedRoot(fs.getPath("/"), outputPath), outputPath.getRelative(relPath));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000632 }
633
cpeyserac09f0a2018-02-05 09:33:15 -0800634 private SpecialArtifact createTreeArtifact(String relPath) throws IOException {
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000635 Path outputDir = fs.getPath("/bin");
636 Path outputPath = outputDir.getRelative(relPath);
637 outputDir.createDirectory();
tomlu1cdcdf92018-01-16 11:07:51 -0800638 ArtifactRoot derivedRoot = ArtifactRoot.asDerivedRoot(fs.getPath("/"), outputDir);
tomluee6a6862018-01-17 14:36:26 -0800639 return new SpecialArtifact(
tomluee6a6862018-01-17 14:36:26 -0800640 derivedRoot,
641 derivedRoot.getExecPath().getRelative(derivedRoot.getRoot().relativize(outputPath)),
janakrefb3f152019-06-05 17:42:34 -0700642 ActionsTestUtil.NULL_ARTIFACT_OWNER,
tomluee6a6862018-01-17 14:36:26 -0800643 SpecialArtifactType.TREE);
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000644 }
645
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000646 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000647 public void testDirtyActions() throws Exception {
648 checkDirtyActions(null, false);
649 }
650
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000651 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000652 public void testDirtyActionsBatchStat() throws Exception {
653 checkDirtyActions(
654 new BatchStat() {
655 @Override
656 public List<FileStatusWithDigest> batchStat(
657 boolean useDigest, boolean includeLinks, Iterable<PathFragment> paths)
658 throws IOException {
659 List<FileStatusWithDigest> stats = new ArrayList<>();
660 for (PathFragment pathFrag : paths) {
661 stats.add(
662 FileStatusWithDigestAdapter.adapt(
tomlu6c919062018-01-11 17:32:09 -0800663 fs.getPath("/").getRelative(pathFrag).statIfFound(Symlinks.NOFOLLOW)));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000664 }
665 return stats;
666 }
667 },
668 false);
669 }
670
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000671 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000672 public void testDirtyActionsBatchStatWithDigest() throws Exception {
673 checkDirtyActions(
674 new BatchStat() {
675 @Override
676 public List<FileStatusWithDigest> batchStat(
677 boolean useDigest, boolean includeLinks, Iterable<PathFragment> paths)
678 throws IOException {
679 List<FileStatusWithDigest> stats = new ArrayList<>();
680 for (PathFragment pathFrag : paths) {
tomlu6c919062018-01-11 17:32:09 -0800681 final Path path = fs.getPath("/").getRelative(pathFrag);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000682 stats.add(statWithDigest(path, path.statIfFound(Symlinks.NOFOLLOW)));
683 }
684 return stats;
685 }
686 },
687 true);
688 }
689
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000690 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000691 public void testDirtyActionsBatchStatFallback() throws Exception {
692 checkDirtyActions(
693 new BatchStat() {
694 @Override
695 public List<FileStatusWithDigest> batchStat(
696 boolean useDigest, boolean includeLinks, Iterable<PathFragment> paths)
697 throws IOException {
698 throw new IOException("try again");
699 }
700 },
701 false);
702 }
703
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000704 @Test
705 public void testDirtyTreeArtifactActions() throws Exception {
706 checkDirtyTreeArtifactActions(null);
707 }
708
709 @Test
710 public void testDirtyTreeArtifactActionsBatchStat() throws Exception {
711 checkDirtyTreeArtifactActions(
712 new BatchStat() {
713 @Override
714 public List<FileStatusWithDigest> batchStat(
715 boolean useDigest, boolean includeLinks, Iterable<PathFragment> paths)
716 throws IOException {
717 List<FileStatusWithDigest> stats = new ArrayList<>();
718 for (PathFragment pathFrag : paths) {
719 stats.add(
720 FileStatusWithDigestAdapter.adapt(
tomlu6c919062018-01-11 17:32:09 -0800721 fs.getPath("/").getRelative(pathFrag).statIfFound(Symlinks.NOFOLLOW)));
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000722 }
723 return stats;
724 }
725 });
726 }
727
728 // TODO(bazel-team): Add some tests for FileSystemValueChecker#changedKeys*() methods.
729 // Presently these appear to be untested.
730
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000731 private ActionExecutionValue actionValue(Action action, boolean forceDigest) {
janakr0c42fc82018-09-14 10:37:25 -0700732 Map<Artifact, ArtifactFileMetadata> artifactData = new HashMap<>();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000733 for (Artifact output : action.getOutputs()) {
734 try {
735 Path path = output.getPath();
736 FileStatusWithDigest stat =
737 forceDigest ? statWithDigest(path, path.statIfFound(Symlinks.NOFOLLOW)) : null;
janakr0c42fc82018-09-14 10:37:25 -0700738 artifactData.put(
739 output, ActionMetadataHandler.fileMetadataFromArtifact(output, stat, null));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000740 } catch (IOException e) {
741 throw new IllegalStateException(e);
742 }
743 }
janakrb9d8d582018-06-13 21:57:19 -0700744 return ActionExecutionValue.create(
Michael Thvedt8d5a7bb2016-02-09 03:06:34 +0000745 artifactData,
746 ImmutableMap.<Artifact, TreeArtifactValue>of(),
kush2ce45a22018-05-02 14:15:37 -0700747 ImmutableMap.<Artifact, FileArtifactValue>of(),
janakrb9d8d582018-06-13 21:57:19 -0700748 /*outputSymlinks=*/ null,
shahanef6f4cf2018-06-26 11:24:59 -0700749 /*discoveredModules=*/ null,
janakr9f496f32018-10-24 15:08:09 -0700750 /*actionDependsOnBuildId=*/ false);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000751 }
752
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000753 private ActionExecutionValue actionValueWithEmptyDirectory(Artifact emptyDir) {
754 TreeArtifactValue emptyValue = TreeArtifactValue.create
Rumou Duana77f32c2016-04-13 21:59:21 +0000755 (ImmutableMap.<TreeFileArtifact, FileArtifactValue>of());
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000756
janakrb9d8d582018-06-13 21:57:19 -0700757 return ActionExecutionValue.create(
janakr0c42fc82018-09-14 10:37:25 -0700758 ImmutableMap.of(),
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000759 ImmutableMap.of(emptyDir, emptyValue),
kush2ce45a22018-05-02 14:15:37 -0700760 ImmutableMap.<Artifact, FileArtifactValue>of(),
janakrb9d8d582018-06-13 21:57:19 -0700761 /*outputSymlinks=*/ null,
shahanef6f4cf2018-06-26 11:24:59 -0700762 /*discoveredModules=*/ null,
janakr9f496f32018-10-24 15:08:09 -0700763 /*actionDependsOnBuildId=*/ false);
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000764 }
765
Rumou Duana77f32c2016-04-13 21:59:21 +0000766 private ActionExecutionValue actionValueWithTreeArtifacts(List<TreeFileArtifact> contents) {
janakr0c42fc82018-09-14 10:37:25 -0700767 Map<Artifact, ArtifactFileMetadata> fileData = new HashMap<>();
Rumou Duana77f32c2016-04-13 21:59:21 +0000768 Map<Artifact, Map<TreeFileArtifact, FileArtifactValue>> directoryData = new HashMap<>();
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000769
Rumou Duana77f32c2016-04-13 21:59:21 +0000770 for (TreeFileArtifact output : contents) {
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000771 try {
Rumou Duana77f32c2016-04-13 21:59:21 +0000772 Map<TreeFileArtifact, FileArtifactValue> dirDatum =
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000773 directoryData.get(output.getParent());
774 if (dirDatum == null) {
775 dirDatum = new HashMap<>();
776 directoryData.put(output.getParent(), dirDatum);
777 }
janakr0c42fc82018-09-14 10:37:25 -0700778 ArtifactFileMetadata fileValue =
779 ActionMetadataHandler.fileMetadataFromArtifact(output, null, null);
Janak Ramakrishnancba16452016-07-29 02:17:02 +0000780 dirDatum.put(output, FileArtifactValue.create(output, fileValue));
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000781 fileData.put(output, fileValue);
782 } catch (IOException e) {
783 throw new IllegalStateException(e);
784 }
785 }
786
787 Map<Artifact, TreeArtifactValue> treeArtifactData = new HashMap<>();
Rumou Duana77f32c2016-04-13 21:59:21 +0000788 for (Map.Entry<Artifact, Map<TreeFileArtifact, FileArtifactValue>> dirDatum :
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000789 directoryData.entrySet()) {
Rumou Duana77f32c2016-04-13 21:59:21 +0000790 treeArtifactData.put(dirDatum.getKey(), TreeArtifactValue.create(dirDatum.getValue()));
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000791 }
792
janakrb9d8d582018-06-13 21:57:19 -0700793 return ActionExecutionValue.create(
kush2ce45a22018-05-02 14:15:37 -0700794 fileData,
795 treeArtifactData,
796 ImmutableMap.<Artifact, FileArtifactValue>of(),
janakrb9d8d582018-06-13 21:57:19 -0700797 /*outputSymlinks=*/ null,
shahanef6f4cf2018-06-26 11:24:59 -0700798 /*discoveredModules=*/ null,
janakr9f496f32018-10-24 15:08:09 -0700799 /*actionDependsOnBuildId=*/ false);
Michael Thvedte4a7b0792016-02-09 12:15:53 +0000800 }
801
buchgr4992ae22019-03-20 04:23:32 -0700802 private ActionExecutionValue actionValueWithRemoteTreeArtifact(
803 SpecialArtifact output, Map<PathFragment, RemoteFileArtifactValue> children) {
804 ImmutableMap.Builder<TreeFileArtifact, FileArtifactValue> childFileValues =
805 ImmutableMap.builder();
806 for (Map.Entry<PathFragment, RemoteFileArtifactValue> child : children.entrySet()) {
807 childFileValues.put(
janakrefb3f152019-06-05 17:42:34 -0700808 ActionInputHelper.treeFileArtifactWithNoGeneratingActionSet(
809 output, child.getKey(), output.getArtifactOwner()),
810 child.getValue());
buchgr4992ae22019-03-20 04:23:32 -0700811 }
812 TreeArtifactValue treeArtifactValue = TreeArtifactValue.create(childFileValues.build());
813 return ActionExecutionValue.create(
814 Collections.emptyMap(),
815 Collections.singletonMap(output, treeArtifactValue),
816 ImmutableMap.of(),
817 /* outputSymlinks= */ null,
818 /* discoveredModules= */ null,
819 /* actionDependsOnBuildId= */ false);
820 }
821
822 private ActionExecutionValue actionValueWithRemoteArtifact(
823 Artifact output, RemoteFileArtifactValue value) {
824 return ActionExecutionValue.create(
825 Collections.singletonMap(output, ArtifactFileMetadata.PLACEHOLDER),
826 ImmutableMap.of(),
827 Collections.singletonMap(output, value),
828 /* outputSymlinks= */ null,
829 /* discoveredModules= */ null,
830 /* actionDependsOnBuildId= */ false);
831 }
832
833 private RemoteFileArtifactValue createRemoteFileArtifactValue(String contents) {
834 byte[] data = contents.getBytes();
835 DigestHashFunction hashFn = fs.getDigestFunction();
836 HashCode hash = hashFn.getHashFunction().hashBytes(data);
837 return new RemoteFileArtifactValue(hash.asBytes(), data.length, -1);
838 }
839
840 @Test
841 public void testRemoteAndLocalArtifacts() throws Exception {
842 // Test that injected remote artifacts are trusted by the FileSystemValueChecker
843 // and that local files always takes preference over remote files.
844 ActionLookupKey actionLookupKey =
845 new ActionLookupKey() {
846 @Override
847 public SkyFunctionName functionName() {
848 return SkyFunctionName.FOR_TESTING;
849 }
850 };
janakrefb3f152019-06-05 17:42:34 -0700851 SkyKey actionKey1 = ActionLookupData.create(actionLookupKey, 0);
852 SkyKey actionKey2 = ActionLookupData.create(actionLookupKey, 1);
buchgr4992ae22019-03-20 04:23:32 -0700853
854 Artifact out1 = createDerivedArtifact("foo");
855 Artifact out2 = createDerivedArtifact("bar");
856 Map<SkyKey, SkyValue> metadataToInject = new HashMap<>();
857 metadataToInject.put(
858 actionKey1,
859 actionValueWithRemoteArtifact(out1, createRemoteFileArtifactValue("foo-content")));
860 metadataToInject.put(
861 actionKey2,
862 actionValueWithRemoteArtifact(out2, createRemoteFileArtifactValue("bar-content")));
863 differencer.inject(metadataToInject);
864
865 EvaluationContext evaluationContext =
866 EvaluationContext.newBuilder()
867 .setKeepGoing(false)
868 .setNumThreads(1)
869 .setEventHander(NullEventHandler.INSTANCE)
870 .build();
871 assertThat(
872 driver.evaluate(ImmutableList.of(actionKey1, actionKey2), evaluationContext).hasError())
873 .isFalse();
874 assertThat(
875 new FilesystemValueChecker(/* tsgm= */ null, /* lastExecutionTimeRange= */ null)
876 .getDirtyActionValues(
877 evaluator.getValues(),
878 /* batchStatter= */ null,
879 ModifiedFileSet.EVERYTHING_MODIFIED))
880 .isEmpty();
881
882 // Create the "out1" artifact on the filesystem and test that it invalidates the generating
883 // action's SkyKey.
884 FileSystemUtils.writeContentAsLatin1(out1.getPath(), "new-foo-content");
885 assertThat(
886 new FilesystemValueChecker(/* tsgm= */ null, /* lastExecutionTimeRange= */ null)
887 .getDirtyActionValues(
888 evaluator.getValues(),
889 /* batchStatter= */ null,
890 ModifiedFileSet.EVERYTHING_MODIFIED))
891 .containsExactly(actionKey1);
892 }
893
894 @Test
895 public void testRemoteAndLocalTreeArtifacts() throws Exception {
896 // Test that injected remote tree artifacts are trusted by the FileSystemValueChecker
897 // and that local files always takes preference over remote files.
898 ActionLookupKey actionLookupKey =
899 new ActionLookupKey() {
900 @Override
901 public SkyFunctionName functionName() {
902 return SkyFunctionName.FOR_TESTING;
903 }
904 };
janakrefb3f152019-06-05 17:42:34 -0700905 SkyKey actionKey = ActionLookupData.create(actionLookupKey, 0);
buchgr4992ae22019-03-20 04:23:32 -0700906
907 SpecialArtifact treeArtifact = createTreeArtifact("dir");
908 treeArtifact.getPath().createDirectoryAndParents();
909 Map<PathFragment, RemoteFileArtifactValue> treeArtifactMetadata = new HashMap<>();
910 treeArtifactMetadata.put(
911 PathFragment.create("foo"), createRemoteFileArtifactValue("foo-content"));
912 treeArtifactMetadata.put(
913 PathFragment.create("bar"), createRemoteFileArtifactValue("bar-content"));
914
915 Map<SkyKey, SkyValue> metadataToInject = new HashMap<>();
916 metadataToInject.put(
917 actionKey, actionValueWithRemoteTreeArtifact(treeArtifact, treeArtifactMetadata));
918 differencer.inject(metadataToInject);
919
920 EvaluationContext evaluationContext =
921 EvaluationContext.newBuilder()
922 .setKeepGoing(false)
923 .setNumThreads(1)
924 .setEventHander(NullEventHandler.INSTANCE)
925 .build();
926 assertThat(driver.evaluate(ImmutableList.of(actionKey), evaluationContext).hasError())
927 .isFalse();
928 assertThat(
929 new FilesystemValueChecker(/* tsgm= */ null, /* lastExecutionTimeRange= */ null)
930 .getDirtyActionValues(
931 evaluator.getValues(),
932 /* batchStatter= */ null,
933 ModifiedFileSet.EVERYTHING_MODIFIED))
934 .isEmpty();
935
936 // Create dir/foo on the local disk and test that it invalidates the associated sky key.
janakrefb3f152019-06-05 17:42:34 -0700937 TreeFileArtifact fooArtifact =
938 ActionsTestUtil.createTreeFileArtifactWithNoGeneratingAction(treeArtifact, "foo");
buchgr4992ae22019-03-20 04:23:32 -0700939 FileSystemUtils.writeContentAsLatin1(fooArtifact.getPath(), "new-foo-content");
940 assertThat(
941 new FilesystemValueChecker(/* tsgm= */ null, /* lastExecutionTimeRange= */ null)
942 .getDirtyActionValues(
943 evaluator.getValues(),
944 /* batchStatter= */ null,
945 ModifiedFileSet.EVERYTHING_MODIFIED))
946 .containsExactly(actionKey);
947 }
948
Han-Wen Nienhuys3b2eae32015-10-28 16:35:08 +0000949 @Test
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000950 public void testPropagatesRuntimeExceptions() throws Exception {
tomluee6a6862018-01-17 14:36:26 -0800951 Collection<SkyKey> values =
952 ImmutableList.of(
953 FileValue.key(
954 RootedPath.toRootedPath(Root.fromPath(pkgRoot), PathFragment.create("foo"))));
Googler10028672018-10-25 12:14:34 -0700955 driver.evaluate(values, EVALUATION_OPTIONS);
Ulf Adamsc73051c62016-03-23 09:18:13 +0000956 FilesystemValueChecker checker = new FilesystemValueChecker(null, null);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000957
Nathan Harmata8cd29782015-11-10 03:24:01 +0000958 assertEmptyDiff(getDirtyFilesystemKeys(evaluator, checker));
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000959
960 fs.statThrowsRuntimeException = true;
jcater83130f42019-04-30 14:29:28 -0700961 RuntimeException e =
962 assertThrows(RuntimeException.class, () -> getDirtyFilesystemKeys(evaluator, checker));
963 assertThat(e).hasMessageThat().isEqualTo("bork");
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000964 }
965
966 private static void assertEmptyDiff(Diff diff) {
967 assertDiffWithNewValues(diff);
968 }
969
970 private static void assertDiffWithNewValues(Diff diff, SkyKey... keysWithNewValues) {
971 assertThat(diff.changedKeysWithoutNewValues()).isEmpty();
972 assertThat(diff.changedKeysWithNewValues().keySet())
973 .containsExactlyElementsIn(Arrays.asList(keysWithNewValues));
974 }
975
976 private class MockFileSystem extends InMemoryFileSystem {
977
978 boolean statThrowsRuntimeException;
979 boolean readlinkThrowsIoException;
980
981 MockFileSystem() {
ccalvarinc9efd062018-07-27 12:46:46 -0700982 super();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000983 }
984
985 @Override
fellya205ed82018-09-10 11:52:34 -0700986 public FileStatus statIfFound(Path path, boolean followSymlinks) throws IOException {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000987 if (statThrowsRuntimeException) {
988 throw new RuntimeException("bork");
989 }
fellya205ed82018-09-10 11:52:34 -0700990 return super.statIfFound(path, followSymlinks);
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000991 }
992
993 @Override
aehligc801c392017-12-19 07:12:25 -0800994 protected PathFragment readSymbolicLink(Path path) throws IOException {
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +0000995 if (readlinkThrowsIoException) {
996 throw new IOException("readlink failed");
997 }
998 return super.readSymbolicLink(path);
999 }
1000 }
1001
1002 private static FileStatusWithDigest statWithDigest(final Path path, final FileStatus stat) {
1003 return new FileStatusWithDigest() {
1004 @Nullable
1005 @Override
1006 public byte[] getDigest() throws IOException {
olaolabfd1d332017-06-19 16:55:24 -04001007 return path.getDigest();
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +00001008 }
1009
1010 @Override
1011 public boolean isFile() {
1012 return stat.isFile();
1013 }
1014
1015 @Override
1016 public boolean isSpecialFile() {
1017 return stat.isSpecialFile();
1018 }
1019
1020 @Override
1021 public boolean isDirectory() {
1022 return stat.isDirectory();
1023 }
1024
1025 @Override
1026 public boolean isSymbolicLink() {
1027 return stat.isSymbolicLink();
1028 }
1029
1030 @Override
1031 public long getSize() throws IOException {
1032 return stat.getSize();
1033 }
1034
1035 @Override
1036 public long getLastModifiedTime() throws IOException {
1037 return stat.getLastModifiedTime();
1038 }
1039
1040 @Override
1041 public long getLastChangeTime() throws IOException {
1042 return stat.getLastChangeTime();
1043 }
1044
1045 @Override
1046 public long getNodeId() throws IOException {
1047 return stat.getNodeId();
1048 }
1049 };
1050 }
1051
Nathan Harmata8cd29782015-11-10 03:24:01 +00001052 private static Diff getDirtyFilesystemKeys(MemoizingEvaluator evaluator,
1053 FilesystemValueChecker checker) throws InterruptedException {
1054 return checker.getDirtyKeys(evaluator.getValues(), new BasicFilesystemDirtinessChecker());
Han-Wen Nienhuys81b90832015-10-26 16:57:27 +00001055 }
1056}