Skip to content

Commit c982939

Browse files
committed
Bump protoc-bridge to 0.9.8 for Scala >= 2.12
This required updates to `scripts/create_repository.py` to accommodate comparisons between `_2.13` and `_3` versions of ScalaPB artifacts. The `_3` versions of the most recent ScalaPB artifacts are only available for Scala 3.3 and later, and `compilerplugin_3` currently still depends on `protoc-gen_2.13`. The `MavenCoordinates` dataclass in `scripts/create_repository.py` has new `unversioned_artifact`, `scala_version`, and `artifact_name` members. Updates to `MavenCoordinates.is_newer_than()` now compare objects with matching `artifact_name` values, and take the `scala_version` into account. These changes then precipitated: - Replacing the `artifact_name()` call with `artifact_name` accesses. - Replacing `ArtifactLabelMaker._remove_scala_version_suffix` with `MavenCoordinates.unversioned_artifact`. - Extracting `__compare_versions` from `is_newer_than` to reuse the same code for comparing Scala versions and artifact versions. (Properly reversed the use of `lhs` and `rhs` in the process.) This change also removes an unnecessary `try`/`catch` block from `scripts.ScalaPbCodeGenerator.process()` for Scala 2.12 and above. The block is still required for the Scala 2.11 implementation of `scripts.ScalaPbCodeGenerator.run()` and in `scalarules.test.extra_protobuf_generator.ExtraProtobufGenerator.run()`. Finally, this change adds notes in a few places to indicate where support remains for Scala 2.11. This supporting code can ultimately be removed if we ever decide to drop Scala 2.11 support. --- Tested by setting the `protobuf` dependencies to a versions I know will break `ScalaPB` 0.11.17: - `abseil-cpp`: 20220623.1 => 20240722.0 - `protobuf`: v21.7 => v26.1 I temporarily removed the `try`/`catch` block for `Throwable` from `scalarules.test.extra_protobuf_generator.ExtraProtobufGenerator.run`. I then ran `bazel shutdown` to stop persistent `ProtoScalaPBRule` workers. After that, building with Bazel 7.4.1 (since Bazel 6.5.0 can't build `abseil-cpp` 20240722.0 without setting C++14 compiler flags) crashed as expected, instead of hanging. Undoing the `abseil-cpp` and `protobuf` changes and building then produced a working build. ```txt $ USE_BAZEL_VERSION=7.4.1 bazel build //third_party/test/proto:scala [ ...snip... ] ERROR: third_party/test/proto/BUILD.bazel:4:14: ProtoScalaPBRule third_party/test/proto/proto_jvm_extra_protobuf_generator_scalapb.srcjar failed: (Exit 1): scalapb_worker failed: error executing ProtoScalaPBRule command (from target //third_party/test/proto:proto) bazel-out/darwin_arm64-opt-exec-ST-a828a81199fe/bin/src/scala/scripts/scalapb_worker ... (remaining 2 arguments skipped) --jvm_extra_protobuf_generator_out: java.lang.VerifyError: Cannot inherit from final class at java.base/java.lang.ClassLoader.defineClass1(Native Method) at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1022) at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174) at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:800) at java.base/jdk.internal.loader.BuiltinClassLoader$4.run(BuiltinClassLoader.java:711) at java.base/jdk.internal.loader.BuiltinClassLoader$4.run(BuiltinClassLoader.java:706) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:719) at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:621) at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:527) at scalapb.options.Scalapb.<clinit>(Scalapb.java:24835) at scalapb.options.compiler.Scalapb$.registerAllExtensions(Scalapb.scala:8) at scalarules.test.extra_protobuf_generator.ExtraProtobufGenerator$.run(ExtraProtobufGenerator.scala:52) at protocbridge.frontend.PluginFrontend$.runWithBytes(PluginFrontend.scala:48) at protocbridge.frontend.PluginFrontend$.runWithInputStream(PluginFrontend.scala:113) at protocbridge.frontend.SocketBasedPluginFrontend.$anonfun$prepare$2(SocketBasedPluginFrontend.scala:31) at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23) at scala.concurrent.impl.ExecutionContextImpl$DefaultThreadFactory$$anon$1$$anon$2.block(ExecutionContextImpl.scala:75) at java.base/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3118) at scala.concurrent.impl.ExecutionContextImpl$DefaultThreadFactory$$anon$1.blockOn(ExecutionContextImpl.scala:87) at scala.concurrent.package$.blocking(package.scala:146) at protocbridge.frontend.SocketBasedPluginFrontend.$anonfun$prepare$1(SocketBasedPluginFrontend.scala:23) at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23) at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:659) at scala.util.Success.$anonfun$map$1(Try.scala:255) at scala.util.Success.map(Try.scala:213) at scala.concurrent.Future.$anonfun$map$1(Future.scala:292) at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:42) at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:74) at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426) at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290) at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020) at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656) at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594) at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183) java.lang.RuntimeException: Exit with code 1 at scala.sys.package$.error(package.scala:30) at scripts.ScalaPBWorker$.work(ScalaPBWorker.scala:44) at io.bazel.rulesscala.worker.Worker.persistentWorkerMain(Worker.java:96) at io.bazel.rulesscala.worker.Worker.workerMain(Worker.java:49) at scripts.ScalaPBWorker$.main(ScalaPBWorker.scala:39) at scripts.ScalaPBWorker.main(ScalaPBWorker.scala) Target //third_party/test/proto:scala failed to build ERROR: third_party/test/proto/BUILD.bazel:4:14 scala @//third_party/test/proto:proto failed: (Exit 1): scalapb_worker failed: error executing ProtoScalaPBRule command (from target //third_party/test/proto:proto) bazel-out/darwin_arm64-opt-exec-ST-a828a81199fe/bin/src/scala/scripts/scalapb_worker ... (remaining 2 arguments skipped) ``` --- The initial motivation for this change was to try to eliminate the need for the custom `scripts.ScalaPbCodeGenerator` implementation by upgrading to `protoc-bridge` 0.9.8. This version contains a change to `catch` any `Throwable` objects raised by a generator implementation in `protocbridge.frontend.PluginFrontend.runWithInputStream()`. - https://github.com/scalapb/protoc-bridge/blob/c574d50eaee5b800fd54493fe25c4e0eed3b9def/bridge/src/main/scala/protocbridge/frontend/PluginFrontend.scala#L107-L122 This change originally came from: - https://github.com/scalapb/protoc-bridge/blob/d0d56f635d13f7efaa2755ed0d2d66bdef18b588/bridge/src/main/scala/protocbridge/frontend/PluginFrontend.scala#L107-L122 - scalapb/protoc-bridge#367 I closed scalapb/ScalaPB#1771 as a result, and reexamined the `try`/`catch` blocks added in bazelbuild#1630 and bazelbuild#1637, and the `scripts.ScalaPBCodeGenerator` implementations added in bazelbuild#1648. However, the last `protoc-bridge` version to support Scala 2.11 is 0.7.14. Scala 2.11 won't be able to use `protoc-bridge` 0.9.8, so we still need to `catch` any `Throwable`s ourselves. This includes the `catch` blocks from the Scala 2.11 `scripts.ScalaPbCodeGenerator` and `scalarules.test.extra_protobuf_generator.ExtraProtobufGenerator.run`. --- In `protoc-bridge` 0.9.7 and 0.9.8, `protocbridge.ProtocCodeGenerator` declares a `run()` method with no implementation (and no `try`/`catch` block). - https://github.com/scalapb/protoc-bridge/blob/v0.9.7/bridge/src/main/scala/protocbridge/ProtocCodeGenerator.scala#L5 In `protoc-gen` 0.9.7 and 0.9.8, `protogen.CodeGenApp` implements `protocbridge.ProtocCodeGenerator`, and `CodeGenApp.run()` wraps a call to `CodeGenApp.process()` inside a `try`/`catch` block. - https://github.com/scalapb/protoc-bridge/blob/v0.9.7/protoc-gen/src/main/scala/protocgen/CodeGenApp.scala#L41-L56 `scalapb.ScalaPbCodeGenerator` from `compilerplugin` 0.11.17 extends `CodeGenApp` and implements `process()`. For this version of `ScalaPbCodeGenerator`, available in Scala 2.12 and later, there's no need for a `try`/`catch` wrapper on our end. - https://github.com/scalapb/ScalaPB/blob/v0.11.17/compiler-plugin/src/main/scala/scalapb/ScalaPbCodeGenerator.scala#L11 However, the last available `compilerplugin` version for Scala 2.11 is 0.9.8. `scalapb.ScalaPbCodeGenerator` from that version implements `protocbridge.ProtocCodeGenerator` and has a `try`/`catch` in its `run()` method. However, the `Scalapb.registerAllExtensions(registry)` call on line 14 lies outside this block, producing the crash described in bazelbuild#1648 (commit 23ae356). This is why we need the Scala 2.11 implementation of `scripts.ScalaPbCodeGenerator`. - https://github.com/scalapb/ScalaPB/blob/v0.9.8/compiler-plugin/src/main/scala/scalapb/ScalaPbCodeGenerator.scala#L14 `scalarules.test.extra_protobuf_generator.ExtraProtobufGenerator`, also extends `ProtocCodeGenerator` directly, instead of implementing `CodeGenApp` (so it also builds with Scala 2.11). This is why `ExtraProtobufGenerator.run()` hangs when we remove the `try`/`catch` block and run with `protoc-bridge` 0.9.7 and `protobuf` > v25.5, even with later Scala versions. --- Since `scalapb.ScalaPbCodeGenerator` from `compilerplugin` 0.11.17 implements `CodeGenApp`, `scripts.ScalaPbCodeGenerator` for Scala 2.12 should be unnecessary. The only reason we need it is to maintain the same interface as the Scala 2.11 implementation. --- Before the `MavenCoordinates` changes, `scripts/create_repository.py` would ScalaPB flip ScalaPB artifacts between their `_2.13` and `_3` versions on subsequent runs (e.g., `protoc-bridge_2.13` vs. `protoc-bridge_3`). See the comments added within `MavenCoordinates.new()` for details. --- Building Scala 3.3 and later versions with `compilerplugin_3` and `protoc-bridge_3` artifacts (instead of `protoc-bridge_2.13` artifacts) produces the following build failure: ```txt $ RULES_SCALA_TEST_ONLY="test_scala_version 3.6.2" \ ./test_thirdparty_version.sh [ ...snip... ] ERROR: third_party/test/proto/BUILD.bazel:4:14: ProtoScalaPBRule third_party/test/proto/proto_jvm_extra_protobuf_generator_scalapb.srcjar failed: (Exit 1): scalapb_worker failed: error executing command (from target //third_party/test/proto:proto) bazel-out/darwin_arm64-opt-exec-2B5CBBC6/bin/src/scala/scripts/scalapb_worker ... (remaining 2 arguments skipped) --scala_out: java.lang.NoClassDefFoundError: Could not initialize class scalapb.ScalaPbCodeGenerator$ at scripts.ScalaPbCodeGenerator$.process(ScalaPbCodeGeneratorWrapper.scala:8) at protocgen.CodeGenApp.run(CodeGenApp.scala:48) at protocgen.CodeGenApp.run$(CodeGenApp.scala:41) at scripts.ScalaPbCodeGenerator$.run(ScalaPbCodeGeneratorWrapper.scala:5) at protocgen.CodeGenApp.run(CodeGenApp.scala:33) at protocgen.CodeGenApp.run$(CodeGenApp.scala:32) at scripts.ScalaPbCodeGenerator$.run(ScalaPbCodeGeneratorWrapper.scala:5) at protocbridge.frontend.PluginFrontend$.runWithBytes(PluginFrontend.scala:48) at protocbridge.frontend.PluginFrontend$.runWithInputStream(PluginFrontend.scala:113) at protocbridge.frontend.SocketBasedPluginFrontend.prepare$$anonfun$1$$anonfun$1(SocketBasedPluginFrontend.scala:31) at protocbridge.frontend.SocketBasedPluginFrontend.prepare$$anonfun$1$$anonfun$adapted$1(SocketBasedPluginFrontend.scala:37) at scala.concurrent.impl.ExecutionContextImpl$DefaultThreadFactory$$anon$1$$anon$2.block(ExecutionContextImpl.scala:60) at java.base/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3118) at scala.concurrent.impl.ExecutionContextImpl$DefaultThreadFactory$$anon$1.blockOn(ExecutionContextImpl.scala:71) at scala.concurrent.package$.blocking(package.scala:124) at protocbridge.frontend.SocketBasedPluginFrontend.prepare$$anonfun$1(SocketBasedPluginFrontend.scala:37) at protocbridge.frontend.SocketBasedPluginFrontend.prepare$$anonfun$adapted$1(SocketBasedPluginFrontend.scala:38) at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:687) at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:467) at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426) at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290) at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020) at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656) at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594) at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183) java.lang.RuntimeException: Exit with code 1 at scala.sys.package$.error(package.scala:27) at scripts.ScalaPBWorker$.work(ScalaPBWorker.scala:44) at io.bazel.rulesscala.worker.Worker.persistentWorkerMain(Worker.java:96) at io.bazel.rulesscala.worker.Worker.workerMain(Worker.java:49) at scripts.ScalaPBWorker$.main(ScalaPBWorker.scala:39) at scripts.ScalaPBWorker.main(ScalaPBWorker.scala) ERROR: third_party/test/proto/BUILD.bazel:4:14 Building source jar third_party/test/proto/proto_scalapb-src.jar failed: (Exit 1): scalapb_worker failed: error executing command (from target //third_party/test/proto:proto) bazel-out/darwin_arm64-opt-exec-2B5CBBC6/bin/src/scala/scripts/scalapb_worker ... (remaining 2 arguments skipped) ```
1 parent c0ca0c5 commit c982939

File tree

13 files changed

+209
-142
lines changed

13 files changed

+209
-142
lines changed

scala_proto/scala_proto_toolchain.bzl

+7
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ scala_proto_toolchain = rule(
8484
default = Label("//src/scala/scripts:scalapb_worker"),
8585
allow_files = True,
8686
),
87+
# `scripts.ScalaPbCodeGenerator` and `_main_generator_dep` are currently
88+
# necessary to support protoc-bridge < 0.9.8, specifically 0.7.14
89+
# required by Scala 2.11. See #1647 and scalapb/ScalaPB#1771.
90+
#
91+
# If we drop 2.11 support, restore `scalapb.ScalaPbCodeGenerator` here,
92+
# remove `_main_generator_dep`, and delete
93+
# `//src/scala/scripts:scalapb_codegenerator_wrapper` and its files.
8794
"main_generator": attr.string(
8895
default = "scripts.ScalaPbCodeGenerator",
8996
),

scripts/create_repository.py

+95-37
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@
3434
PROTOBUF_JAVA_VERSION = "4.29.0"
3535
JLINE_VERSION = '3.27.1'
3636
SCALAPB_VERSION = '0.11.17'
37-
PROTOC_BRIDGE_VERSION = '0.9.7'
37+
PROTOC_BRIDGE_VERSION = '0.9.8'
3838
GRPC_VERSION = '1.68.1'
3939
GRPC_COMMON_PROTOS_VERSION = '2.48.0'
4040
GRPC_LIBS = ['netty', 'protobuf', 'stub']
4141
GUAVA_VERSION = '33.3.1-jre'
4242

43+
# This should include values corresponding to `MavenCoordinates.artifact_name`,
44+
# i.e., group:artifact after stripping any Scala version suffix from artifact.
4345
EXCLUDED_ARTIFACTS = set(["com.google.guava:listenablefuture"])
4446

4547
THIS_FILE = Path(__file__)
@@ -73,15 +75,25 @@ def select_root_artifacts(scala_version, scala_major, is_scala_3) -> List[str]:
7375
v for v in ROOT_SCALA_VERSIONS if v.startswith('2.')
7476
)
7577
max_scala_2_major = '.'.join(max_scala_2_version.split('.')[:2])
78+
minor_version = int(scala_version.split('.')[1])
7679

