...

Text file src/github.com/bazelbuild/bazel-gazelle/def.bzl

Documentation: github.com/bazelbuild/bazel-gazelle

     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
    15load(
    16    "@bazel_skylib//lib:shell.bzl",
    17    "shell",
    18)
    19load(
    20    "@bazel_gazelle_is_bazel_module//:defs.bzl",
    21    "GAZELLE_IS_BAZEL_MODULE",
    22)
    23load(
    24    "//internal:go_repository.bzl",
    25    _go_repository = "go_repository",
    26)
    27load(
    28    "//internal:overlay_repository.bzl",
    29    _git_repository = "git_repository",
    30    _http_archive = "http_archive",
    31)
    32load(
    33    "//internal:gazelle_binary.bzl",
    34    _gazelle_binary = "gazelle_binary_wrapper",
    35)
    36load(
    37    "//internal/generationtest:generationtest.bzl",
    38    _gazelle_generation_test = "gazelle_generation_test",
    39)
    40
    41go_repository = _go_repository
    42git_repository = _git_repository
    43http_archive = _http_archive
    44gazelle_binary = _gazelle_binary
    45gazelle_generation_test = _gazelle_generation_test
    46
    47DEFAULT_LANGUAGES = [
    48    Label("//language/proto:go_default_library"),
    49    Label("//language/go:go_default_library"),
    50]
    51
    52def _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
    66def _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
    72def _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 = "exec",
   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
   169def 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    )

View as plain text