diff options
author | 2017-05-31 20:37:57 +0200 | |
---|---|---|
committer | 2017-06-01 14:08:13 +0200 | |
commit | 7e0cc9e72f2e7dfbcebdbe49af74ed42d0e8f33a (patch) | |
tree | fbe9743942dfa37b95f14070e5d4e219e135c4b2 /src | |
parent | 22b85a2a3c79c6f3aef1e0a61e485bb135be4551 (diff) |
Remote caching: don't crash for actions with no inputs
Fixes #3004.
Change-Id: I6dcef92e9f23df574e0874a81b2901754042cf9a
Closes #3085.
Change-Id: I6dcef92e9f23df574e0874a81b2901754042cf9a
PiperOrigin-RevId: 157612661
Diffstat (limited to 'src')
3 files changed, 46 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/remote/TreeNodeRepository.java b/src/main/java/com/google/devtools/build/lib/remote/TreeNodeRepository.java index fa9eb7d6ee..8272295a84 100644 --- a/src/main/java/com/google/devtools/build/lib/remote/TreeNodeRepository.java +++ b/src/main/java/com/google/devtools/build/lib/remote/TreeNodeRepository.java @@ -68,6 +68,7 @@ public final class TreeNodeRepository extends TreeTraverser<TreeNodeRepository.T /** A pair of path segment, TreeNode. */ @Immutable public static final class ChildEntry { + private final String segment; private final TreeNode child; @@ -176,6 +177,8 @@ public final class TreeNodeRepository extends TreeTraverser<TreeNodeRepository.T } } + private static final TreeNode EMPTY_NODE = new TreeNode(ImmutableList.<TreeNode.ChildEntry>of()); + // Keep only one canonical instance of every TreeNode in the repository. private final Interner<TreeNode> interner = BlazeInterners.newWeakInterner(); // Merkle hashes are computed and cached by the repository, therefore execRoot must @@ -264,6 +267,12 @@ public final class TreeNodeRepository extends TreeTraverser<TreeNodeRepository.T int inputsStart, int inputsEnd, int segmentIndex) { + if (segments.isEmpty()) { + // We sometimes have actions with no inputs (e.g., echo "xyz" > $@), so we need to handle that + // case here. + Preconditions.checkState(inputs.isEmpty()); + return EMPTY_NODE; + } if (segmentIndex == segments.get(inputsStart).size()) { // Leaf node reached. Must be unique. Preconditions.checkArgument( diff --git a/src/test/java/com/google/devtools/build/lib/remote/TreeNodeRepositoryTest.java b/src/test/java/com/google/devtools/build/lib/remote/TreeNodeRepositoryTest.java index 4bb8883269..f9ef9111a6 100644 --- a/src/test/java/com/google/devtools/build/lib/remote/TreeNodeRepositoryTest.java +++ b/src/test/java/com/google/devtools/build/lib/remote/TreeNodeRepositoryTest.java @@ -152,4 +152,14 @@ public class TreeNodeRepositoryTest { .containsExactly( rootDigest, aDigest, barDigest, barContentsDigest, fooDigest, fooContentsDigest); } + + @Test + public void testEmptyTree() throws Exception { + SortedMap<PathFragment, ActionInput> inputs = new TreeMap<>(); + TreeNodeRepository repo = createTestTreeNodeRepository(); + TreeNode root = repo.buildFromActionInputs(inputs); + repo.computeMerkleDigests(root); + + assertThat(root.getChildEntries()).isEmpty(); + } } diff --git a/src/test/shell/bazel/remote_execution_test.sh b/src/test/shell/bazel/remote_execution_test.sh index 1a8748da02..e460bff30e 100755 --- a/src/test/shell/bazel/remote_execution_test.sh +++ b/src/test/shell/bazel/remote_execution_test.sh @@ -224,6 +224,33 @@ EOF || fail "Failed to run //a:test with remote execution" } +function test_noinput_action() { + mkdir -p a + cat > a/rule.bzl <<'EOF' +def _impl(ctx): + output = ctx.outputs.out + ctx.action( + outputs=[output], + command="echo 'Hello World' > %s" % (output.path)) + +empty = rule( + implementation=_impl, + outputs={"out": "%{name}.txt"}, +) +EOF + cat > a/BUILD <<'EOF' +load("//a:rule.bzl", "empty") +package(default_visibility = ["//visibility:public"]) +empty(name = 'test') +EOF + bazel --host_jvm_args=-Dbazel.DigestFunction=SHA1 build \ + --spawn_strategy=remote \ + --remote_cache=localhost:${worker_port} \ + --test_output=errors \ + //a:test >& $TEST_log \ + || fail "Failed to run //a:test with remote execution" +} + # TODO(alpha): Add a test that fails remote execution when remote worker # supports sandbox. |