Skip to content

Commit

Permalink
Merge pull request #202 from thesamet/master
Browse files Browse the repository at this point in the history
Update ScalaPB to 0.10.6 and switch to sandboxed classloader.
  • Loading branch information
rossabaker authored Jun 22, 2020
2 parents 064e040 + 3503c78 commit 00615e1
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 80 deletions.
17 changes: 13 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,15 @@ lazy val root = project
</developers>
}
)
.aggregate(`sbt-java-gen`, `java-runtime`)
.aggregate(`java-gen`, `sbt-java-gen`, `java-runtime`)

lazy val `java-gen` = project
.enablePlugins(GitVersioning)
.settings(
scalaVersion := "2.12.11",
publishTo := sonatypePublishToBundle.value,
libraryDependencies += scalaPbCompiler
)

lazy val `sbt-java-gen` = project
.enablePlugins(GitVersioning, BuildInfoPlugin)
Expand All @@ -48,10 +56,11 @@ lazy val `sbt-java-gen` = project
scalaVersion,
sbtVersion,
organization,
"grpcVersion" -> versions.grpc
"grpcVersion" -> versions.grpc,
"codeGeneratorName" -> (name in `java-gen`).value
),
addSbtPlugin(sbtProtoc),
libraryDependencies += scalaPbCompiler
libraryDependencies += scalaPbCompiler,
addSbtPlugin(sbtProtoc)
)

lazy val `java-runtime` = project
Expand Down
83 changes: 83 additions & 0 deletions java-gen/src/main/scala/Fs2CodeGenerator.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package org.lyranthe.fs2_grpc.java_runtime.sbt_gen

import com.google.protobuf.Descriptors.FileDescriptor
import com.google.protobuf.ExtensionRegistry
import com.google.protobuf.compiler.PluginProtos
import com.google.protobuf.compiler.PluginProtos.{CodeGeneratorRequest, CodeGeneratorResponse}
import protocbridge.ProtocCodeGenerator
import scalapb.compiler.{FunctionalPrinter, GeneratorException, DescriptorImplicits, GeneratorParams}
import scalapb.options.compiler.Scalapb
import scala.collection.JavaConverters._

case class Fs2Params(serviceSuffix: String = "Fs2Grpc")

object Fs2CodeGenerator extends ProtocCodeGenerator {

def generateServiceFiles(
file: FileDescriptor,
fs2params: Fs2Params,
di: DescriptorImplicits
): Seq[PluginProtos.CodeGeneratorResponse.File] = {
file.getServices.asScala.map { service =>
val p = new Fs2GrpcServicePrinter(service, fs2params.serviceSuffix, di)

import di.{ServiceDescriptorPimp, FileDescriptorPimp}
val code = p.printService(FunctionalPrinter()).result()
val b = CodeGeneratorResponse.File.newBuilder()
b.setName(file.scalaDirectory + "/" + service.name + s"${fs2params.serviceSuffix}.scala")
b.setContent(code)
println(b.getName)
b.build
}
}

private def parseParameters(params: String): Either[String, (GeneratorParams, Fs2Params)] =
for {
paramsAndUnparsed <- GeneratorParams.fromStringCollectUnrecognized(params)
params = paramsAndUnparsed._1
unparsed = paramsAndUnparsed._2
suffix <- unparsed.map(_.split("=", 2).toList).foldLeft[Either[String, Fs2Params]](Right(Fs2Params())) {
case (Right(params), ServiceSuffix :: suffix :: Nil) => Right(params.copy(serviceSuffix = suffix))
case (Right(_), xs) => Left(s"Unrecognized parameter: $xs")
case (Left(e), _) => Left(e)
}
} yield (params, suffix)

def handleCodeGeneratorRequest(request: PluginProtos.CodeGeneratorRequest): PluginProtos.CodeGeneratorResponse = {
val b = CodeGeneratorResponse.newBuilder
parseParameters(request.getParameter()) match {
case Right((params, fs2params)) =>
try {
val filesByName: Map[String, FileDescriptor] =
request.getProtoFileList.asScala.foldLeft[Map[String, FileDescriptor]](Map.empty) {
case (acc, fp) =>
val deps = fp.getDependencyList.asScala.map(acc)
acc + (fp.getName -> FileDescriptor.buildFrom(fp, deps.toArray))
}

val implicits = new DescriptorImplicits(params, filesByName.values.toVector)
val genFiles = request.getFileToGenerateList.asScala.map(filesByName)
val srvFiles = genFiles.flatMap(generateServiceFiles(_, fs2params, implicits))
b.addAllFile(srvFiles.asJava)
} catch {
case e: GeneratorException =>
b.setError(e.message)
}

case Left(error) =>
b.setError(error)
}

b.build()
}

override def run(req: Array[Byte]): Array[Byte] = {
println("Running")
val registry = ExtensionRegistry.newInstance()
Scalapb.registerAllExtensions(registry)
val request = CodeGeneratorRequest.parseFrom(req, registry)
handleCodeGeneratorRequest(request).toByteArray
}

private[fs2_grpc] val ServiceSuffix: String = "serviceSuffix"
}
2 changes: 1 addition & 1 deletion project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ object Dependencies {
val minitest = "2.8.2"

val kindProjector = "0.10.3"
val sbtProtoc = "0.99.28"
val sbtProtoc = "0.99.34"

}

