Skip to content

Commit

Permalink
Issue #2929: implement inspect for modules (#3532)
Browse files Browse the repository at this point in the history
Implement inspect for modules:
- Name of module with file/line info
- Scaladoc on module
- Inherited modules
- Module dependencies
- Default task
- Implemented tasks
  • Loading branch information
Shri333 authored Sep 28, 2024
1 parent 0e50ff7 commit 9ea6d67
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 51 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 @@ -20,6 +20,10 @@ trait JUnitTests extends TestModule.Junit4 {
}
}

trait foo

object basic extends Module with foo

/**
* The Core Module Docz!
*/
Expand All @@ -42,3 +46,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 @@ -133,6 +132,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
6 changes: 6 additions & 0 deletions main/define/src/mill/define/Module.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,9 @@ object Module {
}
}
}

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
}
37 changes: 23 additions & 14 deletions main/resolve/src/mill/resolve/Resolve.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import mill.define.{
Command,
Discover,
Module,
ModuleTask,
NamedTask,
Reflect,
Segments,
Expand All @@ -23,7 +24,8 @@ object Resolve {
args: Seq[String],
selector: Segments,
nullCommandDefaults: Boolean,
allowPositionalCommandArgs: Boolean
allowPositionalCommandArgs: Boolean,
resolveToModuleTasks: Boolean
) = {
Right(resolved.map(_.segments))
}
Expand All @@ -38,14 +40,14 @@ object Resolve {
args: Seq[String],
selector: Segments,
nullCommandDefaults: Boolean,
allowPositionalCommandArgs: Boolean
allowPositionalCommandArgs: Boolean,
resolveToModuleTasks: Boolean
) = {
val taskList = resolved.map {
case r: Resolved.NamedTask =>
val instantiated = ResolveCore
.instantiateModule(rootModule, r.segments.init)
.flatMap(instantiateNamedTask(r, _))

instantiated.map(Some(_))

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

instantiated.map(Some(_))

case r: Resolved.Module =>
ResolveCore.instantiateModule(rootModule, r.segments).flatMap {
case value: TaskModule =>
case value if resolveToModuleTasks => Right(Some(ModuleTask(value)))
case value: TaskModule if !resolveToModuleTasks =>
val directChildrenOrErr = ResolveCore.resolveDirectChildren(
rootModule,
value.getClass,
Expand Down Expand Up @@ -147,7 +149,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 Expand Up @@ -211,30 +213,34 @@ trait Resolve[T] {
args: Seq[String],
segments: Segments,
nullCommandDefaults: Boolean,
allowPositionalCommandArgs: Boolean
allowPositionalCommandArgs: Boolean,
resolveToModuleTasks: Boolean
): Either[String, Seq[T]]

def resolve(
rootModule: BaseModule,
scriptArgs: Seq[String],
selectMode: SelectMode,
allowPositionalCommandArgs: Boolean = false
allowPositionalCommandArgs: Boolean = false,
resolveToModuleTasks: Boolean = false
): Either[String, List[T]] = {
resolve0(rootModule, scriptArgs, selectMode, allowPositionalCommandArgs)
resolve0(rootModule, scriptArgs, selectMode, allowPositionalCommandArgs, resolveToModuleTasks)
}

def resolve(
rootModule: BaseModule,
scriptArgs: Seq[String],
selectMode: SelectMode
): Either[String, List[T]] = {
resolve0(rootModule, scriptArgs, selectMode, false)
resolve0(rootModule, scriptArgs, selectMode, false, false)
}

private[mill] def resolve0(
rootModule: BaseModule,
scriptArgs: Seq[String],
selectMode: SelectMode,
allowPositionalCommandArgs: Boolean
allowPositionalCommandArgs: Boolean,
resolveToModuleTasks: Boolean
): Either[String, List[T]] = {
val nullCommandDefaults = selectMode == SelectMode.Multi
val resolvedGroups = ParseArgs(scriptArgs, selectMode).flatMap { groups =>
Expand All @@ -246,7 +252,8 @@ trait Resolve[T] {
rootModuleSels,
sel.getOrElse(Segments()),
nullCommandDefaults,
allowPositionalCommandArgs
allowPositionalCommandArgs,
resolveToModuleTasks
)
}
}
Expand All @@ -268,7 +275,8 @@ trait Resolve[T] {
rootModule: BaseModule,
sel: Segments,
nullCommandDefaults: Boolean,
allowPositionalCommandArgs: Boolean
allowPositionalCommandArgs: Boolean,
resolveToModuleTasks: Boolean
): Either[String, Seq[T]] = {
val rootResolved = ResolveCore.Resolved.Module(Segments(), rootModule.getClass)
val resolved =
Expand Down Expand Up @@ -300,7 +308,8 @@ trait Resolve[T] {
args,
sel,
nullCommandDefaults,
allowPositionalCommandArgs
allowPositionalCommandArgs,
resolveToModuleTasks
))
}

Expand Down
2 changes: 2 additions & 0 deletions main/resolve/test/src/mill/main/ResolveTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ object ResolveTests extends TestSuite {
module,
selectorStrings,
SelectMode.Separated,
false,
false
)
}
Expand All @@ -62,6 +63,7 @@ object ResolveTests extends TestSuite {
module,
selectorStrings,
SelectMode.Separated,
false,
false
).map(_.map(_.render))
}
Expand Down
Loading

0 comments on commit 9ea6d67

Please sign in to comment.