7780
scala_2_version = scala_version
7881
scala_2_major = scala_major
79-
scalatest_major = scala_major
82+
scalapb_major = scala_2_major
8083

8184
if is_scala_3:
8285
scala_2_version = max_scala_2_version
8386
scala_2_major = max_scala_2_major
84-
scalatest_major = '3'
87+
scala_major = '3'
88+
scalapb_major = scala_2_major if minor_version < 3 else scala_major
89+
90+
# For some reason, com.thesamet.scalapb:compilerplugin_3:0.11.17 depends on
91+
# com.thesamet.scalapb:protoc-gen_2.13:0.9.7. Trying to use
92+
# com.thesamet.scalapb:protoc-gen_3:0.9.8 causes a crash, saying:
93+
# `java.lang.NoClassDefFoundError: Could not initialize class
94+
# scalapb.ScalaPbCodeGenerator$`, even though that class is definitely in
95+
# that jar. So we stick with protoc-gen_2.13 for now.
96+
protoc_bridge_major = scala_2_major
8597

8698
scalafmt_version = SCALAFMT_VERSION
8799
scalapb_version = SCALAPB_VERSION
@@ -97,13 +109,13 @@ def select_root_artifacts(scala_version, scala_major, is_scala_3) -> List[str]:
97109
GRPC_COMMON_PROTOS_VERSION,
98110
f'com.google.guava:guava:{GUAVA_VERSION}',
99111
f'com.google.protobuf:protobuf-java:{PROTOBUF_JAVA_VERSION}',
100-
f'com.thesamet.scalapb:compilerplugin_{scala_2_major}:' +
112+
f'com.thesamet.scalapb:compilerplugin_{scalapb_major}:' +
101113
scalapb_version,
102-
f'com.thesamet.scalapb:protoc-bridge_{scala_2_major}:' +
114+
f'com.thesamet.scalapb:protoc-bridge_{protoc_bridge_major}:' +
103115
protoc_bridge_version,
104-
f'com.thesamet.scalapb:scalapb-runtime_{scala_2_major}:' +
116+
f'com.thesamet.scalapb:scalapb-runtime_{scalapb_major}:' +
105117
scalapb_version,
106-
f'com.thesamet.scalapb:scalapb-runtime-grpc_{scala_2_major}:' +
118+
f'com.thesamet.scalapb:scalapb-runtime-grpc_{scalapb_major}:' +
107119
scalapb_version,
108120
f'org.scala-lang.modules:scala-parser-combinators_{scala_2_major}:' +
109121
PARSER_COMBINATORS_VERSION,
@@ -112,11 +124,17 @@ def select_root_artifacts(scala_version, scala_major, is_scala_3) -> List[str]:
112124
f'org.scala-lang:scala-reflect:{scala_2_version}',
113125
f'org.scala-lang:scalap:{scala_2_version}',
114126
f'org.scalameta:scalafmt-core_{scala_2_major}:{scalafmt_version}',
115-
f'org.scalatest:scalatest_{scalatest_major}:{SCALATEST_VERSION}',
127+
f'org.scalatest:scalatest_{scala_major}:{SCALATEST_VERSION}',
116128
f'org.typelevel:kind-projector_{scala_2_version}:' +
117129
KIND_PROJECTOR_VERSION,
118130
] + [f'io.grpc:grpc-{lib}:{GRPC_VERSION}' for lib in GRPC_LIBS]
119131

