Upon noticing an error in an external repository, also report the reason
Users sometimes find it hard (issue #7850) to identify the root
cause of a failure, if it is a fetch in an external repository.
As we print a message anyway on observing a failure in a fetch,
make this message more helpful by
- upgrading it to a proper error message, and
- including the message of the actual fetch error.
Also ensure that in case of a repository fetch failing due to
the execution of `fail` in the implementation function, the
message is reported as well.
Fixes #7850
Fixes #3683
Change-Id: I70eea4f966c98949e0f57462ac73b2a078552073
PiperOrigin-RevId: 243988092
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 5da88d6..b5ec7f5 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
@@ -185,8 +185,11 @@
}
env.getListener()
.handle(
- Event.info(
- "An error occurred during the fetch of repository '" + rule.getName() + "'"));
+ Event.error(
+ "An error occurred during the fetch of repository '"
+ + rule.getName()
+ + "':\n "
+ + e.getMessage()));
if (!Strings.isNullOrEmpty(rule.getDefinitionInformation())) {
env.getListener().handle(Event.info(rule.getDefinitionInformation()));
}
diff --git a/src/test/shell/bazel/skylark_repository_test.sh b/src/test/shell/bazel/skylark_repository_test.sh
index ef3c2b0..72fc395 100755
--- a/src/test/shell/bazel/skylark_repository_test.sh
+++ b/src/test/shell/bazel/skylark_repository_test.sh
@@ -1260,6 +1260,114 @@
|| fail "expected success after successful sync"
}
+function test_download_failure_message() {
+ # Regression test for #7850
+ # Verify that the for a failed downlaod, it is clearly indicated
+ # what was attempted to download and how it fails.
+ cat > BUILD <<'EOF'
+genrule(
+ name = "it",
+ outs = ["it.txt"],
+ srcs = ["@ext_foo//:data.txt"],
+ cmd = "cp $< $@",
+)
+EOF
+ cat > repo.bzl <<'EOF'
+def _impl(ctx):
+ ctx.file("BUILD", "exports_files(['data.txt'])")
+ ctx.symlink(ctx.attr.data, "data.txt")
+
+trivial_repo = repository_rule(
+ implementation = _impl,
+ attrs = { "data" : attr.label() },
+)
+EOF
+ cat > root.bzl <<'EOF'
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+def root_cause():
+ http_archive(
+ name = "this_is_the_root_cause",
+ urls = ["http://does.not.exist.example.com/some/file.tar"],
+ )
+
+EOF
+ cat > WORKSPACE <<'EOF'
+load("//:root.bzl", "root_cause")
+load("//:repo.bzl", "trivial_repo")
+
+root_cause()
+
+trivial_repo(
+ name = "ext_baz",
+ data = "@this_is_the_root_cause//:data.txt",
+)
+trivial_repo(
+ name = "ext_bar",
+ data = "@ext_baz//:data.txt",
+)
+
+trivial_repo(
+ name = "ext_foo",
+ data = "@ext_bar//:data.txt",
+)
+EOF
+
+ bazel build //:it > "${TEST_log}" 2>&1 \
+ && fail "Expected failure" || :
+
+ # Extract the first error message printed
+ ed "${TEST_log}" <<'EOF'
+1
+/^ERROR
+.,/^[^ ]/-1w firsterror.log
+Q
+EOF
+ echo; echo "first error message which should focus on the root cause";
+ echo "=========="; cat firsterror.log; echo "=========="
+ # We expect it to contain the root cause, and the failure ...
+ grep -q 'this_is_the_root_cause' firsterror.log \
+ || fail "Root-cause repository not mentioned"
+ grep -q '[uU]nknown host.*does.not.exist.example.com' firsterror.log \
+ || fail "Failure reason not mentioned"
+ # ...but not be cluttered with information not related to the root cause
+ grep 'ext_foo' firsterror.log && fail "unrelated repo mentioned" || :
+ grep 'ext_bar' firsterror.log && fail "unrelated repo mentioned" || :
+ grep 'ext_baz' firsterror.log && fail "unrelated repo mentioned" || :
+ grep '//:it' firsterror.log && fail "unrelated target mentioned" || :
+
+ # Verify that the same is true, if the error is caused by a fail statement.
+ cat > root.bzl <<'EOF'
+def _impl(ctx):
+ fail("Here be dragons")
+
+repo = repository_rule(implementation=_impl, attrs = {})
+
+def root_cause():
+ repo(name = "this_is_the_root_cause")
+EOF
+ bazel build //:it > "${TEST_log}" 2>&1 \
+ && fail "Expected failure" || :
+
+ # Extract the first error message printed
+ ed "${TEST_log}" <<'EOF'
+1
+/^ERROR
+.,/^[^ ]/-1w firsterror.log
+Q
+EOF
+ echo; echo "first error message which should focus on the root cause";
+ echo "=========="; cat firsterror.log; echo "=========="
+ grep -q 'this_is_the_root_cause' firsterror.log \
+ || fail "Root-cause repository not mentioned"
+ grep -q 'Here be dragons' firsterror.log \
+ || fail "fail error message not shown"
+ grep 'ext_foo' firsterror.log && fail "unrelated repo mentioned" || :
+ grep 'ext_bar' firsterror.log && fail "unrelated repo mentioned" || :
+ grep 'ext_baz' firsterror.log && fail "unrelated repo mentioned" || :
+ grep '//:it' firsterror.log && fail "unrelated target mentioned" || :
+}
+
function test_circular_load_error_message() {
cat > WORKSPACE <<'EOF'
load("//:a.bzl", "total")