Add gRPC's cc_grpc_library to //third_party/grpc/bazel

This adds a simplified version of gRPC's cc_grpc_library to
//third_party/grpc/bazel. I intend to replace the hacky cc_grpc_library
implemented in //tools/build_rules:genproto.bzl and used by
//src/main/protobuf:command_server_cc_proto with this one.

Aside from a general cleanup, this version of the macro supports proto
files/rules with dependencies. Future work with fine-grained failure
reporting will add dependencies to command_server.proto.

The added files, all BUILD/bzl, are taken from gRPC's v1.26.0
(commithash 'de893acb', see https://github.com/grpc/grpc/tree/v1.26.0).
Because these resources are independent of Bazel's other imports from
gRPC, there are no conflicts with the current imported version of gRPC's
C++ sources.

This includes a patch file, bazel.patch, which adapts gRPC's BUILD/bzl
sources for use by Bazel.

This simplifies the cc_grpc_library macro and its deps:
* removes cc_grpc_library's grpc_only parameter (now always true)
* removes its proto_only, well_known_protos parameters (now always
    false)
* removes its use_external parameter (it was previously unused)
* adds to it an extra_cc_library_kwargs parameter (forwarded to its
    generated cc_library rule)
* removes "well_known_proto" functionality from generate_cc.bzl and
    protobuf.bzl
* changes generate_cc's _protoc attribute to protoc
* sets cc_grpc_library's generate_cc call's plugin and protoc arguments
    to Bazel's targets ("//third_party/grpc:cpp_plugin" and
    "//third_party/protobuf:protoc", respectively)
* relativizes load statements throughout
* adds "srcs" filegroup to the package's BUILD file and includes it in
    //third_party/grpc:srcs