132+
if scala_major != '2.11':
133+
root_artifacts.append(
134+
f'com.thesamet.scalapb:protoc-gen_{protoc_bridge_major}:' +
135+
protoc_bridge_version,
136+
)
137+
120138
if scala_version == max_scala_2_version or is_scala_3:
121139
# Since the Scala 2.13 compiler is included in Scala 3 deps.
122140
root_artifacts.append('org.jline:jline:' + JLINE_VERSION)
@@ -155,18 +173,62 @@ class MavenCoordinates:
155173
version: str
156174
coordinate: str
157175

176+
# The `artifact` with the Scala version suffix stripped
177+
unversioned_artifact: str
178+
179+
# The Scala version suffix stripped from `unversioned_artifact`
180+
scala_version: str
181+
182+
# Canonical name for comparing new and existing artifacts
183+
artifact_name: str
184+
158185
@staticmethod
159-
def new(artifact) -> Self:
186+
def new(coords) -> Self:
160187
"""Creates a new MavenCoordinates from a Maven coordinate string."""
161188
# There are Maven artifacts that contain extra components like `:jar` in
162189
# their coordinates. However, the groupId and artifactId are always the
163190
# first two components, and the version is the last.
164-
parts = artifact.split(':')
165-
return MavenCoordinates(parts[0], parts[1], parts[-1], artifact)
166-
167-
def artifact_name(self):
168-
"""Returns the name to use as a hash key for existing artifacts."""
169-
return f'{self.group}:{self.artifact}'
191+
parts = coords.split(':')
192+
group, artifact, vers = parts[0], parts[1], parts[-1]
193+
194+
# Remove any Scala version suffix from what will become the
195+
# `artifact_name`. This is to avoid consecutive runs of the script
196+
# flipping between the `_2.x` and `_3` versions of some artifacts.
197+
#
198+
# Specifically, there are ScalaPB root artifacts specified by this
199+
# script that end in `_3` yet still transitively depend on artifacts
200+
# ending in `_2.13`. However, some of these transitive dependencies are
201+
# also specified as root artifacts ending in `_3`.
202+
#
203+
# Without trimming the version suffix, the script would see the `_3`
204+
# root artifacts and the `_2.13` transitive dependency artifacts as
205+
# entirely different. However, their computed repository labels would be
206+
# the same, causing one version to replace the other on consecutive
207+
# runs.
208+
artifact_parts = artifact.rsplit('_', 1)
209+
scala_version = ''
210+
211+
if len(artifact_parts) != 1:
212+
version_suffix = artifact_parts[-1]
213+
214+
# "Why does `'2.13'.isdecimal()` return `False`, sir?"
215+
# "Nobody knows."
216+
# See: https://youtu.be/JYqfVE-fykk (couldn't resist!)
217+
if version_suffix.split('.')[0].isdigit():
218+
scala_version = version_suffix
219+
del artifact_parts[-1]
220+
221+
unversioned_artifact = '_'.join(artifact_parts)
222+
artifact_name = f'{group}:{unversioned_artifact}'
223+
return MavenCoordinates(
224+
group,
225+
artifact,
226+
vers,
227+
coords,
228+
unversioned_artifact,
229+
scala_version,
230+
artifact_name,
231+
)
170232

