diff --git a/.bazelrc.travis b/.bazelrc.travis
index 83bf60532..657602435 100644
--- a/.bazelrc.travis
+++ b/.bazelrc.travis
@@ -17,7 +17,7 @@ build --verbose_failures
# runs stuff in a container, and since Travis already runs its script
# in a container (unless you require sudo in your .travis.yml) this
# fails to run tests.
-build --spawn_strategy=standalone --genrule_strategy=standalone
+build --spawn_strategy=standalone --genrule_strategy=standalone --strategy=Scalac=worker --strategy=ScroogeRule=worker --worker_max_instances=3
test --test_strategy=standalone
# Below this line, .travis.yml will cat the default bazelrc.
diff --git a/.travis.yml b/.travis.yml
index 477557d78..e4cf4ff9b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,7 +14,7 @@ env:
# we want to test the most recent few releases
- V=0.5.3
- V=0.5.4
- - V=0.6.0rc2
+ - V=0.6.0
before_install:
- |
diff --git a/README.md b/README.md
index 1ddf58aee..8dfa7bc8b 100644
--- a/README.md
+++ b/README.md
@@ -467,6 +467,71 @@ thrift_library(name, srcs, deps, absolute_prefix, absolute_prefixes)
+## scalapb_proto_library
+
+```python
+load("//scala_proto:scala_proto.bzl", "scalapb_proto_library")
+scalapb_proto_library(name, deps, with_grpc, with_java, with_flat_package, with_single_line_to_string)
+```
+
+`scalapb_proto_library` generates a scala library of scala proto bindings
+generated by the [ScalaPB compiler](https://github.com/scalapb/ScalaPB).
+
+
+
+
+
+
+
+
+ Attributes |
+
+
+
+
+ name |
+
+ Name, required
+ A unique name for this target
+ |
+
+ deps |
+
+ List of labels, required
+ List of proto dependencies that this target depends on. Must be of type proto_library
+ |
+
+
+ with_grpc |
+
+ boolean; optional (default False)
+ Enables generation of grpc service bindings for services defined in deps
+ |
+
+
+ with_java |
+
+ boolean; optional (default False)
+ Enables generation of converters to and from java protobuf bindings
+ |
+
+
+ with_flat_package |
+
+ boolean; optional (default False)
+ When true, ScalaPB will not append the protofile base name to the package name
+ |
+
+
+ with_single_line_to_string |
+
+ boolean; optional (default False)
+ Enables generation of toString() methods that use the single line format
+ |
+
+
+
+
## Building from source
Test & Build:
```
diff --git a/WORKSPACE b/WORKSPACE
index 25af75840..85e53d71e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -14,6 +14,9 @@ tut_repositories()
load("//jmh:jmh.bzl", "jmh_repositories")
jmh_repositories()
+load("//scala_proto:scala_proto.bzl", "scala_proto_repositories")
+scala_proto_repositories()
+
load("//specs2:specs2_junit.bzl","specs2_junit_repositories")
specs2_junit_repositories()
@@ -50,3 +53,17 @@ maven_jar(
artifact = "org.apache.commons:commons-lang3:3.5",
sha1 = "6c6c702c89bfff3cd9e80b04d668c5e190d588c6"
)
+
+http_archive(
+ name = "com_google_protobuf",
+ urls = ["https://github.com/google/protobuf/archive/b4b0e304be5a68de3d0ee1af9b286f958750f5e4.zip"],
+ strip_prefix = "protobuf-b4b0e304be5a68de3d0ee1af9b286f958750f5e4",
+ sha256 = "ff771a662fb6bd4d3cc209bcccedef3e93980a49f71df1e987f6afa3bcdcba3a",
+)
+
+http_archive(
+ name = "com_google_protobuf_java",
+ urls = ["https://github.com/google/protobuf/archive/b4b0e304be5a68de3d0ee1af9b286f958750f5e4.zip"],
+ strip_prefix = "protobuf-b4b0e304be5a68de3d0ee1af9b286f958750f5e4",
+ sha256 = "ff771a662fb6bd4d3cc209bcccedef3e93980a49f71df1e987f6afa3bcdcba3a",
+)
diff --git a/scala_proto/BUILD b/scala_proto/BUILD
new file mode 100644
index 000000000..e69de29bb
diff --git a/scala_proto/scala_proto.bzl b/scala_proto/scala_proto.bzl
new file mode 100644
index 000000000..19fb31b7f
--- /dev/null
+++ b/scala_proto/scala_proto.bzl
@@ -0,0 +1,463 @@
+load("//scala:scala.bzl",
+ "scala_library")
+
+def scala_proto_repositories():
+ native.maven_server(
+ name = "scala_proto_deps_maven_server",
+ url = "http://central.maven.org/maven2/",
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_protoc_jar",
+ artifact = "com.github.os72:protoc-jar:3.2.0",
+ sha1 = "7c06b12068193bd2080caf45580b0a00d2a31638",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/protoc',
+ actual = '@scala_proto_rules_protoc_jar//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_scalapb_plugin",
+ artifact = "com.trueaccord.scalapb:compilerplugin_2.11:0.6.5",
+ sha1 = "290094c632c95b36b6f66d7dbfdc15242b9a247f",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/scalapb_plugin',
+ actual = '@scala_proto_rules_scalapb_plugin//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_protoc_bridge",
+ artifact = "com.trueaccord.scalapb:protoc-bridge_2.11:0.3.0-M1",
+ sha1 = "73d38f045ea8f09cc1264991d1064add6eac9e00",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/protoc_bridge',
+ actual = '@scala_proto_rules_protoc_bridge//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_scalapbc",
+ artifact = "com.trueaccord.scalapb:scalapbc_2.11:0.6.5",
+ sha1 = "b204d6d56a042b973af5b6fe28f81ece232d1fe4",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/scalapbc',
+ actual = '@scala_proto_rules_scalapbc//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_scalapb_runtime",
+ artifact = "com.trueaccord.scalapb:scalapb-runtime_2.11:0.6.5",
+ sha1 = "ac9287ff48c632df525773570ee4842e3ddf40e9",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/scalapb_runtime',
+ actual = '@scala_proto_rules_scalapb_runtime//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_scalapb_runtime_grpc",
+ artifact = "com.trueaccord.scalapb:scalapb-runtime-grpc_2.11:0.6.5",
+ sha1 = "9dc3374001f4190548db36a7dc87bd4f9bca6f9c",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/scalapb_runtime_grpc',
+ actual = '@scala_proto_rules_scalapb_runtime_grpc//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_scalapb_lenses",
+ artifact = "com.trueaccord.lenses:lenses_2.11:0.4.12",
+ sha1 = "c5fbf5b872ce99d9a16d3392ccc0d15a0e43d823",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/scalapb_lenses',
+ actual = '@scala_proto_rules_scalapb_lenses//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_scalapb_fastparse",
+ artifact = "com.lihaoyi:fastparse_2.11:0.4.4",
+ sha1 = "f065fe0afe6fd2b4557d985c37362c36f08f9947",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/scalapb_fastparse',
+ actual = '@scala_proto_rules_scalapb_fastparse//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_grpc_core",
+ artifact = "io.grpc:grpc-core:1.3.1",
+ sha1 = "a9b38b4a19af3ef208f4f6bf7871876d959c5eb1",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/grpc_core',
+ actual = '@scala_proto_rules_grpc_core//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_grpc_stub",
+ artifact = "io.grpc:grpc-stub:1.3.1",
+ sha1 = "60bdfa9d8c664a9d87ae461106eff6eed8da6c54",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/grpc_stub',
+ actual = '@scala_proto_rules_grpc_stub//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_grpc_protobuf",
+ artifact = "io.grpc:grpc-protobuf:1.3.1",
+ sha1 = "9562e977cacd6e128a31686c3e6948d61873c496",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/grpc_protobuf',
+ actual = '@scala_proto_rules_grpc_protobuf//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_grpc_netty",
+ artifact = "io.grpc:grpc-netty:1.3.1",
+ sha1 = "cc3831fccb76cfe21445f75cc055b5ffd979dc54",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/grpc_netty',
+ actual = '@scala_proto_rules_grpc_netty//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_grpc_context",
+ artifact = "io.grpc:grpc-context:1.3.1",
+ sha1 = "28accd419b18d59055b8999f78f5cb7767c7bde8",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/grpc_context',
+ actual = '@scala_proto_rules_grpc_context//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_guava",
+ artifact = "com.google.guava:guava:19.0",
+ sha1 = "6ce200f6b23222af3d8abb6b6459e6c44f4bb0e9",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/guava',
+ actual = '@scala_proto_rules_guava//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_google_instrumentation",
+ artifact = "com.google.instrumentation:instrumentation-api:0.3.0",
+ sha1 = "a2e145e7a7567c6372738f5c5a6f3ba6407ac354",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/google_instrumentation',
+ actual = '@scala_proto_rules_google_instrumentation//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_netty_codec",
+ artifact = "io.netty:netty-codec:4.1.8.Final",
+ sha1 = "1bd0a2d032e5c7fc3f42c1b483d0f4c57eb516a3",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/netty_codec',
+ actual = '@scala_proto_rules_netty_codec//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_netty_codec_http",
+ artifact = "io.netty:netty-codec-http:4.1.8.Final",
+ sha1 = "1e88617c4a6c88da7e86fdbbd9494d22a250c879",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/netty_codec_http',
+ actual = '@scala_proto_rules_netty_codec_http//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_netty_codec_socks",
+ artifact = "io.netty:netty-codec-socks:4.1.8.Final",
+ sha1 = "7f7c5f5b154646d7c571f8ca944fb813f71b1d51",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/netty_codec_socks',
+ actual = '@scala_proto_rules_netty_codec_socks//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_netty_codec_http2",
+ artifact = "io.netty:netty-codec-http2:4.1.8.Final",
+ sha1 = "105a99ee5767463370ccc3d2e16800bd99f5648e",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/netty_codec_http2',
+ actual = '@scala_proto_rules_netty_codec_http2//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_netty_handler",
+ artifact = "io.netty:netty-handler:4.1.8.Final",
+ sha1 = "db01139bfb11afd009a695eef55b43bbf22c4ef5",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/netty_handler',
+ actual = '@scala_proto_rules_netty_handler//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_netty_buffer",
+ artifact = "io.netty:netty-buffer:4.1.8.Final",
+ sha1 = "43292c2622e340a0d07178c341ca3bdf3d662034",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/netty_buffer',
+ actual = '@scala_proto_rules_netty_buffer//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_netty_transport",
+ artifact = "io.netty:netty-transport:4.1.8.Final",
+ sha1 = "905b5dadce881c9824b3039c0df36dabbb7b6a07",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/netty_transport',
+ actual = '@scala_proto_rules_netty_transport//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_netty_resolver",
+ artifact = "io.netty:netty-resolver:4.1.8.Final",
+ sha1 = "2e116cdd5edc01b2305072b1dbbd17c0595dbfef",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/netty_resolver',
+ actual = '@scala_proto_rules_netty_resolver//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_netty_common",
+ artifact = "io.netty:netty-common:4.1.8.Final",
+ sha1 = "ee62c80318413d2375d145e51e48d7d35c901324",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/netty_common',
+ actual = '@scala_proto_rules_netty_common//jar'
+ )
+
+ native.maven_jar(
+ name = "scala_proto_rules_netty_handler_proxy",
+ artifact = "io.netty:netty-handler-proxy:4.1.8.Final",
+ sha1 = "c4d22e8b9071a0ea8d75766d869496c32648a758",
+ server = "scala_proto_deps_maven_server",
+ )
+
+ native.bind(
+ name = 'io_bazel_rules_scala/dependency/proto/netty_handler_proxy',
+ actual = '@scala_proto_rules_netty_handler_proxy//jar'
+ )
+
+def _colon_paths(data):
+ return ':'.join([f.path for f in data])
+
+def _gen_proto_srcjar_impl(ctx):
+ acc_imports = depset()
+ for target in ctx.attr.deps:
+ acc_imports += target.proto.transitive_sources
+
+ # Command line args to worker cannot be empty so using padding
+ flags = ["-"]
+ if ctx.attr.with_grpc:
+ flags.append("grpc")
+ if ctx.attr.with_java:
+ flags.append("java_conversions")
+ if ctx.attr.with_flat_package:
+ flags.append("flat_package")
+ if ctx.attr.with_single_line_to_string:
+ flags.append("single_line_to_string")
+
+ worker_content = "{output}\n{paths}\n{flags_arg}".format(
+ output = ctx.outputs.srcjar.path,
+ paths = _colon_paths(acc_imports),
+ flags_arg = ",".join(flags),
+ )
+ argfile = ctx.new_file(ctx.outputs.srcjar, "%s_worker_input" % ctx.label.name)
+ ctx.file_action(output=argfile, content=worker_content)
+ ctx.action(
+ executable = ctx.executable._pluck_scalapb_scala,
+ inputs = list(acc_imports) + [argfile],
+ outputs = [ctx.outputs.srcjar],
+ mnemonic="ProtoScalaPBRule",
+ progress_message = "creating scalapb files %s" % ctx.label,
+ execution_requirements={"supports-workers": "1"},
+ arguments=["@" + argfile.path],
+ )
+ srcjarsattr = struct(
+ srcjar = ctx.outputs.srcjar,
+ )
+ return struct(
+ srcjars=srcjarsattr,
+ extra_information=[struct(
+ srcjars=srcjarsattr,
+ )],
+ )
+
+scalapb_proto_srcjar = rule(
+ _gen_proto_srcjar_impl,
+ attrs={
+ "deps": attr.label_list(
+ mandatory=True,
+ allow_rules=["proto_library"]
+ ),
+ "with_grpc": attr.bool(default=False),
+ "with_java": attr.bool(default=False),
+ "with_flat_package": attr.bool(default=False),
+ "with_single_line_to_string": attr.bool(default=False),
+ "_pluck_scalapb_scala": attr.label(
+ executable=True,
+ cfg="host",
+ default=Label("//src/scala/scripts:scalapb_generator"),
+ allow_files=True
+ ),
+ },
+ outputs={
+ "srcjar": "lib%{name}.srcjar",
+ },
+)
+
+SCALAPB_DEPS = [
+ "//external:io_bazel_rules_scala/dependency/proto/scalapb_runtime",
+ "//external:io_bazel_rules_scala/dependency/com_google_protobuf/protobuf_java",
+ "//external:io_bazel_rules_scala/dependency/proto/scalapb_lenses",
+ "//external:io_bazel_rules_scala/dependency/proto/scalapb_fastparse",
+]
+
+GRPC_DEPS = [
+ "//external:io_bazel_rules_scala/dependency/proto/scalapb_runtime_grpc",
+ "//external:io_bazel_rules_scala/dependency/proto/grpc_core",
+ "//external:io_bazel_rules_scala/dependency/proto/grpc_stub",
+ "//external:io_bazel_rules_scala/dependency/proto/grpc_protobuf",
+ "//external:io_bazel_rules_scala/dependency/proto/grpc_netty",
+ "//external:io_bazel_rules_scala/dependency/proto/grpc_context",
+ "//external:io_bazel_rules_scala/dependency/proto/guava",
+ "//external:io_bazel_rules_scala/dependency/proto/google_instrumentation",
+ "//external:io_bazel_rules_scala/dependency/proto/netty_codec",
+ "//external:io_bazel_rules_scala/dependency/proto/netty_codec_http",
+ "//external:io_bazel_rules_scala/dependency/proto/netty_codec_http2",
+ "//external:io_bazel_rules_scala/dependency/proto/netty_codec_socks",
+ "//external:io_bazel_rules_scala/dependency/proto/netty_handler",
+ "//external:io_bazel_rules_scala/dependency/proto/netty_buffer",
+ "//external:io_bazel_rules_scala/dependency/proto/netty_transport",
+ "//external:io_bazel_rules_scala/dependency/proto/netty_resolver",
+ "//external:io_bazel_rules_scala/dependency/proto/netty_common",
+ "//external:io_bazel_rules_scala/dependency/proto/netty_handler_proxy",
+]
+
+"""Generate scalapb bindings for a set of proto_library targets.
+
+Example:
+ scalapb_proto_library(
+ name = "exampla_proto_scala",
+ with_grpc = True,
+ deps = ["//src/proto:example_service"]
+ )
+
+Args:
+ name: A unique name for this rule
+ deps: Proto library targets that this rule depends on (must be of type proto_library)
+ with_grpc: Enables generation of grpc service bindings for services defined in deps
+ with_java: Enables generation of converters to and from java protobuf bindings
+ with_flat_package: When true, ScalaPB will not append the protofile base name to the package name
+ with_single_line_to_string: Enables generation of toString() methods that use the single line format
+
+Outputs:
+ A scala_library rule that includes the generated scalapb bindings, as
+ well as any library dependencies needed to compile and use these.
+"""
+def scalapb_proto_library(
+ name,
+ deps = [],
+ with_grpc = False,
+ with_java = False,
+ with_flat_package = False,
+ with_single_line_to_string = False,
+ visibility = None):
+
+ srcjar = name + '_srcjar'
+ scalapb_proto_srcjar(
+ name = srcjar,
+ with_grpc = with_grpc,
+ with_java = with_java,
+ with_flat_package = with_flat_package,
+ with_single_line_to_string = with_single_line_to_string,
+ deps = deps,
+ visibility = visibility,
+ )
+
+ external_deps = list(SCALAPB_DEPS + GRPC_DEPS if (with_grpc) else SCALAPB_DEPS)
+
+ if with_java:
+ java_proto_lib = name + "_java_lib"
+ native.java_proto_library(
+ name = java_proto_lib,
+ deps = deps,
+ )
+ external_deps.append(java_proto_lib)
+
+ scala_library(
+ name = name,
+ srcs = [srcjar],
+ deps = external_deps,
+ exports = external_deps,
+ visibility = visibility,
+ )
diff --git a/src/scala/scripts/BUILD b/src/scala/scripts/BUILD
index ec3384a15..13787f7cb 100644
--- a/src/scala/scripts/BUILD
+++ b/src/scala/scripts/BUILD
@@ -21,3 +21,29 @@ scala_binary(
":generator_lib",
],
)
+
+scala_library(
+ name = "scalapb_generator_lib",
+ srcs = ["ScalaPBGenerator.scala"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//external:io_bazel_rules_scala/dependency/proto/protoc",
+ "//external:io_bazel_rules_scala/dependency/proto/scalapb_plugin",
+ "//external:io_bazel_rules_scala/dependency/proto/protoc_bridge",
+ "//external:io_bazel_rules_scala/dependency/proto/scalapbc",
+ "//external:io_bazel_rules_scala/dependency/com_google_protobuf/protobuf_java",
+ "//src/java/io/bazel/rulesscala/io_utils",
+ "//src/java/io/bazel/rulesscala/jar",
+ "//src/java/io/bazel/rulesscala/worker",
+ "//src/scala/io/bazel/rules_scala/scrooge_support:compiler",
+ ],
+)
+
+scala_binary(
+ name = "scalapb_generator",
+ main_class = "scripts.ScalaPBWorker",
+ visibility = ["//visibility:public"],
+ deps = [
+ ":scalapb_generator_lib",
+ ],
+)
diff --git a/src/scala/scripts/ScalaPBGenerator.scala b/src/scala/scripts/ScalaPBGenerator.scala
new file mode 100644
index 000000000..ad6ce2db5
--- /dev/null
+++ b/src/scala/scripts/ScalaPBGenerator.scala
@@ -0,0 +1,72 @@
+package scripts
+
+import io.bazel.rulesscala.jar.JarCreator
+import io.bazel.rulesscala.io_utils.DeleteRecursively
+import java.io.{ File, PrintStream }
+import java.nio.file.{ Files, Path, Paths }
+import scala.collection.mutable.Buffer
+import io.bazel.rulesscala.worker.{ GenericWorker, Processor }
+import scala.io.Source
+import protocbridge.ProtocBridge
+import scalapb.ScalaPbCodeGenerator
+import com.trueaccord.scalapb.{Config, ScalaPBC, ScalaPbcException}
+
+object ScalaPBWorker extends GenericWorker(new ScalaPBGenerator) {
+
+ override protected def setupOutput(ps: PrintStream): Unit = {
+ System.setOut(ps)
+ System.setErr(ps)
+ Console.setErr(ps)
+ Console.setOut(ps)
+ }
+
+ def main(args: Array[String]) {
+ try run(args)
+ catch {
+ case x: Exception =>
+ x.printStackTrace()
+ System.exit(1)
+ }
+ }
+}
+
+class ScalaPBGenerator extends Processor {
+ def deleteDir(path: Path): Unit =
+ try DeleteRecursively.run(path)
+ catch {
+ case e: Exception => ()
+ }
+
+ def processRequest(args: java.util.List[String]) {
+ val jarOutput = args.get(0)
+ val protoFiles = args.get(1).split(':').toList
+ val flagOpt = args.get(2) match {
+ case "-" => None
+ case s => Some(s.drop(2))
+ }
+
+ val tmp = Paths.get(Option(System.getProperty("java.io.tmpdir")).getOrElse("/tmp"))
+ val scalaPBOutput = Files.createTempDirectory(tmp, "bazelscalapb")
+ val flagPrefix = flagOpt.map(_ + ":").getOrElse("")
+ val scalaPBArgs = s"--scala_out=${flagPrefix}${scalaPBOutput}" :: protoFiles
+ val config = ScalaPBC.processArgs(scalaPBArgs.toArray)
+ val code = ProtocBridge.runWithGenerators(
+ protoc = a => com.github.os72.protocjar.Protoc.runProtoc(config.version +: a.toArray),
+ namedGenerators = Seq("scala" -> ScalaPbCodeGenerator),
+ params = config.args)
+
+ val dirsToDelete = Set(scalaPBOutput)
+
+ try {
+ if (!config.throwException) {
+ JarCreator.buildJar(Array(jarOutput, scalaPBOutput.toString))
+ } else {
+ if (code != 0) {
+ throw new ScalaPbcException(s"Exit with code $code")
+ }
+ }
+ } finally {
+ dirsToDelete.foreach { deleteDir(_) }
+ }
+ }
+}
diff --git a/src/scala/scripts/TwitterScroogeGenerator.scala b/src/scala/scripts/TwitterScroogeGenerator.scala
index 9f6a1e68d..f2b53cd65 100644
--- a/src/scala/scripts/TwitterScroogeGenerator.scala
+++ b/src/scala/scripts/TwitterScroogeGenerator.scala
@@ -73,7 +73,7 @@ class ScroogeGenerator extends Processor {
// Further configuration options for scrooge.
val additionalFlags = getIdx(5)
- val tmp = Paths.get(Option(System.getenv("TMPDIR")).getOrElse("/tmp"))
+ val tmp = Paths.get(Option(System.getProperty("java.io.tmpdir")).getOrElse("/tmp"))
val scroogeOutput = Files.createTempDirectory(tmp, "scrooge")
val scrooge = new Compiler
diff --git a/test/BUILD b/test/BUILD
index a7933194a..c7d34683d 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -11,6 +11,9 @@ load("//scala:scala.bzl",
"scala_junit_test",
"scala_specs2_junit_test")
+load("//scala_proto:scala_proto.bzl",
+ "scalapb_proto_library")
+
# The examples below show how to combine Scala and Java rules.
# ScalaBinary is the Scala equivalent of JavaBinary.
@@ -432,3 +435,33 @@ scala_binary(
main_class = "scala.test.BinaryDependentOnJava",
deps = [":JavaOnlySources"],
)
+
+scalapb_proto_library(
+ name = "test_proto_nogrpc",
+ deps = ["//test/proto:test2"]
+)
+
+scalapb_proto_library(
+ name = "test_proto_java_conversions",
+ deps = ["//test/proto:test2", "//test/proto:test"],
+ with_java = True,
+ with_flat_package = True,
+)
+
+scalapb_proto_library(
+ name = "test_proto",
+ with_grpc = True,
+ deps = ["//test/proto:test_service"]
+)
+
+scala_library(
+ name = "lib_with_scala_proto_dep",
+ srcs = ["TestServer.scala"],
+ deps = [":test_proto"]
+)
+
+scala_binary(
+ name = "test_scala_proto_server",
+ main_class = "test.proto.TestServer",
+ deps = [":lib_with_scala_proto_dep"]
+)
diff --git a/test/TestServer.scala b/test/TestServer.scala
new file mode 100644
index 000000000..3a44df27f
--- /dev/null
+++ b/test/TestServer.scala
@@ -0,0 +1,98 @@
+package test.proto
+
+import test.{TestRequest, TestMessage}
+import test2.TestResponse1
+import test3.TestResponse2
+import test_service.TestServiceGrpc
+import test_service.TestServiceGrpc.TestServiceBlockingStub
+
+import io.grpc.{Server, ServerBuilder, StatusRuntimeException, ManagedChannelBuilder, ManagedChannel}
+
+import java.util.concurrent.TimeUnit
+import java.util.logging.{Level, Logger}
+
+import scala.concurrent.{ExecutionContext, Future}
+
+/**
+ * Adapted from https://github.com/xuwei-k/grpc-scala-sample/blob/master/grpc-scala/src/main/scala/io/grpc/examples/helloworld/HelloWorldServer.scala
+ */
+object TestServer {
+ private val logger = Logger.getLogger(classOf[TestServer].getName)
+
+ def main(args: Array[String]): Unit = {
+ val server = new TestServer(ExecutionContext.global)
+ server.start()
+ val client = TestClient("localhost", 50051)
+ val msg = args.headOption.getOrElse("ping")
+ client.send(msg)
+ client.shutdown()
+ server.stop()
+ }
+
+ private val port = 50051
+}
+
+class TestServer(executionContext: ExecutionContext) { self =>
+ lazy val server: Server = ServerBuilder
+ .forPort(TestServer.port)
+ .addService(TestServiceGrpc.bindService(new TestServiceImpl, executionContext))
+ .build
+
+ private def start(): Unit = {
+ server.start()
+ TestServer.logger.info(s"Server started, listening on ${TestServer.port}")
+ sys.addShutdownHook {
+ System.err.println("*** shutting down gRPC server since JVM is shutting down")
+ self.stop()
+ System.err.println("*** server shut down")
+ }
+ }
+
+ private def stop(): Unit = server.shutdown()
+
+ private def blockUntilShutdown(): Unit = server.awaitTermination()
+
+ private class TestServiceImpl extends TestServiceGrpc.TestService {
+ override def testMethod1(request: TestRequest): Future[TestResponse1] = {
+ val response = TestResponse1().withTestMsg(TestMessage(Some("foo")))
+ Future.successful(response)
+ }
+
+ override def testMethod2(request: TestRequest): Future[TestResponse2] = {
+ val response = TestResponse2().withTestMsg(TestMessage(Some("bar")))
+ Future.successful(response)
+ }
+ }
+}
+
+object TestClient {
+ def apply(host: String, port: Int): TestClient = {
+ val channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build
+ val blockingStub = TestServiceGrpc.blockingStub(channel)
+ new TestClient(channel, blockingStub)
+ }
+}
+
+class TestClient private(
+ private val channel: ManagedChannel,
+ private val blockingStub: TestServiceBlockingStub
+) {
+ private[this] val logger = Logger.getLogger(classOf[TestClient].getName)
+
+ def shutdown(): Unit = {
+ channel.shutdown.awaitTermination(5, TimeUnit.SECONDS)
+ }
+
+ def send(name: String): Unit = {
+ logger.info("Will try to send " + name + " ...")
+ val request = TestRequest()
+ try {
+ val response = blockingStub.testMethod1(request)
+ logger.info("Response: " + response.testMsg)
+ }
+ catch {
+ case e: StatusRuntimeException =>
+ logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus)
+ }
+ }
+}
diff --git a/test/proto/BUILD b/test/proto/BUILD
new file mode 100644
index 000000000..cd4f7176a
--- /dev/null
+++ b/test/proto/BUILD
@@ -0,0 +1,26 @@
+proto_library(
+ name = "test",
+ srcs = ["test.proto"],
+ visibility = ["//visibility:public"],
+)
+
+proto_library(
+ name = "test2",
+ deps = [":test"],
+ srcs = ["test2.proto"],
+ visibility = ["//visibility:public"],
+)
+
+proto_library(
+ name = "test3",
+ deps = [":test"],
+ srcs = ["test3.proto"],
+ visibility = ["//visibility:public"],
+)
+
+proto_library(
+ name = "test_service",
+ deps = [":test2", ":test3", ":test"],
+ srcs = ["test_service.proto"],
+ visibility = ["//visibility:public"],
+)
diff --git a/test/proto/test.proto b/test/proto/test.proto
new file mode 100644
index 000000000..6a51d45b2
--- /dev/null
+++ b/test/proto/test.proto
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+option java_package = "test.proto";
+
+message TestRequest {
+ optional uint32 a = 1;
+ optional bool b = 2;
+}
+
+message TestMessage {
+ optional string foo = 1;
+}
diff --git a/test/proto/test2.proto b/test/proto/test2.proto
new file mode 100644
index 000000000..af4cc4757
--- /dev/null
+++ b/test/proto/test2.proto
@@ -0,0 +1,10 @@
+syntax = "proto2";
+
+import "test/proto/test.proto";
+option java_package = "test.proto";
+
+message TestResponse1 {
+ optional uint32 c = 1;
+ optional bool d = 2;
+ optional TestMessage testMsg = 3;
+}
diff --git a/test/proto/test3.proto b/test/proto/test3.proto
new file mode 100644
index 000000000..779e02203
--- /dev/null
+++ b/test/proto/test3.proto
@@ -0,0 +1,10 @@
+syntax = "proto2";
+
+import "test/proto/test.proto";
+option java_package = "test.proto";
+
+message TestResponse2 {
+ optional uint32 e = 1;
+ optional bool f = 2;
+ optional TestMessage testMsg = 3;
+}
diff --git a/test/proto/test_service.proto b/test/proto/test_service.proto
new file mode 100644
index 000000000..fd9f95dd0
--- /dev/null
+++ b/test/proto/test_service.proto
@@ -0,0 +1,12 @@
+syntax = "proto2";
+
+import "test/proto/test.proto";
+import "test/proto/test2.proto";
+import "test/proto/test3.proto";
+
+option java_package = "test.proto";
+
+service TestService {
+ rpc TestMethod1 (TestRequest) returns (TestResponse1) {}
+ rpc TestMethod2 (TestRequest) returns (TestResponse2) {}
+}
diff --git a/test_run.sh b/test_run.sh
index 17f92582b..e5bc24f01 100755
--- a/test_run.sh
+++ b/test_run.sh
@@ -582,3 +582,4 @@ $runner test_scala_library_expect_no_recompilation_on_internal_change_of_scala_d
$runner test_scala_library_expect_no_recompilation_on_internal_change_of_java_dependency
$runner test_scala_library_expect_no_java_recompilation_on_internal_change_of_scala_sibling
$runner test_scala_library_expect_failure_on_missing_direct_java
+$runner bazel run test:test_scala_proto_server
diff --git a/twitter_scrooge/twitter_scrooge.bzl b/twitter_scrooge/twitter_scrooge.bzl
index 68fa1713b..c11e23d7d 100644
--- a/twitter_scrooge/twitter_scrooge.bzl
+++ b/twitter_scrooge/twitter_scrooge.bzl
@@ -113,7 +113,7 @@ def _gen_scrooge_srcjar_impl(ctx):
for target in ctx.attr.remote_jars:
remote_jars += _jar_filetype.filter(target.files)
- # These are JARs that are declared externally and only have Thrift files
+ # These are JARs that are declared externally and only have Thrift files
# in them.
external_jars = _collect_external_jars(ctx.attr.deps)