Skip to content

Commit 69243dc

Browse files
Show workers in resolve / show / inspect too (#3580)
This PR generalizes some `Target`-related stuff in `Resolve` to all `NamedTask`s with no arguments (targets and workers), and makes sure `resolve` / `show` / `inspect` work fine with workers. In particular, running `show` on a worker now prints something like ```json { "worker": "foo.theWorker", "toString": "build_.package_$foo$$anon$1@4acbdb44", "inputsHash": -2075822978 } ```
1 parent c38460b commit 69243dc

File tree

6 files changed

+117
-33
lines changed

6 files changed

+117
-33
lines changed

integration/feature/docannotations/resources/build.mill

+15-1
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,27 @@ trait JUnitTests extends TestModule.Junit4 {
1111
def task = Task {
1212
"???"
1313
}
14+
15+
/**
16+
* *The worker*
17+
*/
18+
def theWorker = Task.Worker {
19+
()
20+
}
1421
}
1522

1623
/**
1724
* The Core Module Docz!
1825
*/
1926
object core extends JavaModule {
20-
object test extends JavaTests with JUnitTests
27+
object test extends JavaTests with JUnitTests {
28+
/**
29+
* -> The worker <-
30+
*/
31+
def theWorker = Task.Worker {
32+
()
33+
}
34+
}
2135

2236
/**
2337
* Core Target Docz!

integration/feature/docannotations/src/DocAnnotationsTests.scala

+16
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,22 @@ object DocAnnotationsTests extends UtestIntegrationTestSuite {
113113
)
114114
)
115115

116+
assert(eval(("inspect", "core.test.theWorker")).isSuccess)
117+
val theWorkerInspect = out("inspect").json.str
118+
119+
assert(
120+
globMatches(
121+
"""core.test.theWorker(build.mill:...)
122+
| -> The worker <-
123+
|
124+
| *The worker*
125+
|
126+
|Inputs:
127+
|""".stripMargin,
128+
theWorkerInspect
129+
)
130+
)
131+
116132
// Make sure both kebab-case and camelCase flags work, even though the
117133
// docs from `inspect` only show the kebab-case version
118134
assert(eval(("core.ivyDepsTree", "--withCompile", "--withRuntime")).isSuccess)

main/eval/src/mill/eval/GroupEvaluator.scala

+28-20
Original file line numberDiff line numberDiff line change
@@ -364,28 +364,36 @@ private[mill] trait GroupEvaluator {
364364
inputsHash: Int,
365365
labelled: Terminal.Labelled[_]
366366
): Unit = {
367-
labelled.task.asWorker match {
368-
case Some(w) =>
369-
workerCache.synchronized {
370-
workerCache.update(w.ctx.segments, (workerCacheHash(inputsHash), v))
371-
}
372-
case None =>
373-
val terminalResult = labelled
374-
.task
375-
.writerOpt
376-
.asInstanceOf[Option[upickle.default.Writer[Any]]]
377-
.map { w => upickle.default.writeJs(v.value)(w) }
378-
379-
for (json <- terminalResult) {
380-
os.write.over(
381-
metaPath,
382-
upickle.default.stream(
383-
Evaluator.Cached(json, hashCode, inputsHash),
384-
indent = 4
385-
),
386-
createFolders = true
367+
for (w <- labelled.task.asWorker)
368+
workerCache.synchronized {
369+
workerCache.update(w.ctx.segments, (workerCacheHash(inputsHash), v))
370+
}
371+
372+
val terminalResult = labelled
373+
.task
374+
.writerOpt
375+
.map { w =>
376+
upickle.default.writeJs(v.value)(w.asInstanceOf[upickle.default.Writer[Any]])
377+
}
378+
.orElse {
379+
labelled.task.asWorker.map { w =>
380+
ujson.Obj(
381+
"worker" -> ujson.Str(labelled.segments.render),
382+
"toString" -> ujson.Str(v.value.toString),
383+
"inputsHash" -> ujson.Num(inputsHash)
387384
)
388385
}
386+
}
387+
388+
for (json <- terminalResult) {
389+
os.write.over(
390+
metaPath,
391+
upickle.default.stream(
392+
Evaluator.Cached(json, hashCode, inputsHash),
393+
indent = 4
394+
),
395+
createFolders = true
396+
)
389397
}
390398
}
391399

main/resolve/src/mill/resolve/Resolve.scala

+9-6
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ object Resolve {
4141
allowPositionalCommandArgs: Boolean
4242
) = {
4343
val taskList = resolved.map {
44-
case r: Resolved.Target =>
44+
case r: Resolved.NamedTask =>
4545
val instantiated = ResolveCore
4646
.instantiateModule(rootModule, r.segments.init)
47-
.flatMap(instantiateTarget(r, _))
47+
.flatMap(instantiateNamedTask(r, _))
4848

4949
instantiated.map(Some(_))
5050

@@ -76,7 +76,7 @@ object Resolve {
7676

7777
directChildrenOrErr.flatMap(directChildren =>
7878
directChildren.head match {
79-
case r: Resolved.Target => instantiateTarget(r, value).map(Some(_))
79+
case r: Resolved.NamedTask => instantiateNamedTask(r, value).map(Some(_))
8080
case r: Resolved.Command =>
8181
instantiateCommand(
8282
rootModule,
@@ -104,13 +104,16 @@ object Resolve {
104104
items.distinctBy(_.ctx.segments)
105105
}
106106

107-
private def instantiateTarget(r: Resolved.Target, p: Module): Either[String, Target[_]] = {
107+
private def instantiateNamedTask(
108+
r: Resolved.NamedTask,
109+
p: Module
110+
): Either[String, NamedTask[_]] = {
108111
val definition = Reflect
109-
.reflect(p.getClass, classOf[Target[_]], _ == r.segments.parts.last, true)
112+
.reflect(p.getClass, classOf[NamedTask[_]], _ == r.segments.parts.last, true)
110113
.head
111114

112115
ResolveCore.catchWrapException(
113-
definition.invoke(p).asInstanceOf[Target[_]]
116+
definition.invoke(p).asInstanceOf[NamedTask[_]]
114117
)
115118
}
116119

main/resolve/src/mill/resolve/ResolveCore.scala

+6-6
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ private object ResolveCore {
2929

3030
object Resolved {
3131
case class Module(segments: Segments, cls: Class[_]) extends Resolved
32-
case class Target(segments: Segments) extends Resolved
32+
case class NamedTask(segments: Segments) extends Resolved
3333
case class Command(segments: Segments) extends Resolved
3434
}
3535

@@ -327,7 +327,7 @@ private object ResolveCore {
327327
.map(
328328
_.map {
329329
case (Resolved.Module(s, cls), _) => Resolved.Module(segments ++ s, cls)
330-
case (Resolved.Target(s), _) => Resolved.Target(segments ++ s)
330+
case (Resolved.NamedTask(s), _) => Resolved.NamedTask(segments ++ s)
331331
case (Resolved.Command(s), _) => Resolved.Command(segments ++ s)
332332
}
333333
.toSet
@@ -376,10 +376,10 @@ private object ResolveCore {
376376
}
377377
}
378378

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

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

391-
modulesOrErr.map(_ ++ targets ++ commands)
391+
modulesOrErr.map(_ ++ namedTasks ++ commands)
392392
}
393393

394394
def notFoundResult(

main/test/src/mill/main/MainModuleTests.scala

+43
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ object MainModuleTests extends TestSuite {
2727
Map("1" -> "hello", "2" -> "world")
2828
}
2929
def helloCommand(x: Int, y: Task[String]) = Task.Command { (x, y(), hello()) }
30+
31+
/**
32+
* The hello worker
33+
*/
34+
def helloWorker = Task.Worker {
35+
// non-JSON-serializable, but everything should work fine nonetheless
36+
new AutoCloseable {
37+
def close() = ()
38+
override def toString =
39+
"theHelloWorker"
40+
}
41+
}
3042
override lazy val millDiscover: Discover = Discover[this.type]
3143
}
3244

@@ -93,6 +105,17 @@ object MainModuleTests extends TestSuite {
93105
res.contains("hello")
94106
)
95107
}
108+
test("worker") - UnitTester(mainModule, null).scoped { eval =>
109+
val Right(result) = eval.apply("inspect", "helloWorker")
110+
111+
val Seq(res: String) = result.value
112+
assert(
113+
res.startsWith("helloWorker("),
114+
res.contains("MainModuleTests.scala:"),
115+
res.contains("The hello worker"),
116+
res.contains("hello")
117+
)
118+
}
96119
}
97120