Expand Down
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.7.0")

addSbtPlugin("io.github.davidgregory084" % "sbt-tpolecat" % "0.1.12")

libraryDependencies += "com.thesamet.scalapb" %% "compilerplugin" % "0.10.4"
libraryDependencies += "com.thesamet.scalapb" %% "compilerplugin" % "0.10.6"
90 changes: 16 additions & 74 deletions sbt-java-gen/src/main/scala/Fs2GrpcPlugin.scala
Original file line number Diff line number Diff line change
@@ -1,84 +1,15 @@
package org.lyranthe.fs2_grpc.java_runtime.sbt_gen

import com.google.protobuf.Descriptors.FileDescriptor
import com.google.protobuf.ExtensionRegistry
import com.google.protobuf.compiler.PluginProtos
import com.google.protobuf.compiler.PluginProtos.{CodeGeneratorRequest, CodeGeneratorResponse}
import org.lyranthe.fs2_grpc.java_runtime.sbt_gen.Fs2GrpcPlugin.autoImport.scalapbCodeGenerators
import protocbridge.{Artifact, JvmGenerator, ProtocCodeGenerator, Target}
import protocbridge.{Artifact, Generator, SandboxedJvmGenerator, Target}
import sbt._
import sbt.Keys._
import sbt.plugins.JvmPlugin
import sbtprotoc.ProtocPlugin.autoImport.PB
import scalapb.compiler.{FunctionalPrinter, GeneratorException, DescriptorImplicits, ProtobufGenerator}
import scalapb.options.compiler.Scalapb
import scala.collection.JavaConverters._
import org.lyranthe.fs2_grpc.buildinfo.BuildInfo

sealed trait CodeGeneratorOption extends Product with Serializable

