Skip to content

Commit

Permalink
Show workers in resolve / show / inspect too
Browse files Browse the repository at this point in the history
  • Loading branch information
alexarchambault committed Sep 25, 2024
1 parent 3e6a101 commit cfcd3a2
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 14 deletions.
16 changes: 15 additions & 1 deletion integration/feature/docannotations/resources/build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,27 @@ trait JUnitTests extends TestModule.Junit4 {
def task = Task {
"???"
}

/**
* *The worker*
*/
def theWorker = Task.Worker {
()
}
}

/**
* The Core Module Docz!
*/
object core extends JavaModule {
object test extends JavaTests with JUnitTests
object test extends JavaTests with JUnitTests {
/**
* -> The worker <-
*/
def theWorker = Task.Worker {
()
}
}

/**
* Core Target Docz!
Expand Down
16 changes: 16 additions & 0 deletions integration/feature/docannotations/src/DocAnnotationsTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,22 @@ object DocAnnotationsTests extends UtestIntegrationTestSuite {
)
)

assert(eval(("inspect", "core.test.theWorker")).isSuccess)
val theWorkerInspect = out("inspect").json.str

assert(
globMatches(
"""core.test.theWorker(build.mill:...)
| -> The worker <-
|
| *The worker*
|
|Inputs:
|""".stripMargin,
theWorkerInspect
)
)

// Make sure both kebab-case and camelCase flags work, even though the
// docs from `inspect` only show the kebab-case version
assert(eval(("core.ivyDepsTree", "--withCompile", "--withRuntime")).isSuccess)
Expand Down
9 changes: 9 additions & 0 deletions main/eval/src/mill/eval/GroupEvaluator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,15 @@ private[mill] trait GroupEvaluator {
.map { w =>
upickle.default.writeJs(v.value)(w.asInstanceOf[upickle.default.Writer[Any]])
}
.orElse {
labelled.task.asWorker.map { w =>
ujson.Obj(
"worker" -> ujson.Str(labelled.segments.render),
"toString" -> ujson.Str(v.value.toString),
"inputsHash" -> ujson.Num(inputsHash)
)
}
}

for (json <- terminalResult) {
os.write.over(
Expand Down
15 changes: 9 additions & 6 deletions main/resolve/src/mill/resolve/Resolve.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ object Resolve {
allowPositionalCommandArgs: Boolean
) = {
val taskList = resolved.map {
case r: Resolved.Target =>
case r: Resolved.NamedTask =>
val instantiated = ResolveCore
.instantiateModule(rootModule, r.segments.init)
.flatMap(instantiateTarget(r, _))
.flatMap(instantiateNamedTask(r, _))

instantiated.map(Some(_))

Expand Down Expand Up @@ -76,7 +76,7 @@ object Resolve {

directChildrenOrErr.flatMap(directChildren =>
directChildren.head match {
case r: Resolved.Target => instantiateTarget(r, value).map(Some(_))
case r: Resolved.NamedTask => instantiateNamedTask(r, value).map(Some(_))
case r: Resolved.Command =>
instantiateCommand(
rootModule,
Expand Down Expand Up @@ -104,13 +104,16 @@ object Resolve {
items.distinctBy(_.ctx.segments)
}

private def instantiateTarget(r: Resolved.Target, p: Module): Either[String, Target[_]] = {
private def instantiateNamedTask(
r: Resolved.NamedTask,
p: Module
): Either[String, NamedTask[_]] = {
val definition = Reflect
.reflect(p.getClass, classOf[Target[_]], _ == r.segments.parts.last, true)
.reflect(p.getClass, classOf[NamedTask[_]], _ == r.segments.parts.last, true)
.head

ResolveCore.catchWrapException(
definition.invoke(p).asInstanceOf[Target[_]]
definition.invoke(p).asInstanceOf[NamedTask[_]]
)
}

Expand Down
12 changes: 6 additions & 6 deletions main/resolve/src/mill/resolve/ResolveCore.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ private object ResolveCore {

object Resolved {
case class Module(segments: Segments, cls: Class[_]) extends Resolved
case class Target(segments: Segments) extends Resolved
case class NamedTask(segments: Segments) extends Resolved
case class Command(segments: Segments) extends Resolved
}

Expand Down Expand Up @@ -327,7 +327,7 @@ private object ResolveCore {
.map(
_.map {
case (Resolved.Module(s, cls), _) => Resolved.Module(segments ++ s, cls)
case (Resolved.Target(s), _) => Resolved.Target(segments ++ s)
case (Resolved.NamedTask(s), _) => Resolved.NamedTask(segments ++ s)
case (Resolved.Command(s), _) => Resolved.Command(segments ++ s)
}
.toSet
Expand Down Expand Up @@ -376,10 +376,10 @@ private object ResolveCore {
}
}

val targets = Reflect
.reflect(cls, classOf[Target[_]], namePred, noParams = true)
val namedTasks = Reflect
.reflect(cls, classOf[NamedTask[_]], namePred, noParams = true)
.map { m =>
Resolved.Target(Segments.labels(decode(m.getName))) ->
Resolved.NamedTask(Segments.labels(decode(m.getName))) ->
None
}

Expand All @@ -388,7 +388,7 @@ private object ResolveCore {
.map(m => decode(m.getName))
.map { name => Resolved.Command(Segments.labels(name)) -> None }

modulesOrErr.map(_ ++ targets ++ commands)
modulesOrErr.map(_ ++ namedTasks ++ commands)
}

def notFoundResult(
Expand Down
2 changes: 1 addition & 1 deletion main/src/mill/main/RunScript.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ object RunScript {
case 0 =>
val nameAndJson = for (t <- targets.toSeq) yield {
t match {
case t: mill.define.NamedTask[_] =>
case t: mill.define.NamedTask[_] if t.writerOpt.isDefined || t.asWorker.isDefined =>
val jsonFile = EvaluatorPaths.resolveDestPaths(evaluator.outPath, t).meta
val metadata = upickle.default.read[Evaluator.Cached](ujson.read(jsonFile.toIO))
Some((t.toString, metadata.value))
Expand Down
43 changes: 43 additions & 0 deletions main/test/src/mill/main/MainModuleTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ object MainModuleTests extends TestSuite {
Map("1" -> "hello", "2" -> "world")
}
def helloCommand(x: Int, y: Task[String]) = Task.Command { (x, y(), hello()) }

/**
* The hello worker
*/
def helloWorker = Task.Worker {
// non-JSON-serializable, but everything should work fine nonetheless
new AutoCloseable {
def close() = ()
override def toString =
"theHelloWorker"
}
}
override lazy val millDiscover: Discover = Discover[this.type]
}

