Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make evictions possible for transitive deps of sandboxed gens #157

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions bridge/src/main/scala/protocbridge/Generator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ final case class JvmGenerator(name: String, gen: ProtocCodeGenerator)
* risk of conflict.
*
* artifact: Artifact containing the generator class.
* extraArtifacts: Artifacts to be resolved together with the main Artifact (potentially causing eviction)
* resolver: Using a ClassLoader, return a new instance of a ProtocCodeGenerator.
*/
final case class SandboxedJvmGenerator private (
name: String,
artifact: Artifact,
extraArtifacts: Seq[Artifact],
suggestedDependencies: Seq[Artifact],
resolver: ClassLoader => ProtocCodeGenerator
) extends Generator {
Expand All @@ -58,9 +60,40 @@ final case class SandboxedJvmGenerator private (
this(
name,
artifact,
Nil,
suggestedDependencies,
SandboxedJvmGenerator.load(generatorClass, _)
)

// kept for binary compatiblity with 0.9.1
private[protocbridge] def this(
name: String,
artifact: Artifact,
suggestedDependencies: Seq[Artifact],
resolver: ClassLoader => ProtocCodeGenerator
) =
this(
name,
artifact,
Nil,
suggestedDependencies,
resolver
)

// kept for binary compatiblity with 0.9.1
private[protocbridge] def copy(
name: String = name,
artifact: Artifact = artifact,
suggestedDependencies: Seq[Artifact] = suggestedDependencies,
resolver: ClassLoader => ProtocCodeGenerator = resolver
): SandboxedJvmGenerator =
SandboxedJvmGenerator(
name,
artifact,
extraArtifacts,
suggestedDependencies,
resolver
)
}

object SandboxedJvmGenerator {
Expand All @@ -75,6 +108,23 @@ object SandboxedJvmGenerator {
SandboxedJvmGenerator(
name,
artifact,
Nil,
suggestedDependencies,
SandboxedJvmGenerator.load(generatorClass, _)
)

/** Instantiates a SandboxedJvmGenerator that loads an object named generatorClass */
def forModule(
name: String,
artifact: Artifact,
extraArtifacts: Seq[Artifact],
generatorClass: String,
suggestedDependencies: Seq[Artifact]
): SandboxedJvmGenerator =
SandboxedJvmGenerator(
name,
artifact,
extraArtifacts,
suggestedDependencies,
SandboxedJvmGenerator.load(generatorClass, _)
)
Expand All @@ -87,10 +137,27 @@ object SandboxedJvmGenerator {
resolver: ClassLoader => ProtocCodeGenerator
): SandboxedJvmGenerator =
SandboxedJvmGenerator(
name,
artifact,
Nil,
suggestedDependencies,
resolver
)

/** Instantiates a SandboxedJvmGenerator that uses a class loader to load a generator */
def forResolver(
name: String,
artifact: Artifact,
extraArtifacts: Seq[Artifact],
suggestedDependencies: Seq[Artifact],
resolver: ClassLoader => ProtocCodeGenerator
): SandboxedJvmGenerator =
SandboxedJvmGenerator(
name,
artifact,
extraArtifacts,
suggestedDependencies,
resolver
)

// kept for binary compatiblity with 0.9.0-RC1
Expand All @@ -107,6 +174,21 @@ object SandboxedJvmGenerator {
suggestedDependencies
)

// kept for binary compatiblity with 0.9.1
@deprecated("use the overload with extraArtifacts", "0.9.2")
def apply(
name: String,
artifact: Artifact,
suggestedDependencies: Seq[Artifact],
resolver: ClassLoader => ProtocCodeGenerator
): SandboxedJvmGenerator =
forResolver(
name,
artifact,
suggestedDependencies,
resolver
)

def load(
generatorClass: String,
loader: ClassLoader
Expand Down
43 changes: 35 additions & 8 deletions bridge/src/main/scala/protocbridge/ProtocBridge.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,62 @@ object ProtocBridge {

/** Runs protoc with a given set of targets.
*
* @param classLoader function that provided a sandboxed ClassLoader for a set of artifacts.
* @param protoc a function that runs protoc with the given command line arguments.
* @param targets a sequence of generators to invokes
* @param params a sequence of additional params to pass to protoc
* @param classLoader function that provided a sandboxed ClassLoader for an artifact.
* @tparam A
* @return the return value from the protoc function.
*/
def execute[ExitCode](
classLoader: Seq[Artifact] => ClassLoader,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to change the parameter order as the Java signature of the overloads would be the same otherwise due to type erasure on Function1

protoc: ProtocRunner[ExitCode],
targets: Seq[Target],
params: Seq[String]
): ExitCode =
execute(
protoc,
targets,
params,
PluginFrontend.newInstance,
Right(classLoader)
)

@deprecated(
"use the overload with a classLoader parameter accepting several artifacts",
"0.9.2"
)
def execute[ExitCode](
protoc: ProtocRunner[ExitCode],
targets: Seq[Target],
params: Seq[String],
classLoader: Artifact => ClassLoader
): ExitCode =
execute(protoc, targets, params, PluginFrontend.newInstance, classLoader)
execute(
protoc,
targets,
params,
PluginFrontend.newInstance,
Left(classLoader)
)

private[protocbridge] def execute[ExitCode](
protoc: ProtocRunner[ExitCode],
targets: Seq[Target],
params: Seq[String],
pluginFrontend: PluginFrontend,
classLoader: Artifact => ClassLoader
classLoader: Either[Artifact => ClassLoader, Seq[Artifact] => ClassLoader]
): ExitCode = {

// The same JvmGenerator might be passed several times, but requires separate frontends
val targetsSuffixed = targets.zipWithIndex.map {
case (t @ Target(gen: JvmGenerator, _, _), i) =>
t.copy(generator = gen.copy(name = s"${gen.name}_$i"))
case (t @ Target(gen: SandboxedJvmGenerator, _, _), i) =>
val codeGen =
gen.resolver(classLoader(gen.artifact))
val cl = classLoader match {
case Left(single) => single(gen.artifact)
case Right(multi) => multi(gen.artifact +: gen.extraArtifacts)
}
val codeGen = gen.resolver(cl)
t.copy(generator =
JvmGenerator(name = codeGen.name + s"_$i", gen = codeGen)
)
Expand Down Expand Up @@ -78,11 +104,12 @@ object ProtocBridge {
targets,
params,
pluginFrontend,
(art: Artifact) =>
Left((art: Artifact) =>
throw new RuntimeException(
s"Unale to load sandboxed plugin for ${art} since ClassLoader was not provided. If " +
"using sbt-protoc, please update to version 1.0.0-RC5 or later."
)
)
)

private[protocbridge] def execute[ExitCode](
Expand Down Expand Up @@ -219,7 +246,7 @@ object ProtocBridge {
targets,
params,
pluginFrontend,
classLoader
Left(classLoader)
)

@deprecated(
Expand Down