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 24, 2024
1 parent 64ee6f6 commit d4a2ca7
Show file tree
Hide file tree
Showing 8 changed files with 261 additions and 85 deletions.
18 changes: 18 additions & 0 deletions integration/feature/docannotations/resources/build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ trait JUnitTests extends TestModule.Junit4 {
}
}

trait foo

object basic extends Module with foo

/**
* The Core Module Docz!
*/
Expand All @@ -28,3 +32,17 @@ object core extends JavaModule {
"Hello!"
}
}

object core2 extends JavaModule

object MyJavaTaskModule extends JavaModule {
override def moduleDeps: Seq[JavaModule] = Seq(core, core2)
def lineCount = T {
allSourceFiles().map(f => os.read.lines(f.path).size).sum
}
def target = Task {
import collection.JavaConverters._
println(this.getClass.getClassLoader.getResources("scalac-plugin.xml").asScala.toList)
"Hello!"
}
}
48 changes: 47 additions & 1 deletion integration/feature/docannotations/src/DocAnnotationsTests.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package mill.integration

import mill.testkit.UtestIntegrationTestSuite

import utest._

object DocAnnotationsTests extends UtestIntegrationTestSuite {
Expand Down Expand Up @@ -117,6 +116,53 @@ object DocAnnotationsTests extends UtestIntegrationTestSuite {
// docs from `inspect` only show the kebab-case version
assert(eval(("core.ivyDepsTree", "--withCompile", "--withRuntime")).isSuccess)
assert(eval(("core.ivyDepsTree", "--with-compile", "--with-runtime")).isSuccess)

assert(eval(("inspect", "basic")).isSuccess)
val basicInspect = out("inspect").json.str
assert(
globMatches(
"""basic(build.mill:...)
|
|Inherited Modules: Module
|""",
basicInspect
)
)

assert(eval(("inspect", "core")).isSuccess)
val coreInspect = out("inspect").json.str
assert(
globMatches(
"""core(build.mill:...)
| The Core Module Docz!
|
|Inherited Modules: JavaModule
|
|Default Task: core.run
|
|Tasks: core.target
|""",
coreInspect
)
)

assert(eval(("inspect", "MyJavaTaskModule")).isSuccess)
val jtmInspect = out("inspect").json.str
assert(
globMatches(
"""MyJavaTaskModule(build.mill:...)
|
|Inherited Modules: JavaModule
|
|Module Dependencies: core, core2
|
|Default Task: MyJavaTaskModule.run
|
|Tasks: MyJavaTaskModule.lineCount, MyJavaTaskModule.target
|""",
jtmInspect
)
)
}
}
}
28 changes: 18 additions & 10 deletions main/define/src/mill/define/Discover.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package mill.define

import language.experimental.macros
import scala.collection.mutable
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

/**
Expand All @@ -19,34 +19,35 @@ import scala.reflect.macros.blackbox
case class Discover private (
value: Map[
Class[_],
(Seq[String], Seq[mainargs.MainData[_, _]])
(Seq[String], Seq[mainargs.MainData[_, _]], Seq[String])
],
dummy: Int = 0 /* avoid conflict with Discover.apply(value: Map) below*/
) {
@deprecated("Binary compatibility shim", "Mill 0.11.4")
private[define] def this(value: Map[Class[_], Seq[mainargs.MainData[_, _]]]) =
this(value.view.mapValues((Nil, _)).toMap)
this(value.view.mapValues((Nil, _, Nil)).toMap)
// Explicit copy, as we also need to provide an override for bin-compat reasons
def copy[T](
value: Map[
Class[_],
(Seq[String], Seq[mainargs.MainData[_, _]])
(Seq[String], Seq[mainargs.MainData[_, _]], Seq[String])
] = value,
dummy: Int = dummy /* avoid conflict with Discover.apply(value: Map) below*/
): Discover = new Discover(value, dummy)
@deprecated("Binary compatibility shim", "Mill 0.11.4")
private[define] def copy(value: Map[Class[_], Seq[mainargs.MainData[_, _]]]): Discover = {
new Discover(value.view.mapValues((Nil, _)).toMap, dummy)
new Discover(value.view.mapValues((Nil, _, Nil)).toMap, dummy)
}
}

