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      )