mirror of https://github.com/grpc/grpc.git
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.
227 lines
6.3 KiB
227 lines
6.3 KiB
"""Generates and compiles Python gRPC stubs from proto_library rules.""" |
|
|
|
load( |
|
"//bazel:protobuf.bzl", |
|
"get_include_protoc_args", |
|
"get_plugin_args", |
|
"get_proto_root", |
|
"proto_path_to_generated_filename", |
|
) |
|
|
|
_GENERATED_PROTO_FORMAT = "{}_pb2.py" |
|
_GENERATED_GRPC_PROTO_FORMAT = "{}_pb2_grpc.py" |
|
|
|
def _get_staged_proto_file(context, source_file): |
|
if source_file.dirname == context.label.package: |
|
return source_file |
|
else: |
|
copied_proto = context.actions.declare_file(source_file.basename) |
|
context.actions.run_shell( |
|
inputs = [source_file], |
|
outputs = [copied_proto], |
|
command = "cp {} {}".format(source_file.path, copied_proto.path), |
|
mnemonic = "CopySourceProto", |
|
) |
|
return copied_proto |
|
|
|
def _generate_py_impl(context): |
|
protos = [] |
|
for src in context.attr.deps: |
|
for file in src[ProtoInfo].direct_sources: |
|
protos.append(_get_staged_proto_file(context, file)) |
|
includes = [ |
|
file |
|
for src in context.attr.deps |
|
for file in src[ProtoInfo].transitive_imports.to_list() |
|
] |
|
proto_root = get_proto_root(context.label.workspace_root) |
|
out_files = [ |
|
context.actions.declare_file( |
|
proto_path_to_generated_filename( |
|
proto.basename, |
|
_GENERATED_PROTO_FORMAT, |
|
), |
|
) |
|
for proto in protos |
|
] |
|
|
|
tools = [context.executable._protoc] |
|
arguments = ([ |
|
"--python_out={}".format( |
|
context.genfiles_dir.path, |
|
), |
|
] + get_include_protoc_args(includes) + [ |
|
"--proto_path={}".format(context.genfiles_dir.path) |
|
for proto in protos |
|
]) |
|
for proto in protos: |
|
massaged_path = proto.path |
|
if massaged_path.startswith(context.genfiles_dir.path): |
|
massaged_path = proto.path[len(context.genfiles_dir.path) + 1:] |
|
arguments.append(massaged_path) |
|
|
|
context.actions.run( |
|
inputs = protos + includes, |
|
tools = tools, |
|
outputs = out_files, |
|
executable = context.executable._protoc, |
|
arguments = arguments, |
|
mnemonic = "ProtocInvocation", |
|
) |
|
return struct(files = depset(out_files)) |
|
|
|
_generate_pb2_src = rule( |
|
attrs = { |
|
"deps": attr.label_list( |
|
mandatory = True, |
|
allow_empty = False, |
|
providers = [ProtoInfo], |
|
), |
|
"_protoc": attr.label( |
|
default = Label("//external:protocol_compiler"), |
|
providers = ["files_to_run"], |
|
executable = True, |
|
cfg = "host", |
|
), |
|
}, |
|
implementation = _generate_py_impl, |
|
) |
|
|
|
def py_proto_library( |
|
name, |
|
srcs, |
|
**kwargs): |
|
"""Generate python code for a protobuf. |
|
|
|
Args: |
|
name: The name of the target. |
|
srcs: A list of proto_library dependencies. Must contain a single element. |
|
""" |
|
codegen_target = "_{}_codegen".format(name) |
|
if len(srcs) > 1: |
|
fail("Can only compile a single proto at a time.") |
|
|
|
|
|
_generate_pb2_src( |
|
name = codegen_target, |
|
deps = srcs, |
|
**kwargs |
|
) |
|
|
|
native.py_library( |
|
name = name, |
|
srcs = [":{}".format(codegen_target)], |
|
deps = ["@com_google_protobuf//:protobuf_python"], |
|
**kwargs |
|
) |
|
|
|
def _generate_pb2_grpc_src_impl(context): |
|
protos = [] |
|
for src in context.attr.deps: |
|
for file in src[ProtoInfo].direct_sources: |
|
protos.append(_get_staged_proto_file(context, file)) |
|
includes = [ |
|
file |
|
for src in context.attr.deps |
|
for file in src[ProtoInfo].transitive_imports.to_list() |
|
] |
|
proto_root = get_proto_root(context.label.workspace_root) |
|
out_files = [ |
|
context.actions.declare_file( |
|
proto_path_to_generated_filename( |
|
proto.basename, |
|
_GENERATED_GRPC_PROTO_FORMAT, |
|
), |
|
) |
|
for proto in protos |
|
] |
|
|
|
arguments = [] |
|
tools = [context.executable._protoc, context.executable._plugin] |
|
arguments += get_plugin_args( |
|
context.executable._plugin, |
|
[], |
|
context.genfiles_dir.path, |
|
False, |
|
) |
|
|
|
arguments += get_include_protoc_args(includes) |
|
arguments += [ |
|
"--proto_path={}".format(context.genfiles_dir.path) |
|
for proto in protos |
|
] |
|
for proto in protos: |
|
massaged_path = proto.path |
|
if massaged_path.startswith(context.genfiles_dir.path): |
|
massaged_path = proto.path[len(context.genfiles_dir.path) + 1:] |
|
arguments.append(massaged_path) |
|
|
|
context.actions.run( |
|
inputs = protos + includes, |
|
tools = tools, |
|
outputs = out_files, |
|
executable = context.executable._protoc, |
|
arguments = arguments, |
|
mnemonic = "ProtocInvocation", |
|
) |
|
return struct(files = depset(out_files)) |
|
|
|
|
|
_generate_pb2_grpc_src = rule( |
|
attrs = { |
|
"deps": attr.label_list( |
|
mandatory = True, |
|
allow_empty = False, |
|
providers = [ProtoInfo], |
|
), |
|
"_plugin": attr.label( |
|
executable = True, |
|
providers = ["files_to_run"], |
|
cfg = "host", |
|
default = Label("//src/compiler:grpc_python_plugin"), |
|
), |
|
"_protoc": attr.label( |
|
executable = True, |
|
providers = ["files_to_run"], |
|
cfg = "host", |
|
default = Label("//external:protocol_compiler"), |
|
), |
|
}, |
|
implementation = _generate_pb2_grpc_src_impl, |
|
) |
|
|
|
def py_grpc_library( |
|
name, |
|
srcs, |
|
deps, |
|
**kwargs): |
|
"""Generate python code for gRPC services defined in a protobuf. |
|
|
|
Args: |
|
name: The name of the target. |
|
srcs: (List of `labels`) a single proto_library target containing the |
|
schema of the service. |
|
deps: (List of `labels`) a single py_proto_library target for the |
|
proto_library in `srcs`. |
|
""" |
|
codegen_grpc_target = "_{}_grpc_codegen".format(name) |
|
if len(srcs) > 1: |
|
fail("Can only compile a single proto at a time.") |
|
|
|
if len(deps) > 1: |
|
fail("Deps must have length 1.") |
|
|
|
_generate_pb2_grpc_src( |
|
name = codegen_grpc_target, |
|
deps = srcs, |
|
**kwargs |
|
) |
|
|
|
native.py_library( |
|
name = name, |
|
srcs = [ |
|
":{}".format(codegen_grpc_target), |
|
], |
|
deps = [Label("//src/python/grpcio/grpc:grpcio")] + deps, |
|
**kwargs |
|
)
|
|
|