Reputation: 22850
I’m writing an sbt task to generate some managed sources, in order to do so I’m using fast-classpath-scanner to extract all sub-classes of the scapegoat inspection class.
I first implemented it as a normal scala project and it worked, but when trying to implement it as an SBT task I’m having a problem, and it is that the scapegoat jar is not in the classpath of the running task, so the classpath scanner is failing.
I have the dependencies of the task in the project/plugins.sbt
file.
//adding the generation task dependencies
libraryDependencies ++= Seq(
"com.sksamuel.scapegoat" %% "scalac-scapegoat-plugin" % "1.3.4",
"io.github.lukehutch" % "fast-classpath-scanner" % "2.18.1"
)
And I implemented the generation task in the build.sbt
file:
//source generator task (simplified)
sourceGenerators in Compile += Def.task {
//_root_ is needed because there is a sbt.io package in scope
import _root_.io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
import _root_.io.github.lukehutch.fastclasspathscanner.matchprocessor.SubclassMatchProcessor
import com.sksamuel.scapegoat.Inspection
import scala.collection.mutable
val inspectionClass = classOf[Inspection]
val fastCPScanner = new FastClasspathScanner(inspectionClass.getPackage.getName)
val inspections = mutable.ListBuffer.empty[Inspection]
fastCPScanner
.matchSubclassesOf(
inspectionClass,
new SubclassMatchProcessor[Inspection] {
override def processMatch(matchingClass: Class[_ <: Inspection]): Unit = {
inspections += matchingClass.newInstance()
println("Hello World")
}
}
).scan()
val lines = inspections.toList.zipWithIndex map {
case (inspection, idx) => s"${inspections.text} -> ${idx}"
}
val scapegoatInspectionsFile = (sourceManaged in Compile).value / "scapegoat" / "inspections.scala"
IO.writeLines(scapegoatInspectionsFile, lines)
Seq(scapegoatInspectionsFile)
}.taskValue
Note: The task compiles and runs perfectly, the problem is that the generated file is empty, because the scanner finds no inspection. This can be confirmed because the print("Hello world")
statement inside the processMatch
method is not executed (no output in the console).
Upvotes: 1
Views: 371
Reputation: 22850
I found that the scapegoat jar was indeed in the classpath of the task, but for some reason (that I don't understand) , probably related with the sbt classloader mechanism, the fast-classpath-scanner was failing to found them.
To anyone with a similar problem, to fix it you only need to override the scanner classloader.
fastCPScanner
.overrideClassLoaders(this.getClass.getClassLoader)
(...)
.scan()
Upvotes: 1