Skip to content

Commit a8b0d98

Browse files
committed
add tests
1 parent fcdc05e commit a8b0d98

2 files changed

Lines changed: 216 additions & 53 deletions

File tree

python/private/venv_runfiles.bzl

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Code for constructing venvs."""
22

33
load("@bazel_skylib//lib:paths.bzl", "paths")
4+
load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED") # buildifier: disable=bzl-visibility
45
load(
56
":common.bzl",
67
"is_file",
@@ -57,7 +58,6 @@ def create_venv_app_files(ctx, deps, venv_dir_map):
5758
if is_file(link_to):
5859
symlink_from = "{}/{}".format(ctx.label.package, bin_venv_path)
5960
runfiles_symlinks[symlink_from] = link_to
60-
6161
else:
6262
venv_link = ctx.actions.declare_symlink(bin_venv_path)
6363
venv_link_rf_path = runfiles_root_path(ctx, venv_link.short_path)
@@ -76,14 +76,16 @@ def create_venv_app_files(ctx, deps, venv_dir_map):
7676
)
7777

7878
# Visible for testing
79-
def build_link_map(ctx, entries):
79+
def build_link_map(ctx, entries, return_conflicts = False):
8080
"""Compute the mapping of venv paths to their backing objects.
8181
82-
8382
Args:
8483
ctx: {type}`ctx` current ctx.
8584
entries: {type}`list[VenvSymlinkEntry]` the entries that describe the
8685
venv-relative
86+
return_conflicts: {type}`bool`. Only present for testing. If True,
87+
also return a list of the groups that had overlapping paths and had
88+
to be resolved and merged.
8789
8890
Returns:
8991
{type}`dict[str, dict[str, str|File]]` Mappings of venv paths to their
@@ -113,6 +115,7 @@ def build_link_map(ctx, entries):
113115

114116
# final paths to keep, grouped by kind
115117
keep_link_map = {} # dict[str kind, dict[path, str|File]]
118+
conflicts = [] if return_conflicts else None
116119
for kind, entries in entries_by_kind.items():
117120
# dict[str kind-relative path, str|File link_to]
118121
keep_kind_link_map = {}
@@ -128,12 +131,17 @@ def build_link_map(ctx, entries):
128131
else:
129132
keep_kind_link_map[entry.venv_path] = entry.link_to_path
130133
else:
134+
if return_conflicts:
135+
conflicts.append(group)
136+
131137
# Merge a group of overlapping prefixes
132138
_merge_venv_path_group(ctx, group, keep_kind_link_map)
133139

134140
keep_link_map[kind] = keep_kind_link_map
135-
136-
return keep_link_map
141+
if return_conflicts:
142+
return keep_link_map, conflicts
143+
else:
144+
return keep_link_map
137145

138146
def _group_venv_path_entries(entries):
139147
"""Group entries by VenvSymlinkEntry.venv_path overlap.
@@ -236,17 +244,6 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
236244

237245
all_files = sorted(files, key = lambda f: f.short_path)
238246

239-
# We want to minimize the number of files symlinked. Ideally only
240-
# the top-level directories under site-packages are symlinked.
241-
# Unfortunately, shared libraries complicate matters: if a
242-
# shared library's directory is linked, then the dynamic linker
243-
# computes the wrong search path. To fix, we have to directly link
244-
# shared libraries. This then means that all the parent directories of
245-
# the shared library can't be linked directly.
246-
# So what we do is identify the shared libraries, mark all their
247-
# parent directories as "cannot be directly linked", then compute
248-
# the files that can be linked with that constraint.
249-
250247
# venv paths that cannot be directly linked. Dict acting as set.
251248
cannot_be_linked_directly = {}
252249

@@ -257,7 +254,14 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
257254
# List of (File, str venv_path) tuples
258255
files_left_to_link = []
259256

260-
repo_runfiles_dirname = None
257+
# We want to minimize the number of files symlinked. Ideally, only the
258+
# top-level directories are symlinked. Unfortunately, shared libraries
259+
# complicate matters: if a shared library's directory is linked, then the
260+
# dynamic linker computes the wrong search path.
261+
#
262+
# To fix, we have to directly link shared libraries. This then means that
263+
# all the parent directories of the shared library can't be linked
264+
# directly.
261265
for src in all_files:
262266
if src.owner.repo_name != ctx.label.repo_name:
263267
# Files in other repos complicate symlink optimization, so
@@ -280,11 +284,13 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
280284
)
281285
parent = paths.dirname(venv_path)
282286
for _ in range(len(venv_path) + 1): # Iterate enough times to traverse up
283-
if parent and parent != ".":
284-
cannot_be_linked_directly[parent] = True
285-
parent = paths.dirname(parent)
286-
else:
287+
if not parent:
287288
break
289+
if cannot_be_linked_directly.get(parent, False):
290+
# Already seen
291+
break
292+
cannot_be_linked_directly[parent] = True
293+
parent = paths.dirname(parent)
288294
else:
289295
files_left_to_link.append((src, venv_path))
290296

@@ -298,7 +304,7 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
298304

299305
for src, venv_path in files_left_to_link:
300306
parent = paths.dirname(venv_path)
301-
if not parent or parent == ".":
307+
if not parent:
302308
# File in root, must be linked directly
303309
optimized_groups.setdefault(venv_path, [])
304310
optimized_groups[venv_path].append(src)
@@ -314,8 +320,8 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
314320
venv_path = parent
315321
next_parent = paths.dirname(parent)
316322
for _ in range(len(venv_path) + 1): # Iterate enough times
317-
if next_parent and next_parent != ".":
318-
if not (next_parent in cannot_be_linked_directly):
323+
if next_parent:
324+
if next_parent not in cannot_be_linked_directly:
319325
venv_path = next_parent
320326
next_parent = paths.dirname(next_parent)
321327
else:
@@ -328,7 +334,7 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
328334

329335
repo_name = ctx.label.repo_name
330336
if repo_name == "":
331-
repo_name = "_main"
337+
repo_name = "_main" if BZLMOD_ENABLED else "__main__"
332338
runfiles_root_prefix = paths.join(repo_name, site_packages_root)
333339

334340
# Finally, for each group, we create the VenvSymlinkEntry objects
@@ -339,14 +345,10 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
339345
).format(
340346
venv_path = venv_path,
341347
))
342-
if len(files) == 1:
343-
link_to_file = files[0]
344-
else:
345-
link_to_file = None
346348
venv_symlinks[venv_path] = VenvSymlinkEntry(
347349
kind = VenvSymlinkKind.LIB,
348350
link_to_path = paths.join(runfiles_root_prefix, venv_path),
349-
link_to_file = link_to_file,
351+
link_to_file = None,
350352
package = package,
351353
version = version_str,
352354
venv_path = venv_path,

0 commit comments

Comments
 (0)