From 7bcd80b28532a659d8f799b4a52f64dd13663cab Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 15 May 2023 21:16:05 -0700 Subject: [PATCH 1/6] . --- main/define/src/mill/define/Discover.scala | 26 +++++----- main/resolve/src/mill/resolve/Resolve.scala | 9 ++-- main/src/mill/main/MainModule.scala | 54 +++++++++++++++++---- 3 files changed, 59 insertions(+), 30 deletions(-) diff --git a/main/define/src/mill/define/Discover.scala b/main/define/src/mill/define/Discover.scala index 5bf18fc3aa5..65b7de04390 100644 --- a/main/define/src/mill/define/Discover.scala +++ b/main/define/src/mill/define/Discover.scala @@ -16,18 +16,18 @@ import scala.reflect.macros.blackbox * the `T.command` methods we find. This mapping from `Class[_]` to `MainData` * can then be used later to look up the `MainData` for any module. */ -case class Discover[T] private (value: Map[Class[_], Seq[(Int, mainargs.MainData[_, _])]]) { - private[mill] def copy(value: Map[Class[_], Seq[(Int, mainargs.MainData[_, _])]] = value) +case class Discover[T] private (value: Map[Class[_], Seq[mainargs.MainData[_, _]]]) { + private[mill] def copy(value: Map[Class[_], Seq[mainargs.MainData[_, _]]] = value) : Discover[T] = new Discover[T](value) } object Discover { - def apply[T](value: Map[Class[_], Seq[(Int, mainargs.MainData[_, _])]]): Discover[T] = + def apply[T](value: Map[Class[_], Seq[mainargs.MainData[_, _]]]): Discover[T] = new Discover[T](value) def apply[T]: Discover[T] = macro Router.applyImpl[T] private def unapply[T](discover: Discover[T]) - : Option[Map[Class[_], Seq[(Int, mainargs.MainData[_, _])]]] = Some(discover.value) + : Option[Map[Class[_], Seq[mainargs.MainData[_, _]]]] = Some(discover.value) private class Router(val ctx: blackbox.Context) extends mainargs.Macros(ctx) { import c.universe._ @@ -90,18 +90,14 @@ object Discover { for { m <- methods.toList if m.returnType <:< weakTypeOf[mill.define.Command[_]] - } yield ( - m.overrides.length, - extractMethod( - m.name, - m.paramLists.flatten, - m.pos, - m.annotations.find(_.tree.tpe =:= typeOf[mainargs.main]), - curCls, - weakTypeOf[Any] - ) + } yield extractMethod( + m.name, + m.paramLists.flatten, + m.pos, + m.annotations.find(_.tree.tpe =:= typeOf[mainargs.main]), + curCls, + weakTypeOf[Any] ) - } if overridesRoutes.nonEmpty } yield { diff --git a/main/resolve/src/mill/resolve/Resolve.scala b/main/resolve/src/mill/resolve/Resolve.scala index 6d09575165e..2240c098ac2 100644 --- a/main/resolve/src/mill/resolve/Resolve.scala +++ b/main/resolve/src/mill/resolve/Resolve.scala @@ -120,7 +120,7 @@ object Resolve { (cls, entryPoints) <- discover.value if cls.isAssignableFrom(target.getClass) ep <- entryPoints - if ep._2.name == name + if ep.name == name } yield { def withNullDefault(a: mainargs.ArgSig): mainargs.ArgSig = { if (a.default.nonEmpty) a @@ -133,7 +133,6 @@ object Resolve { } val flattenedArgSigsWithDefaults = ep - ._2 .flattenedArgSigs .map { case (arg, term) => (withNullDefault(arg), term) } @@ -142,9 +141,9 @@ object Resolve { flattenedArgSigsWithDefaults, allowPositional = true, allowRepeats = false, - allowLeftover = ep._2.argSigs0.exists(_.reader.isLeftover) + allowLeftover = ep.argSigs0.exists(_.reader.isLeftover) ).flatMap { (grouped: TokenGrouping[_]) => - val mainData = ep._2.asInstanceOf[MainData[_, Any]] + val mainData = ep.asInstanceOf[MainData[_, Any]] val mainDataWithDefaults = mainData .copy(argSigs0 = mainData.argSigs0.map(withNullDefault)) @@ -159,7 +158,7 @@ object Resolve { case f: mainargs.Result.Failure => Left( mainargs.Renderer.renderResult( - ep._2, + ep, f, totalWidth = 100, printHelpOnError = true, diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index 21faa80a149..5ede82a5924 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -2,17 +2,15 @@ package mill.main import java.util.concurrent.LinkedBlockingQueue import mill.{BuildInfo, T} -import mill.api.{Ctx, Logger, PathRef, Result, internal} -import mill.define.{Command, NamedTask, Segments, TargetImpl, Task} +import mill.api.{Ctx, Logger, PathRef, Result} +import mill.define.{Command, NamedTask, Segments, Task} import mill.eval.{Evaluator, EvaluatorPaths} import mill.resolve.{Resolve, SelectMode} import mill.resolve.SelectMode.Separated import mill.util.{PrintLogger, Watchable} import pprint.{Renderer, Tree, Truncated} -import ujson.Value import scala.collection.mutable -import scala.util.chaining.scalaUtilChainingOps object MainModule { @@ -234,7 +232,40 @@ trait MainModule extends mill.Module { for (a <- annots.distinct) yield mill.util.Util.cleanupScaladoc(a.value).map("\n " + _).mkString - pprint.Tree.Lazy(ctx => + pprint.Tree.Lazy { ctx => + val mainMethodSig = + if (t.asCommand.isEmpty) List() + else { + val mainData = evaluator + .rootModule + .millDiscover + .value(t.ctx.enclosingCls) + .find(_.name == t.ctx.segments.parts.last) + .get + + if (mainData.renderedArgSigs.isEmpty) List() + else { + val rendered = mainargs.Renderer.formatMainMethodSignature( + mainData, + leftIndent = 2, + totalWidth = 100, + leftColWidth = mainargs.Renderer.getLeftColWidth(mainData.renderedArgSigs), + docsOnNewLine = false, + customName = None, + customDoc = None + ) + + // trim first line containing command name, since we already render + // the command name below with the filename and line num + val trimmedRendered = rendered + .linesIterator + .drop(1) + .mkString("\n") + + List("\n", trimmedRendered, "\n") + } + } + Iterator( ctx.applyPrefixColor(t.toString).toString, "(", @@ -244,12 +275,15 @@ trait MainModule extends mill.Module { t.ctx.lineNum.toString, ")", allDocs.mkString("\n"), - "\n", + "\n" + ) ++ + mainMethodSig.iterator ++ + Iterator( "\n", ctx.applyPrefixColor("Inputs").toString, ":" ) ++ t.inputs.distinct.iterator.flatMap(rec).map("\n " + _.render) - ) + } } MainModule.resolveTasks(evaluator, targets, SelectMode.Multi) { tasks => @@ -266,9 +300,9 @@ trait MainModule extends mill.Module { rendered = renderer.rec(tree, 0, 0).iter truncated = new Truncated(rendered, defaults.defaultWidth, defaults.defaultHeight) } yield { - new StringBuilder().tap { sb => - for { str <- truncated ++ Iterator("\n") } sb.append(str) - }.toString() + val sb = new StringBuilder() + for { str <- truncated ++ Iterator("\n") } sb.append(str) + sb.toString() }).mkString("\n") T.log.outputStream.println(output) fansi.Str(output).plainText From a78e3655b599fc72a19969a7c2a426816d4737c8 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 15 May 2023 21:22:40 -0700 Subject: [PATCH 2/6] . --- main/define/src/mill/define/Discover.scala | 3 +-- main/src/mill/main/MainModule.scala | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/main/define/src/mill/define/Discover.scala b/main/define/src/mill/define/Discover.scala index 65b7de04390..5cbb38ffba1 100644 --- a/main/define/src/mill/define/Discover.scala +++ b/main/define/src/mill/define/Discover.scala @@ -17,8 +17,7 @@ import scala.reflect.macros.blackbox * can then be used later to look up the `MainData` for any module. */ case class Discover[T] private (value: Map[Class[_], Seq[mainargs.MainData[_, _]]]) { - private[mill] def copy(value: Map[Class[_], Seq[mainargs.MainData[_, _]]] = value) - : Discover[T] = + private[mill] def copy(value: Map[Class[_], Seq[mainargs.MainData[_, _]]] = value): Discover[T] = new Discover[T](value) } object Discover { diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index 5ede82a5924..bca678eac89 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -278,11 +278,11 @@ trait MainModule extends mill.Module { "\n" ) ++ mainMethodSig.iterator ++ - Iterator( - "\n", - ctx.applyPrefixColor("Inputs").toString, - ":" - ) ++ t.inputs.distinct.iterator.flatMap(rec).map("\n " + _.render) + Iterator( + "\n", + ctx.applyPrefixColor("Inputs").toString, + ":" + ) ++ t.inputs.distinct.iterator.flatMap(rec).map("\n " + _.render) } } From d31cd9762a3e60689195442b1943bbd801a98a8d Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 15 May 2023 22:00:15 -0700 Subject: [PATCH 3/6] . --- .../feature/docannotations/repo/build.sc | 4 +- .../test/src/DocAnnotationsTests.scala | 89 +++++++++++++++++-- main/src/mill/main/MainModule.scala | 52 +++++------ 3 files changed, 111 insertions(+), 34 deletions(-) diff --git a/integration/feature/docannotations/repo/build.sc b/integration/feature/docannotations/repo/build.sc index d42dfb8e97c..3c1e0f288ca 100644 --- a/integration/feature/docannotations/repo/build.sc +++ b/integration/feature/docannotations/repo/build.sc @@ -19,9 +19,9 @@ object core extends JavaModule { object test extends Tests with JUnitTests /** - * Core Task Docz! + * Core Target Docz! */ - def task = T { + def target = T { import collection.JavaConverters._ println(this.getClass.getClassLoader.getResources("scalac-plugin.xml").asScala.toList) "Hello!" diff --git a/integration/feature/docannotations/test/src/DocAnnotationsTests.scala b/integration/feature/docannotations/test/src/DocAnnotationsTests.scala index e968ab85f0a..6eb0d518a1d 100644 --- a/integration/feature/docannotations/test/src/DocAnnotationsTests.scala +++ b/integration/feature/docannotations/test/src/DocAnnotationsTests.scala @@ -3,28 +3,103 @@ package mill.integration import utest._ object DocAnnotationsTests extends IntegrationTestSuite { + def globMatches(glob: String, input: String) = { + StringContext.glob(glob.stripMargin.split("\\.\\.\\."), input).isDefined + } val tests = Tests { initWorkspace() test("test") - { val res = eval("inspect", "core.test.ivyDeps") assert(res == true) + val inheritedIvyDeps = ujson.read(meta("inspect"))("value").str assert( - inheritedIvyDeps.contains("core.test.ivyDeps"), - inheritedIvyDeps.contains("Overriden ivyDeps Docs!!!"), - inheritedIvyDeps.contains("Any ivy dependencies you want to add to this Module") + globMatches( + """core.test.ivyDeps(build.sc:...) + | Overriden ivyDeps Docs!!! + | + | Any ivy dependencies you want to add to this Module, in the format + | ivy"org::name:version" for Scala dependencies or ivy"org:name:version" + | for Java dependencies + | + |Inputs: + |""".stripMargin, + inheritedIvyDeps + ) ) - assert(eval("inspect", "core.task")) - val task = ujson.read(meta("inspect"))("value").str + assert(eval("inspect", "core.target")) + val target = ujson.read(meta("inspect"))("value").str + pprint.log(target) assert( - task.contains("Core Task Docz!") + globMatches( + """core.target(build.sc:...) + | Core Target Docz! + | + |Inputs: + |""", + target + ) ) assert(eval("inspect", "inspect")) val doc = ujson.read(meta("inspect"))("value").str assert( - doc.contains("Displays metadata about the given task without actually running it.") + globMatches( + """inspect(MainModule.scala:...) + | Displays metadata about the given task without actually running it. + | + |Inputs: + |""".stripMargin, + doc + ) + ) + + assert(eval("inspect", "core.run")) + val run = ujson.read(meta("inspect"))("value").str + + + assert( + globMatches( + """core.run(JavaModule.scala:...) + | Runs this module's code in a subprocess and waits for it to finish + | + | args ... + | + |Inputs: + | core.finalMainClass + | core.runClasspath + | core.forkArgs + | core.forkEnv + | core.forkWorkingDir + | core.runUseArgsFile + |""", + run + ) + ) + + assert(eval("inspect", "core.ivyDepsTree")) + + val ivyDepsTree = ujson.read(meta("inspect"))("value").str + assert( + globMatches( + """core.ivyDepsTree(JavaModule.scala:...) + | Command to print the transitive dependency tree to STDOUT. + | + | --inverse Invert the tree representation, so that the root is on the bottom val + | inverse (will be forced when used with whatDependsOn) + | --whatDependsOn Possible list of modules (org:artifact) to target in the tree in order to + | see where a dependency stems from. + | --withCompile Include the compile-time only dependencies (`compileIvyDeps`, provided + | scope) into the tree. + | --withRuntime Include the runtime dependencies (`runIvyDeps`, runtime scope) into the + | tree. + | + |Inputs: + | core.transitiveIvyDeps + |""".stripMargin, + ivyDepsTree + ) ) } } diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index bca678eac89..38a69abd296 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -236,33 +236,35 @@ trait MainModule extends mill.Module { val mainMethodSig = if (t.asCommand.isEmpty) List() else { - val mainData = evaluator + val mainDataOpt = evaluator .rootModule .millDiscover - .value(t.ctx.enclosingCls) - .find(_.name == t.ctx.segments.parts.last) - .get - - if (mainData.renderedArgSigs.isEmpty) List() - else { - val rendered = mainargs.Renderer.formatMainMethodSignature( - mainData, - leftIndent = 2, - totalWidth = 100, - leftColWidth = mainargs.Renderer.getLeftColWidth(mainData.renderedArgSigs), - docsOnNewLine = false, - customName = None, - customDoc = None - ) - - // trim first line containing command name, since we already render - // the command name below with the filename and line num - val trimmedRendered = rendered - .linesIterator - .drop(1) - .mkString("\n") - - List("\n", trimmedRendered, "\n") + .value + .get(t.ctx.enclosingCls) + .flatMap(_.find(_.name == t.ctx.segments.parts.last)) + + mainDataOpt match{ + case Some(mainData) if mainData.renderedArgSigs.nonEmpty => + val rendered = mainargs.Renderer.formatMainMethodSignature( + mainDataOpt.get, + leftIndent = 2, + totalWidth = 100, + leftColWidth = mainargs.Renderer.getLeftColWidth(mainData.renderedArgSigs), + docsOnNewLine = false, + customName = None, + customDoc = None + ) + + // trim first line containing command name, since we already render + // the command name below with the filename and line num + val trimmedRendered = rendered + .linesIterator + .drop(1) + .mkString("\n") + + List("\n", trimmedRendered, "\n") + + case _ => List() } } From 742ecfb0cbafc6ac23ac283054e90e6f8aea4b31 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 15 May 2023 22:01:10 -0700 Subject: [PATCH 4/6] . --- .../feature/docannotations/test/src/DocAnnotationsTests.scala | 1 - main/src/mill/main/MainModule.scala | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/integration/feature/docannotations/test/src/DocAnnotationsTests.scala b/integration/feature/docannotations/test/src/DocAnnotationsTests.scala index 6eb0d518a1d..d1a00be754d 100644 --- a/integration/feature/docannotations/test/src/DocAnnotationsTests.scala +++ b/integration/feature/docannotations/test/src/DocAnnotationsTests.scala @@ -58,7 +58,6 @@ object DocAnnotationsTests extends IntegrationTestSuite { assert(eval("inspect", "core.run")) val run = ujson.read(meta("inspect"))("value").str - assert( globMatches( """core.run(JavaModule.scala:...) diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index 38a69abd296..a7b63fd0651 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -243,7 +243,7 @@ trait MainModule extends mill.Module { .get(t.ctx.enclosingCls) .flatMap(_.find(_.name == t.ctx.segments.parts.last)) - mainDataOpt match{ + mainDataOpt match { case Some(mainData) if mainData.renderedArgSigs.nonEmpty => val rendered = mainargs.Renderer.formatMainMethodSignature( mainDataOpt.get, From 12316dba1bb1e9a43a8b721d15e919fd454908b1 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 15 May 2023 22:57:49 -0700 Subject: [PATCH 5/6] . --- .../docannotations/test/src/DocAnnotationsTests.scala | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/integration/feature/docannotations/test/src/DocAnnotationsTests.scala b/integration/feature/docannotations/test/src/DocAnnotationsTests.scala index d1a00be754d..356793dc018 100644 --- a/integration/feature/docannotations/test/src/DocAnnotationsTests.scala +++ b/integration/feature/docannotations/test/src/DocAnnotationsTests.scala @@ -4,7 +4,13 @@ import utest._ object DocAnnotationsTests extends IntegrationTestSuite { def globMatches(glob: String, input: String) = { - StringContext.glob(glob.stripMargin.split("\\.\\.\\."), input).isDefined + StringContext + .glob( + // Normalize the line separator to be `\n` for comparisons + glob.stripMargin.linesIterator.mkString("\n").split("\\.\\.\\."), + input.linesIterator.mkString("\n") + ) + .isDefined } val tests = Tests { initWorkspace() From ff06752c737809fad5f5b06fc68603a73cd41387 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 15 May 2023 22:58:14 -0700 Subject: [PATCH 6/6] . --- .../feature/docannotations/test/src/DocAnnotationsTests.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/integration/feature/docannotations/test/src/DocAnnotationsTests.scala b/integration/feature/docannotations/test/src/DocAnnotationsTests.scala index 356793dc018..83c3107642f 100644 --- a/integration/feature/docannotations/test/src/DocAnnotationsTests.scala +++ b/integration/feature/docannotations/test/src/DocAnnotationsTests.scala @@ -12,6 +12,7 @@ object DocAnnotationsTests extends IntegrationTestSuite { ) .isDefined } + val tests = Tests { initWorkspace() test("test") - {