diff --git a/CHANGELOG.md b/CHANGELOG.md index b481832c4c..415b936e8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,13 @@ A brief description of the categories of changes: the downloading of metadata is done in parallel can be done using `parallel_download` attribute. * (deps): `rules_python` depends now on `rules_cc` 0.0.9 +* (pip_parse): A new flag `use_hub_alias_dependencies` has been added that is going + to become default in the next release. This makes use of `dep_template` flag + in the `whl_library` rule. This also affects the + `experimental_requirement_cycles` feature where the dependencies that are in + a group would be only accessible via the hub repo aliases. If you still + depend on legacy labels instead of the hub repo aliases and you use the + `experimental_requirement_cycles`, now is a good time to migrate. [0.XX.0]: https://github.com/bazelbuild/rules_python/releases/tag/0.XX.0 [python_default_visibility]: gazelle/README.md#directive-python_default_visibility diff --git a/python/pip_install/pip_repository.bzl b/python/pip_install/pip_repository.bzl index 55d61fcea0..db6736836f 100644 --- a/python/pip_install/pip_repository.bzl +++ b/python/pip_install/pip_repository.bzl @@ -365,9 +365,12 @@ def _pip_repository_impl(rctx): "python_interpreter": _get_python_interpreter_attr(rctx), "quiet": rctx.attr.quiet, "repo": rctx.attr.name, - "repo_prefix": "{}_".format(rctx.attr.name), "timeout": rctx.attr.timeout, } + if rctx.attr.use_hub_alias_dependencies: + config["dep_template"] = "@{}//{{name}}:{{target}}".format(rctx.attr.name) + else: + config["repo_prefix"] = "{}_".format(rctx.attr.name) if rctx.attr.python_interpreter_target: config["python_interpreter_target"] = str(rctx.attr.python_interpreter_target) @@ -387,6 +390,13 @@ def _pip_repository_impl(rctx): rctx.file("BUILD.bazel", _BUILD_FILE_CONTENTS) rctx.template("requirements.bzl", rctx.attr._template, substitutions = { + " # %%GROUP_LIBRARY%%": """\ + group_repo = "{name}__groups" + group_library( + name = group_repo, + repo_prefix = "{name}_", + groups = all_requirement_groups, + )""".format(name = rctx.attr.name) if not rctx.attr.use_hub_alias_dependencies else "", "%%ALL_DATA_REQUIREMENTS%%": _format_repr_list([ macro_tmpl.format(p, "data") for p in bzl_packages @@ -595,6 +605,8 @@ python_interpreter. An example value: "@python3_x86_64-unknown-linux-gnu//:pytho "repo_prefix": attr.string( doc = """ Prefix for the generated packages will be of the form `@//...` + +DEPRECATED. Only left for people who vendor requirements.bzl. """, ), # 600 is documented as default here: https://docs.bazel.build/versions/master/skylark/lib/repository_ctx.html#execute @@ -637,6 +649,15 @@ attributes. allow_single_file = True, doc = "Override the requirements_lock attribute when the host platform is Windows", ), + "use_hub_alias_dependencies": attr.bool( + default = False, + doc = """\ +Controls if the hub alias dependencies are used. If set to true, then the +group_library will be included in the hub repo. + +True will become default in a subsequent release. +""", + ), "_template": attr.label( default = ":pip_repository_requirements.bzl.tmpl", ), @@ -886,7 +907,7 @@ def _whl_library_impl(rctx): entry_points[entry_point_without_py] = entry_point_script_name build_file_contents = generate_whl_library_build_bazel( - repo_prefix = rctx.attr.repo_prefix, + dep_template = rctx.attr.dep_template or "@{}{{name}}//:{{target}}".format(rctx.attr.repo_prefix), whl_name = whl_path.basename, dependencies = metadata["deps"], dependencies_by_platform = metadata["deps_by_platform"], @@ -941,6 +962,13 @@ whl_library_attrs = dict({ ), allow_files = True, ), + "dep_template": attr.string( + doc = """ +The dep template to use for referencing the dependencies. It should have `{name}` +and `{target}` tokens that will be replaced with the normalized distribution name +and the target that we need respectively. +""", + ), "filename": attr.string( doc = "Download the whl file to this filename. Only used when the `urls` is passed. If not specified, will be auto-detected from the `urls`.", ), diff --git a/python/pip_install/pip_repository_requirements.bzl.tmpl b/python/pip_install/pip_repository_requirements.bzl.tmpl index 2b88f5c41a..8e17720374 100644 --- a/python/pip_install/pip_repository_requirements.bzl.tmpl +++ b/python/pip_install/pip_repository_requirements.bzl.tmpl @@ -58,12 +58,7 @@ def install_deps(**whl_library_kwargs): for requirement in group_requirements } - group_repo = "%%NAME%%__groups" - group_library( - name = group_repo, - repo_prefix = "%%NAME%%_", - groups = all_requirement_groups, - ) + # %%GROUP_LIBRARY%% # Install wheels which may be participants in a group whl_config = dict(_config) diff --git a/python/pip_install/private/generate_group_library_build_bazel.bzl b/python/pip_install/private/generate_group_library_build_bazel.bzl index c122b04781..5fa93e22b7 100644 --- a/python/pip_install/private/generate_group_library_build_bazel.bzl +++ b/python/pip_install/private/generate_group_library_build_bazel.bzl @@ -22,9 +22,10 @@ load( "WHEEL_FILE_PUBLIC_LABEL", ) load("//python/private:normalize_name.bzl", "normalize_name") +load("//python/private:text_util.bzl", "render") _PRELUDE = """\ -load("@rules_python//python:defs.bzl", "py_library", "py_binary") +load("@rules_python//python:defs.bzl", "py_library") """ _GROUP_TEMPLATE = """\ @@ -62,26 +63,39 @@ def _generate_group_libraries(repo_prefix, group_name, group_members): which make up the group. """ - lib_dependencies = [ - "@%s%s//:%s" % (repo_prefix, normalize_name(d), PY_LIBRARY_IMPL_LABEL) - for d in group_members - ] - whl_file_deps = [ - "@%s%s//:%s" % (repo_prefix, normalize_name(d), WHEEL_FILE_IMPL_LABEL) - for d in group_members - ] - visibility = [ - "@%s%s//:__pkg__" % (repo_prefix, normalize_name(d)) - for d in group_members - ] + group_members = sorted(group_members) + + if repo_prefix: + lib_dependencies = [ + "@%s%s//:%s" % (repo_prefix, normalize_name(d), PY_LIBRARY_IMPL_LABEL) + for d in group_members + ] + whl_file_deps = [ + "@%s%s//:%s" % (repo_prefix, normalize_name(d), WHEEL_FILE_IMPL_LABEL) + for d in group_members + ] + visibility = [ + "@%s%s//:__pkg__" % (repo_prefix, normalize_name(d)) + for d in group_members + ] + else: + lib_dependencies = [ + "//%s:%s" % (normalize_name(d), PY_LIBRARY_IMPL_LABEL) + for d in group_members + ] + whl_file_deps = [ + "//%s:%s" % (normalize_name(d), WHEEL_FILE_IMPL_LABEL) + for d in group_members + ] + visibility = ["//:__subpackages__"] return _GROUP_TEMPLATE.format( name = normalize_name(group_name), whl_public_label = WHEEL_FILE_PUBLIC_LABEL, - whl_deps = repr(whl_file_deps), + whl_deps = render.indent(render.list(whl_file_deps)).lstrip(), lib_public_label = PY_LIBRARY_PUBLIC_LABEL, - lib_deps = repr(lib_dependencies), - visibility = repr(visibility), + lib_deps = render.indent(render.list(lib_dependencies)).lstrip(), + visibility = render.indent(render.list(visibility)).lstrip(), ) def generate_group_library_build_bazel( diff --git a/python/pip_install/private/generate_whl_library_build_bazel.bzl b/python/pip_install/private/generate_whl_library_build_bazel.bzl index b1219096ba..8010ccbad8 100644 --- a/python/pip_install/private/generate_whl_library_build_bazel.bzl +++ b/python/pip_install/private/generate_whl_library_build_bazel.bzl @@ -213,7 +213,7 @@ selects.config_setting_group( def generate_whl_library_build_bazel( *, - repo_prefix, + dep_template, whl_name, dependencies, dependencies_by_platform, @@ -226,7 +226,7 @@ def generate_whl_library_build_bazel( """Generate a BUILD file for an unzipped Wheel Args: - repo_prefix: the repo prefix that should be used for dependency lists. + dep_template: the dependency template that should be used for dependency lists. whl_name: the whl_name that this is generated for. dependencies: a list of PyPI packages that are dependencies to the py_library. dependencies_by_platform: a dict[str, list] of PyPI packages that may vary by platform. @@ -328,38 +328,49 @@ def generate_whl_library_build_bazel( lib_dependencies = _render_list_and_select( deps = dependencies, deps_by_platform = dependencies_by_platform, - tmpl = "@{}{{}}//:{}".format(repo_prefix, PY_LIBRARY_PUBLIC_LABEL), + tmpl = dep_template.format(name = "{}", target = PY_LIBRARY_PUBLIC_LABEL), ) whl_file_deps = _render_list_and_select( deps = dependencies, deps_by_platform = dependencies_by_platform, - tmpl = "@{}{{}}//:{}".format(repo_prefix, WHEEL_FILE_PUBLIC_LABEL), + tmpl = dep_template.format(name = "{}", target = WHEEL_FILE_PUBLIC_LABEL), ) # If this library is a member of a group, its public label aliases need to # point to the group implementation rule not the implementation rules. We # also need to mark the implementation rules as visible to the group # implementation. - if group_name: - group_repo = repo_prefix + "_groups" - label_tmpl = "\"@{}//:{}_{{}}\"".format(group_repo, normalize_name(group_name)) - impl_vis = ["@{}//:__pkg__".format(group_repo)] + if group_name and "//:" in dep_template: + # This is the legacy behaviour where the group library is outside the hub repo + label_tmpl = dep_template.format( + name = "_groups", + target = normalize_name(group_name) + "_{}", + ) + impl_vis = [dep_template.format( + name = "_groups", + target = "__pkg__", + )] additional_content.extend([ "", render.alias( name = PY_LIBRARY_PUBLIC_LABEL, - actual = label_tmpl.format(PY_LIBRARY_PUBLIC_LABEL), + actual = repr(label_tmpl.format(PY_LIBRARY_PUBLIC_LABEL)), ), "", render.alias( name = WHEEL_FILE_PUBLIC_LABEL, - actual = label_tmpl.format(WHEEL_FILE_PUBLIC_LABEL), + actual = repr(label_tmpl.format(WHEEL_FILE_PUBLIC_LABEL)), ), ]) py_library_label = PY_LIBRARY_IMPL_LABEL whl_file_label = WHEEL_FILE_IMPL_LABEL + elif group_name: + py_library_label = PY_LIBRARY_PUBLIC_LABEL + whl_file_label = WHEEL_FILE_PUBLIC_LABEL + impl_vis = [dep_template.format(name = "", target = "__subpackages__")] + else: py_library_label = PY_LIBRARY_PUBLIC_LABEL whl_file_label = WHEEL_FILE_PUBLIC_LABEL diff --git a/python/private/BUILD.bazel b/python/private/BUILD.bazel index f1928e2441..fdbd20b896 100644 --- a/python/private/BUILD.bazel +++ b/python/private/BUILD.bazel @@ -227,6 +227,7 @@ bzl_library( ":normalize_name_bzl", ":text_util_bzl", ":version_label_bzl", + "//python/pip_install/private:generate_group_library_build_bazel_bzl", ], ) diff --git a/python/private/bzlmod/pip.bzl b/python/private/bzlmod/pip.bzl index 3d5c0f5a86..ce681259ed 100644 --- a/python/private/bzlmod/pip.bzl +++ b/python/private/bzlmod/pip.bzl @@ -18,7 +18,6 @@ load("@bazel_features//:features.bzl", "bazel_features") load("@pythons_hub//:interpreters.bzl", "DEFAULT_PYTHON_VERSION", "INTERPRETER_LABELS") load( "//python/pip_install:pip_repository.bzl", - "group_library", "locked_requirements_label", "pip_repository_attrs", "use_isolated", @@ -101,7 +100,7 @@ You cannot use both the additive_build_content and additive_build_content_file a whl_mods = whl_mods, ) -def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides, simpleapi_cache): +def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides, group_map, simpleapi_cache): python_interpreter_target = pip_attr.python_interpreter_target # if we do not have the python_interpreter set in the attributes @@ -129,6 +128,7 @@ def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides, simpleapi_ca hub_name, version_label(pip_attr.python_version), ) + major_minor = _major_minor_version(pip_attr.python_version) requirements_lock = locked_requirements_label(module_ctx, pip_attr) @@ -171,12 +171,11 @@ def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides, simpleapi_ca for whl_name in group_whls } - group_repo = "%s__groups" % (pip_name,) - group_library( - name = group_repo, - repo_prefix = pip_name + "_", - groups = pip_attr.experimental_requirement_cycles, - ) + # TODO @aignas 2024-04-05: how do we support different requirement + # cycles for different abis/oses? For now we will need the users to + # assume the same groups across all versions/platforms until we start + # using an alternative cycle resolution strategy. + group_map[hub_name] = pip_attr.experimental_requirement_cycles else: whl_group_mapping = {} requirement_cycles = {} @@ -202,8 +201,6 @@ def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides, simpleapi_ca parallel_download = pip_attr.parallel_download, ) - major_minor = _major_minor_version(pip_attr.python_version) - # Create a new wheel library for each of the different whls for whl_name, requirement_line in requirements: # We are not using the "sanitized name" because the user @@ -220,7 +217,7 @@ def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides, simpleapi_ca repo_name = "{}_{}".format(pip_name, whl_name) whl_library_args = dict( repo = pip_name, - repo_prefix = pip_name + "_", + dep_template = "@{}//{{name}}:{{target}}".format(hub_name), requirement = requirement_line, ) maybe_args = dict( @@ -422,6 +419,7 @@ def _pip_impl(module_ctx): # dict[hub, dict[whl, dict[version, str pip]]] # Where hub, whl, and pip are the repo names hub_whl_map = {} + hub_group_map = {} simpleapi_cache = {} @@ -460,7 +458,7 @@ def _pip_impl(module_ctx): else: pip_hub_map[pip_attr.hub_name].python_versions.append(pip_attr.python_version) - _create_whl_repos(module_ctx, pip_attr, hub_whl_map, whl_overrides, simpleapi_cache) + _create_whl_repos(module_ctx, pip_attr, hub_whl_map, whl_overrides, hub_group_map, simpleapi_cache) for hub_name, whl_map in hub_whl_map.items(): pip_repository( @@ -471,6 +469,7 @@ def _pip_impl(module_ctx): for key, value in whl_map.items() }, default_version = _major_minor_version(DEFAULT_PYTHON_VERSION), + groups = hub_group_map.get(hub_name), ) def _pip_parse_ext_attrs(): diff --git a/python/private/bzlmod/pip_repository.bzl b/python/private/bzlmod/pip_repository.bzl index d96131dad7..3a09766f65 100644 --- a/python/private/bzlmod/pip_repository.bzl +++ b/python/private/bzlmod/pip_repository.bzl @@ -32,6 +32,7 @@ def _pip_repository_impl(rctx): for key, values in rctx.attr.whl_map.items() }, default_version = rctx.attr.default_version, + requirement_cycles = rctx.attr.groups, ) for path, contents in aliases.items(): rctx.file(path, contents) @@ -68,6 +69,9 @@ This is the default python version in the format of X.Y. This should match what is setup by the 'python' extension using the 'is_default = True' setting.""", ), + "groups": attr.string_list_dict( + mandatory = False, + ), "repo_name": attr.string( mandatory = True, doc = "The apparent name of the repo. This is needed because in bzlmod, the name attribute becomes the canonical name.", diff --git a/python/private/render_pkg_aliases.bzl b/python/private/render_pkg_aliases.bzl index 5851baf570..bc1bab2049 100644 --- a/python/private/render_pkg_aliases.bzl +++ b/python/private/render_pkg_aliases.bzl @@ -16,6 +16,19 @@ This is used in bzlmod and non-bzlmod setups.""" +load( + "//python/pip_install/private:generate_group_library_build_bazel.bzl", + "generate_group_library_build_bazel", +) # buildifier: disable=bzl-visibility +load( + ":labels.bzl", + "DATA_LABEL", + "DIST_INFO_LABEL", + "PY_LIBRARY_IMPL_LABEL", + "PY_LIBRARY_PUBLIC_LABEL", + "WHEEL_FILE_IMPL_LABEL", + "WHEEL_FILE_PUBLIC_LABEL", +) load(":normalize_name.bzl", "normalize_name") load(":text_util.bzl", "render") @@ -43,13 +56,18 @@ def _render_whl_library_alias( name, default_version, aliases, + target_name, **kwargs): """Render an alias for common targets.""" if len(aliases) == 1 and not aliases[0].version: alias = aliases[0] return render.alias( name = name, - actual = repr("@{repo}//:{name}".format(repo = alias.repo, name = name)), + actual = repr("@{repo}//:{name}".format( + repo = alias.repo, + name = target_name, + )), + **kwargs ) # Create the alias repositories which contains different select @@ -58,7 +76,7 @@ def _render_whl_library_alias( selects = {} no_match_error = "_NO_MATCH_ERROR" for alias in sorted(aliases, key = lambda x: x.version): - actual = "@{repo}//:{name}".format(repo = alias.repo, name = name) + actual = "@{repo}//:{name}".format(repo = alias.repo, name = target_name) selects.setdefault(actual, []).append(alias.config_setting) if alias.version == default_version: selects[actual].append("//conditions:default") @@ -84,7 +102,7 @@ def _render_whl_library_alias( **kwargs ) -def _render_common_aliases(*, name, aliases, default_version = None): +def _render_common_aliases(*, name, aliases, default_version = None, group_name = None): lines = [ """load("@bazel_skylib//lib:selects.bzl", "selects")""", """package(default_visibility = ["//visibility:public"])""", @@ -119,17 +137,37 @@ def _render_common_aliases(*, name, aliases, default_version = None): lines.extend( [ _render_whl_library_alias( - name = target, + name = name, default_version = default_version, aliases = aliases, + target_name = target_name, + visibility = ["//_groups:__subpackages__"] if name.startswith("_") else None, ) - for target in ["pkg", "whl", "data", "dist_info"] + for target_name, name in { + PY_LIBRARY_PUBLIC_LABEL: PY_LIBRARY_IMPL_LABEL if group_name else PY_LIBRARY_PUBLIC_LABEL, + WHEEL_FILE_PUBLIC_LABEL: WHEEL_FILE_IMPL_LABEL if group_name else WHEEL_FILE_PUBLIC_LABEL, + DATA_LABEL: DATA_LABEL, + DIST_INFO_LABEL: DIST_INFO_LABEL, + }.items() ], ) + if group_name: + lines.extend( + [ + render.alias( + name = "pkg", + actual = repr("//_groups:{}_pkg".format(group_name)), + ), + render.alias( + name = "whl", + actual = repr("//_groups:{}_whl".format(group_name)), + ), + ], + ) return "\n\n".join(lines) -def render_pkg_aliases(*, aliases, default_version = None): +def render_pkg_aliases(*, aliases, default_version = None, requirement_cycles = None): """Create alias declarations for each PyPI package. The aliases should be appended to the pip_repository BUILD.bazel file. These aliases @@ -140,6 +178,7 @@ def render_pkg_aliases(*, aliases, default_version = None): aliases: dict, the keys are normalized distribution names and values are the whl_alias instances. default_version: the default version to be used for the aliases. + requirement_cycles: any package groups to also add. Returns: A dict of file paths and their contents. @@ -150,16 +189,33 @@ def render_pkg_aliases(*, aliases, default_version = None): elif type(aliases) != type({}): fail("The aliases need to be provided as a dict, got: {}".format(type(aliases))) - return { + whl_group_mapping = {} + if requirement_cycles: + requirement_cycles = { + name: [normalize_name(whl_name) for whl_name in whls] + for name, whls in requirement_cycles.items() + } + + whl_group_mapping = { + whl_name: group_name + for group_name, group_whls in requirement_cycles.items() + for whl_name in group_whls + } + + files = { "{}/BUILD.bazel".format(normalize_name(name)): _render_common_aliases( name = normalize_name(name), aliases = pkg_aliases, default_version = default_version, + group_name = whl_group_mapping.get(normalize_name(name)), ).strip() for name, pkg_aliases in aliases.items() } + if requirement_cycles: + files["_groups/BUILD.bazel"] = generate_group_library_build_bazel("", requirement_cycles) + return files -def whl_alias(*, repo, version = None, config_setting = None): +def whl_alias(*, repo, version = None, config_setting = None, extra_targets = None): """The bzl_packages value used by by the render_pkg_aliases function. This contains the minimum amount of information required to generate correct @@ -173,6 +229,8 @@ def whl_alias(*, repo, version = None, config_setting = None): is no match found during a select. config_setting: optional(Label or str), the config setting that we should use. Defaults to "@rules_python//python/config_settings:is_python_{version}". + extra_targets: optional(list[str]), the extra targets that we need to create + aliases for. Returns: a struct with the validated and parsed values. @@ -188,4 +246,5 @@ def whl_alias(*, repo, version = None, config_setting = None): repo = repo, version = version, config_setting = config_setting, + extra_targets = extra_targets or [], ) diff --git a/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl b/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl index ddc9da7097..a38d657962 100644 --- a/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl +++ b/tests/pip_hub_repository/render_pkg_aliases/render_pkg_aliases_test.bzl @@ -388,6 +388,50 @@ def _test_aliases_are_created_for_all_wheels(env): _tests.append(_test_aliases_are_created_for_all_wheels) +def _test_aliases_with_groups(env): + actual = render_pkg_aliases( + default_version = "3.2", + aliases = { + "bar": [ + whl_alias(version = "3.1", repo = "pypi_31_bar"), + whl_alias(version = "3.2", repo = "pypi_32_bar"), + ], + "baz": [ + whl_alias(version = "3.1", repo = "pypi_31_baz"), + whl_alias(version = "3.2", repo = "pypi_32_baz"), + ], + "foo": [ + whl_alias(version = "3.1", repo = "pypi_32_foo"), + whl_alias(version = "3.2", repo = "pypi_31_foo"), + ], + }, + requirement_cycles = { + "group": ["bar", "baz"], + }, + ) + + want_files = [ + "bar/BUILD.bazel", + "foo/BUILD.bazel", + "baz/BUILD.bazel", + "_groups/BUILD.bazel", + ] + env.expect.that_dict(actual).keys().contains_exactly(want_files) + + want_key = "_groups/BUILD.bazel" + + # Just check that it contains a private whl + env.expect.that_str(actual[want_key]).contains("//bar:_whl") + + want_key = "bar/BUILD.bazel" + + # Just check that it contains a private whl + env.expect.that_str(actual[want_key]).contains("name = \"_whl\"") + env.expect.that_str(actual[want_key]).contains("name = \"whl\"") + env.expect.that_str(actual[want_key]).contains("\"//_groups:group_whl\"") + +_tests.append(_test_aliases_with_groups) + def render_pkg_aliases_test_suite(name): """Create the test suite. diff --git a/tests/pip_install/group_library/generate_build_bazel_tests.bzl b/tests/pip_install/group_library/generate_build_bazel_tests.bzl index e7d6b44d3f..cf082c2990 100644 --- a/tests/pip_install/group_library/generate_build_bazel_tests.bzl +++ b/tests/pip_install/group_library/generate_build_bazel_tests.bzl @@ -21,7 +21,7 @@ _tests = [] def _test_simple(env): want = """\ -load("@rules_python//python:defs.bzl", "py_library", "py_binary") +load("@rules_python//python:defs.bzl", "py_library") ## Group vbap @@ -29,25 +29,72 @@ load("@rules_python//python:defs.bzl", "py_library", "py_binary") filegroup( name = "vbap_whl", srcs = [], - data = ["@pypi_oletools//:_whl", "@pypi_pcodedmp//:_whl"], - visibility = ["@pypi_oletools//:__pkg__", "@pypi_pcodedmp//:__pkg__"], + data = [ + "@pypi_oletools//:_whl", + "@pypi_pcodedmp//:_whl", + ], + visibility = [ + "@pypi_oletools//:__pkg__", + "@pypi_pcodedmp//:__pkg__", + ], ) py_library( name = "vbap_pkg", srcs = [], - deps = ["@pypi_oletools//:_pkg", "@pypi_pcodedmp//:_pkg"], - visibility = ["@pypi_oletools//:__pkg__", "@pypi_pcodedmp//:__pkg__"], + deps = [ + "@pypi_oletools//:_pkg", + "@pypi_pcodedmp//:_pkg", + ], + visibility = [ + "@pypi_oletools//:__pkg__", + "@pypi_pcodedmp//:__pkg__", + ], ) """ actual = generate_group_library_build_bazel( repo_prefix = "pypi_", - groups = {"vbap": ["oletools", "pcodedmp"]}, + groups = {"vbap": ["pcodedmp", "oletools"]}, ) env.expect.that_str(actual).equals(want) _tests.append(_test_simple) +def _test_in_hub(env): + want = """\ +load("@rules_python//python:defs.bzl", "py_library") + + +## Group vbap + +filegroup( + name = "vbap_whl", + srcs = [], + data = [ + "//oletools:_whl", + "//pcodedmp:_whl", + ], + visibility = ["//:__subpackages__"], +) + +py_library( + name = "vbap_pkg", + srcs = [], + deps = [ + "//oletools:_pkg", + "//pcodedmp:_pkg", + ], + visibility = ["//:__subpackages__"], +) +""" + actual = generate_group_library_build_bazel( + repo_prefix = "", + groups = {"vbap": ["pcodedmp", "oletools"]}, + ) + env.expect.that_str(actual).equals(want) + +_tests.append(_test_in_hub) + def generate_build_bazel_test_suite(name): """Create the test suite. diff --git a/tests/pip_install/whl_library/generate_build_bazel_tests.bzl b/tests/pip_install/whl_library/generate_build_bazel_tests.bzl index 11611b9a4a..66126cf6fb 100644 --- a/tests/pip_install/whl_library/generate_build_bazel_tests.bzl +++ b/tests/pip_install/whl_library/generate_build_bazel_tests.bzl @@ -71,7 +71,7 @@ py_library( ) """ actual = generate_whl_library_build_bazel( - repo_prefix = "pypi_", + dep_template = "@pypi_{name}//:{target}", whl_name = "foo.whl", dependencies = ["foo", "bar-baz"], dependencies_by_platform = {}, @@ -216,7 +216,7 @@ config_setting( ) """ actual = generate_whl_library_build_bazel( - repo_prefix = "pypi_", + dep_template = "@pypi_{name}//:{target}", whl_name = "foo.whl", dependencies = ["foo", "bar-baz"], dependencies_by_platform = { @@ -305,7 +305,7 @@ copy_file( # SOMETHING SPECIAL AT THE END """ actual = generate_whl_library_build_bazel( - repo_prefix = "pypi_", + dep_template = "@pypi_{name}//:{target}", whl_name = "foo.whl", dependencies = ["foo", "bar-baz"], dependencies_by_platform = {}, @@ -386,7 +386,7 @@ py_binary( ) """ actual = generate_whl_library_build_bazel( - repo_prefix = "pypi_", + dep_template = "@pypi_{name}//:{target}", whl_name = "foo.whl", dependencies = ["foo", "bar-baz"], dependencies_by_platform = {}, @@ -482,7 +482,7 @@ alias( ) """ actual = generate_whl_library_build_bazel( - repo_prefix = "pypi_", + dep_template = "@pypi_{name}//:{target}", whl_name = "foo.whl", dependencies = ["foo", "bar-baz", "qux"], dependencies_by_platform = { @@ -501,6 +501,98 @@ alias( _tests.append(_test_group_member) +def _test_group_member_deps_to_hub(env): + want = """\ +load("@rules_python//python:defs.bzl", "py_library", "py_binary") +load("@bazel_skylib//rules:copy_file.bzl", "copy_file") + +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "dist_info", + srcs = glob(["site-packages/*.dist-info/**"], allow_empty = True), +) + +filegroup( + name = "data", + srcs = glob(["data/**"], allow_empty = True), +) + +filegroup( + name = "whl", + srcs = ["foo.whl"], + data = ["@pypi//bar_baz:whl"] + select( + { + "@platforms//os:linux": ["@pypi//box:whl"], + ":is_linux_x86_64": [ + "@pypi//box:whl", + "@pypi//box_amd64:whl", + ], + "//conditions:default": [], + }, + ), + visibility = ["@pypi//:__subpackages__"], +) + +py_library( + name = "pkg", + srcs = glob( + ["site-packages/**/*.py"], + exclude=[], + # Empty sources are allowed to support wheels that don't have any + # pure-Python code, e.g. pymssql, which is written in Cython. + allow_empty = True, + ), + data = [] + glob( + ["site-packages/**/*"], + exclude=["**/* *", "**/*.py", "**/*.pyc", "**/*.pyc.*", "**/*.dist-info/RECORD"], + ), + # This makes this directory a top-level in the python import + # search path for anything that depends on this. + imports = ["site-packages"], + deps = ["@pypi//bar_baz:pkg"] + select( + { + "@platforms//os:linux": ["@pypi//box:pkg"], + ":is_linux_x86_64": [ + "@pypi//box:pkg", + "@pypi//box_amd64:pkg", + ], + "//conditions:default": [], + }, + ), + tags = [], + visibility = ["@pypi//:__subpackages__"], +) + +config_setting( + name = "is_linux_x86_64", + constraint_values = [ + "@platforms//cpu:x86_64", + "@platforms//os:linux", + ], + visibility = ["//visibility:private"], +) +""" + actual = generate_whl_library_build_bazel( + dep_template = "@pypi//{name}:{target}", + whl_name = "foo.whl", + dependencies = ["foo", "bar-baz", "qux"], + dependencies_by_platform = { + "linux_x86_64": ["box", "box-amd64"], + "windows_x86_64": ["fox"], + "@platforms//os:linux": ["box"], # buildifier: disable=unsorted-dict-items to check that we sort inside the test + }, + tags = [], + entry_points = {}, + data_exclude = [], + annotation = None, + group_name = "qux", + group_deps = ["foo", "fox", "qux"], + ) + env.expect.that_str(actual.replace("@@", "@")).equals(want) + +_tests.append(_test_group_member_deps_to_hub) + def generate_build_bazel_test_suite(name): """Create the test suite.