The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#) https://grpc.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
6.6 KiB

load(
"//bazel:protobuf.bzl",
[bazel][python] Support _virtual_imports input for py_proto_library and py_grpc_library rules `proto_library` targets are used as deps for `py_proto_library` and `py_grpc_library` rules. The `proto_library` targets can be configured using `import_prefix` and/or `strip_import_prefix` (which essentially move original location of the proto file and, as result, affects import path within proto files themselves and in the generated language-specific stubs). The biggest question to answer when generating stubs from moved protos is where to put result (this decision affects all downstream rules as well, because the location of file affects its import path). This PR tries to follow same logic as the native `cc_proto_library` (created and maintained by Bazel team). For example, if we have `firestore.proto` file, which is located under `google/firestore/v1beta1` Bazel package and want to move it under `google/cloud/firestore_v1beta1/proto` (this is axactly what happens in googleapis repository), it can be configured the following way: ```bzl proto_library( name = "firestore_moved_proto", srcs = ["firestore.proto"], import_prefix = "google/cloud/firestore_v1beta1/proto", strip_import_prefix = "google/firestore/v1beta1", ) ``` The rule above will first generate virtual `.proto` files (under new location) and only after that generate a binary descriptor from them. Specifically it will generate the following "virtual" file under `_virtual_imports` subdirectory of same package: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/common.proto ``` When supplied to `cc_proto_library`, like the following: ```bzl cc_proto_library( name = "firestore_moved_cc_proto", deps = ["firestore_moved_proto"], ) ``` The rule will generate .cc and .h files like the following: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore.pb.h bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore.pb.cc ``` Notice, that each generated `.cc` and `.h` file is prefixed with `_virtual_imports/<name_of_proto_library_target>`. The python rules try to do same thing, so for the following py_proto_library rule: ```bzl py_proto_library( name = "firestore_moved_py_proto", deps = [":firestore_moved_proto"], ) ``` It wil generate the following file: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore_pb2.py ``` I.e in same path as cc_proto_library. This all woks, but an annoying part is that to use the generated library in some other py_library, in needs to specify the "_virtual_imports/proto_target" path as its "includes" parameter (and I can't make it better than that). Another option would be to skeep the `_virtual_imports/<name_of_proto_library_target>` the suffix for the generated python stubs, which will make the path look like the following: ``` bazel-bin/google/firestore/v1beta1/google/cloud/firestore_v1beta1/proto/firestore_pb2.py ``` That will make using generated stubs simpler and cleaner (no need to specify imports argument), but it will make it inconsistent with the other rules (like cc_proto_library) and also more susseptible to naming conflicts (if there is already something under the generated path).
5 years ago
"get_include_directory",
"get_plugin_args",
"proto_path_to_generated_filename",
)
load(":grpc_util.bzl", "to_upper_camel_with_extension")
_GRPC_PROTO_HEADER_FMT = "{}.pbrpc.h"
_GRPC_PROTO_SRC_FMT = "{}.pbrpc.m"
_PROTO_HEADER_FMT = "{}.pbobjc.h"
_PROTO_SRC_FMT = "{}.pbobjc.m"
_GENERATED_PROTOS_DIR = "_generated_protos"
_GENERATE_HDRS = 1
_GENERATE_SRCS = 2
_GENERATE_NON_ARC_SRCS = 3
def _generate_objc_impl(ctx):
"""Implementation of the generate_objc rule."""
protos = [
f
for src in ctx.attr.deps
for f in src[ProtoInfo].transitive_imports.to_list()
]
target_package = _join_directories([ctx.label.workspace_root, ctx.label.package])
files_with_rpc = [_label_to_full_file_path(f, target_package) for f in ctx.attr.srcs]
outs = []
for proto in protos:
outs += [_get_output_file_name_from_proto(proto, _PROTO_HEADER_FMT)]
outs += [_get_output_file_name_from_proto(proto, _PROTO_SRC_FMT)]
file_path = _get_full_path_from_file(proto)
if file_path in files_with_rpc:
outs += [_get_output_file_name_from_proto(proto, _GRPC_PROTO_HEADER_FMT)]
outs += [_get_output_file_name_from_proto(proto, _GRPC_PROTO_SRC_FMT)]
[bazel][python] Support _virtual_imports input for py_proto_library and py_grpc_library rules `proto_library` targets are used as deps for `py_proto_library` and `py_grpc_library` rules. The `proto_library` targets can be configured using `import_prefix` and/or `strip_import_prefix` (which essentially move original location of the proto file and, as result, affects import path within proto files themselves and in the generated language-specific stubs). The biggest question to answer when generating stubs from moved protos is where to put result (this decision affects all downstream rules as well, because the location of file affects its import path). This PR tries to follow same logic as the native `cc_proto_library` (created and maintained by Bazel team). For example, if we have `firestore.proto` file, which is located under `google/firestore/v1beta1` Bazel package and want to move it under `google/cloud/firestore_v1beta1/proto` (this is axactly what happens in googleapis repository), it can be configured the following way: ```bzl proto_library( name = "firestore_moved_proto", srcs = ["firestore.proto"], import_prefix = "google/cloud/firestore_v1beta1/proto", strip_import_prefix = "google/firestore/v1beta1", ) ``` The rule above will first generate virtual `.proto` files (under new location) and only after that generate a binary descriptor from them. Specifically it will generate the following "virtual" file under `_virtual_imports` subdirectory of same package: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/common.proto ``` When supplied to `cc_proto_library`, like the following: ```bzl cc_proto_library( name = "firestore_moved_cc_proto", deps = ["firestore_moved_proto"], ) ``` The rule will generate .cc and .h files like the following: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore.pb.h bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore.pb.cc ``` Notice, that each generated `.cc` and `.h` file is prefixed with `_virtual_imports/<name_of_proto_library_target>`. The python rules try to do same thing, so for the following py_proto_library rule: ```bzl py_proto_library( name = "firestore_moved_py_proto", deps = [":firestore_moved_proto"], ) ``` It wil generate the following file: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore_pb2.py ``` I.e in same path as cc_proto_library. This all woks, but an annoying part is that to use the generated library in some other py_library, in needs to specify the "_virtual_imports/proto_target" path as its "includes" parameter (and I can't make it better than that). Another option would be to skeep the `_virtual_imports/<name_of_proto_library_target>` the suffix for the generated python stubs, which will make the path look like the following: ``` bazel-bin/google/firestore/v1beta1/google/cloud/firestore_v1beta1/proto/firestore_pb2.py ``` That will make using generated stubs simpler and cleaner (no need to specify imports argument), but it will make it inconsistent with the other rules (like cc_proto_library) and also more susseptible to naming conflicts (if there is already something under the generated path).
5 years ago
out_files = [ctx.actions.declare_file(out) for out in outs]
dir_out = _join_directories([
str(ctx.genfiles_dir.path),
target_package,
_GENERATED_PROTOS_DIR,
])
arguments = []
if ctx.executable.plugin:
arguments += get_plugin_args(
ctx.executable.plugin,
[],
dir_out,
False,
)
tools = [ctx.executable.plugin]
arguments += ["--objc_out=" + dir_out]
arguments += ["--proto_path=."]
[bazel][python] Support _virtual_imports input for py_proto_library and py_grpc_library rules `proto_library` targets are used as deps for `py_proto_library` and `py_grpc_library` rules. The `proto_library` targets can be configured using `import_prefix` and/or `strip_import_prefix` (which essentially move original location of the proto file and, as result, affects import path within proto files themselves and in the generated language-specific stubs). The biggest question to answer when generating stubs from moved protos is where to put result (this decision affects all downstream rules as well, because the location of file affects its import path). This PR tries to follow same logic as the native `cc_proto_library` (created and maintained by Bazel team). For example, if we have `firestore.proto` file, which is located under `google/firestore/v1beta1` Bazel package and want to move it under `google/cloud/firestore_v1beta1/proto` (this is axactly what happens in googleapis repository), it can be configured the following way: ```bzl proto_library( name = "firestore_moved_proto", srcs = ["firestore.proto"], import_prefix = "google/cloud/firestore_v1beta1/proto", strip_import_prefix = "google/firestore/v1beta1", ) ``` The rule above will first generate virtual `.proto` files (under new location) and only after that generate a binary descriptor from them. Specifically it will generate the following "virtual" file under `_virtual_imports` subdirectory of same package: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/common.proto ``` When supplied to `cc_proto_library`, like the following: ```bzl cc_proto_library( name = "firestore_moved_cc_proto", deps = ["firestore_moved_proto"], ) ``` The rule will generate .cc and .h files like the following: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore.pb.h bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore.pb.cc ``` Notice, that each generated `.cc` and `.h` file is prefixed with `_virtual_imports/<name_of_proto_library_target>`. The python rules try to do same thing, so for the following py_proto_library rule: ```bzl py_proto_library( name = "firestore_moved_py_proto", deps = [":firestore_moved_proto"], ) ``` It wil generate the following file: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore_pb2.py ``` I.e in same path as cc_proto_library. This all woks, but an annoying part is that to use the generated library in some other py_library, in needs to specify the "_virtual_imports/proto_target" path as its "includes" parameter (and I can't make it better than that). Another option would be to skeep the `_virtual_imports/<name_of_proto_library_target>` the suffix for the generated python stubs, which will make the path look like the following: ``` bazel-bin/google/firestore/v1beta1/google/cloud/firestore_v1beta1/proto/firestore_pb2.py ``` That will make using generated stubs simpler and cleaner (no need to specify imports argument), but it will make it inconsistent with the other rules (like cc_proto_library) and also more susseptible to naming conflicts (if there is already something under the generated path).
5 years ago
arguments += [
"--proto_path={}".format(get_include_directory(i))
for i in protos
]
# Include the output directory so that protoc puts the generated code in the
# right directory.
arguments += ["--proto_path={}".format(dir_out)]
arguments += ["--proto_path={}".format(_get_directory_from_proto(proto)) for proto in protos]
arguments += [_get_full_path_from_file(proto) for proto in protos]
# create a list of well known proto files if the argument is non-None
well_known_proto_files = []
if ctx.attr.use_well_known_protos:
f = ctx.attr.well_known_protos.files.to_list()[0].dirname
# go two levels up so that #import "google/protobuf/..." is correct
[bazel][python] Support _virtual_imports input for py_proto_library and py_grpc_library rules `proto_library` targets are used as deps for `py_proto_library` and `py_grpc_library` rules. The `proto_library` targets can be configured using `import_prefix` and/or `strip_import_prefix` (which essentially move original location of the proto file and, as result, affects import path within proto files themselves and in the generated language-specific stubs). The biggest question to answer when generating stubs from moved protos is where to put result (this decision affects all downstream rules as well, because the location of file affects its import path). This PR tries to follow same logic as the native `cc_proto_library` (created and maintained by Bazel team). For example, if we have `firestore.proto` file, which is located under `google/firestore/v1beta1` Bazel package and want to move it under `google/cloud/firestore_v1beta1/proto` (this is axactly what happens in googleapis repository), it can be configured the following way: ```bzl proto_library( name = "firestore_moved_proto", srcs = ["firestore.proto"], import_prefix = "google/cloud/firestore_v1beta1/proto", strip_import_prefix = "google/firestore/v1beta1", ) ``` The rule above will first generate virtual `.proto` files (under new location) and only after that generate a binary descriptor from them. Specifically it will generate the following "virtual" file under `_virtual_imports` subdirectory of same package: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/common.proto ``` When supplied to `cc_proto_library`, like the following: ```bzl cc_proto_library( name = "firestore_moved_cc_proto", deps = ["firestore_moved_proto"], ) ``` The rule will generate .cc and .h files like the following: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore.pb.h bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore.pb.cc ``` Notice, that each generated `.cc` and `.h` file is prefixed with `_virtual_imports/<name_of_proto_library_target>`. The python rules try to do same thing, so for the following py_proto_library rule: ```bzl py_proto_library( name = "firestore_moved_py_proto", deps = [":firestore_moved_proto"], ) ``` It wil generate the following file: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore_pb2.py ``` I.e in same path as cc_proto_library. This all woks, but an annoying part is that to use the generated library in some other py_library, in needs to specify the "_virtual_imports/proto_target" path as its "includes" parameter (and I can't make it better than that). Another option would be to skeep the `_virtual_imports/<name_of_proto_library_target>` the suffix for the generated python stubs, which will make the path look like the following: ``` bazel-bin/google/firestore/v1beta1/google/cloud/firestore_v1beta1/proto/firestore_pb2.py ``` That will make using generated stubs simpler and cleaner (no need to specify imports argument), but it will make it inconsistent with the other rules (like cc_proto_library) and also more susseptible to naming conflicts (if there is already something under the generated path).
5 years ago
arguments += ["-I{0}".format(f + "/../..")]
well_known_proto_files = ctx.attr.well_known_protos.files.to_list()
ctx.actions.run(
inputs = protos + well_known_proto_files,
tools = tools,
outputs = out_files,
executable = ctx.executable._protoc,
arguments = arguments,
)
return struct(files = depset(out_files))
def _label_to_full_file_path(src, package):
if not src.startswith("//"):
# Relative from current package
if not src.startswith(":"):
# "a.proto" -> ":a.proto"
src = ":" + src
src = "//" + package + src
# Converts //path/to/package:File.ext to path/to/package/File.ext.
src = src.replace("//", "")
src = src.replace(":", "/")
if src.startswith("/"):
# "//:a.proto" -> "/a.proto" so remove the initial slash
return src[1:]
else:
return src
def _get_output_file_name_from_proto(proto, fmt):
return proto_path_to_generated_filename(
_GENERATED_PROTOS_DIR + "/" +
_get_directory_from_proto(proto) + _get_slash_or_null_from_proto(proto) +
to_upper_camel_with_extension(_get_file_name_from_proto(proto), "proto"),
fmt,
)
def _get_file_name_from_proto(proto):
return proto.path.rpartition("/")[2]
def _get_slash_or_null_from_proto(proto):
"""Potentially returns empty (if the file is in the root directory)"""
return proto.path.rpartition("/")[1]
def _get_directory_from_proto(proto):
return proto.path.rpartition("/")[0]
def _get_full_path_from_file(file):
gen_dir_length = 0
[bazel][python] Support _virtual_imports input for py_proto_library and py_grpc_library rules `proto_library` targets are used as deps for `py_proto_library` and `py_grpc_library` rules. The `proto_library` targets can be configured using `import_prefix` and/or `strip_import_prefix` (which essentially move original location of the proto file and, as result, affects import path within proto files themselves and in the generated language-specific stubs). The biggest question to answer when generating stubs from moved protos is where to put result (this decision affects all downstream rules as well, because the location of file affects its import path). This PR tries to follow same logic as the native `cc_proto_library` (created and maintained by Bazel team). For example, if we have `firestore.proto` file, which is located under `google/firestore/v1beta1` Bazel package and want to move it under `google/cloud/firestore_v1beta1/proto` (this is axactly what happens in googleapis repository), it can be configured the following way: ```bzl proto_library( name = "firestore_moved_proto", srcs = ["firestore.proto"], import_prefix = "google/cloud/firestore_v1beta1/proto", strip_import_prefix = "google/firestore/v1beta1", ) ``` The rule above will first generate virtual `.proto` files (under new location) and only after that generate a binary descriptor from them. Specifically it will generate the following "virtual" file under `_virtual_imports` subdirectory of same package: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/common.proto ``` When supplied to `cc_proto_library`, like the following: ```bzl cc_proto_library( name = "firestore_moved_cc_proto", deps = ["firestore_moved_proto"], ) ``` The rule will generate .cc and .h files like the following: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore.pb.h bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore.pb.cc ``` Notice, that each generated `.cc` and `.h` file is prefixed with `_virtual_imports/<name_of_proto_library_target>`. The python rules try to do same thing, so for the following py_proto_library rule: ```bzl py_proto_library( name = "firestore_moved_py_proto", deps = [":firestore_moved_proto"], ) ``` It wil generate the following file: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore_pb2.py ``` I.e in same path as cc_proto_library. This all woks, but an annoying part is that to use the generated library in some other py_library, in needs to specify the "_virtual_imports/proto_target" path as its "includes" parameter (and I can't make it better than that). Another option would be to skeep the `_virtual_imports/<name_of_proto_library_target>` the suffix for the generated python stubs, which will make the path look like the following: ``` bazel-bin/google/firestore/v1beta1/google/cloud/firestore_v1beta1/proto/firestore_pb2.py ``` That will make using generated stubs simpler and cleaner (no need to specify imports argument), but it will make it inconsistent with the other rules (like cc_proto_library) and also more susseptible to naming conflicts (if there is already something under the generated path).
5 years ago
# if file is generated, then prepare to remote its root
# (including CPU architecture...)
if not file.is_source:
gen_dir_length = len(file.root.path) + 1
return file.path[gen_dir_length:]
def _join_directories(directories):
massaged_directories = [directory for directory in directories if len(directory) != 0]
return "/".join(massaged_directories)
generate_objc = rule(
attrs = {
"deps": attr.label_list(
mandatory = True,
allow_empty = False,
providers = [ProtoInfo],
),
"plugin": attr.label(
default = "@com_github_grpc_grpc//src/compiler:grpc_objective_c_plugin",
executable = True,
providers = ["files_to_run"],
cfg = "host",
),
"srcs": attr.string_list(
mandatory = False,
allow_empty = True,
),
"use_well_known_protos": attr.bool(
mandatory = False,
default = False,
),
"well_known_protos": attr.label(
default = "@com_google_protobuf//:well_known_protos",
),
"_protoc": attr.label(
default = Label("//external:protocol_compiler"),
executable = True,
cfg = "host",
),
},
output_to_genfiles = True,
implementation = _generate_objc_impl,
)
def _group_objc_files_impl(ctx):
suffix = ""
if ctx.attr.gen_mode == _GENERATE_HDRS:
suffix = "h"
elif ctx.attr.gen_mode == _GENERATE_SRCS:
suffix = "pbrpc.m"
elif ctx.attr.gen_mode == _GENERATE_NON_ARC_SRCS:
suffix = "pbobjc.m"
else:
fail("Undefined gen_mode")
out_files = [
[bazel][python] Support _virtual_imports input for py_proto_library and py_grpc_library rules `proto_library` targets are used as deps for `py_proto_library` and `py_grpc_library` rules. The `proto_library` targets can be configured using `import_prefix` and/or `strip_import_prefix` (which essentially move original location of the proto file and, as result, affects import path within proto files themselves and in the generated language-specific stubs). The biggest question to answer when generating stubs from moved protos is where to put result (this decision affects all downstream rules as well, because the location of file affects its import path). This PR tries to follow same logic as the native `cc_proto_library` (created and maintained by Bazel team). For example, if we have `firestore.proto` file, which is located under `google/firestore/v1beta1` Bazel package and want to move it under `google/cloud/firestore_v1beta1/proto` (this is axactly what happens in googleapis repository), it can be configured the following way: ```bzl proto_library( name = "firestore_moved_proto", srcs = ["firestore.proto"], import_prefix = "google/cloud/firestore_v1beta1/proto", strip_import_prefix = "google/firestore/v1beta1", ) ``` The rule above will first generate virtual `.proto` files (under new location) and only after that generate a binary descriptor from them. Specifically it will generate the following "virtual" file under `_virtual_imports` subdirectory of same package: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/common.proto ``` When supplied to `cc_proto_library`, like the following: ```bzl cc_proto_library( name = "firestore_moved_cc_proto", deps = ["firestore_moved_proto"], ) ``` The rule will generate .cc and .h files like the following: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore.pb.h bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore.pb.cc ``` Notice, that each generated `.cc` and `.h` file is prefixed with `_virtual_imports/<name_of_proto_library_target>`. The python rules try to do same thing, so for the following py_proto_library rule: ```bzl py_proto_library( name = "firestore_moved_py_proto", deps = [":firestore_moved_proto"], ) ``` It wil generate the following file: ``` bazel-bin/google/firestore/v1beta1/_virtual_imports/firestore_moved_proto/google/cloud/firestore_v1beta1/proto/firestore_pb2.py ``` I.e in same path as cc_proto_library. This all woks, but an annoying part is that to use the generated library in some other py_library, in needs to specify the "_virtual_imports/proto_target" path as its "includes" parameter (and I can't make it better than that). Another option would be to skeep the `_virtual_imports/<name_of_proto_library_target>` the suffix for the generated python stubs, which will make the path look like the following: ``` bazel-bin/google/firestore/v1beta1/google/cloud/firestore_v1beta1/proto/firestore_pb2.py ``` That will make using generated stubs simpler and cleaner (no need to specify imports argument), but it will make it inconsistent with the other rules (like cc_proto_library) and also more susseptible to naming conflicts (if there is already something under the generated path).
5 years ago
file
for file in ctx.attr.src.files.to_list()
if file.basename.endswith(suffix)
]
return struct(files = depset(out_files))
generate_objc_hdrs = rule(
attrs = {
"src": attr.label(
mandatory = True,
),
"gen_mode": attr.int(
default = _GENERATE_HDRS,
),
},
implementation = _group_objc_files_impl,
)
generate_objc_srcs = rule(
attrs = {
"src": attr.label(
mandatory = True,
),
"gen_mode": attr.int(
default = _GENERATE_SRCS,
),
},
implementation = _group_objc_files_impl,
)
generate_objc_non_arc_srcs = rule(
attrs = {
"src": attr.label(
mandatory = True,
),
"gen_mode": attr.int(
default = _GENERATE_NON_ARC_SRCS,
),
},
implementation = _group_objc_files_impl,
)