diff options
-rw-r--r-- | core/src/mill/define/Ctx.scala | 4 | ||||
-rw-r--r-- | main/src/mill/main/Resolve.scala | 44 | ||||
-rw-r--r-- | main/test/src/mill/main/MainTests.scala | 6 | ||||
-rw-r--r-- | readme.md | 16 | ||||
-rw-r--r-- | scalalib/src/mill/scalalib/ScalaModule.scala | 2 |
5 files changed, 44 insertions, 28 deletions
diff --git a/core/src/mill/define/Ctx.scala b/core/src/mill/define/Ctx.scala index 6075b804..9b8db6ed 100644 --- a/core/src/mill/define/Ctx.scala +++ b/core/src/mill/define/Ctx.scala @@ -12,7 +12,9 @@ sealed trait Segment{ } } object Segment{ - case class Label(value: String) extends Segment + case class Label(value: String) extends Segment{ + assert(!value.contains('.')) + } case class Cross(value: Seq[Any]) extends Segment } diff --git a/main/src/mill/main/Resolve.scala b/main/src/mill/main/Resolve.scala index bd946be3..01c3dcf3 100644 --- a/main/src/mill/main/Resolve.scala +++ b/main/src/mill/main/Resolve.scala @@ -101,7 +101,7 @@ object ResolveTasks extends Resolve[NamedTask[Any]]{ Resolve.runDefault(obj, Segment.Cross(last), discover, rest).flatten.headOption match{ case None => Left( - "Unable to find default task to evaluate for module " + + "Cannot find default task to evaluate for module " + Segments((Segment.Cross(last) :: revSelectorsSoFar).reverse:_*).render ) case Some(v) => v.map(Seq(_)) @@ -130,6 +130,8 @@ object ResolveTasks extends Resolve[NamedTask[Any]]{ command orElse target orElse Resolve.runDefault(obj, Segment.Label(last), discover, rest).flatten.headOption match { case None => + pprint.log(revSelectorsSoFar) + pprint.log(last) Resolve.errorMsgLabel( singleModuleMeta(obj, discover, revSelectorsSoFar.isEmpty), last, @@ -160,16 +162,17 @@ object Resolve{ dist(s2.length)(s1.length) } - def unableToResolve(last: Segment, revSelectorsSoFar: List[Segment]) = { - "Unable to resolve " + - Segments((last :: revSelectorsSoFar).reverse: _*).render + - "." + def unableToResolve(last: Segment, revSelectorsSoFar: List[Segment]): String = { + unableToResolve(Segments((last :: revSelectorsSoFar).reverse: _*).render) } + def unableToResolve(segments: String): String = "Cannot resolve " + segments + "." + def hintList(last: Segment, revSelectorsSoFar: List[Segment]) = { val search = Segments((last :: revSelectorsSoFar).reverse: _*).render s" Try `mill resolve $search` to see what's available." } + def hintListLabel(revSelectorsSoFar: List[Segment]) = { hintList(Segment.Label("_"), revSelectorsSoFar) } @@ -183,30 +186,41 @@ object Resolve{ revSelectorsSoFar: List[Segment], editSplit: String => String) (strings: T => Seq[String], - segment: T => Segment)= { + render: T => String)= { val last = strings(last0) val similar = direct - .map(strings) - .filter(_.length == last.length) - .map(d => (d, d.zip(last).map{case (a, b) => Resolve.editDistance(editSplit(a), b)}.sum)) + .map(x => (x, strings(x))) + .filter(_._2.length == last.length) + .map{ case (d, s) => (d, s.zip(last).map{case (a, b) => Resolve.editDistance(editSplit(a), b)}.sum)} .filter(_._2 < 3) .sortBy(_._2) val hint = similar match{ case Nil => hintListLabel(revSelectorsSoFar) - case items => " Did you mean " + items.head._1 + "?" + case items => + " Did you mean " + render(items.head._1)+ "?" } - Left(unableToResolve(segment(last0), revSelectorsSoFar) + hint) + pprint.log(direct) + pprint.log(revSelectorsSoFar) + pprint.log(last0) + pprint.log(last) + Left(unableToResolve(render(last0)) + hint) } def errorMsgLabel(direct: Seq[String], last: String, revSelectorsSoFar: List[Segment]) = { - errorMsgBase(direct, last, revSelectorsSoFar, _.split('.').last)(Seq(_), Segment.Label(_)) + errorMsgBase(direct, Segments((Segment.Label(last) :: revSelectorsSoFar).reverse:_*).render, revSelectorsSoFar, _.split('.').last)( + rendered => Seq(rendered.split('.').last), + x => x + ) } def errorMsgCross(crossKeys: Seq[Seq[String]], last: Seq[String], revSelectorsSoFar: List[Segment]) = { - errorMsgBase(crossKeys, last, revSelectorsSoFar, x => x)(x => x, Segment.Cross(_)) + errorMsgBase(crossKeys, last, revSelectorsSoFar, x => x)( + crossKeys => crossKeys, + crossKeys => Segments((Segment.Cross(crossKeys) :: revSelectorsSoFar).reverse:_*).render + ) } def invokeCommand(target: Module, @@ -271,7 +285,7 @@ abstract class Resolve[R: ClassTag] { case head :: tail => val newRevSelectorsSoFar = head :: revSelectorsSoFar - def recurse(searchModules: Seq[Module], resolveFailureMsg: Left[String, Nothing]) = { + def recurse(searchModules: Seq[Module], resolveFailureMsg: => Left[String, Nothing]) = { val matching = searchModules .map(resolve(tail, _, discover, rest, remainingCrossSelectors, newRevSelectorsSoFar)) @@ -315,7 +329,7 @@ abstract class Resolve[R: ClassTag] { Resolve.errorMsgCross( c.items.map(_._1.map(_.toString)), cross.map(_.toString), - revSelectorsSoFar + newRevSelectorsSoFar ) ) case _ => diff --git a/main/test/src/mill/main/MainTests.scala b/main/test/src/mill/main/MainTests.scala index 87b3f7ab..7ad5c00e 100644 --- a/main/test/src/mill/main/MainTests.scala +++ b/main/test/src/mill/main/MainTests.scala @@ -15,7 +15,7 @@ object MainTests extends TestSuite{ val resolved = for{ selectors <- mill.util.ParseArgs(Seq(selectorString), multiSelect = false).map(_._1.head) val crossSelectors = selectors._2.value.map{case Segment.Cross(x) => x.toList.map(_.toString) case _ => Nil} - task <- mill.main.Resolve.resolve( + task <- mill.main.ResolveTasks.resolve( selectors._2.value.toList, module, discover, Nil, crossSelectors.toList, Nil ) } yield task @@ -27,8 +27,8 @@ object MainTests extends TestSuite{ 'single - { val check = MainTests.check(singleton) _ 'pos - check("single", Right(Seq(_.single))) - 'neg1 - check("doesntExist", Left("Cannot resolve doesntExist")) - 'neg2 - check("single.doesntExist", Left("Cannot resolve single")) + 'neg1 - check("doesntExist", Left("Cannot resolve doesntExist. Try `mill resolve _` to see what's available.")) + 'neg2 - check("single.doesntExist", Left("Cannot resolve single. Try `mill resolve _` to see what's available.")) 'neg3 - check("", Left("Selector cannot be empty")) } 'nested - { @@ -23,7 +23,7 @@ own codebase. Run unit test suite: ```bash -sbt core/test +sbt main/test ``` Build a standalone executable jar: @@ -38,8 +38,8 @@ core unit tests e.g.: ```bash ./target/bin/mill core.compile -./target/bin/mill core.test.compile -./target/bin/mill core.test +./target/bin/mill main.test.compile +./target/bin/mill main.test ./target/bin/mill scalalib.assembly ``` @@ -56,7 +56,7 @@ You can get Mill to show the JSON-structured output for a particular `Target` or ./target/bin/mill show core.scalaVersion ./target/bin/mill show core.compile ./target/bin/mill show core.assemblyClasspath -./target/bin/mill show core.test +./target/bin/mill show main.test ``` Output will be generated into a the `./out` folder. @@ -66,7 +66,7 @@ file in the repository root, you can skip the assembly process and directly run it via: ```bash -sbt "~bin/test:run core.test" +sbt "~bin/test:run main.test" sbt "~bin/test:run" ``` @@ -94,7 +94,7 @@ mill bridges[2.12.4].publish --credentials foo --gpgPassphrase bar * Run multiple targets: ```bash -mill all core.test scalalib.test +mill all main.test scalalib.test ``` **Note**: don't forget to put `--all` flag when you run multiple commands, otherwise the only first command will be run, and subsequent commands will be passed as arguments to the first one. @@ -285,8 +285,8 @@ The `out/` folder contains all the generated files & metadata for your build. It is structured with one folder per `Target`/`Command`, that is run, e.g.: - `out/core/compile/` -- `out/core/test/compile/` -- `out/core/test/forkTest/` +- `out/main/test/compile/` +- `out/main/test/forkTest/` - `out/scalalib/compile/` Each folder currently contains the following files: diff --git a/scalalib/src/mill/scalalib/ScalaModule.scala b/scalalib/src/mill/scalalib/ScalaModule.scala index d62cc300..c3d0af4f 100644 --- a/scalalib/src/mill/scalalib/ScalaModule.scala +++ b/scalalib/src/mill/scalalib/ScalaModule.scala @@ -269,7 +269,7 @@ object TestModule{ val badTests = results.filter(x => Set("Error", "Failure").contains(x.status)) if (badTests.isEmpty) Result.Success((doneMsg, results)) else { - val suffix = if (badTests.length == 1) "" else "and " + (badTests.length-1) + " more" + val suffix = if (badTests.length == 1) "" else " and " + (badTests.length-1) + " more" Result.Failure( badTests.head.fullyQualifiedName + " " + badTests.head.selector + suffix, |