171233
def is_newer_than(self, other):
172234
"""Determines if this artifact is newer than the other.
@@ -185,23 +247,28 @@ def is_newer_than(self, other):
185247
CreateRepositoryError if other doesn't match self.group and
186248
self.artifact
187249
"""
188-
if (self.group != other.group) or (self.artifact != other.artifact):
250+
if self.artifact_name != other.artifact_name:
189251
raise CreateRepositoryError(
190252
f'Expected {self.group}:{self.artifact}, ' +
191253
f'got {other.group}:{other.artifact}'
192254
)
255+
return (
256+
self.__compare_versions(other.scala_version, self.scala_version) or
257+
self.__compare_versions(other.version, self.version)
258+
)
193259

194-
lhs_parts = self.version.split(".")
195-
rhs_parts = other.version.split(".")
260+
def __compare_versions(self, lhs, rhs):
261+
lhs_parts = lhs.split('.')
262+
rhs_parts = rhs.split('.')
196263

197264
for lhs_part, rhs_part in zip(lhs_parts, rhs_parts):
198265
if lhs_part == rhs_part:
199266
continue
200267
if lhs_part.isdecimal() and rhs_part.isdecimal():
201-
return int(rhs_part) < int(lhs_part)
202-
return rhs_part < lhs_part
268+
return int(lhs_part) < int(rhs_part)
269+
return lhs_part < rhs_part
203270

