From 17a4696f80df84c0f5bf87db5e17e618c27dce5d Mon Sep 17 00:00:00 2001 From: Mark Soule Date: Tue, 20 Mar 2018 22:33:57 -0500 Subject: [PATCH 1/7] Adding clean as a default task --- main/src/mill/main/MainModule.scala | 38 ++++++++++++++++++++++++++++- readme.md | 11 +++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index 4b0a4354a09..272fe8a2a11 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -1,10 +1,13 @@ package mill.main +import ammonite.ops.Path import mill.define.{NamedTask, Task} import mill.eval.{Evaluator, Result} -import mill.util.{EitherOps, ParseArgs, PrintLogger, Watched} +import mill.util.{PrintLogger, Watched} import pprint.{Renderer, Truncated} import upickle.Js + +import scala.util.{Failure, Success, Try} object MainModule{ def resolveTasks[T](evaluator: Evaluator[Any], targets: Seq[String], multiSelect: Boolean) (f: List[NamedTask[Any]] => T) = { @@ -31,6 +34,9 @@ trait MainModule extends mill.Module{ implicit def millScoptTasksReads[T] = new mill.main.Tasks.Scopt[T]() implicit def millScoptEvaluatorReads[T] = new mill.main.EvaluatorScopt[T]() + private val OutDir: String = "out" + private val BuildFile: String = "build.sc" + /** * Resolves a mill query string and prints out the tasks it resolves to. */ @@ -173,4 +179,34 @@ trait MainModule extends mill.Module{ } } } + + /** + * Deletes the given targets from the out directory. Providing no targets will clean everything. + */ + def clean(targets: String*) = mill.T.command { + val result = Try { + if (ammonite.ops.ls(ammonite.ops.pwd).contains(ammonite.ops.pwd / BuildFile)) { + targets match { + case Nil => + remove(List(ammonite.ops.pwd / OutDir)) + case _ => + remove(targets + .map(_.replace(".", "/")) + .map(target => Path(target, ammonite.ops.pwd / OutDir)) + .toList) + } + } else { + Result.Failure(s"Cannot find $BuildFile") + } + } + result match { + case Success(r) => r + case Failure(error) => Result.Exception(error, new Result.OuterStack(error.getStackTrace)) + } + } + + private def remove(paths: List[Path]): Result[String] = { + paths.filter(ammonite.ops.exists).foreach(ammonite.ops.rm) + Result.Success("Targets cleaned") + } } diff --git a/readme.md b/readme.md index a1dacc2ced1..aa0f5539575 100644 --- a/readme.md +++ b/readme.md @@ -64,6 +64,17 @@ You can get Mill to show the JSON-structured output for a particular `Target` or Output will be generated into a the `./out` folder. +You can clean the project using `clean`: + +```bash +# Clean entire project. +mill clean +# Clean a single target. +mill clean main +# Clean multiple targets. +mill clean main core +``` + If you are repeatedly testing Mill manually by running it against the `build.sc` file in the repository root, you can skip the assembly process and directly run it via: From 284ea8e93ee8b36bd1ac6f580528b78895e5f5c3 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 8 May 2018 18:48:42 +0200 Subject: [PATCH 2/7] [WIP] Improve 'clean' paths resolution --- main/src/mill/main/MainModule.scala | 54 ++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index 0fe252c4b2e..0c2803a52d3 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -3,12 +3,10 @@ package mill.main import ammonite.ops.Path import mill.define.{NamedTask, Task} import mill.eval.{Evaluator, Result} -import mill.util.{EitherOps, ParseArgs, PrintLogger, Watched} +import mill.util.{ParseArgs, PrintLogger, Watched} import pprint.{Renderer, Truncated} import upickle.Js -import scala.util.{Failure, Success, Try} - object MainModule{ def resolveTasks[T](evaluator: Evaluator[Any], targets: Seq[String], multiSelect: Boolean) (f: List[NamedTask[Any]] => T) = { @@ -40,9 +38,7 @@ trait MainModule extends mill.Module{ res } - private val OutDir: String = "out" - private val BuildFile: String = "build.sc" /** * Resolves a mill query string and prints out the tasks it resolves to. @@ -190,30 +186,34 @@ trait MainModule extends mill.Module{ /** * Deletes the given targets from the out directory. Providing no targets will clean everything. */ - def clean(targets: String*) = mill.T.command { - val result = Try { - if (ammonite.ops.ls(ammonite.ops.pwd).contains(ammonite.ops.pwd / BuildFile)) { - targets match { - case Nil => - remove(List(ammonite.ops.pwd / OutDir)) - case _ => - remove(targets - .map(_.replace(".", "/")) - .map(target => Path(target, ammonite.ops.pwd / OutDir)) - .toList) - } - } else { - Result.Failure(s"Cannot find $BuildFile") + def clean(evaluator: Evaluator[Any], targets: String*) = mill.T.command { + + def success = Result.Success("Targets cleaned") + + def remove(paths: List[Path]): Unit = paths.foreach(ammonite.ops.rm) + + if (targets.isEmpty) { + remove(List(ammonite.ops.pwd / OutDir)) + success + } else { + ParseArgs(targets, multiSelect = true) match { + case Left(errMsg) => + Result.Failure(errMsg) + + case Right((selectors, _)) => + val pathsToRemove = selectors.map { case (scopedSel, sel) => + val rootPath = scopedSel match { + case Some(scoped) => + Evaluator.resolveDestPaths(ammonite.ops.pwd / OutDir, scoped).out + case None => + ammonite.ops.pwd / OutDir + } + Evaluator.resolveDestPaths(rootPath, sel).out + } + remove(pathsToRemove) + success } } - result match { - case Success(r) => r - case Failure(error) => Result.Exception(error, new Result.OuterStack(error.getStackTrace)) - } } - private def remove(paths: List[Path]): Result[String] = { - paths.filter(ammonite.ops.exists).foreach(ammonite.ops.rm) - Result.Success("Targets cleaned") - } } From 6f1c2471585a38b72317de651ac3072626a252c2 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 9 May 2018 11:12:28 +0200 Subject: [PATCH 3/7] Improve clean targets resolution mechanism --- main/src/mill/main/MainModule.scala | 46 +++++++++++------------- main/src/mill/main/Resolve.scala | 55 +++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index 0c2803a52d3..8271281817d 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -184,35 +184,29 @@ trait MainModule extends mill.Module{ } /** - * Deletes the given targets from the out directory. Providing no targets will clean everything. + * Deletes the given targets from the out directory. Providing no targets + * will clean everything. */ def clean(evaluator: Evaluator[Any], targets: String*) = mill.T.command { - def success = Result.Success("Targets cleaned") - - def remove(paths: List[Path]): Unit = paths.foreach(ammonite.ops.rm) - - if (targets.isEmpty) { - remove(List(ammonite.ops.pwd / OutDir)) - success - } else { - ParseArgs(targets, multiSelect = true) match { - case Left(errMsg) => - Result.Failure(errMsg) - - case Right((selectors, _)) => - val pathsToRemove = selectors.map { case (scopedSel, sel) => - val rootPath = scopedSel match { - case Some(scoped) => - Evaluator.resolveDestPaths(ammonite.ops.pwd / OutDir, scoped).out - case None => - ammonite.ops.pwd / OutDir - } - Evaluator.resolveDestPaths(rootPath, sel).out - } - remove(pathsToRemove) - success - } + val rootDir = ammonite.ops.pwd / OutDir + + val pathsToRemove = + if (targets.isEmpty) + Right(List(rootDir)) + else + RunScript.resolveTasks( + mill.main.ResolveSegments, evaluator, targets, multiSelect = true + ).map(_.map { segments => + Evaluator.resolveDestPaths(rootDir, segments).out + }) + + pathsToRemove match { + case Left(err) => + Result.Failure(err) + case Right(paths) => + paths.foreach(ammonite.ops.rm) + Result.Success(()) } } diff --git a/main/src/mill/main/Resolve.scala b/main/src/mill/main/Resolve.scala index ccb5ec04e44..4491c5e341f 100644 --- a/main/src/mill/main/Resolve.scala +++ b/main/src/mill/main/Resolve.scala @@ -86,6 +86,61 @@ object ResolveMetadata extends Resolve[String]{ } } +object ResolveSegments extends Resolve[Segments] { + + override def endResolveCross(obj: Module, + revSelectorsSoFar: List[Segment], + last: List[String], + discover: Discover[_], + rest: Seq[String]): Either[String, Seq[Segments]] = { + obj match{ + case c: Cross[Module] => + Right(c.items.map(_._2.millModuleSegments)) + case _ => + Left( + Resolve.unableToResolve(Segment.Cross(last), revSelectorsSoFar) + + Resolve.hintListLabel(revSelectorsSoFar) + ) + } + } + + def endResolveLabel(obj: Module, + revSelectorsSoFar: List[Segment], + last: String, + discover: Discover[_], + rest: Seq[String]): Either[String, Seq[Segments]] = { + val target = + obj + .millInternal + .reflect[Target[_]] + .find(_.label == last) + .map(t => Right(t.ctx.segments)) + + val command = + Resolve + .invokeCommand(obj, last, discover, rest) + .headOption + .map(_.map(_.ctx.segments)) + + val module = + obj.millInternal + .reflectNestedObjects[Module] + .find(_.millOuterCtx.segment == Segment.Label(last)) + .map(m => Right(m.millModuleSegments)) + + command orElse target orElse module match { + case None => + Resolve.errorMsgLabel( + singleModuleMeta(obj, discover, revSelectorsSoFar.isEmpty), + last, + revSelectorsSoFar + ) + + case Some(either) => either.right.map(Seq(_)) + } + } +} + object ResolveTasks extends Resolve[NamedTask[Any]]{ From 166e4da911016fc72ba35f5c65c1ef6dafc6aeaf Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 12 May 2018 17:01:40 +0200 Subject: [PATCH 4/7] fix error on clean all --- main/src/mill/main/MainModule.scala | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index 8271281817d..e6be53a63b9 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -3,7 +3,7 @@ package mill.main import ammonite.ops.Path import mill.define.{NamedTask, Task} import mill.eval.{Evaluator, Result} -import mill.util.{ParseArgs, PrintLogger, Watched} +import mill.util.{PrintLogger, Watched} import pprint.{Renderer, Truncated} import upickle.Js @@ -188,24 +188,34 @@ trait MainModule extends mill.Module{ * will clean everything. */ def clean(evaluator: Evaluator[Any], targets: String*) = mill.T.command { - val rootDir = ammonite.ops.pwd / OutDir + val KeepPattern = "(mill-worker-[0-9]+)".r.anchored + + def keepPath(path: Path) = path.segments.lastOption match { + case Some(KeepPattern(_)) => true + case _ => false + } + val pathsToRemove = if (targets.isEmpty) - Right(List(rootDir)) + Right(ammonite.ops.ls(rootDir).filterNot(keepPath)) else RunScript.resolveTasks( mill.main.ResolveSegments, evaluator, targets, multiSelect = true - ).map(_.map { segments => - Evaluator.resolveDestPaths(rootDir, segments).out - }) + ).map( + _.map { segments => + Evaluator.resolveDestPaths(rootDir, segments).out + }) pathsToRemove match { case Left(err) => Result.Failure(err) case Right(paths) => - paths.foreach(ammonite.ops.rm) + paths.foreach { p => + println(p) + ammonite.ops.rm(p) + } Result.Success(()) } } From 26ec458c7140efbd7635d730895dfabee33745ff Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 12 May 2018 20:20:26 +0200 Subject: [PATCH 5/7] update "clean all" to keep all 'out/mill-*' paths --- main/src/mill/main/MainModule.scala | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index e6be53a63b9..4fed5ec5c67 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -190,8 +190,8 @@ trait MainModule extends mill.Module{ def clean(evaluator: Evaluator[Any], targets: String*) = mill.T.command { val rootDir = ammonite.ops.pwd / OutDir - val KeepPattern = "(mill-worker-[0-9]+)".r.anchored - + val KeepPattern = "(mill-.+)".r.anchored + def keepPath(path: Path) = path.segments.lastOption match { case Some(KeepPattern(_)) => true case _ => false @@ -212,10 +212,7 @@ trait MainModule extends mill.Module{ case Left(err) => Result.Failure(err) case Right(paths) => - paths.foreach { p => - println(p) - ammonite.ops.rm(p) - } + paths.foreach(ammonite.ops.rm) Result.Success(()) } } From 15ef865bb6752786f346843379c086e75425ef3f Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 12 May 2018 21:11:57 +0200 Subject: [PATCH 6/7] fix cross module resolution in clean task --- main/src/mill/main/Resolve.scala | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/main/src/mill/main/Resolve.scala b/main/src/mill/main/Resolve.scala index 4491c5e341f..4b0ae27f1db 100644 --- a/main/src/mill/main/Resolve.scala +++ b/main/src/mill/main/Resolve.scala @@ -95,7 +95,22 @@ object ResolveSegments extends Resolve[Segments] { rest: Seq[String]): Either[String, Seq[Segments]] = { obj match{ case c: Cross[Module] => - Right(c.items.map(_._2.millModuleSegments)) + last match{ + case List("__") => Right(c.items.map(_._2.millModuleSegments)) + case items => + c.items + .filter(_._1.length == items.length) + .filter(_._1.zip(last).forall{case (a, b) => b == "_" || a.toString == b}) + .map(_._2.millModuleSegments) match { + case Nil => + Resolve.errorMsgCross( + c.items.map(_._1.map(_.toString)), + last, + revSelectorsSoFar + ) + case res => Right(res) + } + } case _ => Left( Resolve.unableToResolve(Segment.Cross(last), revSelectorsSoFar) + From 8729054777842cab5cdec0f3e8d91edfbc2b5238 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 12 May 2018 22:58:05 +0200 Subject: [PATCH 7/7] Add documentation for "clean" task --- docs/pages/1 - Intro to Mill.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/pages/1 - Intro to Mill.md b/docs/pages/1 - Intro to Mill.md index 5eab7141bac..f6854ba2c9b 100644 --- a/docs/pages/1 - Intro to Mill.md +++ b/docs/pages/1 - Intro to Mill.md @@ -456,6 +456,26 @@ $ mill show foo.compileDepClasspath `show` is also useful for interacting with Mill from external tools, since the JSON it outputs is structured and easily parsed & manipulated. +### clean + +```bash +$ mill clean +``` + +`clean` deletes all the cached outputs of previously executed tasks. It can +apply to the entire project, entire modules, or specific tasks. + +```bash +mill clean # clean all outputs +mill clean foo # clean all outputs for module 'foo' (including nested modules) +mill clean foo.compile # only clean outputs for task 'compile' in module 'foo' +mill clean foo.{compile,run} +mill clean "foo.{compile,run}" +mill clean foo.compile foo.run +mill clean _.compile +mill clean __.compile +``` + ## IntelliJ Support Mill supports IntelliJ by default. Use `mill mill.scalalib.GenIdea/idea` to