1"""Build rule for java_grpc_library.""" 2 3_JavaRpcToolchainInfo = provider( 4 fields = [ 5 "java_toolchain", 6 "plugin", 7 "plugin_arg", 8 "protoc", 9 "runtime", 10 ], 11) 12 13def _java_rpc_toolchain_impl(ctx): 14 return [ 15 _JavaRpcToolchainInfo( 16 java_toolchain = ctx.attr._java_toolchain, 17 plugin = ctx.executable.plugin, 18 plugin_arg = ctx.attr.plugin_arg, 19 protoc = ctx.executable._protoc, 20 runtime = ctx.attr.runtime, 21 ), 22 platform_common.ToolchainInfo(), # Magic for b/78647825 23 ] 24 25java_rpc_toolchain = rule( 26 attrs = { 27 # This attribute has a "magic" name recognized by the native DexArchiveAspect (b/78647825). 28 "runtime": attr.label_list( 29 cfg = "target", 30 providers = [JavaInfo], 31 ), 32 "plugin": attr.label( 33 cfg = "exec", 34 executable = True, 35 ), 36 "plugin_arg": attr.string(), 37 "_protoc": attr.label( 38 cfg = "exec", 39 default = Label("@com_google_protobuf//:protoc"), 40 executable = True, 41 ), 42 "_java_toolchain": attr.label( 43 default = Label("@bazel_tools//tools/jdk:current_java_toolchain"), 44 ), 45 }, 46 provides = [ 47 _JavaRpcToolchainInfo, 48 platform_common.ToolchainInfo, 49 ], 50 implementation = _java_rpc_toolchain_impl, 51) 52 53# "repository" here is for Bazel builds that span multiple WORKSPACES. 54def _path_ignoring_repository(f): 55 # Bazel creates a _virtual_imports directory in case the .proto source files 56 # need to be accessed at a path that's different from their source path: 57 # https://github.com/bazelbuild/bazel/blob/0.27.1/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCommon.java#L289 58 # 59 # In that case, the import path of the .proto file is the path relative to 60 # the virtual imports directory of the rule in question. 61 virtual_imports = "/_virtual_imports/" 62 if virtual_imports in f.path: 63 return f.path.split(virtual_imports)[1].split("/", 1)[1] 64 elif len(f.owner.workspace_root) == 0: 65 # |f| is in the main repository 66 return f.short_path 67 else: 68 # If |f| is a generated file, it will have "bazel-out/*/genfiles" prefix 69 # before "external/workspace", so we need to add the starting index of "external/workspace" 70 return f.path[f.path.find(f.owner.workspace_root) + len(f.owner.workspace_root) + 1:] 71 72def _java_rpc_library_impl(ctx): 73 if len(ctx.attr.srcs) != 1: 74 fail("Exactly one src value supported", "srcs") 75 if ctx.attr.srcs[0].label.package != ctx.label.package: 76 print(("in srcs attribute of {0}: Proto source with label {1} should be in " + 77 "same package as consuming rule").format(ctx.label, ctx.attr.srcs[0].label)) 78 79 toolchain = ctx.attr._toolchain[_JavaRpcToolchainInfo] 80 srcs = ctx.attr.srcs[0][ProtoInfo].direct_sources 81 descriptor_set_in = ctx.attr.srcs[0][ProtoInfo].transitive_descriptor_sets 82 83 srcjar = ctx.actions.declare_file("%s-proto-gensrc.jar" % ctx.label.name) 84 85 args = ctx.actions.args() 86 args.add(toolchain.plugin, format = "--plugin=protoc-gen-rpc-plugin=%s") 87 args.add("--rpc-plugin_out={0}:{1}".format(toolchain.plugin_arg, srcjar.path)) 88 args.add_joined("--descriptor_set_in", descriptor_set_in, join_with = ctx.configuration.host_path_separator) 89 args.add_all(srcs, map_each = _path_ignoring_repository) 90 91 ctx.actions.run( 92 inputs = depset([toolchain.plugin] + srcs, transitive = [descriptor_set_in]), 93 outputs = [srcjar], 94 executable = toolchain.protoc, 95 arguments = [args], 96 use_default_shell_env = True, 97 ) 98 99 deps_java_info = java_common.merge([dep[JavaInfo] for dep in ctx.attr.deps]) 100 101 java_info = java_common.compile( 102 ctx, 103 java_toolchain = toolchain.java_toolchain[java_common.JavaToolchainInfo], 104 source_jars = [srcjar], 105 output = ctx.outputs.jar, 106 output_source_jar = ctx.outputs.srcjar, 107 deps = [ 108 java_common.make_non_strict(deps_java_info), 109 ] + [dep[JavaInfo] for dep in toolchain.runtime], 110 ) 111 112 return [java_info] 113 114_java_grpc_library = rule( 115 attrs = { 116 "srcs": attr.label_list( 117 mandatory = True, 118 allow_empty = False, 119 providers = [ProtoInfo], 120 ), 121 "deps": attr.label_list( 122 mandatory = True, 123 allow_empty = False, 124 providers = [JavaInfo], 125 ), 126 "_toolchain": attr.label( 127 default = Label("//compiler:java_grpc_library_toolchain"), 128 ), 129 }, 130 toolchains = ["@bazel_tools//tools/jdk:toolchain_type"], 131 fragments = ["java"], 132 outputs = { 133 "jar": "lib%{name}.jar", 134 "srcjar": "lib%{name}-src.jar", 135 }, 136 provides = [JavaInfo], 137 implementation = _java_rpc_library_impl, 138) 139 140_java_lite_grpc_library = rule( 141 attrs = { 142 "srcs": attr.label_list( 143 mandatory = True, 144 allow_empty = False, 145 providers = [ProtoInfo], 146 ), 147 "deps": attr.label_list( 148 mandatory = True, 149 allow_empty = False, 150 providers = [JavaInfo], 151 ), 152 # This attribute has a "magic" name recognized by the native DexArchiveAspect (b/78647825). 153 "_toolchain": attr.label( 154 default = Label("//compiler:java_lite_grpc_library_toolchain"), 155 ), 156 }, 157 toolchains = ["@bazel_tools//tools/jdk:toolchain_type"], 158 fragments = ["java"], 159 outputs = { 160 "jar": "lib%{name}.jar", 161 "srcjar": "lib%{name}-src.jar", 162 }, 163 provides = [JavaInfo], 164 implementation = _java_rpc_library_impl, 165) 166 167def java_grpc_library( 168 name, 169 srcs, 170 deps, 171 flavor = None, 172 **kwargs): 173 """Generates gRPC Java code for services in a `proto_library`. 174 175 This rule only generates code for services; it does not generate code for 176 messages. You will need a separate java_proto_library or 177 java_lite_proto_library rule. 178 179 Args: 180 name: A unique name for this rule. 181 srcs: (List of `labels`) a single proto_library target that contains the 182 schema of the service. 183 deps: (List of `labels`) a single java_proto_library or 184 java_lite_proto_library target for the proto_library in srcs. 185 flavor: (str) "normal" (default) for normal proto runtime. "lite" 186 for the lite runtime. 187 **kwargs: Other common attributes 188 """ 189 190 if len(deps) > 1: 191 print("Multiple values in 'deps' is deprecated in " + name) 192 193 if flavor == None or flavor == "normal": 194 _java_grpc_library( 195 name = name, 196 srcs = srcs, 197 deps = deps, 198 **kwargs 199 ) 200 elif flavor == "lite": 201 _java_lite_grpc_library( 202 name = name, 203 srcs = srcs, 204 deps = deps, 205 **kwargs 206 ) 207 else: 208 fail("Flavor must be normal or lite") 209