From 7be1081c6f8e631696d61d4d4a3290682427e4ba Mon Sep 17 00:00:00 2001 From: Ignas Anikevicius Date: Thu, 11 May 2023 08:59:26 +0900 Subject: [PATCH] feat(bzlmod): a minimal entry_point support and a test Add an `entry_point` macro to the repo generated by the `pip.parse` extension. This works by using the canonical label literal, so should work without users needing to add any "spoke" repos to the `use_repo` statement. We test this by having an extra folder in the `bzlmod` example. --- .bazelrc | 4 +- examples/bzlmod/BUILD.bazel | 1 + examples/bzlmod/MODULE.bazel | 8 ++++ examples/bzlmod/entry_point/BUILD.bazel | 20 +++++++++ .../bzlmod/entry_point/test_entry_point.py | 43 +++++++++++++++++++ python/pip_install/pip_repository.bzl | 1 + ...ip_repository_requirements_bzlmod.bzl.tmpl | 7 +++ 7 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 examples/bzlmod/entry_point/BUILD.bazel create mode 100644 examples/bzlmod/entry_point/test_entry_point.py diff --git a/.bazelrc b/.bazelrc index e7e4af7bbd..fe542b3722 100644 --- a/.bazelrc +++ b/.bazelrc @@ -3,8 +3,8 @@ # This lets us glob() up all the files inside the examples to make them inputs to tests # (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it) # To update these lines, run tools/bazel_integration_test/update_deleted_packages.sh -build --deleted_packages=examples/build_file_generation,examples/build_file_generation/get_url,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/multi_python_versions,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_import,examples/py_proto_library,examples/relative_requirements,tests/compile_pip_requirements,tests/pip_repository_entry_points,tests/pip_deps -query --deleted_packages=examples/build_file_generation,examples/build_file_generation/get_url,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/multi_python_versions,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_import,examples/py_proto_library,examples/relative_requirements,tests/compile_pip_requirements,tests/pip_repository_entry_points,tests/pip_deps +build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod/entry_point,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,tests/compile_pip_requirements,tests/compile_pip_requirements_test_from_external_workspace,tests/ignore_root_user_error,tests/pip_repository_entry_points +query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod/entry_point,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,tests/compile_pip_requirements,tests/compile_pip_requirements_test_from_external_workspace,tests/ignore_root_user_error,tests/pip_repository_entry_points test --test_output=errors diff --git a/examples/bzlmod/BUILD.bazel b/examples/bzlmod/BUILD.bazel index 3183608897..e1f5790631 100644 --- a/examples/bzlmod/BUILD.bazel +++ b/examples/bzlmod/BUILD.bazel @@ -35,6 +35,7 @@ py_binary( py_test( name = "test", srcs = ["test.py"], + main = "test.py", deps = [":lib"], ) diff --git a/examples/bzlmod/MODULE.bazel b/examples/bzlmod/MODULE.bazel index d2d7d63871..145cebd276 100644 --- a/examples/bzlmod/MODULE.bazel +++ b/examples/bzlmod/MODULE.bazel @@ -24,11 +24,19 @@ register_toolchains( "@python3_9_toolchains//:all", ) +interpreter = use_extension("@rules_python//python/extensions:interpreter.bzl", "interpreter") +interpreter.install( + name = "interpreter_python3_9", + python_name = "python3_9", +) +use_repo(interpreter, "interpreter_python3_9") + pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") pip.parse( name = "pip", # Intentionally set it false because the "true" case is already covered by examples/bzlmod_build_file_generation incompatible_generate_aliases = False, + python_interpreter_target = "@interpreter_python3_9//:python", requirements_lock = "//:requirements_lock.txt", requirements_windows = "//:requirements_windows.txt", ) diff --git a/examples/bzlmod/entry_point/BUILD.bazel b/examples/bzlmod/entry_point/BUILD.bazel new file mode 100644 index 0000000000..dfc02b00a0 --- /dev/null +++ b/examples/bzlmod/entry_point/BUILD.bazel @@ -0,0 +1,20 @@ +load("@pip//:requirements.bzl", "entry_point") +load("@rules_python//python:defs.bzl", "py_test") + +alias( + name = "yamllint", + actual = entry_point("yamllint"), +) + +py_test( + name = "entry_point_test", + srcs = ["test_entry_point.py"], + data = [ + ":yamllint", + ], + env = { + "YAMLLINT_ENTRY_POINT": "$(rlocationpath :yamllint)", + }, + main = "test_entry_point.py", + deps = ["@rules_python//python/runfiles"], +) diff --git a/examples/bzlmod/entry_point/test_entry_point.py b/examples/bzlmod/entry_point/test_entry_point.py new file mode 100644 index 0000000000..5a37458348 --- /dev/null +++ b/examples/bzlmod/entry_point/test_entry_point.py @@ -0,0 +1,43 @@ +# Copyright 2023 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import pathlib +import subprocess +import unittest + +from python.runfiles import runfiles + + +class ExampleTest(unittest.TestCase): + def test_entry_point(self): + rlocation_path = os.environ.get("YAMLLINT_ENTRY_POINT") + assert ( + rlocation_path is not None + ), "expected 'YAMLLINT_ENTRY_POINT' env variable to be set to rlocation of the tool" + + entry_point = pathlib.Path(runfiles.Create().Rlocation(rlocation_path)) + self.assertTrue(entry_point.exists(), f"'{entry_point}' does not exist") + + proc = subprocess.run( + [str(entry_point), "--version"], + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + self.assertEqual(proc.stdout.decode("utf-8").strip(), "yamllint 1.28.0") + + +if __name__ == "__main__": + unittest.main() diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl index 406e12113d..5239fd5f9c 100644 --- a/python/pip_install/pip_repository.bzl +++ b/python/pip_install/pip_repository.bzl @@ -387,6 +387,7 @@ def _pip_repository_bzlmod_impl(rctx): for p in bzl_packages ]), "%%MACRO_TMPL%%": macro_tmpl, + "%%NAME%%": rctx.attr.name, "%%REQUIREMENTS_LOCK%%": str(requirements_txt), }) diff --git a/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl b/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl index 1b2e2178bb..b77bf39c38 100644 --- a/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl +++ b/python/pip_install/pip_repository_requirements_bzlmod.bzl.tmpl @@ -22,3 +22,10 @@ def data_requirement(name): def dist_info_requirement(name): return "%%MACRO_TMPL%%".format(_clean_name(name), "dist_info") + +def entry_point(pkg, script = None): + """entry_point returns the target of the canonical label of the package entrypoints. + """ + if not script: + script = pkg + return "@@%%NAME%%_{}//:rules_python_wheel_entry_point_{}".format(_clean_name(pkg), script)