diff --git a/python/private/render_pkg_aliases.bzl b/python/private/render_pkg_aliases.bzl index e38f13321d..5851baf570 100644 --- a/python/private/render_pkg_aliases.bzl +++ b/python/private/render_pkg_aliases.bzl @@ -42,7 +42,8 @@ def _render_whl_library_alias( *, name, default_version, - aliases): + aliases, + **kwargs): """Render an alias for common targets.""" if len(aliases) == 1 and not aliases[0].version: alias = aliases[0] @@ -56,27 +57,36 @@ def _render_whl_library_alias( # whls that are based on a specific version of Python. selects = {} no_match_error = "_NO_MATCH_ERROR" - default = None for alias in sorted(aliases, key = lambda x: x.version): actual = "@{repo}//:{name}".format(repo = alias.repo, name = name) - selects[alias.config_setting] = actual + selects.setdefault(actual, []).append(alias.config_setting) if alias.version == default_version: - default = actual + selects[actual].append("//conditions:default") no_match_error = None - if default: - selects["//conditions:default"] = default - return render.alias( name = name, actual = render.select( - selects, + { + tuple(sorted( + conditions, + # Group `is_python` and other conditions for easier reading + # when looking at the generated files. + key = lambda condition: ("is_python" not in condition, condition), + )): target + for target, conditions in sorted(selects.items()) + }, no_match_error = no_match_error, + # This key_repr is used to render selects.with_or keys + key_repr = lambda x: repr(x[0]) if len(x) == 1 else render.tuple(x), + name = "selects.with_or", ), + **kwargs ) def _render_common_aliases(*, name, aliases, default_version = None): lines = [ + """load("@bazel_skylib//lib:selects.bzl", "selects")""", """package(default_visibility = ["//visibility:public"])""", ] diff --git a/python/private/text_util.bzl b/python/private/text_util.bzl index 78f62be1aa..dade9cba9b 100644 --- a/python/private/text_util.bzl +++ b/python/private/text_util.bzl @@ -35,18 +35,18 @@ def _render_alias(name, actual, *, visibility = None): ")", ]) -def _render_dict(d, *, value_repr = repr): +def _render_dict(d, *, key_repr = repr, value_repr = repr): return "\n".join([ "{", _indent("\n".join([ - "{}: {},".format(repr(k), value_repr(v)) + "{}: {},".format(key_repr(k), value_repr(v)) for k, v in d.items() ])), "}", ]) -def _render_select(selects, *, no_match_error = None, value_repr = repr): - dict_str = _render_dict(selects, value_repr = value_repr) + "," +def _render_select(selects, *, no_match_error = None, key_repr = repr, value_repr = repr, name = "select"): + dict_str = _render_dict(selects, key_repr = key_repr, value_repr = value_repr) + "," if no_match_error: args = "\n".join([ @@ -62,7 +62,7 @@ def _render_select(selects, *, no_match_error = None, value_repr = repr): "", ]) - return "select({})".format(args) + return "{}({})".format(name, args) def _render_list(items): if not items: @@ -80,10 +80,27 @@ def _render_list(items): "]", ]) +def _render_tuple(items, *, value_repr = repr): + if not items: + return "tuple()" + + if len(items) == 1: + return "({},)".format(value_repr(items[0])) + + return "\n".join([ + "(", + _indent("\n".join([ + "{},".format(value_repr(item)) + for item in items + ])), + ")", + ]) + render = struct( alias = _render_alias, dict = _render_dict, indent = _indent, list = _render_list, select = _render_select, + tuple = _render_tuple, ) 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 c61e5ef9b6..ddc9da7097 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 @@ -65,6 +65,8 @@ def _test_legacy_aliases(env): want_key = "foo/BUILD.bazel" want_content = """\ +load("@bazel_skylib//lib:selects.bzl", "selects") + package(default_visibility = ["//visibility:public"]) alias( @@ -108,6 +110,8 @@ def _test_bzlmod_aliases(env): want_key = "bar_baz/BUILD.bazel" want_content = """\ +load("@bazel_skylib//lib:selects.bzl", "selects") + package(default_visibility = ["//visibility:public"]) alias( @@ -117,40 +121,48 @@ alias( alias( name = "pkg", - actual = select( + actual = selects.with_or( { - "//:my_config_setting": "@pypi_32_bar_baz//:pkg", - "//conditions:default": "@pypi_32_bar_baz//:pkg", + ( + "//:my_config_setting", + "//conditions:default", + ): "@pypi_32_bar_baz//:pkg", }, ), ) alias( name = "whl", - actual = select( + actual = selects.with_or( { - "//:my_config_setting": "@pypi_32_bar_baz//:whl", - "//conditions:default": "@pypi_32_bar_baz//:whl", + ( + "//:my_config_setting", + "//conditions:default", + ): "@pypi_32_bar_baz//:whl", }, ), ) alias( name = "data", - actual = select( + actual = selects.with_or( { - "//:my_config_setting": "@pypi_32_bar_baz//:data", - "//conditions:default": "@pypi_32_bar_baz//:data", + ( + "//:my_config_setting", + "//conditions:default", + ): "@pypi_32_bar_baz//:data", }, ), ) alias( name = "dist_info", - actual = select( + actual = selects.with_or( { - "//:my_config_setting": "@pypi_32_bar_baz//:dist_info", - "//conditions:default": "@pypi_32_bar_baz//:dist_info", + ( + "//:my_config_setting", + "//conditions:default", + ): "@pypi_32_bar_baz//:dist_info", }, ), )""" @@ -178,6 +190,8 @@ def _test_bzlmod_aliases_with_no_default_version(env): want_key = "bar_baz/BUILD.bazel" want_content = """\ +load("@bazel_skylib//lib:selects.bzl", "selects") + package(default_visibility = ["//visibility:public"]) _NO_MATCH_ERROR = \"\"\"\\ @@ -206,7 +220,7 @@ alias( alias( name = "pkg", - actual = select( + actual = selects.with_or( { "@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:pkg", "@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:pkg", @@ -217,7 +231,7 @@ alias( alias( name = "whl", - actual = select( + actual = selects.with_or( { "@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:whl", "@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:whl", @@ -228,7 +242,7 @@ alias( alias( name = "data", - actual = select( + actual = selects.with_or( { "@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:data", "@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:data", @@ -239,7 +253,7 @@ alias( alias( name = "dist_info", - actual = select( + actual = selects.with_or( { "@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:dist_info", "@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:dist_info", @@ -273,6 +287,8 @@ def _test_bzlmod_aliases_for_non_root_modules(env): want_key = "bar_baz/BUILD.bazel" want_content = """\ +load("@bazel_skylib//lib:selects.bzl", "selects") + package(default_visibility = ["//visibility:public"]) _NO_MATCH_ERROR = \"\"\"\\ @@ -301,7 +317,7 @@ alias( alias( name = "pkg", - actual = select( + actual = selects.with_or( { "@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:pkg", "@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:pkg", @@ -312,7 +328,7 @@ alias( alias( name = "whl", - actual = select( + actual = selects.with_or( { "@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:whl", "@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:whl", @@ -323,7 +339,7 @@ alias( alias( name = "data", - actual = select( + actual = selects.with_or( { "@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:data", "@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:data", @@ -334,7 +350,7 @@ alias( alias( name = "dist_info", - actual = select( + actual = selects.with_or( { "@@//python/config_settings:is_python_3.1": "@pypi_31_bar_baz//:dist_info", "@@//python/config_settings:is_python_3.2": "@pypi_32_bar_baz//:dist_info", diff --git a/tests/private/text_util/render_tests.bzl b/tests/private/text_util/render_tests.bzl index 7c3dddfc7f..14967a9eab 100644 --- a/tests/private/text_util/render_tests.bzl +++ b/tests/private/text_util/render_tests.bzl @@ -54,6 +54,25 @@ def _test_render_alias(env): _tests.append(_test_render_alias) +def _test_render_tuple_dict(env): + got = render.dict( + { + ("foo", "bar"): "baz", + ("foo",): "bar", + }, + key_repr = render.tuple, + ) + env.expect.that_str(got).equals("""\ +{ + ( + "foo", + "bar", + ): "baz", + ("foo",): "bar", +}""") + +_tests.append(_test_render_tuple_dict) + def render_test_suite(name): """Create the test suite.