diff options
4 files changed, 99 insertions, 13 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryResolvedEvent.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryResolvedEvent.java index 2087f3cd00..47801f3cfb 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryResolvedEvent.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryResolvedEvent.java @@ -21,6 +21,8 @@ import com.google.devtools.build.lib.packages.Info; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.Runtime; +import com.google.devtools.build.lib.vfs.Path; +import java.io.IOException; import java.util.Map; /** @@ -31,6 +33,7 @@ public class RepositoryResolvedEvent implements ProgressLike { public static final String ORIGINAL_ATTRIBUTES = "original_attributes"; public static final String RULE_CLASS = "rule_class"; public static final String ATTRIBUTES = "attributes"; + public static final String OUTPUT_TREE_HASH = "output_tree_hash"; public static final String REPOSITORIES = "repositories"; /** @@ -47,7 +50,7 @@ public class RepositoryResolvedEvent implements ProgressLike { */ private final Object resolvedInformation; - public RepositoryResolvedEvent(Rule rule, Info attrs, Object result) { + public RepositoryResolvedEvent(Rule rule, Info attrs, Path outputDirectory, Object result) { ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder(); String originalClass = @@ -69,25 +72,27 @@ public class RepositoryResolvedEvent implements ProgressLike { ImmutableMap<String, Object> origAttr = origAttrBuilder.build(); builder.put(ORIGINAL_ATTRIBUTES, origAttr); + ImmutableMap.Builder<String, Object> repositoryBuilder = + ImmutableMap.<String, Object>builder().put(RULE_CLASS, originalClass); + + try { + repositoryBuilder.put(OUTPUT_TREE_HASH, outputDirectory.getDirectoryDigest()); + } catch (IOException e) { + // Digest not available, but we still have to report that a repository rule + // was invoked. So we can do nothing, but ignore the event. + } + if (result == Runtime.NONE) { // Rule claims to be already reproducible, so wants to be called as is. builder.put( REPOSITORIES, - ImmutableList.<Object>of( - ImmutableMap.<String, Object>builder() - .put(RULE_CLASS, originalClass) - .put(ATTRIBUTES, origAttr) - .build())); + ImmutableList.<Object>of(repositoryBuilder.put(ATTRIBUTES, origAttr).build())); } else if (result instanceof Map) { // Rule claims that the returned (probably changed) arguments are a reproducible // version of itself. builder.put( REPOSITORIES, - ImmutableList.<Object>of( - ImmutableMap.<String, Object>builder() - .put(RULE_CLASS, originalClass) - .put(ATTRIBUTES, result) - .build())); + ImmutableList.<Object>of(repositoryBuilder.put(ATTRIBUTES, result).build())); } else { // TODO(aehlig): handle strings specially to allow encodings of the former // values to be accepted as well. diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryFunction.java index 4c3611ba8d..a4131bdbc2 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryFunction.java @@ -106,7 +106,9 @@ public class SkylarkRepositoryFunction extends RepositoryFunction { .handle(Event.info("Repository rule '" + rule.getName() + "' returned: " + retValue)); } env.getListener() - .post(new RepositoryResolvedEvent(rule, skylarkRepositoryContext.getAttr(), retValue)); + .post( + new RepositoryResolvedEvent( + rule, skylarkRepositoryContext.getAttr(), outputDirectory, retValue)); } catch (EvalException e) { if (e.getCause() instanceof RepositoryMissingDependencyException) { // A dependency is missing, cleanup and returns null diff --git a/src/test/shell/bazel/BUILD b/src/test/shell/bazel/BUILD index 763565f47f..9034672007 100644 --- a/src/test/shell/bazel/BUILD +++ b/src/test/shell/bazel/BUILD @@ -433,7 +433,7 @@ sh_test( size = "medium", srcs = ["workspace_resolved_test.sh"], data = [":test-deps"], - shard_count = 4, + shard_count = 9, tags = ["no_windows"], ) diff --git a/src/test/shell/bazel/workspace_resolved_test.sh b/src/test/shell/bazel/workspace_resolved_test.sh index b013c6dcaf..73fa099e38 100755 --- a/src/test/shell/bazel/workspace_resolved_test.sh +++ b/src/test/shell/bazel/workspace_resolved_test.sh @@ -435,4 +435,83 @@ EOF expect_not_log 'fn_name' } +create_sample_repository() { + # Create, in the current direcotry, a repository that creates an external + # repository `foo` containing + # - file with fixed data, generated by ctx.file, + # - a BUILD file linked from the main repository + # - a symlink to ., and + # - danling absolute and reproducible symlink. + touch BUILD + cat > rule.bzl <<'EOF' +def _trivial_rule_impl(ctx): + ctx.symlink(ctx.attr.build_file, "BUILD") + ctx.file("data.txt", "some data") + ctx.execute(["ln", "-s", ".", "self_link"]) + ctx.execute(["ln", "-s", "/does/not/exist", "dangling"]) + +trivial_rule = repository_rule( + implementation = _trivial_rule_impl, + attrs = { "build_file" : attr.label() }, +) +EOF + echo '# fixed contents' > BUILD.remote + cat > WORKSPACE <<'EOF' +load("//:rule.bzl", "trivial_rule") + +trivial_rule(name="foo", build_file="@//:BUILD.remote") +EOF +} + +test_hash_included_and_reproducible() { + # Verify that a hash of the output directory is included, that + # the hash is invariant under + # - change of the working directory, and + # - and current time. + + rm -rf fetchrepoA + mkdir fetchrepoA + cd fetchrepoA + create_sample_repository + bazel sync --experimental_repository_resolved_file=../repo.bzl + bazel shutdown; sync; sleep 10 + + cd .. + echo; cat repo.bzl; echo + touch WORKSPACE + cat > BUILD <<'EOF' +load("//:repo.bzl", "resolved") +hashes = [entry["repositories"][0]["output_tree_hash"] + for entry in resolved if entry["original_attributes"]["name"]=="foo"] + +[genrule( + name="hash", + outs=["hash.txt"], + cmd="echo '%s' > $@" % (hash,), +) for hash in hashes] +EOF + bazel build //:hash + cp `bazel info bazel-genfiles`/hash.txt hashA.txt + cat hashA.txt > "${TEST_log}" + [ `cat hashA.txt | wc -c` -gt 2 ] \ + || fail "A hash of reasonable length expected" + bazel clean --expunge + rm repo.bzl + + + rm -rf fetchrepoB + mkdir fetchrepoB + cd fetchrepoB + create_sample_repository + bazel sync --experimental_repository_resolved_file=../repo.bzl + bazel shutdown; sync; sleep 10 + + cd .. + echo; cat repo.bzl; echo + bazel build //:hash + cp `bazel info bazel-genfiles`/hash.txt hashB.txt + cat hashB.txt > "${TEST_log}" + diff hashA.txt hashB.txt || fail "Expected hash to be reproducible" +} + run_suite "workspace_resolved_test tests" |