class Fs2CodeGenerator(serviceSuffix: String) extends ProtocCodeGenerator {

def generateServiceFiles(
file: FileDescriptor,
di: DescriptorImplicits
): Seq[PluginProtos.CodeGeneratorResponse.File] = {
file.getServices.asScala.map { service =>
val p = new Fs2GrpcServicePrinter(service, serviceSuffix, di)

import di.{ServiceDescriptorPimp, FileDescriptorPimp}
val code = p.printService(FunctionalPrinter()).result()
val b = CodeGeneratorResponse.File.newBuilder()
b.setName(file.scalaDirectory + "/" + service.name + s"$serviceSuffix.scala")
b.setContent(code)
println(b.getName)
b.build
}
}

def handleCodeGeneratorRequest(request: PluginProtos.CodeGeneratorRequest): PluginProtos.CodeGeneratorResponse = {
val b = CodeGeneratorResponse.newBuilder
ProtobufGenerator.parseParameters(request.getParameter) match {
case Right(params) =>
try {

val filesByName: Map[String, FileDescriptor] =
request.getProtoFileList.asScala.foldLeft[Map[String, FileDescriptor]](Map.empty) {
case (acc, fp) =>
val deps = fp.getDependencyList.asScala.map(acc)
acc + (fp.getName -> FileDescriptor.buildFrom(fp, deps.toArray))
}

val implicits = new DescriptorImplicits(params, filesByName.values.toVector)
val genFiles = request.getFileToGenerateList.asScala.map(filesByName)
val srvFiles = genFiles.flatMap(generateServiceFiles(_, implicits))
b.addAllFile(srvFiles.asJava)
} catch {
case e: GeneratorException =>
b.setError(e.message)
}

case Left(error) =>
b.setError(error)
}

b.build()
}

override def run(req: Array[Byte]): Array[Byte] = {
println("Running")
val registry = ExtensionRegistry.newInstance()
Scalapb.registerAllExtensions(registry)
val request = CodeGeneratorRequest.parseFrom(req, registry)
handleCodeGeneratorRequest(request).toByteArray
}

override def suggestedDependencies: Seq[Artifact] =
Seq(
Artifact("com.thesamet.scalapb", "scalapb-runtime", scalapb.compiler.Version.scalapbVersion, crossVersion = true)
)
}

object Fs2Grpc extends AutoPlugin {
override def requires: Plugins = Fs2GrpcPlugin
override def trigger: PluginTrigger = NoTrigger
Expand Down Expand Up @@ -124,14 +55,13 @@ object Fs2GrpcPlugin extends AutoPlugin {
settingKey[String](
"Suffix used for generated service, e.g. service `Foo` with suffix `Fs2Grpc` results in `FooFs2Grpc`"
)

}
import autoImport._

override def requires = sbtprotoc.ProtocPlugin && JvmPlugin
override def trigger = NoTrigger

def convertOptionsToScalapbGen(options: Set[CodeGeneratorOption]): (JvmGenerator, Seq[String]) = {
def convertOptionsToScalapbGen(options: Set[CodeGeneratorOption]): (Generator, Seq[String]) = {
scalapb.gen(
flatPackage = options(CodeGeneratorOption.FlatPackage),
javaConversions = options(CodeGeneratorOption.JavaConversions),
Expand All @@ -141,6 +71,8 @@ object Fs2GrpcPlugin extends AutoPlugin {
)
}

private def codegenScalaBinaryVersion = CrossVersion.binaryScalaVersion(BuildInfo.scalaVersion)

override def projectSettings: Seq[Def.Setting[_]] =
List(
fs2GrpcServiceSuffix := "Fs2Grpc",
Expand All @@ -153,8 +85,18 @@ object Fs2GrpcPlugin extends AutoPlugin {
Option(
Target(
(
JvmGenerator("scala-fs2-grpc", new Fs2CodeGenerator(fs2GrpcServiceSuffix.value)),
scalapbCodeGeneratorOptions.value.filterNot(_ == CodeGeneratorOption.Fs2Grpc).map(_.toString)
SandboxedJvmGenerator.forModule(
"scala-fs2-grpc",
Artifact(
BuildInfo.organization,
s"${BuildInfo.codeGeneratorName}_$codegenScalaBinaryVersion",
BuildInfo.version
),
"org.lyranthe.fs2_grpc.java_runtime.sbt_gen.Fs2CodeGenerator$",
Nil
),
scalapbCodeGeneratorOptions.value.filterNot(_ == CodeGeneratorOption.Fs2Grpc).map(_.toString) :+
s"serviceSuffix=${fs2GrpcServiceSuffix.value}"
),
(sourceManaged in Compile).value / "fs2-grpc"
)
Expand Down

0 comments on commit 00615e1

Please sign in to comment.