diff --git a/py/BUILD.bazel b/py/BUILD.bazel index d12225d2..f0c38798 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -1,11 +1,9 @@ load("@aspect_bazel_lib//:bzl_library.bzl", "bzl_library") -# For Bazel 6.x compatibility, since -# PyRuntimeInfo shipped only with Bazel 7 -# Users can set, e.g. --@aspect_rules_py//py:interpreter_version=3.9.18 alias( name = "interpreter_version", - actual = "@rules_python//python/config_settings:python_version", + actual = "//py/settings:interpreter_version", + deprecation = "Please prefer py/settings:interpreter_version", visibility = ["//visibility:public"], ) @@ -34,6 +32,7 @@ bzl_library( "//py/private:py_unpacked_wheel", "//py/private:py_wheel", "//py/private:virtual", + "//py/private/link", "//py/private/py_venv", "@aspect_bazel_lib//lib:utils", ], @@ -41,6 +40,7 @@ bzl_library( # This needs to dep on @aspect_tools_telemetry_report but we don't have that in WORKSPACE # gazelle:exclude extensions.bzl +# # bzl_library( # name = "extensions", # srcs = [ diff --git a/py/defs.bzl b/py/defs.bzl index bc9ff216..65f4f3dc 100644 --- a/py/defs.bzl +++ b/py/defs.bzl @@ -42,14 +42,48 @@ load("//py/private:py_pex_binary.bzl", _py_pex_binary = "py_pex_binary") load("//py/private:py_pytest_main.bzl", _py_pytest_main = "py_pytest_main") load("//py/private:py_unpacked_wheel.bzl", _py_unpacked_wheel = "py_unpacked_wheel") load("//py/private:virtual.bzl", _resolutions = "resolutions") -load("//py/private/py_venv:defs.bzl", _py_venv_link = "py_venv_link") +load("//py/private/link:defs.bzl", _py_link_venv = "py_link_venv") +load("//py/private/py_venv:defs.bzl", _py_venv_binary = "py_venv_binary") py_pex_binary = _py_pex_binary py_pytest_main = _py_pytest_main # FIXME: Badly chosen name; will be replaced/migrated -py_venv = _py_venv_link -py_venv_link = _py_venv_link +def py_venv(name, srcs = [], data = [], deps = [], imports = None, testonly = False, **kwargs): + native.alias( + name = name, + actual = select({ + Label("//py/private/link:dynamic_venvs"): ":{}_dynamic".format(name), + Label("//py/private/link:static_venvs"): ":{}_static".format(name), + }), + tags = ["manual"], + ) + + _py_link_venv( + _py_binary, + name = "{}_dynamic".format(name), + srcs = srcs, + data = data, + deps = deps, + imports = kwargs.get("imports"), + tags = ["manual"], + testonly = kwargs.get("testonly", False), + target_compatible_with = kwargs.get("target_compatible_with", []), + ) + + _py_link_venv( + _py_venv_binary, + name = "{}_static".format(name), + srcs = srcs, + data = data, + deps = deps, + imports = kwargs.get("imports"), + tags = ["manual"], + testonly = kwargs.get("testonly", False), + target_compatible_with = kwargs.get("target_compatible_with", []), + ) + +py_venv_link = py_venv py_binary_rule = _py_binary py_test_rule = _py_test @@ -70,15 +104,12 @@ def _py_binary_or_test(name, rule, srcs, main, data = [], deps = [], **kwargs): **kwargs ) - _py_venv_link( - name = "{}.venv".format(name), + py_venv( + name = name + ".venv", srcs = srcs, data = data, deps = deps, - imports = kwargs.get("imports"), - tags = ["manual"], - testonly = kwargs.get("testonly", False), - target_compatible_with = kwargs.get("target_compatible_with", []), + **kwargs ) def py_binary(name, srcs = [], main = None, **kwargs): diff --git a/py/private/link/BUILD.bazel b/py/private/link/BUILD.bazel new file mode 100644 index 00000000..af533407 --- /dev/null +++ b/py/private/link/BUILD.bazel @@ -0,0 +1,40 @@ +load("@bazel_lib//:bzl_library.bzl", "bzl_library") +load("@bazel_skylib//rules:common_settings.bzl", "string_flag") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["link.py"]) + +bzl_library( + name = "link", + srcs = [ + "defs.bzl", + ], + deps = [ + "@bazel_skylib//lib:sets", + ], +) + +string_flag( + name = "venv_strategy", + build_setting_default = "dynamic", + values = [ + "dynamic", + "static", + ], + visibility = ["//visibility:public"], +) + +config_setting( + name = "static_venvs", + flag_values = { + ":venv_strategy": "static", + }, +) + +config_setting( + name = "dynamic_venvs", + flag_values = { + ":venv_strategy": "dynamic", + }, +) diff --git a/py/private/link/defs.bzl b/py/private/link/defs.bzl new file mode 100644 index 00000000..801c6057 --- /dev/null +++ b/py/private/link/defs.bzl @@ -0,0 +1,46 @@ +load("@bazel_skylib//lib:sets.bzl", "sets") + +def py_link_venv( + binary_rule, + name, + srcs, + args = [], + venv_name = None, + venv_dest = None, + **kwargs): + """ + Build a Python virtual environment and produce a script to link it into the + user's directory of choice. + + Args: + binary_rule (rule): A py_binary-alike rule to employ. Must build a "venv". + + venv_name (str): A name to use for venv's link. + + venv_dest (str): A path (relative to the repo + root/$BUILD_WORKING_DIRECTORY) where the link will be created. + + srcs (list): srcs for the underlying binary. + + args (list): args for the underlying binary. + + **kwargs (dict): Delegate args for the underlying binary rule. + + """ + + # Note that the binary is already wrapped with debug + link_script = str(Label("//py/private/link:link.py")) + + if venv_name != None: + args = ["--name=" + venv_name] + args + + if venv_dest != None: + args = ["--dest=" + venv_dest] + args + + binary_rule( + name = name, + args = args, + main = link_script, + srcs = sets.to_list(sets.make(srcs + [link_script])), + **kwargs + ) diff --git a/py/private/py_venv/link.py b/py/private/link/link.py similarity index 96% rename from py/private/py_venv/link.py rename to py/private/link/link.py index 28748e81..99123f17 100644 --- a/py/private/py_venv/link.py +++ b/py/private/link/link.py @@ -7,8 +7,6 @@ import argparse import os -import sys -import site from pathlib import Path @@ -23,7 +21,6 @@ def munge_venv_name(target_package, virtualenv_name): if __name__ == "__main__": virtualenv_home = os.path.normpath(os.environ["VIRTUAL_ENV"]) virtualenv_name = os.path.basename(virtualenv_home) - runfiles_dir = os.path.normpath(os.environ["RUNFILES_DIR"]) builddir = os.path.normpath(os.environ["BUILD_WORKING_DIRECTORY"]) target_package, target_name = os.environ["BAZEL_TARGET"].split("//", 1)[1].split(":") diff --git a/py/private/py_venv/BUILD.bazel b/py/private/py_venv/BUILD.bazel index d2e5576a..fb93cfc1 100644 --- a/py/private/py_venv/BUILD.bazel +++ b/py/private/py_venv/BUILD.bazel @@ -1,12 +1,10 @@ load("@bazel_lib//:bzl_library.bzl", "bzl_library") load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") -load(":defs.bzl", "py_venv_test") package(default_visibility = ["//py:__subpackages__"]) exports_files([ "entrypoint.tmpl.sh", - "link.py", ]) bool_flag( @@ -59,16 +57,6 @@ bzl_library( ], ) -py_venv_test( - name = "test_link", - srcs = [ - "link.py", - "test_link.py", - ], - imports = ["."], - main = "test_link.py", -) - bzl_library( name = "defs", srcs = ["defs.bzl"], diff --git a/py/private/py_venv/defs.bzl b/py/private/py_venv/defs.bzl index 272b0967..aa4ea366 100644 --- a/py/private/py_venv/defs.bzl +++ b/py/private/py_venv/defs.bzl @@ -1,8 +1,7 @@ """Implementation for the py_binary and py_test rules.""" -load(":py_venv.bzl", _py_venv = "py_venv", _py_venv_binary = "py_venv_binary", _py_venv_link = "py_venv_link", _py_venv_test = "py_venv_test") +load(":py_venv.bzl", _py_venv = "py_venv", _py_venv_binary = "py_venv_binary", _py_venv_test = "py_venv_test") py_venv = _py_venv -py_venv_link = _py_venv_link py_venv_binary = _py_venv_binary py_venv_test = _py_venv_test diff --git a/py/private/py_venv/py_venv.bzl b/py/private/py_venv/py_venv.bzl index 0f3788da..5d9ea722 100644 --- a/py/private/py_venv/py_venv.bzl +++ b/py/private/py_venv/py_venv.bzl @@ -430,19 +430,3 @@ _py_venv_test = rule( py_venv = _wrap_with_debug(_py_venv) py_venv_binary = _wrap_with_debug(_py_venv_binary) py_venv_test = _wrap_with_debug(_py_venv_test) - -def py_venv_link(venv_name = None, srcs = [], **kwargs): - """Build a Python virtual environment and produce a script to link it into the build directory.""" - - # Note that the binary is already wrapped with debug - link_script = str(Label("//py/private/py_venv:link.py")) - kwargs["debug"] = select({ - Label(":debug_venv_setting"): True, - "//conditions:default": False, - }) - py_venv_binary( - args = [] + (["--name=" + venv_name] if venv_name else []), - main = link_script, - srcs = srcs + [link_script], - **kwargs - ) diff --git a/py/settings/BUILD.bazel b/py/settings/BUILD.bazel new file mode 100644 index 00000000..c5ebff38 --- /dev/null +++ b/py/settings/BUILD.bazel @@ -0,0 +1,20 @@ +load("@bazel_skylib//rules:common_settings.bzl", "string_flag") + +# For Bazel 6.x compatibility, since +# PyRuntimeInfo shipped only with Bazel 7 +# Users can set, e.g. --@aspect_rules_py//py:interpreter_version=3.9.18 +alias( + name = "interpreter_version", + actual = "@rules_python//python/config_settings:python_version", + visibility = ["//visibility:public"], +) + +string_flag( + name = "venv_strategy", + build_setting_default = "dynamic", + values = [ + "dynamic", + "static", + ], + visibility = ["//visibility:public"], +) diff --git a/py/tests/venv-link/BUILD.bazel b/py/tests/venv-link/BUILD.bazel new file mode 100644 index 00000000..3a0e1e6e --- /dev/null +++ b/py/tests/venv-link/BUILD.bazel @@ -0,0 +1,11 @@ +load("//py/private/py_venv:defs.bzl", "py_venv_test") + +py_venv_test( + name = "test_link", + srcs = [ + "test_link.py", + "//py/private/link:link.py", + ], + imports = ["../../private/link/"], + main = "test_link.py", +) diff --git a/py/private/py_venv/test_link.py b/py/tests/venv-link/test_link.py similarity index 100% rename from py/private/py_venv/test_link.py rename to py/tests/venv-link/test_link.py diff --git a/py/unstable/defs.bzl b/py/unstable/defs.bzl index 497ddf85..61748b96 100644 --- a/py/unstable/defs.bzl +++ b/py/unstable/defs.bzl @@ -5,9 +5,8 @@ Unstable rules and preview machinery. No promises are made about compatibility across releases. """ -load("//py/private/py_venv:defs.bzl", _bin = "py_venv_binary", _link = "py_venv_link", _test = "py_venv_test", _venv = "py_venv") +load("//py/private/py_venv:defs.bzl", _bin = "py_venv_binary", _test = "py_venv_test", _venv = "py_venv") py_venv = _venv -py_venv_link = _link py_venv_binary = _bin py_venv_test = _test