xref: /aosp_15_r20/external/bazel-skylib/lib/modules.bzl (revision bcb5dc7965af6ee42bf2f21341a2ec00233a8c8a)
1*bcb5dc79SHONG Yifan# Copyright 2023 The Bazel Authors. All rights reserved.
2*bcb5dc79SHONG Yifan#
3*bcb5dc79SHONG Yifan# Licensed under the Apache License, Version 2.0 (the "License");
4*bcb5dc79SHONG Yifan# you may not use this file except in compliance with the License.
5*bcb5dc79SHONG Yifan# You may obtain a copy of the License at
6*bcb5dc79SHONG Yifan#
7*bcb5dc79SHONG Yifan#    http://www.apache.org/licenses/LICENSE-2.0
8*bcb5dc79SHONG Yifan#
9*bcb5dc79SHONG Yifan# Unless required by applicable law or agreed to in writing, software
10*bcb5dc79SHONG Yifan# distributed under the License is distributed on an "AS IS" BASIS,
11*bcb5dc79SHONG Yifan# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*bcb5dc79SHONG Yifan# See the License for the specific language governing permissions and
13*bcb5dc79SHONG Yifan# limitations under the License.
14*bcb5dc79SHONG Yifan
15*bcb5dc79SHONG Yifan"""Skylib module containing utilities for Bazel modules and module extensions."""
16*bcb5dc79SHONG Yifan
17*bcb5dc79SHONG Yifandef _as_extension(macro, doc = None):
18*bcb5dc79SHONG Yifan    """Wraps a WORKSPACE dependency macro into a module extension.
19*bcb5dc79SHONG Yifan
20*bcb5dc79SHONG Yifan    Example:
21*bcb5dc79SHONG Yifan    ```starlark
22*bcb5dc79SHONG Yifan    def rules_foo_deps(optional_arg = True):
23*bcb5dc79SHONG Yifan        some_repo_rule(name = "foobar")
24*bcb5dc79SHONG Yifan        http_archive(name = "bazqux")
25*bcb5dc79SHONG Yifan
26*bcb5dc79SHONG Yifan    rules_foo_deps_ext = modules.as_extension(rules_foo_deps)
27*bcb5dc79SHONG Yifan    ```
28*bcb5dc79SHONG Yifan
29*bcb5dc79SHONG Yifan    Args:
30*bcb5dc79SHONG Yifan      macro: A [WORKSPACE dependency macro](https://bazel.build/rules/deploying#dependencies), i.e.,
31*bcb5dc79SHONG Yifan          a function with no required parameters that instantiates one or more repository rules.
32*bcb5dc79SHONG Yifan      doc: A description of the module extension that can be extracted by documentation generating
33*bcb5dc79SHONG Yifan          tools.
34*bcb5dc79SHONG Yifan
35*bcb5dc79SHONG Yifan    Returns:
36*bcb5dc79SHONG Yifan      A module extension that generates the repositories instantiated by the given macro and also
37*bcb5dc79SHONG Yifan      uses [`use_all_repos`](#use_all_repos) to indicate that all of those repositories should be
38*bcb5dc79SHONG Yifan      imported via `use_repo`. The extension is marked as reproducible if supported by the current
39*bcb5dc79SHONG Yifan      version of Bazel and thus doesn't result in a lockfile entry.
40*bcb5dc79SHONG Yifan    """
41*bcb5dc79SHONG Yifan
42*bcb5dc79SHONG Yifan    def _ext_impl(module_ctx):
43*bcb5dc79SHONG Yifan        macro()
44*bcb5dc79SHONG Yifan
45*bcb5dc79SHONG Yifan        # Setting `reproducible` is safe since `macro`, as a function without parameters, must be
46*bcb5dc79SHONG Yifan        # deterministic.
47*bcb5dc79SHONG Yifan        return _use_all_repos(module_ctx, reproducible = True)
48*bcb5dc79SHONG Yifan
49*bcb5dc79SHONG Yifan    kwargs = {}
50*bcb5dc79SHONG Yifan    if doc != None:
51*bcb5dc79SHONG Yifan        kwargs["doc"] = doc
52*bcb5dc79SHONG Yifan
53*bcb5dc79SHONG Yifan    return module_extension(
54*bcb5dc79SHONG Yifan        implementation = _ext_impl,
55*bcb5dc79SHONG Yifan        **kwargs
56*bcb5dc79SHONG Yifan    )
57*bcb5dc79SHONG Yifan
58*bcb5dc79SHONG Yifandef _use_all_repos(module_ctx, reproducible = False):
59*bcb5dc79SHONG Yifan    """Return from a module extension that should have all its repositories imported via `use_repo`.
60*bcb5dc79SHONG Yifan
61*bcb5dc79SHONG Yifan    Example:
62*bcb5dc79SHONG Yifan    ```starlark
63*bcb5dc79SHONG Yifan    def _ext_impl(module_ctx):
64*bcb5dc79SHONG Yifan        some_repo_rule(name = "foobar")
65*bcb5dc79SHONG Yifan        http_archive(name = "bazqux")
66*bcb5dc79SHONG Yifan        return modules.use_all_repos(module_ctx)
67*bcb5dc79SHONG Yifan
68*bcb5dc79SHONG Yifan    ext = module_extension(_ext_impl)
69*bcb5dc79SHONG Yifan    ```
70*bcb5dc79SHONG Yifan
71*bcb5dc79SHONG Yifan    Args:
72*bcb5dc79SHONG Yifan      module_ctx: The [`module_ctx`](https://bazel.build/rules/lib/builtins/module_ctx) object
73*bcb5dc79SHONG Yifan          passed to the module extension's implementation function.
74*bcb5dc79SHONG Yifan      reproducible: The value of the `reproducible` parameter to pass to the
75*bcb5dc79SHONG Yifan          [`extension_metadata`](https://bazel.build/rules/lib/builtins/extension_metadata.html)
76*bcb5dc79SHONG Yifan          object returned by this function. This is safe to set with Bazel versions that don't
77*bcb5dc79SHONG Yifan          support this parameter and will be ignored in that case.
78*bcb5dc79SHONG Yifan
79*bcb5dc79SHONG Yifan    Returns:
80*bcb5dc79SHONG Yifan      An [`extension_metadata`](https://bazel.build/rules/lib/builtins/extension_metadata.html)
81*bcb5dc79SHONG Yifan      object that, when returned from a module extension implementation function, specifies that all
82*bcb5dc79SHONG Yifan      repositories generated by this extension should be imported via `use_repo`. If the current
83*bcb5dc79SHONG Yifan      version of Bazel doesn't support `extension_metadata`, returns `None` instead, which can
84*bcb5dc79SHONG Yifan      safely be returned from a module extension implementation function in all versions of Bazel.
85*bcb5dc79SHONG Yifan    """
86*bcb5dc79SHONG Yifan
87*bcb5dc79SHONG Yifan    # module_ctx.extension_metadata is available in Bazel 6.2.0 and later.
88*bcb5dc79SHONG Yifan    # If not available, returning None from a module extension is equivalent to not returning
89*bcb5dc79SHONG Yifan    # anything.
90*bcb5dc79SHONG Yifan    extension_metadata = getattr(module_ctx, "extension_metadata", None)
91*bcb5dc79SHONG Yifan    if not extension_metadata:
92*bcb5dc79SHONG Yifan        return None
93*bcb5dc79SHONG Yifan
94*bcb5dc79SHONG Yifan    # module_ctx.root_module_has_non_dev_dependency is available in Bazel 6.3.0 and later.
95*bcb5dc79SHONG Yifan    root_module_has_non_dev_dependency = getattr(
96*bcb5dc79SHONG Yifan        module_ctx,
97*bcb5dc79SHONG Yifan        "root_module_has_non_dev_dependency",
98*bcb5dc79SHONG Yifan        None,
99*bcb5dc79SHONG Yifan    )
100*bcb5dc79SHONG Yifan    if root_module_has_non_dev_dependency == None:
101*bcb5dc79SHONG Yifan        return None
102*bcb5dc79SHONG Yifan
103*bcb5dc79SHONG Yifan    # module_ctx.extension_metadata has the paramater `reproducible` as of Bazel 7.1.0. We can't
104*bcb5dc79SHONG Yifan    # test for it directly and would ideally use bazel_features to check for it, but adding a
105*bcb5dc79SHONG Yifan    # dependency on it would require complicating the WORKSPACE setup for skylib. Thus, test for
106*bcb5dc79SHONG Yifan    # it by checking the availability of another feature introduced in 7.1.0.
107*bcb5dc79SHONG Yifan    extension_metadata_kwargs = {}
108*bcb5dc79SHONG Yifan    if hasattr(module_ctx, "watch"):
109*bcb5dc79SHONG Yifan        extension_metadata_kwargs["reproducible"] = reproducible
110*bcb5dc79SHONG Yifan
111*bcb5dc79SHONG Yifan    return extension_metadata(
112*bcb5dc79SHONG Yifan        root_module_direct_deps = "all" if root_module_has_non_dev_dependency else [],
113*bcb5dc79SHONG Yifan        root_module_direct_dev_deps = [] if root_module_has_non_dev_dependency else "all",
114*bcb5dc79SHONG Yifan        **extension_metadata_kwargs
115*bcb5dc79SHONG Yifan    )
116*bcb5dc79SHONG Yifan
117*bcb5dc79SHONG Yifanmodules = struct(
118*bcb5dc79SHONG Yifan    as_extension = _as_extension,
119*bcb5dc79SHONG Yifan    use_all_repos = _use_all_repos,
120*bcb5dc79SHONG Yifan)
121