summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2018-02-09 00:14:47 -0800
committerLi Haoyi <haoyi.sg@gmail.com>2018-02-09 08:17:47 -0800
commit8ddd2fa054bc8639c28db2e95b7903e2954fdb7d (patch)
treeaa985f1e715f07eb279e6facad61de8a187e316c /core
parent90d0a3388d280554eaa51371f666d2f7a965a8af (diff)
downloadmill-8ddd2fa054bc8639c28db2e95b7903e2954fdb7d.tar.gz
mill-8ddd2fa054bc8639c28db2e95b7903e2954fdb7d.tar.bz2
mill-8ddd2fa054bc8639c28db2e95b7903e2954fdb7d.zip
.
Diffstat (limited to 'core')
-rw-r--r--core/src/mill/Main.scala83
-rw-r--r--core/src/mill/define/BaseModule.scala10
-rw-r--r--core/src/mill/define/Ctx.scala13
-rw-r--r--core/src/mill/define/Discover.scala7
-rw-r--r--core/src/mill/define/Module.scala2
-rw-r--r--core/src/mill/eval/Evaluator.scala8
-rw-r--r--core/src/mill/main/MagicScopt.scala49
-rw-r--r--core/src/mill/main/MainModule.scala27
-rw-r--r--core/src/mill/main/MainRunner.scala119
-rw-r--r--core/src/mill/main/ReplApplyHandler.scala125
-rw-r--r--core/src/mill/main/Resolve.scala143
-rw-r--r--core/src/mill/main/RunScript.scala231
-rw-r--r--core/src/mill/modules/Jvm.scala257
-rw-r--r--core/src/mill/modules/Util.scala65
-rw-r--r--core/src/mill/package.scala12
-rw-r--r--core/src/mill/util/ParseArgs.scala (renamed from core/src/mill/main/ParseArgs.scala)3
-rw-r--r--core/src/mill/util/Router.scala (renamed from core/src/mill/main/Router.scala)30
-rw-r--r--core/src/mill/util/Scripts.scala (renamed from core/src/mill/main/Scripts.scala)6
-rw-r--r--core/src/mill/util/Watched.scala8
-rw-r--r--core/test/resources/examples/javac/build.sc23
-rw-r--r--core/test/resources/examples/javac/resources/hello.txt1
-rw-r--r--core/test/resources/examples/javac/src/Bar.java4
-rw-r--r--core/test/resources/examples/javac/src/Foo.java7
-rw-r--r--core/test/src/mill/TestMain.scala6
-rw-r--r--core/test/src/mill/UTestFramework.scala11
-rw-r--r--core/test/src/mill/define/ApplicativeTests.scala125
-rw-r--r--core/test/src/mill/define/BasePathTests.scala68
-rw-r--r--core/test/src/mill/define/CacherTests.scala76
-rw-r--r--core/test/src/mill/define/DiscoverTests.scala60
-rw-r--r--core/test/src/mill/define/GraphTests.scala199
-rw-r--r--core/test/src/mill/define/MacroErrorTests.scala83
-rw-r--r--core/test/src/mill/eval/CrossTests.scala56
-rw-r--r--core/test/src/mill/eval/EvaluationTests.scala317
-rw-r--r--core/test/src/mill/eval/FailureTests.scala100
-rw-r--r--core/test/src/mill/eval/JavaCompileJarTests.scala159
-rw-r--r--core/test/src/mill/eval/ModuleTests.scala45
-rw-r--r--core/test/src/mill/eval/TarjanTests.scala91
-rw-r--r--core/test/src/mill/eval/TaskTests.scala95
-rw-r--r--core/test/src/mill/main/JavaCompileJarTests.scala66
-rw-r--r--core/test/src/mill/main/MainTests.scala222
-rw-r--r--core/test/src/mill/main/ParseArgsTest.scala241
-rw-r--r--core/test/src/mill/util/ScriptTestSuite.scala38
-rw-r--r--core/test/src/mill/util/TestEvaluator.scala83
-rw-r--r--core/test/src/mill/util/TestGraphs.scala242
-rw-r--r--core/test/src/mill/util/TestUtil.scala81
45 files changed, 51 insertions, 3646 deletions
diff --git a/core/src/mill/Main.scala b/core/src/mill/Main.scala
deleted file mode 100644
index 3025994c..00000000
--- a/core/src/mill/Main.scala
+++ /dev/null
@@ -1,83 +0,0 @@
-package mill
-
-import ammonite.main.Cli.{formatBlock, genericSignature, replSignature}
-import ammonite.ops._
-import ammonite.util.Util
-
-object Main {
- case class Config(home: ammonite.ops.Path = pwd/'out/'ammonite,
- colored: Option[Boolean] = None,
- help: Boolean = false,
- repl: Boolean = false,
- watch: Boolean = false)
-
- def main(args: Array[String]): Unit = {
-
- import ammonite.main.Cli
-
- var show = false
- val showCliArg = Cli.Arg[Cli.Config, Unit](
- "show",
- None,
- "Display the json-formatted value of the given target, if any",
- (x, _) => {
- show = true
- x
- }
- )
- val removed = Set("predef-code", "home", "no-home-predef")
- val millArgSignature = (Cli.genericSignature :+ showCliArg).filter(a => !removed(a.name))
- Cli.groupArgs(
- args.toList,
- millArgSignature,
- Cli.Config(remoteLogging = false)
- ) match{
- case Left(msg) =>
- System.err.println(msg)
- System.exit(1)
- case Right((cliConfig, _)) if cliConfig.help =>
- val leftMargin = millArgSignature.map(ammonite.main.Cli.showArg(_).length).max + 2
- System.out.println(
- s"""Mill Build Tool
- |usage: mill [mill-options] [target [target-options]]
- |
- |${formatBlock(millArgSignature, leftMargin).mkString(Util.newLine)}""".stripMargin
- )
- System.exit(0)
- case Right((cliConfig, leftoverArgs)) =>
-
- val repl = leftoverArgs.isEmpty
- val config =
- if(!repl) cliConfig
- else cliConfig.copy(
- predefCode =
- """import $file.build, build._
- |implicit val replApplyHandler = mill.main.ReplApplyHandler(
- | interp.colors(),
- | repl.pprinter(),
- | build.millSelf.get,
- | build.millDiscover
- |)
- |repl.pprinter() = replApplyHandler.pprinter
- |import replApplyHandler.generatedEval._
- |
- """.stripMargin,
- welcomeBanner = None
- )
-
- val runner = new mill.main.MainRunner(
- config, show,
- System.out, System.err, System.in
- )
- if (repl){
- runner.printInfo("Loading...")
- runner.runRepl()
- } else {
- val result = runner.runScript(pwd / "build.sc", leftoverArgs)
- System.exit(if(result) 0 else 1)
- }
- }
- }
-}
-
-
diff --git a/core/src/mill/define/BaseModule.scala b/core/src/mill/define/BaseModule.scala
index 5253e691..fccb19ae 100644
--- a/core/src/mill/define/BaseModule.scala
+++ b/core/src/mill/define/BaseModule.scala
@@ -1,8 +1,6 @@
package mill.define
-import mill.main.Router.Overrides
import ammonite.ops.Path
-import mill.main.ParseArgs
object BaseModule{
case class Implicit(value: BaseModule)
@@ -11,7 +9,8 @@ object BaseModule{
abstract class BaseModule(millSourcePath0: Path, external0: Boolean = false)
(implicit millModuleEnclosing0: sourcecode.Enclosing,
millModuleLine0: sourcecode.Line,
- millName0: sourcecode.Name)
+ millName0: sourcecode.Name,
+ millFile0: sourcecode.File)
extends Module()(
mill.define.Ctx.make(
implicitly,
@@ -19,8 +18,9 @@ abstract class BaseModule(millSourcePath0: Path, external0: Boolean = false)
implicitly,
BasePath(millSourcePath0),
Segments(),
- Overrides(0),
- Ctx.External(external0)
+ mill.util.Router.Overrides(0),
+ Ctx.External(external0),
+ millFile0
)
){
// A BaseModule should provide an empty Segments list to it's children, since
diff --git a/core/src/mill/define/Ctx.scala b/core/src/mill/define/Ctx.scala
index 11e9e1f5..6075b804 100644
--- a/core/src/mill/define/Ctx.scala
+++ b/core/src/mill/define/Ctx.scala
@@ -1,6 +1,6 @@
package mill.define
-import mill.main.Router.Overrides
+
import ammonite.ops.{Path, RelPath}
import scala.annotation.implicitNotFound
@@ -57,7 +57,8 @@ case class Ctx(enclosing: String,
millSourcePath: Path,
segments: Segments,
overrides: Int,
- external: Boolean){
+ external: Boolean,
+ fileName: String){
}
object Ctx{
@@ -67,8 +68,9 @@ object Ctx{
millName0: sourcecode.Name,
millModuleBasePath0: BasePath,
segments0: Segments,
- overrides0: mill.main.Router.Overrides,
- external0: External): Ctx = {
+ overrides0: mill.util.Router.Overrides,
+ external0: External,
+ fileName: sourcecode.File): Ctx = {
Ctx(
millModuleEnclosing0.value,
millModuleLine0.value,
@@ -76,7 +78,8 @@ object Ctx{
millModuleBasePath0.value,
segments0,
overrides0.value,
- external0.value
+ external0.value,
+ fileName.value
)
}
} \ No newline at end of file
diff --git a/core/src/mill/define/Discover.scala b/core/src/mill/define/Discover.scala
index fd5bd449..1b6b002a 100644
--- a/core/src/mill/define/Discover.scala
+++ b/core/src/mill/define/Discover.scala
@@ -1,6 +1,7 @@
package mill.define
+import mill.util.Router.EntryPoint
+
import language.experimental.macros
-import mill.main.Router.{EntryPoint, Overrides}
import sourcecode.Compat.Context
import scala.collection.mutable
@@ -41,7 +42,7 @@ object Discover {
}
rec(weakTypeOf[T])
- val router = new mill.main.Router(c)
+ val router = new mill.util.Router(c)
val mapping = for{
discoveredModuleType <- seen
val curCls = discoveredModuleType.asInstanceOf[router.c.Type]
@@ -57,7 +58,7 @@ object Discover {
val (overrides, routes) = overridesRoutes.unzip
val lhs = q"classOf[${discoveredModuleType.typeSymbol.asClass}]"
val clsType = discoveredModuleType.typeSymbol.asClass
- val rhs = q"scala.Seq[(Int, mill.main.Router.EntryPoint[_])](..$overridesRoutes)"
+ val rhs = q"scala.Seq[(Int, mill.util.Router.EntryPoint[_])](..$overridesRoutes)"
q"$lhs -> $rhs"
}
diff --git a/core/src/mill/define/Module.scala b/core/src/mill/define/Module.scala
index a53ed345..bfc15191 100644
--- a/core/src/mill/define/Module.scala
+++ b/core/src/mill/define/Module.scala
@@ -2,12 +2,10 @@ package mill.define
import java.lang.reflect.Modifier
-import mill.main.Router.{EntryPoint, Overrides}
import ammonite.ops.Path
import scala.language.experimental.macros
import scala.reflect.ClassTag
-import scala.reflect.macros.blackbox
/**
* `Module` is a class meant to be extended by `trait`s *only*, in order to
* propagate the implicit parameters forward to the final concrete
diff --git a/core/src/mill/eval/Evaluator.scala b/core/src/mill/eval/Evaluator.scala
index 347ad321..70fab152 100644
--- a/core/src/mill/eval/Evaluator.scala
+++ b/core/src/mill/eval/Evaluator.scala
@@ -2,7 +2,7 @@ package mill.eval
import java.net.URLClassLoader
-import mill.main.Router.EntryPoint
+import mill.util.Router.EntryPoint
import ammonite.ops._
import ammonite.runtime.SpecialClassLoader
import mill.define.{Ctx => _, _}
@@ -330,6 +330,12 @@ class Evaluator[T](val outPath: Path,
object Evaluator{
+ // This needs to be a ThreadLocal because we need to pass it into the body of
+ // the TargetScopt#read call, which does not accept additional parameters.
+ // Until we migrate our CLI parsing off of Scopt (so we can pass the BaseModule
+ // in directly) we are forced to pass it in via a ThreadLocal
+ val currentEvaluator = new ThreadLocal[mill.eval.Evaluator[_]]
+
case class Paths(out: Path,
dest: Path,
meta: Path,
diff --git a/core/src/mill/main/MagicScopt.scala b/core/src/mill/main/MagicScopt.scala
deleted file mode 100644
index acba57cb..00000000
--- a/core/src/mill/main/MagicScopt.scala
+++ /dev/null
@@ -1,49 +0,0 @@
-package mill.main
-import mill.define.ExternalModule
-import mill.main.ParseArgs
-
-object MagicScopt{
- // This needs to be a ThreadLocal because we need to pass it into the body of
- // the TargetScopt#read call, which does not accept additional parameters.
- // Until we migrate our CLI parsing off of Scopt (so we can pass the BaseModule
- // in directly) we are forced to pass it in via a ThreadLocal
- val currentEvaluator = new ThreadLocal[mill.eval.Evaluator[_]]
-
- case class Tasks[T](items: Seq[mill.define.NamedTask[T]])
-}
-class EvaluatorScopt[T]()
- extends scopt.Read[mill.eval.Evaluator[T]]{
- def arity = 0
- def reads = s => try{
- MagicScopt.currentEvaluator.get.asInstanceOf[mill.eval.Evaluator[T]]
- }
-}
-class TargetScopt[T]()
- extends scopt.Read[MagicScopt.Tasks[T]]{
- def arity = 0
- def reads = s => {
- val rootModule = MagicScopt.currentEvaluator.get.rootModule
- val d = rootModule.millDiscover
- val (expanded, leftover) = ParseArgs(Seq(s)).fold(e => throw new Exception(e), identity)
- val resolved = expanded.map{
- case (Some(scoping), segments) =>
- val moduleCls = rootModule.getClass.getClassLoader.loadClass(scoping.render + "$")
- val externalRootModule = moduleCls.getField("MODULE$").get(moduleCls).asInstanceOf[ExternalModule]
- val crossSelectors = segments.value.map {
- case mill.define.Segment.Cross(x) => x.toList.map(_.toString)
- case _ => Nil
- }
- mill.main.Resolve.resolve(segments.value.toList, externalRootModule, d, leftover, crossSelectors.toList, Nil)
- case (None, segments) =>
- val crossSelectors = segments.value.map {
- case mill.define.Segment.Cross(x) => x.toList.map(_.toString)
- case _ => Nil
- }
- mill.main.Resolve.resolve(segments.value.toList, rootModule, d, leftover, crossSelectors.toList, Nil)
- }
- mill.util.EitherOps.sequence(resolved) match{
- case Left(s) => throw new Exception(s)
- case Right(ts) => MagicScopt.Tasks(ts.flatten).asInstanceOf[MagicScopt.Tasks[T]]
- }
- }
-} \ No newline at end of file
diff --git a/core/src/mill/main/MainModule.scala b/core/src/mill/main/MainModule.scala
deleted file mode 100644
index fd46fb77..00000000
--- a/core/src/mill/main/MainModule.scala
+++ /dev/null
@@ -1,27 +0,0 @@
-package mill.main
-
-trait MainModule extends mill.Module{
- implicit def millDiscover: mill.define.Discover[_]
- implicit def millScoptTargetReads[T] = new mill.main.TargetScopt[T]()
- implicit def millScoptEvaluatorReads[T] = new mill.main.EvaluatorScopt[T]()
- def resolve(targets: mill.main.MagicScopt.Tasks[Any]*) = mill.T.command{
- targets.flatMap(_.items).foreach(println)
- }
- def all(evaluator: mill.eval.Evaluator[Any],
- targets: mill.main.MagicScopt.Tasks[Any]*) = mill.T.command{
- val (watched, res) = mill.main.RunScript.evaluate(
- evaluator,
- mill.util.Strict.Agg.from(targets.flatMap(_.items))
- )
- }
- def show(evaluator: mill.eval.Evaluator[Any],
- targets: mill.main.MagicScopt.Tasks[Any]*) = mill.T.command{
- val (watched, res) = mill.main.RunScript.evaluate(
- evaluator,
- mill.util.Strict.Agg.from(targets.flatMap(_.items))
- )
- for(json <- res.right.get.flatMap(_._2)){
- println(json)
- }
- }
-}
diff --git a/core/src/mill/main/MainRunner.scala b/core/src/mill/main/MainRunner.scala
deleted file mode 100644
index 9004de39..00000000
--- a/core/src/mill/main/MainRunner.scala
+++ /dev/null
@@ -1,119 +0,0 @@
-package mill.main
-import java.io.{InputStream, OutputStream, PrintStream}
-
-import ammonite.Main
-import ammonite.interp.{Interpreter, Preprocessor}
-import ammonite.ops.Path
-import ammonite.util._
-import mill.define.Discover
-import mill.eval.{Evaluator, PathRef}
-import mill.util.PrintLogger
-import upickle.Js
-
-/**
- * Customized version of [[ammonite.MainRunner]], allowing us to run Mill
- * `build.sc` scripts with mill-specific tweaks such as a custom
- * `scriptCodeWrapper` or with a persistent evaluator between runs.
- */
-class MainRunner(config: ammonite.main.Cli.Config,
- show: Boolean,
- outprintStream: PrintStream,
- errPrintStream: PrintStream,
- stdIn: InputStream)
- extends ammonite.MainRunner(
- config, outprintStream, errPrintStream,
- stdIn, outprintStream, errPrintStream
- ){
-
- var lastEvaluator: Option[(Seq[(Path, Long)], Evaluator[Any])] = None
-
- override def runScript(scriptPath: Path, scriptArgs: List[String]) =
- watchLoop(
- isRepl = false,
- printing = true,
- mainCfg => {
- val (result, interpWatched) = RunScript.runScript(
- mainCfg.wd,
- scriptPath,
- mainCfg.instantiateInterpreter(),
- scriptArgs,
- lastEvaluator,
- new PrintLogger(
- colors != ammonite.util.Colors.BlackWhite,
- colors,
- if (show) errPrintStream else outprintStream,
- errPrintStream,
- errPrintStream
- )
- )
-
- result match{
- case Res.Success(data) =>
- val (eval, evaluationWatches, res) = data
-
- lastEvaluator = Some((interpWatched, eval))
-
- (Res(res), interpWatched ++ evaluationWatches)
- case _ => (result, interpWatched)
- }
- }
- )
-
- override def handleWatchRes[T](res: Res[T], printing: Boolean) = {
- res match{
- case Res.Success(value) =>
-// if (show){
-// for(json <- value.asInstanceOf[Seq[Js.Value]]){
-// outprintStream.println(json)
-// }
-// }
-
- true
-
- case _ => super.handleWatchRes(res, printing)
- }
-
- }
- override def initMain(isRepl: Boolean) = {
- super.initMain(isRepl).copy(
- scriptCodeWrapper = CustomCodeWrapper,
- // Ammonite does not properly forward the wd from CliConfig to Main, so
- // force forward it outselves
- wd = config.wd
- )
- }
- object CustomCodeWrapper extends Preprocessor.CodeWrapper {
- def top(pkgName: Seq[Name], imports: Imports, indexedWrapperName: Name) = {
- val wrapName = indexedWrapperName.backticked
- val literalPath = pprint.Util.literalize(config.wd.toString)
- s"""
- |package ${pkgName.head.encoded}
- |package ${Util.encodeScalaSourcePath(pkgName.tail)}
- |$imports
- |import mill._
- |object $wrapName
- |extends mill.define.BaseModule(ammonite.ops.Path($literalPath))
- |with $wrapName{
- | // Stub to make sure Ammonite has something to call after it evaluates a script,
- | // even if it does nothing...
- | def $$main() = Iterator[String]()
- |
- | implicit def millDiscover: mill.define.Discover[this.type] = mill.define.Discover[this.type]
- | // Need to wrap the returned Module in Some(...) to make sure it
- | // doesn't get picked up during reflective child-module discovery
- | val millSelf = Some(this)
- |}
- |
- |sealed trait $wrapName extends mill.main.MainModule{
- |""".stripMargin
- }
-
-
- def bottom(printCode: String, indexedWrapperName: Name, extraCode: String) = {
- // We need to disable the `$main` method definition inside the wrapper class,
- // because otherwise it might get picked up by Ammonite and run as a static
- // class method, which blows up since it's defined as an instance method
- "\n}"
- }
- }
-}
diff --git a/core/src/mill/main/ReplApplyHandler.scala b/core/src/mill/main/ReplApplyHandler.scala
deleted file mode 100644
index 0849f2c8..00000000
--- a/core/src/mill/main/ReplApplyHandler.scala
+++ /dev/null
@@ -1,125 +0,0 @@
-package mill.main
-
-
-import mill.define.Applicative.ApplyHandler
-import mill.define.Segment.Label
-import mill.define._
-import mill.eval.{Evaluator, Result}
-import mill.util.Strict.Agg
-
-import scala.collection.mutable
-object ReplApplyHandler{
- def apply[T](colors: ammonite.util.Colors,
- pprinter0: pprint.PPrinter,
- rootModule: mill.define.BaseModule,
- discover: Discover[_]) = {
- new ReplApplyHandler(
- pprinter0,
- new Evaluator(
- ammonite.ops.pwd / 'out,
- ammonite.ops.pwd / 'out,
- rootModule,
- discover,
- new mill.util.PrintLogger(
- colors != ammonite.util.Colors.BlackWhite,
- colors,
- System.out,
- System.err,
- System.err
- )
- )
- )
- }
-}
-class ReplApplyHandler(pprinter0: pprint.PPrinter,
- evaluator: Evaluator[_]) extends ApplyHandler[Task] {
- // Evaluate classLoaderSig only once in the REPL to avoid busting caches
- // as the user enters more REPL commands and changes the classpath
- val classLoaderSig = Evaluator.classLoaderSig
- override def apply[V](t: Task[V]) = {
- val res = evaluator.evaluate(Agg(t))
- res.values match{
- case Seq(head: V) => head
- case Nil =>
- val msg = new mutable.StringBuilder()
- msg.append(res.failing.keyCount + " targets failed\n")
- for((k, vs) <- res.failing.items){
- msg.append(k match{
- case Left(t) => "Anonymous Task\n"
- case Right(k) => k.segments.render + "\n"
- })
-
- for(v <- vs){
- v match{
- case Result.Failure(m, _) => msg.append(m + "\n")
- case Result.Exception(t, outerStack) =>
- msg.append(
- t.toString +
- t.getStackTrace.dropRight(outerStack.value.length).map("\n " + _).mkString +
- "\n"
- )
-
- }
- }
- }
- throw new Exception(msg.toString)
- }
- }
-
- val generatedEval = new EvalGenerated(evaluator)
-
- val millHandlers: PartialFunction[Any, pprint.Tree] = {
- case c: Cross[_] =>
- pprint.Tree.Lazy( ctx =>
- Iterator(c.millOuterCtx.enclosing , ":", c.millOuterCtx.lineNum.toString, ctx.applyPrefixColor("\nChildren:").toString) ++
- c.items.iterator.map(x =>
- "\n (" + x._1.map(pprint.PPrinter.BlackWhite.apply(_)).mkString(", ") + ")"
- )
- )
- case m: mill.Module if evaluator.rootModule.millInternal.modules.contains(m) =>
- pprint.Tree.Lazy( ctx =>
- Iterator(m.millInternal.millModuleEnclosing, ":", m.millInternal.millModuleLine.toString) ++
- (if (m.millInternal.reflect[mill.Module].isEmpty) Nil
- else
- ctx.applyPrefixColor("\nChildren:").toString +:
- m.millInternal.reflect[mill.Module].map("\n ." + _.millOuterCtx.segment.pathSegments.mkString("."))) ++
- (evaluator.discover.value.get(m.getClass) match{
- case None => Nil
- case Some(commands) =>
- ctx.applyPrefixColor("\nCommands:").toString +: commands.map{c =>
- "\n ." + c._2.name + "(" +
- c._2.argSignatures.map(s => s.name + ": " + s.typeString).mkString(", ") +
- ")()"
- }
- }) ++
- (if (m.millInternal.reflect[Target[_]].isEmpty) Nil
- else {
- Seq(ctx.applyPrefixColor("\nTargets:").toString) ++
- m.millInternal.reflect[Target[_]].sortBy(_.label).map(t =>
- "\n ." + t.label + "()"
- )
- })
-
- )
- case t: mill.define.Target[_] if evaluator.rootModule.millInternal.targets.contains(t) =>
- val seen = mutable.Set.empty[Task[_]]
- def rec(t: Task[_]): Seq[Segments] = {
- if (seen(t)) Nil // do nothing
- else t match {
- case t: Target[_] if evaluator.rootModule.millInternal.targets.contains(t) =>
- Seq(t.ctx.segments)
- case _ =>
- seen.add(t)
- t.inputs.flatMap(rec)
- }
- }
- pprint.Tree.Lazy(ctx =>
- Iterator(t.ctx.enclosing, ":", t.ctx.lineNum.toString, "\n", ctx.applyPrefixColor("Inputs:").toString) ++
- t.inputs.iterator.flatMap(rec).map("\n " + _.render)
- )
-
- }
- val pprinter = pprinter0.copy(
- additionalHandlers = millHandlers orElse pprinter0.additionalHandlers
- )
-}
diff --git a/core/src/mill/main/Resolve.scala b/core/src/mill/main/Resolve.scala
deleted file mode 100644
index 1932c241..00000000
--- a/core/src/mill/main/Resolve.scala
+++ /dev/null
@@ -1,143 +0,0 @@
-package mill.main
-
-import mill.define._
-import mill.define.TaskModule
-import mill.main.Router.EntryPoint
-import ammonite.util.{Res}
-
-object Resolve {
- def resolve[T, V](remainingSelector: List[Segment],
- obj: mill.Module,
- discover: Discover[_],
- rest: Seq[String],
- remainingCrossSelectors: List[List[String]],
- revSelectorsSoFar: List[Segment]): Either[String, Seq[NamedTask[Any]]] = {
-
- remainingSelector match{
- case Segment.Cross(_) :: Nil => Left("Selector cannot start with a [cross] segment")
- case Segment.Label(last) :: Nil =>
- val target =
- obj
- .millInternal
- .reflect[Target[_]]
- .find(_.label == last)
- .map(Right(_))
-
- def shimArgsig[T](a: mill.main.Router.ArgSig[T, _]) = {
- ammonite.main.Router.ArgSig[T](
- a.name,
- a.typeString,
- a.doc,
- a.default
- )
- }
- def invokeCommand(target: mill.Module, name: String) = for{
- (cls, entryPoints) <- discover.value
- if cls.isAssignableFrom(target.getClass)
- ep <- entryPoints
- if ep._2.name == name
- } yield mill.main.Scripts.runMainMethod(
- target,
- ep._2.asInstanceOf[EntryPoint[mill.Module]],
- ammonite.main.Scripts.groupArgs(rest.toList)
- ) match{
- case Res.Success(v: Command[_]) => Right(v)
- case Res.Failure(msg) => Left(msg)
- case Res.Exception(ex, msg) =>
- val sw = new java.io.StringWriter()
- ex.printStackTrace(new java.io.PrintWriter(sw))
- val prefix = if (msg.nonEmpty) msg + "\n" else msg
- Left(prefix + sw.toString)
-
- }
-
- val runDefault = for{
- child <- obj.millInternal.reflectNestedObjects[mill.Module]
- if child.millOuterCtx.segment == Segment.Label(last)
- res <- child match{
- case taskMod: TaskModule => Some(invokeCommand(child, taskMod.defaultCommandName()).headOption)
- case _ => None
- }
- } yield res
-
- val command = invokeCommand(obj, last).headOption
-
- command orElse target orElse runDefault.flatten.headOption match{
- case None => Left("Cannot resolve task " +
- Segments((Segment.Label(last) :: revSelectorsSoFar).reverse:_*).render
- )
- // Contents of `either` *must* be a `Task`, because we only select
- // methods returning `Task` in the discovery process
- case Some(either) => either.right.map(Seq(_))
- }
-
-
- case head :: tail =>
- val newRevSelectorsSoFar = head :: revSelectorsSoFar
- head match{
- case Segment.Label(singleLabel) =>
- if (singleLabel == "__") {
-
- val matching =
- obj.millInternal.modules
- .map(resolve(tail, _, discover, rest, remainingCrossSelectors, newRevSelectorsSoFar))
- .collect{case Right(vs) => vs}.flatten
-
- if (matching.nonEmpty)Right(matching)
- else Left("Cannot resolve module " + Segments(newRevSelectorsSoFar.reverse:_*).render)
- } else if (singleLabel == "_") {
-
- val matching =
- obj.millModuleDirectChildren
- .map(resolve(tail, _, discover, rest, remainingCrossSelectors, newRevSelectorsSoFar))
- .collect{case Right(vs) => vs}.flatten
-
- if (matching.nonEmpty)Right(matching)
- else Left("Cannot resolve module " + Segments(newRevSelectorsSoFar.reverse:_*).render)
- }else{
-
- obj.millInternal.reflectNestedObjects[mill.Module].find{
- _.millOuterCtx.segment == Segment.Label(singleLabel)
- } match{
- case Some(child: mill.Module) => resolve(tail, child, discover, rest, remainingCrossSelectors, newRevSelectorsSoFar)
- case None => Left("Cannot resolve module " + Segments(newRevSelectorsSoFar.reverse:_*).render)
- }
- }
-
- case Segment.Cross(cross) =>
- obj match{
- case c: Cross[_] =>
- if(cross == Seq("__")){
- val matching =
- for ((k, v) <- c.items)
- yield resolve(tail, v.asInstanceOf[mill.Module], discover, rest, remainingCrossSelectors, newRevSelectorsSoFar)
-
- val results = matching.collect{case Right(res) => res}.flatten
-
- if (results.isEmpty) Left("Cannot resolve cross " + Segments(newRevSelectorsSoFar.reverse:_*).render)
- else Right(results)
- } else if (cross.contains("_")){
- val matching = for {
- (k, v) <- c.items
- if k.length == cross.length
- if k.zip(cross).forall { case (l, r) => l == r || r == "_" }
- } yield resolve(tail, v.asInstanceOf[mill.Module], discover, rest, remainingCrossSelectors, newRevSelectorsSoFar)
-
- val results = matching.collect{case Right(res) => res}.flatten
-
- if (results.isEmpty) Left("Cannot resolve cross " + Segments(newRevSelectorsSoFar.reverse:_*).render)
- else Right(results)
- }else{
- c.itemMap.get(cross.toList) match{
- case Some(m: mill.Module) => resolve(tail, m, discover, rest, remainingCrossSelectors, newRevSelectorsSoFar)
- case None => Left("Cannot resolve cross " + Segments(newRevSelectorsSoFar.reverse:_*).render)
- }
- }
- case _ => Left("Cannot resolve cross " + Segments(newRevSelectorsSoFar.reverse:_*).render)
- }
- }
-
- case Nil => Left("Selector cannot be empty")
- }
- }
-}
diff --git a/core/src/mill/main/RunScript.scala b/core/src/mill/main/RunScript.scala
deleted file mode 100644
index 17d520e7..00000000
--- a/core/src/mill/main/RunScript.scala
+++ /dev/null
@@ -1,231 +0,0 @@
-package mill.main
-
-import java.nio.file.NoSuchFileException
-
-import ammonite.interp.Interpreter
-import ammonite.ops.{Path, read}
-import ammonite.runtime.SpecialClassLoader
-import ammonite.util.Util.CodeSource
-import ammonite.util.{Name, Res, Util}
-import mill.{PathRef, define}
-import mill.define.{Discover, ExternalModule, Segment, Task}
-import mill.eval.{Evaluator, Result}
-import mill.util.{EitherOps, Logger}
-import mill.util.Strict.Agg
-import upickle.Js
-
-/**
- * Custom version of ammonite.main.Scripts, letting us run the build.sc script
- * directly without going through Ammonite's main-method/argument-parsing
- * subsystem
- */
-object RunScript{
- def runScript(wd: Path,
- path: Path,
- instantiateInterpreter: => Either[(Res.Failing, Seq[(Path, Long)]), ammonite.interp.Interpreter],
- scriptArgs: Seq[String],
- lastEvaluator: Option[(Seq[(Path, Long)], Evaluator[Any])],
- log: Logger)
- : (Res[(Evaluator[Any], Seq[(Path, Long)], Either[String, Seq[Js.Value]])], Seq[(Path, Long)]) = {
-
- val (evalRes, interpWatched) = lastEvaluator match{
- case Some((prevInterpWatchedSig, prevEvaluator))
- if watchedSigUnchanged(prevInterpWatchedSig) =>
-
- (Res.Success(prevEvaluator), prevInterpWatchedSig)
-
- case _ =>
- instantiateInterpreter match{
- case Left((res, watched)) => (res, watched)
- case Right(interp) =>
- interp.watch(path)
- val eval =
- for((mapping, discover) <- evaluateMapping(wd, path, interp))
- yield new Evaluator[Any](
- wd / 'out, wd / 'out, mapping, discover, log,
- mapping.getClass.getClassLoader.asInstanceOf[SpecialClassLoader].classpathSignature
- )
-
- (eval, interp.watchedFiles)
- }
- }
-
- val evaluated = for{
- evaluator <- evalRes
- (evalWatches, res) <- Res(evaluateTarget(evaluator, scriptArgs))
- } yield {
- val alreadyStale = evalWatches.exists(p => p.sig != new PathRef(p.path, p.quick).sig)
- // If the file changed between the creation of the original
- // `PathRef` and the current moment, use random junk .sig values
- // to force an immediate re-run. Otherwise calculate the
- // pathSignatures the same way Ammonite would and hand over the
- // values, so Ammonite can watch them and only re-run if they
- // subsequently change
- val evaluationWatches =
- if (alreadyStale) evalWatches.map(_.path -> util.Random.nextLong())
- else evalWatches.map(p => p.path -> Interpreter.pathSignature(p.path))
-
- (evaluator, evaluationWatches, res.map(_.flatMap(_._2)))
- }
- (evaluated, interpWatched)
- }
-
- def watchedSigUnchanged(sig: Seq[(Path, Long)]) = {
- sig.forall{case (p, l) => Interpreter.pathSignature(p) == l}
- }
-
- def evaluateMapping(wd: Path,
- path: Path,
- interp: ammonite.interp.Interpreter): Res[(mill.define.BaseModule, Discover[Any])] = {
-
- val (pkg, wrapper) = Util.pathToPackageWrapper(Seq(), path relativeTo wd)
-
- for {
- scriptTxt <-
- try Res.Success(Util.normalizeNewlines(read(path)))
- catch { case e: NoSuchFileException => Res.Failure("Script file not found: " + path) }
-
- processed <- interp.processModule(
- scriptTxt,
- CodeSource(wrapper, pkg, Seq(Name("ammonite"), Name("$file")), Some(path)),
- autoImport = true,
- extraCode = "",
- hardcoded = true
- )
-
- buildClsName <- processed.blockInfo.lastOption match {
- case Some(meta) => Res.Success(meta.id.wrapperPath)
- case None => Res.Skip
- }
-
- buildCls = interp
- .evalClassloader
- .loadClass(buildClsName)
-
- module <- try {
- Util.withContextClassloader(interp.evalClassloader) {
- Res.Success(
- buildCls.getMethod("millSelf")
- .invoke(null)
- .asInstanceOf[Some[mill.define.BaseModule]]
- .get
- )
- }
- } catch {
- case e: Throwable => Res.Exception(e, "")
- }
- discover <- try {
- Util.withContextClassloader(interp.evalClassloader) {
- Res.Success(
- buildCls.getMethod("millDiscover")
- .invoke(module)
- .asInstanceOf[Discover[Any]]
- )
- }
- } catch {
- case e: Throwable => Res.Exception(e, "")
- }
-// _ <- Res(consistencyCheck(mapping))
- } yield (module, discover)
- }
-
- def evaluateTarget[T](evaluator: Evaluator[T], scriptArgs: Seq[String]) = {
- for {
- parsed <- ParseArgs(scriptArgs)
- (selectors, args) = parsed
- targets <- {
- val selected = selectors.map { case (scopedSel, sel) =>
- val (rootModule, discover) = scopedSel match{
- case None => (evaluator.rootModule, evaluator.discover)
- case Some(scoping) =>
- val moduleCls =
- evaluator.rootModule.getClass.getClassLoader.loadClass(scoping.render + "$")
-
- val rootModule = moduleCls.getField("MODULE$").get(moduleCls).asInstanceOf[ExternalModule]
- (rootModule, rootModule.millDiscover)
- }
- val crossSelectors = sel.value.map {
- case Segment.Cross(x) => x.toList.map(_.toString)
- case _ => Nil
- }
-
- try {
- // We inject the `evaluator.rootModule` into the TargetScopt, rather
- // than the `rootModule`, because even if you are running an external
- // module we still want you to be able to resolve targets from your
- // main build. Resolving targets from external builds as CLI arguments
- // is not currently supported
- mill.main.MagicScopt.currentEvaluator.set(evaluator)
- mill.main.Resolve.resolve(
- sel.value.toList, rootModule,
- discover,
- args, crossSelectors.toList, Nil
- )
- } finally{
- mill.main.MagicScopt.currentEvaluator.set(null)
- }
- }
- EitherOps.sequence(selected)
- }
- (watched, res) = evaluate(
- evaluator,
- Agg.from(targets.flatten.distinct)
- )
- } yield (watched, res)
- }
-
- def evaluate(evaluator: Evaluator[_],
- targets: Agg[Task[Any]]): (Seq[PathRef], Either[String, Seq[(Any, Option[upickle.Js.Value])]]) = {
- val evaluated = evaluator.evaluate(targets)
- val watched = evaluated.results
- .iterator
- .collect {
- case (t: define.Sources, Result.Success(p: Seq[PathRef])) => p
- }
- .flatten
- .toSeq
-
- val errorStr =
- (for((k, fs) <- evaluated.failing.items()) yield {
- val ks = k match{
- case Left(t) => t.toString
- case Right(t) => t.segments.render
- }
- val fss = fs.map{
- case Result.Exception(t, outerStack) =>
- t.toString +
- t.getStackTrace.dropRight(outerStack.value.length).map("\n " + _).mkString
- case Result.Failure(t, _) => t
- }
- s"$ks ${fss.mkString(", ")}"
- }).mkString("\n")
-
- evaluated.failing.keyCount match {
- case 0 =>
- val json = for(t <- targets.toSeq) yield {
- t match {
- case t: mill.define.NamedTask[_] =>
- val jsonFile = Evaluator
- .resolveDestPaths(evaluator.outPath, t.ctx.segments)
- .meta
- val metadata = upickle.json.read(jsonFile.toIO)
- Some(metadata(1))
-
- case _ => None
- }
- }
-
- watched -> Right(evaluated.values.zip(json))
- case n => watched -> Left(s"$n targets failed\n$errorStr")
- }
- }
-
-// def consistencyCheck[T](mapping: Discovered.Mapping[T]): Either[String, Unit] = {
-// val consistencyErrors = Discovered.consistencyCheck(mapping)
-// if (consistencyErrors.nonEmpty) {
-// Left(s"Failed Discovered.consistencyCheck: ${consistencyErrors.map(_.render)}")
-// } else {
-// Right(())
-// }
-// }
-}
diff --git a/core/src/mill/modules/Jvm.scala b/core/src/mill/modules/Jvm.scala
deleted file mode 100644
index 297dcf1f..00000000
--- a/core/src/mill/modules/Jvm.scala
+++ /dev/null
@@ -1,257 +0,0 @@
-package mill.modules
-
-import java.io.FileOutputStream
-import java.lang.reflect.Modifier
-import java.net.URLClassLoader
-import java.nio.file.attribute.PosixFilePermission
-import java.util.jar.{JarEntry, JarFile, JarOutputStream}
-
-import ammonite.ops._
-import mill.define.Task
-import mill.eval.PathRef
-import mill.util.{Ctx, Loose}
-import mill.util.Ctx.Log
-import mill.util.Loose.Agg
-import upickle.default.{Reader, Writer}
-
-import scala.annotation.tailrec
-import scala.collection.mutable
-import scala.reflect.ClassTag
-
-
-object Jvm {
-
- def interactiveSubprocess(mainClass: String,
- classPath: Agg[Path],
- jvmArgs: Seq[String] = Seq.empty,
- envArgs: Map[String, String] = Map.empty,
- mainArgs: Seq[String] = Seq.empty,
- workingDir: Path = null): Unit = {
- import ammonite.ops.ImplicitWd._
- val commandArgs =
- Vector("java") ++
- jvmArgs ++
- Vector("-cp", classPath.mkString(":"), mainClass) ++
- mainArgs
-
- %.copy(envArgs = envArgs)(commandArgs)(workingDir)
- }
-
- def runLocal(mainClass: String,
- classPath: Agg[Path],
- mainArgs: Seq[String] = Seq.empty)
- (implicit ctx: Ctx): Unit = {
- inprocess(classPath, classLoaderOverrideSbtTesting = false, cl => {
- getMainMethod(mainClass, cl).invoke(null, mainArgs.toArray)
- })
- }
-
- private def getMainMethod(mainClassName: String, cl: ClassLoader) = {
- val mainClass = cl.loadClass(mainClassName)
- val method = mainClass.getMethod("main", classOf[Array[String]])
- // jvm allows the actual main class to be non-public and to run a method in the non-public class,
- // we need to make it accessible
- method.setAccessible(true)
- val modifiers = method.getModifiers
- if (!Modifier.isPublic(modifiers))
- throw new NoSuchMethodException(mainClassName + ".main is not public")
- if (!Modifier.isStatic(modifiers))
- throw new NoSuchMethodException(mainClassName + ".main is not static")
- method
- }
-
-
-
- def inprocess[T](classPath: Agg[Path],
- classLoaderOverrideSbtTesting: Boolean,
- body: ClassLoader => T): T = {
- val cl = if (classLoaderOverrideSbtTesting) {
- val outerClassLoader = getClass.getClassLoader
- new URLClassLoader(classPath.map(_.toIO.toURI.toURL).toArray, null){
- override def findClass(name: String) = {
- if (name.startsWith("sbt.testing.")){
- outerClassLoader.loadClass(name)
- }else{
- super.findClass(name)
- }
- }
- }
- } else {
- new URLClassLoader(classPath.map(_.toIO.toURI.toURL).toArray, null)
- }
- val oldCl = Thread.currentThread().getContextClassLoader
- Thread.currentThread().setContextClassLoader(cl)
- try {
- body(cl)
- }finally{
- Thread.currentThread().setContextClassLoader(oldCl)
- cl.close()
- }
- }
-
- def subprocess(mainClass: String,
- classPath: Agg[Path],
- jvmArgs: Seq[String] = Seq.empty,
- envArgs: Map[String, String] = Map.empty,
- mainArgs: Seq[String] = Seq.empty,
- workingDir: Path = null)
- (implicit ctx: Ctx) = {
-
- val commandArgs =
- Vector("java") ++
- jvmArgs ++
- Vector("-cp", classPath.mkString(":"), mainClass) ++
- mainArgs
-
- val workingDir1 = Option(workingDir).getOrElse(ctx.dest)
- mkdir(workingDir1)
- val builder =
- new java.lang.ProcessBuilder()
- .directory(workingDir1.toIO)
- .command(commandArgs:_*)
- .redirectOutput(ProcessBuilder.Redirect.PIPE)
- .redirectError(ProcessBuilder.Redirect.PIPE)
-
- for((k, v) <- envArgs) builder.environment().put(k, v)
- val proc = builder.start()
- val stdout = proc.getInputStream
- val stderr = proc.getErrorStream
- val sources = Seq(
- (stdout, Left(_: Bytes), ctx.log.outputStream),
- (stderr, Right(_: Bytes),ctx.log.errorStream )
- )
- val chunks = mutable.Buffer.empty[Either[Bytes, Bytes]]
- while(
- // Process.isAlive doesn't exist on JDK 7 =/
- util.Try(proc.exitValue).isFailure ||
- stdout.available() > 0 ||
- stderr.available() > 0
- ){
- var readSomething = false
- for ((subStream, wrapper, parentStream) <- sources){
- while (subStream.available() > 0){
- readSomething = true
- val array = new Array[Byte](subStream.available())
- val actuallyRead = subStream.read(array)
- chunks.append(wrapper(new ammonite.ops.Bytes(array)))
- parentStream.write(array, 0, actuallyRead)
- }
- }
- // if we did not read anything sleep briefly to avoid spinning
- if(!readSomething)
- Thread.sleep(2)
- }
-
- if (proc.exitValue() != 0) throw new InteractiveShelloutException()
- else ammonite.ops.CommandResult(proc.exitValue(), chunks)
- }
-
- private def createManifest(mainClass: Option[String]) = {
- val m = new java.util.jar.Manifest()
- m.getMainAttributes.put(java.util.jar.Attributes.Name.MANIFEST_VERSION, "1.0")
- m.getMainAttributes.putValue( "Created-By", "Scala mill" )
- mainClass.foreach(
- m.getMainAttributes.put(java.util.jar.Attributes.Name.MAIN_CLASS, _)
- )
- m
- }
-
- def createJar(inputPaths: Agg[Path], mainClass: Option[String] = None)
- (implicit ctx: Ctx.Dest): PathRef = {
- val outputPath = ctx.dest / "out.jar"
- rm(outputPath)
-
- val seen = mutable.Set.empty[RelPath]
- seen.add("META-INF" / "MANIFEST.MF")
- val jar = new JarOutputStream(
- new FileOutputStream(outputPath.toIO),
- createManifest(mainClass)
- )
-
- try{
- assert(inputPaths.forall(exists(_)))
- for{
- p <- inputPaths
- (file, mapping) <-
- if (p.isFile) Iterator(p -> empty/p.last)
- else ls.rec(p).filter(_.isFile).map(sub => sub -> sub.relativeTo(p))
- if !seen(mapping)
- } {
- seen.add(mapping)
- val entry = new JarEntry(mapping.toString)
- entry.setTime(file.mtime.toMillis)
- jar.putNextEntry(entry)
- jar.write(read.bytes(file))
- jar.closeEntry()
- }
- } finally {
- jar.close()
- }
-
- PathRef(outputPath)
- }
-
- def createAssembly(inputPaths: Agg[Path],
- mainClass: Option[String] = None,
- prependShellScript: String = "")
- (implicit ctx: Ctx.Dest): PathRef = {
- val outputPath = ctx.dest / "out.jar"
- rm(outputPath)
-
- if(inputPaths.nonEmpty) {
-
- val output = new FileOutputStream(outputPath.toIO)
-
- // Prepend shell script and make it executable
- if (prependShellScript.nonEmpty) {
- output.write((prependShellScript + "\n").getBytes)
- val perms = java.nio.file.Files.getPosixFilePermissions(outputPath.toNIO)
- perms.add(PosixFilePermission.GROUP_EXECUTE)
- perms.add(PosixFilePermission.OWNER_EXECUTE)
- perms.add(PosixFilePermission.OTHERS_EXECUTE)
- java.nio.file.Files.setPosixFilePermissions(outputPath.toNIO, perms)
- }
-
- val jar = new JarOutputStream(
- output,
- createManifest(mainClass)
- )
-
- val seen = mutable.Set("META-INF/MANIFEST.MF")
- try{
-
-
- for{
- p <- inputPaths
- if exists(p)
- (file, mapping) <-
- if (p.isFile) {
- val jf = new JarFile(p.toIO)
- import collection.JavaConverters._
- for(entry <- jf.entries().asScala if !entry.isDirectory) yield {
- read.bytes(jf.getInputStream(entry)) -> entry.getName
- }
- }
- else {
- ls.rec(p).iterator
- .filter(_.isFile)
- .map(sub => read.bytes(sub) -> sub.relativeTo(p).toString)
- }
- if !seen(mapping)
- } {
- seen.add(mapping)
- val entry = new JarEntry(mapping.toString)
- jar.putNextEntry(entry)
- jar.write(file)
- jar.closeEntry()
- }
- } finally {
- jar.close()
- output.close()
- }
-
- }
- PathRef(outputPath)
- }
-
-}
diff --git a/core/src/mill/modules/Util.scala b/core/src/mill/modules/Util.scala
deleted file mode 100644
index cef11859..00000000
--- a/core/src/mill/modules/Util.scala
+++ /dev/null
@@ -1,65 +0,0 @@
-package mill.modules
-
-
-import ammonite.ops.{Path, RelPath, empty, mkdir, read}
-import mill.eval.PathRef
-import mill.util.Ctx
-
-object Util {
- def download(url: String, dest: RelPath = "download")(implicit ctx: Ctx.Dest) = {
- val out = ctx.dest / dest
-
- val website = new java.net.URI(url).toURL
- val rbc = java.nio.channels.Channels.newChannel(website.openStream)
- try{
- val fos = new java.io.FileOutputStream(out.toIO)
- try{
- fos.getChannel.transferFrom(rbc, 0, java.lang.Long.MAX_VALUE)
- PathRef(out)
- } finally{
- fos.close()
- }
- } finally{
- rbc.close()
- }
- }
-
- def downloadUnpackZip(url: String, dest: RelPath = "unpacked")
- (implicit ctx: Ctx.Dest) = {
-
- val tmpName = if (dest == empty / "tmp.zip") "tmp2.zip" else "tmp.zip"
- val downloaded = download(url, tmpName)
- unpackZip(downloaded.path, dest)
- }
-
- def unpackZip(src: Path, dest: RelPath = "unpacked")
- (implicit ctx: Ctx.Dest) = {
-
- val byteStream = read.getInputStream(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 / RelPath(entry.getName)
- mkdir(entryDest / ammonite.ops.up)
- val fileOut = new java.io.FileOutputStream(entryDest.toString)
- val buffer = new Array[Byte](4096)
- while ( {
- zipStream.read(buffer) match {
- case -1 => false
- case n =>
- fileOut.write(buffer, 0, n)
- true
- }
- }) ()
- fileOut.close()
- }
- zipStream.closeEntry()
- true
- }
- })()
- PathRef(ctx.dest / dest)
- }
-}
diff --git a/core/src/mill/package.scala b/core/src/mill/package.scala
deleted file mode 100644
index 93916c8b..00000000
--- a/core/src/mill/package.scala
+++ /dev/null
@@ -1,12 +0,0 @@
-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
- type Module = define.Module
- type Cross[T] = define.Cross[T]
- type Agg[T] = util.Loose.Agg[T]
- val Agg = util.Loose.Agg
-}
diff --git a/core/src/mill/main/ParseArgs.scala b/core/src/mill/util/ParseArgs.scala
index bafcd907..315edabc 100644
--- a/core/src/mill/main/ParseArgs.scala
+++ b/core/src/mill/util/ParseArgs.scala
@@ -1,6 +1,5 @@
-package mill.main
+package mill.util
-import mill.util.EitherOps
import fastparse.all._
import mill.define.{Segment, Segments}
diff --git a/core/src/mill/main/Router.scala b/core/src/mill/util/Router.scala
index 935ffc72..f628730b 100644
--- a/core/src/mill/main/Router.scala
+++ b/core/src/mill/util/Router.scala
@@ -1,12 +1,12 @@
-package mill.main
-
+package mill.util
import ammonite.main.Compat
+import language.experimental.macros
import scala.annotation.StaticAnnotation
import scala.collection.mutable
-import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
+
/**
* More or less a minimal version of Autowire's Server that lets you generate
* a set of "routes" from the methods defined in an object, and call them
@@ -24,7 +24,7 @@ object Router{
implicit def generate: Overrides = macro impl
def impl(c: Context): c.Tree = {
import c.universe._
- q"new _root_.mill.main.Router.Overrides(${c.internal.enclosingOwner.overrides.length})"
+ q"new _root_.mill.util.Router.Overrides(${c.internal.enclosingOwner.overrides.length})"
}
}
@@ -262,8 +262,8 @@ object Router{
}
def makeReadCall(dict: Map[String, String],
- default: => Option[Any],
- arg: ArgSig[_, _]) = {
+ default: => Option[Any],
+ arg: ArgSig[_, _]) = {
read(dict, default, arg, arg.reads.reads(_))
}
def makeReadVarargsCall(arg: ArgSig[_, _], values: Seq[String]) = {
@@ -271,6 +271,7 @@ object Router{
}
}
+
class Router [C <: Context](val c: C) {
import c.universe._
def getValsOrMeths(curCls: Type): Iterable[MethodSymbol] = {
@@ -365,7 +366,7 @@ class Router [C <: Context](val c: C) {
}
val argSig = q"""
- mill.main.Router.ArgSig[$curCls, $docUnwrappedType](
+ mill.util.Router.ArgSig[$curCls, $docUnwrappedType](
${arg.name.toString},
${docUnwrappedType.toString + (if(vararg) "*" else "")},
$docTree,
@@ -375,12 +376,12 @@ class Router [C <: Context](val c: C) {
val reader =
if(vararg) q"""
- mill.main.Router.makeReadVarargsCall(
+ mill.util.Router.makeReadVarargsCall(
$argSig,
$extrasSymbol
)
""" else q"""
- mill.main.Router.makeReadCall(
+ mill.util.Router.makeReadCall(
$argListSymbol,
$default,
$argSig
@@ -403,7 +404,7 @@ class Router [C <: Context](val c: C) {
val res = q"""
- mill.main.Router.EntryPoint[$curCls](
+ mill.util.Router.EntryPoint[$curCls](
${meth.name.toString},
scala.Seq(..$argSigs),
${methodDoc match{
@@ -412,12 +413,12 @@ class Router [C <: Context](val c: C) {
}},
${varargs.contains(true)},
($baseArgSym: $curCls, $argListSymbol: Map[String, String], $extrasSymbol: Seq[String]) =>
- mill.main.Router.validate(Seq(..$readArgs)) match{
- case mill.main.Router.Result.Success(List(..$argNames)) =>
- mill.main.Router.Result.Success(
+ mill.util.Router.validate(Seq(..$readArgs)) match{
+ case mill.util.Router.Result.Success(List(..$argNames)) =>
+ mill.util.Router.Result.Success(
$baseArgSym.${meth.name.toTermName}(..$argNameCasts)
)
- case x: mill.main.Router.Result.Error => x
+ case x: mill.util.Router.Result.Error => x
},
ammonite.main.Router.Overrides()
)
@@ -439,4 +440,3 @@ class Router [C <: Context](val c: C) {
}
}
}
-
diff --git a/core/src/mill/main/Scripts.scala b/core/src/mill/util/Scripts.scala
index 334c610f..7dde8252 100644
--- a/core/src/mill/main/Scripts.scala
+++ b/core/src/mill/util/Scripts.scala
@@ -1,14 +1,14 @@
-package mill.main
-import java.nio.file.NoSuchFileException
+package mill.util
+import java.nio.file.NoSuchFileException
-import mill.main.Router.{ArgSig, EntryPoint}
import ammonite.ops._
import ammonite.runtime.Evaluator.AmmoniteExit
import ammonite.util.Name.backtickWrap
import ammonite.util.Util.CodeSource
import ammonite.util.{Name, Res, Util}
import fastparse.utils.Utils._
+import mill.util.Router.{ArgSig, EntryPoint}
/**
* Logic around using Ammonite as a script-runner; invoking scripts via the
diff --git a/core/src/mill/util/Watched.scala b/core/src/mill/util/Watched.scala
new file mode 100644
index 00000000..f1ef4fee
--- /dev/null
+++ b/core/src/mill/util/Watched.scala
@@ -0,0 +1,8 @@
+package mill.util
+
+import mill.eval.PathRef
+
+case class Watched[T](value: T, watched: Seq[PathRef])
+object Watched{
+ implicit def readWrite[T: upickle.default.ReadWriter] = upickle.default.macroRW[Watched[T]]
+}
diff --git a/core/test/resources/examples/javac/build.sc b/core/test/resources/examples/javac/build.sc
deleted file mode 100644
index 0783ac17..00000000
--- a/core/test/resources/examples/javac/build.sc
+++ /dev/null
@@ -1,23 +0,0 @@
-import ammonite.ops._
-import mill.T
-import mill.eval.JavaCompileJarTests.compileAll
-import mill.eval.PathRef
-import mill.modules.Jvm
-import mill.util.Loose
-
-def sourceRootPath = millSourcePath / 'src
-def resourceRootPath = millSourcePath / 'resources
-
-// sourceRoot -> allSources -> classFiles
-// |
-// v
-// resourceRoot ----> jar
-def sourceRoot = T.sources{ sourceRootPath }
-def resourceRoot = T.sources{ resourceRootPath }
-def allSources = T{ sourceRoot().flatMap(p => ls.rec(p.path)).map(PathRef(_)) }
-def classFiles = T{ compileAll(allSources()) }
-def jar = T{ Jvm.createJar(Loose.Agg(classFiles().path) ++ resourceRoot().map(_.path)) }
-
-def run(mainClsName: String) = T.command{
- %%('java, "-cp", classFiles().path, mainClsName)(T.ctx().dest)
-}
diff --git a/core/test/resources/examples/javac/resources/hello.txt b/core/test/resources/examples/javac/resources/hello.txt
deleted file mode 100644
index 5e1c309d..00000000
--- a/core/test/resources/examples/javac/resources/hello.txt
+++ /dev/null
@@ -1 +0,0 @@
-Hello World \ No newline at end of file
diff --git a/core/test/resources/examples/javac/src/Bar.java b/core/test/resources/examples/javac/src/Bar.java
deleted file mode 100644
index 4e30c89b..00000000
--- a/core/test/resources/examples/javac/src/Bar.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package test;
-public class Bar{
- static int value = 271828;
-} \ No newline at end of file
diff --git a/core/test/resources/examples/javac/src/Foo.java b/core/test/resources/examples/javac/src/Foo.java
deleted file mode 100644
index e694f9fa..00000000
--- a/core/test/resources/examples/javac/src/Foo.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package test;
-public class Foo{
- static int value = 31337;
- public static void main(String[] args){
- System.out.println(value + Bar.value);
- }
-} \ No newline at end of file
diff --git a/core/test/src/mill/TestMain.scala b/core/test/src/mill/TestMain.scala
deleted file mode 100644
index 80e7e627..00000000
--- a/core/test/src/mill/TestMain.scala
+++ /dev/null
@@ -1,6 +0,0 @@
-package mill
-
-object TestMain {
- def main(args: Array[String]): Unit = {
- }
-}
diff --git a/core/test/src/mill/UTestFramework.scala b/core/test/src/mill/UTestFramework.scala
deleted file mode 100644
index 6c0d5191..00000000
--- a/core/test/src/mill/UTestFramework.scala
+++ /dev/null
@@ -1,11 +0,0 @@
-package mill
-
-class UTestFramework extends utest.runner.Framework {
- override def exceptionStackFrameHighlighter(s: StackTraceElement) = {
- s.getClassName.startsWith("mill.")
- }
- override def setup() = {
- import ammonite.ops._
- rm(pwd / 'target / 'workspace)
- }
-}
diff --git a/core/test/src/mill/define/ApplicativeTests.scala b/core/test/src/mill/define/ApplicativeTests.scala
deleted file mode 100644
index 72b715bb..00000000
--- a/core/test/src/mill/define/ApplicativeTests.scala
+++ /dev/null
@@ -1,125 +0,0 @@
-package mill.define
-
-import mill.define.Applicative.ImplicitStub
-import utest._
-
-import scala.annotation.compileTimeOnly
-import scala.language.experimental.macros
-
-
-object ApplicativeTests extends TestSuite {
- implicit def optionToOpt[T](o: Option[T]): Opt[T] = new Opt(o)
- class Opt[T](val self: Option[T]) extends Applicative.Applyable[Option, T]
- object Opt extends OptGenerated with Applicative.Applyer[Opt, Option, Applicative.Id, String]{
-
- val injectedCtx = "helloooo"
- def underlying[A](v: Opt[A]) = v.self
- def apply[T](t: T): Option[T] = macro Applicative.impl[Option, T, String]
-
- def mapCtx[A, B](a: Option[A])(f: (A, String) => B): Option[B] = a.map(f(_, injectedCtx))
- def zip() = Some(())
- def zip[A](a: Option[A]) = a.map(Tuple1(_))
- }
- class Counter{
- var value = 0
- def apply() = {
- value += 1
- value
- }
- }
- @compileTimeOnly("Target.ctx() can only be used with a T{...} block")
- @ImplicitStub
- implicit def taskCtx: String = ???
-
- val tests = Tests{
-
- 'selfContained - {
-
- 'simple - assert(Opt("lol " + 1) == Some("lol 1"))
- 'singleSome - assert(Opt("lol " + Some("hello")()) == Some("lol hello"))
- 'twoSomes - assert(Opt(Some("lol ")() + Some("hello")()) == Some("lol hello"))
- 'singleNone - assert(Opt("lol " + None()) == None)
- 'twoNones - assert(Opt("lol " + None() + None()) == None)
- }
- 'context - {
- assert(Opt(Opt.ctx() + Some("World")()) == Some("hellooooWorld"))
- }
- 'capturing - {
- val lol = "lol "
- def hell(o: String) = "hell" + o
- 'simple - assert(Opt(lol + 1) == Some("lol 1"))
- 'singleSome - assert(Opt(lol + Some(hell("o"))()) == Some("lol hello"))
- 'twoSomes - assert(Opt(Some(lol)() + Some(hell("o"))()) == Some("lol hello"))
- 'singleNone - assert(Opt(lol + None()) == None)
- 'twoNones - assert(Opt(lol + None() + None()) == None)
- }
- 'allowedLocalDef - {
- // Although x is defined inside the Opt{...} block, it is also defined
- // within the LHS of the Applyable#apply call, so it is safe to life it
- // out into the `zipMap` arguments list.
- val res = Opt{ "lol " + Some("hello").flatMap(x => Some(x)).apply() }
- assert(res == Some("lol hello"))
- }
- 'upstreamAlwaysEvaluated - {
- // Whether or not control-flow reaches the Applyable#apply call inside an
- // Opt{...} block, we always evaluate the LHS of the Applyable#apply
- // because it gets lifted out of any control flow statements
- val counter = new Counter()
- def up = Opt{ "lol " + counter() }
- val down = Opt{ if ("lol".length > 10) up() else "fail" }
- assert(
- down == Some("fail"),
- counter.value == 1
- )
- }
- 'upstreamEvaluatedOnlyOnce - {
- // Even if control-flow reaches the Applyable#apply call more than once,
- // it only gets evaluated once due to its lifting out of the Opt{...} block
- val counter = new Counter()
- def up = Opt{ "lol " + counter() }
- def runTwice[T](t: => T) = (t, t)
- val down = Opt{ runTwice(up()) }
- assert(
- down == Some(("lol 1", "lol 1")),
- counter.value == 1
- )
- }
- 'evaluationsInsideLambdasWork - {
- // This required some fiddling with owner chains inside the macro to get
- // working, so ensure it doesn't regress
- val counter = new Counter()
- def up = Opt{ "hello" + counter() }
- val down1 = Opt{ (() => up())() }
- val down2 = Opt{ Seq(1, 2, 3).map(n => up() * n) }
- assert(
- down1 == Some("hello1"),
- down2 == Some(Seq("hello2", "hello2hello2", "hello2hello2hello2"))
- )
- }
- 'appliesEvaluatedOncePerLexicalCallsite - {
- // If you have multiple Applyable#apply() lexically in the source code of
- // your Opt{...} call, each one gets evaluated once, even if the LHS of each
- // apply() call is identical. It's up to the downstream zipMap()
- // implementation to decide if it wants to dedup them or do other things.
- val counter = new Counter()
- def up = Opt{ "hello" + counter() }
- val down = Opt{ Seq(1, 2, 3).map(n => n + up() + up()) }
- assert(down == Some(Seq("1hello1hello2", "2hello1hello2", "3hello1hello2")))
- }
- 'appliesEvaluateBeforehand - {
- // Every Applyable#apply() within a Opt{...} block evaluates before any
- // other logic within that block, even if they would happen first in the
- // normal Scala evaluation order
- val counter = new Counter()
- def up = Opt{ counter() }
- val down = Opt{
- val res = counter()
- val one = up()
- val two = up()
- val three = up()
- (res, one, two, three)
- }
- assert(down == Some((4, 1, 2, 3)))
- }
- }
-}
diff --git a/core/test/src/mill/define/BasePathTests.scala b/core/test/src/mill/define/BasePathTests.scala
deleted file mode 100644
index 1f5b4037..00000000
--- a/core/test/src/mill/define/BasePathTests.scala
+++ /dev/null
@@ -1,68 +0,0 @@
-package mill.define
-
-import mill.util.{TestGraphs, TestUtil}
-import utest._
-import ammonite.ops._
-import mill.{Module, T}
-object BasePathTests extends TestSuite{
- val testGraphs = new TestGraphs
- val tests = Tests{
- def check[T <: Module](m: T)(f: T => Module, segments: String*) = {
- val remaining = f(m).millSourcePath.relativeTo(m.millSourcePath).segments
- assert(remaining == segments)
- }
- 'singleton - {
- check(testGraphs.singleton)(identity)
- }
- 'separateGroups - {
- check(TestGraphs.triangleTask)(identity)
- }
- 'TraitWithModuleObject - {
- check(TestGraphs.TraitWithModuleObject)(
- _.TraitModule,
- "TraitModule"
- )
- }
- 'nestedModuleNested - {
- check(TestGraphs.nestedModule)(_.nested, "nested")
- }
- 'nestedModuleInstance - {
- check(TestGraphs.nestedModule)(_.classInstance, "classInstance")
- }
- 'singleCross - {
- check(TestGraphs.singleCross)(_.cross, "cross")
- check(TestGraphs.singleCross)(_.cross("210"), "cross", "210")
- check(TestGraphs.singleCross)(_.cross("211"), "cross", "211")
- }
- 'doubleCross - {
- check(TestGraphs.doubleCross)(_.cross, "cross")
- check(TestGraphs.doubleCross)(_.cross("210", "jvm"), "cross", "210", "jvm")
- check(TestGraphs.doubleCross)(_.cross("212", "js"), "cross", "212", "js")
- }
- 'nestedCrosses - {
- check(TestGraphs.nestedCrosses)(_.cross, "cross")
- check(TestGraphs.nestedCrosses)(
- _.cross("210").cross2("js"),
- "cross", "210", "cross2", "js"
- )
- }
- 'overriden - {
- object overridenBasePath extends TestUtil.BaseModule {
- override def millSourcePath = pwd / 'overridenBasePathRootValue
- object nested extends Module{
- override def millSourcePath = super.millSourcePath / 'overridenBasePathNested
- object nested extends Module{
- override def millSourcePath = super.millSourcePath / 'overridenBasePathDoubleNested
- }
- }
- }
- assert(
- overridenBasePath.millSourcePath == pwd / 'overridenBasePathRootValue,
- overridenBasePath.nested.millSourcePath == pwd / 'overridenBasePathRootValue / 'nested / 'overridenBasePathNested,
- overridenBasePath.nested.nested.millSourcePath == pwd / 'overridenBasePathRootValue / 'nested / 'overridenBasePathNested / 'nested / 'overridenBasePathDoubleNested
- )
- }
-
- }
-}
-
diff --git a/core/test/src/mill/define/CacherTests.scala b/core/test/src/mill/define/CacherTests.scala
deleted file mode 100644
index 606de846..00000000
--- a/core/test/src/mill/define/CacherTests.scala
+++ /dev/null
@@ -1,76 +0,0 @@
-package mill.define
-
-import ammonite.ops.pwd
-import mill.util.{DummyLogger, TestEvaluator, TestUtil}
-import mill.util.Strict.Agg
-import mill.T
-import mill.eval.Result.Success
-import utest._
-import utest.framework.TestPath
-import mill.util.TestEvaluator.implicitDisover
-
-object CacherTests extends TestSuite{
- object Base extends Base
- trait Base extends TestUtil.BaseModule{
- def value = T{ 1 }
- def result = T{ Success(1) }
- }
- object Middle extends Middle
- trait Middle extends Base{
- def value = T{ super.value() + 2}
- def overriden = T{ super.value()}
- }
- object Terminal extends Terminal
- trait Terminal extends Middle{
- override def value = T{ super.value() + 4}
- }
-
- val tests = Tests{
- def eval[T <: TestUtil.BaseModule, V](mapping: T, v: Task[V])
- (implicit discover: Discover[T], tp: TestPath) = {
- val evaluator = new TestEvaluator(mapping)
- evaluator(v).right.get._1
- }
- def check(x: Any, y: Any) = assert(x == y)
-
- 'simpleDefIsCached - {
- Predef.assert(Base.value eq Base.value)
- Predef.assert(eval(Base, Base.value) == 1)
- }
-
- 'resultDefIsCached - {
- Predef.assert(Base.result eq Base.result)
- Predef.assert(eval(Base, Base.result) == 1)
- }
-
-
- 'overridingDefIsAlsoCached - {
- Predef.assert(eval(Middle, Middle.value) == 3)
- Predef.assert(Middle.value eq Middle.value)
- }
-
- 'overridenDefRemainsAvailable - {
- Predef.assert(eval(Middle, Middle.overriden) == 1)
- }
-
-
- 'multipleOverridesWork- {
- Predef.assert(eval(Terminal, Terminal.value) == 7)
- Predef.assert(eval(Terminal, Terminal.overriden) == 1)
- }
- // Doesn't fail, presumably compileError doesn't go far enough in the
- // compilation pipeline to hit the override checks
- //
- // 'overrideOutsideModuleFails - {
- // compileError("""
- // trait Foo{
- // def x = 1
- // }
- // object Bar extends Foo{
- // def x = 2
- // }
- // """)
- // }
- }
-}
-
diff --git a/core/test/src/mill/define/DiscoverTests.scala b/core/test/src/mill/define/DiscoverTests.scala
deleted file mode 100644
index 7621169a..00000000
--- a/core/test/src/mill/define/DiscoverTests.scala
+++ /dev/null
@@ -1,60 +0,0 @@
-package mill.define
-
-import mill.util.TestGraphs
-import utest._
-
-object DiscoverTests extends TestSuite{
- val testGraphs = new TestGraphs
- val tests = Tests{
- def check[T <: Module](m: T)(targets: (T => Target[_])*) = {
- val discovered = m.millInternal.targets
- val expected = targets.map(_(m)).toSet
- assert(discovered == expected)
- }
- 'singleton - {
- check(testGraphs.singleton)(_.single)
- }
- 'separateGroups - {
- check(TestGraphs.triangleTask)(_.left, _.right)
- }
- 'TraitWithModuleObject - {
- check(TestGraphs.TraitWithModuleObject)(_.TraitModule.testFramework)
- }
- 'nestedModule - {
- check(TestGraphs.nestedModule)(_.single, _.nested.single, _.classInstance.single)
- }
- 'singleCross - {
- check(TestGraphs.singleCross)(
- _.cross("210").suffix,
- _.cross("211").suffix,
- _.cross("212").suffix
- )
- }
- 'doubleCross - {
- check(TestGraphs.doubleCross)(
- _.cross("210", "jvm").suffix,
- _.cross("210", "js").suffix,
- _.cross("211", "jvm").suffix,
- _.cross("211", "js").suffix,
- _.cross("212", "jvm").suffix,
- _.cross("212", "js").suffix,
- _.cross("212", "native").suffix
- )
- }
- 'nestedCrosses - {
- check(TestGraphs.nestedCrosses)(
- _.cross("210").cross2("jvm").suffix,
- _.cross("210").cross2("js").suffix,
- _.cross("210").cross2("native").suffix,
- _.cross("211").cross2("jvm").suffix,
- _.cross("211").cross2("js").suffix,
- _.cross("211").cross2("native").suffix,
- _.cross("212").cross2("jvm").suffix,
- _.cross("212").cross2("js").suffix,
- _.cross("212").cross2("native").suffix
- )
- }
-
- }
-}
-
diff --git a/core/test/src/mill/define/GraphTests.scala b/core/test/src/mill/define/GraphTests.scala
deleted file mode 100644
index 7e6680be..00000000
--- a/core/test/src/mill/define/GraphTests.scala
+++ /dev/null
@@ -1,199 +0,0 @@
-package mill.define
-
-
-import mill.eval.Evaluator
-import mill.util.{TestGraphs, TestUtil}
-import utest._
-import mill.util.Strict.Agg
-object GraphTests extends TestSuite{
-
- val tests = Tests{
-
-
- val graphs = new TestGraphs()
- import graphs._
- import TestGraphs._
-
- 'topoSortedTransitiveTargets - {
- def check(targets: Agg[Task[_]], expected: Agg[Task[_]]) = {
- val result = Graph.topoSorted(Graph.transitiveTargets(targets)).values
- TestUtil.checkTopological(result)
- assert(result == expected)
- }
-
- 'singleton - check(
- targets = Agg(singleton.single),
- expected = Agg(singleton.single)
- )
- 'pair - check(
- targets = Agg(pair.down),
- expected = Agg(pair.up, pair.down)
- )
- 'anonTriple - check(
- targets = Agg(anonTriple.down),
- expected = Agg(anonTriple.up, anonTriple.down.inputs(0), anonTriple.down)
- )
- 'diamond - check(
- targets = Agg(diamond.down),
- expected = Agg(diamond.up, diamond.left, diamond.right, diamond.down)
- )
- 'anonDiamond - check(
- targets = Agg(diamond.down),
- expected = Agg(
- diamond.up,
- diamond.down.inputs(0),
- diamond.down.inputs(1),
- diamond.down
- )
- )
- 'defCachedDiamond - check(
- targets = Agg(defCachedDiamond.down),
- expected = Agg(
- defCachedDiamond.up.inputs(0),
- defCachedDiamond.up,
- defCachedDiamond.down.inputs(0).inputs(0).inputs(0),
- defCachedDiamond.down.inputs(0).inputs(0),
- defCachedDiamond.down.inputs(0).inputs(1).inputs(0),
- defCachedDiamond.down.inputs(0).inputs(1),
- defCachedDiamond.down.inputs(0),
- defCachedDiamond.down
- )
- )
- 'bigSingleTerminal - {
- val result = Graph.topoSorted(Graph.transitiveTargets(Agg(bigSingleTerminal.j))).values
- TestUtil.checkTopological(result)
- assert(result.size == 28)
- }
- }
-
- 'groupAroundNamedTargets - {
- def check[T, R <: Target[Int]](base: T)
- (target: T => R,
- important0: Agg[T => Target[_]],
- expected: Agg[(R, Int)]) = {
-
- val topoSorted = Graph.topoSorted(Graph.transitiveTargets(Agg(target(base))))
-
- val important = important0.map(_ (base))
- val grouped = Graph.groupAroundImportantTargets(topoSorted) {
- case t: Target[_] if important.contains(t) => t
- }
- val flattened = Agg.from(grouped.values().flatMap(_.items))
-
- TestUtil.checkTopological(flattened)
- for ((terminal, expectedSize) <- expected) {
- val grouping = grouped.lookupKey(terminal)
- assert(
- grouping.size == expectedSize,
- grouping.flatMap(_.asTarget: Option[Target[_]]).filter(important.contains) == Agg(terminal)
- )
- }
- }
-
- 'singleton - check(singleton)(
- _.single,
- Agg(_.single),
- Agg(singleton.single -> 1)
- )
- 'pair - check(pair)(
- _.down,
- Agg(_.up, _.down),
- Agg(pair.up -> 1, pair.down -> 1)
- )
- 'anonTriple - check(anonTriple)(
- _.down,
- Agg(_.up, _.down),
- Agg(anonTriple.up -> 1, anonTriple.down -> 2)
- )
- 'diamond - check(diamond)(
- _.down,
- Agg(_.up, _.left, _.right, _.down),
- Agg(
- diamond.up -> 1,
- diamond.left -> 1,
- diamond.right -> 1,
- diamond.down -> 1
- )
- )
-
- 'defCachedDiamond - check(defCachedDiamond)(
- _.down,
- Agg(_.up, _.left, _.right, _.down),
- Agg(
- defCachedDiamond.up -> 2,
- defCachedDiamond.left -> 2,
- defCachedDiamond.right -> 2,
- defCachedDiamond.down -> 2
- )
- )
-
- 'anonDiamond - check(anonDiamond)(
- _.down,
- Agg(_.down, _.up),
- Agg(
- anonDiamond.up -> 1,
- anonDiamond.down -> 3
- )
- )
- 'bigSingleTerminal - check(bigSingleTerminal)(
- _.j,
- Agg(_.a, _.b, _.e, _.f, _.i, _.j),
- Agg(
- bigSingleTerminal.a -> 3,
- bigSingleTerminal.b -> 2,
- bigSingleTerminal.e -> 9,
- bigSingleTerminal.i -> 6,
- bigSingleTerminal.f -> 4,
- bigSingleTerminal.j -> 4
- )
- )
- }
- 'multiTerminalGroupCounts - {
- def countGroups(goals: Task[_]*) = {
-
- val topoSorted = Graph.topoSorted(
- Graph.transitiveTargets(Agg.from(goals))
- )
- val grouped = Graph.groupAroundImportantTargets(topoSorted) {
- case t: NamedTask[Any] => t
- case t if goals.contains(t) => t
- }
- grouped.keyCount
- }
-
- 'separateGroups - {
- import separateGroups._
- val groupCount = countGroups(right, left)
- assert(groupCount == 3)
- }
-
- 'triangleTask - {
- // Make sure the following graph ends up as a single group, since although
- // `right` depends on `left`, both of them depend on the un-cached `task`
- // which would force them both to re-compute every time `task` changes
- import triangleTask._
- val groupCount = countGroups(right, left)
- assert(groupCount == 2)
- }
-
-
- 'multiTerminalGroup - {
- // Make sure the following graph ends up as two groups
- import multiTerminalGroup._
- val groupCount = countGroups(right, left)
- assert(groupCount == 2)
- }
-
-
- 'multiTerminalBoundary - {
- // Make sure the following graph ends up as a three groups: one for
- // each cached target, and one for the downstream task we are running
- import multiTerminalBoundary._
- val groupCount = countGroups(task2)
- assert(groupCount == 3)
- }
- }
-
-
- }
-}
diff --git a/core/test/src/mill/define/MacroErrorTests.scala b/core/test/src/mill/define/MacroErrorTests.scala
deleted file mode 100644
index a389feaa..00000000
--- a/core/test/src/mill/define/MacroErrorTests.scala
+++ /dev/null
@@ -1,83 +0,0 @@
-package mill.define
-
-import utest._
-import mill.{T, Module}
-import mill.util.TestUtil
-object MacroErrorTests extends TestSuite{
-
- val tests = Tests{
-
- 'errors{
- val expectedMsg =
- "T{} members must be defs defined in a Cacher class/trait/object body"
-
- val err = compileError("object Foo extends TestUtil.BaseModule{ val x = T{1} }")
- assert(err.msg == expectedMsg)
- }
-
- 'badTmacro - {
- // Make sure we can reference values from outside the T{...} block as part
- // of our `Target#apply()` calls, but we cannot reference any values that
- // come from inside the T{...} block
- 'pos - {
- val e = compileError("""
- val a = T{ 1 }
- val arr = Array(a)
- val b = {
- val c = 0
- T{
- arr(c)()
- }
- }
- """)
- assert(e.msg.contains(
- "Modules, Targets and Commands can only be defined within a mill Module")
- )
- }
- 'neg - {
-
- val expectedMsg =
- "Target#apply() call cannot use `value n` defined within the T{...} block"
- val err = compileError("""new Module{
- def a = T{ 1 }
- val arr = Array(a)
- def b = {
- T{
- val n = 0
- arr(n)()
- }
- }
- }""")
- assert(err.msg == expectedMsg)
- }
- 'neg2 - {
-
- val expectedMsg =
- "Target#apply() call cannot use `value x` defined within the T{...} block"
- val err = compileError("""new Module{
- def a = T{ 1 }
- val arr = Array(a)
- def b = {
- T{
- arr.map{x => x()}
- }
- }
- }""")
- assert(err.msg == expectedMsg)
- }
- 'neg3{
- val borkedCachedDiamond1 = utest.compileError("""
- object borkedCachedDiamond1 {
- def up = T{ TestUtil.test() }
- def left = T{ TestUtil.test(up) }
- def right = T{ TestUtil.test(up) }
- def down = T{ TestUtil.test(left, right) }
- }
- """)
- assert(borkedCachedDiamond1.msg.contains(
- "Modules, Targets and Commands can only be defined within a mill Module")
- )
- }
- }
- }
-}
diff --git a/core/test/src/mill/eval/CrossTests.scala b/core/test/src/mill/eval/CrossTests.scala
deleted file mode 100644
index aa12e180..00000000
--- a/core/test/src/mill/eval/CrossTests.scala
+++ /dev/null
@@ -1,56 +0,0 @@
-package mill.eval
-
-import ammonite.ops._
-import mill.define.Discover
-import mill.util.TestEvaluator
-import mill.util.TestEvaluator.implicitDisover
-import mill.util.TestGraphs.{crossResolved, doubleCross, nestedCrosses, singleCross}
-import utest._
-object CrossTests extends TestSuite{
- val tests = Tests{
- 'singleCross - {
- val check = new TestEvaluator(singleCross)
-
- val Right(("210", 1)) = check.apply(singleCross.cross("210").suffix)
- val Right(("211", 1)) = check.apply(singleCross.cross("211").suffix)
- val Right(("212", 1)) = check.apply(singleCross.cross("212").suffix)
- }
-
- 'crossResolved - {
- val check = new TestEvaluator(crossResolved)
-
- val Right(("2.10", 1)) = check.apply(crossResolved.foo("2.10").suffix)
- val Right(("2.11", 1)) = check.apply(crossResolved.foo("2.11").suffix)
- val Right(("2.12", 1)) = check.apply(crossResolved.foo("2.12").suffix)
-
- val Right(("_2.10", 1)) = check.apply(crossResolved.bar("2.10").longSuffix)
- val Right(("_2.11", 1)) = check.apply(crossResolved.bar("2.11").longSuffix)
- val Right(("_2.12", 1)) = check.apply(crossResolved.bar("2.12").longSuffix)
- }
-
-
- 'doubleCross - {
- val check = new TestEvaluator(doubleCross)
-
- val Right(("210_jvm", 1)) = check.apply(doubleCross.cross("210", "jvm").suffix)
- val Right(("210_js", 1)) = check.apply(doubleCross.cross("210", "js").suffix)
- val Right(("211_jvm", 1)) = check.apply(doubleCross.cross("211", "jvm").suffix)
- val Right(("211_js", 1)) = check.apply(doubleCross.cross("211", "js").suffix)
- val Right(("212_jvm", 1)) = check.apply(doubleCross.cross("212", "jvm").suffix)
- val Right(("212_js", 1)) = check.apply(doubleCross.cross("212", "js").suffix)
- val Right(("212_native", 1)) = check.apply(doubleCross.cross("212", "native").suffix)
- }
-
- 'nestedCrosses - {
- val check = new TestEvaluator(nestedCrosses)
-
- val Right(("210_jvm", 1)) = check.apply(nestedCrosses.cross("210").cross2("jvm").suffix)
- val Right(("210_js", 1)) = check.apply(nestedCrosses.cross("210").cross2("js").suffix)
- val Right(("211_jvm", 1)) = check.apply(nestedCrosses.cross("211").cross2("jvm").suffix)
- val Right(("211_js", 1)) = check.apply(nestedCrosses.cross("211").cross2("js").suffix)
- val Right(("212_jvm", 1)) = check.apply(nestedCrosses.cross("212").cross2("jvm").suffix)
- val Right(("212_js", 1)) = check.apply(nestedCrosses.cross("212").cross2("js").suffix)
- val Right(("212_native", 1)) = check.apply(nestedCrosses.cross("212").cross2("native").suffix)
- }
- }
-}
diff --git a/core/test/src/mill/eval/EvaluationTests.scala b/core/test/src/mill/eval/EvaluationTests.scala
deleted file mode 100644
index e5f0e57d..00000000
--- a/core/test/src/mill/eval/EvaluationTests.scala
+++ /dev/null
@@ -1,317 +0,0 @@
-package mill.eval
-
-
-import mill.util.TestUtil.{Test, test}
-import mill.define.{Discover, Graph, Target, Task}
-import mill.{Module, T}
-import mill.util.{DummyLogger, TestEvaluator, TestGraphs, TestUtil}
-import mill.util.Strict.Agg
-import utest._
-import utest.framework.TestPath
-import mill.util.TestEvaluator.implicitDisover
-import ammonite.ops._
-
-object EvaluationTests extends TestSuite{
- class Checker[T <: TestUtil.BaseModule](module: T)
- (implicit tp: TestPath, discover: Discover[T]) {
- // Make sure data is persisted even if we re-create the evaluator each time
-
- def evaluator = new TestEvaluator(module).evaluator
-
- def apply(target: Task[_], expValue: Any,
- expEvaled: Agg[Task[_]],
- // How many "other" tasks were evaluated other than those listed above.
- // Pass in -1 to skip the check entirely
- extraEvaled: Int = 0,
- // Perform a second evaluation of the same tasks, and make sure the
- // outputs are the same but nothing was evaluated. Disable this if you
- // are directly evaluating tasks which need to re-evaluate every time
- secondRunNoOp: Boolean = true) = {
-
- val evaled = evaluator.evaluate(Agg(target))
-
- val (matchingReturnedEvaled, extra) =
- evaled.evaluated.indexed.partition(expEvaled.contains)
-
- assert(
- evaled.values == Seq(expValue),
- matchingReturnedEvaled.toSet == expEvaled.toSet,
- extraEvaled == -1 || extra.length == extraEvaled
- )
-
- // Second time the value is already cached, so no evaluation needed
- if (secondRunNoOp){
- val evaled2 = evaluator.evaluate(Agg(target))
- val expecteSecondRunEvaluated = Agg()
- assert(
- evaled2.values == evaled.values,
- evaled2.evaluated == expecteSecondRunEvaluated
- )
- }
- }
- }
-
-
- val tests = Tests{
- object graphs extends TestGraphs()
- import graphs._
- import TestGraphs._
- 'evaluateSingle - {
-
- 'singleton - {
- import singleton._
- val check = new Checker(singleton)
- // First time the target is evaluated
- check(single, expValue = 0, expEvaled = Agg(single))
-
- single.counter += 1
- // After incrementing the counter, it forces re-evaluation
- check(single, expValue = 1, expEvaled = Agg(single))
- }
- 'pair - {
- import pair._
- val check = new Checker(pair)
- check(down, expValue = 0, expEvaled = Agg(up, down))
-
- down.counter += 1
- check(down, expValue = 1, expEvaled = Agg(down))
-
- up.counter += 1
- check(down, expValue = 2, expEvaled = Agg(up, down))
- }
- 'anonTriple - {
- import anonTriple._
- val check = new Checker(anonTriple)
- val middle = down.inputs(0)
- check(down, expValue = 0, expEvaled = Agg(up, middle, down))
-
- down.counter += 1
- check(down, expValue = 1, expEvaled = Agg(middle, down))
-
- up.counter += 1
- check(down, expValue = 2, expEvaled = Agg(up, middle, down))
-
- middle.asInstanceOf[TestUtil.Test].counter += 1
-
- check(down, expValue = 3, expEvaled = Agg(middle, down))
- }
- 'diamond - {
- import diamond._
- val check = new Checker(diamond)
- check(down, expValue = 0, expEvaled = Agg(up, left, right, down))
-
- down.counter += 1
- check(down, expValue = 1, expEvaled = Agg(down))
-
- up.counter += 1
- // Increment by 2 because up is referenced twice: once by left once by right
- check(down, expValue = 3, expEvaled = Agg(up, left, right, down))
-
- left.counter += 1
- check(down, expValue = 4, expEvaled = Agg(left, down))
-
- right.counter += 1
- check(down, expValue = 5, expEvaled = Agg(right, down))
- }
- 'anonDiamond - {
- import anonDiamond._
- val check = new Checker(anonDiamond)
- val left = down.inputs(0).asInstanceOf[TestUtil.Test]
- val right = down.inputs(1).asInstanceOf[TestUtil.Test]
- check(down, expValue = 0, expEvaled = Agg(up, left, right, down))
-
- down.counter += 1
- check(down, expValue = 1, expEvaled = Agg(left, right, down))
-
- up.counter += 1
- // Increment by 2 because up is referenced twice: once by left once by right
- check(down, expValue = 3, expEvaled = Agg(up, left, right, down))
-
- left.counter += 1
- check(down, expValue = 4, expEvaled = Agg(left, right, down))
-
- right.counter += 1
- check(down, expValue = 5, expEvaled = Agg(left, right, down))
- }
-
- 'bigSingleTerminal - {
- import bigSingleTerminal._
- val check = new Checker(bigSingleTerminal)
-
- check(j, expValue = 0, expEvaled = Agg(a, b, e, f, i, j), extraEvaled = 22)
-
- j.counter += 1
- check(j, expValue = 1, expEvaled = Agg(j), extraEvaled = 3)
-
- i.counter += 1
- // increment value by 2 because `i` is used twice on the way to `j`
- check(j, expValue = 3, expEvaled = Agg(j, i), extraEvaled = 8)
-
- b.counter += 1
- // increment value by 4 because `b` is used four times on the way to `j`
- check(j, expValue = 7, expEvaled = Agg(b, e, f, i, j), extraEvaled = 20)
- }
- }
-
- 'evaluateMixed - {
- 'separateGroups - {
- // Make sure that `left` and `right` are able to recompute separately,
- // even though one depends on the other
-
- import separateGroups._
- val checker = new Checker(separateGroups)
- val evaled1 = checker.evaluator.evaluate(Agg(right, left))
- val filtered1 = evaled1.evaluated.filter(_.isInstanceOf[Target[_]])
- assert(filtered1 == Agg(change, left, right))
- val evaled2 = checker.evaluator.evaluate(Agg(right, left))
- val filtered2 = evaled2.evaluated.filter(_.isInstanceOf[Target[_]])
- assert(filtered2 == Agg())
- change.counter += 1
- val evaled3 = checker.evaluator.evaluate(Agg(right, left))
- val filtered3 = evaled3.evaluated.filter(_.isInstanceOf[Target[_]])
- assert(filtered3 == Agg(change, right))
-
-
- }
- 'triangleTask - {
-
- import triangleTask._
- val checker = new Checker(triangleTask)
- checker(right, 3, Agg(left, right), extraEvaled = -1)
- checker(left, 1, Agg(), extraEvaled = -1)
-
- }
- 'multiTerminalGroup - {
- import multiTerminalGroup._
-
- val checker = new Checker(multiTerminalGroup)
- checker(right, 1, Agg(right), extraEvaled = -1)
- checker(left, 1, Agg(left), extraEvaled = -1)
- }
-
- 'multiTerminalBoundary - {
-
- import multiTerminalBoundary._
-
- val checker = new Checker(multiTerminalBoundary)
- checker(task2, 4, Agg(right, left), extraEvaled = -1, secondRunNoOp = false)
- checker(task2, 4, Agg(), extraEvaled = -1, secondRunNoOp = false)
- }
-
- 'overrideSuperTask - {
- // Make sure you can override targets, call their supers, and have the
- // overriden target be allocated a spot within the overriden/ folder of
- // the main publically-available target
- import canOverrideSuper._
-
- val checker = new Checker(canOverrideSuper)
- checker(foo, Seq("base", "object"), Agg(foo), extraEvaled = -1)
-
-
- val public = ammonite.ops.read(checker.evaluator.outPath / 'foo / "meta.json")
- val overriden = ammonite.ops.read(
- checker.evaluator.outPath / 'foo /
- 'overriden / "mill.util.TestGraphs.BaseModule#foo" / "meta.json"
- )
- assert(
- public.contains("base"),
- public.contains("object"),
- overriden.contains("base"),
- !overriden.contains("object")
- )
- }
- 'overrideSuperCommand - {
- // Make sure you can override commands, call their supers, and have the
- // overriden command be allocated a spot within the overriden/ folder of
- // the main publically-available command
- import canOverrideSuper._
-
- val checker = new Checker(canOverrideSuper)
- val runCmd = cmd(1)
- checker(
- runCmd,
- Seq("base1", "object1"),
- Agg(runCmd),
- extraEvaled = -1,
- secondRunNoOp = false
- )
-
- val public = ammonite.ops.read(checker.evaluator.outPath / 'cmd / "meta.json")
- val overriden = ammonite.ops.read(
- checker.evaluator.outPath / 'cmd /
- 'overriden / "mill.util.TestGraphs.BaseModule#cmd" / "meta.json"
- )
- assert(
- public.contains("base1"),
- public.contains("object1"),
- overriden.contains("base1"),
- !overriden.contains("object1")
- )
- }
-
- 'tasksAreUncached - {
- // Make sure the tasks `left` and `middle` re-compute every time, while
- // the target `right` does not
- //
- // ___ left ___
- // / \
- // up middle -- down
- // /
- // right
- object build extends TestUtil.BaseModule{
- var leftCount = 0
- var rightCount = 0
- var middleCount = 0
- def up = T{ test.anon() }
- def left = T.task{ leftCount += 1; up() + 1 }
- def middle = T.task{ middleCount += 1; 100 }
- def right = T{ rightCount += 1; 10000 }
- def down = T{ left() + middle() + right() }
- }
-
- import build._
-
- // Ensure task objects themselves are not cached, and recomputed each time
- assert(
- up eq up,
- left ne left,
- middle ne middle,
- right eq right,
- down eq down
- )
-
- // During the first evaluation, they get computed normally like any
- // cached target
- val check = new Checker(build)
- assert(leftCount == 0, rightCount == 0)
- check(down, expValue = 10101, expEvaled = Agg(up, right, down), extraEvaled = 8)
- assert(leftCount == 1, middleCount == 1, rightCount == 1)
-
- // If the upstream `up` doesn't change, the entire block of tasks
- // doesn't need to recompute
- check(down, expValue = 10101, expEvaled = Agg())
- assert(leftCount == 1, middleCount == 1, rightCount == 1)
-
- // But if `up` changes, the entire block of downstream tasks needs to
- // recompute together, including `middle` which doesn't depend on `up`,
- // because tasks have no cached value that can be used. `right`, which
- // is a cached Target, does not recompute
- up.inputs(0).asInstanceOf[Test].counter += 1
- check(down, expValue = 10102, expEvaled = Agg(up, down), extraEvaled = 6)
- assert(leftCount == 2, middleCount == 2, rightCount == 1)
-
- // Running the tasks themselves results in them being recomputed every
- // single time, even if nothing changes
- check(left, expValue = 2, expEvaled = Agg(), extraEvaled = 1, secondRunNoOp = false)
- assert(leftCount == 3, middleCount == 2, rightCount == 1)
- check(left, expValue = 2, expEvaled = Agg(), extraEvaled = 1, secondRunNoOp = false)
- assert(leftCount == 4, middleCount == 2, rightCount == 1)
-
- check(middle, expValue = 100, expEvaled = Agg(), extraEvaled = 2, secondRunNoOp = false)
- assert(leftCount == 4, middleCount == 3, rightCount == 1)
- check(middle, expValue = 100, expEvaled = Agg(), extraEvaled = 2, secondRunNoOp = false)
- assert(leftCount == 4, middleCount == 4, rightCount == 1)
- }
- }
- }
-}
diff --git a/core/test/src/mill/eval/FailureTests.scala b/core/test/src/mill/eval/FailureTests.scala
deleted file mode 100644
index 90cff686..00000000
--- a/core/test/src/mill/eval/FailureTests.scala
+++ /dev/null
@@ -1,100 +0,0 @@
-package mill.eval
-import mill.T
-import mill.util.{TestEvaluator, TestUtil}
-import ammonite.ops.{Path, pwd, rm}
-import mill.eval.Result.OuterStack
-import utest._
-import utest.framework.TestPath
-import mill.util.TestEvaluator.implicitDisover
-
-object FailureTests extends TestSuite{
-
- val tests = Tests{
- val graphs = new mill.util.TestGraphs()
- import graphs._
-
- 'evaluateSingle - {
- val check = new TestEvaluator(singleton)
- check.fail(
- target = singleton.single,
- expectedFailCount = 0,
- expectedRawValues = Seq(Result.Success(0))
- )
-
- singleton.single.failure = Some("lols")
-
- check.fail(
- target = singleton.single,
- expectedFailCount = 1,
- expectedRawValues = Seq(Result.Failure("lols"))
- )
-
- singleton.single.failure = None
-
- check.fail(
- target = singleton.single,
- expectedFailCount = 0,
- expectedRawValues = Seq(Result.Success(0))
- )
-
-
- val ex = new IndexOutOfBoundsException()
- singleton.single.exception = Some(ex)
-
-
- check.fail(
- target = singleton.single,
- expectedFailCount = 1,
- expectedRawValues = Seq(Result.Exception(ex, new OuterStack(Nil)))
- )
- }
- 'evaluatePair - {
- val check = new TestEvaluator(pair)
- check.fail(
- pair.down,
- expectedFailCount = 0,
- expectedRawValues = Seq(Result.Success(0))
- )
-
- pair.up.failure = Some("lols")
-
- check.fail(
- pair.down,
- expectedFailCount = 1,
- expectedRawValues = Seq(Result.Skipped)
- )
-
- pair.up.failure = None
-
- check.fail(
- pair.down,
- expectedFailCount = 0,
- expectedRawValues = Seq(Result.Success(0))
- )
-
- pair.up.exception = Some(new IndexOutOfBoundsException())
-
- check.fail(
- pair.down,
- expectedFailCount = 1,
- expectedRawValues = Seq(Result.Skipped)
- )
- }
- 'multipleUsesOfDest - {
- object build extends TestUtil.BaseModule {
- // Using `T.ctx( ).dest` twice in a single task is ok
- def left = T{ + T.ctx().dest.toString.length + T.ctx().dest.toString.length }
-
- // Using `T.ctx( ).dest` once in two different tasks is not ok
- val task = T.task{ T.ctx().dest.toString.length }
- def right = T{ task() + left() + T.ctx().dest.toString().length }
- }
-
- val check = new TestEvaluator(build)
- val Right(_) = check(build.left)
- val Left(Result.Exception(e, _)) = check(build.right)
- assert(e.getMessage.contains("`dest` can only be used in one place"))
- }
- }
-}
-
diff --git a/core/test/src/mill/eval/JavaCompileJarTests.scala b/core/test/src/mill/eval/JavaCompileJarTests.scala
deleted file mode 100644
index 71feebda..00000000
--- a/core/test/src/mill/eval/JavaCompileJarTests.scala
+++ /dev/null
@@ -1,159 +0,0 @@
-package mill.eval
-
-import ammonite.ops.ImplicitWd._
-import ammonite.ops._
-import mill.define.{Discover, Input, Target, Task}
-import mill.modules.Jvm
-import mill.util.Ctx.Dest
-import mill.{Module, T}
-import mill.util.{DummyLogger, Loose, TestEvaluator, TestUtil}
-import mill.util.Strict.Agg
-import utest._
-import mill._
-import TestEvaluator.implicitDisover
-object JavaCompileJarTests extends TestSuite{
- def compileAll(sources: Seq[PathRef])(implicit ctx: Dest) = {
- mkdir(ctx.dest)
- import ammonite.ops._
- %("javac", sources.map(_.path.toString()), "-d", ctx.dest)(wd = ctx.dest)
- PathRef(ctx.dest)
- }
-
- val tests = Tests{
- 'javac {
- val javacSrcPath = pwd / 'core / 'test / 'resources / 'examples / 'javac
- val javacDestPath = TestUtil.getOutPath() / 'src
-
- mkdir(javacDestPath / up)
- cp(javacSrcPath, javacDestPath)
-
- object Build extends TestUtil.BaseModule{
- def sourceRootPath = javacDestPath / 'src
- def resourceRootPath = javacDestPath / 'resources
-
- // sourceRoot -> allSources -> classFiles
- // |
- // v
- // resourceRoot ----> jar
- def sourceRoot = T.sources{ sourceRootPath }
- def resourceRoot = T.sources{ resourceRootPath }
- def allSources = T{ sourceRoot().flatMap(p => ls.rec(p.path)).map(PathRef(_)) }
- def classFiles = T{ compileAll(allSources()) }
- def jar = T{ Jvm.createJar(Loose.Agg(classFiles().path) ++ resourceRoot().map(_.path)) }
-
- def run(mainClsName: String) = T.command{
- %%('java, "-cp", classFiles().path, mainClsName)
- }
- }
-
- import Build._
-
- var evaluator = new TestEvaluator(Build)
- def eval[T](t: Task[T]) = {
- evaluator.apply(t)
- }
- def check(targets: Agg[Task[_]], expected: Agg[Task[_]]) = {
- evaluator.check(targets, expected)
- }
-
- def append(path: Path, txt: String) = ammonite.ops.write.append(path, txt)
-
-
- check(
- targets = Agg(jar),
- expected = Agg(allSources, classFiles, jar)
- )
-
- // Re-running with no changes results in nothing being evaluated
- check(targets = Agg(jar), expected = Agg())
-
- // Appending an empty string gets ignored due to file-content hashing
- append(sourceRootPath / "Foo.java", "")
- check(targets = Agg(jar), expected = Agg())
-
- // Appending whitespace forces a recompile, but the classfilesend up
- // exactly the same so no re-jarring.
- append(sourceRootPath / "Foo.java", " ")
- // Note that `sourceRoot` and `resourceRoot` never turn up in the `expected`
- // list, because they are `Source`s not `Target`s
- check(targets = Agg(jar), expected = Agg(/*sourceRoot, */allSources, classFiles))
-
- // Appending a new class changes the classfiles, which forces us to
- // re-create the final jar
- append(sourceRootPath / "Foo.java", "\nclass FooTwo{}")
- check(targets = Agg(jar), expected = Agg(allSources, classFiles, jar))
-
- // Tweaking the resources forces rebuild of the final jar, without
- // recompiling classfiles
- append(resourceRootPath / "hello.txt", " ")
- check(targets = Agg(jar), expected = Agg(jar))
-
- // You can swap evaluators halfway without any ill effects
- evaluator = new TestEvaluator(Build)
-
- // Asking for an intermediate target forces things to be build up to that
- // target only; these are re-used for any downstream targets requested
- append(sourceRootPath / "Bar.java", "\nclass BarTwo{}")
- append(resourceRootPath / "hello.txt", " ")
- check(targets = Agg(classFiles), expected = Agg(allSources, classFiles))
- check(targets = Agg(jar), expected = Agg(jar))
- check(targets = Agg(allSources), expected = Agg())
-
- append(sourceRootPath / "Bar.java", "\nclass BarThree{}")
- append(resourceRootPath / "hello.txt", " ")
- check(targets = Agg(resourceRoot), expected = Agg())
- check(targets = Agg(allSources), expected = Agg(allSources))
- check(targets = Agg(jar), expected = Agg(classFiles, jar))
-
- val jarContents = %%('jar, "-tf", evaluator.outPath/'jar/'dest/"out.jar")(evaluator.outPath).out.string
- val expectedJarContents =
- """META-INF/MANIFEST.MF
- |test/Bar.class
- |test/BarThree.class
- |test/BarTwo.class
- |test/Foo.class
- |test/FooTwo.class
- |hello.txt
- |""".stripMargin
- assert(jarContents == expectedJarContents)
-
- val executed = %%('java, "-cp", evaluator.outPath/'jar/'dest/"out.jar", "test.Foo")(evaluator.outPath).out.string
- assert(executed == (31337 + 271828) + "\n")
-
- for(i <- 0 until 3){
- // Build.run is not cached, so every time we eval it it has to
- // re-evaluate
- val Right((runOutput, evalCount)) = eval(Build.run("test.Foo"))
- assert(
- runOutput.out.string == (31337 + 271828) + "\n",
- evalCount == 1
- )
- }
-
- val Left(Result.Exception(ex, _)) = eval(Build.run("test.BarFour"))
-
- assert(ex.getMessage.contains("Could not find or load main class"))
-
- append(
- sourceRootPath / "Bar.java",
- """
- class BarFour{
- public static void main(String[] args){
- System.out.println("New Cls!");
- }
- }
- """
- )
- val Right((runOutput2, evalCount2)) = eval(Build.run("test.BarFour"))
- assert(
- runOutput2.out.string == "New Cls!\n",
- evalCount2 == 3
- )
- val Right((runOutput3, evalCount3)) = eval(Build.run("test.BarFour"))
- assert(
- runOutput3.out.string == "New Cls!\n",
- evalCount3 == 1
- )
- }
- }
-}
diff --git a/core/test/src/mill/eval/ModuleTests.scala b/core/test/src/mill/eval/ModuleTests.scala
deleted file mode 100644
index c6125b32..00000000
--- a/core/test/src/mill/eval/ModuleTests.scala
+++ /dev/null
@@ -1,45 +0,0 @@
-package mill.eval
-
-import ammonite.ops._
-import mill.util.{TestEvaluator, TestUtil}
-import mill.T
-import mill.define.Discover
-import mill.util.TestEvaluator.implicitDisover
-import utest._
-
-object ModuleTests extends TestSuite{
- object ExternalModule extends mill.define.ExternalModule {
- def x = T{13}
- object inner extends mill.Module{
- def y = T{17}
- }
- def millDiscover = Discover[this.type]
- }
- object Build extends TestUtil.BaseModule{
- def z = T{ ExternalModule.x() + ExternalModule.inner.y() }
- }
- val tests = Tests {
- rm(TestEvaluator.externalOutPath)
- 'externalModuleTargetsAreNamespacedByModulePackagePath - {
- val check = new TestEvaluator(Build)
-
- val Right((30, 1)) = check.apply(Build.z)
- assert(
- read(check.evaluator.outPath / 'z / "meta.json").contains("30"),
- read(TestEvaluator.externalOutPath / 'mill / 'eval / 'ModuleTests / 'ExternalModule / 'x / "meta.json").contains("13"),
- read(TestEvaluator.externalOutPath / 'mill / 'eval / 'ModuleTests / 'ExternalModule / 'inner / 'y / "meta.json").contains("17")
- )
- }
- 'externalModuleMustBeGlobalStatic - {
-
-
- object Build extends mill.define.ExternalModule {
-
- def z = T{ ExternalModule.x() + ExternalModule.inner.y() }
- def millDiscover = Discover[this.type]
- }
-
- intercept[java.lang.AssertionError]{ Build }
- }
- }
-}
diff --git a/core/test/src/mill/eval/TarjanTests.scala b/core/test/src/mill/eval/TarjanTests.scala
deleted file mode 100644
index 2f9d0a4d..00000000
--- a/core/test/src/mill/eval/TarjanTests.scala
+++ /dev/null
@@ -1,91 +0,0 @@
-package mill.eval
-
-import utest._
-
-object TarjanTests extends TestSuite{
- def check(input: Seq[Seq[Int]], expected: Seq[Seq[Int]]) = {
- val result = Tarjans(input).map(_.sorted)
- val sortedExpected = expected.map(_.sorted)
- assert(result == sortedExpected)
- }
- val tests = Tests{
- //
- 'empty - check(Seq(), Seq())
-
- // (0)
- 'singleton - check(Seq(Seq()), Seq(Seq(0)))
-
-
- // (0)-.
- // ^._/
- 'selfCycle - check(Seq(Seq(0)), Seq(Seq(0)))
-
- // (0) <-> (1)
- 'simpleCycle- check(Seq(Seq(1), Seq(0)), Seq(Seq(1, 0)))
-
- // (0) (1) (2)
- 'multipleSingletons - check(
- Seq(Seq(), Seq(), Seq()),
- Seq(Seq(0), Seq(1), Seq(2))
- )
-
- // (0) -> (1) -> (2)
- 'straightLineNoCycles- check(
- Seq(Seq(1), Seq(2), Seq()),
- Seq(Seq(2), Seq(1), Seq(0))
- )
-
- // (0) <- (1) <- (2)
- 'straightLineNoCyclesReversed- check(
- Seq(Seq(), Seq(0), Seq(1)),
- Seq(Seq(0), Seq(1), Seq(2))
- )
-
- // (0) <-> (1) (2) -> (3) -> (4)
- // ^.____________/
- 'independentSimpleCycles - check(
- Seq(Seq(1), Seq(0), Seq(3), Seq(4), Seq(2)),
- Seq(Seq(1, 0), Seq(4, 3, 2))
- )
-
- // ___________________
- // v \
- // (0) <-> (1) (2) -> (3) -> (4)
- // ^.____________/
- 'independentLinkedCycles - check(
- Seq(Seq(1), Seq(0), Seq(3), Seq(4), Seq(2, 1)),
- Seq(Seq(1, 0), Seq(4, 3, 2))
- )
- // _____________
- // / v
- // (0) <-> (1) (2) -> (3) -> (4)
- // ^.____________/
- 'independentLinkedCycles2 - check(
- Seq(Seq(1, 2), Seq(0), Seq(3), Seq(4), Seq(2)),
- Seq(Seq(4, 3, 2), Seq(1, 0))
- )
-
- // _____________
- // / v
- // (0) <-> (1) (2) -> (3) -> (4)
- // ^. ^.____________/
- // \________________/
- 'combinedCycles - check(
- Seq(Seq(1, 2), Seq(0), Seq(3), Seq(4), Seq(2, 1)),
- Seq(Seq(4, 3, 2, 1, 0))
- )
- //
- // (0) <-> (1) <- (2) <- (3) <-> (4) <- (5)
- // ^.____________/ / /
- // / /
- // (6) <- (7) <-/ (8) <-'
- // / /
- // v /
- // (9) <--------'
- 'combinedCycles - check(
- Seq(Seq(1), Seq(0), Seq(0, 1), Seq(2, 4, 7, 9), Seq(3), Seq(4, 8), Seq(9), Seq(6), Seq(), Seq()),
- Seq(Seq(0, 1), Seq(2), Seq(9), Seq(6), Seq(7), Seq(3, 4), Seq(8), Seq(5))
- )
-
- }
-} \ No newline at end of file
diff --git a/core/test/src/mill/eval/TaskTests.scala b/core/test/src/mill/eval/TaskTests.scala
deleted file mode 100644
index 114a2910..00000000
--- a/core/test/src/mill/eval/TaskTests.scala
+++ /dev/null
@@ -1,95 +0,0 @@
-package mill.eval
-
-import utest._
-import ammonite.ops._
-import mill.T
-import mill.util.TestEvaluator.implicitDisover
-import mill.util.TestEvaluator
-object TaskTests extends TestSuite{
- val tests = Tests{
- object build extends mill.util.TestUtil.BaseModule{
- var count = 0
- // Explicitly instantiate `Function1` objects to make sure we get
- // different instances each time
- def staticWorker = T.worker{
- new Function1[Int, Int] {
- def apply(v1: Int) = v1 + 1
- }
- }
- def noisyWorker = T.worker{
- new Function1[Int, Int] {
- def apply(v1: Int) = input() + 1
- }
- }
- def input = T.input{
- count += 1
- count
- }
- def task = T.task{
- count += 1
- count
- }
- def taskInput = T{ input() }
- def taskNoInput = T{ task() }
-
- def persistent = T.persistent{
- input() // force re-computation
- mkdir(T.ctx().dest)
- write.append(T.ctx().dest/'count, "hello\n")
- read.lines(T.ctx().dest/'count).length
- }
- def nonPersistent = T{
- input() // force re-computation
- mkdir(T.ctx().dest)
- write.append(T.ctx().dest/'count, "hello\n")
- read.lines(T.ctx().dest/'count).length
- }
-
- def staticWorkerDownstream = T{
- staticWorker().apply(1)
- }
- def noisyWorkerDownstream = T{
- noisyWorker().apply(1)
- }
- }
-
- 'inputs - {
- // Inputs always re-evaluate, including forcing downstream cached Targets
- // to re-evaluate, but normal Tasks behind a Target run once then are cached
- val check = new TestEvaluator(build)
-
- val Right((1, 1)) = check.apply(build.taskInput)
- val Right((2, 1)) = check.apply(build.taskInput)
- val Right((3, 1)) = check.apply(build.taskInput)
-
- val Right((4, 1)) = check.apply(build.taskNoInput)
- val Right((4, 0)) = check.apply(build.taskNoInput)
- val Right((4, 0)) = check.apply(build.taskNoInput)
- }
-
- 'persistent - {
- // Persistent tasks keep the working dir around between runs
- val check = new TestEvaluator(build)
- val Right((1, 1)) = check.apply(build.persistent)
- val Right((2, 1)) = check.apply(build.persistent)
- val Right((3, 1)) = check.apply(build.persistent)
-
- val Right((1, 1)) = check.apply(build.nonPersistent)
- val Right((1, 1)) = check.apply(build.nonPersistent)
- val Right((1, 1)) = check.apply(build.nonPersistent)
- }
-
- 'worker - {
- // Persistent task
- def check = new TestEvaluator(build)
-
- val Right((2, 1)) = check.apply(build.noisyWorkerDownstream)
- val Right((3, 1)) = check.apply(build.noisyWorkerDownstream)
- val Right((4, 1)) = check.apply(build.noisyWorkerDownstream)
-
- val Right((2, 1)) = check.apply(build.staticWorkerDownstream)
- val Right((2, 0)) = check.apply(build.staticWorkerDownstream)
- val Right((2, 0)) = check.apply(build.staticWorkerDownstream)
- }
- }
-}
diff --git a/core/test/src/mill/main/JavaCompileJarTests.scala b/core/test/src/mill/main/JavaCompileJarTests.scala
deleted file mode 100644
index a4c9fafe..00000000
--- a/core/test/src/mill/main/JavaCompileJarTests.scala
+++ /dev/null
@@ -1,66 +0,0 @@
-package mill.main
-
-import ammonite.ops._
-import mill.util.ScriptTestSuite
-import utest._
-
-object JavaCompileJarTests extends ScriptTestSuite {
- def workspaceSlug = "java-compile-jar"
- def scriptSourcePath = pwd / 'core / 'test / 'resources / 'examples / 'javac
- val tests = Tests{
- initWorkspace()
- 'test - {
- // Basic target evaluation works
- assert(eval("classFiles"))
- assert(eval("jar"))
-
- val classFiles1 = meta("classFiles")
- val jar1 = meta("jar")
-
- assert(eval("classFiles"))
- assert(eval("jar"))
-
- // Repeated evaluation has the same results
- val classFiles2 = meta("classFiles")
- val jar2 = meta("jar")
-
- assert(
- jar1 == jar2,
- classFiles1 == classFiles2
- )
-
- // If we update resources, classFiles are unchanged but jar changes
- for(scalaFile <- ls.rec(workspacePath).filter(_.ext == "txt")){
- write.append(scalaFile, "\n")
- }
-
- assert(eval("classFiles"))
- assert(eval("jar"))
-
- val classFiles3 = meta("classFiles")
- val jar3 = meta("jar")
-
- assert(
- jar2 != jar3,
- classFiles2 == classFiles3
- )
-
- // We can intentionally break the code, have the targets break, then
- // fix the code and have them recover.
- for(scalaFile <- ls.rec(workspacePath).filter(_.ext == "java")){
- write.append(scalaFile, "\n}")
- }
-
- assert(!eval("classFiles"))
- assert(!eval("jar"))
-
- for(scalaFile <- ls.rec(workspacePath).filter(_.ext == "java")){
- write.over(scalaFile, read(scalaFile).dropRight(2))
- }
-
- assert(eval("classFiles"))
- assert(eval("jar"))
- }
- }
-}
-
diff --git a/core/test/src/mill/main/MainTests.scala b/core/test/src/mill/main/MainTests.scala
deleted file mode 100644
index 22f93ae0..00000000
--- a/core/test/src/mill/main/MainTests.scala
+++ /dev/null
@@ -1,222 +0,0 @@
-package mill.main
-
-import mill.define.{Discover, Segment, Task}
-import mill.util.TestGraphs._
-import mill.util.TestEvaluator.implicitDisover
-import utest._
-object MainTests extends TestSuite{
-
- def check[T <: mill.Module](module: T)(
- selectorString: String,
- expected0: Either[String, Seq[T => Task[_]]])
- (implicit discover: Discover[T])= {
-
- val expected = expected0.map(_.map(_(module)))
- val resolved = for{
- selectors <- mill.main.ParseArgs(Seq(selectorString)).map(_._1.head)
- val crossSelectors = selectors._2.value.map{case Segment.Cross(x) => x.toList.map(_.toString) case _ => Nil}
- task <- mill.main.Resolve.resolve(
- selectors._2.value.toList, module, discover, Nil, crossSelectors.toList, Nil
- )
- } yield task
- assert(resolved == expected)
- }
- val tests = Tests{
- val graphs = new mill.util.TestGraphs()
- import graphs._
- 'single - {
- val check = MainTests.check(singleton) _
- 'pos - check("single", Right(Seq(_.single)))
- 'neg1 - check("doesntExist", Left("Cannot resolve task doesntExist"))
- 'neg2 - check("single.doesntExist", Left("Cannot resolve module single"))
- 'neg3 - check("", Left("Selector cannot be empty"))
- }
- 'nested - {
- val check = MainTests.check(nestedModule) _
- 'pos1 - check("single", Right(Seq(_.single)))
- 'pos2 - check("nested.single", Right(Seq(_.nested.single)))
- 'pos3 - check("classInstance.single", Right(Seq(_.classInstance.single)))
- 'neg1 - check("doesntExist", Left("Cannot resolve task doesntExist"))
- 'neg2 - check("single.doesntExist", Left("Cannot resolve module single"))
- 'neg3 - check("nested.doesntExist", Left("Cannot resolve task nested.doesntExist"))
- 'neg4 - check("classInstance.doesntExist", Left("Cannot resolve task classInstance.doesntExist"))
- 'wildcard - check(
- "_.single",
- Right(Seq(
- _.classInstance.single,
- _.nested.single
- ))
- )
- 'wildcardNeg - check(
- "_._.single",
- Left("Cannot resolve module _")
- )
- 'wildcardNeg2 - check(
- "_._.__",
- Left("Cannot resolve module _")
- )
- 'wildcard2 - check(
- "__.single",
- Right(Seq(
- _.single,
- _.classInstance.single,
- _.nested.single
- ))
- )
-
- 'wildcard3 - check(
- "_.__.single",
- Right(Seq(
- _.classInstance.single,
- _.nested.single
- ))
- )
-
- }
- 'cross - {
- 'single - {
- val check = MainTests.check(singleCross) _
- 'pos1 - check("cross[210].suffix", Right(Seq(_.cross("210").suffix)))
- 'pos2 - check("cross[211].suffix", Right(Seq(_.cross("211").suffix)))
- 'neg1 - check("cross[210].doesntExist", Left("Cannot resolve task cross[210].doesntExist"))
- 'neg2 - check("cross[doesntExist].doesntExist", Left("Cannot resolve cross cross[doesntExist]"))
- 'neg2 - check("cross[doesntExist].suffix", Left("Cannot resolve cross cross[doesntExist]"))
- 'wildcard - check(
- "cross[_].suffix",
- Right(Seq(
- _.cross("210").suffix,
- _.cross("211").suffix,
- _.cross("212").suffix
- ))
- )
- 'wildcard2 - check(
- "cross[__].suffix",
- Right(Seq(
- _.cross("210").suffix,
- _.cross("211").suffix,
- _.cross("212").suffix
- ))
- )
- }
- 'double - {
- val check = MainTests.check(doubleCross) _
- 'pos1 - check(
- "cross[210,jvm].suffix",
- Right(Seq(_.cross("210", "jvm").suffix))
- )
- 'pos2 - check(
- "cross[211,jvm].suffix",
- Right(Seq(_.cross("211", "jvm").suffix))
- )
- 'wildcard - {
- 'labelNeg - check(
- "_.suffix",
- Left("Cannot resolve module _")
- )
- 'labelPos - check(
- "__.suffix",
- Right(Seq(
- _.cross("210", "jvm").suffix,
- _.cross("210", "js").suffix,
-
- _.cross("211", "jvm").suffix,
- _.cross("211", "js").suffix,
-
- _.cross("212", "jvm").suffix,
- _.cross("212", "js").suffix,
- _.cross("212", "native").suffix
- ))
- )
- 'first - check(
- "cross[_,jvm].suffix",
- Right(Seq(
- _.cross("210", "jvm").suffix,
- _.cross("211", "jvm").suffix,
- _.cross("212", "jvm").suffix
- ))
- )
- 'second - check(
- "cross[210,_].suffix",
- Right(Seq(
- _.cross("210", "jvm").suffix,
- _.cross("210", "js").suffix
- ))
- )
- 'both - check(
- "cross[_,_].suffix",
- Right(Seq(
- _.cross("210", "jvm").suffix,
- _.cross("210", "js").suffix,
-
- _.cross("211", "jvm").suffix,
- _.cross("211", "js").suffix,
-
- _.cross("212", "jvm").suffix,
- _.cross("212", "js").suffix,
- _.cross("212", "native").suffix
- ))
- )
- 'both2 - check(
- "cross[__].suffix",
- Right(Seq(
- _.cross("210", "jvm").suffix,
- _.cross("210", "js").suffix,
-
- _.cross("211", "jvm").suffix,
- _.cross("211", "js").suffix,
-
- _.cross("212", "jvm").suffix,
- _.cross("212", "js").suffix,
- _.cross("212", "native").suffix
- ))
- )
- }
- }
- 'nested - {
- val check = MainTests.check(nestedCrosses) _
- 'pos1 - check(
- "cross[210].cross2[js].suffix",
- Right(Seq(_.cross("210").cross2("js").suffix))
- )
- 'pos2 - check(
- "cross[211].cross2[jvm].suffix",
- Right(Seq(_.cross("211").cross2("jvm").suffix))
- )
- 'wildcard - {
- 'first - check(
- "cross[_].cross2[jvm].suffix",
- Right(Seq(
- _.cross("210").cross2("jvm").suffix,
- _.cross("211").cross2("jvm").suffix,
- _.cross("212").cross2("jvm").suffix
- ))
- )
- 'second - check(
- "cross[210].cross2[_].suffix",
- Right(Seq(
- _.cross("210").cross2("jvm").suffix,
- _.cross("210").cross2("js").suffix,
- _.cross("210").cross2("native").suffix
- ))
- )
- 'both - check(
- "cross[_].cross2[_].suffix",
- Right(Seq(
- _.cross("210").cross2("jvm").suffix,
- _.cross("210").cross2("js").suffix,
- _.cross("210").cross2("native").suffix,
-
- _.cross("211").cross2("jvm").suffix,
- _.cross("211").cross2("js").suffix,
- _.cross("211").cross2("native").suffix,
-
- _.cross("212").cross2("jvm").suffix,
- _.cross("212").cross2("js").suffix,
- _.cross("212").cross2("native").suffix
- ))
- )
- }
- }
- }
- }
-}
diff --git a/core/test/src/mill/main/ParseArgsTest.scala b/core/test/src/mill/main/ParseArgsTest.scala
deleted file mode 100644
index 6678f12c..00000000
--- a/core/test/src/mill/main/ParseArgsTest.scala
+++ /dev/null
@@ -1,241 +0,0 @@
-package mill.main
-
-import mill.define.Segment
-import mill.define.Segment.{Cross, Label}
-import utest._
-
-object ParseArgsTest extends TestSuite {
-
- val tests = Tests {
- 'extractSelsAndArgs - {
- def check(input: Seq[String],
- expectedSelectors: Seq[String],
- expectedArgs: Seq[String],
- expectedIsMulti: Boolean) = {
- val (selectors, args, isMulti) = ParseArgs.extractSelsAndArgs(input)
-
- assert(
- selectors == expectedSelectors,
- args == expectedArgs,
- isMulti == expectedIsMulti
- )
- }
-
- 'empty - check(input = Seq.empty,
- expectedSelectors = Seq.empty,
- expectedArgs = Seq.empty,
- expectedIsMulti = false)
- 'singleSelector - check(
- input = Seq("core.compile"),
- expectedSelectors = Seq("core.compile"),
- expectedArgs = Seq.empty,
- expectedIsMulti = false
- )
- 'singleSelectorWithArgs - check(
- input = Seq("application.run", "hello", "world"),
- expectedSelectors = Seq("application.run"),
- expectedArgs = Seq("hello", "world"),
- expectedIsMulti = false
- )
- 'singleSelectorWithAllInArgs - check(
- input = Seq("application.run", "hello", "world", "--all"),
- expectedSelectors = Seq("application.run"),
- expectedArgs = Seq("hello", "world", "--all"),
- expectedIsMulti = false
- )
- 'multiSelectors - check(
- input = Seq("--all", "core.jar", "core.docsJar", "core.sourcesJar"),
- expectedSelectors = Seq("core.jar", "core.docsJar", "core.sourcesJar"),
- expectedArgs = Seq.empty,
- expectedIsMulti = true
- )
- 'multiSelectorsSeq - check(
- input = Seq("--seq", "core.jar", "core.docsJar", "core.sourcesJar"),
- expectedSelectors = Seq("core.jar", "core.docsJar", "core.sourcesJar"),
- expectedArgs = Seq.empty,
- expectedIsMulti = true
- )
- 'multiSelectorsWithArgs - check(
- input = Seq("--all",
- "core.compile",
- "application.runMain",
- "--",
- "Main",
- "hello",
- "world"),
- expectedSelectors = Seq("core.compile", "application.runMain"),
- expectedArgs = Seq("Main", "hello", "world"),
- expectedIsMulti = true
- )
- 'multiSelectorsWithArgsWithAllInArgs - check(
- input = Seq("--all",
- "core.compile",
- "application.runMain",
- "--",
- "Main",
- "--all",
- "world"),
- expectedSelectors = Seq("core.compile", "application.runMain"),
- expectedArgs = Seq("Main", "--all", "world"),
- expectedIsMulti = true
- )
- }
- 'expandBraces - {
- def check(input: String, expectedExpansion: List[String]) = {
- val Right(expanded) = ParseArgs.expandBraces(input)
-
- assert(expanded == expectedExpansion)
- }
-
- 'expandLeft - check(
- "{application,core}.compile",
- List("application.compile", "core.compile")
- )
- 'expandRight - check(
- "application.{jar,docsJar,sourcesJar}",
- List("application.jar", "application.docsJar", "application.sourcesJar")
- )
- 'expandBoth - check(
- "{core,application}.{jar,docsJar}",
- List(
- "core.jar",
- "core.docsJar",
- "application.jar",
- "application.docsJar"
- )
- )
- 'expandNested - {
- check("{hello,world.{cow,moo}}",
- List("hello", "world.cow", "world.moo"))
- check("{a,b{c,d}}", List("a", "bc", "bd"))
- check("{a,b,{c,d}}", List("a", "b", "c", "d"))
- check("{a,b{c,d{e,f}}}", List("a", "bc", "bde", "bdf"))
- check("{a{b,c},d}", List("ab", "ac", "d"))
- check("{a,{b,c}d}", List("a", "bd", "cd"))
- check("{a{b,c},d{e,f}}", List("ab", "ac", "de", "df"))
- check("{a,b{c,d},e{f,g}}", List("a", "bc", "bd", "ef", "eg"))
- }
- 'expandMixed - check(
- "{a,b}.{c}.{}.e",
- List("a.{c}.{}.e", "b.{c}.{}.e")
- )
- 'malformed - {
- val malformed = Seq("core.{compile", "core.{compile,test]")
-
- malformed.foreach { m =>
- val Left(error) = ParseArgs.expandBraces(m)
- assert(error.contains("Parsing exception"))
- }
- }
- 'dontExpand - {
- check("core.compile", List("core.compile"))
- check("{}.compile", List("{}.compile"))
- check("{core}.compile", List("{core}.compile"))
- }
- 'keepUnknownSymbols - {
- check("{a,b}.e<>", List("a.e<>", "b.e<>"))
- check("a[99]&&", List("a[99]&&"))
- check(
- "{a,b}.<%%>.{c,d}",
- List("a.<%%>.c", "a.<%%>.d", "b.<%%>.c", "b.<%%>.d")
- )
- }
- }
-
- 'apply - {
- def check(input: Seq[String],
- expectedSelectors: List[(Option[List[Segment]], List[Segment])],
- expectedArgs: Seq[String]) = {
- val Right((selectors0, args)) = ParseArgs(input)
-
- val selectors = selectors0.map{
- case (Some(v1), v2) => (Some(v1.value), v2.value)
- case (None, v2) => (None, v2.value)
- }
- assert(
- selectors == expectedSelectors,
- args == expectedArgs
- )
- }
-
- 'rejectEmpty {
- assert(ParseArgs(Seq.empty) == Left("Selector cannot be empty"))
- }
- 'singleSelector - check(
- input = Seq("core.compile"),
- expectedSelectors = List(
- None -> List(Label("core"), Label("compile"))
- ),
- expectedArgs = Seq.empty
- )
- 'externalSelector - check(
- input = Seq("foo.bar/core.compile"),
- expectedSelectors = List(
- Some(List(Label("foo"), Label("bar"))) -> List(Label("core"), Label("compile"))
- ),
- expectedArgs = Seq.empty
- )
- 'singleSelectorWithArgs - check(
- input = Seq("application.run", "hello", "world"),
- expectedSelectors = List(
- None -> List(Label("application"), Label("run"))
- ),
- expectedArgs = Seq("hello", "world")
- )
- 'singleSelectorWithCross - check(
- input = Seq("bridges[2.12.4,jvm].compile"),
- expectedSelectors = List(
- None -> List(Label("bridges"), Cross(Seq("2.12.4", "jvm")), Label("compile"))
- ),
- expectedArgs = Seq.empty
- )
- 'multiSelectorsBraceExpansion - check(
- input = Seq("--all", "{core,application}.compile"),
- expectedSelectors = List(
- None -> List(Label("core"), Label("compile")),
- None -> List(Label("application"), Label("compile"))
- ),
- expectedArgs = Seq.empty
- )
- 'multiSelectorsBraceExpansionWithArgs - check(
- input = Seq("--all", "{core,application}.run", "--", "hello", "world"),
- expectedSelectors = List(
- None -> List(Label("core"), Label("run")),
- None -> List(Label("application"), Label("run"))
- ),
- expectedArgs = Seq("hello", "world")
- )
- 'multiSelectorsBraceExpansionWithCross - check(
- input = Seq("--all", "bridges[2.12.4,jvm].{test,jar}"),
- expectedSelectors = List(
- None -> List(Label("bridges"), Cross(Seq("2.12.4", "jvm")), Label("test")),
- None -> List(Label("bridges"), Cross(Seq("2.12.4", "jvm")), Label("jar"))
- ),
- expectedArgs = Seq.empty
- )
- 'multiSelectorsBraceExpansionInsideCross - check(
- input = Seq("--all", "bridges[{2.11.11,2.11.8}].jar"),
- expectedSelectors = List(
- None -> List(Label("bridges"), Cross(Seq("2.11.11")), Label("jar")),
- None -> List(Label("bridges"), Cross(Seq("2.11.8")), Label("jar"))
- ),
- expectedArgs = Seq.empty
- )
- 'multiSelectorsBraceExpansionWithoutAll - {
- assert(
- ParseArgs(Seq("{core,application}.compile")) == Left(
- "Please use --all flag to run multiple tasks")
- )
- }
- 'multiSelectorsWithoutAllAsSingle - check(
- // this is how it works when we pass multiple tasks without --all flag
- input = Seq("core.compile", "application.compile"),
- expectedSelectors = List(
- None -> List(Label("core"), Label("compile"))
- ),
- expectedArgs = Seq("application.compile")
- )
- }
- }
-
-}
diff --git a/core/test/src/mill/util/ScriptTestSuite.scala b/core/test/src/mill/util/ScriptTestSuite.scala
deleted file mode 100644
index 1aa74de1..00000000
--- a/core/test/src/mill/util/ScriptTestSuite.scala
+++ /dev/null
@@ -1,38 +0,0 @@
-package mill.util
-
-import java.io.{ByteArrayInputStream, ByteArrayOutputStream, PrintStream}
-
-import ammonite.ops._
-import mill.main.ParseArgs
-import utest._
-
-abstract class ScriptTestSuite extends TestSuite{
- def workspaceSlug: String
- def scriptSourcePath: Path
-
- val workspacePath = pwd / 'target / 'workspace / workspaceSlug
- val stdOutErr = new PrintStream(new ByteArrayOutputStream())
-// val stdOutErr = new PrintStream(System.out)
- val stdIn = new ByteArrayInputStream(Array())
- val runner = new mill.main.MainRunner(
- ammonite.main.Cli.Config(wd = workspacePath), false,
- stdOutErr, stdOutErr, stdIn
- )
- def eval(s: String*) = runner.runScript(workspacePath / "build.sc", s.toList)
- def meta(s: String) = {
- val (List(selector), args) = ParseArgs.apply(Seq(s)).right.get
-
- read(workspacePath / "out" / selector._2.value.flatMap(_.pathSegments) / "meta.json")
- }
-
-
- def initWorkspace() = {
- rm(workspacePath)
- mkdir(workspacePath / up)
- // The unzipped git repo snapshots we get from github come with a
- // wrapper-folder inside the zip file, so copy the wrapper folder to the
- // destination instead of the folder containing the wrapper.
-
- cp(scriptSourcePath, workspacePath)
- }
-}
diff --git a/core/test/src/mill/util/TestEvaluator.scala b/core/test/src/mill/util/TestEvaluator.scala
deleted file mode 100644
index a5be0488..00000000
--- a/core/test/src/mill/util/TestEvaluator.scala
+++ /dev/null
@@ -1,83 +0,0 @@
-package mill.util
-
-import ammonite.ops.{Path, pwd}
-import mill.define.Discover.applyImpl
-import mill.define.{Discover, Input, Target, Task}
-import mill.eval.Result.OuterStack
-import mill.eval.{Evaluator, Result}
-import mill.util.Strict.Agg
-import utest.assert
-import utest.framework.TestPath
-
-import language.experimental.macros
-object TestEvaluator{
- implicit def implicitDisover[T]: Discover[T] = macro applyImpl[T]
- val externalOutPath = pwd / 'target / 'external
-
-
- def static[T <: TestUtil.BaseModule](module: T)
- (implicit discover: Discover[T],
- fullName: sourcecode.FullName) = {
- new TestEvaluator[T](module)(discover, fullName, TestPath(Nil))
- }
-}
-
-class TestEvaluator[T <: TestUtil.BaseModule](module: T)
- (implicit discover: Discover[T],
- fullName: sourcecode.FullName,
- tp: TestPath){
- val outPath = TestUtil.getOutPath()
-
- val logger = DummyLogger
-// val logger = new PrintLogger(true, ammonite.util.Colors.Default, System.out, System.out, System.err)
- val evaluator = new Evaluator(outPath, TestEvaluator.externalOutPath, module, discover, logger)
-
- def apply[T](t: Task[T]): Either[Result.Failing[T], (T, Int)] = {
- val evaluated = evaluator.evaluate(Agg(t))
-
- if (evaluated.failing.keyCount == 0) {
- Right(
- Tuple2(
- evaluated.rawValues.head.asInstanceOf[Result.Success[T]].value,
- evaluated.evaluated.collect {
- case t: Target[_]
- if module.millInternal.targets.contains(t)
- && !t.isInstanceOf[Input[_]]
- && !t.ctx.external => t
- case t: mill.define.Command[_] => t
- }.size
- ))
- } else {
- Left(
- evaluated.failing.lookupKey(evaluated.failing.keys().next).items.next()
- .asInstanceOf[Result.Failing[T]]
- )
- }
- }
-
- def fail(target: Target[_], expectedFailCount: Int, expectedRawValues: Seq[Result[_]]) = {
-
- val res = evaluator.evaluate(Agg(target))
-
- val cleaned = res.rawValues.map{
- case Result.Exception(ex, _) => Result.Exception(ex, new OuterStack(Nil))
- case x => x
- }
-
- assert(
- cleaned == expectedRawValues,
- res.failing.keyCount == expectedFailCount
- )
-
- }
-
- def check(targets: Agg[Task[_]], expected: Agg[Task[_]]) = {
- val evaluated = evaluator.evaluate(targets)
- .evaluated
- .flatMap(_.asTarget)
- .filter(module.millInternal.targets.contains)
- .filter(!_.isInstanceOf[Input[_]])
- assert(evaluated == expected)
- }
-
-}
diff --git a/core/test/src/mill/util/TestGraphs.scala b/core/test/src/mill/util/TestGraphs.scala
deleted file mode 100644
index 581d5e0a..00000000
--- a/core/test/src/mill/util/TestGraphs.scala
+++ /dev/null
@@ -1,242 +0,0 @@
-package mill.util
-import TestUtil.test
-import mill.define.Cross
-import mill.{Module, T}
-
-/**
- * Example dependency graphs for us to use in our test suite.
- *
- * The graphs using `test()` live in the `class` and need to be instantiated
- * every time you use them, because they are mutable (you can poke at the
- * `test`'s `counter`/`failure`/`exception` fields to test various graph
- * evaluation scenarios.
- *
- * The immutable graphs, used for testing discovery & target resolution,
- * live in the companion object.
- */
-class TestGraphs(){
- // single
- object singleton extends TestUtil.BaseModule {
- val single = test()
- }
-
- // up---down
- object pair extends TestUtil.BaseModule{
- val up = test()
- val down = test(up)
- }
-
- // up---o---down
- object anonTriple extends TestUtil.BaseModule {
- val up = test()
- val down = test(test.anon(up))
- }
-
- // left
- // / \
- // up down
- // \ /
- // right
- object diamond extends TestUtil.BaseModule {
- val up = test()
- val left = test(up)
- val right = test(up)
- val down = test(left, right)
- }
-
- // o
- // / \
- // up down
- // \ /
- // o
- object anonDiamond extends TestUtil.BaseModule {
- val up = test()
- val down = test(test.anon(up), test.anon(up))
- }
-
- object defCachedDiamond extends TestUtil.BaseModule {
- def up = T{ test() }
- def left = T{ test(up) }
- def right = T{ test(up) }
- def down = T{ test(left, right) }
- }
-
-
- object borkedCachedDiamond2 extends TestUtil.BaseModule {
- def up = test()
- def left = test(up)
- def right = test(up)
- def down = test(left, right)
- }
-
- object borkedCachedDiamond3 extends TestUtil.BaseModule {
- def up = test()
- def left = test(up)
- def right = test(up)
- def down = test(left, right)
- }
-
- // o g-----o
- // \ \ \
- // o o h-----I---o
- // \ / \ / \ / \ \
- // A---c--o E o-o \ \
- // / \ / \ / \ o---J
- // o d o--o o / /
- // \ / \ / /
- // o o---F---o
- // / /
- // o--B o
- object bigSingleTerminal extends TestUtil.BaseModule {
- val a = test(test.anon(), test.anon())
- val b = test(test.anon())
- val e = {
- val c = test.anon(a)
- val d = test.anon(a)
- test(
- test.anon(test.anon(), test.anon(c)),
- test.anon(test.anon(c, test.anon(d, b)))
- )
- }
- val f = test(test.anon(test.anon(), test.anon(e)))
-
- val i = {
- val g = test.anon()
- val h = test.anon(g, e)
- test(test.anon(g), test.anon(test.anon(h)))
- }
- val j = test(test.anon(i), test.anon(i, f), test.anon(f))
- }
- // _ left _
- // / \
- // task1 -------- right
- // _/
- // change - task2
- object separateGroups extends TestUtil.BaseModule {
- val task1 = T.task{ 1 }
- def left = T{ task1() }
- val change = test()
- val task2 = T.task{ change() }
- def right = T{ task1() + task2() + left() + 1 }
-
- }
-}
-
-
-object TestGraphs{
- // _ left _
- // / \
- // task -------- right
- object triangleTask extends TestUtil.BaseModule {
- val task = T.task{ 1 }
- def left = T{ task() }
- def right = T{ task() + left() + 1 }
- }
-
-
- // _ left
- // /
- // task -------- right
- object multiTerminalGroup extends TestUtil.BaseModule {
- val task = T.task{ 1 }
- def left = T{ task() }
- def right = T{ task() }
- }
-
- // _ left _____________
- // / \ \
- // task1 -------- right ----- task2
- object multiTerminalBoundary extends TestUtil.BaseModule {
- val task1 = T.task{ 1 }
- def left = T{ task1() }
- def right = T{ task1() + left() + 1 }
- val task2 = T.task{ left() + right() }
- }
-
-
- trait CanNest extends Module{
- def single = T{ 1 }
- def invisible: Any = T{ 2 }
- def invisible2: mill.define.Task[Int] = T{ 3 }
- def invisible3: mill.define.Task[_] = T{ 4 }
- }
- object nestedModule extends TestUtil.BaseModule {
- def single = T{ 5 }
- def invisible: Any = T{ 6 }
- object nested extends Module{
- def single = T{ 7 }
- def invisible: Any = T{ 8 }
-
- }
- object classInstance extends CanNest
-
- }
-
- trait BaseModule extends Module {
- def foo = T{ Seq("base") }
- def cmd(i: Int) = T.command{ Seq("base" + i) }
- }
-
- object canOverrideSuper extends TestUtil.BaseModule with BaseModule {
- override def foo = T{ super.foo() ++ Seq("object") }
- override def cmd(i: Int) = T.command{ super.cmd(i)() ++ Seq("object" + i) }
- }
-
- trait TraitWithModule extends Module{ outer =>
- object TraitModule extends Module{
- def testFramework = T{ "mill.UTestFramework" }
- def test() = T.command{ ()/*donothing*/ }
- }
- }
-
-
- // Make sure nested objects inherited from traits work
- object TraitWithModuleObject extends TestUtil.BaseModule with TraitWithModule
-
-
- object singleCross extends TestUtil.BaseModule {
- object cross extends mill.Cross[Cross]("210", "211", "212")
- class Cross(scalaVersion: String) extends Module{
- def suffix = T{ scalaVersion }
- }
- }
- object crossResolved extends TestUtil.BaseModule {
- trait MyModule extends Module{
- def crossVersion: String
- implicit object resolver extends mill.define.Cross.Resolver[MyModule]{
- def resolve[V <: MyModule](c: Cross[V]): V = c.itemMap(List(crossVersion))
- }
- }
-
- object foo extends mill.Cross[FooModule]("2.10", "2.11", "2.12")
- class FooModule(val crossVersion: String) extends MyModule{
- def suffix = T{ crossVersion }
- }
-
- object bar extends mill.Cross[BarModule]("2.10", "2.11", "2.12")
- class BarModule(val crossVersion: String) extends MyModule{
- def longSuffix = T{ "_" + foo().suffix() }
- }
- }
- object doubleCross extends TestUtil.BaseModule {
- val crossMatrix = for{
- scalaVersion <- Seq("210", "211", "212")
- platform <- Seq("jvm", "js", "native")
- if !(platform == "native" && scalaVersion != "212")
- } yield (scalaVersion, platform)
- object cross extends mill.Cross[Cross](crossMatrix:_*)
- class Cross(scalaVersion: String, platform: String) extends Module{
- def suffix = T{ scalaVersion + "_" + platform }
- }
- }
-
- object nestedCrosses extends TestUtil.BaseModule {
- object cross extends mill.Cross[Cross]("210", "211", "212")
- class Cross(scalaVersion: String) extends mill.Module{
- object cross2 extends mill.Cross[Cross]("jvm", "js", "native")
- class Cross(platform: String) extends mill.Module{
- def suffix = T{ scalaVersion + "_" + platform }
- }
- }
- }
-}
diff --git a/core/test/src/mill/util/TestUtil.scala b/core/test/src/mill/util/TestUtil.scala
deleted file mode 100644
index 7ef43943..00000000
--- a/core/test/src/mill/util/TestUtil.scala
+++ /dev/null
@@ -1,81 +0,0 @@
-package mill.util
-
-import mill.main.Router.Overrides
-import ammonite.ops.pwd
-import mill.define._
-import mill.eval.Result
-import mill.eval.Result.OuterStack
-import utest.assert
-import mill.util.Strict.Agg
-import utest.framework.TestPath
-
-import scala.collection.mutable
-
-object TestUtil {
- def getOutPath()(implicit fullName: sourcecode.FullName,
- tp: TestPath) = {
- pwd / 'target / 'workspace / (fullName.value.split('.') ++ tp.value)
- }
- def getOutPathStatic()(implicit fullName: sourcecode.FullName) = {
- pwd / 'target / 'workspace / fullName.value.split('.')
- }
-
- def getSrcPathStatic()(implicit fullName: sourcecode.FullName) = {
- pwd / 'target / 'worksources / fullName.value.split('.')
- }
- def getSrcPathBase() = {
- pwd / 'target / 'worksources
- }
-
- class BaseModule(implicit millModuleEnclosing0: sourcecode.Enclosing,
- millModuleLine0: sourcecode.Line,
- millName0: sourcecode.Name,
- overrides: Overrides)
- extends mill.define.BaseModule(getSrcPathBase() / millModuleEnclosing0.value.split("\\.| |#")){
- def millDiscover: Discover[this.type] = Discover[this.type]
- }
-
- object test{
-
- def anon(inputs: Task[Int]*) = new Test(inputs)
- def apply(inputs: Task[Int]*)
- (implicit ctx: mill.define.Ctx)= {
- new TestTarget(inputs, pure = inputs.nonEmpty)
- }
- }
-
- class Test(val inputs: Seq[Task[Int]]) extends Task[Int]{
- var counter = 0
- var failure = Option.empty[String]
- var exception = Option.empty[Throwable]
- override def evaluate(args: Ctx) = {
- failure.map(Result.Failure(_)) orElse
- exception.map(Result.Exception(_, new OuterStack(Nil))) getOrElse
- Result.Success(counter + args.args.map(_.asInstanceOf[Int]).sum)
- }
- override def sideHash = counter + failure.hashCode() + exception.hashCode()
- }
- /**
- * A dummy target that takes any number of inputs, and whose output can be
- * controlled externally, so you can construct arbitrary dataflow graphs and
- * test how changes propagate.
- */
- class TestTarget(inputs: Seq[Task[Int]],
- val pure: Boolean)
- (implicit ctx0: mill.define.Ctx)
- extends Test(inputs) with Target[Int]{
- val ctx = ctx0.copy(segments = ctx0.segments ++ Seq(ctx0.segment))
- val readWrite = upickle.default.IntRW
-
-
- }
- def checkTopological(targets: Agg[Task[_]]) = {
- val seen = mutable.Set.empty[Task[_]]
- for(t <- targets.indexed.reverseIterator){
- seen.add(t)
- for(upstream <- t.inputs){
- assert(!seen(upstream))
- }
- }
- }
-}