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 "//go:def.bzl",
17 "GoLibrary",
18 "GoSource",
19 "go_context",
20)
21load(
22 "@bazel_skylib//lib:types.bzl",
23 "types",
24)
25load(
26 "//proto:compiler.bzl",
27 "GoProtoCompiler",
28 "proto_path",
29)
30load(
31 "//go/private:common.bzl",
32 "GO_TOOLCHAIN",
33)
34load(
35 "//go/private/rules:transition.bzl",
36 "non_go_tool_transition",
37)
38load(
39 "@rules_proto//proto:defs.bzl",
40 "ProtoInfo",
41)
42
43GoProtoImports = provider()
44
45def get_imports(attr, importpath):
46 proto_deps = []
47
48 # ctx.attr.proto is a one-element array since there is a Starlark transition attached to it.
49 if hasattr(attr, "proto") and attr.proto and types.is_list(attr.proto) and ProtoInfo in attr.proto[0]:
50 proto_deps = [attr.proto[0]]
51 elif hasattr(attr, "protos"):
52 proto_deps = [d for d in attr.protos if ProtoInfo in d]
53 else:
54 proto_deps = []
55
56 direct = dict()
57 for dep in proto_deps:
58 for src in dep[ProtoInfo].check_deps_sources.to_list():
59 direct["{}={}".format(proto_path(src, dep[ProtoInfo]), importpath)] = True
60
61 deps = getattr(attr, "deps", []) + getattr(attr, "embed", [])
62 transitive = [
63 dep[GoProtoImports].imports
64 for dep in deps
65 if GoProtoImports in dep
66 ]
67 return depset(direct = direct.keys(), transitive = transitive)
68
69def _go_proto_aspect_impl(_target, ctx):
70 go = go_context(ctx, ctx.rule.attr)
71 imports = get_imports(ctx.rule.attr, go.importpath)
72 return [GoProtoImports(imports = imports)]
73
74_go_proto_aspect = aspect(
75 _go_proto_aspect_impl,
76 attr_aspects = [
77 "deps",
78 "embed",
79 ],
80 toolchains = [GO_TOOLCHAIN],
81)
82
83def _proto_library_to_source(_go, attr, source, merge):
84 if attr.compiler:
85 compilers = [attr.compiler]
86 else:
87 compilers = attr.compilers
88 for compiler in compilers:
89 if GoSource in compiler:
90 merge(source, compiler[GoSource])
91
92def _go_proto_library_impl(ctx):
93 go = go_context(ctx)
94 if ctx.attr.compiler:
95 #TODO: print("DEPRECATED: compiler attribute on {}, use compilers instead".format(ctx.label))
96 compilers = [ctx.attr.compiler]
97 else:
98 compilers = ctx.attr.compilers
99
100 if ctx.attr.proto:
101 #TODO: print("DEPRECATED: proto attribute on {}, use protos instead".format(ctx.label))
102 if ctx.attr.protos:
103 fail("Either proto or protos (non-empty) argument must be specified, but not both")
104
105 # ctx.attr.proto is a one-element array since there is a Starlark transition attached to it.
106 proto_deps = [ctx.attr.proto[0]]
107 else:
108 if not ctx.attr.protos:
109 fail("Either proto or protos (non-empty) argument must be specified")
110 proto_deps = ctx.attr.protos
111
112 go_srcs = []
113 valid_archive = False
114
115 for c in compilers:
116 compiler = c[GoProtoCompiler]
117 if compiler.valid_archive:
118 valid_archive = True
119 go_srcs.extend(compiler.compile(
120 go,
121 compiler = compiler,
122 protos = [d[ProtoInfo] for d in proto_deps],
123 imports = get_imports(ctx.attr, go.importpath),
124 importpath = go.importpath,
125 ))
126 library = go.new_library(
127 go,
128 resolver = _proto_library_to_source,
129 srcs = go_srcs,
130 )
131 source = go.library_to_source(go, ctx.attr, library, False)
132 providers = [library, source]
133 output_groups = {
134 "go_generated_srcs": go_srcs,
135 }
136 if valid_archive:
137 archive = go.archive(go, source)
138 output_groups["compilation_outputs"] = [archive.data.file]
139 providers.extend([
140 archive,
141 DefaultInfo(
142 files = depset([archive.data.file]),
143 runfiles = archive.runfiles,
144 ),
145 ])
146 return providers + [OutputGroupInfo(**output_groups)]
147
148go_proto_library = rule(
149 implementation = _go_proto_library_impl,
150 attrs = {
151 "proto": attr.label(
152 cfg = non_go_tool_transition,
153 providers = [ProtoInfo],
154 ),
155 "protos": attr.label_list(
156 cfg = non_go_tool_transition,
157 providers = [ProtoInfo],
158 default = [],
159 ),
160 "deps": attr.label_list(
161 providers = [GoLibrary],
162 aspects = [_go_proto_aspect],
163 ),
164 "importpath": attr.string(),
165 "importmap": attr.string(),
166 "importpath_aliases": attr.string_list(), # experimental, undocumented
167 "embed": attr.label_list(providers = [GoLibrary]),
168 "gc_goopts": attr.string_list(),
169 "compiler": attr.label(providers = [GoProtoCompiler]),
170 "compilers": attr.label_list(
171 providers = [GoProtoCompiler],
172 default = ["//proto:go_proto"],
173 ),
174 "_go_context_data": attr.label(
175 default = "//:go_context_data",
176 ),
177 "_allowlist_function_transition": attr.label(
178 default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
179 ),
180 },
181 toolchains = [GO_TOOLCHAIN],
182)
183# go_proto_library is a rule that takes a proto_library (in the proto
184# attribute) and produces a go library for it.
185
186def go_grpc_library(name, **kwargs):
187 if "compilers" not in kwargs:
188 kwargs["compilers"] = [
189 Label("//proto:go_proto"),
190 Label("//proto:go_grpc_v2"),
191 ]
192 go_proto_library(
193 name = name,
194 **kwargs
195 )
196
197def proto_register_toolchains():
198 print("You no longer need to call proto_register_toolchains(), it does nothing")
View as plain text