Skip to content

Commit ebbae84

Browse files
authored
fix(py_venv): copy the _virtualenv.py shim instead of symlinking it (#1287)
### Changes are visible to end-users: no ### Test plan - Covered by existing test cases - New test cases added
1 parent 0bdf8bb commit ebbae84

3 files changed

Lines changed: 21 additions & 28 deletions

File tree

py/private/modify_mtree.awk

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,17 @@
33
# following and inlining the target bytes.
44
#
55
# Forked from @tar.bzl//tar/private:preserve_symlinks.awk and tracking
6-
# https://github.com/bazel-contrib/tar.bzl/pull/115. Two behavioural
7-
# differences remain:
6+
# https://github.com/bazel-contrib/tar.bzl/pull/115. One behavioural
7+
# difference remains:
88
#
9-
# 1. `bazel-out/` vs `external/` strip is exclusive (`if` / `else if`)
10-
# rather than two sequential `sub`s. Without this, paths matching
11-
# both regexes — e.g. `bazel-out/<cfg>/bin/external/<repo>/...`,
12-
# the canonical shape of a generated wheel file — get
13-
# over-stripped down to `external/<repo>/...`, miss the
14-
# `symlink_map` lookup, and dangle inside the OCI layer.
15-
# 2. Classified `bazel-out/` or `external/` targets NOT in the
16-
# layer's mtree fall back to `type=file content=...` (bsdtar
17-
# inlines the bytes) instead of being written as a dangling
18-
# `type=link link=external/<repo>/...`. Exercised by py_venv's
19-
# `_virtualenv.py` symlink into the rules_py source tree, which
20-
# under bzlmod's `external/aspect_rules_py+/...` layout isn't a
21-
# separate tar entry.
9+
# The `bazel-out/` vs `external/` strip is exclusive (`if` / `else if`)
10+
# rather than two sequential `sub`s. Without this, paths matching
11+
# both regexes — e.g. `bazel-out/<cfg>/bin/external/<repo>/...`,
12+
# the canonical shape of a generated wheel file — get
13+
# over-stripped down to `external/<repo>/...`, miss the
14+
# `symlink_map` lookup, and dangle inside the OCI layer.
2215
#
23-
# Send a follow-up PR to bazel-contrib/tar.bzl with both once #115
16+
# Send a follow-up PR to bazel-contrib/tar.bzl once #115
2417
# lands so this fork can retire.
2518
#
2619
# Invoked from `_run_tar_action` in [py_image_layer.bzl](py_image_layer.bzl)
@@ -180,16 +173,8 @@ END {
180173
linked_to = make_relative_link(mapped_link, field0)
181174
} else if (resolved_path ~ /^bazel-out\// || resolved_path ~ /^external\//) {
182175
# Classified to a Bazel-tree path but the target row
183-
# isn't in this layer's mtree. Slow path falls back to
184-
# `type=file content=...` so bsdtar inlines the target
185-
# bytes; the hot path has no equivalent (declared
186-
# symlinks whose targets aren't in the layer are a
187-
# config bug) so we emit a dangling `type=link link=...`
188-
# to surface the issue visibly.
189-
if (original_line ~ /type=file/) {
190-
out_lines[++n] = original_line
191-
continue
192-
}
176+
# isn't in this layer's mtree — a config bug. Emit a
177+
# dangling `type=link link=...` to surface it visibly.
193178
linked_to = resolved_path
194179
} else {
195180
# Already a relative path

py/private/py_venv/venv.bzl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -928,12 +928,15 @@ def assemble_venv(
928928
declared.append(bin_activate)
929929

930930
# _virtualenv.py + _virtualenv.pth — distutils shim for pip interop.
931+
# Materialised as a real file, not a symlink into the rules_py source
932+
# tree, so tar/OCI/rsync etc. consumers of the venv can resolve the file.
931933
virtualenv_shim_py_out = ctx.actions.declare_file(
932934
"{}/_virtualenv.py".format(site_packages_rel),
933935
)
934-
ctx.actions.symlink(
936+
ctx.actions.expand_template(
937+
template = virtualenv_shim_py,
935938
output = virtualenv_shim_py_out,
936-
target_file = virtualenv_shim_py,
939+
substitutions = {},
937940
)
938941
declared.append(virtualenv_shim_py_out)
939942

py/tests/py-internal-venv/test.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
# The virtualenv module should have already been loaded at interpreter startup
1616
assert "_virtualenv" in sys.modules
1717

18+
# The shim must be a real file inside the venv, not a symlink resolving into
19+
# the rules_py source tree — symlinked copies dangle outside Bazel (tar/OCI).
20+
_shim = os.path.realpath(sys.modules["_virtualenv"].__file__)
21+
assert _shim.endswith("site-packages/_virtualenv.py"), _shim
22+
1823
# Note that we can't assume that a `.runfiles` tree has been created as CI may
1924
# use a different layout.
2025

0 commit comments

Comments
 (0)