diff --git a/MODULE.bazel b/MODULE.bazel index 001c21c..85ede7d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -7,29 +7,11 @@ bazel_dep(name = "bazel_skylib", version = "1.8.2") bazel_dep(name = "rules_python", version = "1.6.3") bazel_dep(name = "rules_rust", version = "0.74.0") -local_runtime_repo = use_repo_rule( - "@rules_python//python/local_toolchains:repos.bzl", - "local_runtime_repo", -) -local_runtime_toolchains_repo = use_repo_rule( - "@rules_python//python/local_toolchains:repos.bzl", - "local_runtime_toolchains_repo", -) - -local_runtime_repo( - name = "local_python3", - interpreter_path = "python3", - on_failure = "fail", - dev_dependency = True, -) -local_runtime_toolchains_repo( - name = "local_python_toolchains", - runtimes = ["local_python3"], - dev_dependency = True, -) +python = use_extension("//bazel:python.bzl", "python") +use_repo(python, "python") rust = use_extension("//bazel:rust.bzl", "rust") use_repo(rust, "rust") -register_toolchains("@local_python_toolchains//:all", dev_dependency = True) +register_toolchains("@python//:python") register_toolchains("@rust//:rust") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 44b3b9c..8a117a8 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -146,6 +146,23 @@ }, "selectedYankedVersions": {}, "moduleExtensions": { + "//bazel:python.bzl%python": { + "general": { + "bzlTransitiveDigest": "CbGiMYJXjcea8dmoNxUWe/lWOjqRWfQPTXFHUUMheIY=", + "usagesDigest": "bcY43VsTrhTJ8N4Dj5FtsgMhZxLyKKjHP+wWK4ntJQ4=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "python": { + "bzlFile": "@@//bazel:python.bzl", + "ruleClassName": "python_repository", + "attributes": {} + } + }, + "recordedRepoMappingEntries": [] + } + }, "//bazel:rust.bzl%rust": { "general": { "bzlTransitiveDigest": "4kUzQyjRjzchWIBZJKkNs8LuO4F+g/DwuwtTa0RTPcU=", diff --git a/bazel/BUILD b/bazel/BUILD index d4baa17..6b4254d 100644 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -1,4 +1,6 @@ exports_files([ + "python.BUILD.template", + "python.bzl", "rust.BUILD.template", "rust.bzl", "utils.bzl", diff --git a/bazel/python.BUILD.template b/bazel/python.BUILD.template new file mode 100644 index 0000000..308f3ef --- /dev/null +++ b/bazel/python.BUILD.template @@ -0,0 +1,25 @@ +load("@rules_python//python:py_runtime.bzl", "py_runtime") +load("@rules_python//python:py_runtime_pair.bzl", "py_runtime_pair") + +py_runtime( + name = "runtime", + implementation_name = "cpython", + interpreter_path = "{interpreter_path}", + interpreter_version_info = { + "major": "{major}", + "minor": "{minor}", + "micro": "{micro}", + }, + python_version = "PY3", +) + +py_runtime_pair( + name = "runtime_pair", + py3_runtime = ":runtime", +) + +toolchain( + name = "python", + toolchain = ":runtime_pair", + toolchain_type = "@rules_python//python:toolchain_type", +) diff --git a/bazel/python.bzl b/bazel/python.bzl new file mode 100644 index 0000000..ddbee84 --- /dev/null +++ b/bazel/python.bzl @@ -0,0 +1,46 @@ +load("//bazel:utils.bzl", "execute", "require_env") + + +def _python_repository_impl(repository_ctx): + root = repository_ctx.path(require_env(repository_ctx, "PYTHON_TOOLCHAIN_ROOT")) + python3 = root.get_child("bin/python3") + + version = execute( + repository_ctx, + [ + str(python3), + "-c", + "import sys; print('{}.{}.{}'.format(*sys.version_info[:3]))", + ], + ) + parts = version.split(".") + if len(parts) != 3: + fail("python3 did not report a major.minor.micro version") + + repository_ctx.file("WORKSPACE.bazel", "") + repository_ctx.template( + "BUILD.bazel", + Label("//bazel:python.BUILD.template"), + { + "{interpreter_path}": str(python3), + "{major}": parts[0], + "{minor}": parts[1], + "{micro}": parts[2], + }, + ) + + +python_repository = repository_rule( + implementation = _python_repository_impl, + local = True, + environ = ["PYTHON_TOOLCHAIN_ROOT"], +) + + +def _python_impl(module_ctx): + python_repository(name = "python") + + +python = module_extension( + implementation = _python_impl, +) diff --git a/configs/nixos/modules/shell/python.nix b/configs/nixos/modules/shell/python.nix index 7b27ce6..a77471a 100644 --- a/configs/nixos/modules/shell/python.nix +++ b/configs/nixos/modules/shell/python.nix @@ -13,6 +13,8 @@ in options.modules.shell.python.enable = lib.mkEnableOption "Python tools for the primary user's shell environment"; config = lib.mkIf cfg.enable { + registry.env-var.${config.networking.hostName}.PYTHON_TOOLCHAIN_ROOT = "${pkgs.python3}"; + home-manager.users.${user}.home.packages = [ pkgs.python3 ]; }; } diff --git a/third_party/python/README.md b/third_party/python/README.md index 0412b4e..c913308 100644 --- a/third_party/python/README.md +++ b/third_party/python/README.md @@ -1,7 +1,7 @@ # Vendored Python packages This package exposes vendored Python dependencies through stable public Bazel targets. -Bazel runs Python targets with the local `python3` runtime. +Bazel uses `PYTHON_TOOLCHAIN_ROOT` to find the monorepo `python3` runtime. Project code depends on aliases in `//third_party/python`. It does not depend on versioned package directories directly. @@ -22,7 +22,7 @@ Use the upstream package name for public aliases. For command-line tools, add a `_bin` suffix to the binary target. Preserve upstream license files and package metadata. -Keep local Bazel files separate from upstream source when possible. +Keep repository Bazel files separate from upstream source when possible. Add optional dependencies as separate public targets. Do not bundle optional dependencies into the primary package target.