204-
return len(rhs_parts) < len(lhs_parts)
271+
return len(lhs_parts) < len(rhs_parts)
205272

206273

207274
@dataclass
@@ -231,8 +298,7 @@ def get_label(self, coordinates) -> str:
231298
def _get_label_impl(self, coordinates) -> str:
232299
group = coordinates.group
233300
group_label = self._labelize(group)
234-
artifact = self._remove_scala_version_suffix(coordinates.artifact)
235-
artifact_label = self._labelize(artifact)
301+
artifact_label = self._labelize(coordinates.unversioned_artifact)
236302

237303
if group in self._SCALA_LANG_GROUPS:
238304
return self._get_scala_lang_label(artifact_label, coordinates)
@@ -243,7 +309,7 @@ def _get_label_impl(self, coordinates) -> str:
243309
if group in self._SCALA_PROTO_RULES_GROUPS:
244310
return self._get_scala_proto_label(artifact_label, coordinates)
245311

246-
artifact_name = f'{group}:{artifact}'
312+
artifact_name = coordinates.artifact_name
247313

248314
if artifact_name in self._SPECIAL_CASE_ARTIFACT_LABELS:
249315
return self._SPECIAL_CASE_ARTIFACT_LABELS[artifact_name]
@@ -253,14 +319,6 @@ def _get_label_impl(self, coordinates) -> str:
253319
def _labelize(s):
254320
return s.replace('.', '_').replace('-', '_')
255321

