From ea7fceb6e56f53bde3517586dfc57e10a605a524 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Wed, 12 Dec 2018 22:15:38 +0800 Subject: First pass at splitting out worker-api from mill core. (#504) This reduces the {scala,scalajs,scalanative}-worker dependency from the entirety of Mill to a much narrower `mill.api` module. This reduces the amount of classpath pollution within these workers, should mean they're much faster to download the first time, and reduces the amount of random junk they would pull in if they were to be used outside of the Mill project. The interactions between the various *Modules and their *WorkerImpls has been narrowed down to the `*.api` modules, which only depend on other `*.api` modules. A lot of things have been moved around; user code is unlikely to break, but it's possible some will if it references classes that have been moved around. Forwarders have been left for the few internal classes that Mill uses in it's own `build.sc`, to support bootstrapping. Third-party code which breaks should be a straightforward to fix just by updating imports The `*.api` modules have minimal dependencies (mostly uPickle and os-lib) and minimal code. There is still a bunch of implementation code in there: some of it defining data-types that are commonly sent across the module/worker interface (`Agg`, `PathRef`, ...), and some of it just general helper functions that are needed both in modules and workers. The latter code isn't strictly API definitions, but for now is small enough it's not worth splitting into it's own module --- build.sc | 47 +++-- ci/shared.sc | 4 +- contrib/buildinfo/src/mill/contrib/BuildInfo.scala | 4 +- .../test/src/mill/contrib/BuildInfoTests.scala | 2 +- .../mill/contrib/scalapblib/ScalaPBModule.scala | 2 +- .../mill/contrib/scalapblib/ScalaPBWorker.scala | 6 +- .../mill/contrib/scalapblib/TutorialTests.scala | 2 +- .../tut/test/src/mill/contrib/tut/TutTests.scala | 2 +- .../twirllib/src/mill/twirllib/TwirlModule.scala | 4 +- .../twirllib/src/mill/twirllib/TwirlWorker.scala | 9 +- docs/pages/4 - Tasks.md | 12 +- integration/test/resources/ammonite/build.sc | 4 +- integration/test/resources/jawn/build.sc | 2 +- integration/test/resources/play-json/build.sc | 2 +- integration/test/resources/play-json/headers.sc | 2 +- .../src/io/github/retronym/java9rtexport/Copy.java | 75 +++++++ .../io/github/retronym/java9rtexport/Export.java | 103 +++++++++ main/api/src/mill/api/AggWrapper.scala | 120 +++++++++++ main/api/src/mill/api/ClassLoader.scala | 63 ++++++ main/api/src/mill/api/Ctx.scala | 55 +++++ main/api/src/mill/api/JsonFormatters.scala | 44 ++++ main/api/src/mill/api/Logger.scala | 41 ++++ main/api/src/mill/api/PathRef.scala | 122 +++++++++++ main/api/src/mill/api/Result.scala | 36 ++++ main/core/src/mill/define/Applicative.scala | 4 +- main/core/src/mill/define/Task.scala | 44 ++-- main/core/src/mill/eval/Evaluator.scala | 2 +- main/core/src/mill/eval/PathRef.scala | 69 ------- main/core/src/mill/eval/Result.scala | 36 ---- main/core/src/mill/eval/package.scala | 12 ++ main/core/src/mill/util/ClassLoader.scala | 62 ------ main/core/src/mill/util/Ctx.scala | 55 ----- main/core/src/mill/util/IO.scala | 32 --- main/core/src/mill/util/JsonFormatters.scala | 43 +--- main/core/src/mill/util/Logger.scala | 229 --------------------- main/core/src/mill/util/Loggers.scala | 190 +++++++++++++++++ main/core/src/mill/util/Watched.scala | 2 +- main/core/src/mill/util/package.scala | 7 + main/src/mill/MillMain.scala | 4 +- main/src/mill/main/MainScopts.scala | 2 +- main/src/mill/main/MillServerMain.scala | 2 +- main/src/mill/main/RunScript.scala | 3 +- main/src/mill/main/VisualizeModule.scala | 2 +- main/src/mill/modules/Jvm.scala | 9 +- main/src/mill/modules/Util.scala | 31 +-- main/src/mill/package.scala | 4 +- main/test/resources/examples/javac/build.sc | 2 +- main/test/src/mill/define/ApplicativeTests.scala | 2 +- main/test/src/mill/define/CacherTests.scala | 2 +- main/test/src/mill/eval/FailureTests.scala | 2 +- main/test/src/mill/eval/JavaCompileJarTests.scala | 2 +- main/test/src/mill/util/TestEvaluator.scala | 2 +- main/test/src/mill/util/TestUtil.scala | 4 +- .../src/mill/scalajslib/api/ScalaJSWorkerApi.scala | 41 ++++ scalajslib/src/mill/scalajslib/NodeJSConfig.scala | 11 - scalajslib/src/mill/scalajslib/ScalaJSModule.scala | 10 +- .../src/mill/scalajslib/ScalaJSWorkerApi.scala | 35 +--- .../src/mill/scalajslib/HelloJSWorldTests.scala | 2 +- .../src/mill/scalajslib/MultiModuleTests.scala | 2 +- .../src/mill/scalajslib/NodeJSConfigTests.scala | 2 +- .../mill/scalajslib/worker/ScalaJSWorkerImpl.scala | 6 +- .../mill/scalajslib/worker/ScalaJSWorkerImpl.scala | 6 +- .../api/src/mill/scalalib/api/ZincWorkerApi.scala | 76 +++++++ scalalib/src/mill/scalalib/Dep.scala | 5 +- scalalib/src/mill/scalalib/GenIdeaImpl.scala | 2 +- scalalib/src/mill/scalalib/JavaModule.scala | 2 +- scalalib/src/mill/scalalib/Lib.scala | 40 +--- scalalib/src/mill/scalalib/PublishModule.scala | 2 +- scalalib/src/mill/scalalib/ScalaModule.scala | 14 +- scalalib/src/mill/scalalib/ZincWorkerApi.scala | 87 -------- scalalib/src/mill/scalalib/ZincWorkerModule.scala | 56 +++++ .../dependency/DependencyUpdatesImpl.scala | 2 +- .../dependency/versions/VersionsFinder.scala | 2 +- .../mill/scalalib/publish/SonatypePublisher.scala | 2 +- .../mill/scalalib/scalafmt/ScalafmtWorker.scala | 2 +- .../test/src/mill/scalalib/HelloJavaTests.scala | 2 +- .../test/src/mill/scalalib/HelloWorldTests.scala | 2 +- .../test/src/mill/scalalib/ResolveDepsTests.scala | 2 +- .../src/mill/scalalib/worker/ZincWorkerImpl.scala | 38 ++-- .../scalanativelib/api/ScalaNativeWorkerApi.scala | 60 ++++++ .../mill/scalanativelib/ScalaNativeModule.scala | 27 +-- .../mill/scalanativelib/ScalaNativeWorkerApi.scala | 34 +-- .../scalanativelib/HelloNativeWorldTests.scala | 2 +- .../worker/ScalaNativeWorkerImpl.scala | 4 +- 84 files changed, 1278 insertions(+), 923 deletions(-) create mode 100644 main/api/src/io/github/retronym/java9rtexport/Copy.java create mode 100644 main/api/src/io/github/retronym/java9rtexport/Export.java create mode 100644 main/api/src/mill/api/AggWrapper.scala create mode 100644 main/api/src/mill/api/ClassLoader.scala create mode 100644 main/api/src/mill/api/Ctx.scala create mode 100644 main/api/src/mill/api/JsonFormatters.scala create mode 100644 main/api/src/mill/api/Logger.scala create mode 100644 main/api/src/mill/api/PathRef.scala create mode 100644 main/api/src/mill/api/Result.scala delete mode 100644 main/core/src/mill/eval/PathRef.scala delete mode 100644 main/core/src/mill/eval/Result.scala create mode 100644 main/core/src/mill/eval/package.scala delete mode 100644 main/core/src/mill/util/ClassLoader.scala delete mode 100644 main/core/src/mill/util/Ctx.scala delete mode 100644 main/core/src/mill/util/IO.scala delete mode 100644 main/core/src/mill/util/Logger.scala create mode 100644 main/core/src/mill/util/Loggers.scala create mode 100644 main/core/src/mill/util/package.scala create mode 100644 scalajslib/api/src/mill/scalajslib/api/ScalaJSWorkerApi.scala delete mode 100644 scalajslib/src/mill/scalajslib/NodeJSConfig.scala create mode 100644 scalalib/api/src/mill/scalalib/api/ZincWorkerApi.scala delete mode 100644 scalalib/src/mill/scalalib/ZincWorkerApi.scala create mode 100644 scalalib/src/mill/scalalib/ZincWorkerModule.scala create mode 100644 scalanativelib/api/src/mill/scalanativelib/api/ScalaNativeWorkerApi.scala diff --git a/build.sc b/build.sc index aad309a8..1cbbe992 100755 --- a/build.sc +++ b/build.sc @@ -26,8 +26,7 @@ trait MillPublishModule extends PublishModule{ def javacOptions = Seq("-source", "1.8", "-target", "1.8") } - -trait MillModule extends MillPublishModule with ScalaModule{ outer => +trait MillApiModule extends MillPublishModule with ScalaModule{ def scalaVersion = T{ "2.12.6" } def compileIvyDeps = Agg(ivy"com.lihaoyi::acyclic:0.1.7") def scalacOptions = Seq("-P:acyclic:force") @@ -35,6 +34,8 @@ trait MillModule extends MillPublishModule with ScalaModule{ outer => def repositories = super.repositories ++ Seq( MavenRepository("https://oss.sonatype.org/content/repositories/releases") ) +} +trait MillModule extends MillApiModule{ outer => def scalacPluginClasspath = super.scalacPluginClasspath() ++ Seq(main.moduledefs.jar()) @@ -77,9 +78,14 @@ object main extends MillModule { Seq(PathRef(shared.generateCoreTestSources(T.ctx().dest))) } } - + object api extends MillApiModule{ + def ivyDeps = Agg( + ivy"com.lihaoyi::os-lib:0.2.6", + ivy"com.lihaoyi::upickle:0.7.1", + ) + } object core extends MillModule { - def moduleDeps = Seq(moduledefs) + def moduleDeps = Seq(moduledefs, api) def compileIvyDeps = Agg( ivy"org.scala-lang:scala-reflect:${scalaVersion()}" @@ -134,7 +140,7 @@ object main extends MillModule { object scalalib extends MillModule { - def moduleDeps = Seq(main) + def moduleDeps = Seq(main, scalalib.api) def ivyDeps = Agg( ivy"org.scala-sbt:test-interface:1.0" @@ -172,23 +178,27 @@ object scalalib extends MillModule { ) } } - object worker extends MillModule{ - def moduleDeps = Seq(main, scalalib) + object api extends MillApiModule{ + def moduleDeps = Seq(main.api) + } + object worker extends MillApiModule{ + + def moduleDeps = Seq(scalalib.api) def ivyDeps = Agg( // Keep synchronized with zinc in Versions.scala ivy"org.scala-sbt::zinc:1.2.1" ) - def testArgs = Seq( + def testArgs = T{Seq( "-DMILL_SCALA_WORKER=" + runClasspath().map(_.path).mkString(",") - ) + )} } } object scalajslib extends MillModule { - def moduleDeps = Seq(scalalib) + def moduleDeps = Seq(scalalib, scalajslib.api) def testArgs = T{ val mapping = Map( @@ -201,9 +211,12 @@ object scalajslib extends MillModule { (for((k, v) <- mapping.toSeq) yield s"-D$k=$v") } + object api extends MillApiModule{ + def moduleDeps = Seq(main.core) + } object worker extends Cross[WorkerModule]("0.6", "1.0") - class WorkerModule(scalajsBinary: String) extends MillModule{ - def moduleDeps = Seq(scalajslib) + class WorkerModule(scalajsBinary: String) extends MillApiModule{ + def moduleDeps = Seq(scalajslib.api) def ivyDeps = scalajsBinary match { case "0.6" => Agg( @@ -257,7 +270,7 @@ object contrib extends MillModule { object scalanativelib extends MillModule { - def moduleDeps = Seq(scalalib) + def moduleDeps = Seq(scalalib, scalanativelib.api) def scalacOptions = Seq[String]() // disable -P:acyclic:force @@ -273,11 +286,13 @@ object scalanativelib extends MillModule { scalalib.backgroundwrapper.testArgs() ++ (for((k, v) <- mapping.toSeq) yield s"-D$k=$v") } - + object api extends MillApiModule{ + def moduleDeps = Seq(main.core) + } object worker extends Cross[WorkerModule]("0.3") - class WorkerModule(scalaNativeBinary: String) extends MillModule { + class WorkerModule(scalaNativeBinary: String) extends MillApiModule { def scalaNativeVersion = T{ "0.3.8" } - def moduleDeps = Seq(scalanativelib) + def moduleDeps = Seq(scalanativelib.api) def ivyDeps = scalaNativeBinary match { case "0.3" => Agg( diff --git a/ci/shared.sc b/ci/shared.sc index d0fc246f..2f133486 100644 --- a/ci/shared.sc +++ b/ci/shared.sc @@ -41,7 +41,7 @@ def generateTarget(dir: Path) = { val parameters = lowercases.zip(uppercases).map { case (lower, upper) => s"$lower: TT[$upper]" }.mkString(", ") val body = uppercases.zipWithIndex.map { case (t, i) => s"args[$t]($i)" }.mkString(", ") - s"def zip[$typeArgs]($parameters) = makeT[($typeArgs)](Seq($zipArgs), (args: mill.util.Ctx) => ($body))" + s"def zip[$typeArgs]($parameters) = makeT[($typeArgs)](Seq($zipArgs), (args: mill.api.Ctx) => ($body))" } write( @@ -50,7 +50,7 @@ def generateTarget(dir: Path) = { |import scala.language.higherKinds |trait TargetGenerated { | type TT[+X] - | def makeT[X](inputs: Seq[TT[_]], evaluate: mill.util.Ctx => mill.eval.Result[X]): TT[X] + | def makeT[X](inputs: Seq[TT[_]], evaluate: mill.api.Ctx => mill.api.Result[X]): TT[X] | ${(3 to 22).map(generate).mkString("\n")} |}""".stripMargin ) diff --git a/contrib/buildinfo/src/mill/contrib/BuildInfo.scala b/contrib/buildinfo/src/mill/contrib/BuildInfo.scala index 9202fd95..1c8d9d9e 100644 --- a/contrib/buildinfo/src/mill/contrib/BuildInfo.scala +++ b/contrib/buildinfo/src/mill/contrib/BuildInfo.scala @@ -2,9 +2,9 @@ package mill.contrib import mill.T import mill.define.Target -import mill.eval.PathRef +import mill.api.PathRef import mill.scalalib.ScalaModule -import mill.util.Ctx +import mill.api.Ctx trait BuildInfo extends ScalaModule { diff --git a/contrib/buildinfo/test/src/mill/contrib/BuildInfoTests.scala b/contrib/buildinfo/test/src/mill/contrib/BuildInfoTests.scala index 05070985..4293bba7 100644 --- a/contrib/buildinfo/test/src/mill/contrib/BuildInfoTests.scala +++ b/contrib/buildinfo/test/src/mill/contrib/BuildInfoTests.scala @@ -3,7 +3,7 @@ package mill.contrib import java.util.jar.JarFile import mill._ import mill.define.Target -import mill.eval.Result._ +import mill.api.Result._ import mill.eval.{Evaluator, Result} import mill.modules.Assembly import mill.scalalib.publish.VersionControl diff --git a/contrib/scalapblib/src/mill/contrib/scalapblib/ScalaPBModule.scala b/contrib/scalapblib/src/mill/contrib/scalapblib/ScalaPBModule.scala index 9aa5b833..db5c5c8b 100644 --- a/contrib/scalapblib/src/mill/contrib/scalapblib/ScalaPBModule.scala +++ b/contrib/scalapblib/src/mill/contrib/scalapblib/ScalaPBModule.scala @@ -4,7 +4,7 @@ package contrib.scalapblib import coursier.{Cache, MavenRepository} import coursier.core.Version import mill.define.Sources -import mill.eval.PathRef +import mill.api.PathRef import mill.scalalib.Lib.resolveDependencies import mill.scalalib._ import mill.util.Loose diff --git a/contrib/scalapblib/src/mill/contrib/scalapblib/ScalaPBWorker.scala b/contrib/scalapblib/src/mill/contrib/scalapblib/ScalaPBWorker.scala index a1b345b4..125cd3fd 100644 --- a/contrib/scalapblib/src/mill/contrib/scalapblib/ScalaPBWorker.scala +++ b/contrib/scalapblib/src/mill/contrib/scalapblib/ScalaPBWorker.scala @@ -5,7 +5,7 @@ import java.io.File import java.lang.reflect.Method import java.net.URLClassLoader -import mill.eval.PathRef +import mill.api.PathRef class ScalaPBWorker { @@ -40,7 +40,7 @@ class ScalaPBWorker { } def compile(scalaPBClasspath: Agg[os.Path], scalaPBSources: Seq[os.Path], scalaPBOptions: String, dest: os.Path) - (implicit ctx: mill.util.Ctx): mill.eval.Result[PathRef] = { + (implicit ctx: mill.api.Ctx): mill.api.Result[PathRef] = { val compiler = scalaPB(scalaPBClasspath) def compileScalaPBDir(inputDir: os.Path) { @@ -55,7 +55,7 @@ class ScalaPBWorker { scalaPBSources.foreach(compileScalaPBDir) - mill.eval.Result.Success(PathRef(dest)) + mill.api.Result.Success(PathRef(dest)) } } diff --git a/contrib/scalapblib/test/src/mill/contrib/scalapblib/TutorialTests.scala b/contrib/scalapblib/test/src/mill/contrib/scalapblib/TutorialTests.scala index 65558f72..fe0ce8d5 100644 --- a/contrib/scalapblib/test/src/mill/contrib/scalapblib/TutorialTests.scala +++ b/contrib/scalapblib/test/src/mill/contrib/scalapblib/TutorialTests.scala @@ -1,6 +1,6 @@ package mill.contrib.scalapblib -import mill.eval.Result +import mill.api.Result import mill.util.{TestEvaluator, TestUtil} import utest.framework.TestPath import utest.{TestSuite, Tests, assert, _} diff --git a/contrib/tut/test/src/mill/contrib/tut/TutTests.scala b/contrib/tut/test/src/mill/contrib/tut/TutTests.scala index 8168930f..468654bb 100644 --- a/contrib/tut/test/src/mill/contrib/tut/TutTests.scala +++ b/contrib/tut/test/src/mill/contrib/tut/TutTests.scala @@ -2,7 +2,7 @@ package mill.contrib package tut import mill._ -import mill.eval.Result._ +import mill.api.Result._ import mill.scalalib._ import mill.util.{TestEvaluator, TestUtil} import utest._ diff --git a/contrib/twirllib/src/mill/twirllib/TwirlModule.scala b/contrib/twirllib/src/mill/twirllib/TwirlModule.scala index 8f735f3a..328afc47 100644 --- a/contrib/twirllib/src/mill/twirllib/TwirlModule.scala +++ b/contrib/twirllib/src/mill/twirllib/TwirlModule.scala @@ -3,7 +3,7 @@ package twirllib import coursier.{Cache, MavenRepository} import mill.define.Sources -import mill.eval.PathRef +import mill.api.PathRef import mill.scalalib.Lib.resolveDependencies import mill.scalalib._ import mill.util.Loose @@ -41,7 +41,7 @@ trait TwirlModule extends mill.Module { private def twirlInclusiveDot: Boolean = false - def compileTwirl: T[CompilationResult] = T.persistent { + def compileTwirl: T[mill.scalalib.api.CompilationResult] = T.persistent { TwirlWorkerApi.twirlWorker .compile( twirlClasspath().map(_.path), diff --git a/contrib/twirllib/src/mill/twirllib/TwirlWorker.scala b/contrib/twirllib/src/mill/twirllib/TwirlWorker.scala index b8fe9c66..09376a6f 100644 --- a/contrib/twirllib/src/mill/twirllib/TwirlWorker.scala +++ b/contrib/twirllib/src/mill/twirllib/TwirlWorker.scala @@ -5,11 +5,10 @@ import java.io.File import java.lang.reflect.Method import java.net.URLClassLoader -import mill.eval.PathRef -import mill.scalalib.CompilationResult +import mill.api.PathRef +import mill.scalalib.api.CompilationResult import scala.io.Codec - class TwirlWorker { private var twirlInstanceCache = Option.empty[(Long, TwirlWorkerApi)] @@ -103,7 +102,7 @@ class TwirlWorker { constructorAnnotations: Seq[String], codec: Codec, inclusiveDot: Boolean) - (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] = { + (implicit ctx: mill.api.Ctx): mill.api.Result[CompilationResult] = { val compiler = twirl(twirlClasspath) def compileTwirlDir(inputDir: os.Path) { @@ -127,7 +126,7 @@ class TwirlWorker { val zincFile = ctx.dest / 'zinc val classesDir = ctx.dest - mill.eval.Result.Success(CompilationResult(zincFile, PathRef(classesDir))) + mill.api.Result.Success(CompilationResult(zincFile, PathRef(classesDir))) } private def twirlExtensionFormat(name: String) = diff --git a/docs/pages/4 - Tasks.md b/docs/pages/4 - Tasks.md index e69ae662..78a6e58e 100644 --- a/docs/pages/4 - Tasks.md +++ b/docs/pages/4 - Tasks.md @@ -176,10 +176,10 @@ There are several APIs available to you within the body of a `T {...}` or `T.command {...}` block to help your write the code implementing your Target or Command: -### mill.util.Ctx.Dest +### mill.api.Ctx.Dest - `T.ctx().dest` -- `implicitly[mill.util.Ctx.Dest]` +- `implicitly[mill.api.Ctx.Dest]` This is the unique `out/classFiles/dest/` path or `out/run/dest/` path that is assigned to every Target or Command. It is cleared before your task runs, and @@ -188,10 +188,10 @@ artifacts. This is guaranteed to be unique for every `Target` or `Command`, so you can be sure that you will not collide or interfere with anyone else writing to those same paths. -### mill.util.Ctx.Log +### mill.api.Ctx.Log - `T.ctx().log` -- `implicitly[mill.util.Ctx.Log]` +- `implicitly[mill.api.Ctx.Log]` This is the default logger provided for every task. While your task is running, `System.out` and `System.in` are also redirected to this logger. The logs for a @@ -202,10 +202,10 @@ specific output is also streamed to a log file on disk, e.g. `out/run/log` or Messages logged with `log.debug` appear by default only in the log files. You can use the `--debug` option when running mill to show them on the console too. -### mill.util.Ctx.Env +### mill.api.Ctx.Env - `T.ctx().env` -- `implicitly[mill.util.Ctx.Env]` +- `implicitly[mill.api.Ctx.Env]` Mill keeps a long-lived JVM server to avoid paying the cost of recurrent classloading. Because of this, running `System.getenv` in a task might not yield diff --git a/integration/test/resources/ammonite/build.sc b/integration/test/resources/ammonite/build.sc index 66e67087..86f354b4 100644 --- a/integration/test/resources/ammonite/build.sc +++ b/integration/test/resources/ammonite/build.sc @@ -280,7 +280,7 @@ def generateConstantsFile(version: String = buildVersion, unstableCurlUrl: String = "", oldCurlUrls: Seq[(String, String)] = Nil, oldUnstableCurlUrls: Seq[(String, String)] = Nil) - (implicit ctx: mill.util.Ctx.Dest)= { + (implicit ctx: mill.api.Ctx.Dest)= { val versionTxt = s""" package ammonite object Constants{ @@ -305,7 +305,7 @@ def generateConstantsFile(version: String = buildVersion, def generateDependenciesFile(scalaVersion: String, fileName: String, deps: Seq[coursier.Dependency]) - (implicit ctx: mill.util.Ctx.Dest) = { + (implicit ctx: mill.api.Ctx.Dest) = { val dir = ctx.dest / "extra-resources" val dest = dir / fileName diff --git a/integration/test/resources/jawn/build.sc b/integration/test/resources/jawn/build.sc index 8b58efc7..144ef814 100644 --- a/integration/test/resources/jawn/build.sc +++ b/integration/test/resources/jawn/build.sc @@ -42,7 +42,7 @@ class JawnModule(crossVersion: String) extends mill.Module{ object play extends Support(){ def ivyDeps = mill.T{ - Lib.scalaBinaryVersion(scalaVersion()) match{ + mill.scalalib.api.Util.scalaBinaryVersion(scalaVersion()) match{ case "2.10" => Agg(ivy"com.typesafe.play::play-json:2.4.11") case "2.11" => Agg(ivy"com.typesafe.play::play-json:2.5.15") case _ => Agg(ivy"com.typesafe.play::play-json:2.6.0") diff --git a/integration/test/resources/play-json/build.sc b/integration/test/resources/play-json/build.sc index 54e63d65..eb51e999 100644 --- a/integration/test/resources/play-json/build.sc +++ b/integration/test/resources/play-json/build.sc @@ -36,7 +36,7 @@ trait PlayJsonModule extends BaseModule with PublishModule with MiMa { trait Tests extends super.Tests with Scalariform with Headers { val specs2Core = T { - val v = Lib.scalaBinaryVersion(scalaVersion()) match { + val v = mill.scalalib.api.Util.scalaBinaryVersion(scalaVersion()) match { case "2.10" => "3.9.1" case _ => "4.0.2" } diff --git a/integration/test/resources/play-json/headers.sc b/integration/test/resources/play-json/headers.sc index 9737cb3d..31613fe6 100644 --- a/integration/test/resources/play-json/headers.sc +++ b/integration/test/resources/play-json/headers.sc @@ -2,7 +2,7 @@ import $ivy.`com.github.rockjam::license-headers:0.0.1` import mill._, scalalib._ -import mill.eval.PathRef +import mill.api.PathRef import de.heikoseeberger.sbtheader.{CommentStyle, FileType, HeaderCreator, License} trait Headers extends ScalaModule { diff --git a/main/api/src/io/github/retronym/java9rtexport/Copy.java b/main/api/src/io/github/retronym/java9rtexport/Copy.java new file mode 100644 index 00000000..ac3615bb --- /dev/null +++ b/main/api/src/io/github/retronym/java9rtexport/Copy.java @@ -0,0 +1,75 @@ +/* +Copyright (C) 2012-2014 EPFL +Copyright (C) 2012-2014 Typesafe, Inc. +All rights reserved. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the EPFL nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package io.github.retronym.java9rtexport; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.util.EnumSet; + +import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; + +public class Copy { + public static void copyDirectory(final Path source, final Path target) + throws IOException { + Files.walkFileTree(source, EnumSet.of(FileVisitOption.FOLLOW_LINKS), + Integer.MAX_VALUE, new FileVisitor() { + + @Override + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes sourceBasic) throws IOException { + + String relative = source.relativize(dir).toString(); + if (!Files.exists(target.getFileSystem().getPath(relative))) + Files.createDirectory(target.getFileSystem().getPath(relative)); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + String relative = source.relativize(file).toString(); + Files.copy(file, target.getFileSystem().getPath(relative), COPY_ATTRIBUTES, REPLACE_EXISTING); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException e) throws IOException { + throw e; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException { + if (e != null) throw e; + return FileVisitResult.CONTINUE; + } + }); + } + +} \ No newline at end of file diff --git a/main/api/src/io/github/retronym/java9rtexport/Export.java b/main/api/src/io/github/retronym/java9rtexport/Export.java new file mode 100644 index 00000000..b71ca555 --- /dev/null +++ b/main/api/src/io/github/retronym/java9rtexport/Export.java @@ -0,0 +1,103 @@ +/* +Copyright (C) 2012-2014 EPFL +Copyright (C) 2012-2014 Typesafe, Inc. +All rights reserved. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the EPFL nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package io.github.retronym.java9rtexport; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.*; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class Export { + private final static Object lock = new Object(); + private static File tempFile = null; + + public static String rtJarName = "rt-" + System.getProperty("java.version") + ".jar"; + + public static File rt() { + try { + synchronized (lock) { + if (tempFile == null) { + Path tempPath = Files.createTempFile("rt", ".jar"); + tempFile = tempPath.toFile(); + tempFile.deleteOnExit(); + tempFile.delete(); + FileSystem fileSystem = FileSystems.getFileSystem(URI.create("jrt:/")); + Path path = fileSystem.getPath("/modules"); + URI uri = URI.create("jar:" + tempPath.toUri()); + Map env = new HashMap<>(); + env.put("create", "true"); + try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) { + Iterator iterator = Files.list(path).iterator(); + while (iterator.hasNext()) { + Path next = iterator.next(); + Copy.copyDirectory(next, zipfs.getPath("/")); + } + } + } + } + } catch (IOException e) { + e.printStackTrace(); + System.exit(-1); + } + return tempFile; + } + + public static boolean rtTo(File dest, boolean verbose) { + try { + if (!dest.exists()) { + if (verbose) { + System.out.println("Copying Java " + + System.getProperty("java.version") + + " runtime jar to " + + dest.getParentFile() + + " ..."); + System.out.flush(); + } + dest.getParentFile().mkdirs(); + java.nio.file.Files.copy(rt().toPath(), dest.toPath()); + return true; + } + } catch (IOException e) { + e.printStackTrace(); + System.exit(-1); + } + return false; + } + + public static File rtAt(File dir, boolean verbose) { + File f = new File(dir, rtJarName); + rtTo(f, verbose); + return f; + } + + public static File rtAt(File dir) { + return rtAt(dir, false); + } +} \ No newline at end of file diff --git a/main/api/src/mill/api/AggWrapper.scala b/main/api/src/mill/api/AggWrapper.scala new file mode 100644 index 00000000..98d46d68 --- /dev/null +++ b/main/api/src/mill/api/AggWrapper.scala @@ -0,0 +1,120 @@ +package mill.api + + + +import scala.collection.mutable +object Strict extends AggWrapper(true) +object Loose extends AggWrapper(false) + +sealed class AggWrapper(strictUniqueness: Boolean){ + /** + * A collection with enforced uniqueness, fast contains and deterministic + * ordering. Raises an exception if a duplicate is found; call + * `toSeq.distinct` if you explicitly want to make it swallow duplicates + */ + trait Agg[V] extends TraversableOnce[V]{ + def contains(v: V): Boolean + def items: Iterator[V] + def indexed: IndexedSeq[V] + def flatMap[T](f: V => TraversableOnce[T]): Agg[T] + def map[T](f: V => T): Agg[T] + def filter(f: V => Boolean): Agg[V] + def withFilter(f: V => Boolean): Agg[V] + def collect[T](f: PartialFunction[V, T]): Agg[T] + def zipWithIndex: Agg[(V, Int)] + def reverse: Agg[V] + def zip[T](other: Agg[T]): Agg[(V, T)] + def ++[T >: V](other: TraversableOnce[T]): Agg[T] + def length: Int + } + + object Agg{ + def empty[V]: Agg[V] = new Agg.Mutable[V] + implicit def jsonFormat[T: upickle.default.ReadWriter]: upickle.default.ReadWriter[Agg[T]] = + upickle.default.readwriter[Seq[T]].bimap[Agg[T]]( + _.toList, + Agg.from(_) + ) + + def apply[V](items: V*) = from(items) + + implicit def from[V](items: TraversableOnce[V]): Agg[V] = { + val set = new Agg.Mutable[V]() + items.foreach(set.append) + set + } + + + class Mutable[V]() extends Agg[V]{ + + private[this] val set0 = mutable.LinkedHashSet.empty[V] + def contains(v: V) = set0.contains(v) + def append(v: V) = if (!contains(v)){ + set0.add(v) + + }else if (strictUniqueness){ + throw new Exception("Duplicated item inserted into OrderedSet: " + v) + } + def appendAll(vs: Seq[V]) = vs.foreach(append) + def items = set0.iterator + def indexed: IndexedSeq[V] = items.toIndexedSeq + def set: collection.Set[V] = set0 + + def map[T](f: V => T): Agg[T] = { + val output = new Agg.Mutable[T] + for(i <- items) output.append(f(i)) + output + } + def flatMap[T](f: V => TraversableOnce[T]): Agg[T] = { + val output = new Agg.Mutable[T] + for(i <- items) for(i0 <- f(i)) output.append(i0) + output + } + def filter(f: V => Boolean): Agg[V] = { + val output = new Agg.Mutable[V] + for(i <- items) if (f(i)) output.append(i) + output + } + def withFilter(f: V => Boolean): Agg[V] = filter(f) + + def collect[T](f: PartialFunction[V, T]) = this.filter(f.isDefinedAt).map(x => f(x)) + + def zipWithIndex = { + var i = 0 + this.map{ x => + i += 1 + (x, i-1) + } + } + + def reverse = Agg.from(indexed.reverseIterator) + + def zip[T](other: Agg[T]) = Agg.from(items.zip(other.items)) + def ++[T >: V](other: TraversableOnce[T]) = Agg.from(items ++ other) + def length: Int = set0.size + + // Members declared in scala.collection.GenTraversableOnce + def isTraversableAgain: Boolean = items.isTraversableAgain + def toIterator: Iterator[V] = items.toIterator + def toStream: Stream[V] = items.toStream + + // Members declared in scala.collection.TraversableOnce + def copyToArray[B >: V](xs: Array[B], start: Int,len: Int): Unit = items.copyToArray(xs, start, len) + def exists(p: V => Boolean): Boolean = items.exists(p) + def find(p: V => Boolean): Option[V] = items.find(p) + def forall(p: V => Boolean): Boolean = items.forall(p) + def foreach[U](f: V => U): Unit = items.foreach(f) + def hasDefiniteSize: Boolean = items.hasDefiniteSize + def isEmpty: Boolean = items.isEmpty + def seq: scala.collection.TraversableOnce[V] = items + def toTraversable: Traversable[V] = items.toTraversable + + override def hashCode() = items.map(_.hashCode()).sum + override def equals(other: Any) = other match{ + case s: Agg[_] => items.sameElements(s.items) + case _ => super.equals(other) + } + override def toString = items.mkString("Agg(", ", ", ")") + } + } +} diff --git a/main/api/src/mill/api/ClassLoader.scala b/main/api/src/mill/api/ClassLoader.scala new file mode 100644 index 00000000..198cbf6c --- /dev/null +++ b/main/api/src/mill/api/ClassLoader.scala @@ -0,0 +1,63 @@ +package mill.api + +import java.net.{URL, URLClassLoader} + + +import io.github.retronym.java9rtexport.Export + +import scala.util.Try + +object ClassLoader { + def java9OrAbove = !System.getProperty("java.specification.version").startsWith("1.") + def create(urls: Seq[URL], + parent: java.lang.ClassLoader) + (implicit ctx: Ctx.Home): URLClassLoader = { + create(urls, parent, _ => None) + } + def create(urls: Seq[URL], + parent: java.lang.ClassLoader, + customFindClass: String => Option[Class[_]]) + (implicit ctx: Ctx.Home): URLClassLoader = { + new URLClassLoader( + makeUrls(urls).toArray, + refinePlatformParent(parent) + ) { + override def findClass(name: String): Class[_] = { + if (name.startsWith("com.sun.jna")) getClass.getClassLoader.loadClass(name) + else customFindClass(name).getOrElse(super.findClass(name)) + } + } + } + + + /** + * Return `ClassLoader.getPlatformClassLoader` for java 9 and above, if parent class loader is null, + * otherwise return same parent class loader. + * More details: https://docs.oracle.com/javase/9/migrate/toc.htm#JSMIG-GUID-A868D0B9-026F-4D46-B979-901834343F9E + * + * `ClassLoader.getPlatformClassLoader` call is implemented via runtime reflection, cause otherwise + * mill could be compiled only with jdk 9 or above. We don't want to introduce this restriction now. + */ + private def refinePlatformParent(parent: java.lang.ClassLoader): ClassLoader = { + if (!java9OrAbove || parent != null) parent + else { + // Make sure when `parent == null`, we only delegate java.* classes + // to the parent getPlatformClassLoader. This is necessary because + // in Java 9+, somehow the getPlatformClassLoader ends up with all + // sorts of other non-java stuff on it's classpath, which is not what + // we want for an "isolated" classloader! + classOf[ClassLoader] + .getMethod("getPlatformClassLoader") + .invoke(null) + .asInstanceOf[ClassLoader] + } + } + + private def makeUrls(urls: Seq[URL])(implicit ctx: Ctx.Home): Seq[URL] = { + if (java9OrAbove) { + urls :+ Export.rtAt(ctx.home.toIO).toURI.toURL + } else { + urls + } + } +} diff --git a/main/api/src/mill/api/Ctx.scala b/main/api/src/mill/api/Ctx.scala new file mode 100644 index 00000000..567da003 --- /dev/null +++ b/main/api/src/mill/api/Ctx.scala @@ -0,0 +1,55 @@ +package mill.api + + +import scala.annotation.{StaticAnnotation, compileTimeOnly} +import scala.language.implicitConversions + +object Ctx{ + @compileTimeOnly("Target.ctx() can only be used with a T{...} block") + @ImplicitStub + implicit def taskCtx: Ctx = ??? + + object Dest { + implicit def pathToCtx(path: os.Path): Dest = new Dest { def dest = path } + } + trait Dest{ + def dest: os.Path + } + trait Log{ + def log: Logger + } + trait Home{ + def home: os.Path + } + trait Env{ + def env: Map[String, String] + } + object Log{ + implicit def logToCtx(l: Logger): Log = new Log { def log = l } + } + trait Args{ + def args: IndexedSeq[_] + } + + def defaultHome = os.home / ".mill" / "ammonite" + + class ImplicitStub extends StaticAnnotation +} +class Ctx(val args: IndexedSeq[_], + dest0: () => os.Path, + val log: Logger, + val home: os.Path, + val env : Map[String, String]) + extends Ctx.Dest + with Ctx.Log + with Ctx.Args + with Ctx.Home + with Ctx.Env { + + def dest = dest0() + def length = args.length + def apply[T](index: Int): T = { + if (index >= 0 && index < args.length) args(index).asInstanceOf[T] + else throw new IndexOutOfBoundsException(s"Index $index outside of range 0 - ${args.length}") + } +} diff --git a/main/api/src/mill/api/JsonFormatters.scala b/main/api/src/mill/api/JsonFormatters.scala new file mode 100644 index 00000000..918fa693 --- /dev/null +++ b/main/api/src/mill/api/JsonFormatters.scala @@ -0,0 +1,44 @@ +package mill.api + +import upickle.default.{ReadWriter => RW} +import scala.util.matching.Regex +object JsonFormatters extends JsonFormatters +trait JsonFormatters { + implicit val pathReadWrite: RW[os.Path] = upickle.default.readwriter[String] + .bimap[os.Path]( + _.toString, + os.Path(_) + ) + + implicit val regexReadWrite: RW[Regex] = upickle.default.readwriter[String] + .bimap[Regex]( + _.pattern.toString, + _.r + ) + + implicit val bytesReadWrite: RW[os.Bytes] = upickle.default.readwriter[String] + .bimap( + o => java.util.Base64.getEncoder.encodeToString(o.array), + str => new os.Bytes(java.util.Base64.getDecoder.decode(str)) + ) + + + implicit lazy val crFormat: RW[os.CommandResult] = upickle.default.macroRW + + implicit val stackTraceRW = upickle.default.readwriter[ujson.Obj].bimap[StackTraceElement]( + ste => ujson.Obj( + "declaringClass" -> ujson.Str(ste.getClassName), + "methodName" -> ujson.Str(ste.getMethodName), + "fileName" -> ujson.Str(ste.getFileName), + "lineNumber" -> ujson.Num(ste.getLineNumber) + ), + {case json: ujson.Obj => + new StackTraceElement( + json("declaringClass").str.toString, + json("methodName").str.toString, + json("fileName").str.toString, + json("lineNumber").num.toInt + ) + } + ) +} diff --git a/main/api/src/mill/api/Logger.scala b/main/api/src/mill/api/Logger.scala new file mode 100644 index 00000000..4ae6e74d --- /dev/null +++ b/main/api/src/mill/api/Logger.scala @@ -0,0 +1,41 @@ +package mill.api + +import java.io._ + +/** + * The standard logging interface of the Mill build tool. + * + * Contains these primary logging methods, in order of increasing importance: + * + * - `debug` : internal debug messages normally not shown to the user; + * mostly useful when debugging issues + * + * - `ticker`: short-lived logging output where consecutive lines over-write + * each other; useful for information which is transient and disposable + * + * - `info`: miscellaneous logging output which isn't part of the main output + * a user is looking for, but useful to provide context on what Mill is doing + * + * - `error`: logging output which represents problems the user should care + * about + * + * + * Also contains the two forwarded stdout and stderr streams, for code executed + * by Mill to use directly. Typically these correspond to the stdout and stderr, + * but when `show` is used both are forwarded to stderr and stdout is only + * used to display the final `show` output for easy piping. + */ +trait Logger { + def colored: Boolean + + val errorStream: PrintStream + val outputStream: PrintStream + val inStream: InputStream + + def info(s: String): Unit + def error(s: String): Unit + def ticker(s: String): Unit + def debug(s: String): Unit + + def close(): Unit = () +} diff --git a/main/api/src/mill/api/PathRef.scala b/main/api/src/mill/api/PathRef.scala new file mode 100644 index 00000000..24f3627e --- /dev/null +++ b/main/api/src/mill/api/PathRef.scala @@ -0,0 +1,122 @@ +package mill.api + +import java.io.IOException +import java.nio.file.attribute.BasicFileAttributes +import java.nio.file.{FileVisitResult, FileVisitor} +import java.nio.{file => jnio} +import java.security.{DigestOutputStream, MessageDigest} + +import upickle.default.{ReadWriter => RW} + + +/** + * A wrapper around `os.Path` that calculates it's hashcode based + * on the contents of the filesystem underneath it. Used to ensure filesystem + * changes can bust caches which are keyed off hashcodes. + */ +case class PathRef(path: os.Path, quick: Boolean, sig: Int){ + override def hashCode() = sig +} + +object PathRef{ + def apply(path: os.Path, quick: Boolean = false) = { + val sig = { + val digest = MessageDigest.getInstance("MD5") + val digestOut = new DigestOutputStream(DummyOutputStream, digest) + if (os.exists(path)){ + for((path, attrs) <- os.walk.attrs(path, includeTarget = true, followLinks = true)){ + digest.update(path.toString.getBytes) + if (!attrs.isDir) { + if (quick){ + val value = (attrs.mtime, attrs.size).hashCode() + digest.update((value >>> 24).toByte) + digest.update((value >>> 16).toByte) + digest.update((value >>> 8).toByte) + digest.update(value.toByte) + } else if (jnio.Files.isReadable(path.toNIO)) { + val is = os.read.inputStream(path) + IO.stream(is, digestOut) + is.close() + } + } + } + } + + java.util.Arrays.hashCode(digest.digest()) + + } + new PathRef(path, quick, sig) + } + + implicit def jsonFormatter: RW[PathRef] = upickle.default.readwriter[String].bimap[PathRef]( + p => { + (if (p.quick) "qref" else "ref") + ":" + + String.format("%08x", p.sig: Integer) + ":" + + p.path.toString() + }, + s => { + val Array(prefix, hex, path) = s.split(":", 3) + PathRef( + os.Path(path), + prefix match{ case "qref" => true case "ref" => false}, + // Parsing to a long and casting to an int is the only way to make + // round-trip handling of negative numbers work =( + java.lang.Long.parseLong(hex, 16).toInt + ) + } + ) +} + + +import java.io.{InputStream, OutputStream} + +/** + * Misc IO utilities, eventually probably should be pushed upstream into + * ammonite-ops + */ +object IO { + def stream(src: InputStream, dest: OutputStream) = { + val buffer = new Array[Byte](4096) + while ( { + src.read(buffer) match { + case -1 => false + case n => + dest.write(buffer, 0, n) + true + } + }) () + } + + + def unpackZip(src: os.Path, dest: os.RelPath = "unpacked") + (implicit ctx: Ctx.Dest) = { + + val byteStream = os.read.inputStream(src) + val zipStream = new java.util.zip.ZipInputStream(byteStream) + while({ + zipStream.getNextEntry match{ + case null => false + case entry => + if (!entry.isDirectory) { + val entryDest = ctx.dest / dest / os.RelPath(entry.getName) + os.makeDir.all(entryDest / os.up) + val fileOut = new java.io.FileOutputStream(entryDest.toString) + IO.stream(zipStream, fileOut) + fileOut.close() + } + zipStream.closeEntry() + true + } + })() + PathRef(ctx.dest / dest) + } +} + +import java.io.{ByteArrayInputStream, OutputStream} + +object DummyInputStream extends ByteArrayInputStream(Array()) +object DummyOutputStream extends java.io.OutputStream{ + override def write(b: Int) = () + override def write(b: Array[Byte]) = () + override def write(b: Array[Byte], off: Int, len: Int) = () +} diff --git a/main/api/src/mill/api/Result.scala b/main/api/src/mill/api/Result.scala new file mode 100644 index 00000000..b4071a99 --- /dev/null +++ b/main/api/src/mill/api/Result.scala @@ -0,0 +1,36 @@ +package mill.api + +sealed trait Result[+T]{ + def map[V](f: T => V): Result[V] + def asSuccess: Option[Result.Success[T]] = None +} +object Result{ + implicit def create[T](t: => T): Result[T] = { + try Success(t) + catch { case e: Throwable => Exception(e, new OuterStack(new java.lang.Exception().getStackTrace)) } + } + case class Success[+T](value: T) extends Result[T]{ + def map[V](f: T => V) = Result.Success(f(value)) + override def asSuccess = Some(this) + } + case object Skipped extends Result[Nothing]{ + def map[V](f: Nothing => V) = this + } + sealed trait Failing[+T] extends Result[T]{ + def map[V](f: T => V): Failing[V] + } + case class Failure[T](msg: String, value: Option[T] = None) extends Failing[T]{ + def map[V](f: T => V) = Result.Failure(msg, value.map(f(_))) + } + case class Exception(throwable: Throwable, outerStack: OuterStack) extends Failing[Nothing]{ + def map[V](f: Nothing => V) = this + } + class OuterStack(val value: Seq[StackTraceElement]){ + override def hashCode() = value.hashCode() + + override def equals(obj: scala.Any) = obj match{ + case o: OuterStack => value.equals(o.value) + case _ => false + } + } +} \ No newline at end of file diff --git a/main/core/src/mill/define/Applicative.scala b/main/core/src/mill/define/Applicative.scala index 69c506f7..5e63b1cc 100644 --- a/main/core/src/mill/define/Applicative.scala +++ b/main/core/src/mill/define/Applicative.scala @@ -25,7 +25,7 @@ object Applicative { def self: M[T] def apply()(implicit handler: ApplyHandler[M]): T = handler(self) } - class ImplicitStub extends StaticAnnotation + type Id[+T] = T trait Applyer[W[_], T[_], Z[_], Ctx] extends ApplyerGenerated[T, Z, Ctx] { @@ -81,7 +81,7 @@ object Applicative { tempIdent case (t, api) if t.symbol != null - && t.symbol.annotations.exists(_.tree.tpe =:= typeOf[ImplicitStub]) => + && t.symbol.annotations.exists(_.tree.tpe =:= typeOf[mill.api.Ctx.ImplicitStub]) => val tempIdent = Ident(ctxSym) c.internal.setType(tempIdent, t.tpe) diff --git a/main/core/src/mill/define/Task.scala b/main/core/src/mill/define/Task.scala index 07576724..a464bf18 100644 --- a/main/core/src/mill/define/Task.scala +++ b/main/core/src/mill/define/Task.scala @@ -27,7 +27,7 @@ abstract class Task[+T] extends Task.Ops[T] with Applyable[Task, T]{ /** * Evaluate this target */ - def evaluate(args: mill.util.Ctx): Result[T] + def evaluate(args: mill.api.Ctx): Result[T] /** * Even if this target's inputs did not change, does it need to re-evaluate @@ -53,7 +53,7 @@ trait Target[+T] extends NamedTask[T]{ def readWrite: RW[_] } -object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Result, mill.util.Ctx] { +object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { implicit def apply[T](t: T) (implicit rw: RW[T], @@ -64,7 +64,7 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul (rw: c.Expr[RW[T]], ctx: c.Expr[mill.define.Ctx]): c.Expr[Target[T]] = { import c.universe._ - val lhs = Applicative.impl0[Task, T, mill.util.Ctx](c)(reify(Result.Success(t.splice)).tree) + val lhs = Applicative.impl0[Task, T, mill.api.Ctx](c)(reify(Result.Success(t.splice)).tree) mill.moduledefs.Cacher.impl0[TargetImpl[T]](c)( reify( @@ -85,7 +85,7 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul mill.moduledefs.Cacher.impl0[Target[T]](c)( reify( new TargetImpl[T]( - Applicative.impl0[Task, T, mill.util.Ctx](c)(t.tree).splice, + Applicative.impl0[Task, T, mill.api.Ctx](c)(t.tree).splice, ctx.splice, rw.splice ) @@ -118,7 +118,7 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul import c.universe._ val wrapped = for (value <- values.toList) - yield Applicative.impl0[Task, PathRef, mill.util.Ctx](c)( + yield Applicative.impl0[Task, PathRef, mill.api.Ctx](c)( reify(value.splice.map(PathRef(_))).tree ).tree @@ -144,7 +144,7 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul mill.moduledefs.Cacher.impl0[Sources](c)( reify( new Sources( - Applicative.impl0[Task, Seq[PathRef], mill.util.Ctx](c)(values.tree).splice, + Applicative.impl0[Task, Seq[PathRef], mill.api.Ctx](c)(values.tree).splice, ctx.splice ) ) @@ -163,7 +163,7 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul mill.moduledefs.Cacher.impl0[Input[T]](c)( reify( new Input[T]( - Applicative.impl[Task, T, mill.util.Ctx](c)(value).splice, + Applicative.impl[Task, T, mill.api.Ctx](c)(value).splice, ctx.splice, rw.splice ) @@ -194,7 +194,7 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul import c.universe._ reify( new Command[T]( - Applicative.impl[Task, T, mill.util.Ctx](c)(t).splice, + Applicative.impl[Task, T, mill.api.Ctx](c)(t).splice, ctx.splice, w.splice, cls.splice.value, @@ -214,11 +214,11 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul (ctx: c.Expr[mill.define.Ctx]): c.Expr[Worker[T]] = { import c.universe._ reify( - new Worker[T](Applicative.impl[Task, T, mill.util.Ctx](c)(t).splice, ctx.splice) + new Worker[T](Applicative.impl[Task, T, mill.api.Ctx](c)(t).splice, ctx.splice) ) } - def task[T](t: Result[T]): Task[T] = macro Applicative.impl[Task, T, mill.util.Ctx] + def task[T](t: Result[T]): Task[T] = macro Applicative.impl[Task, T, mill.api.Ctx] def persistent[T](t: Result[T])(implicit rw: RW[T], ctx: mill.define.Ctx): Persistent[T] = macro persistentImpl[T] @@ -233,7 +233,7 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul mill.moduledefs.Cacher.impl0[Persistent[T]](c)( reify( new Persistent[T]( - Applicative.impl[Task, T, mill.util.Ctx](c)(t).splice, + Applicative.impl[Task, T, mill.api.Ctx](c)(t).splice, ctx.splice, rw.splice ) @@ -242,20 +242,20 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul } type TT[+X] = Task[X] - def makeT[X](inputs0: Seq[TT[_]], evaluate0: mill.util.Ctx => Result[X]) = new Task[X] { + def makeT[X](inputs0: Seq[TT[_]], evaluate0: mill.api.Ctx => Result[X]) = new Task[X] { val inputs = inputs0 - def evaluate(x: mill.util.Ctx) = evaluate0(x) + def evaluate(x: mill.api.Ctx) = evaluate0(x) } def underlying[A](v: Task[A]) = v - def mapCtx[A, B](t: Task[A])(f: (A, mill.util.Ctx) => Result[B]) = t.mapDest(f) + def mapCtx[A, B](t: Task[A])(f: (A, mill.api.Ctx) => Result[B]) = t.mapDest(f) def zip() = new Task.Task0(()) def zip[A](a: Task[A]) = a.map(Tuple1(_)) def zip[A, B](a: Task[A], b: Task[B]) = a.zip(b) } abstract class NamedTaskImpl[+T](ctx0: mill.define.Ctx, t: Task[T]) extends NamedTask[T]{ - def evaluate(args: mill.util.Ctx) = args[T](0) + def evaluate(args: mill.api.Ctx) = args[T](0) val ctx = ctx0.copy(segments = ctx0.segments ++ Seq(ctx0.segment)) val inputs = Seq(t) } @@ -303,12 +303,12 @@ object Task { class Task0[T](t: T) extends Task[T]{ lazy val t0 = t val inputs = Nil - def evaluate(args: mill.util.Ctx) = t0 + def evaluate(args: mill.api.Ctx) = t0 } abstract class Ops[+T]{ this: Task[T] => def map[V](f: T => V) = new Task.Mapped(this, f) - def mapDest[V](f: (T, mill.util.Ctx) => Result[V]) = new Task.MappedDest(this, f) + def mapDest[V](f: (T, mill.api.Ctx) => Result[V]) = new Task.MappedDest(this, f) def filter(f: T => Boolean) = this def withFilter(f: T => Boolean) = this @@ -323,22 +323,22 @@ object Task { class Sequence[+T](inputs0: Seq[Task[T]]) extends Task[Seq[T]]{ val inputs = inputs0 - def evaluate(args: mill.util.Ctx) = { + def evaluate(args: mill.api.Ctx) = { for (i <- 0 until args.length) yield args(i).asInstanceOf[T] } } class Mapped[+T, +V](source: Task[T], f: T => V) extends Task[V]{ - def evaluate(args: mill.util.Ctx) = f(args(0)) + def evaluate(args: mill.api.Ctx) = f(args(0)) val inputs = List(source) } - class MappedDest[+T, +V](source: Task[T], f: (T, mill.util.Ctx) => Result[V]) extends Task[V]{ - def evaluate(args: mill.util.Ctx) = f(args(0), args) + class MappedDest[+T, +V](source: Task[T], f: (T, mill.api.Ctx) => Result[V]) extends Task[V]{ + def evaluate(args: mill.api.Ctx) = f(args(0), args) val inputs = List(source) } class Zipped[+T, +V](source1: Task[T], source2: Task[V]) extends Task[(T, V)]{ - def evaluate(args: mill.util.Ctx) = (args(0), args(1)) + def evaluate(args: mill.api.Ctx) = (args(0), args(1)) val inputs = List(source1, source2) } } diff --git a/main/core/src/mill/eval/Evaluator.scala b/main/core/src/mill/eval/Evaluator.scala index 2aafdb7a..8709064e 100644 --- a/main/core/src/mill/eval/Evaluator.scala +++ b/main/core/src/mill/eval/Evaluator.scala @@ -7,7 +7,7 @@ import scala.collection.JavaConverters._ import mill.util.Router.EntryPoint import ammonite.runtime.SpecialClassLoader import mill.define.{Ctx => _, _} -import mill.eval.Result.OuterStack +import mill.api.Result.OuterStack import mill.util import mill.util._ import mill.util.Strict.Agg diff --git a/main/core/src/mill/eval/PathRef.scala b/main/core/src/mill/eval/PathRef.scala deleted file mode 100644 index 92ef8d24..00000000 --- a/main/core/src/mill/eval/PathRef.scala +++ /dev/null @@ -1,69 +0,0 @@ -package mill.eval - -import java.io.IOException -import java.nio.file.attribute.BasicFileAttributes -import java.nio.file.{FileVisitResult, FileVisitor} -import java.nio.{file => jnio} -import java.security.{DigestOutputStream, MessageDigest} - -import upickle.default.{ReadWriter => RW} -import mill.util.{DummyOutputStream, IO, JsonFormatters} - - -/** - * A wrapper around `os.Path` that calculates it's hashcode based - * on the contents of the filesystem underneath it. Used to ensure filesystem - * changes can bust caches which are keyed off hashcodes. - */ -case class PathRef(path: os.Path, quick: Boolean, sig: Int){ - override def hashCode() = sig -} - -object PathRef{ - def apply(path: os.Path, quick: Boolean = false) = { - val sig = { - val digest = MessageDigest.getInstance("MD5") - val digestOut = new DigestOutputStream(DummyOutputStream, digest) - if (os.exists(path)){ - for((path, attrs) <- os.walk.attrs(path, includeTarget = true, followLinks = true)){ - digest.update(path.toString.getBytes) - if (!attrs.isDir) { - if (quick){ - val value = (attrs.mtime, attrs.size).hashCode() - digest.update((value >>> 24).toByte) - digest.update((value >>> 16).toByte) - digest.update((value >>> 8).toByte) - digest.update(value.toByte) - } else if (jnio.Files.isReadable(path.toNIO)) { - val is = os.read.inputStream(path) - IO.stream(is, digestOut) - is.close() - } - } - } - } - - java.util.Arrays.hashCode(digest.digest()) - - } - new PathRef(path, quick, sig) - } - - implicit def jsonFormatter: RW[PathRef] = upickle.default.readwriter[String].bimap[PathRef]( - p => { - (if (p.quick) "qref" else "ref") + ":" + - String.format("%08x", p.sig: Integer) + ":" + - p.path.toString() - }, - s => { - val Array(prefix, hex, path) = s.split(":", 3) - PathRef( - os.Path(path), - prefix match{ case "qref" => true case "ref" => false}, - // Parsing to a long and casting to an int is the only way to make - // round-trip handling of negative numbers work =( - java.lang.Long.parseLong(hex, 16).toInt - ) - } - ) -} diff --git a/main/core/src/mill/eval/Result.scala b/main/core/src/mill/eval/Result.scala deleted file mode 100644 index d0400599..00000000 --- a/main/core/src/mill/eval/Result.scala +++ /dev/null @@ -1,36 +0,0 @@ -package mill.eval - -sealed trait Result[+T]{ - def map[V](f: T => V): Result[V] - def asSuccess: Option[Result.Success[T]] = None -} -object Result{ - implicit def create[T](t: => T): Result[T] = { - try Success(t) - catch { case e: Throwable => Exception(e, new OuterStack(new java.lang.Exception().getStackTrace)) } - } - case class Success[+T](value: T) extends Result[T]{ - def map[V](f: T => V) = Result.Success(f(value)) - override def asSuccess = Some(this) - } - case object Skipped extends Result[Nothing]{ - def map[V](f: Nothing => V) = this - } - sealed trait Failing[+T] extends Result[T]{ - def map[V](f: T => V): Failing[V] - } - case class Failure[T](msg: String, value: Option[T] = None) extends Failing[T]{ - def map[V](f: T => V) = Result.Failure(msg, value.map(f(_))) - } - case class Exception(throwable: Throwable, outerStack: OuterStack) extends Failing[Nothing]{ - def map[V](f: Nothing => V) = this - } - class OuterStack(val value: Seq[StackTraceElement]){ - override def hashCode() = value.hashCode() - - override def equals(obj: scala.Any) = obj match{ - case o: OuterStack => value.equals(o.value) - case _ => false - } - } -} \ No newline at end of file diff --git a/main/core/src/mill/eval/package.scala b/main/core/src/mill/eval/package.scala new file mode 100644 index 00000000..433f9074 --- /dev/null +++ b/main/core/src/mill/eval/package.scala @@ -0,0 +1,12 @@ +package mill + +package object eval { + // Backwards compatibility forwarders + val Result = mill.api.Result + type Result[+T] = mill.api.Result[T] + + val PathRef = mill.api.PathRef + type PathRef = mill.api.PathRef + + type Logger = mill.api.Logger +} diff --git a/main/core/src/mill/util/ClassLoader.scala b/main/core/src/mill/util/ClassLoader.scala deleted file mode 100644 index 07ab1ca9..00000000 --- a/main/core/src/mill/util/ClassLoader.scala +++ /dev/null @@ -1,62 +0,0 @@ -package mill.util - -import java.net.{URL, URLClassLoader} - - -import io.github.retronym.java9rtexport.Export - -import scala.util.Try - -object ClassLoader { - def create(urls: Seq[URL], - parent: java.lang.ClassLoader) - (implicit ctx: Ctx.Home): URLClassLoader = { - create(urls, parent, _ => None) - } - def create(urls: Seq[URL], - parent: java.lang.ClassLoader, - customFindClass: String => Option[Class[_]]) - (implicit ctx: Ctx.Home): URLClassLoader = { - new URLClassLoader( - makeUrls(urls).toArray, - refinePlatformParent(parent) - ) { - override def findClass(name: String): Class[_] = { - if (name.startsWith("com.sun.jna")) getClass.getClassLoader.loadClass(name) - else customFindClass(name).getOrElse(super.findClass(name)) - } - } - } - - - /** - * Return `ClassLoader.getPlatformClassLoader` for java 9 and above, if parent class loader is null, - * otherwise return same parent class loader. - * More details: https://docs.oracle.com/javase/9/migrate/toc.htm#JSMIG-GUID-A868D0B9-026F-4D46-B979-901834343F9E - * - * `ClassLoader.getPlatformClassLoader` call is implemented via runtime reflection, cause otherwise - * mill could be compiled only with jdk 9 or above. We don't want to introduce this restriction now. - */ - private def refinePlatformParent(parent: java.lang.ClassLoader): ClassLoader = { - if (!ammonite.util.Util.java9OrAbove || parent != null) parent - else { - // Make sure when `parent == null`, we only delegate java.* classes - // to the parent getPlatformClassLoader. This is necessary because - // in Java 9+, somehow the getPlatformClassLoader ends up with all - // sorts of other non-java stuff on it's classpath, which is not what - // we want for an "isolated" classloader! - classOf[ClassLoader] - .getMethod("getPlatformClassLoader") - .invoke(null) - .asInstanceOf[ClassLoader] - } - } - - private def makeUrls(urls: Seq[URL])(implicit ctx: Ctx.Home): Seq[URL] = { - if (ammonite.util.Util.java9OrAbove) { - urls :+ Export.rtAt(ctx.home.toIO).toURI.toURL - } else { - urls - } - } -} diff --git a/main/core/src/mill/util/Ctx.scala b/main/core/src/mill/util/Ctx.scala deleted file mode 100644 index bbc243b7..00000000 --- a/main/core/src/mill/util/Ctx.scala +++ /dev/null @@ -1,55 +0,0 @@ -package mill.util - -import mill.define.Applicative.ImplicitStub - -import scala.annotation.compileTimeOnly -import scala.language.implicitConversions - -object Ctx{ - @compileTimeOnly("Target.ctx() can only be used with a T{...} block") - @ImplicitStub - implicit def taskCtx: Ctx = ??? - - object Dest { - implicit def pathToCtx(path: os.Path): Dest = new Dest { def dest = path } - } - trait Dest{ - def dest: os.Path - } - trait Log{ - def log: Logger - } - trait Home{ - def home: os.Path - } - trait Env{ - def env: Map[String, String] - } - object Log{ - implicit def logToCtx(l: Logger): Log = new Log { def log = l } - } - trait Args{ - def args: IndexedSeq[_] - } - - def defaultHome = ammonite.ops.home / ".mill" / "ammonite" - -} -class Ctx(val args: IndexedSeq[_], - dest0: () => os.Path, - val log: Logger, - val home: os.Path, - val env : Map[String, String]) - extends Ctx.Dest - with Ctx.Log - with Ctx.Args - with Ctx.Home - with Ctx.Env { - - def dest = dest0() - def length = args.length - def apply[T](index: Int): T = { - if (index >= 0 && index < args.length) args(index).asInstanceOf[T] - else throw new IndexOutOfBoundsException(s"Index $index outside of range 0 - ${args.length}") - } -} diff --git a/main/core/src/mill/util/IO.scala b/main/core/src/mill/util/IO.scala deleted file mode 100644 index 833e52c7..00000000 --- a/main/core/src/mill/util/IO.scala +++ /dev/null @@ -1,32 +0,0 @@ -package mill.util - -import java.io.{InputStream, OutputStream} - -import scala.tools.nsc.interpreter.OutputStream - -/** - * Misc IO utilities, eventually probably should be pushed upstream into - * ammonite-ops - */ -object IO { - def stream(src: InputStream, dest: OutputStream) = { - val buffer = new Array[Byte](4096) - while ( { - src.read(buffer) match { - case -1 => false - case n => - dest.write(buffer, 0, n) - true - } - }) () - } -} - -import java.io.{ByteArrayInputStream, OutputStream} - -object DummyInputStream extends ByteArrayInputStream(Array()) -object DummyOutputStream extends OutputStream{ - override def write(b: Int) = () - override def write(b: Array[Byte]) = () - override def write(b: Array[Byte], off: Int, len: Int) = () -} diff --git a/main/core/src/mill/util/JsonFormatters.scala b/main/core/src/mill/util/JsonFormatters.scala index dba599f7..830782c6 100644 --- a/main/core/src/mill/util/JsonFormatters.scala +++ b/main/core/src/mill/util/JsonFormatters.scala @@ -1,49 +1,10 @@ package mill.util import upickle.default.{ReadWriter => RW} -import scala.util.matching.Regex -object JsonFormatters extends JsonFormatters -trait JsonFormatters { - implicit val pathReadWrite: RW[os.Path] = upickle.default.readwriter[String] - .bimap[os.Path]( - _.toString, - os.Path(_) - ) - - implicit val regexReadWrite: RW[Regex] = upickle.default.readwriter[String] - .bimap[Regex]( - _.pattern.toString, - _.r - ) - - implicit val bytesReadWrite: RW[os.Bytes] = upickle.default.readwriter[String] - .bimap( - o => java.util.Base64.getEncoder.encodeToString(o.array), - str => new os.Bytes(java.util.Base64.getDecoder.decode(str)) - ) - - - implicit lazy val crFormat: RW[os.CommandResult] = upickle.default.macroRW +trait JsonFormatters extends mill.api.JsonFormatters{ implicit lazy val modFormat: RW[coursier.Module] = upickle.default.macroRW implicit lazy val depFormat: RW[coursier.Dependency]= upickle.default.macroRW implicit lazy val attrFormat: RW[coursier.Attributes] = upickle.default.macroRW - implicit val stackTraceRW = upickle.default.readwriter[ujson.Obj].bimap[StackTraceElement]( - ste => ujson.Obj( - "declaringClass" -> ujson.Str(ste.getClassName), - "methodName" -> ujson.Str(ste.getMethodName), - "fileName" -> ujson.Str(ste.getFileName), - "lineNumber" -> ujson.Num(ste.getLineNumber) - ), - {case json: ujson.Obj => - new StackTraceElement( - json("declaringClass").str.toString, - json("methodName").str.toString, - json("fileName").str.toString, - json("lineNumber").num.toInt - ) - } - ) - - } +object JsonFormatters extends JsonFormatters diff --git a/main/core/src/mill/util/Logger.scala b/main/core/src/mill/util/Logger.scala deleted file mode 100644 index 4857953d..00000000 --- a/main/core/src/mill/util/Logger.scala +++ /dev/null @@ -1,229 +0,0 @@ -package mill.util - -import java.io._ - -import ammonite.util.Colors - -/** - * The standard logging interface of the Mill build tool. - * - * Contains these primary logging methods, in order of increasing importance: - * - * - `debug` : internal debug messages normally not shown to the user; - * mostly useful when debugging issues - * - * - `ticker`: short-lived logging output where consecutive lines over-write - * each other; useful for information which is transient and disposable - * - * - `info`: miscellaneous logging output which isn't part of the main output - * a user is looking for, but useful to provide context on what Mill is doing - * - * - `error`: logging output which represents problems the user should care - * about - * - * - * Also contains the two forwarded stdout and stderr streams, for code executed - * by Mill to use directly. Typically these correspond to the stdout and stderr, - * but when `show` is used both are forwarded to stderr and stdout is only - * used to display the final `show` output for easy piping. - */ -trait Logger { - def colored: Boolean - - val errorStream: PrintStream - val outputStream: PrintStream - val inStream: InputStream - - def info(s: String): Unit - def error(s: String): Unit - def ticker(s: String): Unit - def debug(s: String): Unit - - def close(): Unit = () -} - -object DummyLogger extends Logger { - def colored = false - - object errorStream extends PrintStream(_ => ()) - object outputStream extends PrintStream(_ => ()) - val inStream = new ByteArrayInputStream(Array()) - - def info(s: String) = () - def error(s: String) = () - def ticker(s: String) = () - def debug(s: String) = () -} - -class CallbackStream(wrapped: OutputStream, - setPrintState0: PrintState => Unit) extends OutputStream{ - def setPrintState(c: Char) = { - setPrintState0( - c match{ - case '\n' => PrintState.Newline - case '\r' => PrintState.Newline - case _ => PrintState.Middle - } - ) - } - override def write(b: Array[Byte]): Unit = { - if (b.nonEmpty) setPrintState(b(b.length-1).toChar) - wrapped.write(b) - } - - override def write(b: Array[Byte], off: Int, len: Int): Unit = { - if (len != 0) setPrintState(b(off+len-1).toChar) - wrapped.write(b, off, len) - } - - def write(b: Int) = { - setPrintState(b.toChar) - wrapped.write(b) - } -} -sealed trait PrintState -object PrintState{ - case object Ticker extends PrintState - case object Newline extends PrintState - case object Middle extends PrintState -} - -case class PrintLogger( - colored: Boolean, - disableTicker: Boolean, - colors: ammonite.util.Colors, - outStream: PrintStream, - infoStream: PrintStream, - errStream: PrintStream, - inStream: InputStream, - debugEnabled: Boolean - ) extends Logger { - - var printState: PrintState = PrintState.Newline - - override val errorStream = new PrintStream(new CallbackStream(errStream, printState = _)) - override val outputStream = new PrintStream(new CallbackStream(outStream, printState = _)) - - - def info(s: String) = { - printState = PrintState.Newline - infoStream.println(colors.info()(s)) - } - def error(s: String) = { - printState = PrintState.Newline - errStream.println(colors.error()(s)) - } - def ticker(s: String) = { - if(!disableTicker) { - printState match{ - case PrintState.Newline => - infoStream.println(colors.info()(s)) - case PrintState.Middle => - infoStream.println() - infoStream.println(colors.info()(s)) - case PrintState.Ticker => - val p = new PrintWriter(infoStream) - val nav = new ammonite.terminal.AnsiNav(p) - nav.up(1) - nav.clearLine(2) - nav.left(9999) - p.flush() - - infoStream.println(colors.info()(s)) - } - printState = PrintState.Ticker - } - } - - def debug(s: String) = if (debugEnabled) { - printState = PrintState.Newline - errStream.println(s) - } -} - -case class FileLogger(colored: Boolean, file: os.Path, debugEnabled: Boolean) extends Logger { - private[this] var outputStreamUsed: Boolean = false - - lazy val outputStream = { - if (!outputStreamUsed) os.remove.all(file) - outputStreamUsed = true - new PrintStream(new FileOutputStream(file.toIO.getAbsolutePath)) - } - - lazy val errorStream = { - if (!outputStreamUsed) os.remove.all(file) - outputStreamUsed = true - new PrintStream(new FileOutputStream(file.toIO.getAbsolutePath)) - } - - def info(s: String) = outputStream.println(s) - def error(s: String) = outputStream.println(s) - def ticker(s: String) = outputStream.println(s) - def debug(s: String) = if (debugEnabled) outputStream.println(s) - val inStream: InputStream = DummyInputStream - override def close() = { - if (outputStreamUsed) - outputStream.close() - } -} - - - -class MultiStream(stream1: OutputStream, stream2: OutputStream) extends PrintStream(new OutputStream { - def write(b: Int): Unit = { - stream1.write(b) - stream2.write(b) - } - override def write(b: Array[Byte]): Unit = { - stream1.write(b) - stream2.write(b) - } - override def write(b: Array[Byte], off: Int, len: Int) = { - stream1.write(b, off, len) - stream2.write(b, off, len) - } - override def flush() = { - stream1.flush() - stream2.flush() - } - override def close() = { - stream1.close() - stream2.close() - } -}) - -case class MultiLogger(colored: Boolean, logger1: Logger, logger2: Logger) extends Logger { - - - lazy val outputStream: PrintStream = new MultiStream(logger1.outputStream, logger2.outputStream) - - lazy val errorStream: PrintStream = new MultiStream(logger1.errorStream, logger2.errorStream) - - lazy val inStream = Seq(logger1, logger2).collectFirst{case t: PrintLogger => t} match{ - case Some(x) => x.inStream - case None => new ByteArrayInputStream(Array()) - } - - def info(s: String) = { - logger1.info(s) - logger2.info(s) - } - def error(s: String) = { - logger1.error(s) - logger2.error(s) - } - def ticker(s: String) = { - logger1.ticker(s) - logger2.ticker(s) - } - - def debug(s: String) = { - logger1.debug(s) - logger2.debug(s) - } - - override def close() = { - logger1.close() - logger2.close() - } -} diff --git a/main/core/src/mill/util/Loggers.scala b/main/core/src/mill/util/Loggers.scala new file mode 100644 index 00000000..aab1a324 --- /dev/null +++ b/main/core/src/mill/util/Loggers.scala @@ -0,0 +1,190 @@ +package mill.util + +import java.io._ +import mill.api.Logger + +object DummyLogger extends Logger { + def colored = false + + object errorStream extends PrintStream(_ => ()) + object outputStream extends PrintStream(_ => ()) + val inStream = new ByteArrayInputStream(Array()) + + def info(s: String) = () + def error(s: String) = () + def ticker(s: String) = () + def debug(s: String) = () +} + +class CallbackStream(wrapped: OutputStream, + setPrintState0: PrintState => Unit) extends OutputStream{ + def setPrintState(c: Char) = { + setPrintState0( + c match{ + case '\n' => PrintState.Newline + case '\r' => PrintState.Newline + case _ => PrintState.Middle + } + ) + } + override def write(b: Array[Byte]): Unit = { + if (b.nonEmpty) setPrintState(b(b.length-1).toChar) + wrapped.write(b) + } + + override def write(b: Array[Byte], off: Int, len: Int): Unit = { + if (len != 0) setPrintState(b(off+len-1).toChar) + wrapped.write(b, off, len) + } + + def write(b: Int) = { + setPrintState(b.toChar) + wrapped.write(b) + } +} +sealed trait PrintState +object PrintState{ + case object Ticker extends PrintState + case object Newline extends PrintState + case object Middle extends PrintState +} + +case class PrintLogger( + colored: Boolean, + disableTicker: Boolean, + colors: ammonite.util.Colors, + outStream: PrintStream, + infoStream: PrintStream, + errStream: PrintStream, + inStream: InputStream, + debugEnabled: Boolean + ) extends Logger { + + var printState: PrintState = PrintState.Newline + + override val errorStream = new PrintStream(new CallbackStream(errStream, printState = _)) + override val outputStream = new PrintStream(new CallbackStream(outStream, printState = _)) + + + def info(s: String) = { + printState = PrintState.Newline + infoStream.println(colors.info()(s)) + } + def error(s: String) = { + printState = PrintState.Newline + errStream.println(colors.error()(s)) + } + def ticker(s: String) = { + if(!disableTicker) { + printState match{ + case PrintState.Newline => + infoStream.println(colors.info()(s)) + case PrintState.Middle => + infoStream.println() + infoStream.println(colors.info()(s)) + case PrintState.Ticker => + val p = new PrintWriter(infoStream) + val nav = new ammonite.terminal.AnsiNav(p) + nav.up(1) + nav.clearLine(2) + nav.left(9999) + p.flush() + + infoStream.println(colors.info()(s)) + } + printState = PrintState.Ticker + } + } + + def debug(s: String) = if (debugEnabled) { + printState = PrintState.Newline + errStream.println(s) + } +} + +case class FileLogger(colored: Boolean, file: os.Path, debugEnabled: Boolean) extends Logger { + private[this] var outputStreamUsed: Boolean = false + + lazy val outputStream = { + if (!outputStreamUsed) os.remove.all(file) + outputStreamUsed = true + new PrintStream(new FileOutputStream(file.toIO.getAbsolutePath)) + } + + lazy val errorStream = { + if (!outputStreamUsed) os.remove.all(file) + outputStreamUsed = true + new PrintStream(new FileOutputStream(file.toIO.getAbsolutePath)) + } + + def info(s: String) = outputStream.println(s) + def error(s: String) = outputStream.println(s) + def ticker(s: String) = outputStream.println(s) + def debug(s: String) = if (debugEnabled) outputStream.println(s) + val inStream: InputStream = mill.api.DummyInputStream + override def close() = { + if (outputStreamUsed) + outputStream.close() + } +} + + + +class MultiStream(stream1: OutputStream, stream2: OutputStream) extends PrintStream(new OutputStream { + def write(b: Int): Unit = { + stream1.write(b) + stream2.write(b) + } + override def write(b: Array[Byte]): Unit = { + stream1.write(b) + stream2.write(b) + } + override def write(b: Array[Byte], off: Int, len: Int) = { + stream1.write(b, off, len) + stream2.write(b, off, len) + } + override def flush() = { + stream1.flush() + stream2.flush() + } + override def close() = { + stream1.close() + stream2.close() + } +}) + +case class MultiLogger(colored: Boolean, logger1: Logger, logger2: Logger) extends Logger { + + + lazy val outputStream: PrintStream = new MultiStream(logger1.outputStream, logger2.outputStream) + + lazy val errorStream: PrintStream = new MultiStream(logger1.errorStream, logger2.errorStream) + + lazy val inStream = Seq(logger1, logger2).collectFirst{case t: PrintLogger => t} match{ + case Some(x) => x.inStream + case None => new ByteArrayInputStream(Array()) + } + + def info(s: String) = { + logger1.info(s) + logger2.info(s) + } + def error(s: String) = { + logger1.error(s) + logger2.error(s) + } + def ticker(s: String) = { + logger1.ticker(s) + logger2.ticker(s) + } + + def debug(s: String) = { + logger1.debug(s) + logger2.debug(s) + } + + override def close() = { + logger1.close() + logger2.close() + } +} diff --git a/main/core/src/mill/util/Watched.scala b/main/core/src/mill/util/Watched.scala index f1ef4fee..29be53c3 100644 --- a/main/core/src/mill/util/Watched.scala +++ b/main/core/src/mill/util/Watched.scala @@ -1,6 +1,6 @@ package mill.util -import mill.eval.PathRef +import mill.api.PathRef case class Watched[T](value: T, watched: Seq[PathRef]) object Watched{ diff --git a/main/core/src/mill/util/package.scala b/main/core/src/mill/util/package.scala new file mode 100644 index 00000000..ec5d2efc --- /dev/null +++ b/main/core/src/mill/util/package.scala @@ -0,0 +1,7 @@ +package mill + +package object util { + // Backwards compat stubs + val Ctx = mill.api.Ctx + type Ctx = mill.api.Ctx +} diff --git a/main/src/mill/MillMain.scala b/main/src/mill/MillMain.scala index e030fdc7..e953e65d 100644 --- a/main/src/mill/MillMain.scala +++ b/main/src/mill/MillMain.scala @@ -6,7 +6,7 @@ import scala.collection.JavaConverters._ import ammonite.main.Cli._ import io.github.retronym.java9rtexport.Export import mill.eval.Evaluator -import mill.util.DummyInputStream +import mill.api.DummyInputStream object MillMain { @@ -38,7 +38,7 @@ object MillMain { setIdle: Boolean => Unit): (Boolean, Option[Evaluator.State]) = { import ammonite.main.Cli - val millHome = mill.util.Ctx.defaultHome + val millHome = mill.api.Ctx.defaultHome val removed = Set("predef-code", "no-home-predef") var interactive = false diff --git a/main/src/mill/main/MainScopts.scala b/main/src/mill/main/MainScopts.scala index 5cc4d7ba..718a30e6 100644 --- a/main/src/mill/main/MainScopts.scala +++ b/main/src/mill/main/MainScopts.scala @@ -25,7 +25,7 @@ object Tasks{ class EvaluatorScopt[T]() extends scopt.Read[mill.eval.Evaluator]{ def arity = 0 - def reads = s => try{ + def reads = s => { Evaluator.currentEvaluator.get.asInstanceOf[mill.eval.Evaluator] } } diff --git a/main/src/mill/main/MillServerMain.scala b/main/src/mill/main/MillServerMain.scala index 5ced75eb..26ca99e6 100644 --- a/main/src/mill/main/MillServerMain.scala +++ b/main/src/mill/main/MillServerMain.scala @@ -9,7 +9,7 @@ import scala.collection.JavaConverters._ import org.scalasbt.ipcsocket._ import mill.main.client._ import mill.eval.Evaluator -import mill.util.DummyInputStream +import mill.api.DummyInputStream import sun.misc.{Signal, SignalHandler} trait MillServerMain[T]{ diff --git a/main/src/mill/main/RunScript.scala b/main/src/mill/main/RunScript.scala index 119ac2aa..47526631 100644 --- a/main/src/mill/main/RunScript.scala +++ b/main/src/mill/main/RunScript.scala @@ -9,7 +9,8 @@ import ammonite.util.{Name, Res, Util} import mill.define import mill.define._ import mill.eval.{Evaluator, PathRef, Result} -import mill.util.{EitherOps, Logger, ParseArgs, Watched} +import mill.util.{EitherOps, ParseArgs, Watched} +import mill.api.Logger import mill.util.Strict.Agg import scala.collection.mutable diff --git a/main/src/mill/main/VisualizeModule.scala b/main/src/mill/main/VisualizeModule.scala index 71b9fc22..e950973f 100644 --- a/main/src/mill/main/VisualizeModule.scala +++ b/main/src/mill/main/VisualizeModule.scala @@ -37,7 +37,7 @@ trait VisualizeModule extends mill.define.TaskModule{ val in = new LinkedBlockingQueue[(Seq[_], Seq[_], os.Path)]() val out = new LinkedBlockingQueue[Result[Seq[PathRef]]]() - val cl = mill.util.ClassLoader.create( + val cl = mill.api.ClassLoader.create( classpath().map(_.path.toNIO.toUri.toURL).toVector, getClass.getClassLoader ) diff --git a/main/src/mill/modules/Jvm.scala b/main/src/mill/modules/Jvm.scala index 8d2c4de4..1a51ed8b 100644 --- a/main/src/mill/modules/Jvm.scala +++ b/main/src/mill/modules/Jvm.scala @@ -13,7 +13,8 @@ import coursier.util.{Gather, Task} import geny.Generator import mill.main.client.InputPumper import mill.eval.{PathRef, Result} -import mill.util.{Ctx, IO} +import mill.util.Ctx +import mill.api.IO import mill.util.Loose.Agg import scala.collection.mutable @@ -165,15 +166,15 @@ object Jvm { val urls = classPath.map(_.toIO.toURI.toURL) val cl = if (classLoaderOverrideSbtTesting) { val outerClassLoader = getClass.getClassLoader - mill.util.ClassLoader.create(urls.toVector, null, customFindClass = { name => + mill.api.ClassLoader.create(urls.toVector, null, customFindClass = { name => if (name.startsWith("sbt.testing.")) Some(outerClassLoader.loadClass(name)) else None }) } else if (isolated) { - mill.util.ClassLoader.create(urls.toVector, null) + mill.api.ClassLoader.create(urls.toVector, null) } else { - mill.util.ClassLoader.create(urls.toVector, getClass.getClassLoader) + mill.api.ClassLoader.create(urls.toVector, getClass.getClassLoader) } val oldCl = Thread.currentThread().getContextClassLoader diff --git a/main/src/mill/modules/Util.scala b/main/src/mill/modules/Util.scala index 2f57595e..2b98a304 100644 --- a/main/src/mill/modules/Util.scala +++ b/main/src/mill/modules/Util.scala @@ -2,8 +2,9 @@ package mill.modules import coursier.Repository -import mill.eval.PathRef -import mill.util.{Ctx, IO, Loose} +import mill.api.{PathRef, IO} +import mill.util.{Ctx, Loose} + object Util { def cleanupScaladoc(v: String) = { @@ -42,31 +43,9 @@ object Util { val tmpName = if (dest == os.rel / "tmp.zip") "tmp2.zip" else "tmp.zip" val downloaded = download(url, tmpName) - unpackZip(downloaded.path, dest) + IO.unpackZip(downloaded.path, dest) } - def unpackZip(src: os.Path, dest: os.RelPath = "unpacked") - (implicit ctx: Ctx.Dest) = { - - val byteStream = os.read.inputStream(src) - val zipStream = new java.util.zip.ZipInputStream(byteStream) - while({ - zipStream.getNextEntry match{ - case null => false - case entry => - if (!entry.isDirectory) { - val entryDest = ctx.dest / dest / os.RelPath(entry.getName) - os.makeDir.all(entryDest / ammonite.ops.up) - val fileOut = new java.io.FileOutputStream(entryDest.toString) - IO.stream(zipStream, fileOut) - fileOut.close() - } - zipStream.closeEntry() - true - } - })() - PathRef(ctx.dest / dest) - } def millProjectModule(key: String, artifact: String, @@ -75,7 +54,7 @@ object Util { artifactSuffix: String = "_2.12") = { val localPath = sys.props(key) if (localPath != null) { - mill.eval.Result.Success( + mill.api.Result.Success( Loose.Agg.from(localPath.split(',').map(p => PathRef(os.Path(p), quick = true))) ) } else { diff --git a/main/src/mill/package.scala b/main/src/mill/package.scala index 93916c8b..0ccd094f 100644 --- a/main/src/mill/package.scala +++ b/main/src/mill/package.scala @@ -3,8 +3,8 @@ import mill.util.JsonFormatters package object mill extends JsonFormatters{ val T = define.Target type T[T] = define.Target[T] - val PathRef = mill.eval.PathRef - type PathRef = mill.eval.PathRef + val PathRef = mill.api.PathRef + type PathRef = mill.api.PathRef type Module = define.Module type Cross[T] = define.Cross[T] type Agg[T] = util.Loose.Agg[T] diff --git a/main/test/resources/examples/javac/build.sc b/main/test/resources/examples/javac/build.sc index c45a6e2d..2ed9f915 100644 --- a/main/test/resources/examples/javac/build.sc +++ b/main/test/resources/examples/javac/build.sc @@ -1,6 +1,6 @@ import mill.T import mill.eval.JavaCompileJarTests.compileAll -import mill.eval.PathRef +import mill.api.PathRef import mill.modules.Jvm import mill.util.Loose diff --git a/main/test/src/mill/define/ApplicativeTests.scala b/main/test/src/mill/define/ApplicativeTests.scala index 72b715bb..9dd2132f 100644 --- a/main/test/src/mill/define/ApplicativeTests.scala +++ b/main/test/src/mill/define/ApplicativeTests.scala @@ -1,6 +1,6 @@ package mill.define -import mill.define.Applicative.ImplicitStub +import mill.api.Ctx.ImplicitStub import utest._ import scala.annotation.compileTimeOnly diff --git a/main/test/src/mill/define/CacherTests.scala b/main/test/src/mill/define/CacherTests.scala index 84a8d840..59ebf3f6 100644 --- a/main/test/src/mill/define/CacherTests.scala +++ b/main/test/src/mill/define/CacherTests.scala @@ -3,7 +3,7 @@ package mill.define import mill.util.{DummyLogger, TestEvaluator, TestUtil} import mill.util.Strict.Agg import mill.T -import mill.eval.Result.Success +import mill.api.Result.Success import utest._ import utest.framework.TestPath diff --git a/main/test/src/mill/eval/FailureTests.scala b/main/test/src/mill/eval/FailureTests.scala index bf45119c..dcfbcb60 100644 --- a/main/test/src/mill/eval/FailureTests.scala +++ b/main/test/src/mill/eval/FailureTests.scala @@ -1,7 +1,7 @@ package mill.eval import mill.T import mill.util.{TestEvaluator, TestUtil} -import mill.eval.Result.OuterStack +import mill.api.Result.OuterStack import utest._ import utest.framework.TestPath diff --git a/main/test/src/mill/eval/JavaCompileJarTests.scala b/main/test/src/mill/eval/JavaCompileJarTests.scala index 8e931747..426c6ea6 100644 --- a/main/test/src/mill/eval/JavaCompileJarTests.scala +++ b/main/test/src/mill/eval/JavaCompileJarTests.scala @@ -2,7 +2,7 @@ package mill.eval import mill.define.{Discover, Input, Target, Task} import mill.modules.Jvm -import mill.util.Ctx.Dest +import mill.api.Ctx.Dest import mill.{Module, T} import mill.util.{DummyLogger, Loose, TestEvaluator, TestUtil} import mill.util.Strict.Agg diff --git a/main/test/src/mill/util/TestEvaluator.scala b/main/test/src/mill/util/TestEvaluator.scala index 67ba96dc..9a235679 100644 --- a/main/test/src/mill/util/TestEvaluator.scala +++ b/main/test/src/mill/util/TestEvaluator.scala @@ -1,7 +1,7 @@ package mill.util import mill.define.{Input, Target, Task} -import mill.eval.Result.OuterStack +import mill.api.Result.OuterStack import mill.eval.{Evaluator, Result} import mill.util.Strict.Agg import utest.assert diff --git a/main/test/src/mill/util/TestUtil.scala b/main/test/src/mill/util/TestUtil.scala index e5fe906e..baab2992 100644 --- a/main/test/src/mill/util/TestUtil.scala +++ b/main/test/src/mill/util/TestUtil.scala @@ -2,8 +2,8 @@ package mill.util import mill.util.Router.Overrides import mill.define._ -import mill.eval.Result -import mill.eval.Result.OuterStack +import mill.api.Result +import mill.api.Result.OuterStack import utest.assert import mill.util.Strict.Agg import utest.framework.TestPath diff --git a/scalajslib/api/src/mill/scalajslib/api/ScalaJSWorkerApi.scala b/scalajslib/api/src/mill/scalajslib/api/ScalaJSWorkerApi.scala new file mode 100644 index 00000000..4e44a8df --- /dev/null +++ b/scalajslib/api/src/mill/scalajslib/api/ScalaJSWorkerApi.scala @@ -0,0 +1,41 @@ +package mill.scalajslib.api +import java.io.File +import mill.api.Result +trait ScalaJSWorkerApi { + def link(sources: Array[File], + libraries: Array[File], + dest: File, + main: String, + fullOpt: Boolean, + moduleKind: ModuleKind): Result[File] + + def run(config: NodeJSConfig, linkedFile: File): Unit + + def getFramework(config: NodeJSConfig, + frameworkName: String, + linkedFile: File): (() => Unit, sbt.testing.Framework) + +} + + +sealed trait OptimizeMode + +object FastOpt extends OptimizeMode +object FullOpt extends OptimizeMode + +sealed trait ModuleKind +object ModuleKind{ + object NoModule extends ModuleKind + object CommonJSModule extends ModuleKind +} + + +object NodeJSConfig { + import upickle.default.{ReadWriter => RW, macroRW} + implicit def rw: RW[NodeJSConfig] = macroRW +} + +final case class NodeJSConfig(executable: String = "node", + args: List[String] = Nil, + env: Map[String, String] = Map.empty, + sourceMap: Boolean = true) diff --git a/scalajslib/src/mill/scalajslib/NodeJSConfig.scala b/scalajslib/src/mill/scalajslib/NodeJSConfig.scala deleted file mode 100644 index de39308c..00000000 --- a/scalajslib/src/mill/scalajslib/NodeJSConfig.scala +++ /dev/null @@ -1,11 +0,0 @@ -package mill.scalajslib - -object NodeJSConfig { - import upickle.default.{ReadWriter => RW, macroRW} - implicit def rw: RW[NodeJSConfig] = macroRW -} - -final case class NodeJSConfig(executable: String = "node", - args: List[String] = Nil, - env: Map[String, String] = Map.empty, - sourceMap: Boolean = true) diff --git a/scalajslib/src/mill/scalajslib/ScalaJSModule.scala b/scalajslib/src/mill/scalajslib/ScalaJSModule.scala index 37537a85..8568c39b 100644 --- a/scalajslib/src/mill/scalajslib/ScalaJSModule.scala +++ b/scalajslib/src/mill/scalajslib/ScalaJSModule.scala @@ -4,11 +4,11 @@ package scalajslib import coursier.Cache import coursier.maven.MavenRepository import mill.eval.{PathRef, Result} -import mill.eval.Result.Success +import mill.api.Result.Success import mill.scalalib.Lib.resolveDependencies import mill.scalalib.{DepSyntax, Lib, TestModule, TestRunner} import mill.util.{Ctx, Loose} - +import mill.scalajslib.api._ trait ScalaJSModule extends scalalib.ScalaModule { outer => def scalaJSVersion: T[String] @@ -21,7 +21,7 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer => override def moduleDeps = Seq(outer) } - def scalaJSBinaryVersion = T { Lib.scalaBinaryVersion(scalaJSVersion()) } + def scalaJSBinaryVersion = T { mill.scalalib.api.Util.scalaBinaryVersion(scalaJSVersion()) } def scalaJSWorkerVersion = T{ scalaJSVersion().split('.').dropRight(1).mkString(".") } @@ -92,11 +92,11 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer => } override def runMainLocal(mainClass: String, args: String*) = T.command[Unit] { - mill.eval.Result.Failure("runMain is not supported in Scala.js") + mill.api.Result.Failure("runMain is not supported in Scala.js") } override def runMain(mainClass: String, args: String*) = T.command[Unit] { - mill.eval.Result.Failure("runMain is not supported in Scala.js") + mill.api.Result.Failure("runMain is not supported in Scala.js") } def link(worker: ScalaJSWorker, diff --git a/scalajslib/src/mill/scalajslib/ScalaJSWorkerApi.scala b/scalajslib/src/mill/scalajslib/ScalaJSWorkerApi.scala index 881a65b9..bcaeb2d3 100644 --- a/scalajslib/src/mill/scalajslib/ScalaJSWorkerApi.scala +++ b/scalajslib/src/mill/scalajslib/ScalaJSWorkerApi.scala @@ -4,21 +4,10 @@ import java.io.File import java.net.URLClassLoader import mill.define.Discover -import mill.eval.Result -import mill.util.Ctx +import mill.api.Result +import mill.api.Ctx import mill.{Agg, T} - -sealed trait OptimizeMode - -object FastOpt extends OptimizeMode -object FullOpt extends OptimizeMode - -sealed trait ModuleKind -object ModuleKind{ - object NoModule extends ModuleKind - object CommonJSModule extends ModuleKind -} - +import mill.scalajslib.api._ class ScalaJSWorker { private var scalaInstanceCache = Option.empty[(Long, ScalaJSWorkerApi)] @@ -29,7 +18,7 @@ class ScalaJSWorker { scalaInstanceCache match { case Some((sig, bridge)) if sig == classloaderSig => bridge case _ => - val cl = mill.util.ClassLoader.create( + val cl = mill.api.ClassLoader.create( toolsClasspath.map(_.toIO.toURI.toURL).toVector, getClass.getClassLoader ) @@ -76,22 +65,6 @@ class ScalaJSWorker { } -trait ScalaJSWorkerApi { - def link(sources: Array[File], - libraries: Array[File], - dest: File, - main: String, - fullOpt: Boolean, - moduleKind: ModuleKind): Result[File] - - def run(config: NodeJSConfig, linkedFile: File): Unit - - def getFramework(config: NodeJSConfig, - frameworkName: String, - linkedFile: File): (() => Unit, sbt.testing.Framework) - -} - object ScalaJSWorkerApi extends mill.define.ExternalModule { def scalaJSWorker = T.worker { new ScalaJSWorker() } diff --git a/scalajslib/test/src/mill/scalajslib/HelloJSWorldTests.scala b/scalajslib/test/src/mill/scalajslib/HelloJSWorldTests.scala index 7b1027e8..1b3e9bb3 100644 --- a/scalajslib/test/src/mill/scalajslib/HelloJSWorldTests.scala +++ b/scalajslib/test/src/mill/scalajslib/HelloJSWorldTests.scala @@ -11,7 +11,7 @@ import utest._ import scala.collection.JavaConverters._ - +import mill.scalajslib.api._ object HelloJSWorldTests extends TestSuite { val workspacePath = TestUtil.getOutPathStatic() / "hello-js-world" diff --git a/scalajslib/test/src/mill/scalajslib/MultiModuleTests.scala b/scalajslib/test/src/mill/scalajslib/MultiModuleTests.scala index 751c7537..2ffea2cf 100644 --- a/scalajslib/test/src/mill/scalajslib/MultiModuleTests.scala +++ b/scalajslib/test/src/mill/scalajslib/MultiModuleTests.scala @@ -6,7 +6,7 @@ import mill.eval.Evaluator import mill.util._ import mill.scalalib._ import utest._ - +import mill.scalajslib.api._ object MultiModuleTests extends TestSuite { val workspacePath = TestUtil.getOutPathStatic() / "multi-module" val sourcePath = os.pwd / 'scalajslib / 'test / 'resources / "multi-module" diff --git a/scalajslib/test/src/mill/scalajslib/NodeJSConfigTests.scala b/scalajslib/test/src/mill/scalajslib/NodeJSConfigTests.scala index 27ea0a13..d9e6b45b 100644 --- a/scalajslib/test/src/mill/scalajslib/NodeJSConfigTests.scala +++ b/scalajslib/test/src/mill/scalajslib/NodeJSConfigTests.scala @@ -6,7 +6,7 @@ import mill.eval.Evaluator import mill.scalalib.{CrossScalaModule, DepSyntax} import mill.util.{TestEvaluator, TestUtil} import utest._ - +import mill.scalajslib.api._ object NodeJSConfigTests extends TestSuite { val workspacePath = TestUtil.getOutPathStatic() / "hello-js-world" diff --git a/scalajslib/worker/0.6/src/mill/scalajslib/worker/ScalaJSWorkerImpl.scala b/scalajslib/worker/0.6/src/mill/scalajslib/worker/ScalaJSWorkerImpl.scala index 7c30ece9..64b668e5 100644 --- a/scalajslib/worker/0.6/src/mill/scalajslib/worker/ScalaJSWorkerImpl.scala +++ b/scalajslib/worker/0.6/src/mill/scalajslib/worker/ScalaJSWorkerImpl.scala @@ -4,7 +4,7 @@ package worker import java.io.File -import mill.eval.Result +import mill.api.Result import org.scalajs.core.tools.io.IRFileCache.IRContainer import org.scalajs.core.tools.io._ import org.scalajs.core.tools.jsdep.ResolvedJSDependency @@ -13,8 +13,8 @@ import org.scalajs.core.tools.logging.ScalaConsoleLogger import org.scalajs.jsenv._ import org.scalajs.jsenv.nodejs._ import org.scalajs.testadapter.TestAdapter - -class ScalaJSWorkerImpl extends mill.scalajslib.ScalaJSWorkerApi { +import mill.scalajslib.api.{ModuleKind, NodeJSConfig} +class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi { def link(sources: Array[File], libraries: Array[File], dest: File, diff --git a/scalajslib/worker/1.0/src/mill/scalajslib/worker/ScalaJSWorkerImpl.scala b/scalajslib/worker/1.0/src/mill/scalajslib/worker/ScalaJSWorkerImpl.scala index 45795271..f40f7a6b 100644 --- a/scalajslib/worker/1.0/src/mill/scalajslib/worker/ScalaJSWorkerImpl.scala +++ b/scalajslib/worker/1.0/src/mill/scalajslib/worker/ScalaJSWorkerImpl.scala @@ -3,8 +3,8 @@ package scalajslib package worker import java.io.File - -import mill.eval.Result +import mill.scalajslib.api.{ModuleKind, NodeJSConfig} +import mill.api.Result import org.scalajs.core.tools.io._ import org.scalajs.core.tools.linker.{ModuleInitializer, Semantics, StandardLinker, ModuleKind => ScalaJSModuleKind} import org.scalajs.core.tools.logging.ScalaConsoleLogger @@ -12,7 +12,7 @@ import org.scalajs.jsenv.ConsoleJSConsole import org.scalajs.jsenv.nodejs._ import org.scalajs.testadapter.TestAdapter -class ScalaJSWorkerImpl extends mill.scalajslib.ScalaJSWorkerApi { +class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi { def link(sources: Array[File], libraries: Array[File], dest: File, diff --git a/scalalib/api/src/mill/scalalib/api/ZincWorkerApi.scala b/scalalib/api/src/mill/scalalib/api/ZincWorkerApi.scala new file mode 100644 index 00000000..c5230ec5 --- /dev/null +++ b/scalalib/api/src/mill/scalalib/api/ZincWorkerApi.scala @@ -0,0 +1,76 @@ +package mill.scalalib.api + +import mill.api.Loose.Agg +import mill.api.PathRef +import mill.api.JsonFormatters._ + +trait ZincWorkerApi { + /** Compile a Java-only project */ + def compileJava(upstreamCompileOutput: Seq[CompilationResult], + sources: Agg[os.Path], + compileClasspath: Agg[os.Path], + javacOptions: Seq[String]) + (implicit ctx: mill.api.Ctx): mill.api.Result[CompilationResult] + + /** Compile a mixed Scala/Java or Scala-only project */ + def compileMixed(upstreamCompileOutput: Seq[CompilationResult], + sources: Agg[os.Path], + compileClasspath: Agg[os.Path], + javacOptions: Seq[String], + scalaVersion: String, + scalacOptions: Seq[String], + compilerBridgeSources: os.Path, + compilerClasspath: Agg[os.Path], + scalacPluginClasspath: Agg[os.Path]) + (implicit ctx: mill.api.Ctx): mill.api.Result[CompilationResult] + + def discoverMainClasses(compilationResult: CompilationResult) + (implicit ctx: mill.api.Ctx): Seq[String] + + def docJar(scalaVersion: String, + compilerBridgeSources: os.Path, + compilerClasspath: Agg[os.Path], + scalacPluginClasspath: Agg[os.Path], + args: Seq[String]) + (implicit ctx: mill.api.Ctx): Boolean +} + + +object CompilationResult { + implicit val jsonFormatter: upickle.default.ReadWriter[CompilationResult] = upickle.default.macroRW +} + +// analysisFile is represented by os.Path, so we won't break caches after file changes +case class CompilationResult(analysisFile: os.Path, classes: PathRef) + +object Util{ + def isDotty(scalaVersion: String) = + scalaVersion.startsWith("0.") + + + def grepJar(classPath: Agg[os.Path], name: String, version: String, sources: Boolean = false) = { + val suffix = if (sources) "-sources" else "" + val mavenStylePath = s"$name-$version$suffix.jar" + val ivyStylePath = { + val dir = if (sources) "srcs" else "jars" + s"$version/$dir/$name$suffix.jar" + } + + classPath + .find(p => p.toString.endsWith(mavenStylePath) || p.toString.endsWith(ivyStylePath)) + .getOrElse(throw new Exception(s"Cannot find $mavenStylePath or $ivyStylePath")) + } + + private val ReleaseVersion = raw"""(\d+)\.(\d+)\.(\d+)""".r + private val MinorSnapshotVersion = raw"""(\d+)\.(\d+)\.([1-9]\d*)-SNAPSHOT""".r + private val DottyVersion = raw"""0\.(\d+)\.(\d+).*""".r + + def scalaBinaryVersion(scalaVersion: String) = { + scalaVersion match { + case ReleaseVersion(major, minor, _) => s"$major.$minor" + case MinorSnapshotVersion(major, minor, _) => s"$major.$minor" + case DottyVersion(minor, _) => s"0.$minor" + case _ => scalaVersion + } + } +} \ No newline at end of file diff --git a/scalalib/src/mill/scalalib/Dep.scala b/scalalib/src/mill/scalalib/Dep.scala index b419462c..714fa21e 100644 --- a/scalalib/src/mill/scalalib/Dep.scala +++ b/scalalib/src/mill/scalalib/Dep.scala @@ -5,7 +5,7 @@ import upickle.default.{macroRW, ReadWriter => RW} import CrossVersion._ case class Dep(dep: coursier.Dependency, cross: CrossVersion, force: Boolean) { - import Dep.isDotty + import mill.scalalib.api.Util.isDotty def artifactName(binaryVersion: String, fullVersion: String, platformSuffix: String) = { val suffix = cross.suffixString(binaryVersion, fullVersion, platformSuffix) @@ -51,9 +51,6 @@ object Dep { val DefaultConfiguration = "default(compile)" - def isDotty(scalaVersion: String) = - scalaVersion.startsWith("0.") - implicit def parse(signature: String): Dep = { val parts = signature.split(';') val module = parts.head diff --git a/scalalib/src/mill/scalalib/GenIdeaImpl.scala b/scalalib/src/mill/scalalib/GenIdeaImpl.scala index 87b039df..2d76d804 100644 --- a/scalalib/src/mill/scalalib/GenIdeaImpl.scala +++ b/scalalib/src/mill/scalalib/GenIdeaImpl.scala @@ -4,7 +4,7 @@ import ammonite.runtime.SpecialClassLoader import coursier.{Cache, CoursierPaths, Repository} import mill.define._ import mill.eval.{Evaluator, PathRef, Result} -import mill.util.Ctx.{Home, Log} +import mill.api.Ctx.{Home, Log} import mill.util.Strict.Agg import mill.util.{Loose, Strict} import mill.{T, scalalib} diff --git a/scalalib/src/mill/scalalib/JavaModule.scala b/scalalib/src/mill/scalalib/JavaModule.scala index 5cd9b600..78be8893 100644 --- a/scalalib/src/mill/scalalib/JavaModule.scala +++ b/scalalib/src/mill/scalalib/JavaModule.scala @@ -209,7 +209,7 @@ trait JavaModule extends mill.Module with TaskModule { outer => /** * Compiles the current module to generate compiled classfiles/bytecode */ - def compile: T[CompilationResult] = T.persistent{ + def compile: T[mill.scalalib.api.CompilationResult] = T.persistent{ zincWorker.worker().compileJava( upstreamCompileOutput(), allSourceFiles().map(_.path), diff --git a/scalalib/src/mill/scalalib/Lib.scala b/scalalib/src/mill/scalalib/Lib.scala index 80723637..b8b253bd 100644 --- a/scalalib/src/mill/scalalib/Lib.scala +++ b/scalalib/src/mill/scalalib/Lib.scala @@ -9,49 +9,17 @@ import javax.tools.ToolProvider import ammonite.util.Util import coursier.{Cache, Dependency, Fetch, Repository, Resolution} -import Dep.isDotty +import mill.scalalib.api.Util.isDotty import mill.Agg import mill.eval.{PathRef, Result} import mill.modules.Jvm -import mill.util.Ctx +import mill.api.Ctx import sbt.testing._ import scala.collection.mutable -object CompilationResult { - implicit val jsonFormatter: upickle.default.ReadWriter[CompilationResult] = upickle.default.macroRW -} - -// analysisFile is represented by os.Path, so we won't break caches after file changes -case class CompilationResult(analysisFile: os.Path, classes: PathRef) object Lib{ - private val ReleaseVersion = raw"""(\d+)\.(\d+)\.(\d+)""".r - private val MinorSnapshotVersion = raw"""(\d+)\.(\d+)\.([1-9]\d*)-SNAPSHOT""".r - private val DottyVersion = raw"""0\.(\d+)\.(\d+).*""".r - - def scalaBinaryVersion(scalaVersion: String) = { - scalaVersion match { - case ReleaseVersion(major, minor, _) => s"$major.$minor" - case MinorSnapshotVersion(major, minor, _) => s"$major.$minor" - case DottyVersion(minor, _) => s"0.$minor" - case _ => scalaVersion - } - } - - def grepJar(classPath: Agg[os.Path], name: String, version: String, sources: Boolean = false) = { - val suffix = if (sources) "-sources" else "" - val mavenStylePath = s"$name-$version$suffix.jar" - val ivyStylePath = { - val dir = if (sources) "srcs" else "jars" - s"$version/$dir/$name$suffix.jar" - } - - classPath - .find(p => p.toString.endsWith(mavenStylePath) || p.toString.endsWith(ivyStylePath)) - .getOrElse(throw new Exception(s"Cannot find $mavenStylePath or $ivyStylePath")) - } - def depToDependencyJava(dep: Dep, platformSuffix: String = ""): Dependency = { assert(dep.cross.isConstant, s"Not a Java dependency: $dep") depToDependency(dep, "", platformSuffix) @@ -59,7 +27,7 @@ object Lib{ def depToDependency(dep: Dep, scalaVersion: String, platformSuffix: String = ""): Dependency = dep.toDependency( - binaryVersion = scalaBinaryVersion(scalaVersion), + binaryVersion = mill.scalalib.api.Util.scalaBinaryVersion(scalaVersion), fullVersion = scalaVersion, platformSuffix = platformSuffix ) @@ -98,7 +66,7 @@ object Lib{ ) } def scalaCompilerIvyDeps(scalaOrganization: String, scalaVersion: String) = - if (isDotty(scalaVersion)) + if (mill.scalalib.api.Util.isDotty(scalaVersion)) Agg(ivy"$scalaOrganization::dotty-compiler:$scalaVersion".forceVersion()) else Agg( diff --git a/scalalib/src/mill/scalalib/PublishModule.scala b/scalalib/src/mill/scalalib/PublishModule.scala index a3d0856f..588781f4 100644 --- a/scalalib/src/mill/scalalib/PublishModule.scala +++ b/scalalib/src/mill/scalalib/PublishModule.scala @@ -2,7 +2,7 @@ package mill package scalalib import mill.define.{ExternalModule, Task} -import mill.eval.PathRef +import mill.api.PathRef import mill.scalalib.publish.{Artifact, SonatypePublisher} /** diff --git a/scalalib/src/mill/scalalib/ScalaModule.scala b/scalalib/src/mill/scalalib/ScalaModule.scala index 38a5a8ea..9d669bf4 100644 --- a/scalalib/src/mill/scalalib/ScalaModule.scala +++ b/scalalib/src/mill/scalalib/ScalaModule.scala @@ -6,10 +6,10 @@ import mill.define.{Target, Task, TaskModule} import mill.eval.{PathRef, Result} import mill.modules.Jvm import mill.modules.Jvm.createJar -import Dep.isDotty +import mill.scalalib.api.Util.isDotty import Lib._ import mill.util.Loose.Agg -import mill.util.DummyInputStream +import mill.api.DummyInputStream /** * Core configuration required to compile a single Scala compilation target @@ -60,7 +60,7 @@ trait ScalaModule extends JavaModule { outer => publish.Artifact.fromDep( _: Dep, scalaVersion(), - Lib.scalaBinaryVersion(scalaVersion()), + mill.scalalib.api.Util.scalaBinaryVersion(scalaVersion()), platformSuffix() ) } @@ -84,7 +84,7 @@ trait ScalaModule extends JavaModule { outer => def scalaCompilerBridgeSources = T { val (scalaVersion0, scalaBinaryVersion0) = scalaVersion() match { case Milestone213(_, _) => ("2.13.0-M2", "2.13.0-M2") - case _ => (scalaVersion(), Lib.scalaBinaryVersion(scalaVersion())) + case _ => (scalaVersion(), mill.scalalib.api.Util.scalaBinaryVersion(scalaVersion())) } val (bridgeDep, bridgeName, bridgeVersion) = @@ -106,7 +106,7 @@ trait ScalaModule extends JavaModule { outer => Seq(bridgeDep), sources = true ).map(deps => - grepJar(deps.map(_.path), bridgeName, bridgeVersion, sources = true) + mill.scalalib.api.Util.grepJar(deps.map(_.path), bridgeName, bridgeVersion, sources = true) ) } @@ -152,7 +152,7 @@ trait ScalaModule extends JavaModule { outer => resolveDeps(T.task{runIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps()})() } - override def compile: T[CompilationResult] = T.persistent{ + override def compile: T[mill.scalalib.api.CompilationResult] = T.persistent{ zincWorker.worker().compileMixed( upstreamCompileOutput(), allSourceFiles().map(_.path), @@ -262,7 +262,7 @@ trait ScalaModule extends JavaModule { outer => */ def artifactScalaVersion: T[String] = T { if (crossFullScalaVersion()) scalaVersion() - else Lib.scalaBinaryVersion(scalaVersion()) + else mill.scalalib.api.Util.scalaBinaryVersion(scalaVersion()) } /** diff --git a/scalalib/src/mill/scalalib/ZincWorkerApi.scala b/scalalib/src/mill/scalalib/ZincWorkerApi.scala deleted file mode 100644 index dbcaa6da..00000000 --- a/scalalib/src/mill/scalalib/ZincWorkerApi.scala +++ /dev/null @@ -1,87 +0,0 @@ -package mill.scalalib - -import coursier.Cache -import coursier.maven.MavenRepository -import mill.Agg -import mill.T -import mill.define.{Discover, Worker} -import mill.scalalib.Lib.resolveDependencies -import mill.util.Loose -import mill.util.JsonFormatters._ - -object ZincWorkerModule extends mill.define.ExternalModule with ZincWorkerModule{ - lazy val millDiscover = Discover[this.type] -} -trait ZincWorkerModule extends mill.Module{ - def repositories = Seq( - Cache.ivy2Local, - MavenRepository("https://repo1.maven.org/maven2"), - MavenRepository("https://oss.sonatype.org/content/repositories/releases") - ) - - def classpath = T{ - mill.modules.Util.millProjectModule("MILL_SCALA_WORKER", "mill-scalalib-worker", repositories) - } - - def scalalibClasspath = T{ - mill.modules.Util.millProjectModule("MILL_SCALA_LIB", "mill-scalalib", repositories) - } - - def backgroundWrapperClasspath = T{ - mill.modules.Util.millProjectModule( - "MILL_BACKGROUNDWRAPPER", "mill-scalalib-backgroundwrapper", - repositories, artifactSuffix = "" - ) - } - - def worker: Worker[ZincWorkerApi] = T.worker{ - val cl = mill.util.ClassLoader.create( - classpath().map(_.path.toNIO.toUri.toURL).toVector, - getClass.getClassLoader - ) - val cls = cl.loadClass("mill.scalalib.worker.ZincWorkerImpl") - val instance = cls.getConstructor(classOf[mill.util.Ctx], classOf[Array[String]]) - .newInstance(T.ctx(), compilerInterfaceClasspath().map(_.path.toString).toArray[String]) - instance.asInstanceOf[ZincWorkerApi] - } - - def compilerInterfaceClasspath = T{ - resolveDependencies( - repositories, - Lib.depToDependency(_, "2.12.4", ""), - Seq(ivy"org.scala-sbt:compiler-interface:${Versions.zinc}") - ) - } - -} - -trait ZincWorkerApi { - /** Compile a Java-only project */ - def compileJava(upstreamCompileOutput: Seq[CompilationResult], - sources: Agg[os.Path], - compileClasspath: Agg[os.Path], - javacOptions: Seq[String]) - (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] - - /** Compile a mixed Scala/Java or Scala-only project */ - def compileMixed(upstreamCompileOutput: Seq[CompilationResult], - sources: Agg[os.Path], - compileClasspath: Agg[os.Path], - javacOptions: Seq[String], - scalaVersion: String, - scalacOptions: Seq[String], - compilerBridgeSources: os.Path, - compilerClasspath: Agg[os.Path], - scalacPluginClasspath: Agg[os.Path]) - (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] - - def discoverMainClasses(compilationResult: CompilationResult) - (implicit ctx: mill.util.Ctx): Seq[String] - - def docJar(scalaVersion: String, - compilerBridgeSources: os.Path, - compilerClasspath: Agg[os.Path], - scalacPluginClasspath: Agg[os.Path], - args: Seq[String]) - (implicit ctx: mill.util.Ctx): Boolean -} diff --git a/scalalib/src/mill/scalalib/ZincWorkerModule.scala b/scalalib/src/mill/scalalib/ZincWorkerModule.scala new file mode 100644 index 00000000..5ca824ce --- /dev/null +++ b/scalalib/src/mill/scalalib/ZincWorkerModule.scala @@ -0,0 +1,56 @@ +package mill.scalalib + +import coursier.Cache +import coursier.maven.MavenRepository +import mill.Agg +import mill.T +import mill.define.{Discover, Worker} +import mill.scalalib.Lib.resolveDependencies +import mill.util.Loose +import mill.util.JsonFormatters._ + +object ZincWorkerModule extends mill.define.ExternalModule with ZincWorkerModule{ + lazy val millDiscover = Discover[this.type] +} +trait ZincWorkerModule extends mill.Module{ + def repositories = Seq( + Cache.ivy2Local, + MavenRepository("https://repo1.maven.org/maven2"), + MavenRepository("https://oss.sonatype.org/content/repositories/releases") + ) + + def classpath = T{ + mill.modules.Util.millProjectModule("MILL_SCALA_WORKER", "mill-scalalib-worker", repositories) + } + + def scalalibClasspath = T{ + mill.modules.Util.millProjectModule("MILL_SCALA_LIB", "mill-scalalib", repositories) + } + + def backgroundWrapperClasspath = T{ + mill.modules.Util.millProjectModule( + "MILL_BACKGROUNDWRAPPER", "mill-scalalib-backgroundwrapper", + repositories, artifactSuffix = "" + ) + } + + def worker: Worker[mill.scalalib.api.ZincWorkerApi] = T.worker{ + val cl = mill.api.ClassLoader.create( + classpath().map(_.path.toNIO.toUri.toURL).toVector, + getClass.getClassLoader + ) + val cls = cl.loadClass("mill.scalalib.worker.ZincWorkerImpl") + val instance = cls.getConstructor(classOf[mill.api.Ctx], classOf[Array[String]]) + .newInstance(T.ctx(), compilerInterfaceClasspath().map(_.path.toString).toArray[String]) + instance.asInstanceOf[mill.scalalib.api.ZincWorkerApi] + } + + def compilerInterfaceClasspath = T{ + resolveDependencies( + repositories, + Lib.depToDependency(_, "2.12.4", ""), + Seq(ivy"org.scala-sbt:compiler-interface:${Versions.zinc}") + ) + } + +} diff --git a/scalalib/src/mill/scalalib/dependency/DependencyUpdatesImpl.scala b/scalalib/src/mill/scalalib/dependency/DependencyUpdatesImpl.scala index dc548c88..3bb94202 100644 --- a/scalalib/src/mill/scalalib/dependency/DependencyUpdatesImpl.scala +++ b/scalalib/src/mill/scalalib/dependency/DependencyUpdatesImpl.scala @@ -7,7 +7,7 @@ import mill.scalalib.dependency.updates.{ UpdatesFinder } import mill.scalalib.dependency.versions.VersionsFinder -import mill.util.Ctx.{Home, Log} +import mill.api.Ctx.{Home, Log} object DependencyUpdatesImpl { diff --git a/scalalib/src/mill/scalalib/dependency/versions/VersionsFinder.scala b/scalalib/src/mill/scalalib/dependency/versions/VersionsFinder.scala index b1033688..a831ffc3 100644 --- a/scalalib/src/mill/scalalib/dependency/versions/VersionsFinder.scala +++ b/scalalib/src/mill/scalalib/dependency/versions/VersionsFinder.scala @@ -4,7 +4,7 @@ import mill.define.{BaseModule, Task} import mill.eval.Evaluator import mill.scalalib.dependency.metadata.MetadataLoaderFactory import mill.scalalib.{Dep, JavaModule, Lib} -import mill.util.Ctx.{Home, Log} +import mill.api.Ctx.{Home, Log} import mill.util.{Loose, Strict} private[dependency] object VersionsFinder { diff --git a/scalalib/src/mill/scalalib/publish/SonatypePublisher.scala b/scalalib/src/mill/scalalib/publish/SonatypePublisher.scala index 5e596618..1843943b 100644 --- a/scalalib/src/mill/scalalib/publish/SonatypePublisher.scala +++ b/scalalib/src/mill/scalalib/publish/SonatypePublisher.scala @@ -3,7 +3,7 @@ package mill.scalalib.publish import java.math.BigInteger import java.security.MessageDigest -import mill.util.Logger +import mill.api.Logger import scalaj.http.HttpResponse diff --git a/scalalib/src/mill/scalalib/scalafmt/ScalafmtWorker.scala b/scalalib/src/mill/scalalib/scalafmt/ScalafmtWorker.scala index d6992fc8..47d8375f 100644 --- a/scalalib/src/mill/scalalib/scalafmt/ScalafmtWorker.scala +++ b/scalalib/src/mill/scalalib/scalafmt/ScalafmtWorker.scala @@ -3,7 +3,7 @@ package mill.scalalib.scalafmt import mill._ import mill.define.{Discover, ExternalModule, Worker} import mill.modules.Jvm -import mill.util.Ctx +import mill.api.Ctx import scala.collection.mutable diff --git a/scalalib/test/src/mill/scalalib/HelloJavaTests.scala b/scalalib/test/src/mill/scalalib/HelloJavaTests.scala index ff0de5a6..5b7b93b2 100644 --- a/scalalib/test/src/mill/scalalib/HelloJavaTests.scala +++ b/scalalib/test/src/mill/scalalib/HelloJavaTests.scala @@ -2,7 +2,7 @@ package mill package scalalib -import mill.eval.Result +import mill.api.Result import mill.util.{TestEvaluator, TestUtil} import utest._ import utest.framework.TestPath diff --git a/scalalib/test/src/mill/scalalib/HelloWorldTests.scala b/scalalib/test/src/mill/scalalib/HelloWorldTests.scala index 67c4b433..da08f056 100644 --- a/scalalib/test/src/mill/scalalib/HelloWorldTests.scala +++ b/scalalib/test/src/mill/scalalib/HelloWorldTests.scala @@ -5,7 +5,7 @@ import java.util.jar.JarFile import mill._ import mill.define.Target -import mill.eval.Result.Exception +import mill.api.Result.Exception import mill.eval.{Evaluator, Result} import mill.modules.Assembly import mill.scalalib.publish._ diff --git a/scalalib/test/src/mill/scalalib/ResolveDepsTests.scala b/scalalib/test/src/mill/scalalib/ResolveDepsTests.scala index 4240478c..78361625 100644 --- a/scalalib/test/src/mill/scalalib/ResolveDepsTests.scala +++ b/scalalib/test/src/mill/scalalib/ResolveDepsTests.scala @@ -2,7 +2,7 @@ package mill.scalalib import coursier.Cache import coursier.maven.MavenRepository -import mill.eval.Result.{Failure, Success} +import mill.api.Result.{Failure, Success} import mill.eval.{PathRef, Result} import mill.util.Loose.Agg import utest._ diff --git a/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala b/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala index d494760e..705d4682 100644 --- a/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala +++ b/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala @@ -3,18 +3,14 @@ package mill.scalalib.worker import java.io.File import java.util.Optional -import ammonite.util.Colors -import mill.Agg -import mill.eval.PathRef -import mill.scalalib.{CompilationResult, Lib, TestRunner} +import mill.api.Loose.Agg +import mill.api.PathRef import xsbti.compile.{CompilerCache => _, FileAnalysisStore => _, ScalaInstance => _, _} -import mill.scalalib.Dep.isDotty -import mill.scalalib.Lib.{grepJar, scalaBinaryVersion} -import mill.util.{Ctx, PrintLogger} +import mill.scalalib.api.Util.{isDotty, grepJar, scalaBinaryVersion} import sbt.internal.inc._ import sbt.internal.util.{ConsoleOut, MainAppender} import sbt.util.LogExchange - +import mill.scalalib.api.CompilationResult case class MockedLookup(am: File => Optional[CompileAnalysis]) extends PerClasspathEntryLookup { override def analysis(classpathEntry: File): Optional[CompileAnalysis] = am(classpathEntry) @@ -23,8 +19,8 @@ case class MockedLookup(am: File => Optional[CompileAnalysis]) extends PerClassp Locate.definesClass(classpathEntry) } -class ZincWorkerImpl(ctx0: mill.util.Ctx, - compilerBridgeClasspath: Array[String]) extends mill.scalalib.ZincWorkerApi{ +class ZincWorkerImpl(ctx0: mill.api.Ctx, + compilerBridgeClasspath: Array[String]) extends mill.scalalib.api.ZincWorkerApi{ private val ic = new sbt.internal.inc.IncrementalCompilerImpl() val javaOnlyCompilers = { // Keep the classpath as written by the user @@ -53,7 +49,7 @@ class ZincWorkerImpl(ctx0: mill.util.Ctx, compilerClasspath: Agg[os.Path], scalacPluginClasspath: Agg[os.Path], args: Seq[String]) - (implicit ctx: mill.util.Ctx): Boolean = { + (implicit ctx: mill.api.Ctx): Boolean = { val compilers: Compilers = prepareCompilers( scalaVersion, compilerBridgeSources, @@ -79,8 +75,8 @@ class ZincWorkerImpl(ctx0: mill.util.Ctx, os.makeDir.all(workingDir) os.makeDir.all(compiledDest) - val sourceFolder = mill.modules.Util.unpackZip(sourcesJar)(workingDir) - val classloader = mill.util.ClassLoader.create(compilerJars.map(_.toURI.toURL), null)(ctx0) + val sourceFolder = mill.api.IO.unpackZip(sourcesJar)(workingDir) + val classloader = mill.api.ClassLoader.create(compilerJars.map(_.toURI.toURL), null)(ctx0) val compilerMain = classloader.loadClass( if (isDotty(scalaVersion)) "dotty.tools.dotc.Main" @@ -100,7 +96,7 @@ class ZincWorkerImpl(ctx0: mill.util.Ctx, - def discoverMainClasses(compilationResult: CompilationResult)(implicit ctx: mill.util.Ctx): Seq[String] = { + def discoverMainClasses(compilationResult: CompilationResult)(implicit ctx: mill.api.Ctx): Seq[String] = { def toScala[A](o: Optional[A]): Option[A] = if (o.isPresent) Some(o.get) else None toScala(FileAnalysisStore.binary(compilationResult.analysisFile.toIO).get()) @@ -118,7 +114,7 @@ class ZincWorkerImpl(ctx0: mill.util.Ctx, sources: Agg[os.Path], compileClasspath: Agg[os.Path], javacOptions: Seq[String]) - (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] = { + (implicit ctx: mill.api.Ctx): mill.api.Result[CompilationResult] = { compileInternal( upstreamCompileOutput, sources, @@ -138,7 +134,7 @@ class ZincWorkerImpl(ctx0: mill.util.Ctx, compilerBridgeSources: os.Path, compilerClasspath: Agg[os.Path], scalacPluginClasspath: Agg[os.Path]) - (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] = { + (implicit ctx: mill.api.Ctx): mill.api.Result[CompilationResult] = { val compilers: Compilers = prepareCompilers( scalaVersion, compilerBridgeSources, @@ -160,7 +156,7 @@ class ZincWorkerImpl(ctx0: mill.util.Ctx, compilerBridgeSources: os.Path, compilerClasspath: Agg[os.Path], scalacPluginClasspath: Agg[os.Path]) - (implicit ctx: mill.util.Ctx)= { + (implicit ctx: mill.api.Ctx)= { val combinedCompilerClasspath = compilerClasspath ++ scalacPluginClasspath val combinedCompilerJars = combinedCompilerClasspath.toArray.map(_.toIO) @@ -185,7 +181,7 @@ class ZincWorkerImpl(ctx0: mill.util.Ctx, "scala-compiler" val scalaInstance = new ScalaInstance( version = scalaVersion, - loader = mill.util.ClassLoader.create(combinedCompilerJars.map(_.toURI.toURL), null), + loader = mill.api.ClassLoader.create(combinedCompilerJars.map(_.toURI.toURL), null), libraryJar = grepJar(compilerClasspath, "scala-library", scalaVersion).toIO, compilerJar = grepJar(compilerClasspath, compilerName, scalaVersion).toIO, allJars = combinedCompilerJars, @@ -209,7 +205,7 @@ class ZincWorkerImpl(ctx0: mill.util.Ctx, javacOptions: Seq[String], scalacOptions: Seq[String], compilers: Compilers) - (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] = { + (implicit ctx: mill.api.Ctx): mill.api.Result[CompilationResult] = { os.makeDir.all(ctx.dest) val logger = { @@ -282,7 +278,7 @@ class ZincWorkerImpl(ctx0: mill.util.Ctx, ) ) - mill.eval.Result.Success(CompilationResult(zincFile, PathRef(classesDir))) - }catch{case e: CompileFailed => mill.eval.Result.Failure(e.toString)} + mill.api.Result.Success(CompilationResult(zincFile, PathRef(classesDir))) + }catch{case e: CompileFailed => mill.api.Result.Failure(e.toString)} } } diff --git a/scalanativelib/api/src/mill/scalanativelib/api/ScalaNativeWorkerApi.scala b/scalanativelib/api/src/mill/scalanativelib/api/ScalaNativeWorkerApi.scala new file mode 100644 index 00000000..e1fee0da --- /dev/null +++ b/scalanativelib/api/src/mill/scalanativelib/api/ScalaNativeWorkerApi.scala @@ -0,0 +1,60 @@ +package mill.scalanativelib.api + +import upickle.default.{macroRW, ReadWriter => RW} +import java.io.File +import sbt.testing.Framework + +trait ScalaNativeWorkerApi { + def discoverClang: os.Path + def discoverClangPP: os.Path + def discoverTarget(clang: os.Path, workDir: os.Path): String + def discoverCompileOptions: Seq[String] + def discoverLinkingOptions: Seq[String] + + def config(nativeLibJar: os.Path, + mainClass: String, + classpath: Seq[os.Path], + nativeWorkdir: os.Path, + nativeClang: os.Path, + nativeClangPP: os.Path, + nativeTarget: String, + nativeCompileOptions: Seq[String], + nativeLinkingOptions: Seq[String], + nativeGC: String, + nativeLinkStubs: Boolean, + releaseMode: ReleaseMode, + logLevel: NativeLogLevel): NativeConfig + + def defaultGarbageCollector: String + def nativeLink(nativeConfig: NativeConfig, outPath: os.Path): os.Path + + def newScalaNativeFrameWork(framework: Framework, id: Int, testBinary: File, + logLevel: NativeLogLevel, envVars: Map[String, String]): Framework +} + + +sealed abstract class NativeLogLevel(val level: Int) extends Ordered[NativeLogLevel] { + def compare(that: NativeLogLevel) = this.level - that.level +} + +object NativeLogLevel { + case object Error extends NativeLogLevel(200) + case object Warn extends NativeLogLevel(300) + case object Info extends NativeLogLevel(400) + case object Debug extends NativeLogLevel(500) + case object Trace extends NativeLogLevel(600) + + implicit def rw: RW[NativeLogLevel] = macroRW +} + +sealed abstract class ReleaseMode(val name: String) + +object ReleaseMode { + case object Debug extends ReleaseMode("debug") + case object Release extends ReleaseMode("release") + + implicit def rw: RW[ReleaseMode] = macroRW +} + +// result wrapper to preserve some type safety +case class NativeConfig(config: Any) \ No newline at end of file diff --git a/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala b/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala index d8a282de..a7a2b96b 100644 --- a/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala +++ b/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala @@ -6,37 +6,14 @@ import java.net.URLClassLoader import coursier.Cache import coursier.maven.MavenRepository import mill.define.{Target, Task} -import mill.eval.Result +import mill.api.Result import mill.modules.Jvm import mill.scalalib.{Dep, DepSyntax, Lib, SbtModule, ScalaModule, TestModule, TestRunner} import mill.util.Loose.Agg import sbt.testing.{AnnotatedFingerprint, SubclassFingerprint} import sbt.testing.Fingerprint import upickle.default.{ReadWriter => RW, macroRW} - - -sealed abstract class NativeLogLevel(val level: Int) extends Ordered[NativeLogLevel] { - def compare(that: NativeLogLevel) = this.level - that.level -} - -object NativeLogLevel { - case object Error extends NativeLogLevel(200) - case object Warn extends NativeLogLevel(300) - case object Info extends NativeLogLevel(400) - case object Debug extends NativeLogLevel(500) - case object Trace extends NativeLogLevel(600) - - implicit def rw: RW[NativeLogLevel] = macroRW -} - -sealed abstract class ReleaseMode(val name: String) - -object ReleaseMode { - case object Debug extends ReleaseMode("debug") - case object Release extends ReleaseMode("release") - - implicit def rw: RW[ReleaseMode] = macroRW -} +import mill.scalanativelib.api._ trait ScalaNativeModule extends ScalaModule { outer => diff --git a/scalanativelib/src/mill/scalanativelib/ScalaNativeWorkerApi.scala b/scalanativelib/src/mill/scalanativelib/ScalaNativeWorkerApi.scala index be834e89..80325f1e 100644 --- a/scalanativelib/src/mill/scalanativelib/ScalaNativeWorkerApi.scala +++ b/scalanativelib/src/mill/scalanativelib/ScalaNativeWorkerApi.scala @@ -5,7 +5,7 @@ import java.net.URLClassLoader import mill.define.{Discover, Worker} import mill.{Agg, T} -import sbt.testing.Framework +import mill.scalanativelib.api._ class ScalaNativeWorker { @@ -38,38 +38,6 @@ class ScalaNativeWorker { } } - -// result wrapper to preserve some type safety -case class NativeConfig(config: Any) - -trait ScalaNativeWorkerApi { - def discoverClang: os.Path - def discoverClangPP: os.Path - def discoverTarget(clang: os.Path, workDir: os.Path): String - def discoverCompileOptions: Seq[String] - def discoverLinkingOptions: Seq[String] - - def config(nativeLibJar: os.Path, - mainClass: String, - classpath: Seq[os.Path], - nativeWorkdir: os.Path, - nativeClang: os.Path, - nativeClangPP: os.Path, - nativeTarget: String, - nativeCompileOptions: Seq[String], - nativeLinkingOptions: Seq[String], - nativeGC: String, - nativeLinkStubs: Boolean, - releaseMode: ReleaseMode, - logLevel: NativeLogLevel): NativeConfig - - def defaultGarbageCollector: String - def nativeLink(nativeConfig: NativeConfig, outPath: os.Path): os.Path - - def newScalaNativeFrameWork(framework: Framework, id: Int, testBinary: File, - logLevel: NativeLogLevel, envVars: Map[String, String]): Framework -} - object ScalaNativeWorkerApi extends mill.define.ExternalModule { def scalaNativeWorker: Worker[ScalaNativeWorker] = T.worker { new ScalaNativeWorker() } lazy val millDiscover = Discover[this.type] diff --git a/scalanativelib/test/src/mill/scalanativelib/HelloNativeWorldTests.scala b/scalanativelib/test/src/mill/scalanativelib/HelloNativeWorldTests.scala index 37fbfc80..74d4238a 100644 --- a/scalanativelib/test/src/mill/scalanativelib/HelloNativeWorldTests.scala +++ b/scalanativelib/test/src/mill/scalanativelib/HelloNativeWorldTests.scala @@ -12,7 +12,7 @@ import utest._ import scala.collection.JavaConverters._ - +import mill.scalanativelib.api._ object HelloNativeWorldTests extends TestSuite { val workspacePath = TestUtil.getOutPathStatic() / "hello-native-world" diff --git a/scalanativelib/worker/0.3/src/mill/scalanativelib/worker/ScalaNativeWorkerImpl.scala b/scalanativelib/worker/0.3/src/mill/scalanativelib/worker/ScalaNativeWorkerImpl.scala index 8c24a39e..b32e84ff 100644 --- a/scalanativelib/worker/0.3/src/mill/scalanativelib/worker/ScalaNativeWorkerImpl.scala +++ b/scalanativelib/worker/0.3/src/mill/scalanativelib/worker/ScalaNativeWorkerImpl.scala @@ -4,13 +4,13 @@ import java.io.File import java.lang.System.{err, out} import scala.scalanative.build.{Build, Config, Discover, GC, Logger, Mode} -import mill.scalanativelib.{NativeConfig, NativeLogLevel, ReleaseMode} +import mill.scalanativelib.api.{NativeConfig, NativeLogLevel, ReleaseMode} import sbt.testing.Framework import scala.scalanative.testinterface.ScalaNativeFramework -class ScalaNativeWorkerImpl extends mill.scalanativelib.ScalaNativeWorkerApi { +class ScalaNativeWorkerImpl extends mill.scalanativelib.api.ScalaNativeWorkerApi { def logger(level: NativeLogLevel) = Logger( debugFn = msg => if (level >= NativeLogLevel.Debug) out.println(msg), -- cgit v1.2.3