-
-
Notifications
You must be signed in to change notification settings - Fork 692
feat(venv): support data, include, and scripts schemes #3726
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 38 commits
b4e6496
c676d6e
10ace3b
0fd7c6d
7d2893f
16c5100
9e53c53
76cc0e0
9470aac
5b57de2
103ec9a
f41bfda
fe1ad5f
b35951a
52dfac5
45611a5
fd6cda6
958e61e
194693c
82b9acc
dd2b0b3
3ed727e
7561c72
24a94a2
1fabeea
473966b
dd5d8c2
08aeea4
747f7cb
03da47f
de2a11f
82e9e2a
cdb2cf1
e7ca80d
e16757e
e35d1a4
e38fd1c
9184bcc
db05136
51f614b
9681318
50cc8f0
cd18acc
8c3daaa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,17 +69,35 @@ def create_venv_app_files(ctx, deps, venv_dir_map): | |
| ctx.label.package, | ||
| ) | ||
|
|
||
| seen_bin_venv_paths = {} | ||
|
|
||
| for kind, kind_map in link_map.items(): | ||
| base = venv_dir_map[kind] | ||
| for venv_path, link_to in kind_map.items(): | ||
| bin_venv_path = paths.join(base, venv_path) | ||
| if bin_venv_path in seen_bin_venv_paths: | ||
| continue | ||
| seen_bin_venv_paths[bin_venv_path] = True | ||
|
|
||
| if is_file(link_to): | ||
| # use paths.join to handle ctx.label.package = "" | ||
| # runfile_prefix should be prepended as we use runfiles.root_symlinks | ||
| runfile_prefix = ctx.label.repo_name or ctx.workspace_name | ||
| symlink_from = paths.join(runfile_prefix, ctx.label.package, bin_venv_path) | ||
|
|
||
| runfiles_symlinks[symlink_from] = link_to | ||
|
|
||
| # On Windows, we need to explicitly create the symlink in the venv | ||
| # because the bootstrap script won't otherwise know about it. | ||
| if is_windows: | ||
| rf_path = paths.join(ctx_rf_path, bin_venv_path) | ||
| _, _, venv_path = bin_venv_path.partition(".venv/") | ||
| explicit_symlinks.append(ExplicitSymlink( | ||
| runfiles_path = rf_path, | ||
| venv_path = venv_path, | ||
| link_to_path = runfiles_root_path(ctx, link_to.short_path), | ||
| files = depset([link_to]), | ||
| )) | ||
| elif not is_windows: | ||
| venv_link = ctx.actions.declare_symlink(bin_venv_path) | ||
| venv_link_rf_path = runfiles_root_path(ctx, venv_link.short_path) | ||
|
|
@@ -275,10 +293,16 @@ def _get_file_venv_path(ctx, f, site_packages_root): | |
|
|
||
| Returns: | ||
| A tuple `(venv_path, rf_root_path)` if the file is under | ||
| `site_packages_root`, otherwise `(None, None)`. | ||
| `site_packages_root` or data/, bin/, include/ otherwise `(None, None)`. | ||
| """ | ||
| rf_root_path = runfiles_root_path(ctx, f.short_path) | ||
| _, _, repo_rel_path = rf_root_path.partition("/") | ||
|
|
||
| # Check for wheel data/bin/include folders first | ||
| for prefix in ["data/", "bin/", "include/"]: | ||
| if repo_rel_path.startswith(prefix): | ||
| return (repo_rel_path, rf_root_path) | ||
|
|
||
| head, found_sp_root, venv_path = repo_rel_path.partition(site_packages_root) | ||
| if head or not found_sp_root: | ||
| # If head is set, then the path didn't start with site_packages_root | ||
|
|
@@ -324,17 +348,37 @@ def get_venv_symlinks( | |
|
|
||
| all_files = sorted(files, key = lambda f: f.short_path) | ||
|
|
||
| cannot_be_linked_directly = {} | ||
| for dirname in [ | ||
| # The venv directories that bin, include, and data get put into are | ||
| # shared across wheels, are also shared across wheels, so we cannot link | ||
| # them directly | ||
| "bin", | ||
| "include", | ||
| "data", | ||
| # The data scheme is overlaid on the venv root, so the files under it | ||
| # could, in theory, get installed into e.g. bin/ or similar. Explicitly | ||
| # mark them as non-directly linkable to avoid issues. | ||
| "data/bin", | ||
| "data/include", | ||
| "data/lib", | ||
| "data/Scripts", | ||
| "data/Include", | ||
| "data/Lib", | ||
| ]: | ||
|
rickeylev marked this conversation as resolved.
|
||
| cannot_be_linked_directly[dirname] = True | ||
|
|
||
| # dict[str venv-relative dirname, bool is_namespace_package] | ||
| namespace_package_dirs = { | ||
| ns: True | ||
| for ns in _WELL_KNOWN_NAMESPACE_PACKAGES | ||
| } | ||
|
|
||
| # venv paths that cannot be directly linked. Dict acting as set. | ||
| cannot_be_linked_directly = { | ||
| cannot_be_linked_directly.update({ | ||
| dirname: True | ||
| for dirname in namespace_package_dirs.keys() | ||
| } | ||
| }) | ||
| for f in namespace_package_files: | ||
| venv_path, _ = _get_file_venv_path(ctx, f, site_packages_root) | ||
| if venv_path == None: | ||
|
|
@@ -452,19 +496,36 @@ def get_venv_symlinks( | |
|
|
||
| # Finally, for each group, we create the VenvSymlinkEntry objects | ||
| for venv_path, files in optimized_groups.items(): | ||
| if venv_path.startswith("data/"): | ||
| out_venv_path = venv_path[len("data/"):] | ||
| kind = VenvSymlinkKind.DATA | ||
| prefix = "" | ||
| elif venv_path.startswith("include/"): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about windows wheels? Do we not need to check for capitalized includes?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, because the wheel extraction always uses unix names. Platform-specific renaming happens at the py_binary level. Admittedly, I'm not entirely happy with this block of logic because it assumes how whl_library extracted the contents. Just another good reason we need to create a
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The rule would be taking what as an input? The wheel or extracted contents of the wheel? You mean the moving of the files around could be done in the build phase? I would definitely +1 that. With pipstar being the only code path that might be doable, but might require a 3.0 release.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whl_library would read entry point.txt and generate a target for each entry point. This target generates a platform aware/specific file (which shows up as a KIND: BIN entry in PyInfo), but . This file is venv agnostic (by way of the polyglot trick or equivalent). Py binary can then just copy/symlink that file into the venv bin directory. That's my rough thinking anyways |
||
| out_venv_path = venv_path[len("include/"):] | ||
| kind = VenvSymlinkKind.INCLUDE | ||
| prefix = "" | ||
| elif venv_path.startswith("bin/"): | ||
| out_venv_path = venv_path[len("bin/"):] | ||
| kind = VenvSymlinkKind.BIN | ||
| prefix = "" | ||
|
rickeylev marked this conversation as resolved.
|
||
| else: | ||
| out_venv_path = venv_path | ||
| kind = VenvSymlinkKind.LIB | ||
| prefix = site_packages_root | ||
|
|
||
| link_to_path = ( | ||
| _get_label_runfiles_repo(ctx, files[0].owner) + | ||
| "/" + | ||
| site_packages_root + | ||
| prefix + | ||
| venv_path | ||
| ) | ||
| venv_symlinks[venv_path] = VenvSymlinkEntry( | ||
| kind = VenvSymlinkKind.LIB, | ||
| kind = kind, | ||
| link_to_path = link_to_path, | ||
| link_to_file = None, | ||
| package = package, | ||
| version = version_str, | ||
| venv_path = venv_path, | ||
| venv_path = out_venv_path, | ||
| files = depset(files), | ||
| ) | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.