github.com/bazelbuild/bazel-gazelle@v0.36.1-0.20240520142334-61b277ba6fed/internal/gazelle_binary.bzl (about)

     1  # Copyright 2018 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      "@io_bazel_rules_go//go:def.bzl",
    17      "GoArchive",
    18      "go_context",
    19  )
    20  
    21  def _gazelle_binary_impl(ctx):
    22      go = go_context(ctx)
    23  
    24      # Generate a source file with a list of languages. This will get compiled
    25      # with the rest of the sources in the main package.
    26      langs_file = go.declare_file(go, "langs.go")
    27      langs_content_tpl = """
    28  package main
    29  
    30  import (
    31  	"github.com/bazelbuild/bazel-gazelle/language"
    32  
    33  	{lang_imports}
    34  )
    35  
    36  var languages = []language.Language{{
    37  	{lang_calls},
    38  }}
    39  """
    40      lang_imports = [format_import(d[GoArchive].data.importpath) for d in ctx.attr.languages]
    41      lang_calls = [format_call(d[GoArchive].data.importpath) for d in ctx.attr.languages]
    42      langs_content = langs_content_tpl.format(
    43          lang_imports = "\n\t".join(lang_imports),
    44          lang_calls = ",\n\t".join(lang_calls),
    45      )
    46      go.actions.write(langs_file, langs_content)
    47  
    48      # Build the gazelle binary.
    49      library = go.new_library(go, is_main = True)
    50      attr = struct(
    51          srcs = [struct(files = [langs_file])],
    52          deps = ctx.attr.languages,
    53          embed = [ctx.attr._srcs],
    54      )
    55      source = go.library_to_source(go, attr, library, ctx.coverage_instrumented())
    56  
    57      archive, executable, runfiles = go.binary(
    58          go,
    59          name = ctx.label.name,
    60          source = source,
    61          version_file = ctx.version_file,
    62          info_file = ctx.info_file,
    63      )
    64  
    65      return [
    66          library,
    67          source,
    68          archive,
    69          OutputGroupInfo(compilation_outputs = [archive.data.file]),
    70          DefaultInfo(
    71              files = depset([executable]),
    72              runfiles = runfiles,
    73              executable = executable,
    74          ),
    75      ]
    76  
    77  _gazelle_binary_kwargs = {
    78      "implementation": _gazelle_binary_impl,
    79      "doc": """The `gazelle_binary` rule builds a Go binary that incorporates a list of
    80  language extensions. This requires generating a small amount of code that
    81  must be compiled into Gazelle's main package, so the normal [go_binary]
    82  rule is not used.
    83  
    84  When the binary runs, each language extension is run sequentially. This affects
    85  the order that rules appear in generated build files. Metadata may be produced
    86  by an earlier extension and consumed by a later extension. For example, the
    87  proto extension stores metadata in hidden attributes of generated
    88  `proto_library` rules. The Go extension uses this metadata to generate
    89  `go_proto_library` rules.
    90  """,
    91      "attrs": {
    92          "languages": attr.label_list(
    93              doc = """A list of language extensions the Gazelle binary will use.
    94  
    95              Each extension must be a [go_library] or something compatible. Each extension
    96              must export a function named `NewLanguage` with no parameters that returns
    97              a value assignable to [Language].""",
    98              providers = [GoArchive],
    99              mandatory = True,
   100              allow_empty = False,
   101          ),
   102          "_go_context_data": attr.label(default = "@io_bazel_rules_go//:go_context_data"),
   103          # _stdlib is needed for rules_go versions before v0.23.0. After that,
   104          # _go_context_data includes a dependency on stdlib.
   105          "_stdlib": attr.label(default = "@io_bazel_rules_go//:stdlib"),
   106          "_srcs": attr.label(
   107              default = "//cmd/gazelle:gazelle_lib",
   108          ),
   109      },
   110      "executable": True,
   111      "toolchains": ["@io_bazel_rules_go//go:toolchain"],
   112  }
   113  
   114  gazelle_binary = rule(**_gazelle_binary_kwargs)
   115  
   116  def gazelle_binary_wrapper(**kwargs):
   117      for key in ("goos", "goarch", "static", "msan", "race", "pure", "strip", "debug", "linkmode", "gotags"):
   118          if key in kwargs:
   119              fail("gazelle_binary attribute '%s' is no longer supported (https://github.com/bazelbuild/bazel-gazelle/issues/803)" % key)
   120      gazelle_binary(**kwargs)
   121  
   122  def _import_alias(importpath):
   123      return importpath.replace("/", "_").replace(".", "_").replace("-", "_") + "_"
   124  
   125  def format_import(importpath):
   126      return '{} "{}"'.format(_import_alias(importpath), importpath)
   127  
   128  def format_call(importpath):
   129      return _import_alias(importpath) + ".NewLanguage()"