256-
@staticmethod
257-
def _remove_scala_version_suffix(artifact):
258-
"""Removes the Scala version suffix from artifact, e.g., scopt_2.13."""
259-
parts = artifact.split('_')
260-
if len(parts) != 1 and parts[-1][0].isdigit():
261-
return '_'.join(parts[:-1])
262-
return artifact
263-
264322
_ARTIFACT_LABEL_ONLY_GROUPS = set([
265323
"com.google.guava",
266324
"com.twitter",
@@ -358,9 +416,9 @@ def resolve_artifacts(
358416

359417
for artifact in artifacts_data['dependencies']:
360418
coords = MavenCoordinates.new(artifact['coord'])
361-
current = current_artifacts_map.get(coords.artifact_name())
419+
current = current_artifacts_map.get(coords.artifact_name)
362420

363-
if coords.artifact_name() in EXCLUDED_ARTIFACTS:
421+
if coords.artifact_name in EXCLUDED_ARTIFACTS:
364422
continue
365423

366424
if current is None or coords.is_newer_than(current.coordinates):
@@ -392,7 +450,7 @@ def _create_current_artifacts_map(original_artifacts):
392450

393451
for metadata in original_artifacts.values():
394452
coordinates = MavenCoordinates.new(metadata['artifact'])
395-
name = coordinates.artifact_name()
453+
name = coordinates.artifact_name
396454

397455
if name not in result and metadata.get('testonly') is not True:
398456
result[name] = ResolvedArtifact(
@@ -409,7 +467,7 @@ def _get_artifact_metadata(self, artifact) -> str:
409467
MavenCoordinates.new(d) for d in artifact['directDependencies']
410468
]
411469
metadata['deps'] = [
412-
d for d in deps if d.artifact_name() not in EXCLUDED_ARTIFACTS
470+
d for d in deps if d.artifact_name not in EXCLUDED_ARTIFACTS
413471
]
414472
with open(artifact['file'], 'rb') as f:
415473
metadata['checksum'] = hashlib.sha256(f.read()).hexdigest()
@@ -530,7 +588,7 @@ def _update_artifact_labels(artifacts, labeler):
530588
for existing_label, metadata in artifacts.items():
531589
coords = MavenCoordinates.new(metadata['artifact'])
532590

533-
if coords.artifact_name() in EXCLUDED_ARTIFACTS:
591+
if coords.artifact_name in EXCLUDED_ARTIFACTS:
534592
continue
535593

536594
label = (

src/scala/scripts/BUILD

+7
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ scala_binary(
2323
],
2424
)
2525

26+
# Used by `scala_proto_toolchain()` to support protoc-bridge < 0.9.8,
27+
# specifically 0.7.14 required by Scala 2.11. See #1647 and
28+
# scalapb/ScalaPB#1771.
29+
#
30+
# If we drop 2.11 support, delete this target and its files, and update
31+
# `scala_proto_toolchain()` (in `scala_proto/scala_proto_toolchain.bzl`) to use
32+
# `scalapb.ScalaPbCodeGenerator` as its `main_generator`.
2633
scala_library(
2734
name = "scalapb_codegenerator_wrapper",
2835
srcs = select_for_scala_version(

src/scala/scripts/ScalaPbCodeGeneratorWrapper.scala

+2-11
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,6 @@ package scripts
33
import protocgen.{CodeGenApp,CodeGenRequest,CodeGenResponse}
44

55
object ScalaPbCodeGenerator extends CodeGenApp {
6-
def process(request: CodeGenRequest): CodeGenResponse = {
7-
try {
8-
scalapb.ScalaPbCodeGenerator.process(request)
9-
10-
} catch {
11-
case e: Throwable =>
12-
val stackStream = new java.io.ByteArrayOutputStream
13-
e.printStackTrace(new java.io.PrintStream(stackStream))
14-
CodeGenResponse.fail(stackStream.toString())
15-
}
16-
}
6+
def process(request: CodeGenRequest): CodeGenResponse =
7+
scalapb.ScalaPbCodeGenerator.process(request)
178
}

test/src/main/scala/scalarules/test/extra_protobuf_generator/ExtraProtobufGenerator.scala

+6-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ class CustomProtobufGenerator(
4343

4444
}
4545

46-
4746
object ExtraProtobufGenerator extends ProtocCodeGenerator {
4847
override def run(req: Array[Byte]): Array[Byte] = {
4948
val b = CodeGeneratorResponse.newBuilder
@@ -58,7 +57,12 @@ object ExtraProtobufGenerator extends ProtocCodeGenerator {
5857
case e: Throwable =>
5958
// Yes, we want to catch _all_ errors and send them back to the
6059
// requestor. Otherwise uncaught errors will cause the generator to
61-
// die and the worker invoking it to hang.
60+
// die and the worker invoking it to hang under protoc-bridge < 0.9.8.
61+
// See #1647 and scalapb/ScalaPB#1771.
62+
//
63+
// Scala 2.11 is stuck at protoc-bridge 0.7.14. If/when we drop
64+
// Scala 2.11 support, we can remove this `catch` block (and elide the
65+
// `ProtobufAdapter` implementation and delete its files).
6266
val stackStream = new java.io.ByteArrayOutputStream
6367
e.printStackTrace(new java.io.PrintStream(stackStream))
6468
b.setError(stackStream.toString())

third_party/repositories/scala_2_12.bzl

+4-4
Original file line numberDiff line numberDiff line change
@@ -815,16 +815,16 @@ artifacts = {
815815
],
816816
},
817817
"scala_proto_rules_scalapb_protoc_bridge": {
818-
"artifact": "com.thesamet.scalapb:protoc-bridge_2.12:0.9.7",
819-
"sha256": "6d039a28d29253ac78aec0e3102f6423d269e65203c114a17f0d52a91d4876f4",
818+
"artifact": "com.thesamet.scalapb:protoc-bridge_2.12:0.9.8",
819+
"sha256": "4af997be5176753aa480ce40cbe9aab89ba659740a1ca6dae660afffb7bb343a",
820820
"deps": [
821821
"@dev_dirs_directories",
822822
"@io_bazel_rules_scala_scala_library",
823823
],
824824
},
825825
"scala_proto_rules_scalapb_protoc_gen": {
826-
"artifact": "com.thesamet.scalapb:protoc-gen_2.12:0.9.7",
827-
"sha256": "81df11e24e52887515dff20eb4d1a050fd58e078200291c3c87fd04218abe53b",
826+
"artifact": "com.thesamet.scalapb:protoc-gen_2.12:0.9.8",
827+
"sha256": "65391bf190ac9cab45674dcd8063893e4bffd4f7289742cad145962b42928648",
828828
"deps": [
829829
"@io_bazel_rules_scala_scala_library",
830830
"@scala_proto_rules_scalapb_protoc_bridge",

third_party/repositories/scala_2_13.bzl

+4-4
Original file line numberDiff line numberDiff line change
@@ -837,16 +837,16 @@ artifacts = {
837837
],
838838
},
839839
"scala_proto_rules_scalapb_protoc_bridge": {
840-
"artifact": "com.thesamet.scalapb:protoc-bridge_2.13:0.9.7",
841-
"sha256": "403f0e7223c8fd052cff0fbf977f3696c387a696a3a12d7b031d95660c7552f5",
840+
"artifact": "com.thesamet.scalapb:protoc-bridge_2.13:0.9.8",
841+
"sha256": "0b3827da2cd9bca867d6963c2a821e7eaff41f5ac3babf671c4c00408bd14a9b",
842842
"deps": [
843843
"@dev_dirs_directories",
844844
"@io_bazel_rules_scala_scala_library",
845845
],
846846
},
847847
"scala_proto_rules_scalapb_protoc_gen": {
848-
"artifact": "com.thesamet.scalapb:protoc-gen_2.13:0.9.7",
849-
"sha256": "f9943ce49261aad80a063c2ce55b01fb62cfd9487ffa2d36a2eade467bc16b23",
848+
"artifact": "com.thesamet.scalapb:protoc-gen_2.13:0.9.8",
849+
"sha256": "cf2b50721952cb4f10ca05a0ed36d7b01b88eb6505a9478556ee5a7af1a21775",
850850
"deps": [
851851
"@io_bazel_rules_scala_scala_library",
852852
"@scala_proto_rules_scalapb_protoc_bridge",

third_party/repositories/scala_3_1.bzl

+4-4
Original file line numberDiff line numberDiff line change
@@ -879,16 +879,16 @@ artifacts = {
879879
],
880880
},
881881
"scala_proto_rules_scalapb_protoc_bridge": {
882-
"artifact": "com.thesamet.scalapb:protoc-bridge_2.13:0.9.7",
883-
"sha256": "403f0e7223c8fd052cff0fbf977f3696c387a696a3a12d7b031d95660c7552f5",
882+
"artifact": "com.thesamet.scalapb:protoc-bridge_2.13:0.9.8",
883+
"sha256": "0b3827da2cd9bca867d6963c2a821e7eaff41f5ac3babf671c4c00408bd14a9b",
884884
"deps": [
885885
"@dev_dirs_directories",
886886
"@io_bazel_rules_scala_scala_library_2",
887887
],
888888
},
889889
"scala_proto_rules_scalapb_protoc_gen": {
890-
"artifact": "com.thesamet.scalapb:protoc-gen_2.13:0.9.7",
891-
"sha256": "f9943ce49261aad80a063c2ce55b01fb62cfd9487ffa2d36a2eade467bc16b23",
890+
"artifact": "com.thesamet.scalapb:protoc-gen_2.13:0.9.8",
891+
"sha256": "cf2b50721952cb4f10ca05a0ed36d7b01b88eb6505a9478556ee5a7af1a21775",
892892
"deps": [
893893
"@io_bazel_rules_scala_scala_library_2",
894894
"@scala_proto_rules_scalapb_protoc_bridge",

0 commit comments

Comments
 (0)