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
15load(
16 "@io_bazel_rules_go//go:def.bzl",
17 "GoArchive",
18 "go_context",
19)
20
21def _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 = """
28package main
29
30import (
31 "github.com/bazelbuild/bazel-gazelle/language"
32
33 {lang_imports}
34)
35
36var 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
80language extensions. This requires generating a small amount of code that
81must be compiled into Gazelle's main package, so the normal [go_binary]
82rule is not used.
83
84When the binary runs, each language extension is run sequentially. This affects
85the order that rules appear in generated build files. Metadata may be produced
86by an earlier extension and consumed by a later extension. For example, the
87proto 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
114gazelle_binary = rule(**_gazelle_binary_kwargs)
115
116def 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
122def _import_alias(importpath):
123 return importpath.replace("/", "_").replace(".", "_").replace("-", "_") + "_"
124
125def format_import(importpath):
126 return '{} "{}"'.format(_import_alias(importpath), importpath)
127
128def format_call(importpath):
129 return _import_alias(importpath) + ".NewLanguage()"
View as plain text