Skip to content

Commit

Permalink
Issue #2929: implement inspect for modules (WIP)
Browse files Browse the repository at this point in the history
Pull request: #3532
  • Loading branch information
Shri333 committed Sep 21, 2024
1 parent 92a7211 commit 2d28b14
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 56 deletions.
10 changes: 10 additions & 0 deletions main/define/src/mill/define/Module.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ trait Module extends Module.BaseClass {
@internal
object millInternal extends Module.Internal(this)

@internal
val moduleTask: Module.ModuleTask[_] = Module.ModuleTask(this)

def millModuleDirectChildren: Seq[Module] = millModuleDirectChildrenImpl

// We keep a private `lazy val` and a public `def` so
Expand Down Expand Up @@ -91,4 +94,11 @@ object Module {
.map { case (name, cls, getter) => getter(outer) }
}
}

@internal
case class ModuleTask[+T](module: Module) extends NamedTask[T] {
override def t: Task[T] = this
override def ctx0: Ctx = module.millOuterCtx
override def isPrivate: Option[Boolean] = None
}
}
40 changes: 2 additions & 38 deletions main/resolve/src/mill/resolve/Resolve.scala
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
package mill.resolve

import mainargs.{MainData, TokenGrouping}
import mill.define.{
BaseModule,
Command,
Discover,
Module,
NamedTask,
Reflect,
Segments,
Target,
TaskModule
}
import mill.define.{BaseModule, Command, Discover, Module, NamedTask, Reflect, Segments, Target}
import mill.resolve.ResolveCore.{Resolved, makeResultException}
import mill.util.EitherOps

Expand Down Expand Up @@ -45,7 +35,6 @@ object Resolve {
val instantiated = ResolveCore
.instantiateModule(rootModule, r.segments.init)
.flatMap(instantiateTarget(r, _))

instantiated.map(Some(_))

case r: Resolved.Command =>
Expand All @@ -61,35 +50,10 @@ object Resolve {
allowPositionalCommandArgs
)
}

instantiated.map(Some(_))

case r: Resolved.Module =>
ResolveCore.instantiateModule(rootModule, r.segments).flatMap {
case value: TaskModule =>
val directChildrenOrErr = ResolveCore.resolveDirectChildren(
rootModule,
value.getClass,
Some(value.defaultCommandName()),
value.millModuleSegments
)

directChildrenOrErr.flatMap(directChildren =>
directChildren.head match {
case r: Resolved.Target => instantiateTarget(r, value).map(Some(_))
case r: Resolved.Command =>
instantiateCommand(
rootModule,
r,
value,
args,
nullCommandDefaults,
allowPositionalCommandArgs
).map(Some(_))
}
)
case _ => Right(None)
}
ResolveCore.instantiateModule(rootModule, r.segments).map(mod => Some(mod.moduleTask))
}

