|  | @@ -4,81 +4,132 @@ This is an internal rule used by cc_grpc_library, and shouldn't be used
 | 
	
		
			
				|  |  |  directly.
 | 
	
		
			
				|  |  |  """
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -def generate_cc_impl(ctx):
 | 
	
		
			
				|  |  | -  """Implementation of the generate_cc rule."""
 | 
	
		
			
				|  |  | -  protos = [f for src in ctx.attr.srcs for f in src.proto.direct_sources]
 | 
	
		
			
				|  |  | -  includes = [f for src in ctx.attr.srcs for f in src.proto.transitive_imports]
 | 
	
		
			
				|  |  | -  outs = []
 | 
	
		
			
				|  |  | -  # label_len is length of the path from WORKSPACE root to the location of this build file
 | 
	
		
			
				|  |  | -  label_len = 0
 | 
	
		
			
				|  |  | -  # proto_root is the directory relative to which generated include paths should be
 | 
	
		
			
				|  |  | -  proto_root = ""
 | 
	
		
			
				|  |  | -  if ctx.label.package:
 | 
	
		
			
				|  |  | -    # The +1 is for the trailing slash.
 | 
	
		
			
				|  |  | -    label_len += len(ctx.label.package) + 1
 | 
	
		
			
				|  |  | -  if ctx.label.workspace_root:
 | 
	
		
			
				|  |  | -    label_len += len(ctx.label.workspace_root) + 1
 | 
	
		
			
				|  |  | -    proto_root = "/" + ctx.label.workspace_root
 | 
	
		
			
				|  |  | +load(
 | 
	
		
			
				|  |  | +    "//bazel:protobuf.bzl",
 | 
	
		
			
				|  |  | +    "get_include_protoc_args",
 | 
	
		
			
				|  |  | +    "get_plugin_args",
 | 
	
		
			
				|  |  | +    "get_proto_root",
 | 
	
		
			
				|  |  | +    "proto_path_to_generated_filename",
 | 
	
		
			
				|  |  | +)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +_GRPC_PROTO_HEADER_FMT = "{}.grpc.pb.h"
 | 
	
		
			
				|  |  | +_GRPC_PROTO_SRC_FMT = "{}.grpc.pb.cc"
 | 
	
		
			
				|  |  | +_GRPC_PROTO_MOCK_HEADER_FMT = "{}_mock.grpc.pb.h"
 | 
	
		
			
				|  |  | +_PROTO_HEADER_FMT = "{}.pb.h"
 | 
	
		
			
				|  |  | +_PROTO_SRC_FMT = "{}.pb.cc"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if ctx.executable.plugin:
 | 
	
		
			
				|  |  | -    outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.h" for proto in protos]
 | 
	
		
			
				|  |  | -    outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.cc" for proto in protos]
 | 
	
		
			
				|  |  | -    if ctx.attr.generate_mocks:
 | 
	
		
			
				|  |  | -      outs += [proto.path[label_len:-len(".proto")] + "_mock.grpc.pb.h" for proto in protos]
 | 
	
		
			
				|  |  | -  else:
 | 
	
		
			
				|  |  | -    outs += [proto.path[label_len:-len(".proto")] + ".pb.h" for proto in protos]
 | 
	
		
			
				|  |  | -    outs += [proto.path[label_len:-len(".proto")] + ".pb.cc" for proto in protos]
 | 
	
		
			
				|  |  | -  out_files = [ctx.actions.declare_file(out) for out in outs]
 | 
	
		
			
				|  |  | -  dir_out = str(ctx.genfiles_dir.path + proto_root)
 | 
	
		
			
				|  |  | +def _strip_package_from_path(label_package, path):
 | 
	
		
			
				|  |  | +    if len(label_package) == 0:
 | 
	
		
			
				|  |  | +        return path
 | 
	
		
			
				|  |  | +    if not path.startswith(label_package + "/"):
 | 
	
		
			
				|  |  | +        fail("'{}' does not lie within '{}'.".format(path, label_package))
 | 
	
		
			
				|  |  | +    return path[len(label_package + "/"):]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  arguments = []
 | 
	
		
			
				|  |  | -  if ctx.executable.plugin:
 | 
	
		
			
				|  |  | -    arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path]
 | 
	
		
			
				|  |  | -    flags = list(ctx.attr.flags)
 | 
	
		
			
				|  |  | -    if ctx.attr.generate_mocks:
 | 
	
		
			
				|  |  | -      flags.append("generate_mock_code=true")
 | 
	
		
			
				|  |  | -    arguments += ["--PLUGIN_out=" + ",".join(flags) + ":" + dir_out]
 | 
	
		
			
				|  |  | -    tools = [ctx.executable.plugin]
 | 
	
		
			
				|  |  | -  else:
 | 
	
		
			
				|  |  | -    arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
 | 
	
		
			
				|  |  | -    tools = []
 | 
	
		
			
				|  |  | +def _join_directories(directories):
 | 
	
		
			
				|  |  | +    massaged_directories = [directory for directory in directories if len(directory) != 0]
 | 
	
		
			
				|  |  | +    return "/".join(massaged_directories)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  # Import protos relative to their workspace root so that protoc prints the
 | 
	
		
			
				|  |  | -  # right include paths.
 | 
	
		
			
				|  |  | -  for include in includes:
 | 
	
		
			
				|  |  | -    directory = include.path
 | 
	
		
			
				|  |  | -    if directory.startswith("external"):
 | 
	
		
			
				|  |  | -      external_sep = directory.find("/")
 | 
	
		
			
				|  |  | -      repository_sep = directory.find("/", external_sep + 1)
 | 
	
		
			
				|  |  | -      arguments += ["--proto_path=" + directory[:repository_sep]]
 | 
	
		
			
				|  |  | +def generate_cc_impl(ctx):
 | 
	
		
			
				|  |  | +    """Implementation of the generate_cc rule."""
 | 
	
		
			
				|  |  | +    protos = [f for src in ctx.attr.srcs for f in src.proto.direct_sources]
 | 
	
		
			
				|  |  | +    includes = [
 | 
	
		
			
				|  |  | +        f
 | 
	
		
			
				|  |  | +        for src in ctx.attr.srcs
 | 
	
		
			
				|  |  | +        for f in src.proto.transitive_imports
 | 
	
		
			
				|  |  | +    ]
 | 
	
		
			
				|  |  | +    outs = []
 | 
	
		
			
				|  |  | +    proto_root = get_proto_root(
 | 
	
		
			
				|  |  | +        ctx.label.workspace_root,
 | 
	
		
			
				|  |  | +    )
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    label_package = _join_directories([ctx.label.workspace_root, ctx.label.package])
 | 
	
		
			
				|  |  | +    if ctx.executable.plugin:
 | 
	
		
			
				|  |  | +        outs += [
 | 
	
		
			
				|  |  | +            proto_path_to_generated_filename(
 | 
	
		
			
				|  |  | +                _strip_package_from_path(label_package, proto.path),
 | 
	
		
			
				|  |  | +                _GRPC_PROTO_HEADER_FMT,
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  | +            for proto in protos
 | 
	
		
			
				|  |  | +        ]
 | 
	
		
			
				|  |  | +        outs += [
 | 
	
		
			
				|  |  | +            proto_path_to_generated_filename(
 | 
	
		
			
				|  |  | +                _strip_package_from_path(label_package, proto.path),
 | 
	
		
			
				|  |  | +                _GRPC_PROTO_SRC_FMT,
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  | +            for proto in protos
 | 
	
		
			
				|  |  | +        ]
 | 
	
		
			
				|  |  | +        if ctx.attr.generate_mocks:
 | 
	
		
			
				|  |  | +            outs += [
 | 
	
		
			
				|  |  | +                proto_path_to_generated_filename(
 | 
	
		
			
				|  |  | +                    _strip_package_from_path(label_package, proto.path),
 | 
	
		
			
				|  |  | +                    _GRPC_PROTO_MOCK_HEADER_FMT,
 | 
	
		
			
				|  |  | +                )
 | 
	
		
			
				|  |  | +                for proto in protos
 | 
	
		
			
				|  |  | +            ]
 | 
	
		
			
				|  |  |      else:
 | 
	
		
			
				|  |  | -      arguments += ["--proto_path=."]
 | 
	
		
			
				|  |  | -  # Include the output directory so that protoc puts the generated code in the
 | 
	
		
			
				|  |  | -  # right directory.
 | 
	
		
			
				|  |  | -  arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)]
 | 
	
		
			
				|  |  | -  arguments += [proto.path for proto in protos]
 | 
	
		
			
				|  |  | +        outs += [
 | 
	
		
			
				|  |  | +            proto_path_to_generated_filename(
 | 
	
		
			
				|  |  | +                _strip_package_from_path(label_package, proto.path),
 | 
	
		
			
				|  |  | +                _PROTO_HEADER_FMT,
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  | +            for proto in protos
 | 
	
		
			
				|  |  | +        ]
 | 
	
		
			
				|  |  | +        outs += [
 | 
	
		
			
				|  |  | +            proto_path_to_generated_filename(
 | 
	
		
			
				|  |  | +                _strip_package_from_path(label_package, proto.path),
 | 
	
		
			
				|  |  | +                _PROTO_SRC_FMT,
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  | +            for proto in protos
 | 
	
		
			
				|  |  | +        ]
 | 
	
		
			
				|  |  | +    out_files = [ctx.actions.declare_file(out) for out in outs]
 | 
	
		
			
				|  |  | +    dir_out = str(ctx.genfiles_dir.path + proto_root)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  # create a list of well known proto files if the argument is non-None
 | 
	
		
			
				|  |  | -  well_known_proto_files = []
 | 
	
		
			
				|  |  | -  if ctx.attr.well_known_protos:
 | 
	
		
			
				|  |  | -    f = ctx.attr.well_known_protos.files.to_list()[0].dirname
 | 
	
		
			
				|  |  | -    if f != "external/com_google_protobuf/src/google/protobuf":
 | 
	
		
			
				|  |  | -      print("Error: Only @com_google_protobuf//:well_known_protos is supported")
 | 
	
		
			
				|  |  | +    arguments = []
 | 
	
		
			
				|  |  | +    if ctx.executable.plugin:
 | 
	
		
			
				|  |  | +        arguments += get_plugin_args(
 | 
	
		
			
				|  |  | +            ctx.executable.plugin,
 | 
	
		
			
				|  |  | +            ctx.attr.flags,
 | 
	
		
			
				|  |  | +            dir_out,
 | 
	
		
			
				|  |  | +            ctx.attr.generate_mocks,
 | 
	
		
			
				|  |  | +        )
 | 
	
		
			
				|  |  | +        tools = [ctx.executable.plugin]
 | 
	
		
			
				|  |  |      else:
 | 
	
		
			
				|  |  | -      # f points to "external/com_google_protobuf/src/google/protobuf"
 | 
	
		
			
				|  |  | -      # add -I argument to protoc so it knows where to look for the proto files.
 | 
	
		
			
				|  |  | -      arguments += ["-I{0}".format(f + "/../..")]
 | 
	
		
			
				|  |  | -      well_known_proto_files = [f for f in ctx.attr.well_known_protos.files]
 | 
	
		
			
				|  |  | +        arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
 | 
	
		
			
				|  |  | +        tools = []
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    arguments += get_include_protoc_args(includes)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  ctx.actions.run(
 | 
	
		
			
				|  |  | -      inputs = protos + includes + well_known_proto_files,
 | 
	
		
			
				|  |  | -      tools = tools,
 | 
	
		
			
				|  |  | -      outputs = out_files,
 | 
	
		
			
				|  |  | -      executable = ctx.executable._protoc,
 | 
	
		
			
				|  |  | -      arguments = arguments,
 | 
	
		
			
				|  |  | -  )
 | 
	
		
			
				|  |  | +    # Include the output directory so that protoc puts the generated code in the
 | 
	
		
			
				|  |  | +    # right directory.
 | 
	
		
			
				|  |  | +    arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)]
 | 
	
		
			
				|  |  | +    arguments += [proto.path for proto in protos]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  return struct(files=depset(out_files))
 | 
	
		
			
				|  |  | +    # create a list of well known proto files if the argument is non-None
 | 
	
		
			
				|  |  | +    well_known_proto_files = []
 | 
	
		
			
				|  |  | +    if ctx.attr.well_known_protos:
 | 
	
		
			
				|  |  | +        f = ctx.attr.well_known_protos.files.to_list()[0].dirname
 | 
	
		
			
				|  |  | +        if f != "external/com_google_protobuf/src/google/protobuf":
 | 
	
		
			
				|  |  | +            print(
 | 
	
		
			
				|  |  | +                "Error: Only @com_google_protobuf//:well_known_protos is supported",
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  | +        else:
 | 
	
		
			
				|  |  | +            # f points to "external/com_google_protobuf/src/google/protobuf"
 | 
	
		
			
				|  |  | +            # add -I argument to protoc so it knows where to look for the proto files.
 | 
	
		
			
				|  |  | +            arguments += ["-I{0}".format(f + "/../..")]
 | 
	
		
			
				|  |  | +            well_known_proto_files = [
 | 
	
		
			
				|  |  | +                f
 | 
	
		
			
				|  |  | +                for f in ctx.attr.well_known_protos.files
 | 
	
		
			
				|  |  | +            ]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    ctx.actions.run(
 | 
	
		
			
				|  |  | +        inputs = protos + includes + well_known_proto_files,
 | 
	
		
			
				|  |  | +        tools = tools,
 | 
	
		
			
				|  |  | +        outputs = out_files,
 | 
	
		
			
				|  |  | +        executable = ctx.executable._protoc,
 | 
	
		
			
				|  |  | +        arguments = arguments,
 | 
	
		
			
				|  |  | +    )
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return struct(files = depset(out_files))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  _generate_cc = rule(
 | 
	
		
			
				|  |  |      attrs = {
 | 
	
	
		
			
				|  | @@ -96,10 +147,8 @@ _generate_cc = rule(
 | 
	
		
			
				|  |  |              mandatory = False,
 | 
	
		
			
				|  |  |              allow_empty = True,
 | 
	
		
			
				|  |  |          ),
 | 
	
		
			
				|  |  | -        "well_known_protos" : attr.label(
 | 
	
		
			
				|  |  | -            mandatory = False,
 | 
	
		
			
				|  |  | -        ),
 | 
	
		
			
				|  |  | -        "generate_mocks" : attr.bool(
 | 
	
		
			
				|  |  | +        "well_known_protos": attr.label(mandatory = False),
 | 
	
		
			
				|  |  | +        "generate_mocks": attr.bool(
 | 
	
		
			
				|  |  |              default = False,
 | 
	
		
			
				|  |  |              mandatory = False,
 | 
	
		
			
				|  |  |          ),
 | 
	
	
		
			
				|  | @@ -115,7 +164,10 @@ _generate_cc = rule(
 | 
	
		
			
				|  |  |  )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  def generate_cc(well_known_protos, **kwargs):
 | 
	
		
			
				|  |  | -  if well_known_protos:
 | 
	
		
			
				|  |  | -    _generate_cc(well_known_protos="@com_google_protobuf//:well_known_protos", **kwargs)
 | 
	
		
			
				|  |  | -  else:
 | 
	
		
			
				|  |  | -    _generate_cc(**kwargs)
 | 
	
		
			
				|  |  | +    if well_known_protos:
 | 
	
		
			
				|  |  | +        _generate_cc(
 | 
	
		
			
				|  |  | +            well_known_protos = "@com_google_protobuf//:well_known_protos",
 | 
	
		
			
				|  |  | +            **kwargs
 | 
	
		
			
				|  |  | +        )
 | 
	
		
			
				|  |  | +    else:
 | 
	
		
			
				|  |  | +        _generate_cc(**kwargs)
 |