Skip to content

Commit 548bce9

Browse files
ignasljohnynek
authored andcommitted
Fix paths in --proto_path and avoid copying proto files (#850)
* Fix paths in proto_path and avoid copying * Prepare mapping in advance * Condensed all transformations into one method * Added tests * Buildifier corrections
1 parent 177e2ee commit 548bce9

File tree

4 files changed

+59
-19
lines changed

4 files changed

+59
-19
lines changed

src/scala/scripts/PBGenerateRequest.scala

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,30 @@ case class PBGenerateRequest(jarOutput: String, scalaPBOutput: Path, scalaPBArgs
66

77
object PBGenerateRequest {
88

9+
// This little function fixes a problem, where external/com_google_protobuf is not found. The com_google_protobuf
10+
// is special in a way that it also brings-in protoc and also google well-known proto files. This, possibly,
11+
// confuses Bazel and external/com_google_protobuf is not made available for target builds. Actual causes are unknown
12+
// and this fixTransitiveProtoPath fixes this problem in the following way:
13+
// (1) We have a list of all required .proto files; this is a tuple list (root -> full path), for example:
14+
// bazel-out/k8-fastbuild/bin -> bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/source_context.proto
15+
// (2) Convert the full path to relative from the root:
16+
// bazel-out/k8-fastbuild/bin -> external/com_google_protobuf/google/protobuf/source_context.proto
17+
// (3) From all the included protos we find the first one that is located within dir we are processing -- relative
18+
// path starts with the dir we are processing
19+
// (4) If found -- the include folder is "orphan" and is not anchored in either host or target. To fix we prepend
20+
// root. If not found, return original. This works as long as "external/com_google_protobuf" is available in
21+
// target root.
22+
def fixTransitiveProtoPath(includedProto: List[(Path, Path)]): String => String = {
23+
val includedRelProto = includedProto.map { case (root, full) => (root.toString, root.relativize(full).toString) }
24+
25+
{ orig =>
26+
includedRelProto.find { case (_, rel) => rel.startsWith(orig) } match {
27+
case Some((root, _)) => s"$root/$orig"
28+
case None => orig
29+
}
30+
}
31+
}
32+
933
def from(args: java.util.List[String]): PBGenerateRequest = {
1034
val jarOutput = args.get(0)
1135
val protoFiles = args.get(4).split(':')
@@ -23,17 +47,18 @@ object PBGenerateRequest {
2347
case s if s.charAt(0) == '-' => Some(s.tail) //drop padding character
2448
case other => sys.error(s"expected a padding character of - (dash), but found: $other")
2549
}
26-
val transitiveProtoPaths = (args.get(3) match {
50+
51+
val transitiveProtoPaths: List[String] = (args.get(3) match {
2752
case "-" => Nil
2853
case s if s.charAt(0) == '-' => s.tail.split(':').toList //drop padding character
2954
case other => sys.error(s"expected a padding character of - (dash), but found: $other")
30-
}) ++ List(".")
55+
}).map(fixTransitiveProtoPath(includedProto)) ++ List(".")
3156

3257
val tmp = Paths.get(Option(System.getProperty("java.io.tmpdir")).getOrElse("/tmp"))
3358
val scalaPBOutput = Files.createTempDirectory(tmp, "bazelscalapb")
3459
val flagPrefix = flagOpt.fold("")(_ + ":")
3560

36-
val namedGenerators = args.get(6).drop(1).split(',').filter(_.nonEmpty).map { e =>
61+
val namedGenerators = args.get(6).drop(1).split(',').filter(_.nonEmpty).map { e =>
3762
val kv = e.split('=')
3863
(kv(0), kv(1))
3964
}

src/scala/scripts/ScalaPBGenerator.scala

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,6 @@ object ScalaPBWorker extends GenericWorker(new ScalaPBGenerator) {
3434
}
3535

3636
class ScalaPBGenerator extends Processor {
37-
def setupIncludedProto(includedProto: List[(Path, Path)]): Unit = {
38-
includedProto.foreach { case (root, fullPath) =>
39-
require(fullPath.toFile.exists, s"Path $fullPath does not exist, which it should as a dependency of this rule")
40-
val relativePath = root.relativize(fullPath)
41-
42-
relativePath.toFile.getParentFile.mkdirs
43-
Try(Files.copy(fullPath, relativePath)) match {
44-
case Failure(err: FileAlreadyExistsException) =>
45-
Console.println(s"File already exists, skipping: ${err.getMessage}")
46-
case Failure(err) => throw err
47-
case _ => ()
48-
}
49-
}
50-
}
5137
def deleteDir(path: Path): Unit =
5238
try DeleteRecursively.run(path)
5339
catch {
@@ -56,8 +42,6 @@ class ScalaPBGenerator extends Processor {
5642

5743
def processRequest(args: java.util.List[String]) {
5844
val extractRequestResult = PBGenerateRequest.from(args)
59-
setupIncludedProto(extractRequestResult.includedProto)
60-
6145
val extraClassesClassLoader = new URLClassLoader(extractRequestResult.extraJars.map { e =>
6246
val f = e.toFile
6347
require(f.exists, s"Expected file for classpath loading $f to exist")
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
load("//scala:scala.bzl", "scala_library", "scala_specs2_junit_test")
2+
load("//scala:scala_import.bzl", "scala_import")
3+
4+
scala_specs2_junit_test(
5+
name = "pb_generate_request_test",
6+
size = "small",
7+
srcs = ["PBGenerateRequestTest.scala"],
8+
suffixes = ["Test"],
9+
deps = ["//src/scala/scripts:scala_proto_request_extractor"],
10+
)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package scalarules.test.scripts
2+
3+
import java.nio.file.Paths
4+
import scripts.PBGenerateRequest
5+
import org.specs2.mutable.SpecWithJUnit
6+
7+
class PBGenerateRequestTest extends SpecWithJUnit {
8+
"fixTransitiveProtoPath should fix path when included proto is available, ignore otherwise" >> {
9+
val includedProtos = List(Paths.get("a/b/c") -> Paths.get("a/b/c/d/e/f.proto"))
10+
Seq("d/e", "x/y/z").map(PBGenerateRequest.fixTransitiveProtoPath(includedProtos)) must
11+
beEqualTo(Seq("a/b/c/d/e", "x/y/z"))
12+
}
13+
14+
"actual case observed in builds" >> {
15+
val includedProtos = List(
16+
Paths.get("bazel-out/k8-fastbuild/bin") ->
17+
Paths.get("bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/source_context.proto"))
18+
Seq("external/com_google_protobuf").map(PBGenerateRequest.fixTransitiveProtoPath(includedProtos)) must
19+
beEqualTo(Seq("bazel-out/k8-fastbuild/bin/external/com_google_protobuf"))
20+
}
21+
}

0 commit comments

Comments
 (0)