|
17 | 17 | load("@rules_python//python:repositories.bzl", "python_register_toolchains")
|
18 | 18 | load("@rules_python//python/extensions/private:interpreter_hub.bzl", "hub_repo")
|
19 | 19 |
|
| 20 | +def _python_register_toolchains(toolchain_attr, version_constraint): |
| 21 | + python_register_toolchains( |
| 22 | + name = toolchain_attr.name, |
| 23 | + python_version = toolchain_attr.python_version, |
| 24 | + register_coverage_tool = toolchain_attr.configure_coverage_tool, |
| 25 | + ignore_root_user_error = toolchain_attr.ignore_root_user_error, |
| 26 | + set_python_version_constraint = version_constraint, |
| 27 | + ) |
| 28 | + |
20 | 29 | def _python_impl(module_ctx):
|
21 |
| - toolchains = [] |
| 30 | + # We collect all of the toolchain names to create |
| 31 | + # the INTERPRETER_LABELS map. This is used |
| 32 | + # by interpreter_extensions.bzl via the hub_repo call below. |
| 33 | + toolchain_names = [] |
| 34 | + |
| 35 | + # Used to store the default toolchain so we can create it last. |
| 36 | + default_toolchain = None |
| 37 | + |
| 38 | + # Used to store toolchains that are in sub modules. |
| 39 | + sub_toolchains_map = {} |
| 40 | + |
22 | 41 | for mod in module_ctx.modules:
|
23 | 42 | for toolchain_attr in mod.tags.toolchain:
|
24 |
| - python_register_toolchains( |
25 |
| - name = toolchain_attr.name, |
26 |
| - python_version = toolchain_attr.python_version, |
27 |
| - bzlmod = True, |
28 |
| - # Toolchain registration in bzlmod is done in MODULE file |
29 |
| - register_toolchains = False, |
30 |
| - register_coverage_tool = toolchain_attr.configure_coverage_tool, |
31 |
| - ignore_root_user_error = toolchain_attr.ignore_root_user_error, |
32 |
| - ) |
33 |
| - |
34 |
| - # We collect all of the toolchain names to create |
35 |
| - # the INTERPRETER_LABELS map. This is used |
36 |
| - # by interpreter_extensions.bzl |
37 |
| - toolchains.append(toolchain_attr.name) |
| 43 | + # If we are in the root module we always register the toolchain. |
| 44 | + # We wait to register the default toolchain till the end. |
| 45 | + if mod.is_root: |
| 46 | + toolchain_names.append(toolchain_attr.name) |
| 47 | + |
| 48 | + # If we have the default version or we only have one toolchain |
| 49 | + # in the root module we set the toolchain as the default toolchain. |
| 50 | + if toolchain_attr.default_version or len(mod.tags.toolchain) == 1: |
| 51 | + # We have already found one default toolchain, and we can |
| 52 | + # only have one. |
| 53 | + if default_toolchain != None: |
| 54 | + fail("""We found more than one toolchain that is marked |
| 55 | +as the default version. Only set one toolchain with default_version set as |
| 56 | +True.""") |
| 57 | + default_toolchain = toolchain_attr |
| 58 | + continue |
| 59 | + |
| 60 | + # Always register toolchains that are in the root module. |
| 61 | + _python_register_toolchains(toolchain_attr, True) |
| 62 | + else: |
| 63 | + # We add the toolchain to a map, and we later create the |
| 64 | + # toolchain if the root module does not have a toolchain with |
| 65 | + # the same name. We have to loop through all of the modules to |
| 66 | + # ensure that we get a full list of the root toolchains. |
| 67 | + sub_toolchains_map[toolchain_attr.name] = toolchain_attr |
| 68 | + |
| 69 | + # We did not find a default toolchain so we fail. |
| 70 | + if default_toolchain == None: |
| 71 | + fail("""Unable to find a default toolchain in the root module. |
| 72 | +Please define a toolchain that has default_version set to True.""") |
| 73 | + |
| 74 | + # Create the toolchains in the submodule(s). |
| 75 | + for name, toolchain_attr in sub_toolchains_map: |
| 76 | + # A sub module cannot have a toolchain that is marked as the |
| 77 | + # default version. TODO: should we create the toolchain anyways, |
| 78 | + # but set the default version to False? |
| 79 | + if toolchain_attr.default_version: |
| 80 | + fail("""Not able to create toolchain named: {}. This toolchain exists |
| 81 | +in a sub module and defalult_version is set to True.""".format(name)) |
| 82 | + |
| 83 | + # We cannot have a toolchain in a sub module that has the same name of |
| 84 | + # a toolchain in the root module. This will cause name clashing. |
| 85 | + if name in toolchain_names: |
| 86 | + print("""Not creating the toolchain from sub module, with the name {}. The root |
| 87 | + modhas a toolchain of the same name.""".format(toolchain_attr.name)) |
| 88 | + continue |
| 89 | + toolchain_names.append(name) |
| 90 | + _python_register_toolchains(toolchain_attr, True) |
38 | 91 |
|
| 92 | + # We register the default toolchain last. |
| 93 | + _python_register_toolchains(default_toolchain, False) |
| 94 | + |
| 95 | + # Create the hub for the different interpreter versions. |
39 | 96 | hub_repo(
|
40 | 97 | name = "pythons_hub",
|
41 |
| - toolchains = toolchains, |
| 98 | + toolchains = toolchain_names, |
42 | 99 | )
|
43 | 100 |
|
44 | 101 | python = module_extension(
|
45 |
| - doc = "Bzlmod extension that is used to register a Python toolchain.", |
| 102 | + doc = """Bzlmod extension that is used to register Python toolchains. |
| 103 | +""", |
46 | 104 | implementation = _python_impl,
|
47 | 105 | tag_classes = {
|
48 | 106 | "toolchain": tag_class(
|
| 107 | + doc = """Tag class used to register Python toolchains. |
| 108 | +Use this tag class to register one of more Python toolchains. This class |
| 109 | +is also potentially called by sub modules. The following covers different |
| 110 | +business rules and use cases. |
| 111 | +
|
| 112 | +Toolchains in the Root Module |
| 113 | +
|
| 114 | +This class registers all toolchains in the root module. |
| 115 | +
|
| 116 | +Toolchains in Sub Modules |
| 117 | +
|
| 118 | +It will create a toolchain that is in a sub module, if the toolchain |
| 119 | +of the same name does not exist in the root module. The extension stops name |
| 120 | +clashing between toolchains in the root module and toolchains in sub modules. |
| 121 | +You cannot configure more than one toolchain as the default toolchain. |
| 122 | +
|
| 123 | +Toolchain set as the default versions |
| 124 | +
|
| 125 | +This extension will not create a toolchain that exists in a sub module, |
| 126 | +if the sub module toolchain is marked as the default version. If you have |
| 127 | +more than one toolchain in your root module, you need to set one of the |
| 128 | +toolchains as the default version. If there is only one toolchain it |
| 129 | +is set as the default toolchain. |
| 130 | +""", |
49 | 131 | attrs = {
|
50 | 132 | "configure_coverage_tool": attr.bool(
|
51 | 133 | mandatory = False,
|
52 | 134 | doc = "Whether or not to configure the default coverage tool for the toolchains.",
|
53 | 135 | ),
|
| 136 | + "default_version": attr.bool( |
| 137 | + mandatory = False, |
| 138 | + doc = "Whether the toolchain is the default version", |
| 139 | + ), |
54 | 140 | "ignore_root_user_error": attr.bool(
|
55 | 141 | default = False,
|
56 | 142 | doc = "Whether the check for root should be ignored or not. This causes cache misses with .pyc files.",
|
|
0 commit comments