11import sbt ._
22import sbt .Keys ._
33import sbt .Keys .streams
4-
54import sbtprotoc .ProtocPlugin
65import ProtocPlugin .autoImport .PB
76import akka .grpc .sbt .AkkaGrpcPlugin
87import akka .grpc .sbt .AkkaGrpcPlugin .autoImport ._
98import sbt .internal .inc .classpath .ClasspathUtilities
109
10+ import java .nio .file .{ Files , Path , Paths }
11+
1112/**
1213 * A plugin that allows to use a code generator compiled in one subproject to be used in a test project
1314 */
@@ -16,6 +17,10 @@ object ReflectiveCodeGen extends AutoPlugin {
1617 override def requires = AkkaGrpcPlugin
1718 override def trigger = noTrigger
1819
20+ val copyUnmanagedSources =
21+ settingKey[Boolean ](
22+ " Flag to determine if code generation should copy generated unmanaged resources to the sourceDirectory directory if missing" )
23+
1924 override def projectSettings =
2025 Seq (
2126 Compile / akkaGrpcGeneratedLanguages := Seq (AkkaGrpc .Java ),
@@ -25,8 +30,9 @@ object ReflectiveCodeGen extends AutoPlugin {
2530 def runAkkaServerlessCodegen (
2631 classpath : Classpath ,
2732 protobufDescriptor : File ,
33+ srcDir : File ,
2834 genSrcDir : File ,
29- testSrcManaged : File ,
35+ genTestSrcDir : File ,
3036 logger : Logger ): Seq [File ] = {
3137
3238 val cp = classpath.map(_.data)
@@ -41,24 +47,24 @@ object ReflectiveCodeGen extends AutoPlugin {
4147 |import com.lightbend.akkasls.codegen.java.SourceGenerator
4248 |import scala.collection.immutable
4349 |
44- |(protobufDescriptor: java.io.File, genSrcDir: java.io.File, genTestSrcDir: java.io.File, logger: sbt.util.Logger) => {
45- |
50+ |(protobufDescriptor: java.io.File, srcDir: java.io.File, genSrcDir: java.io.File, genTestSrcDir: java.io.File, logger: sbt.util.Logger) => {
51+ |
4652 | val path = genSrcDir.toPath
4753 | val testPath = genTestSrcDir.toPath
48- |
54+ |
4955 | implicit val codegenLog = new com.lightbend.akkasls.codegen.Log {
5056 | override def debug(message: String): Unit = logger.debug(message)
5157 | override def info(message: String): Unit = logger.info(message)
5258 | }
53- |
59+ |
5460 | SourceGenerator
55- | .generate(protobufDescriptor, path , testPath, testPath, path, testPath, "com.example.Main")
61+ | .generate(protobufDescriptor, srcDir.toPath , testPath, testPath, path, testPath, "com.example.Main")
5662 | .map(_.toFile).to[immutable.Seq]
57- |}
63+ |}
5864 """ .stripMargin
5965
60- val generatorsF = tb.eval(tb.parse(source)).asInstanceOf [(File , File , File , sbt.util.Logger ) => Seq [File ]]
61- generatorsF(protobufDescriptor, genSrcDir, testSrcManaged , logger)
66+ val generatorsF = tb.eval(tb.parse(source)).asInstanceOf [(File , File , File , File , sbt.util.Logger ) => Seq [File ]]
67+ generatorsF(protobufDescriptor, srcDir, genSrcDir, genTestSrcDir , logger)
6268
6369 }
6470
@@ -68,23 +74,75 @@ object ReflectiveCodeGen extends AutoPlugin {
6874 val cp = (ProjectRef (file(" ." ), " codegenJava" ) / Compile / fullClasspath).value
6975 val srcManaged = (Compile / sourceManaged).value
7076 val testSrcManaged = (Test / sourceManaged).value
77+ val tmpUnmanaged = (Compile / temporaryUnmanagedDirectory).value
7178 val sbtLogger = streams.value.log
72- runAkkaServerlessCodegen(cp, protobufDescriptorSetOut.value, srcManaged, testSrcManaged, sbtLogger)
79+ val generatedFiles =
80+ runAkkaServerlessCodegen(
81+ cp,
82+ protobufDescriptorSetOut.value,
83+ tmpUnmanaged,
84+ srcManaged,
85+ testSrcManaged,
86+ sbtLogger)
87+
88+ if ((Compile / copyUnmanagedSources).value) // in this case use the files in the unmanaged source tree
89+ generatedFiles.filterNot(_.getCanonicalPath.startsWith(tmpUnmanaged.getCanonicalPath))
90+ else
91+ generatedFiles // use files directly from the
7392 }
7493 .dependsOn(Compile / PB .generate)
7594
7695 lazy val protobufDescriptorSetOut = settingKey[File ](" The file to write the protobuf descriptor set to" )
96+ lazy val temporaryUnmanagedDirectory = settingKey[File ](" Directory to generate 'unmanaged' sources into" )
97+ val generateUnmanaged = taskKey[Seq [File ]](
98+ " Generate \" unmanaged\" akkaserverless scaffolding code based on the available .proto definitions.\n " +
99+ " These are the source files that are placed in the source tree, and after initial generation should typically be maintained by the user.\n " +
100+ " Files that already exist they are not re-generated." )
101+
77102 lazy val attachProtobufDescriptorSets = Seq (
78103 protobufDescriptorSetOut := (Compile / resourceManaged).value / " protobuf" / " descriptor-sets" / " user-function.desc" ,
79104 Compile / PB .generate := (Compile / PB .generate)
80105 .dependsOn(Def .task {
81106 protobufDescriptorSetOut.value.getParentFile.mkdirs()
82107 })
83108 .value,
109+ Compile / temporaryUnmanagedDirectory := (Compile / baseDirectory).value / " target" / " akkaserverless-unmanaged" ,
84110 Compile / PB .protocOptions ++= Seq (
85111 " --descriptor_set_out" ,
86112 protobufDescriptorSetOut.value.getAbsolutePath,
87113 " --include_source_info" ),
88114 Compile / managedResources += protobufDescriptorSetOut.value,
89- Compile / unmanagedResourceDirectories ++= (Compile / PB .protoSources).value)
115+ Compile / unmanagedResourceDirectories ++= (Compile / PB .protoSources).value,
116+ Compile / generateUnmanaged := {
117+ if ((Compile / copyUnmanagedSources).value) {
118+ Files .createDirectories(Paths .get((Compile / temporaryUnmanagedDirectory).value.toURI))
119+ // Make sure generation has happened
120+ val _ = (Compile / PB .generate).value
121+ val managed = (Compile / managedSources).value
122+ // Then copy over any new generated unmanaged sources
123+ copyIfNotExist(
124+ Paths .get((Compile / temporaryUnmanagedDirectory).value.toURI),
125+ Paths .get((Compile / sourceDirectory).value.toURI).resolve(" java" )
126+ ) // FIXME: copy java and scala separately
127+ } else Seq .empty
128+ },
129+ Compile / unmanagedSources :=
130+ (Compile / generateUnmanaged).value ++ (Compile / unmanagedSources).value)
131+
132+ // copied from AkkaserverlessPlugin.scala
133+ private def copyIfNotExist (from : Path , to : Path ): Seq [File ] = {
134+ Files
135+ .walk(from)
136+ .filter(Files .isRegularFile(_))
137+ .flatMap[File ](file => {
138+ val target = to.resolve(from.relativize(file))
139+ if (! Files .exists(target)) {
140+ Files .createDirectories(target.getParent)
141+ Files .copy(file, target)
142+ java.util.stream.Stream .of[File ](target.toFile)
143+ } else java.util.stream.Stream .empty()
144+ })
145+ .toArray(new Array [File ](_))
146+ .toVector
147+ }
90148}
0 commit comments