xref: /aosp_15_r20/external/bazelbuild-rules_python/gazelle/manifest/defs.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"""This module provides the gazelle_python_manifest macro that contains targets
16*60517a1eSAndroid Build Coastguard Workerfor updating and testing the Gazelle manifest file.
17*60517a1eSAndroid Build Coastguard Worker"""
18*60517a1eSAndroid Build Coastguard Worker
19*60517a1eSAndroid Build Coastguard Workerload("@bazel_skylib//rules:diff_test.bzl", "diff_test")
20*60517a1eSAndroid Build Coastguard Workerload("@io_bazel_rules_go//go:def.bzl", "GoSource", "go_test")
21*60517a1eSAndroid Build Coastguard Workerload("@rules_python//python:defs.bzl", "py_binary")
22*60517a1eSAndroid Build Coastguard Worker
23*60517a1eSAndroid Build Coastguard Workerdef gazelle_python_manifest(
24*60517a1eSAndroid Build Coastguard Worker        name,
25*60517a1eSAndroid Build Coastguard Worker        modules_mapping,
26*60517a1eSAndroid Build Coastguard Worker        requirements = [],
27*60517a1eSAndroid Build Coastguard Worker        pip_repository_name = "",
28*60517a1eSAndroid Build Coastguard Worker        pip_deps_repository_name = "",
29*60517a1eSAndroid Build Coastguard Worker        manifest = ":gazelle_python.yaml",
30*60517a1eSAndroid Build Coastguard Worker        **kwargs):
31*60517a1eSAndroid Build Coastguard Worker    """A macro for defining the updating and testing targets for the Gazelle manifest file.
32*60517a1eSAndroid Build Coastguard Worker
33*60517a1eSAndroid Build Coastguard Worker    Args:
34*60517a1eSAndroid Build Coastguard Worker        name: the name used as a base for the targets.
35*60517a1eSAndroid Build Coastguard Worker        modules_mapping: the target for the generated modules_mapping.json file.
36*60517a1eSAndroid Build Coastguard Worker        requirements: the target for the requirements.txt file or a list of
37*60517a1eSAndroid Build Coastguard Worker            requirements files that will be concatenated before passing on to
38*60517a1eSAndroid Build Coastguard Worker            the manifest generator. If unset, no integrity field is added to the
39*60517a1eSAndroid Build Coastguard Worker            manifest, meaning testing it is just as expensive as generating it,
40*60517a1eSAndroid Build Coastguard Worker            but modifying it is much less likely to result in a merge conflict.
41*60517a1eSAndroid Build Coastguard Worker        pip_repository_name: the name of the pip_install or pip_repository target.
42*60517a1eSAndroid Build Coastguard Worker        pip_deps_repository_name: deprecated - the old pip_install target name.
43*60517a1eSAndroid Build Coastguard Worker        manifest: the Gazelle manifest file.
44*60517a1eSAndroid Build Coastguard Worker            defaults to the same value as manifest.
45*60517a1eSAndroid Build Coastguard Worker        **kwargs: other bazel attributes passed to the generate and test targets
46*60517a1eSAndroid Build Coastguard Worker            generated by this macro.
47*60517a1eSAndroid Build Coastguard Worker    """
48*60517a1eSAndroid Build Coastguard Worker    if pip_deps_repository_name != "":
49*60517a1eSAndroid Build Coastguard Worker        # buildifier: disable=print
50*60517a1eSAndroid Build Coastguard Worker        print("DEPRECATED pip_deps_repository_name in //{}:{}. Please use pip_repository_name instead.".format(
51*60517a1eSAndroid Build Coastguard Worker            native.package_name(),
52*60517a1eSAndroid Build Coastguard Worker            name,
53*60517a1eSAndroid Build Coastguard Worker        ))
54*60517a1eSAndroid Build Coastguard Worker        pip_repository_name = pip_deps_repository_name
55*60517a1eSAndroid Build Coastguard Worker
56*60517a1eSAndroid Build Coastguard Worker    if pip_repository_name == "":
57*60517a1eSAndroid Build Coastguard Worker        # This is a temporary check while pip_deps_repository_name exists as deprecated.
58*60517a1eSAndroid Build Coastguard Worker        fail("pip_repository_name must be set in //{}:{}".format(native.package_name(), name))
59*60517a1eSAndroid Build Coastguard Worker
60*60517a1eSAndroid Build Coastguard Worker    test_target = "{}.test".format(name)
61*60517a1eSAndroid Build Coastguard Worker    update_target = "{}.update".format(name)
62*60517a1eSAndroid Build Coastguard Worker    update_target_label = "//{}:{}".format(native.package_name(), update_target)
63*60517a1eSAndroid Build Coastguard Worker
64*60517a1eSAndroid Build Coastguard Worker    manifest_genrule = name + ".genrule"
65*60517a1eSAndroid Build Coastguard Worker    generated_manifest = name + ".generated_manifest"
66*60517a1eSAndroid Build Coastguard Worker    manifest_generator = Label("//manifest/generate:generate")
67*60517a1eSAndroid Build Coastguard Worker    manifest_generator_hash = Label("//manifest/generate:generate_lib_sources_hash")
68*60517a1eSAndroid Build Coastguard Worker
69*60517a1eSAndroid Build Coastguard Worker    if requirements and type(requirements) == "list":
70*60517a1eSAndroid Build Coastguard Worker        # This runs if requirements is a list or is unset (default value is empty list)
71*60517a1eSAndroid Build Coastguard Worker        native.genrule(
72*60517a1eSAndroid Build Coastguard Worker            name = name + "_requirements_gen",
73*60517a1eSAndroid Build Coastguard Worker            srcs = sorted(requirements),
74*60517a1eSAndroid Build Coastguard Worker            outs = [name + "_requirements.txt"],
75*60517a1eSAndroid Build Coastguard Worker            cmd_bash = "cat $(SRCS) > $@",
76*60517a1eSAndroid Build Coastguard Worker            cmd_bat = "type $(SRCS) > $@",
77*60517a1eSAndroid Build Coastguard Worker        )
78*60517a1eSAndroid Build Coastguard Worker        requirements = name + "_requirements_gen"
79*60517a1eSAndroid Build Coastguard Worker
80*60517a1eSAndroid Build Coastguard Worker    update_args = [
81*60517a1eSAndroid Build Coastguard Worker        "--manifest-generator-hash=$(execpath {})".format(manifest_generator_hash),
82*60517a1eSAndroid Build Coastguard Worker        "--requirements=$(rootpath {})".format(requirements) if requirements else "--requirements=",
83*60517a1eSAndroid Build Coastguard Worker        "--pip-repository-name={}".format(pip_repository_name),
84*60517a1eSAndroid Build Coastguard Worker        "--modules-mapping=$(execpath {})".format(modules_mapping),
85*60517a1eSAndroid Build Coastguard Worker        "--output=$(execpath {})".format(generated_manifest),
86*60517a1eSAndroid Build Coastguard Worker        "--update-target={}".format(update_target_label),
87*60517a1eSAndroid Build Coastguard Worker    ]
88*60517a1eSAndroid Build Coastguard Worker
89*60517a1eSAndroid Build Coastguard Worker    native.genrule(
90*60517a1eSAndroid Build Coastguard Worker        name = manifest_genrule,
91*60517a1eSAndroid Build Coastguard Worker        outs = [generated_manifest],
92*60517a1eSAndroid Build Coastguard Worker        cmd = "$(execpath {}) {}".format(manifest_generator, " ".join(update_args)),
93*60517a1eSAndroid Build Coastguard Worker        tools = [manifest_generator],
94*60517a1eSAndroid Build Coastguard Worker        srcs = [
95*60517a1eSAndroid Build Coastguard Worker            modules_mapping,
96*60517a1eSAndroid Build Coastguard Worker            manifest_generator_hash,
97*60517a1eSAndroid Build Coastguard Worker        ] + ([requirements] if requirements else []),
98*60517a1eSAndroid Build Coastguard Worker        tags = ["manual"],
99*60517a1eSAndroid Build Coastguard Worker    )
100*60517a1eSAndroid Build Coastguard Worker
101*60517a1eSAndroid Build Coastguard Worker    py_binary(
102*60517a1eSAndroid Build Coastguard Worker        name = update_target,
103*60517a1eSAndroid Build Coastguard Worker        srcs = [Label("//manifest:copy_to_source.py")],
104*60517a1eSAndroid Build Coastguard Worker        main = Label("//manifest:copy_to_source.py"),
105*60517a1eSAndroid Build Coastguard Worker        args = [
106*60517a1eSAndroid Build Coastguard Worker            "$(rootpath {})".format(generated_manifest),
107*60517a1eSAndroid Build Coastguard Worker            "$(rootpath {})".format(manifest),
108*60517a1eSAndroid Build Coastguard Worker        ],
109*60517a1eSAndroid Build Coastguard Worker        data = [
110*60517a1eSAndroid Build Coastguard Worker            generated_manifest,
111*60517a1eSAndroid Build Coastguard Worker            manifest,
112*60517a1eSAndroid Build Coastguard Worker        ],
113*60517a1eSAndroid Build Coastguard Worker        tags = kwargs.get("tags", []) + ["manual"],
114*60517a1eSAndroid Build Coastguard Worker        **{k: v for k, v in kwargs.items() if k != "tags"}
115*60517a1eSAndroid Build Coastguard Worker    )
116*60517a1eSAndroid Build Coastguard Worker
117*60517a1eSAndroid Build Coastguard Worker    if requirements:
118*60517a1eSAndroid Build Coastguard Worker        attrs = {
119*60517a1eSAndroid Build Coastguard Worker            "env": {
120*60517a1eSAndroid Build Coastguard Worker                "_TEST_MANIFEST": "$(rootpath {})".format(manifest),
121*60517a1eSAndroid Build Coastguard Worker                "_TEST_MANIFEST_GENERATOR_HASH": "$(rlocationpath {})".format(manifest_generator_hash),
122*60517a1eSAndroid Build Coastguard Worker                "_TEST_REQUIREMENTS": "$(rootpath {})".format(requirements),
123*60517a1eSAndroid Build Coastguard Worker            },
124*60517a1eSAndroid Build Coastguard Worker            "size": "small",
125*60517a1eSAndroid Build Coastguard Worker        }
126*60517a1eSAndroid Build Coastguard Worker        go_test(
127*60517a1eSAndroid Build Coastguard Worker            name = test_target,
128*60517a1eSAndroid Build Coastguard Worker            srcs = [Label("//manifest/test:test.go")],
129*60517a1eSAndroid Build Coastguard Worker            data = [
130*60517a1eSAndroid Build Coastguard Worker                manifest,
131*60517a1eSAndroid Build Coastguard Worker                requirements,
132*60517a1eSAndroid Build Coastguard Worker                manifest_generator_hash,
133*60517a1eSAndroid Build Coastguard Worker            ],
134*60517a1eSAndroid Build Coastguard Worker            rundir = ".",
135*60517a1eSAndroid Build Coastguard Worker            deps = [
136*60517a1eSAndroid Build Coastguard Worker                Label("//manifest"),
137*60517a1eSAndroid Build Coastguard Worker                Label("@io_bazel_rules_go//go/runfiles"),
138*60517a1eSAndroid Build Coastguard Worker            ],
139*60517a1eSAndroid Build Coastguard Worker            # kwargs could contain test-specific attributes like size or timeout
140*60517a1eSAndroid Build Coastguard Worker            **dict(attrs, **kwargs)
141*60517a1eSAndroid Build Coastguard Worker        )
142*60517a1eSAndroid Build Coastguard Worker    else:
143*60517a1eSAndroid Build Coastguard Worker        diff_test(
144*60517a1eSAndroid Build Coastguard Worker            name = test_target,
145*60517a1eSAndroid Build Coastguard Worker            file1 = generated_manifest,
146*60517a1eSAndroid Build Coastguard Worker            file2 = manifest,
147*60517a1eSAndroid Build Coastguard Worker            failure_message = "Gazelle manifest is out of date. Run 'bazel run {}' to update it.".format(native.package_relative_label(update_target)),
148*60517a1eSAndroid Build Coastguard Worker            **kwargs
149*60517a1eSAndroid Build Coastguard Worker        )
150*60517a1eSAndroid Build Coastguard Worker
151*60517a1eSAndroid Build Coastguard Worker    native.filegroup(
152*60517a1eSAndroid Build Coastguard Worker        name = name,
153*60517a1eSAndroid Build Coastguard Worker        srcs = [manifest],
154*60517a1eSAndroid Build Coastguard Worker        tags = ["manual"],
155*60517a1eSAndroid Build Coastguard Worker        visibility = ["//visibility:public"],
156*60517a1eSAndroid Build Coastguard Worker    )
157*60517a1eSAndroid Build Coastguard Worker
158*60517a1eSAndroid Build Coastguard Worker# buildifier: disable=provider-params
159*60517a1eSAndroid Build Coastguard WorkerAllSourcesInfo = provider(fields = {"all_srcs": "All sources collected from the target and dependencies."})
160*60517a1eSAndroid Build Coastguard Worker
161*60517a1eSAndroid Build Coastguard Worker_rules_python_workspace = Label("@rules_python//:WORKSPACE")
162*60517a1eSAndroid Build Coastguard Worker
163*60517a1eSAndroid Build Coastguard Workerdef _get_all_sources_impl(target, ctx):
164*60517a1eSAndroid Build Coastguard Worker    is_rules_python = target.label.workspace_name == _rules_python_workspace.workspace_name
165*60517a1eSAndroid Build Coastguard Worker    if not is_rules_python:
166*60517a1eSAndroid Build Coastguard Worker        # Avoid adding third-party dependency files to the checksum of the srcs.
167*60517a1eSAndroid Build Coastguard Worker        return AllSourcesInfo(all_srcs = depset())
168*60517a1eSAndroid Build Coastguard Worker    srcs = depset(
169*60517a1eSAndroid Build Coastguard Worker        target[GoSource].orig_srcs,
170*60517a1eSAndroid Build Coastguard Worker        transitive = [dep[AllSourcesInfo].all_srcs for dep in ctx.rule.attr.deps],
171*60517a1eSAndroid Build Coastguard Worker    )
172*60517a1eSAndroid Build Coastguard Worker    return [AllSourcesInfo(all_srcs = srcs)]
173*60517a1eSAndroid Build Coastguard Worker
174*60517a1eSAndroid Build Coastguard Worker_get_all_sources = aspect(
175*60517a1eSAndroid Build Coastguard Worker    implementation = _get_all_sources_impl,
176*60517a1eSAndroid Build Coastguard Worker    attr_aspects = ["deps"],
177*60517a1eSAndroid Build Coastguard Worker)
178*60517a1eSAndroid Build Coastguard Worker
179*60517a1eSAndroid Build Coastguard Workerdef _sources_hash_impl(ctx):
180*60517a1eSAndroid Build Coastguard Worker    all_srcs = ctx.attr.go_library[AllSourcesInfo].all_srcs
181*60517a1eSAndroid Build Coastguard Worker    hash_file = ctx.actions.declare_file(ctx.attr.name + ".hash")
182*60517a1eSAndroid Build Coastguard Worker    args = ctx.actions.args()
183*60517a1eSAndroid Build Coastguard Worker    args.add(hash_file)
184*60517a1eSAndroid Build Coastguard Worker    args.add_all(all_srcs)
185*60517a1eSAndroid Build Coastguard Worker    ctx.actions.run(
186*60517a1eSAndroid Build Coastguard Worker        outputs = [hash_file],
187*60517a1eSAndroid Build Coastguard Worker        inputs = all_srcs,
188*60517a1eSAndroid Build Coastguard Worker        arguments = [args],
189*60517a1eSAndroid Build Coastguard Worker        executable = ctx.executable._hasher,
190*60517a1eSAndroid Build Coastguard Worker    )
191*60517a1eSAndroid Build Coastguard Worker    return [DefaultInfo(
192*60517a1eSAndroid Build Coastguard Worker        files = depset([hash_file]),
193*60517a1eSAndroid Build Coastguard Worker        runfiles = ctx.runfiles([hash_file]),
194*60517a1eSAndroid Build Coastguard Worker    )]
195*60517a1eSAndroid Build Coastguard Worker
196*60517a1eSAndroid Build Coastguard Workersources_hash = rule(
197*60517a1eSAndroid Build Coastguard Worker    _sources_hash_impl,
198*60517a1eSAndroid Build Coastguard Worker    attrs = {
199*60517a1eSAndroid Build Coastguard Worker        "go_library": attr.label(
200*60517a1eSAndroid Build Coastguard Worker            aspects = [_get_all_sources],
201*60517a1eSAndroid Build Coastguard Worker            providers = [GoSource],
202*60517a1eSAndroid Build Coastguard Worker        ),
203*60517a1eSAndroid Build Coastguard Worker        "_hasher": attr.label(
204*60517a1eSAndroid Build Coastguard Worker            cfg = "exec",
205*60517a1eSAndroid Build Coastguard Worker            default = Label("//manifest/hasher"),
206*60517a1eSAndroid Build Coastguard Worker            executable = True,
207*60517a1eSAndroid Build Coastguard Worker        ),
208*60517a1eSAndroid Build Coastguard Worker    },
209*60517a1eSAndroid Build Coastguard Worker)
210