|
|
|
# Borrowed from
|
|
|
|
# https://github.com/bazelbuild/rules_go/blob/master/proto/toolchain.bzl. This
|
|
|
|
# does some magic munging to remove workspace prefixes from output paths to
|
|
|
|
# convert path as understood by Bazel into paths as understood by protoc.
|
|
|
|
def _proto_path(proto):
|
|
|
|
"""
|
|
|
|
The proto path is not really a file path
|
|
|
|
It's the path to the proto that was seen when the descriptor file was generated.
|
|
|
|
"""
|
|
|
|
path = proto.path
|
|
|
|
root = proto.root.path
|
|
|
|
ws = proto.owner.workspace_root
|
|
|
|
if path.startswith(root): path = path[len(root):]
|
|
|
|
if path.startswith("/"): path = path[1:]
|
|
|
|
if path.startswith(ws): path = path[len(ws):]
|
|
|
|
if path.startswith("/"): path = path[1:]
|
|
|
|
return path
|
|
|
|
|
|
|
|
# Bazel aspect (https://docs.bazel.build/versions/master/skylark/aspects.html)
|
|
|
|
# that can be invoked from the CLI to produce docs via //tools/protodoc for
|
|
|
|
# proto_library targets. Example use:
|
|
|
|
#
|
|
|
|
# bazel build //api --aspects tools/protodoc/protodoc.bzl%proto_doc_aspect \
|
|
|
|
# --output_groups=rst
|
|
|
|
#
|
|
|
|
# The aspect builds the transitive docs, so any .proto in the dependency graph
|
|
|
|
# get docs created.
|
|
|
|
def _proto_doc_aspect_impl(target, ctx):
|
|
|
|
# Compute RST files from the current proto_library node's dependencies.
|
|
|
|
transitive_outputs = depset()
|
|
|
|
for dep in ctx.rule.attr.deps:
|
|
|
|
transitive_outputs = transitive_outputs | dep.output_groups["rst"]
|
|
|
|
proto_sources = target.proto.direct_sources
|
|
|
|
# If this proto_library doesn't actually name any sources, e.g. //api:api,
|
|
|
|
# but just glues together other libs, we just need to follow the graph.
|
|
|
|
if not proto_sources:
|
|
|
|
return [OutputGroupInfo(rst=transitive_outputs)]
|
|
|
|
# Figure out the set of import paths. Ideally we would use descriptor sets
|
|
|
|
# built by proto_library, which avoid having to do nasty path mangling, but
|
|
|
|
# these don't include source_code_info, which we need for comment
|
|
|
|
# extractions. See https://github.com/bazelbuild/bazel/issues/3971.
|
|
|
|
import_paths = []
|
|
|
|
for f in target.proto.transitive_sources:
|
|
|
|
if f.root.path:
|
|
|
|
import_path = f.root.path + "/" + f.owner.workspace_root
|
|
|
|
else:
|
|
|
|
import_path = f.owner.workspace_root
|
|
|
|
if import_path:
|
|
|
|
import_paths += [import_path]
|
|
|
|
# The outputs live in the ctx.label's package root. We add some additional
|
|
|
|
# path information to match with protoc's notion of path relative locations.
|
|
|
|
outputs = [ctx.actions.declare_file(ctx.label.name + "/" + _proto_path(f) +
|
|
|
|
".rst") for f in proto_sources]
|
|
|
|
# Create the protoc command-line args.
|
|
|
|
ctx_path = ctx.label.package + "/" + ctx.label.name
|
|
|
|
output_path = outputs[0].root.path + "/" + outputs[0].owner.workspace_root + "/" + ctx_path
|
|
|
|
args = ["-I./" + ctx.label.workspace_root]
|
|
|
|
args += ["-I" + import_path for import_path in import_paths]
|
|
|
|
args += ["--plugin=protoc-gen-protodoc=" + ctx.executable._protodoc.path, "--protodoc_out=" + output_path]
|
|
|
|
args += [_proto_path(src) for src in target.proto.direct_sources]
|
|
|
|
ctx.action(executable=ctx.executable._protoc,
|
|
|
|
arguments=args,
|
|
|
|
inputs=[ctx.executable._protodoc] + target.proto.transitive_sources.to_list(),
|
|
|
|
outputs=outputs,
|
|
|
|
mnemonic="ProtoDoc",
|
|
|
|
use_default_shell_env=True)
|
|
|
|
transitive_outputs = depset(outputs) | transitive_outputs
|
|
|
|
return [OutputGroupInfo(rst=transitive_outputs)]
|
|
|
|
|
|
|
|
proto_doc_aspect = aspect(implementation = _proto_doc_aspect_impl,
|
|
|
|
attr_aspects = ["deps"],
|
|
|
|
attrs = {
|
|
|
|
"_protoc": attr.label(default=Label("@com_google_protobuf//:protoc"),
|
|
|
|
executable=True,
|
|
|
|
cfg="host"),
|
|
|
|
"_protodoc": attr.label(default=Label("//tools/protodoc"),
|
|
|
|
executable=True,
|
|
|
|
cfg="host"),
|
|
|
|
}
|
|
|
|
)
|