| # Copyright 2017 The Bazel Authors. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| load( |
| "//go:def.bzl", |
| "GoLibrary", |
| "GoSource", |
| "go_context", |
| ) |
| load( |
| "@bazel_skylib//lib:types.bzl", |
| "types", |
| ) |
| load( |
| "//proto:compiler.bzl", |
| "GoProtoCompiler", |
| "proto_path", |
| ) |
| load( |
| "//go/private:go_toolchain.bzl", |
| "GO_TOOLCHAIN", |
| ) |
| load( |
| "//go/private:providers.bzl", |
| "INFERRED_PATH", |
| ) |
| load( |
| "//go/private/rules:transition.bzl", |
| "non_go_tool_transition", |
| ) |
| load( |
| "@rules_proto//proto:defs.bzl", |
| "ProtoInfo", |
| ) |
| |
| GoProtoImports = provider() |
| |
| def get_imports(attr): |
| proto_deps = [] |
| |
| # ctx.attr.proto is a one-element array since there is a Starlark transition attached to it. |
| if hasattr(attr, "proto") and attr.proto and types.is_list(attr.proto) and ProtoInfo in attr.proto[0]: |
| proto_deps = [attr.proto[0]] |
| elif hasattr(attr, "protos"): |
| proto_deps = [d for d in attr.protos if ProtoInfo in d] |
| else: |
| proto_deps = [] |
| |
| direct = dict() |
| for dep in proto_deps: |
| for src in dep[ProtoInfo].check_deps_sources.to_list(): |
| direct["{}={}".format(proto_path(src, dep[ProtoInfo]), attr.importpath)] = True |
| |
| deps = getattr(attr, "deps", []) + getattr(attr, "embed", []) |
| transitive = [ |
| dep[GoProtoImports].imports |
| for dep in deps |
| if GoProtoImports in dep |
| ] |
| return depset(direct = direct.keys(), transitive = transitive) |
| |
| def _go_proto_aspect_impl(target, ctx): |
| imports = get_imports(ctx.rule.attr) |
| return [GoProtoImports(imports = imports)] |
| |
| _go_proto_aspect = aspect( |
| _go_proto_aspect_impl, |
| attr_aspects = [ |
| "deps", |
| "embed", |
| ], |
| ) |
| |
| def _proto_library_to_source(go, attr, source, merge): |
| if attr.compiler: |
| compilers = [attr.compiler] |
| else: |
| compilers = attr.compilers |
| for compiler in compilers: |
| if GoSource in compiler: |
| merge(source, compiler[GoSource]) |
| |
| def _go_proto_library_impl(ctx): |
| go = go_context(ctx) |
| if go.pathtype == INFERRED_PATH: |
| fail("importpath must be specified in this library or one of its embedded libraries") |
| if ctx.attr.compiler: |
| #TODO: print("DEPRECATED: compiler attribute on {}, use compilers instead".format(ctx.label)) |
| compilers = [ctx.attr.compiler] |
| else: |
| compilers = ctx.attr.compilers |
| |
| if ctx.attr.proto: |
| #TODO: print("DEPRECATED: proto attribute on {}, use protos instead".format(ctx.label)) |
| if ctx.attr.protos: |
| fail("Either proto or protos (non-empty) argument must be specified, but not both") |
| |
| # ctx.attr.proto is a one-element array since there is a Starlark transition attached to it. |
| proto_deps = [ctx.attr.proto[0]] |
| else: |
| if not ctx.attr.protos: |
| fail("Either proto or protos (non-empty) argument must be specified") |
| proto_deps = ctx.attr.protos |
| |
| go_srcs = [] |
| valid_archive = False |
| |
| for c in compilers: |
| compiler = c[GoProtoCompiler] |
| if compiler.valid_archive: |
| valid_archive = True |
| go_srcs.extend(compiler.compile( |
| go, |
| compiler = compiler, |
| protos = [d[ProtoInfo] for d in proto_deps], |
| imports = get_imports(ctx.attr), |
| importpath = go.importpath, |
| )) |
| library = go.new_library( |
| go, |
| resolver = _proto_library_to_source, |
| srcs = go_srcs, |
| ) |
| source = go.library_to_source(go, ctx.attr, library, False) |
| providers = [library, source] |
| output_groups = { |
| "go_generated_srcs": go_srcs, |
| } |
| if valid_archive: |
| archive = go.archive(go, source) |
| output_groups["compilation_outputs"] = [archive.data.file] |
| providers.extend([ |
| archive, |
| DefaultInfo( |
| files = depset([archive.data.file]), |
| runfiles = archive.runfiles, |
| ), |
| ]) |
| return providers + [OutputGroupInfo(**output_groups)] |
| |
| go_proto_library = rule( |
| implementation = _go_proto_library_impl, |
| attrs = { |
| "proto": attr.label( |
| cfg = non_go_tool_transition, |
| providers = [ProtoInfo], |
| ), |
| "protos": attr.label_list( |
| cfg = non_go_tool_transition, |
| providers = [ProtoInfo], |
| default = [], |
| ), |
| "deps": attr.label_list( |
| providers = [GoLibrary], |
| aspects = [_go_proto_aspect], |
| ), |
| "importpath": attr.string(), |
| "importmap": attr.string(), |
| "importpath_aliases": attr.string_list(), # experimental, undocumented |
| "embed": attr.label_list(providers = [GoLibrary]), |
| "gc_goopts": attr.string_list(), |
| "compiler": attr.label(providers = [GoProtoCompiler]), |
| "compilers": attr.label_list( |
| providers = [GoProtoCompiler], |
| default = ["//proto:go_proto"], |
| ), |
| "_go_context_data": attr.label( |
| default = "//:go_context_data", |
| ), |
| "_allowlist_function_transition": attr.label( |
| default = "@bazel_tools//tools/allowlists/function_transition_allowlist", |
| ), |
| }, |
| toolchains = [GO_TOOLCHAIN], |
| ) |
| # go_proto_library is a rule that takes a proto_library (in the proto |
| # attribute) and produces a go library for it. |
| |
| def go_grpc_library(**kwargs): |
| # TODO: Deprecate once gazelle generates just go_proto_library |
| go_proto_library(compilers = [Label("//proto:go_grpc")], **kwargs) |
| |
| def proto_register_toolchains(): |
| print("You no longer need to call proto_register_toolchains(), it does nothing") |