val sequenced = EitherOps.sequence(taskList).map(_.flatten)
Expand Down
25 changes: 13 additions & 12 deletions main/resolve/test/src/mill/main/ResolveTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -489,9 +489,9 @@ object ResolveTests extends TestSuite {
Right(Set(_.cross("211").cross2("jvm").suffix)),
Set("cross[211].cross2[jvm].suffix")
)
test("pos2NoDefaultTask") - check(
test("pos2Module") - check(
"cross[211].cross2[jvm]",
Left("Cannot find default task to evaluate for module cross[211].cross2[jvm]")
Right(Set(_.cross("211").cross2("jvm").moduleTask))
)
test("wildcard") {
test("first") - check(
Expand Down Expand Up @@ -565,10 +565,9 @@ object ResolveTests extends TestSuite {
Right(Set(_.cross1("210").cross2("js").suffixCmd())),
Set("cross1[210].cross2[js].suffixCmd")
)
test("pos1Default") - check.checkSeq(
test("pos1Module") - check.checkSeq(
Seq("cross1[210].cross2[js]"),
Right(Set(_.cross1("210").cross2("js").suffixCmd())),
Set("cross1[210].cross2[js]")
Right(Set(_.cross1("210").cross2("js").moduleTask))
)
test("pos1WithWildcard") - check.checkSeq(
Seq("cross1[210].cross2[js]._"),
Expand All @@ -585,10 +584,9 @@ object ResolveTests extends TestSuite {
Right(Set(_.cross1("211").cross2("jvm").suffixCmd())),
Set("cross1[211].cross2[jvm].suffixCmd")
)
test("pos2Default") - check.checkSeq(
test("pos2Module") - check.checkSeq(
Seq("cross1[211].cross2[jvm]"),
Right(Set(_.cross1("211").cross2("jvm").suffixCmd())),
Set("cross1[211].cross2[jvm]")
Right(Set(_.cross1("211").cross2("jvm").moduleTask))
)
}
}
Expand All @@ -607,23 +605,26 @@ object ResolveTests extends TestSuite {
test("wrapped") {
test("targets") - check.checkSeq0(
Seq("__.test1"),
_ == Right(List(duplicates.wrapper.test1.test1)),
_ == Right(List(duplicates.wrapper.test1.moduleTask, duplicates.wrapper.test1.test1)),
_ == Right(List("wrapper.test1", "wrapper.test1.test1"))
)
test("commands") - check.checkSeq0(
Seq("__.test2"),
segments(_, Right(List(duplicates.wrapper.test2.test2()))),
segments(
_,
Right(List(duplicates.wrapper.test2.moduleTask, duplicates.wrapper.test2.test2()))
),
_ == Right(List("wrapper.test2", "wrapper.test2.test2"))
)
}
test("targets") - check.checkSeq0(
Seq("__.test3"),
_ == Right(List(duplicates.test3.test3)),
_ == Right(List(duplicates.test3.moduleTask, duplicates.test3.test3)),
_ == Right(List("test3", "test3.test3"))
)
test("commands") - check.checkSeq0(
Seq("__.test4"),
segments(_, Right(List(duplicates.test4.test4()))),
segments(_, Right(List(duplicates.test4.moduleTask, duplicates.test4.test4()))),
_ == Right(List("test4", "test4.test4"))
)
}
Expand Down
64 changes: 58 additions & 6 deletions main/src/mill/main/MainModule.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package mill.main

import java.util.concurrent.LinkedBlockingQueue
import mill.define.{BaseModule0, Command, NamedTask, Segments, Target, Task}
import mill.api.{Ctx, Logger, PathRef, Result}
import mill.define._
import mill.eval.{Evaluator, EvaluatorPaths, Terminal}
import mill.resolve.{Resolve, SelectMode}
import mill.moduledefs.Scaladoc
import mill.resolve.SelectMode.Separated
import mill.util.Watchable
import mill.resolve.{Resolve, SelectMode}
import mill.util.{Util, Watchable}
import pprint.{Renderer, Tree, Truncated}

import java.util.concurrent.LinkedBlockingQueue
import scala.collection.mutable
import scala.reflect.NameTransformer.decode

object MainModule {

Expand Down Expand Up @@ -175,12 +177,12 @@ trait MainModule extends BaseModule0 {
* Displays metadata about the given task without actually running it.
*/
def inspect(evaluator: Evaluator, targets: String*): Command[String] = Target.command {

def resolveParents(c: Class[_]): Seq[Class[_]] = {
Seq(c) ++ Option(c.getSuperclass).toSeq.flatMap(resolveParents) ++ c.getInterfaces.flatMap(
resolveParents
)
}

def pprintTask(t: NamedTask[_], evaluator: Evaluator): Tree.Lazy = {
val seen = mutable.Set.empty[Task[_]]

Expand Down Expand Up @@ -266,10 +268,60 @@ trait MainModule extends BaseModule0 {
}
}

def pprintModule(t: Module.ModuleTask[_]): Tree.Lazy = {
val cls = t.module.getClass
val annotation = cls.getAnnotation(classOf[Scaladoc])
val scaladocOpt = Option.when(annotation != null)(
Util.cleanupScaladoc(annotation.value).map("\n " + _).mkString
)
val fileName = t.ctx.fileName.split('/').last.split('\\').last
val parents = cls.getInterfaces ++ Option(cls.getSuperclass).toSeq
val inheritedModules =
parents.distinct.filter(classOf[Module].isAssignableFrom(_)).map(_.getSimpleName)
val moduleDepsOpt = cls.getMethods.find(m => decode(m.getName) == "moduleDeps").map(
_.invoke(t.module).asInstanceOf[Seq[Module]]
).filter(_.nonEmpty)
val defaultTaskOpt = t.module match {
case taskMod: TaskModule => Some(s"${t.module}.${taskMod.defaultCommandName()}")
case _ => None
}
val tasks = Seq()
pprint.Tree.Lazy { ctx =>
Iterator(
ctx.applyPrefixColor(t.module.toString).toString,
s"($fileName:${t.ctx.lineNum})"
) ++ Iterator(scaladocOpt).flatten ++ Iterator(
"\n\n",
ctx.applyPrefixColor("Inherited Modules").toString,
": ",
inheritedModules.mkString(", ")
) ++ moduleDepsOpt.fold(Iterator.empty[String])(deps =>
Iterator(
"\n\n",
ctx.applyPrefixColor("Module Dependencies").toString,
": ",
deps.mkString(", ")
)
) ++ defaultTaskOpt.fold(Iterator.empty[String])(task =>
Iterator("\n\n", ctx.applyPrefixColor("Default Task").toString, ": ", task)
) ++ (if (tasks.nonEmpty)
Iterator(
"\n\n",
ctx.applyPrefixColor("Tasks").toString,
": ",
tasks.mkString(", ")
)
else Iterator.empty[String])
}
}

MainModule.resolveTasks(evaluator, targets, SelectMode.Multi) { tasks =>
val output = (for {
task <- tasks
tree = pprintTask(task, evaluator)
tree = task match {
case t: Module.ModuleTask[_] => pprintModule(t)
case t => pprintTask(t, evaluator)
}
defaults = pprint.PPrinter()
renderer = new Renderer(
defaults.defaultWidth,
Expand Down

0 comments on commit 2d28b14

Please sign in to comment.