98121
test("show") {
@@ -173,6 +196,14 @@ object MainModuleTests extends TestSuite {
173196
val Seq(res) = result.value
174197
assert(res == ujson.Arr(1337, "lol", ujson.Arr("hello", "world")))
175198
}
199+
200+
test("worker") {
201+
val Right(result) = evaluator.apply("show", "helloWorker")
202+
val Seq(res: ujson.Obj) = result.value
203+
assert(res("toString").str == "theHelloWorker")
204+
assert(res("worker").str == "helloWorker")
205+
assert(res("inputsHash").numOpt.isDefined)
206+
}
176207
}
177208

178209
test("showNamed") {
@@ -209,6 +240,18 @@ object MainModuleTests extends TestSuite {
209240
}
210241
}
211242

243+
test("resolve") {
244+
UnitTester(mainModule, null).scoped { eval =>
245+
val Right(result) = eval.apply("resolve", "_")
246+
247+
val Seq(res: Seq[String]) = result.value
248+
assert(res.contains("hello"))
249+
assert(res.contains("hello2"))
250+
assert(res.contains("helloCommand"))
251+
assert(res.contains("helloWorker"))
252+
}
253+
}
254+
212255
test("clean") {
213256
val ev = UnitTester(cleanModule, null)
214257
val out = ev.evaluator.outPath

0 commit comments

Comments
 (0)