github.com/bazelbuild/bazel-gazelle@v0.36.1-0.20240520142334-61b277ba6fed/def.bzl (about) 1 # Copyright 2017 The Bazel Authors. All rights reserved. 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 15 load( 16 "@bazel_gazelle_is_bazel_module//:defs.bzl", 17 "GAZELLE_IS_BAZEL_MODULE", 18 ) 19 load( 20 "@bazel_skylib//lib:shell.bzl", 21 "shell", 22 ) 23 load( 24 "//internal:gazelle_binary.bzl", 25 _gazelle_binary = "gazelle_binary_wrapper", 26 ) 27 load( 28 "//internal:go_repository.bzl", 29 _go_repository = "go_repository", 30 ) 31 load( 32 "//internal:overlay_repository.bzl", 33 _git_repository = "git_repository", 34 _http_archive = "http_archive", 35 ) 36 load( 37 "//internal/generationtest:generationtest.bzl", 38 _gazelle_generation_test = "gazelle_generation_test", 39 ) 40 41 go_repository = _go_repository 42 git_repository = _git_repository 43 http_archive = _http_archive 44 gazelle_binary = _gazelle_binary 45 gazelle_generation_test = _gazelle_generation_test 46 47 DEFAULT_LANGUAGES = [ 48 Label("//language/proto:go_default_library"), 49 Label("//language/go:go_default_library"), 50 ] 51 52 def _valid_env_variable_name(name): 53 """ Returns if a string is in the regex [a-zA-Z_][a-zA-Z0-9_]* 54 55 Given that bazel lacks support of regex, we need to implement 56 a poor man validation 57 """ 58 if not name: 59 return False 60 for i, c in enumerate(name.elems()): 61 if c.isalpha() or c == "_" or (i > 0 and c.isdigit()): 62 continue 63 return False 64 return True 65 66 def _rlocation_path(ctx, file): 67 if file.short_path.startswith("../"): 68 return file.short_path[3:] 69 else: 70 return ctx.workspace_name + "/" + file.short_path 71 72 def _gazelle_runner_impl(ctx): 73 args = [ctx.attr.command] 74 if ctx.attr.mode: 75 args.extend(["-mode", ctx.attr.mode]) 76 if ctx.attr.external: 77 args.extend(["-external", ctx.attr.external]) 78 if ctx.attr.prefix: 79 args.extend(["-go_prefix", ctx.attr.prefix]) 80 if ctx.attr.build_tags: 81 args.extend(["-build_tags", ",".join(ctx.attr.build_tags)]) 82 if GAZELLE_IS_BAZEL_MODULE: 83 args.append("-bzlmod") 84 args.extend([ctx.expand_location(arg, ctx.attr.data) for arg in ctx.attr.extra_args]) 85 86 for key in ctx.attr.env: 87 if not _valid_env_variable_name(key): 88 fail("Invalid environmental variable name: '%s'" % key) 89 90 env = "\n".join(["export %s=%s" % (x, shell.quote(y)) for (x, y) in ctx.attr.env.items()]) 91 92 out_file = ctx.actions.declare_file(ctx.label.name + ".bash") 93 go_tool = ctx.toolchains["@io_bazel_rules_go//go:toolchain"].sdk.go 94 repo_config = ctx.file._repo_config 95 substitutions = { 96 "@@ARGS@@": shell.array_literal(args), 97 "@@GAZELLE_PATH@@": shell.quote(_rlocation_path(ctx, ctx.executable.gazelle)), 98 "@@GENERATED_MESSAGE@@": """ 99 # Generated by {label} 100 # DO NOT EDIT 101 """.format(label = str(ctx.label)), 102 "@@GOTOOL@@": shell.quote(_rlocation_path(ctx, go_tool)), 103 "@@ENV@@": env, 104 "@@REPO_CONFIG_PATH@@": shell.quote(_rlocation_path(ctx, repo_config)) if repo_config else "", 105 } 106 ctx.actions.expand_template( 107 template = ctx.file._template, 108 output = out_file, 109 substitutions = substitutions, 110 is_executable = True, 111 ) 112 runfiles = ctx.runfiles(files = [ 113 ctx.executable.gazelle, 114 go_tool, 115 ] + ([repo_config] if repo_config else [])).merge( 116 ctx.attr.gazelle[DefaultInfo].default_runfiles, 117 ) 118 for d in ctx.attr.data: 119 runfiles = runfiles.merge(d[DefaultInfo].default_runfiles) 120 return [DefaultInfo( 121 files = depset([out_file]), 122 runfiles = runfiles, 123 executable = out_file, 124 )] 125 126 _gazelle_runner = rule( 127 implementation = _gazelle_runner_impl, 128 attrs = { 129 "gazelle": attr.label( 130 allow_single_file = True, 131 default = "//cmd/gazelle", 132 executable = True, 133 cfg = "target", 134 ), 135 "command": attr.string( 136 values = [ 137 "fix", 138 "update", 139 "update-repos", 140 ], 141 default = "update", 142 ), 143 "mode": attr.string( 144 values = ["", "print", "fix", "diff"], 145 default = "", 146 ), 147 "external": attr.string( 148 values = ["", "external", "static", "vendored"], 149 default = "", 150 ), 151 "build_tags": attr.string_list(), 152 "prefix": attr.string(), 153 "extra_args": attr.string_list(), 154 "data": attr.label_list(allow_files = True), 155 "env": attr.string_dict(), 156 "_repo_config": attr.label( 157 default = "@bazel_gazelle_go_repository_config//:WORKSPACE" if GAZELLE_IS_BAZEL_MODULE else None, 158 allow_single_file = True, 159 ), 160 "_template": attr.label( 161 default = "//internal:gazelle.bash.in", 162 allow_single_file = True, 163 ), 164 }, 165 executable = True, 166 toolchains = ["@io_bazel_rules_go//go:toolchain"], 167 ) 168 169 def gazelle(name, **kwargs): 170 if "args" in kwargs: 171 # The args attribute has special meaning for executable rules, but we 172 # always want extra_args here instead. 173 if "extra_args" in kwargs: 174 fail("{}: both args and extra_args were provided".format(name)) 175 kwargs["extra_args"] = kwargs["args"] 176 kwargs.pop("args") 177 178 visibility = kwargs.pop("visibility", default = None) 179 180 tags_set = {t: "" for t in kwargs.pop("tags", [])} 181 tags_set["manual"] = "" 182 tags = [k for k in tags_set.keys()] 183 runner_name = name + "-runner" 184 _gazelle_runner( 185 name = runner_name, 186 tags = tags, 187 **kwargs 188 ) 189 native.sh_binary( 190 name = name, 191 srcs = [runner_name], 192 tags = tags, 193 visibility = visibility, 194 deps = ["@bazel_tools//tools/bash/runfiles"], 195 data = kwargs["data"] if "data" in kwargs else [], 196 )