From 0230ea5bc23ff964a08837b7e284e0c76bd2a4ef Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Fri, 20 Jan 2023 08:23:13 +0100 Subject: [PATCH] Fix Bash `runfiles_current_repository` for tools Shell scripts invoked as tools in actions are usually invoked with relative paths starting with `bazel-out`, which resulted in them being misclassified as from the main repo. --- src/test/shell/bazel/bazel_rules_test.sh | 212 +++++++++++++++++++++++ tools/bash/runfiles/runfiles.bash | 2 +- 2 files changed, 213 insertions(+), 1 deletion(-) diff --git a/src/test/shell/bazel/bazel_rules_test.sh b/src/test/shell/bazel/bazel_rules_test.sh index cc49a1fe4728dc..0f9552e750e8e3 100755 --- a/src/test/shell/bazel/bazel_rules_test.sh +++ b/src/test/shell/bazel/bazel_rules_test.sh @@ -1035,4 +1035,216 @@ function test_bash_runfiles_current_repository_test_nobuild_runfile_links() { expect_log "in external/other_repo/pkg/library2.sh: 'other_repo'" } +function test_bash_runfiles_current_repository_action_binary_main_repo() { + touch MODULE.bazel + + mkdir -p pkg + cat > pkg/BUILD.bazel <<'EOF' +genrule( + name = "gen", + outs = ["out"], + tools = [":binary"], + cmd = "$(location :binary) && touch $@", +) + +sh_binary( + name = "binary", + srcs = ["binary.sh"], + deps = [ + "@bazel_tools//tools/bash/runfiles", + ], + visibility = ["//visibility:public"], +) +EOF + + cat > pkg/binary.sh <<'EOF' +#!/usr/bin/env bash +# --- begin runfiles.bash initialization v2 --- +# Copy-pasted from the Bazel Bash runfiles library v2. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v2 --- + +echo "in pkg/binary.sh: '$(runfiles_current_repository)'" +EOF + chmod +x pkg/binary.sh + + bazel build --enable_bzlmod //pkg:gen &>"$TEST_log" || fail "Build should succeed" + expect_log "in pkg/binary.sh: ''" +} + +function test_bash_runfiles_current_repository_action_generated_binary_main_repo() { + touch MODULE.bazel + + mkdir -p pkg + cat > pkg/BUILD.bazel <<'EOF' +genrule( + name = "gen", + outs = ["out"], + tools = [":binary"], + cmd = "$(location :binary) && touch $@", +) + +genrule( + name = "copy_binary", + outs = ["gen_binary.sh"], + srcs = ["binary.sh"], + cmd = "cp $(location binary.sh) $@", +) + +sh_binary( + name = "binary", + srcs = ["binary.sh"], + deps = [ + "@bazel_tools//tools/bash/runfiles", + ], + visibility = ["//visibility:public"], +) +EOF + + cat > pkg/binary.sh <<'EOF' +#!/usr/bin/env bash +# --- begin runfiles.bash initialization v2 --- +# Copy-pasted from the Bazel Bash runfiles library v2. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v2 --- + +echo "in copy of pkg/gen_binary.sh: '$(runfiles_current_repository)'" +EOF + chmod +x pkg/binary.sh + + bazel build --enable_bzlmod //pkg:gen &>"$TEST_log" || fail "Build should succeed" + expect_log "in copy of pkg/gen_binary.sh: ''" +} + +function test_bash_runfiles_current_repository_action_binary_external_repo() { + touch MODULE.bazel + + cat >> WORKSPACE <<'EOF' +local_repository( + name = "other_repo", + path = "other_repo", +) +EOF + + mkdir -p pkg + cat > pkg/BUILD.bazel <<'EOF' +genrule( + name = "gen", + outs = ["out"], + tools = ["@other_repo//pkg:binary"], + cmd = "$(location @other_repo//pkg:binary) && touch $@", +) +EOF + + mkdir -p other_repo + touch other_repo/WORKSPACE + + mkdir -p other_repo/pkg + cat > other_repo/pkg/BUILD.bazel <<'EOF' +sh_binary( + name = "binary", + srcs = ["binary.sh"], + deps = [ + "@bazel_tools//tools/bash/runfiles", + ], + visibility = ["//visibility:public"], +) +EOF + + cat > other_repo/pkg/binary.sh <<'EOF' +#!/usr/bin/env bash +# --- begin runfiles.bash initialization v2 --- +# Copy-pasted from the Bazel Bash runfiles library v2. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v2 --- + +echo "in external/other_repo/pkg/binary.sh: '$(runfiles_current_repository)'" +EOF + chmod +x other_repo/pkg/binary.sh + + bazel build --enable_bzlmod //pkg:gen &>"$TEST_log" || fail "Build should succeed" + expect_log "in external/other_repo/pkg/binary.sh: 'other_repo'" +} + +function test_bash_runfiles_current_repository_action_generated_binary_external_repo() { + touch MODULE.bazel + + cat >> WORKSPACE <<'EOF' +local_repository( + name = "other_repo", + path = "other_repo", +) +EOF + + mkdir -p pkg + cat > pkg/BUILD.bazel <<'EOF' +genrule( + name = "gen", + outs = ["out"], + tools = ["@other_repo//pkg:binary"], + cmd = "$(location @other_repo//pkg:binary) && touch $@", +) +EOF + + mkdir -p other_repo + touch other_repo/WORKSPACE + + mkdir -p other_repo/pkg + cat > other_repo/pkg/BUILD.bazel <<'EOF' +genrule( + name = "copy_binary", + outs = ["gen_binary.sh"], + srcs = ["binary.sh"], + cmd = "cp $(location binary.sh) $@", +) + +sh_binary( + name = "binary", + srcs = ["gen_binary.sh"], + deps = [ + "@bazel_tools//tools/bash/runfiles", + ], + visibility = ["//visibility:public"], +) +EOF + + cat > other_repo/pkg/binary.sh <<'EOF' +#!/usr/bin/env bash +# --- begin runfiles.bash initialization v2 --- +# Copy-pasted from the Bazel Bash runfiles library v2. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v2 --- + +echo "in copy of external/other_repo/pkg/binary.sh: '$(runfiles_current_repository)'" +EOF + chmod +x other_repo/pkg/binary.sh + + bazel build --enable_bzlmod //pkg:gen &>"$TEST_log" || fail "Build should succeed" + expect_log "in copy of external/other_repo/pkg/binary.sh: 'other_repo'" +} + run_suite "rules test" diff --git a/tools/bash/runfiles/runfiles.bash b/tools/bash/runfiles/runfiles.bash index 9788fa49a28a16..6607317c759ab8 100644 --- a/tools/bash/runfiles/runfiles.bash +++ b/tools/bash/runfiles/runfiles.bash @@ -261,7 +261,7 @@ function runfiles_current_repository() { # The only shell script that is not executed from the runfiles directory (if it is populated) # is the sh_binary entrypoint. Parse its path under the execroot, using the last match to # allow for nested execroots (e.g. in Bazel integration tests). - local -r repository=$(echo "$normalized_caller_path" | __runfiles_maybe_grep -E -o '/bazel-out/[^/]+/bin/external/[^/]+/' | tail -1 | rev | cut -d / -f 2 | rev) + local -r repository=$(echo "$normalized_caller_path" | __runfiles_maybe_grep -E -o '(^|/)bazel-out/[^/]+/bin/external/[^/]+/' | tail -1 | rev | cut -d / -f 2 | rev) if [[ -n "$repository" ]]; then if [[ "${RUNFILES_LIB_DEBUG:-}" == 1 ]]; then echo >&2 "INFO[runfiles.bash]: runfiles_current_repository($idx): ($normalized_caller_path) lies in repository ($repository)"