Skip to content

Commit

Permalink
rework contrib.scoverage.api to be java based.
Browse files Browse the repository at this point in the history
  • Loading branch information
bishabosha committed Sep 17, 2024
1 parent d0a4153 commit 714f3e2
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 106 deletions.
28 changes: 12 additions & 16 deletions contrib/package.mill
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,13 @@ object `package` extends RootModule {
}

object scoverage extends ContribModule {
object api extends build.MillPublishScalaModule {
def compileModuleDeps = Seq(build.main.api)
}
object api extends build.MillPublishJavaModule

def moduleDeps = Seq(scoverage.api)
def compileModuleDeps = Seq(build.scalalib)

def testTransitiveDeps =
super.testTransitiveDeps() ++ Seq(/*worker.testDep(), */ worker2.testDep())
super.testTransitiveDeps() ++ Seq(worker.testDep(), worker2.testDep())

def testArgs = T {
super.testArgs() ++
Expand All @@ -130,21 +128,19 @@ object `package` extends RootModule {

// TODO: (Scala 3) temporarily disable until decision on compatibility with Scala 3
// Worker for Scoverage 1.x
// object worker extends build.MillPublishScalaModule {
// // scoverage is on an old Scala version which doesnt support scalafix
// def fix(args: String*): Command[Unit] = T.command {}
// def compileModuleDeps = Seq(build.main.api)
// def moduleDeps = Seq(scoverage.api)
// def testDepPaths = T { Seq(compile().classes) }

// // compile-time only, need to provide the correct scoverage version at runtime
// def compileIvyDeps = Agg(build.Deps.scalacScoveragePlugin)
// def scalaVersion = build.Deps.scalaVersionForScoverageWorker1
// }
object worker extends build.MillPublishScalaModule {
// scoverage is on an old Scala version which doesnt support scalafix
def fix(args: String*): Command[Unit] = T.command {}
def moduleDeps = Seq(scoverage.api)
def testDepPaths = T { Seq(compile().classes) }

// compile-time only, need to provide the correct scoverage version at runtime
def compileIvyDeps = Agg(build.Deps.scalacScoveragePlugin)
def scalaVersion = build.Deps.scalaVersionForScoverageWorker1
}

// Worker for Scoverage 2.0
object worker2 extends build.MillPublishScalaModule {
def compileModuleDeps = Seq(build.main.api)
def moduleDeps = Seq(scoverage.api)
def testDepPaths = T { Seq(compile().classes) }
def compileIvyDeps = T {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package mill.contrib.scoverage.api;

import java.nio.file.Path;
import java.nio.file.Files;
import java.io.IOException;
import java.io.Serializable;

public interface ScoverageReportWorkerApi2 {

interface Logger {
void info(String msg);
void error(String msg);
void debug(String msg);
}

interface Ctx {
Logger log();
Path dest();
}

public static abstract class ReportType implements Serializable {
private String name;

/*private[api]*/
ReportType(String name) {}

public static final ReportType Console = new ConsoleModule();
public static final FileReportType Html = new HtmlModule();
public static final FileReportType Xml = new XmlModule();
public static final FileReportType XmlCobertura = new XmlCoberturaModule();

/* private[api]*/
static final class ConsoleModule extends ReportType implements Serializable {
/* private[api]*/
ConsoleModule() {
super("Console");
}
};

/* private[api]*/
static final class HtmlModule extends FileReportType implements Serializable {
/* private[api]*/
HtmlModule() {
super("Html", "htmlReport");
}
};

/* private[api]*/
static final class XmlModule extends FileReportType implements Serializable {
/* private[api]*/
XmlModule() {
super("Xml", "xmlReport");
}
}

/* private[api]*/
static final class XmlCoberturaModule extends FileReportType implements Serializable {
/* private[api]*/
XmlCoberturaModule() {
super("XmlCobertura", "xmlCoberturaReport");
}
}

@Override
public String toString() {
return name;
}
}

public static abstract class FileReportType extends ReportType implements Serializable {
private final String folderName;

/*private[api]*/
FileReportType(String name, String folderName) {
super(name);
this.folderName = folderName;
}

public String folderName() {
return folderName;
}
}

void report(ReportType reportType, Path[] sources, Path[] dataDirs, Path sourceRoot, Ctx ctx);

static void makeAllDirs(Path path) throws IOException {
// Replicate behavior of `os.makeDir.all(path)`
if (Files.isDirectory(path) && Files.isSymbolicLink(path)) {
// do nothing
} else {
Files.createDirectories(path);
}
}

}
21 changes: 14 additions & 7 deletions contrib/scoverage/src/mill/contrib/scoverage/ScoverageModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package mill.contrib.scoverage
import coursier.Repository
import mill._
import mill.api.{Loose, PathRef, Result}
import mill.contrib.scoverage.api.ScoverageReportWorkerApi.ReportType
import mill.contrib.scoverage.api.ScoverageReportWorkerApi2.ReportType
import mill.main.BuildInfo
import mill.scalalib.api.ZincWorkerUtil
import mill.scalalib.{Dep, DepSyntax, JavaModule, ScalaModule}
Expand Down Expand Up @@ -114,17 +114,23 @@ trait ScoverageModule extends ScalaModule { outer: ScalaModule =>
val millScalaVersion = BuildInfo.scalaVersion

if (sv.startsWith("1.")) {
def clampScalaVersion(): String = {
val v = "2.13.8"
T.log.outputStream.println(
s"Detected an unsupported Scala version (${millScalaVersion}). Using Scala version ${v} to resolve scoverage ${sv} reporting API."
)
v
}

// In Scoverage 1.x, the reporting API is included in the plugin jar
val scalaVersion = millScalaVersion.split("[.]", 4).toList.take(3) match {
// Scoverage 1 is not released for Scala > 2.13.8, but we don't need to compiler specific code,
// only the reporter API, which does not depend on the Compiler API, so using another full Scala version
// should be safe
case "2" :: "13" :: c :: _ if Try(c.toInt).getOrElse(0) > 8 =>
val v = "2.13.8"
T.log.outputStream.println(
s"Detected an unsupported Scala version (${millScalaVersion}). Using Scala version ${v} to resolve scoverage ${sv} reporting API."
)
v
clampScalaVersion()
case "3" :: _ =>
clampScalaVersion()
case _ => millScalaVersion
}
Agg(ivy"org.scoverage:scalac-scoverage-plugin_${scalaVersion}:${sv}")
Expand Down Expand Up @@ -159,7 +165,8 @@ trait ScoverageModule extends ScalaModule { outer: ScalaModule =>
millProjectModule(
workerArtifact,
repositoriesTask(),
resolveFilter = _.toString.contains(workerArtifact)
resolveFilter = _.toString.contains(workerArtifact),
artifactSuffix = if (isScov2) "_3" else "_2.13"
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package mill.contrib.scoverage

import mill.contrib.scoverage.api.ScoverageReportWorkerApi.ReportType
import mill.contrib.scoverage.api.ScoverageReportWorkerApi2.ReportType
import mill.define.{Command, Module, Task}
import mill.eval.Evaluator
import mill.resolve.{Resolve, SelectMode}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ package mill.contrib.scoverage

import mill.{Agg, T}
import mill.api.{ClassLoader, Ctx, PathRef}
import mill.contrib.scoverage.api.ScoverageReportWorkerApi
import mill.contrib.scoverage.api.ScoverageReportWorkerApi2
import mill.define.{Discover, ExternalModule, Worker}

import ScoverageReportWorker.ScoverageReportWorkerApiBridge
import ScoverageReportWorkerApi2.ReportType
import ScoverageReportWorkerApi2.Logger as ApiLogger
import ScoverageReportWorkerApi2.Ctx as ApiCtx

class ScoverageReportWorker extends AutoCloseable {
private[this] var scoverageClCache = Option.empty[(Long, ClassLoader)]
private var scoverageClCache = Option.empty[(Long, ClassLoader)]

def bridge(classpath: Agg[PathRef])(implicit ctx: Ctx): ScoverageReportWorkerApi = {
def bridge(classpath: Agg[PathRef])(implicit ctx: Ctx): ScoverageReportWorkerApiBridge = {

val classloaderSig = classpath.hashCode
val cl = scoverageClCache match {
Expand All @@ -24,11 +29,43 @@ class ScoverageReportWorker extends AutoCloseable {
cl
}

cl
.loadClass("mill.contrib.scoverage.worker.ScoverageReportWorkerImpl")
.getDeclaredConstructor()
.newInstance()
.asInstanceOf[api.ScoverageReportWorkerApi]
val worker =
cl
.loadClass("mill.contrib.scoverage.worker.ScoverageReportWorkerImpl")
.getDeclaredConstructor()
.newInstance()
.asInstanceOf[api.ScoverageReportWorkerApi2]

def ctx0(using ctx: Ctx): ApiCtx = {
val logger = new ApiLogger {
def info(msg: String): Unit = ctx.log.info(msg)
def error(msg: String): Unit = ctx.log.error(msg)
def debug(msg: String): Unit = ctx.log.debug(msg)
}
new {
def log() = logger
def dest() = ctx.dest.toNIO
}
}

new ScoverageReportWorkerApiBridge {
override def report(
reportType: ReportType,
sources: Seq[os.Path],
dataDirs: Seq[os.Path],
sourceRoot: os.Path
)(implicit
ctx: Ctx
): Unit = {
worker.report(
reportType,
sources.map(_.toNIO).toArray,
dataDirs.map(_.toNIO).toArray,
sourceRoot.toNIO,
ctx0
)
}
}
}

override def close(): Unit = {
Expand All @@ -37,6 +74,18 @@ class ScoverageReportWorker extends AutoCloseable {
}

object ScoverageReportWorker extends ExternalModule {
import ScoverageReportWorkerApi2.ReportType

trait ScoverageReportWorkerApiBridge {
def report(
reportType: ReportType,
sources: Seq[os.Path],
dataDirs: Seq[os.Path],
sourceRoot: os.Path
)(implicit
ctx: Ctx
): Unit
}

def scoverageReportWorker: Worker[ScoverageReportWorker] =
T.worker { new ScoverageReportWorker() }
Expand Down
Loading

0 comments on commit 714f3e2

Please sign in to comment.