object Discover {
def apply2[T](value: Map[Class[_], (Seq[String], Seq[mainargs.MainData[_, _]])]): Discover =
def apply2[T](value: Map[Class[_], (Seq[String], Seq[mainargs.MainData[_, _]], Seq[String])])
: Discover =
new Discover(value)

@deprecated("Binary compatibility shim", "Mill 0.11.4")
def apply[T](value: Map[Class[_], Seq[mainargs.MainData[_, _]]]): Discover =
new Discover(value.view.mapValues((Nil, _)).toMap)
new Discover(value.view.mapValues((Nil, _, Nil)).toMap)

def apply[T]: Discover = macro Router.applyImpl[T]

Expand Down Expand Up @@ -106,14 +107,17 @@ object Discover {
discoveredModuleType <- seen.toSeq.sortBy(_.typeSymbol.fullName)
curCls = discoveredModuleType
methods = getValsOrMeths(curCls)
declMethods = curCls.decls.toList.collect {
case m: MethodSymbol if !m.isSynthetic && m.isPublic => m
}
overridesRoutes = {
assertParamListCounts(
methods,
(weakTypeOf[mill.define.Command[_]], 1, "`Task.Command`"),
(weakTypeOf[mill.define.Target[_]], 0, "Target")
)

Tuple2(
Tuple3(
for {
m <- methods.toList.sortBy(_.fullName)
if m.returnType <:< weakTypeOf[mill.define.NamedTask[_]]
Expand All @@ -128,10 +132,14 @@ object Discover {
m.annotations.find(_.tree.tpe =:= typeOf[mainargs.main]),
curCls,
weakTypeOf[Any]
)
),
for {
m <- declMethods.sortBy(_.fullName)
if m.returnType <:< weakTypeOf[mill.define.Task[_]]
} yield m.name.decodedName.toString
)
}
if overridesRoutes._1.nonEmpty || overridesRoutes._2.nonEmpty
if overridesRoutes._1.nonEmpty || overridesRoutes._2.nonEmpty || overridesRoutes._3.nonEmpty
} yield {
// by wrapping the `overridesRoutes` in a lambda function we kind of work around
// the problem of generating a *huge* macro method body that finally exceeds the
Expand Down
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
}
}
10 changes: 3 additions & 7 deletions main/eval/test/src/mill/eval/ModuleTests.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package mill.eval

import mill.testkit.UnitTester
import mill.testkit.UnitTester.Result
import mill.testkit.TestBaseModule
import mill.{T, Task}
import mill.Task
import mill.define.Discover

import mill.testkit.UnitTester.Result
import mill.testkit.{TestBaseModule, UnitTester}
import utest._

object TestExternalModule extends mill.define.ExternalModule with mill.define.TaskModule {
Expand All @@ -25,8 +23,6 @@ object ModuleTests extends TestSuite {
val check = UnitTester(Build, null)
val result = check.apply("mill.eval.TestExternalModule/x")
assert(result == Right(Result(Vector(13), 0)))
val result2 = check.apply("mill.eval.TestExternalModule/")
assert(result2 == Right(Result(Vector(13), 0)))
}
test("externalModuleTargetsAreNamespacedByModulePackagePath") {
val check = UnitTester(Build, null)
Expand Down
42 changes: 4 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,34 +50,11 @@ 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)
}
}

Expand Down Expand Up @@ -144,7 +110,7 @@ object Resolve {
nullCommandDefaults: Boolean,
allowPositionalCommandArgs: Boolean
): Iterable[Either[String, Command[_]]] = for {
(cls, (names, entryPoints)) <- discover.value
(cls, (names, entryPoints, _)) <- discover.value
if cls.isAssignableFrom(target.getClass)
ep <- entryPoints
if ep.name == name
Expand Down
Loading

0 comments on commit d4a2ca7

Please sign in to comment.