Skip to content

Commit 4e8e912

Browse files
author
Armin Motekalem
committed
scalapb-support-java-generation
1 parent 89604d3 commit 4e8e912

File tree

3 files changed

+86
-36
lines changed

3 files changed

+86
-36
lines changed

contrib/scalapblib/src/mill/contrib/scalapblib/ScalaPBModule.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ trait ScalaPBModule extends ScalaModule {
2222

2323
def scalaPBVersion: T[String]
2424

25+
def scalaPBGenerators: T[Seq[Generator]] = Seq[Generator](ScalaGen)
26+
2527
def scalaPBFlatPackage: T[Boolean] = Task { false }
2628

2729
def scalaPBJavaConversions: T[Boolean] = Task { false }
@@ -141,7 +143,8 @@ trait ScalaPBModule extends ScalaModule {
141143
scalaPBSources().map(_.path),
142144
scalaPBOptions(),
143145
Task.dest,
144-
scalaPBCompileOptions()
146+
scalaPBCompileOptions(),
147+
scalaPBGenerators()
145148
)
146149
}
147150
}

contrib/scalapblib/src/mill/contrib/scalapblib/ScalaPBWorker.scala

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import java.io.File
55

66
import mill.api.PathRef
77
import mill.api.{Discover, ExternalModule}
8+
import upickle.default.ReadWriter
89