Expand Down Expand Up @@ -93,6 +105,17 @@ object MainModuleTests extends TestSuite {
res.contains("hello")
)
}
test("worker") - UnitTester(mainModule, null).scoped { eval =>
val Right(result) = eval.apply("inspect", "helloWorker")

val Seq(res: String) = result.value
assert(
res.startsWith("helloWorker("),
res.contains("MainModuleTests.scala:"),
res.contains("The hello worker"),
res.contains("hello")
)
}
}

test("show") {
Expand Down Expand Up @@ -173,6 +196,14 @@ object MainModuleTests extends TestSuite {
val Seq(res) = result.value
assert(res == ujson.Arr(1337, "lol", ujson.Arr("hello", "world")))
}

test("worker") {
val Right(result) = evaluator.apply("show", "helloWorker")
val Seq(res: ujson.Obj) = result.value
assert(res("toString").str == "theHelloWorker")
assert(res("worker").str == "helloWorker")
assert(res("inputsHash").numOpt.isDefined)
}
}

test("showNamed") {
Expand Down Expand Up @@ -209,6 +240,18 @@ object MainModuleTests extends TestSuite {
}
}

test("resolve") {
UnitTester(mainModule, null).scoped { eval =>
val Right(result) = eval.apply("resolve", "_")

val Seq(res: Seq[String]) = result.value
assert(res.contains("hello"))
assert(res.contains("hello2"))
assert(res.contains("helloCommand"))
assert(res.contains("helloWorker"))
}
}

test("clean") {
val ev = UnitTester(cleanModule, null)
val out = ev.evaluator.outPath
Expand Down

0 comments on commit cfcd3a2

Please sign in to comment.