This also deletes the obsolete grpc.patch file.
diff --git a/third_party/grpc/BUILD b/third_party/grpc/BUILD
index 974b854..a7dbc1e 100644
--- a/third_party/grpc/BUILD
+++ b/third_party/grpc/BUILD
@@ -33,7 +33,9 @@
 
 filegroup(
     name = "srcs",
-    srcs = glob(["**"]),
+    srcs = glob(["**"]) + [
+        "//third_party/grpc/bazel:srcs",
+    ],
 )
 
 config_setting(
diff --git a/third_party/grpc/README.bazel.md b/third_party/grpc/README.bazel.md
index 812dd7d..650bd0e 100644
--- a/third_party/grpc/README.bazel.md
+++ b/third_party/grpc/README.bazel.md
@@ -8,10 +8,19 @@
 6. `rm -rf third_party/grpc/src/core/tsi/test_creds`
 7. Update BUILD files by copying the rules from the BUILD file of gRPC;
    fix macros in third_party/grpc/build_defs.bzl if necessary
-8. Apply local patches if necessary: `patch -p3 < netinet_tcp_h.patch`,
-   `patch -p1 < grpc-gettid.patch`
+8. In the `third_party/grpc` directory, apply local patches if necessary:
+   `patch -p3 < netinet_tcp_h.patch`, `patch -p1 < grpc-gettid.patch`
 9. Update //third_party/nanopb if necessary
 
+# How to update the BUILD/bzl sources of gRPC:
+
+1. Unless you've done so while updating C++ sources,
+   `git clone http://github.com/grpc/grpc.git` in a convenient directory
+2. `git checkout <tag>` (current is `v1.26.0`, commithash `de893acb`)
+3. `mkdir -p third_party/grpc/bazel`
+4. `cp <gRPC git tree>/bazel/{BUILD,cc_grpc_library.bzl,generate_cc.bzl,protobuf.bzl} third_party/grpc/bazel`
+5. In the `third_party/grpc` directory, apply local patches:
+   `patch -p3 < bazel.patch`
 
 # How to update the Java plugin:
 
diff --git a/third_party/grpc/bazel.patch b/third_party/grpc/bazel.patch
new file mode 100644
index 0000000..3fc089d
--- /dev/null
+++ b/third_party/grpc/bazel.patch
@@ -0,0 +1,302 @@
+From 6eb4a396945bbe89831ce1d205106c1348f376e3 Mon Sep 17 00:00:00 2001
+From: Mark Schaller <mschaller@google.com>
+Date: Thu, 9 Jan 2020 19:50:57 -0500
+Subject: [PATCH] Adapt gRPC bazel files for use in Bazel
+
+This simplifies the cc_grpc_library macro and its deps:
+* removes cc_grpc_library's grpc_only parameter (now always true)
+* removes its proto_only, well_known_protos parameters (now always
+    false)
+* removes its use_external parameter (it was previously unused)
+* adds to it an extra_cc_library_kwargs parameter (forwarded to its
+    generated cc_library rule)
+* removes "well_known_proto" functionality from generate_cc.bzl and
+    protobuf.bzl
+* changes generate_cc's _protoc attribute to protoc
+* sets cc_grpc_library's generate_cc call's plugin and protoc arguments
+    to Bazel's targets ("//third_party/grpc:cpp_plugin" and
+    "//third_party/protobuf:protoc", respectively)
+* relativizes load statements throughout
+* adds "srcs" filegroup to the package's BUILD file and includes it in
+    //third_party/grpc:srcs
+    
+---
+ third_party/grpc/bazel/BUILD               |   5 +
+ third_party/grpc/bazel/cc_grpc_library.bzl | 127 +++++++--------------
+ third_party/grpc/bazel/generate_cc.bzl     |  39 +------
+ third_party/grpc/bazel/protobuf.bzl        |  16 ---
+ 4 files changed, 51 insertions(+), 136 deletions(-)
+
+diff --git a/third_party/grpc/bazel/BUILD b/third_party/grpc/bazel/BUILD
+index c3c82c9c0c..6f451a6f24 100644
+--- a/third_party/grpc/bazel/BUILD
++++ b/third_party/grpc/bazel/BUILD
+@@ -17,3 +17,8 @@ licenses(["notice"])  # Apache v2
+ package(default_visibility = ["//:__subpackages__"])
+ 
+ load(":cc_grpc_library.bzl", "cc_grpc_library")
++
++filegroup(
++    name = "srcs",
++    srcs = glob(["**"]),
++)
+diff --git a/third_party/grpc/bazel/cc_grpc_library.bzl b/third_party/grpc/bazel/cc_grpc_library.bzl
+index dea493eaf2..0470a294fc 100644
+--- a/third_party/grpc/bazel/cc_grpc_library.bzl
++++ b/third_party/grpc/bazel/cc_grpc_library.bzl
+@@ -1,105 +1,58 @@
+ """Generates and compiles C++ grpc stubs from proto_library rules."""
+ 
+-load("//bazel:generate_cc.bzl", "generate_cc")
+-load("//bazel:protobuf.bzl", "well_known_proto_libs")
++load(":generate_cc.bzl", "generate_cc")
+ 
++# Simplified version of gRPC upstream's cc_grpc_library.
+ def cc_grpc_library(
+         name,
+         srcs,
+         deps,
+-        proto_only = False,
+-        well_known_protos = False,
+         generate_mocks = False,
+-        use_external = False,
+-        grpc_only = False,
++        extra_cc_library_kwargs = {},
+         **kwargs):
+-    """Generates C++ grpc classes for services defined in a proto file.
++    """Generates C++ grpc classes for services defined in proto_library rules.
+ 
+-    If grpc_only is True, this rule is compatible with proto_library and
+-    cc_proto_library native rules such that it expects proto_library target
+-    as srcs argument and generates only grpc library classes, expecting
+-    protobuf messages classes library (cc_proto_library target) to be passed in
+-    deps argument. By default grpc_only is False which makes this rule to behave
+-    in a backwards-compatible mode (trying to generate both proto and grpc
+-    classes).
++    This rule expects a singleton list containing a proto_library target for its
++    srcs argument, and expects a list (of arbitrary size) of cc_proto_library
++    targets for its deps argument.
++
++    It generates only grpc library classes.
+ 
+     Assumes the generated classes will be used in cc_api_version = 2.
+ 
+     Args:
+         name (str): Name of rule.
+-        srcs (list): A single .proto file which contains services definitions,
+-          or if grpc_only parameter is True, a single proto_library which
+-          contains services descriptors.
+-        deps (list): A list of C++ proto_library (or cc_proto_library) which
+-          provides the compiled code of any message that the services depend on.
+-        proto_only (bool): If True, create only C++ proto classes library,
+-          avoid creating C++ grpc classes library (expect it in deps).
+-          Deprecated, use native cc_proto_library instead. False by default.
+-        well_known_protos (bool): Should this library additionally depend on
+-          well known protos. Deprecated, the well known protos should be
+-          specified as explicit dependencies of the proto_library target
+-          (passed in srcs parameter) instead. False by default.
++        srcs (list): A single proto_library which contains services descriptors.
++        deps (list): A list of cc_proto_library targets which
++          provide the compiled code of any message that the services depend on.
+         generate_mocks (bool): when True, Google Mock code for client stub is
+           generated. False by default.
+-        use_external (bool): Not used.
+-        grpc_only (bool): if True, generate only grpc library, expecting
+-          protobuf messages library (cc_proto_library target) to be passed as
+-          deps. False by default (will become True by default eventually).
+-        **kwargs: rest of arguments, e.g., compatible_with and visibility
++        extra_cc_library_kwargs (map): extra arguments to pass to the cc_library
++          rule
++        **kwargs: extra arguments to pass to all rules instantiated by this
++          macro. Must be common to all build rules. See
++          https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes
+     """
+-    if len(srcs) > 1:
+-        fail("Only one srcs value supported", "srcs")
+-    if grpc_only and proto_only:
+-        fail("A mutualy exclusive configuration is specified: grpc_only = True and proto_only = True")
+-
+-    extra_deps = []
+-    proto_targets = []
+-
+-    if not grpc_only:
+-        proto_target = "_" + name + "_only"
+-        cc_proto_target = name if proto_only else "_" + name + "_cc_proto"
+-
+-        proto_deps = ["_" + dep + "_only" for dep in deps if dep.find(":") == -1]
+-        proto_deps += [dep.split(":")[0] + ":" + "_" + dep.split(":")[1] + "_only" for dep in deps if dep.find(":") != -1]
+-        if well_known_protos:
+-            proto_deps += well_known_proto_libs()
+-
+-        native.proto_library(
+-            name = proto_target,
+-            srcs = srcs,
+-            deps = proto_deps,
+-            **kwargs
+-        )
+-
+-        native.cc_proto_library(
+-            name = cc_proto_target,
+-            deps = [":" + proto_target],
+-            **kwargs
+-        )
+-        extra_deps.append(":" + cc_proto_target)
+-        proto_targets.append(proto_target)
+-    else:
+-        if not srcs:
+-            fail("srcs cannot be empty", "srcs")
+-        proto_targets += srcs
+-
+-    if not proto_only:
+-        codegen_grpc_target = "_" + name + "_grpc_codegen"
+-        generate_cc(
+-            name = codegen_grpc_target,
+-            srcs = proto_targets,
+-            plugin = "@com_github_grpc_grpc//src/compiler:grpc_cpp_plugin",
+-            well_known_protos = well_known_protos,
+-            generate_mocks = generate_mocks,
+-            **kwargs
+-        )
+-
+-        native.cc_library(
+-            name = name,
+-            srcs = [":" + codegen_grpc_target],
+-            hdrs = [":" + codegen_grpc_target],
+-            deps = deps +
+-                   extra_deps +
+-                   ["@com_github_grpc_grpc//:grpc++_codegen_proto"],
+-            **kwargs
+-        )
++    if len(srcs) != 1:
++        fail("The srcs attribute must be a singleton list but was " + str(srcs),
++             "srcs")
++
++    codegen_grpc_target = "_" + name + "_grpc_codegen"
++    generate_cc(
++        name = codegen_grpc_target,
++        srcs = srcs,
++        plugin = "//third_party/grpc:cpp_plugin",
++        generate_mocks = generate_mocks,
++        protoc = "//third_party/protobuf:protoc",
++        **kwargs
++    )
++
++    cc_library_kwargs = dict(**extra_cc_library_kwargs)
++    cc_library_kwargs.update(**kwargs)
++    native.cc_library(
++        name = name,
++        srcs = [":" + codegen_grpc_target],
++        hdrs = [":" + codegen_grpc_target],
++        deps = deps + ["//third_party/grpc:grpc++_codegen_proto"],
++        **cc_library_kwargs
++    )
+diff --git a/third_party/grpc/bazel/generate_cc.bzl b/third_party/grpc/bazel/generate_cc.bzl
+index 484959ebb7..38a5b460f9 100644
+--- a/third_party/grpc/bazel/generate_cc.bzl
++++ b/third_party/grpc/bazel/generate_cc.bzl
+@@ -5,7 +5,7 @@ directly.
+ """
+ 
+ load(
+-    "//bazel:protobuf.bzl",
++    ":protobuf.bzl",
+     "get_include_directory",
+     "get_plugin_args",
+     "get_proto_root",
+@@ -117,34 +117,17 @@ def generate_cc_impl(ctx):
+     arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)]
+     arguments += [_get_srcs_file_path(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.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.to_list()
+-            ]
+-
+     ctx.actions.run(
+-        inputs = protos + includes + well_known_proto_files,
++        inputs = protos + includes,
+         tools = tools,
+         outputs = out_files,
+-        executable = ctx.executable._protoc,
++        executable = ctx.executable.protoc,
+         arguments = arguments,
+     )
+ 
+     return struct(files = depset(out_files))
+ 
+-_generate_cc = rule(
++generate_cc = rule(
+     attrs = {
+         "srcs": attr.label_list(
+             mandatory = True,
+@@ -160,13 +143,12 @@ _generate_cc = rule(
+             mandatory = False,
+             allow_empty = True,
+         ),
+-        "well_known_protos": attr.label(mandatory = False),
+         "generate_mocks": attr.bool(
+             default = False,
+             mandatory = False,
+         ),
+-        "_protoc": attr.label(
+-            default = Label("//external:protocol_compiler"),
++        "protoc": attr.label(
++            mandatory = True,
+             executable = True,
+             cfg = "host",
+         ),
+@@ -175,12 +157,3 @@ _generate_cc = rule(
+     output_to_genfiles = True,
+     implementation = generate_cc_impl,
+ )
+-
+-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)
+diff --git a/third_party/grpc/bazel/protobuf.bzl b/third_party/grpc/bazel/protobuf.bzl
+index 7af27a8b30..0d6a4135f0 100644
+--- a/third_party/grpc/bazel/protobuf.bzl
++++ b/third_party/grpc/bazel/protobuf.bzl
+@@ -3,22 +3,6 @@
+ _PROTO_EXTENSION = ".proto"
+ _VIRTUAL_IMPORTS = "/_virtual_imports/"
+ 
+-def well_known_proto_libs():
+-    return [
+-        "@com_google_protobuf//:any_proto",
+-        "@com_google_protobuf//:api_proto",
+-        "@com_google_protobuf//:compiler_plugin_proto",
+-        "@com_google_protobuf//:descriptor_proto",
+-        "@com_google_protobuf//:duration_proto",
+-        "@com_google_protobuf//:empty_proto",
+-        "@com_google_protobuf//:field_mask_proto",
+-        "@com_google_protobuf//:source_context_proto",
+-        "@com_google_protobuf//:struct_proto",
+-        "@com_google_protobuf//:timestamp_proto",
+-        "@com_google_protobuf//:type_proto",
+-        "@com_google_protobuf//:wrappers_proto",
+-    ]
+-
+ def get_proto_root(workspace_root):
+     """Gets the root protobuf directory.
+ 
+-- 
+2.25.0.rc1.283.g88dfdc4193-goog
+
diff --git a/third_party/grpc/bazel/BUILD b/third_party/grpc/bazel/BUILD
new file mode 100644
index 0000000..6f451a6
--- /dev/null
+++ b/third_party/grpc/bazel/BUILD
@@ -0,0 +1,24 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache v2
+
+package(default_visibility = ["//:__subpackages__"])
+
+load(":cc_grpc_library.bzl", "cc_grpc_library")
+
+filegroup(
+    name = "srcs",
+    srcs = glob(["**"]),
+)
diff --git a/third_party/grpc/bazel/cc_grpc_library.bzl b/third_party/grpc/bazel/cc_grpc_library.bzl
new file mode 100644
index 0000000..0470a29
--- /dev/null
+++ b/third_party/grpc/bazel/cc_grpc_library.bzl
@@ -0,0 +1,58 @@
+"""Generates and compiles C++ grpc stubs from proto_library rules."""
+
+load(":generate_cc.bzl", "generate_cc")
+
+# Simplified version of gRPC upstream's cc_grpc_library.
+def cc_grpc_library(
+        name,
+        srcs,
+        deps,
+        generate_mocks = False,
+        extra_cc_library_kwargs = {},
+        **kwargs):
+    """Generates C++ grpc classes for services defined in proto_library rules.
+
+    This rule expects a singleton list containing a proto_library target for its
+    srcs argument, and expects a list (of arbitrary size) of cc_proto_library
+    targets for its deps argument.
+
+    It generates only grpc library classes.
+
+    Assumes the generated classes will be used in cc_api_version = 2.
+
+    Args:
+        name (str): Name of rule.
+        srcs (list): A single proto_library which contains services descriptors.
+        deps (list): A list of cc_proto_library targets which
+          provide the compiled code of any message that the services depend on.
+        generate_mocks (bool): when True, Google Mock code for client stub is
+          generated. False by default.
+        extra_cc_library_kwargs (map): extra arguments to pass to the cc_library
+          rule
+        **kwargs: extra arguments to pass to all rules instantiated by this
+          macro. Must be common to all build rules. See
+          https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes
+    """
+    if len(srcs) != 1:
+        fail("The srcs attribute must be a singleton list but was " + str(srcs),
+             "srcs")
+
+    codegen_grpc_target = "_" + name + "_grpc_codegen"
+    generate_cc(
+        name = codegen_grpc_target,
+        srcs = srcs,
+        plugin = "//third_party/grpc:cpp_plugin",
+        generate_mocks = generate_mocks,
+        protoc = "//third_party/protobuf:protoc",
+        **kwargs
+    )
+
+    cc_library_kwargs = dict(**extra_cc_library_kwargs)
+    cc_library_kwargs.update(**kwargs)
+    native.cc_library(
+        name = name,
+        srcs = [":" + codegen_grpc_target],
+        hdrs = [":" + codegen_grpc_target],
+        deps = deps + ["//third_party/grpc:grpc++_codegen_proto"],
+        **cc_library_kwargs
+    )
diff --git a/third_party/grpc/bazel/generate_cc.bzl b/third_party/grpc/bazel/generate_cc.bzl
new file mode 100644
index 0000000..38a5b46
--- /dev/null
+++ b/third_party/grpc/bazel/generate_cc.bzl
@@ -0,0 +1,159 @@
+"""Generates C++ grpc stubs from proto_library rules.
+
+This is an internal rule used by cc_grpc_library, and shouldn't be used
+directly.
+"""
+
+load(
+    ":protobuf.bzl",
+    "get_include_directory",
+    "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"
+
+def _strip_package_from_path(label_package, file):
+    prefix_len = 0
+    if not file.is_source and file.path.startswith(file.root.path):
+        prefix_len = len(file.root.path) + 1
+
+    path = file.path
+    if len(label_package) == 0:
+        return path
+    if not path.startswith(label_package + "/", prefix_len):
+        fail("'{}' does not lie within '{}'.".format(path, label_package))
+    return path[prefix_len + len(label_package + "/"):]
+
+def _get_srcs_file_path(file):
+    if not file.is_source and file.path.startswith(file.root.path):
+        return file.path[len(file.root.path) + 1:]
+    return file.path
+
+def _join_directories(directories):
+    massaged_directories = [directory for directory in directories if len(directory) != 0]
+    return "/".join(massaged_directories)
+
+def generate_cc_impl(ctx):
+    """Implementation of the generate_cc rule."""
+    protos = [f for src in ctx.attr.srcs for f in src[ProtoInfo].check_deps_sources.to_list()]
+    includes = [
+        f
+        for src in ctx.attr.srcs
+        for f in src[ProtoInfo].transitive_imports.to_list()
+    ]
+    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),
+                _GRPC_PROTO_HEADER_FMT,
+            )
+            for proto in protos
+        ]
+        outs += [
+            proto_path_to_generated_filename(
+                _strip_package_from_path(label_package, proto),
+                _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),
+                    _GRPC_PROTO_MOCK_HEADER_FMT,
+                )
+                for proto in protos
+            ]
+    else:
+        outs += [
+            proto_path_to_generated_filename(
+                _strip_package_from_path(label_package, proto),
+                _PROTO_HEADER_FMT,
+            )
+            for proto in protos
+        ]
+        outs += [
+            proto_path_to_generated_filename(
+                _strip_package_from_path(label_package, proto),
+                _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)
+
+    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:
+        arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
+        tools = []
+
+    arguments += [
+        "--proto_path={}".format(get_include_directory(i))
+        for i in includes
+    ]
+
+    # 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 += [_get_srcs_file_path(proto) for proto in protos]
+
+    ctx.actions.run(
+        inputs = protos + includes,
+        tools = tools,
+        outputs = out_files,
+        executable = ctx.executable.protoc,
+        arguments = arguments,
+    )
+
+    return struct(files = depset(out_files))
+
+generate_cc = rule(
+    attrs = {
+        "srcs": attr.label_list(
+            mandatory = True,
+            allow_empty = False,
+            providers = [ProtoInfo],
+        ),
+        "plugin": attr.label(
+            executable = True,
+            providers = ["files_to_run"],
+            cfg = "host",
+        ),
+        "flags": attr.string_list(
+            mandatory = False,
+            allow_empty = True,
+        ),
+        "generate_mocks": attr.bool(
+            default = False,
+            mandatory = False,
+        ),
+        "protoc": attr.label(
+            mandatory = True,
+            executable = True,
+            cfg = "host",
+        ),
+    },
+    # We generate .h files, so we need to output to genfiles.
+    output_to_genfiles = True,
+    implementation = generate_cc_impl,
+)
diff --git a/third_party/grpc/bazel/protobuf.bzl b/third_party/grpc/bazel/protobuf.bzl
new file mode 100644
index 0000000..0d6a413
--- /dev/null
+++ b/third_party/grpc/bazel/protobuf.bzl
@@ -0,0 +1,230 @@
+"""Utility functions for generating protobuf code."""
+
+_PROTO_EXTENSION = ".proto"
+_VIRTUAL_IMPORTS = "/_virtual_imports/"
+
+def get_proto_root(workspace_root):
+    """Gets the root protobuf directory.
+
+    Args:
+      workspace_root: context.label.workspace_root
+
+    Returns:
+      The directory relative to which generated include paths should be.
+    """
+    if workspace_root:
+        return "/{}".format(workspace_root)
+    else:
+        return ""
+
+def _strip_proto_extension(proto_filename):
+    if not proto_filename.endswith(_PROTO_EXTENSION):
+        fail('"{}" does not end with "{}"'.format(
+            proto_filename,
+            _PROTO_EXTENSION,
+        ))
+    return proto_filename[:-len(_PROTO_EXTENSION)]
+
+def proto_path_to_generated_filename(proto_path, fmt_str):
+    """Calculates the name of a generated file for a protobuf path.
+
+    For example, "examples/protos/helloworld.proto" might map to
+      "helloworld.pb.h".
+
+    Args:
+      proto_path: The path to the .proto file.
+      fmt_str: A format string used to calculate the generated filename. For
+        example, "{}.pb.h" might be used to calculate a C++ header filename.
+
+    Returns:
+      The generated filename.
+    """
+    return fmt_str.format(_strip_proto_extension(proto_path))
+
+def get_include_directory(source_file):
+    """Returns the include directory path for the source_file. I.e. all of the
+    include statements within the given source_file are calculated relative to
+    the directory returned by this method.
+
+    The returned directory path can be used as the "--proto_path=" argument
+    value.
+
+    Args:
+      source_file: A proto file.
+
+    Returns:
+      The include directory path for the source_file.
+    """
+    directory = source_file.path
+    prefix_len = 0
+
+    if is_in_virtual_imports(source_file):
+        root, relative = source_file.path.split(_VIRTUAL_IMPORTS, 2)
+        result = root + _VIRTUAL_IMPORTS + relative.split("/", 1)[0]
+        return result
+
+    if not source_file.is_source and directory.startswith(source_file.root.path):
+        prefix_len = len(source_file.root.path) + 1
+
+    if directory.startswith("external", prefix_len):
+        external_separator = directory.find("/", prefix_len)
+        repository_separator = directory.find("/", external_separator + 1)
+        return directory[:repository_separator]
+    else:
+        return source_file.root.path if source_file.root.path else "."
+
+def get_plugin_args(
+        plugin,
+        flags,
+        dir_out,
+        generate_mocks,
+        plugin_name = "PLUGIN"):
+    """Returns arguments configuring protoc to use a plugin for a language.
+
+    Args:
+      plugin: An executable file to run as the protoc plugin.
+      flags: The plugin flags to be passed to protoc.
+      dir_out: The output directory for the plugin.
+      generate_mocks: A bool indicating whether to generate mocks.
+      plugin_name: A name of the plugin, it is required to be unique when there
+      are more than one plugin used in a single protoc command.
+    Returns:
+      A list of protoc arguments configuring the plugin.
+    """
+    augmented_flags = list(flags)
+    if generate_mocks:
+        augmented_flags.append("generate_mock_code=true")
+
+    augmented_dir_out = dir_out
+    if augmented_flags:
+        augmented_dir_out = ",".join(augmented_flags) + ":" + dir_out
+
+    return [
+        "--plugin=protoc-gen-{plugin_name}={plugin_path}".format(
+            plugin_name = plugin_name,
+            plugin_path = plugin.path,
+        ),
+        "--{plugin_name}_out={dir_out}".format(
+            plugin_name = plugin_name,
+            dir_out = augmented_dir_out,
+        ),
+    ]
+
+def _get_staged_proto_file(context, source_file):
+    if source_file.dirname == context.label.package or \
+       is_in_virtual_imports(source_file):
+        # Current target and source_file are in same package
+        return source_file
+    else:
+        # Current target and source_file are in different packages (most
+        # probably even in different repositories)
+        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 protos_from_context(context):
+    """Copies proto files to the appropriate location.
+
+    Args:
+      context: The ctx object for the rule.
+
+    Returns:
+      A list of the protos.
+    """
+    protos = []
+    for src in context.attr.deps:
+        for file in src[ProtoInfo].direct_sources:
+            protos.append(_get_staged_proto_file(context, file))
+    return protos
+
+def includes_from_deps(deps):
+    """Get includes from rule dependencies."""
+    return [
+        file
+        for src in deps
+        for file in src[ProtoInfo].transitive_imports.to_list()
+    ]
+
+def get_proto_arguments(protos, genfiles_dir_path):
+    """Get the protoc arguments specifying which protos to compile."""
+    arguments = []
+    for proto in protos:
+        strip_prefix_len = 0
+        if is_in_virtual_imports(proto):
+            incl_directory = get_include_directory(proto)
+            if proto.path.startswith(incl_directory):
+                strip_prefix_len = len(incl_directory) + 1
+        elif proto.path.startswith(genfiles_dir_path):
+            strip_prefix_len = len(genfiles_dir_path) + 1
+
+        arguments.append(proto.path[strip_prefix_len:])
+
+    return arguments
+
+def declare_out_files(protos, context, generated_file_format):
+    """Declares and returns the files to be generated."""
+
+    out_file_paths = []
+    for proto in protos:
+        if not is_in_virtual_imports(proto):
+            out_file_paths.append(proto.basename)
+        else:
+            path = proto.path[proto.path.index(_VIRTUAL_IMPORTS) + 1:]
+            out_file_paths.append(path)
+
+    return [
+        context.actions.declare_file(
+            proto_path_to_generated_filename(
+                out_file_path,
+                generated_file_format,
+            ),
+        )
+        for out_file_path in out_file_paths
+    ]
+
+def get_out_dir(protos, context):
+    """ Returns the calculated value for --<lang>_out= protoc argument based on
+    the input source proto files and current context.
+
+    Args:
+        protos: A list of protos to be used as source files in protoc command
+        context: A ctx object for the rule.
+    Returns:
+        The value of --<lang>_out= argument.
+    """
+    at_least_one_virtual = 0
+    for proto in protos:
+        if is_in_virtual_imports(proto):
+            at_least_one_virtual = True
+        elif at_least_one_virtual:
+            fail("Proto sources must be either all virtual imports or all real")
+    if at_least_one_virtual:
+        out_dir = get_include_directory(protos[0])
+        ws_root = protos[0].owner.workspace_root
+        if ws_root and out_dir.find(ws_root) >= 0:
+            out_dir = "".join(out_dir.rsplit(ws_root, 1))
+        return struct(
+            path = out_dir,
+            import_path = out_dir[out_dir.find(_VIRTUAL_IMPORTS) + 1:],
+        )
+    return struct(path = context.genfiles_dir.path, import_path = None)
+
+def is_in_virtual_imports(source_file, virtual_folder = _VIRTUAL_IMPORTS):
+    """Determines if source_file is virtual (is placed in _virtual_imports
+    subdirectory). The output of all proto_library targets which use
+    import_prefix  and/or strip_import_prefix arguments is placed under
+    _virtual_imports directory.
+
+    Args:
+        source_file: A proto file.
+        virtual_folder: The virtual folder name (is set to "_virtual_imports"
+            by default)
+    Returns:
+        True if source_file is located under _virtual_imports, False otherwise.
+    """
+    return not source_file.is_source and virtual_folder in source_file.path
diff --git a/third_party/grpc/grpc.patch b/third_party/grpc/grpc.patch
deleted file mode 100644
index 0ce4923..0000000
--- a/third_party/grpc/grpc.patch
+++ /dev/null
@@ -1,102 +0,0 @@
-diff --git a/tools/build_rules/genproto.bzl b/tools/build_rules/genproto.bzl
-index 62284a3..bc76cd1 100644
---- a/tools/build_rules/genproto.bzl
-+++ b/tools/build_rules/genproto.bzl
-@@ -25,6 +25,8 @@ def gensrcjar_impl(ctx):
-         "JAR='%s'" % ctx.executable._jar.path,
-         "OUTPUT='%s'" % out.path,
-         "PROTO_COMPILER='%s'" % ctx.executable._proto_compiler.path,
-+        "GRPC_JAVA_PLUGIN='%s'" % ctx.executable.grpc_java_plugin.path if \
-+            ctx.executable.grpc_java_plugin else "",
-         "SOURCE='%s'" % ctx.file.src.path,
-         ctx.executable._gensrcjar.path,
-     ]),
-@@ -43,14 +45,19 @@ gensrcjar = rule(
-             allow_files = proto_filetype,
-             single_file = True,
-         ),
-+        "grpc_java_plugin": attr.label(
-+            cfg = "host",
-+            executable = True,
-+            single_file = True,
-+        ),
-         "_gensrcjar": attr.label(
--            default = Label("@bazel_tools//tools/build_rules:gensrcjar"),
-+            default = Label("//tools/build_rules:gensrcjar"),
-             executable = True,
-         ),
-         # TODO(bazel-team): this should be a hidden attribute with a default
-         # value, but Skylark needs to support select first.
-         "_proto_compiler": attr.label(
--            default = Label("@bazel_tools//third_party/protobuf:protoc"),
-+            default = Label("//third_party/protobuf:protoc"),
-             allow_files = True,
-             executable = True,
-             single_file = True,
-@@ -73,13 +80,42 @@ gensrcjar = rule(
-     outputs = {"srcjar": "lib%{name}.srcjar"},
- )
- 
-+def cc_grpc_library(name, src):
-+  basename = src[:-len(".proto")]
-+
-+  native.genrule(
-+      name = name + "_codegen",
-+      srcs = [src],
-+      tools = ["//third_party/protobuf:protoc", "//third_party/grpc:cpp_plugin"],
-+      cmd = "\\\n".join([
-+          "$(location //third_party/protobuf:protoc)",
-+          "    --plugin=protoc-gen-grpc=$(location //third_party/grpc:cpp_plugin)",
-+          "    --cpp_out=$(GENDIR)",
-+          "    --grpc_out=$(GENDIR)",
-+          "    $(location " + src + ")"]),
-+      outs = [basename + ".grpc.pb.h", basename + ".grpc.pb.cc", basename + ".pb.cc", basename + ".pb.h"])
-+
-+  native.cc_library(
-+      name = name,
-+      srcs = [basename + ".grpc.pb.cc", basename + ".pb.cc"],
-+      hdrs = [basename + ".grpc.pb.h", basename + ".pb.h"],
-+      deps = ["//third_party/grpc:grpc++"],
-+      includes = ["."])
-+
- # TODO(bazel-team): support proto => proto dependencies too
--def java_proto_library(name, src):
--  gensrcjar(name=name + "_srcjar", src=src)
-+def java_proto_library(name, src, use_grpc_plugin=False):
-+  grpc_java_plugin = None
-+  if use_grpc_plugin:
-+    grpc_java_plugin = "//third_party/grpc:grpc-java-plugin"
-+
-+  gensrcjar(name=name + "_srcjar", src=src, grpc_java_plugin=grpc_java_plugin)
-+  deps = ["//third_party/protobuf"]
-+  if use_grpc_plugin:
-+    deps += ["//third_party/grpc:grpc-jar", "//third_party:guava"]
-   native.java_library(
-     name=name,
-     srcs=[name + "_srcjar"],
--    deps=["@bazel_tools//third_party/protobuf"],
-+    deps=deps,
-     # The generated code has lots of 'rawtypes' warnings.
-     javacopts=["-Xlint:-rawtypes"],
- )
-diff --git a/tools/build_rules/gensrcjar.sh b/tools/build_rules/gensrcjar.sh
-index b94408a..c1674a3 100755
---- a/tools/build_rules/gensrcjar.sh
-+++ b/tools/build_rules/gensrcjar.sh
-@@ -65,8 +65,14 @@ main() {
-   "${PREPROCESSOR}" <"${SOURCE}" >"${processed_source}" \
-       || err "Preprocessor ${PREPROCESSOR} failed"
- 
--  "${PROTO_COMPILER}" --java_out="${proto_output}" "${processed_source}" \
--      || err "proto_compiler failed"
-+  if [ -n "${GRPC_JAVA_PLUGIN}" ]; then
-+    "${PROTO_COMPILER}" --plugin=protoc-gen-grpc="${GRPC_JAVA_PLUGIN}" \
-+        --grpc_out="${proto_output}" --java_out="${proto_output}" "${processed_source}" \
-+        || err "proto_compiler failed"
-+  else
-+    "${PROTO_COMPILER}" --java_out="${proto_output}" "${processed_source}" \
-+        || err "proto_compiler failed"
-+  fi
-   find "${proto_output}" -exec touch -t "${TIMESTAMP}" '{}' \; \
-       || err "Failed to reset timestamps"
-   "${JAR}" cMf "${OUTPUT}.tmp" -C "${proto_output}" . \