Skip to content

Commit c9bb66e

Browse files
faximanaignas
andauthored
fix(bootstrap): manual runfiles path construction when using submodules (#3636)
This fixes #3563. Verified by running the repro in https://github.com/mering/reproduction_rules_python_1_7. The identified regression in b8e32c4 is problematic because prepending `ctx.workspace_name` to `short_path` results in paths containing `..` (e.g., `_main/../sub+/path/to/file.py`) when building from a root module that includes other modules. This causes the `_find_runfiles_root` [logic](https://github.com/faximan/rules_python/blob/eb6ac472eb86cc263acc336a2b73982043069aae/python/private/site_init_template.py#L73), which _counts slashes_, to incorrectly calculate the runfiles root. The fix is simply using the available `runfiles_root_path` function instead. In the example above, this makes the path simply `sub+/path/to/file.py`. --------- Co-authored-by: Ignas Anikevicius <240938+aignas@users.noreply.github.com>
1 parent 77a89a6 commit c9bb66e

File tree

5 files changed

+54
-14
lines changed

5 files changed

+54
-14
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ Other changes:
8080
configuration. See the {any}`RULES_PYTHON_PYCACHE_DIR` environment variable
8181
for more information.
8282
([#3643](https://github.com/bazel-contrib/rules_python/issues/3643)).
83+
* (bootstrap) Fixed incorrect runfiles path construction in bootstrap
84+
scripts when binary is defined in another bazel module
85+
([#3563](https://github.com/bazel-contrib/rules_python/issues/3563)).
8386

8487
{#v0-0-0-added}
8588
### Added

examples/bzlmod/other_module/other_module/pkg/BUILD.bazel

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
load("@rules_python//python:py_binary.bzl", "py_binary")
22
load("@rules_python//python:py_library.bzl", "py_library")
3+
load("@rules_python//python/zipapp:py_zipapp_binary.bzl", "py_zipapp_binary")
34

45
py_library(
56
name = "lib",
@@ -26,4 +27,13 @@ py_binary(
2627
],
2728
)
2829

30+
# This is used for regression testing runfiles paths in submodules.
31+
# https://github.com/bazel-contrib/rules_python/issues/3563.
32+
py_zipapp_binary(
33+
name = "bin_zipapp",
34+
testonly = True,
35+
binary = ":bin",
36+
visibility = ["//visibility:public"],
37+
)
38+
2939
exports_files(["data/data.txt"])

examples/bzlmod/tests/other_module/BUILD.bazel

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,24 @@
55
# in the root module.
66

77
load("@bazel_skylib//rules:build_test.bzl", "build_test")
8+
load("@rules_python//python:py_test.bzl", "py_test")
89

910
build_test(
1011
name = "other_module_bin_build_test",
1112
targets = [
1213
"@our_other_module//other_module/pkg:bin",
1314
],
1415
)
16+
17+
py_test(
18+
name = "other_module_import_test",
19+
srcs = ["other_module_import_test.py"],
20+
data = ["@our_other_module//other_module/pkg:bin_zipapp"],
21+
env = {"ZIPAPP_PATH": "$(location @our_other_module//other_module/pkg:bin_zipapp)"},
22+
# For now, skip this test on Windows because it fails for reasons
23+
# other than the code path being tested.
24+
target_compatible_with = select({
25+
"@platforms//os:windows": ["@platforms//:incompatible"],
26+
"//conditions:default": [],
27+
}),
28+
)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""Regression test for https://github.com/bazel-contrib/rules_python/issues/3563"""
2+
import os
3+
import subprocess
4+
import sys
5+
6+
def main():
7+
# The rlocation path for the bin_zipapp. It is in the "our_other_module" repository.
8+
zipapp_path = os.environ.get("ZIPAPP_PATH")
9+
print(f"Running bin_zipapp at: {zipapp_path}")
10+
11+
result = subprocess.run([zipapp_path], capture_output=True, text=True)
12+
print("--- bin_zippapp stdout ---")
13+
print(result.stdout)
14+
print("--- bin_zippapp stderr ---")
15+
print(result.stderr)
16+
17+
if result.returncode != 0:
18+
print(f"bin_zippapp failed with return code {result.returncode}")
19+
sys.exit(result.returncode)
20+
21+
if __name__ == "__main__":
22+
main()

python/private/py_executable.bzl

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -510,10 +510,7 @@ def _create_zip_main(ctx, *, stage2_bootstrap, runtime_details, venv):
510510
substitutions = {
511511
"%python_binary%": python_binary,
512512
"%python_binary_actual%": python_binary_actual,
513-
"%stage2_bootstrap%": "{}/{}".format(
514-
ctx.workspace_name,
515-
stage2_bootstrap.short_path,
516-
),
513+
"%stage2_bootstrap%": runfiles_root_path(ctx, stage2_bootstrap.short_path),
517514
"%workspace_name%": ctx.workspace_name,
518515
},
519516
)
@@ -616,7 +613,7 @@ def _create_venv(ctx, output_prefix, imports, runtime_details, add_runfiles_root
616613
"%add_runfiles_root_to_sys_path%": add_runfiles_root_to_sys_path,
617614
"%coverage_tool%": _get_coverage_tool_runfiles_path(ctx, runtime),
618615
"%import_all%": "True" if read_possibly_native_flag(ctx, "python_import_all_repositories") else "False",
619-
"%site_init_runfiles_path%": "{}/{}".format(ctx.workspace_name, site_init.short_path),
616+
"%site_init_runfiles_path%": runfiles_root_path(ctx, site_init.short_path),
620617
"%workspace_name%": ctx.workspace_name,
621618
},
622619
computed_substitutions = computed_subs,
@@ -671,10 +668,7 @@ def _get_coverage_tool_runfiles_path(ctx, runtime):
671668
if (ctx.configuration.coverage_enabled and
672669
runtime and
673670
runtime.coverage_tool):
674-
return "{}/{}".format(
675-
ctx.workspace_name,
676-
runtime.coverage_tool.short_path,
677-
)
671+
return runfiles_root_path(ctx, runtime.coverage_tool.short_path)
678672
else:
679673
return ""
680674

@@ -777,10 +771,7 @@ def _create_stage1_bootstrap(
777771
if (ctx.configuration.coverage_enabled and
778772
runtime and
779773
runtime.coverage_tool):
780-
coverage_tool_runfiles_path = "{}/{}".format(
781-
ctx.workspace_name,
782-
runtime.coverage_tool.short_path,
783-
)
774+
coverage_tool_runfiles_path = runfiles_root_path(ctx, runtime.coverage_tool.short_path)
784775
else:
785776
coverage_tool_runfiles_path = ""
786777
if runtime:
@@ -793,7 +784,7 @@ def _create_stage1_bootstrap(
793784
subs["%coverage_tool%"] = coverage_tool_runfiles_path
794785
subs["%import_all%"] = ("True" if read_possibly_native_flag(ctx, "python_import_all_repositories") else "False")
795786
subs["%imports%"] = ":".join(imports.to_list())
796-
subs["%main%"] = "{}/{}".format(ctx.workspace_name, main_py.short_path)
787+
subs["%main%"] = runfiles_root_path(ctx, main_py.short_path)
797788

798789
ctx.actions.expand_template(
799790
template = template,

0 commit comments

Comments
 (0)