xref: /aosp_15_r20/external/bazelbuild-rules_python/python/private/pythons_hub.bzl (revision 60517a1edbc8ecf509223e9af94a7adec7d736b8)
1*60517a1eSAndroid Build Coastguard Worker# Copyright 2023 The Bazel Authors. All rights reserved
2*60517a1eSAndroid Build Coastguard Worker#
3*60517a1eSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*60517a1eSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*60517a1eSAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*60517a1eSAndroid Build Coastguard Worker#
7*60517a1eSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
8*60517a1eSAndroid Build Coastguard Worker#
9*60517a1eSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*60517a1eSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*60517a1eSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*60517a1eSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*60517a1eSAndroid Build Coastguard Worker# limitations under the License.
14*60517a1eSAndroid Build Coastguard Worker
15*60517a1eSAndroid Build Coastguard Worker"Repo rule used by bzlmod extension to create a repo that has a map of Python interpreters and their labels"
16*60517a1eSAndroid Build Coastguard Worker
17*60517a1eSAndroid Build Coastguard Workerload(
18*60517a1eSAndroid Build Coastguard Worker    "//python/private:toolchains_repo.bzl",
19*60517a1eSAndroid Build Coastguard Worker    "python_toolchain_build_file_content",
20*60517a1eSAndroid Build Coastguard Worker)
21*60517a1eSAndroid Build Coastguard Worker
22*60517a1eSAndroid Build Coastguard Workerdef _have_same_length(*lists):
23*60517a1eSAndroid Build Coastguard Worker    if not lists:
24*60517a1eSAndroid Build Coastguard Worker        fail("expected at least one list")
25*60517a1eSAndroid Build Coastguard Worker    return len({len(length): None for length in lists}) == 1
26*60517a1eSAndroid Build Coastguard Worker
27*60517a1eSAndroid Build Coastguard Worker_HUB_BUILD_FILE_TEMPLATE = """\
28*60517a1eSAndroid Build Coastguard Workerload("@bazel_skylib//:bzl_library.bzl", "bzl_library")
29*60517a1eSAndroid Build Coastguard Workerload("@@{rules_python}//python/private:py_toolchain_suite.bzl", "py_toolchain_suite")
30*60517a1eSAndroid Build Coastguard Worker
31*60517a1eSAndroid Build Coastguard Workerbzl_library(
32*60517a1eSAndroid Build Coastguard Worker    name = "interpreters_bzl",
33*60517a1eSAndroid Build Coastguard Worker    srcs = ["interpreters.bzl"],
34*60517a1eSAndroid Build Coastguard Worker    visibility = ["@rules_python//:__subpackages__"],
35*60517a1eSAndroid Build Coastguard Worker)
36*60517a1eSAndroid Build Coastguard Worker
37*60517a1eSAndroid Build Coastguard Worker{toolchains}
38*60517a1eSAndroid Build Coastguard Worker"""
39*60517a1eSAndroid Build Coastguard Worker
40*60517a1eSAndroid Build Coastguard Workerdef _hub_build_file_content(
41*60517a1eSAndroid Build Coastguard Worker        prefixes,
42*60517a1eSAndroid Build Coastguard Worker        python_versions,
43*60517a1eSAndroid Build Coastguard Worker        set_python_version_constraints,
44*60517a1eSAndroid Build Coastguard Worker        user_repository_names,
45*60517a1eSAndroid Build Coastguard Worker        workspace_location):
46*60517a1eSAndroid Build Coastguard Worker    """This macro iterates over each of the lists and returns the toolchain content.
47*60517a1eSAndroid Build Coastguard Worker
48*60517a1eSAndroid Build Coastguard Worker    python_toolchain_build_file_content is called to generate each of the toolchain
49*60517a1eSAndroid Build Coastguard Worker    definitions.
50*60517a1eSAndroid Build Coastguard Worker    """
51*60517a1eSAndroid Build Coastguard Worker
52*60517a1eSAndroid Build Coastguard Worker    if not _have_same_length(python_versions, set_python_version_constraints, user_repository_names):
53*60517a1eSAndroid Build Coastguard Worker        fail("all lists must have the same length")
54*60517a1eSAndroid Build Coastguard Worker
55*60517a1eSAndroid Build Coastguard Worker    # Iterate over the length of python_versions and call
56*60517a1eSAndroid Build Coastguard Worker    # build the toolchain content by calling python_toolchain_build_file_content
57*60517a1eSAndroid Build Coastguard Worker    toolchains = "\n".join(
58*60517a1eSAndroid Build Coastguard Worker        [
59*60517a1eSAndroid Build Coastguard Worker            python_toolchain_build_file_content(
60*60517a1eSAndroid Build Coastguard Worker                prefix = prefixes[i],
61*60517a1eSAndroid Build Coastguard Worker                python_version = python_versions[i],
62*60517a1eSAndroid Build Coastguard Worker                set_python_version_constraint = set_python_version_constraints[i],
63*60517a1eSAndroid Build Coastguard Worker                user_repository_name = user_repository_names[i],
64*60517a1eSAndroid Build Coastguard Worker            )
65*60517a1eSAndroid Build Coastguard Worker            for i in range(len(python_versions))
66*60517a1eSAndroid Build Coastguard Worker        ],
67*60517a1eSAndroid Build Coastguard Worker    )
68*60517a1eSAndroid Build Coastguard Worker
69*60517a1eSAndroid Build Coastguard Worker    return _HUB_BUILD_FILE_TEMPLATE.format(
70*60517a1eSAndroid Build Coastguard Worker        toolchains = toolchains,
71*60517a1eSAndroid Build Coastguard Worker        rules_python = workspace_location.workspace_name,
72*60517a1eSAndroid Build Coastguard Worker    )
73*60517a1eSAndroid Build Coastguard Worker
74*60517a1eSAndroid Build Coastguard Worker_interpreters_bzl_template = """
75*60517a1eSAndroid Build Coastguard WorkerINTERPRETER_LABELS = {{
76*60517a1eSAndroid Build Coastguard Worker{interpreter_labels}
77*60517a1eSAndroid Build Coastguard Worker}}
78*60517a1eSAndroid Build Coastguard WorkerDEFAULT_PYTHON_VERSION = "{default_python_version}"
79*60517a1eSAndroid Build Coastguard Worker"""
80*60517a1eSAndroid Build Coastguard Worker
81*60517a1eSAndroid Build Coastguard Worker_line_for_hub_template = """\
82*60517a1eSAndroid Build Coastguard Worker    "{name}_host": Label("@{name}_host//:python"),
83*60517a1eSAndroid Build Coastguard Worker"""
84*60517a1eSAndroid Build Coastguard Worker
85*60517a1eSAndroid Build Coastguard Workerdef _hub_repo_impl(rctx):
86*60517a1eSAndroid Build Coastguard Worker    # Create the various toolchain definitions and
87*60517a1eSAndroid Build Coastguard Worker    # write them to the BUILD file.
88*60517a1eSAndroid Build Coastguard Worker    rctx.file(
89*60517a1eSAndroid Build Coastguard Worker        "BUILD.bazel",
90*60517a1eSAndroid Build Coastguard Worker        _hub_build_file_content(
91*60517a1eSAndroid Build Coastguard Worker            rctx.attr.toolchain_prefixes,
92*60517a1eSAndroid Build Coastguard Worker            rctx.attr.toolchain_python_versions,
93*60517a1eSAndroid Build Coastguard Worker            rctx.attr.toolchain_set_python_version_constraints,
94*60517a1eSAndroid Build Coastguard Worker            rctx.attr.toolchain_user_repository_names,
95*60517a1eSAndroid Build Coastguard Worker            rctx.attr._rules_python_workspace,
96*60517a1eSAndroid Build Coastguard Worker        ),
97*60517a1eSAndroid Build Coastguard Worker        executable = False,
98*60517a1eSAndroid Build Coastguard Worker    )
99*60517a1eSAndroid Build Coastguard Worker
100*60517a1eSAndroid Build Coastguard Worker    # Create a dict that is later used to create
101*60517a1eSAndroid Build Coastguard Worker    # a symlink to a interpreter.
102*60517a1eSAndroid Build Coastguard Worker    interpreter_labels = "".join([
103*60517a1eSAndroid Build Coastguard Worker        _line_for_hub_template.format(name = name)
104*60517a1eSAndroid Build Coastguard Worker        for name in rctx.attr.toolchain_user_repository_names
105*60517a1eSAndroid Build Coastguard Worker    ])
106*60517a1eSAndroid Build Coastguard Worker
107*60517a1eSAndroid Build Coastguard Worker    rctx.file(
108*60517a1eSAndroid Build Coastguard Worker        "interpreters.bzl",
109*60517a1eSAndroid Build Coastguard Worker        _interpreters_bzl_template.format(
110*60517a1eSAndroid Build Coastguard Worker            interpreter_labels = interpreter_labels,
111*60517a1eSAndroid Build Coastguard Worker            default_python_version = rctx.attr.default_python_version,
112*60517a1eSAndroid Build Coastguard Worker        ),
113*60517a1eSAndroid Build Coastguard Worker        executable = False,
114*60517a1eSAndroid Build Coastguard Worker    )
115*60517a1eSAndroid Build Coastguard Worker
116*60517a1eSAndroid Build Coastguard Workerhub_repo = repository_rule(
117*60517a1eSAndroid Build Coastguard Worker    doc = """\
118*60517a1eSAndroid Build Coastguard WorkerThis private rule create a repo with a BUILD file that contains a map of interpreter names
119*60517a1eSAndroid Build Coastguard Workerand the labels to said interpreters. This map is used to by the interpreter hub extension.
120*60517a1eSAndroid Build Coastguard WorkerThis rule also writes out the various toolchains for the different Python versions.
121*60517a1eSAndroid Build Coastguard Worker""",
122*60517a1eSAndroid Build Coastguard Worker    implementation = _hub_repo_impl,
123*60517a1eSAndroid Build Coastguard Worker    attrs = {
124*60517a1eSAndroid Build Coastguard Worker        "default_python_version": attr.string(
125*60517a1eSAndroid Build Coastguard Worker            doc = "Default Python version for the build in `X.Y` or `X.Y.Z` format.",
126*60517a1eSAndroid Build Coastguard Worker            mandatory = True,
127*60517a1eSAndroid Build Coastguard Worker        ),
128*60517a1eSAndroid Build Coastguard Worker        "toolchain_prefixes": attr.string_list(
129*60517a1eSAndroid Build Coastguard Worker            doc = "List prefixed for the toolchains",
130*60517a1eSAndroid Build Coastguard Worker            mandatory = True,
131*60517a1eSAndroid Build Coastguard Worker        ),
132*60517a1eSAndroid Build Coastguard Worker        "toolchain_python_versions": attr.string_list(
133*60517a1eSAndroid Build Coastguard Worker            doc = "List of Python versions for the toolchains. In `X.Y.Z` format.",
134*60517a1eSAndroid Build Coastguard Worker            mandatory = True,
135*60517a1eSAndroid Build Coastguard Worker        ),
136*60517a1eSAndroid Build Coastguard Worker        "toolchain_set_python_version_constraints": attr.string_list(
137*60517a1eSAndroid Build Coastguard Worker            doc = "List of version contraints for the toolchains",
138*60517a1eSAndroid Build Coastguard Worker            mandatory = True,
139*60517a1eSAndroid Build Coastguard Worker        ),
140*60517a1eSAndroid Build Coastguard Worker        "toolchain_user_repository_names": attr.string_list(
141*60517a1eSAndroid Build Coastguard Worker            doc = "List of the user repo names for the toolchains",
142*60517a1eSAndroid Build Coastguard Worker            mandatory = True,
143*60517a1eSAndroid Build Coastguard Worker        ),
144*60517a1eSAndroid Build Coastguard Worker        "_rules_python_workspace": attr.label(default = Label("//:does_not_matter_what_this_name_is")),
145*60517a1eSAndroid Build Coastguard Worker    },
146*60517a1eSAndroid Build Coastguard Worker)
147