Skip to content

Commit 2bca683

Browse files
committed
add tests
1 parent d346b0f commit 2bca683

2 files changed

Lines changed: 216 additions & 52 deletions

File tree

python/private/venv_runfiles.bzl

Lines changed: 32 additions & 29 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,17 @@ 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
8282
8383
Args:
8484
ctx: {type}`ctx` current ctx.
8585
entries: {type}`list[VenvSymlinkEntry]` the entries that describe the
8686
venv-relative
87+
return_conflicts: {type}`bool`. Only present for testing. If True,
88+
also return a list of the groups that had overlapping paths and had
89+
to be resolved and merged.
8790
8891
Returns:
8992
{type}`dict[str, dict[str, str|File]]` Mappings of venv paths to their
@@ -113,6 +116,7 @@ def build_link_map(ctx, entries):
113116

114117
# final paths to keep, grouped by kind
115118
keep_link_map = {} # dict[str kind, dict[path, str|File]]
119+
conflicts = [] if return_conflicts else None
116120
for kind, entries in entries_by_kind.items():
117121
# dict[str kind-relative path, str|File link_to]
118122
keep_kind_link_map = {}
@@ -128,12 +132,17 @@ def build_link_map(ctx, entries):
128132
else:
129133
keep_kind_link_map[entry.venv_path] = entry.link_to_path
130134
else:
135+
if return_conflicts:
136+
conflicts.append(group)
137+
131138
# Merge a group of overlapping prefixes
132139
_merge_venv_path_group(ctx, group, keep_kind_link_map)
133140

134141
keep_link_map[kind] = keep_kind_link_map
135-
136-
return keep_link_map
142+
if return_conflicts:
143+
return keep_link_map, conflicts
144+
else:
145+
return keep_link_map
137146

138147
def _group_venv_path_entries(entries):
139148
"""Group entries by VenvSymlinkEntry.venv_path overlap.
@@ -236,17 +245,6 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
236245

237246
all_files = sorted(files, key = lambda f: f.short_path)
238247

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-
250248
# venv paths that cannot be directly linked. Dict acting as set.
251249
cannot_be_linked_directly = {}
252250

@@ -257,7 +255,14 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
257255
# List of (File, str venv_path) tuples
258256
files_left_to_link = []
259257

260-
repo_runfiles_dirname = None
258+
# We want to minimize the number of files symlinked. Ideally, only the
259+
# top-level directories are symlinked. Unfortunately, shared libraries
260+
# complicate matters: if a shared library's directory is linked, then the
261+
# dynamic linker computes the wrong search path.
262+
#
263+
# To fix, we have to directly link shared libraries. This then means that
264+
# all the parent directories of the shared library can't be linked
265+
# directly.
261266
for src in all_files:
262267
if src.owner.repo_name != ctx.label.repo_name:
263268
# Files in other repos complicate symlink optimization, so
@@ -280,11 +285,13 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
280285
)
281286
parent = paths.dirname(venv_path)
282287
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:
288+
if not parent:
287289
break
290+
if cannot_be_linked_directly.get(parent, False):
291+
# Already seen
292+
break
293+
cannot_be_linked_directly[parent] = True
294+
parent = paths.dirname(parent)
288295
else:
289296
files_left_to_link.append((src, venv_path))
290297

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

299306
for src, venv_path in files_left_to_link:
300307
parent = paths.dirname(venv_path)
301-
if not parent or parent == ".":
308+
if not parent:
302309
# File in root, must be linked directly
303310
optimized_groups.setdefault(venv_path, [])
304311
optimized_groups[venv_path].append(src)
@@ -314,8 +321,8 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
314321
venv_path = parent
315322
next_parent = paths.dirname(parent)
316323
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):
324+
if next_parent:
325+
if next_parent not in cannot_be_linked_directly:
319326
venv_path = next_parent
320327
next_parent = paths.dirname(next_parent)
321328
else:
@@ -328,7 +335,7 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
328335

329336
repo_name = ctx.label.repo_name
330337
if repo_name == "":
331-
repo_name = "_main"
338+
repo_name = "_main" if BZLMOD_ENABLED else "__main__"
332339
runfiles_root_prefix = paths.join(repo_name, site_packages_root)
333340

334341
# Finally, for each group, we create the VenvSymlinkEntry objects
@@ -339,14 +346,10 @@ def get_venv_symlinks(ctx, files, package, version_str, site_packages_root):
339346
).format(
340347
venv_path = venv_path,
341348
))
342-
if len(files) == 1:
343-
link_to_file = files[0]
344-
else:
345-
link_to_file = None
346349
venv_symlinks[venv_path] = VenvSymlinkEntry(
347350
kind = VenvSymlinkKind.LIB,
348351
link_to_path = paths.join(runfiles_root_prefix, venv_path),
349-
link_to_file = link_to_file,
352+
link_to_file = None,
350353
package = package,
351354
version = version_str,
352355
venv_path = venv_path,

0 commit comments

Comments
 (0)