-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add a virtual environment rule
- Loading branch information
Showing
3 changed files
with
83 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,14 @@ | ||
py_binary( | ||
name = "poetry_deps", | ||
srcs = ["poetry_deps.py"], | ||
visibility = ["//visibility:public"], | ||
visibility = ["__subpackages__"], | ||
deps = [ | ||
"@rules_poetry_pip//:pkg", | ||
], | ||
) | ||
|
||
py_binary( | ||
name = "py_venv", | ||
srcs = ["py_venv.py"], | ||
visibility = ["__subpackages__"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
def _py_venv_impl(ctx): | ||
""" | ||
Rule to link Python package into a virtual environment. | ||
Arguments: | ||
ctx: The rule context. | ||
Attributes: | ||
deps: label_list The package dependencies list. | ||
Private attributes: | ||
_py_venv: | ||
Returns: | ||
The providers list or a tuple with a venv package. | ||
""" | ||
|
||
deps = ctx.attr.deps | ||
output = ctx.actions.declare_directory("venv/{}".format(ctx.label.name)) | ||
import_paths = ["{}/external/{}".format(ctx.bin_dir.path, path) for dep in deps for path in dep[PyInfo].imports.to_list()] | ||
|
||
ctx.actions.run( | ||
outputs = [output], | ||
inputs = ctx.files.deps, | ||
mnemonic = "CreateVenv", | ||
progress_message = "Creating venv {}".format(ctx.label.name), | ||
arguments = [output.path] + import_paths, | ||
use_default_shell_env = True, | ||
executable = ctx.executable._py_venv, | ||
) | ||
|
||
transitive_depsets = [dep[PyInfo].transitive_sources for dep in deps] | ||
runfiles = [output] + [item for dep in transitive_depsets for item in dep.to_list()] | ||
files = depset([output], transitive = transitive_depsets) | ||
|
||
return [ | ||
DefaultInfo(files = files, runfiles = ctx.runfiles(files = runfiles)), | ||
PyInfo(transitive_sources = files, imports = depset(["_main/" + output.short_path])), | ||
] | ||
|
||
py_venv = rule( | ||
implementation = _py_venv_impl, | ||
provides = [PyInfo], | ||
attrs = { | ||
"deps": attr.label_list(doc = "The package dependencies list"), | ||
"_py_venv": attr.label(default = ":py_venv", cfg = "exec", executable = True), | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import argparse | ||
from pathlib import Path | ||
|
||
SKIP_SET = {Path("requirements.txt")} | ||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser(description="Download and install a Poetry package") | ||
|
||
parser.add_argument("target", type=Path, help="output virtual environment directory") | ||
parser.add_argument("path", type=Path, nargs="*", help="python package path") | ||
|
||
args = parser.parse_args() | ||
|
||
for python_path in args.path: | ||
if not python_path.exists() or not python_path.is_dir(): | ||
raise RuntimeError(f"Required Python package directory {path} does not exist") | ||
|
||
for directory_path, _, file_names in python_path.walk(): | ||
in_package_directory = directory_path.relative_to(python_path) | ||
target_directory = args.target / in_package_directory | ||
target_directory.mkdir(parents=True, exist_ok=True) | ||
relative_directory = directory_path.relative_to(target_directory, walk_up=True) | ||
|
||
for file_name in file_names: | ||
if in_package_directory / file_name not in SKIP_SET: | ||
symlink_path = target_directory / file_name | ||
target_path = relative_directory / file_name | ||
symlink_path.symlink_to(target_path) |