diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-11 07:26:09 -0800 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-11 07:37:28 -0800 |
commit | efbaf34d7d977a13a083638426b86f5a2218eceb (patch) | |
tree | db3971c665693a8f024c1a50350b5052e56c0e61 | |
parent | 337508c82cbe598b8796fc532cd92e8230b099cb (diff) | |
download | mill-efbaf34d7d977a13a083638426b86f5a2218eceb.tar.gz mill-efbaf34d7d977a13a083638426b86f5a2218eceb.tar.bz2 mill-efbaf34d7d977a13a083638426b86f5a2218eceb.zip |
First sketch at SBT test integration works
-rw-r--r-- | build.sbt | 3 | ||||
-rw-r--r-- | core/src/test/scala/mill/TestMain.scala | 152 | ||||
-rw-r--r-- | scalaplugin/src/main/scala/mill/scalaplugin/Subproject.scala | 32 |
3 files changed, 102 insertions, 85 deletions
@@ -39,7 +39,8 @@ lazy val core = project "com.lihaoyi" %% "pprint" % "0.5.3", "com.lihaoyi" % "ammonite" % "1.0.3" cross CrossVersion.full, "com.typesafe.play" %% "play-json" % "2.6.6", - "org.scala-sbt" %% "zinc" % "1.0.3" + "org.scala-sbt" %% "zinc" % "1.0.3", + "org.scala-sbt" % "test-interface" % "1.0" ) ) diff --git a/core/src/test/scala/mill/TestMain.scala b/core/src/test/scala/mill/TestMain.scala index d0ebfc9d..c8fb3148 100644 --- a/core/src/test/scala/mill/TestMain.scala +++ b/core/src/test/scala/mill/TestMain.scala @@ -1,100 +1,86 @@ package mill -import ammonite.ops._ -import java.io.File +import java.io.FileInputStream -import coursier._ -import sbt.internal.inc.{FreshCompilerCache, ScalaInstance, ZincUtil} -import sbt.internal.util.{ConsoleOut, MainAppender} -import sbt.util.LogExchange -import xsbti.api.{ClassLike, DependencyContext} -import xsbti.compile._ +import ammonite.ops._ +import java.lang.annotation.Annotation +import java.util.zip.ZipInputStream -import scalaz.concurrent.Task +import sbt.testing._ object TestMain { - def main(args: Array[String]): Unit = { - val scalaVersion = "2.12.4" - val start = Resolution( - Set( - Dependency(Module("org.scala-lang", "scala-reflect"), scalaVersion), - Dependency(Module("org.scala-lang", "scala-compiler"), scalaVersion), - Dependency(Module("org.scala-lang", "scala-reflect"), scalaVersion), - Dependency(Module("org.scala-sbt", "compiler-bridge_2.12"), "1.0.3"), - Dependency(Module("com.lihaoyi", "sourcecode_2.12"), "0.1.4"), - Dependency(Module("com.lihaoyi", "pprint_2.12"), "0.5.3"), - Dependency(Module("com.lihaoyi", "ammonite_2.12.4"), "1.0.3"), - Dependency(Module("com.typesafe.play", "play-json_2.12"), "2.6.6"), - Dependency(Module("org.scala-sbt", "zinc_2.12"), "1.0.3") - ) - ) - val repositories = Seq( - Cache.ivy2Local, - MavenRepository("https://repo1.maven.org/maven2") - ) - - val fetch = Fetch.from(repositories, Cache.fetch()) - val resolution = start.process.run(fetch).unsafePerformSync + def listClassFiles(base: Path): Iterator[String] = { + if (base.isDir) ls.rec(base).toIterator.filter(_.ext == "class").map(_.relativeTo(base).toString) + else { + val zip = new ZipInputStream(new FileInputStream(base.toIO)) + Iterator.continually(zip.getNextEntry).takeWhile(_ != null).map(_.getName).filter(_.endsWith(".class")) + } + } + def runTests(framework: Framework, + targets: Seq[Path]) = { - val localArtifacts: Seq[File] = Task.gatherUnordered( - resolution.artifacts.map(Cache.file(_).run) - ).unsafePerformSync.flatMap(_.toOption) + val fingerprints = framework.fingerprints() + val testClasses = targets.flatMap { base => + listClassFiles(base).flatMap { path => + val cls = Class.forName(path.stripSuffix(".class").replace('/', '.')) + fingerprints.find { + case f: SubclassFingerprint => + Class.forName(f.superclassName()).isAssignableFrom(cls) + case f: AnnotatedFingerprint => + cls.isAnnotationPresent( + Class.forName(f.annotationName()).asInstanceOf[Class[Annotation]] + ) + }.map { f => (cls, f) } + } + } + testClasses + } + def main(args: Array[String]): Unit = { - pprint.log(localArtifacts) - def grepJar(s: String) = localArtifacts.find(_.toString.endsWith(s)).get + val framework = Class.forName("mill.UTestFramework") + .newInstance() + .asInstanceOf[sbt.testing.Framework] - val scalac = ZincUtil.scalaCompiler( - new ScalaInstance( - version = scalaVersion, - loader = getClass.getClassLoader, - libraryJar = grepJar(s"scala-library-$scalaVersion.jar"), - compilerJar = grepJar(s"scala-compiler-$scalaVersion.jar"), - allJars = localArtifacts.toArray, - explicitActual = None - ), - grepJar("compiler-bridge_2.12-1.0.3.jar") + val testClasses = runTests( + framework, + Seq(pwd/'core/'target/"scala-2.12"/"test-classes") ) - val outputDir = pwd/'target/'zinc - mkdir(outputDir) - val scalaFiles = ls.rec(pwd/'src/'main/'scala/'mill).filter(_.ext == "scala").map(_.toIO).toArray + pprint.log(testClasses) - pprint.log(scalaFiles) - scalac.apply( - sources = scalaFiles, - changes = new DependencyChanges { - def isEmpty = true - def modifiedBinaries() = Array[File]() - def modifiedClasses() = Array[String]() - }, - classpath = localArtifacts.toArray, - singleOutput = outputDir.toIO, - options = Array(), - callback = new xsbti.AnalysisCallback { - def startSource(source: File) = () - def apiPhaseCompleted() = () - def enabled() = true - def binaryDependency(onBinaryEntry: File, onBinaryClassName: String, fromClassName: String, fromSourceFile: File, context: DependencyContext) = () - def generatedNonLocalClass(source: File, classFile: File, binaryClassName: String, srcClassName: String) = () - def problem(what: String, pos: xsbti.Position, msg: String, severity: xsbti.Severity, reported: Boolean) = () - def dependencyPhaseCompleted() = () - def classDependency(onClassName: String, sourceClassName: String, context: DependencyContext) = () - def generatedLocalClass(source: File, classFile: File) = () - def api(sourceFile: File, classApi: ClassLike) = () + val runner = framework.runner(Array(), Array(), getClass.getClassLoader) + println(runner) - def mainClass(sourceFile: File, className: String) = () - def usedName(className: String, name: String, useScopes: java.util.EnumSet[xsbti.UseScope]) = () - }, - maximumErrors = 10, - cache = new FreshCompilerCache(), - log = { - val console = ConsoleOut.systemOut - val consoleAppender = MainAppender.defaultScreen(console) - val l = LogExchange.logger("Hello") - LogExchange.unbindLoggerAppenders("Hello") - LogExchange.bindLoggerAppenders("Hello", (consoleAppender -> sbt.util.Level.Warn) :: Nil) - l + val tasks = runner.tasks( + for((cls, fingerprint) <- testClasses.toArray) + yield { + new TaskDef(cls.getName.stripSuffix("$"), fingerprint, true, Array()) } ) + for(t <- tasks){ + t.execute( + new EventHandler { + def handle(event: Event) = () + }, + Array( + new Logger { + def debug(msg: String) = println(msg) + + def error(msg: String) = println(msg) + + def ansiCodesSupported() = true + + def warn(msg: String) = println(msg) + + def trace(t: Throwable) = println(t) + + def info(msg: String) = println(msg) + }) + ) + } + val doneMsg = runner.done() + if (doneMsg.trim.nonEmpty){ + println(doneMsg) + } } } diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/Subproject.scala b/scalaplugin/src/main/scala/mill/scalaplugin/Subproject.scala index 59538a69..f30e74d2 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/Subproject.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/Subproject.scala @@ -2,8 +2,10 @@ package mill package scalaplugin import java.io.File +import java.lang.annotation.Annotation +import java.net.URLClassLoader -import ammonite.ops.{Path, ls, mkdir, pwd} +import ammonite.ops.{Path, ls, mkdir, pwd, up} import coursier.{Cache, Dependency, Fetch, MavenRepository, Module, Repository, Resolution} import mill.define.Task import mill.define.Task.Cacher @@ -12,11 +14,39 @@ import mill.util.Args import play.api.libs.json._ import sbt.internal.inc.{FreshCompilerCache, ScalaInstance, ZincUtil} import sbt.internal.util.{ConsoleOut, MainAppender} +import sbt.testing.{AnnotatedFingerprint, SubclassFingerprint} import sbt.util.LogExchange import xsbti.api.{ClassLike, DependencyContext} import xsbti.compile.DependencyChanges + + object Subproject{ + def runTests(frameworkName: String, + testClassloader: URLClassLoader) = { + val framework = Class.forName(frameworkName) + .newInstance() + .asInstanceOf[sbt.testing.Framework] + + val fingerprints = framework.fingerprints() + val testClasses = for{ + url <- testClassloader.getURLs + path <- ls.rec(ammonite.ops.Path(url.getFile)).toIterator + if path.ext == "class" + className = (path/up/path.last.stripSuffix(".class")).segments.mkString(".") + cls = testClassloader.loadClass(className) + if fingerprints.exists{ + case f: SubclassFingerprint => + cls.isAssignableFrom(cls) + case f: AnnotatedFingerprint => + cls.isAnnotationPresent( + Class.forName(f.annotationName()).asInstanceOf[Class[Annotation]] + ) + } + } yield cls + + + } def compileScala(scalaVersion: String, sources: PathRef, compileClasspath: Seq[PathRef], |