910
class ScalaPBWorker {
1011

@@ -15,16 +16,17 @@ class ScalaPBWorker {
1516
sources: Seq[File],
1617
scalaPBOptions: String,
1718
generatedDirectory: File,
18-
otherArgs: Seq[String]
19+
otherArgs: Seq[String],
20+
generators: Seq[Generator]
1921
): Unit = {
2022
val pbcClasspath = scalaPBClasspath.map(_.path).toVector
2123
mill.util.Jvm.withClassLoader(pbcClasspath, null) { cl =>
2224
val scalaPBCompilerClass = cl.loadClass("scalapb.ScalaPBC")
2325
val mainMethod = scalaPBCompilerClass.getMethod("main", classOf[Array[java.lang.String]])
24-
val opts = if (scalaPBOptions.isEmpty) "" else scalaPBOptions + ":"
25-
val args = otherArgs ++ Seq(
26-
s"--scala_out=${opts}${generatedDirectory.getCanonicalPath}"
27-
) ++ roots.map(root => s"--proto_path=${root.getCanonicalPath}") ++ sources.map(
26+
val args = otherArgs ++ generators.map { gen =>
27+
val opts = if (scalaPBOptions.isEmpty || !gen.supportsScalaPBOptions) "" else scalaPBOptions + ":"
28+
s"${gen.generator}=$opts${generatedDirectory.getCanonicalPath}"
29+
} ++ roots.map(root => s"--proto_path=${root.getCanonicalPath}") ++ sources.map(
2830
_.getCanonicalPath
2931
)
3032
ctx.log.debug(s"ScalaPBC args: ${args.mkString(" ")}")
@@ -70,7 +72,8 @@ class ScalaPBWorker {
7072
scalaPBSources: Seq[os.Path],
7173
scalaPBOptions: String,
7274
dest: os.Path,
73-
scalaPBCExtraArgs: Seq[String]
75+
scalaPBCExtraArgs: Seq[String],
76+
generators: Seq[Generator]
7477
)(implicit ctx: mill.api.TaskCtx): mill.api.Result[PathRef] = {
7578
val compiler = scalaPB(scalaPBClasspath)
7679
val sources = scalaPBSources.flatMap {
@@ -86,7 +89,7 @@ class ScalaPBWorker {
8689
Seq(ioFile)
8790
}
8891
val roots = scalaPBSources.map(_.toIO).filter(_.isDirectory)
89-
compiler.compileScalaPB(roots, sources, scalaPBOptions, dest.toIO, scalaPBCExtraArgs)
92+
compiler.compileScalaPB(roots, sources, scalaPBOptions, dest.toIO, scalaPBCExtraArgs, generators)
9093
mill.api.Result.Success(PathRef(dest))
9194
}
9295
}
@@ -97,10 +100,24 @@ trait ScalaPBWorkerApi {
97100
source: Seq[File],
98101
scalaPBOptions: String,
99102
generatedDirectory: File,
100-
otherArgs: Seq[String]
103+
otherArgs: Seq[String],
104+
generators: Seq[Generator]
101105
): Unit
102106
}
103107

108+
sealed trait Generator derives ReadWriter {
109+
def generator: String
110+
def supportsScalaPBOptions: Boolean
111+
}
112+
case object ScalaGen extends Generator {
113+
override def generator: String = "--scala_out"
114+
override def supportsScalaPBOptions: Boolean = true
115+
}
116+
case object JavaGen extends Generator {
117+
override def generator: String = "--java_out"
118+
override def supportsScalaPBOptions: Boolean = false // Java options are specified directly in the proto file
119+
}
120+
104121
object ScalaPBWorkerApi extends ExternalModule {
105122
def scalaPBWorker: Worker[ScalaPBWorker] = Task.Worker { new ScalaPBWorker() }
106123
lazy val millDiscover = Discover[this.type]

contrib/scalapblib/test/src/mill/contrib/scalapblib/TutorialTests.scala

Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import utest.{TestSuite, Tests, assert, *}
1111
object TutorialTests extends TestSuite {
1212
val testScalaPbVersion = "0.11.7"
1313

14-
trait TutorialBase extends TestRootModule
14+
trait TutorialBase extends TestRootModule {
15+
val core: TutorialModule
16+
}
1517

1618
trait TutorialModule extends ScalaPBModule {
1719
def scalaVersion = sys.props.getOrElse("TEST_SCALA_2_12_VERSION", ???)
@@ -70,19 +72,68 @@ object TutorialTests extends TestSuite {
7072
lazy val millDiscover = Discover[this.type]
7173
}
7274

75+
object TutorialWithJavaGen extends TutorialBase {
76+
object core extends TutorialModule {
77+
override def scalaPBGenerators = Seq(JavaGen)
78+
}
79+
80+
lazy val millDiscover = Discover[this.type]
81+
}
82+
83+
object TutorialWithScalaAndJavaGen extends TutorialBase {
84+
object core extends TutorialModule {
85+
override def scalaPBGenerators = Seq[Generator](ScalaGen, JavaGen)
86+
}
87+
88+
lazy val millDiscover = Discover[this.type]
89+
}
90+
7391
val resourcePath: os.Path = os.Path(sys.env("MILL_TEST_RESOURCE_DIR"))
7492

7593
def protobufOutPath(eval: UnitTester): os.Path =
7694
eval.outPath / "core/compileScalaPB.dest/com/example/tutorial"
7795

78-
def compiledSourcefiles: Seq[os.RelPath] = Seq[os.RelPath](
96+
def compiledScalaSourcefiles: Seq[os.RelPath] = Seq[os.RelPath](
7997
os.rel / "AddressBook.scala",
8098
os.rel / "Person.scala",
8199
os.rel / "TutorialProto.scala",
82100
os.rel / "Include.scala",
83101
os.rel / "IncludeProto.scala"
84102
)
85103

104+
def compiledJavaSourcefiles: Seq[os.RelPath] = Seq[os.RelPath](
105+
os.rel / "AddressBookProtos.java",
106+
os.rel / "IncludeOuterClass.java"
107+
)
108+
109+
// Helper function to test compilation with different generators
110+
def testCompilation(
111+
module: TutorialBase,
112+
expectedFiles: Seq[os.RelPath]
113+
): Unit = {
114+
UnitTester(module, resourcePath).scoped { eval =>
115+
if (!mill.constants.Util.isWindows) {
116+
val Right(result) = eval.apply(module.core.compileScalaPB): @unchecked
117+
118+
val outPath = protobufOutPath(eval)
119+
val outputFiles = os.walk(result.value.path).filter(os.isFile)
120+
val expectedSourcefiles = expectedFiles.map(outPath / _)
121+
122+
assert(
123+
result.value.path == eval.outPath / "core/compileScalaPB.dest",
124+
outputFiles.nonEmpty,
125+
outputFiles.forall(expectedSourcefiles.contains),
126+
outputFiles.size == outputFiles.size,
127+
result.evalCount > 0
128+
)
129+
130+
// don't recompile if nothing changed
131+
val Right(result2) = eval.apply(module.core.compileScalaPB): @unchecked
132+
assert(result2.evalCount == 0)
133+
}
134+
}
135+
}
136+
86137
def tests: Tests = Tests {
87138
test("scalapbVersion") {
88139

@@ -97,30 +148,9 @@ object TutorialTests extends TestSuite {
97148
}
98149

99150
test("compileScalaPB") {
100-
test("calledDirectly") - UnitTester(Tutorial, resourcePath).scoped { eval =>
101-
if (!mill.constants.Util.isWindows) {
102-
val Right(result) = eval.apply(Tutorial.core.compileScalaPB): @unchecked
103-
104-
val outPath = protobufOutPath(eval)
105-
106-
val outputFiles = os.walk(result.value.path).filter(os.isFile)
107-
108-
val expectedSourcefiles = compiledSourcefiles.map(outPath / _)
109-
110-
assert(
111-
result.value.path == eval.outPath / "core/compileScalaPB.dest",
112-
outputFiles.nonEmpty,
113-
outputFiles.forall(expectedSourcefiles.contains),
114-
outputFiles.size == 5,
115-
result.evalCount > 0
116-
)
117-
118-
// don't recompile if nothing changed
119-
val Right(result2) = eval.apply(Tutorial.core.compileScalaPB): @unchecked
120-
121-
assert(result2.evalCount == 0)
122-
}
123-
}
151+
test("scalaGen") - testCompilation(Tutorial, compiledScalaSourcefiles)
152+
test("javaGen") - testCompilation(TutorialWithJavaGen, compiledJavaSourcefiles)
153+
test("scalaAndJavaGen") - testCompilation(TutorialWithScalaAndJavaGen, compiledScalaSourcefiles ++ compiledJavaSourcefiles)
124154

125155
test("calledWithSpecificFile") - UnitTester(
126156
TutorialWithSpecificSources,
@@ -165,7 +195,7 @@ object TutorialTests extends TestSuite {
165195
//
166196
// // val outputFiles = os.walk(outPath).filter(_.isFile)
167197
//
168-
// // val expectedSourcefiles = compiledSourcefiles.map(outPath / _)
198+
// // val expectedSourcefiles = compiledScalaSourcefiles.map(outPath / _)
169199
//
170200
// // assert(
171201
// // outputFiles.nonEmpty,

0 commit comments

Comments
 (0)