Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More refactoring for Resolve logic #2511

Merged
merged 20 commits into from
May 8, 2023
5 changes: 4 additions & 1 deletion build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ trait MillModule extends MillApiModule with MillAutoTestSetup with WithMillCompi

object main extends MillModule {

override def moduleDeps = Seq(eval, client)
override def moduleDeps = Seq(eval, resolve, client)
override def ivyDeps = Agg(
Deps.windowsAnsi,
Deps.mainargs,
Expand Down Expand Up @@ -727,6 +727,9 @@ object main extends MillModule {
object eval extends MillModule {
override def moduleDeps = Seq(define)
}
object resolve extends MillModule {
override def moduleDeps = Seq(define)
}

object client extends MillPublishModule with BuildInfo {
def buildInfoPackageName = "mill.main.client"
Expand Down
30 changes: 15 additions & 15 deletions ci/mill-bootstrap.patch
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
diff --git a/build.sc b/build.sc
index 1eeefd4f6..293b15164 100644
index 5d071823cd..be020eb125 100644
--- a/build.sc
+++ b/build.sc
@@ -19,17 +19,18 @@ import com.github.lolgab.mill.mima.{
Expand All @@ -14,7 +14,7 @@ index 1eeefd4f6..293b15164 100644
import mill.modules.Jvm
-import mill.define.SelectMode
-
+import mill.main.SelectMode
+import mill.resolve.SelectMode
+import $ivy.`com.lihaoyi::mill-contrib-buildinfo:`
+import mill.contrib.buildinfo.BuildInfo
+import mill.scalalib.api.Versions
Expand Down Expand Up @@ -325,7 +325,7 @@ index 1eeefd4f6..293b15164 100644
}

/** A Module compiled with applied Mill-specific compiler plugins: mill-moduledefs. */
@@ -852,7 +616,9 @@ object scalajslib extends MillModule with BuildInfo {
@@ -855,7 +619,9 @@ object scalajslib extends MillModule with BuildInfo {
override def ivyDeps = Agg(Deps.sbtTestInterface)
}
object worker extends Cross[WorkerModule]("1")
Expand All @@ -336,7 +336,7 @@ index 1eeefd4f6..293b15164 100644
def testDepPaths = T { Seq(compile().classes) }
override def moduleDeps = Seq(scalajslib.`worker-api`, main.client, main.api)
override def ivyDeps = Agg(
@@ -916,8 +682,10 @@ object contrib extends MillModule {
@@ -919,8 +685,10 @@ object contrib extends MillModule {

object api extends MillPublishModule

Expand All @@ -349,7 +349,7 @@ index 1eeefd4f6..293b15164 100644
override def sources = T.sources {
// We want to avoid duplicating code as long as the Play APIs allow.
// But if newer Play versions introduce incompatibilities,
@@ -1080,8 +848,10 @@ object scalanativelib extends MillModule {
@@ -1083,8 +851,10 @@ object scalanativelib extends MillModule {
override def ivyDeps = Agg(Deps.sbtTestInterface)
}
object worker extends Cross[WorkerModule]("0.4")
Expand All @@ -362,7 +362,7 @@ index 1eeefd4f6..293b15164 100644
def testDepPaths = T { Seq(compile().classes) }
override def moduleDeps = Seq(scalanativelib.`worker-api`)
override def ivyDeps = scalaNativeWorkerVersion match {
@@ -1200,7 +970,10 @@ trait IntegrationTestModule extends MillScalaModule {
@@ -1203,7 +973,10 @@ trait IntegrationTestModule extends MillScalaModule {
}
}

Expand All @@ -374,7 +374,7 @@ index 1eeefd4f6..293b15164 100644
object local extends ModeModule
object fork extends ModeModule
object server extends ModeModule
@@ -1214,15 +987,15 @@ object example extends MillScalaModule {
@@ -1217,15 +990,15 @@ object example extends MillScalaModule {

def moduleDeps = Seq(integration)

Expand All @@ -398,7 +398,7 @@ index 1eeefd4f6..293b15164 100644
def sources = T.sources()
def testRepoRoot: T[PathRef] = T.source(millSourcePath)
def compile = example.compile()
@@ -1272,7 +1045,7 @@ object example extends MillScalaModule {
@@ -1275,7 +1048,7 @@ object example extends MillScalaModule {
val title =
if (seenCode) ""
else {
Expand All @@ -407,7 +407,7 @@ index 1eeefd4f6..293b15164 100644
val exampleDashed = examplePath.segments.mkString("-")
val download = s"{mill-download-url}/$label-$exampleDashed.zip[download]"
val browse = s"{mill-example-url}/$examplePath[browse]"
@@ -1303,9 +1076,9 @@ object example extends MillScalaModule {
@@ -1306,9 +1079,9 @@ object example extends MillScalaModule {
}

object integration extends MillScalaModule {
Expand All @@ -420,7 +420,7 @@ index 1eeefd4f6..293b15164 100644

def moduleDeps = Seq(scalalib, scalajslib, scalanativelib, runner.test)

@@ -1633,8 +1406,8 @@ object dev extends MillModule {
@@ -1636,8 +1409,8 @@ object dev extends MillModule {
mill.modules.Jvm.createJar(Agg(), mill.modules.Jvm.JarManifest(manifestEntries))
}

Expand All @@ -431,7 +431,7 @@ index 1eeefd4f6..293b15164 100644
case Nil => mill.api.Result.Failure("Need to pass in cwd as first argument to dev.run")
case wd0 +: rest =>
val wd = os.Path(wd0, T.workspace)
@@ -1661,67 +1434,11 @@ object docs extends Module {
@@ -1664,67 +1437,11 @@ object docs extends Module {
def moduleDeps = build.millInternal.modules.collect { case m: MillApiModule => m }

def unidocSourceUrl = T {
Expand Down Expand Up @@ -500,7 +500,7 @@ index 1eeefd4f6..293b15164 100644
private val npmExe = if (scala.util.Properties.isWin) "npm.cmd" else "npm"
private val antoraExe = if (scala.util.Properties.isWin) "antora.cmd" else "antora"
def npmBase: T[os.Path] = T.persistent { T.dest }
@@ -1774,7 +1491,7 @@ object docs extends Module {
@@ -1777,7 +1494,7 @@ object docs extends Module {

val contribReadmes = T.traverse(contrib.contribModules)(m =>
T.task {
Expand All @@ -509,7 +509,7 @@ index 1eeefd4f6..293b15164 100644
}
)()

@@ -2006,7 +1723,7 @@ def exampleZips: Target[Seq[PathRef]] = T {
@@ -2009,7 +1726,7 @@ def exampleZips: Target[Seq[PathRef]] = T {
examplePath = exampleMod.millSourcePath
} yield {
val example = examplePath.subRelativeTo(T.workspace)
Expand All @@ -518,7 +518,7 @@ index 1eeefd4f6..293b15164 100644
os.copy(examplePath, T.dest / exampleStr, createFolders = true)
os.copy(bootstrapLauncher().path, T.dest / exampleStr / "mill")
val zip = T.dest / s"$exampleStr.zip"
@@ -2016,51 +1733,10 @@ def exampleZips: Target[Seq[PathRef]] = T {
@@ -2019,51 +1736,10 @@ def exampleZips: Target[Seq[PathRef]] = T {
}

def uploadToGithub(authKey: String) = T.command {
Expand Down Expand Up @@ -571,7 +571,7 @@ index 1eeefd4f6..293b15164 100644
ev.withFailFast(false),
Seq(
"__.compile",
@@ -2073,7 +1749,8 @@ def validate(ev: Evaluator): Command[Unit] = T.command {
@@ -2076,7 +1752,8 @@ def validate(ev: Evaluator): Command[Unit] = T.command {
"docs.localPages"
),
selectMode = SelectMode.Separated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package mill.contrib.scoverage
import mill.contrib.scoverage.api.ScoverageReportWorkerApi.ReportType
import mill.define.{Command, Module, Task}
import mill.eval.Evaluator
import mill.main.{ResolveTasks, RunScript, SelectMode}
import mill.resolve.{Resolve, SelectMode}
import mill.main.RunScript
import mill.{PathRef, T}
import os.Path

Expand Down Expand Up @@ -80,16 +81,16 @@ trait ScoverageReport extends Module {
sources: String,
dataTargets: String
): Task[PathRef] = {
val sourcesTasks: Seq[Task[Seq[PathRef]]] = ResolveTasks.resolve(
evaluator,
val sourcesTasks: Seq[Task[Seq[PathRef]]] = Resolve.Tasks.resolve(
evaluator.rootModule,
Seq(sources),
SelectMode.Separated
) match {
case Left(err) => throw new Exception(err)
case Right(tasks) => tasks.asInstanceOf[Seq[Task[Seq[PathRef]]]]
}
val dataTasks: Seq[Task[PathRef]] = ResolveTasks.resolve(
evaluator,
val dataTasks: Seq[Task[PathRef]] = Resolve.Tasks.resolve(
evaluator.rootModule,
Seq(dataTargets),
SelectMode.Separated
) match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,40 @@ object ModuleInitErrorTests extends IntegrationTestSuite {
val tests = Tests {
initWorkspace()

test("resolve") {
// Ensure that resolve works even of the modules containing the resolved
// tasks are broken
val res1 = evalStdout("resolve", "foo.fooTarget")
assert(res1.isSuccess == true)
assert(res1.out.contains("foo.fooTarget"))

val res2 = evalStdout("resolve", "_._")
assert(res2.isSuccess == true)
assert(
res2.out.contains("bar.barCommand"),
res2.out.contains("bar.barTarget"),
res2.out.contains("bar.qux"),
res2.out.contains("foo.fooTarget"),
res2.out.contains("foo.fooCommand")
)

val res3 = evalStdout("resolve", "__.fooTarget")
assert(res3.isSuccess == true)
assert(res3.out.contains("foo.fooTarget"))

val res4 = evalStdout("resolve", "__")
assert(res4.isSuccess == true)
assert(res4.out.contains("bar"))
assert(res4.out.contains("bar.barCommand"))
assert(res4.out.contains("bar.barTarget"))
assert(res4.out.contains("bar.qux"))
assert(res4.out.contains("bar.qux.quxCommand"))
assert(res4.out.contains("bar.qux.quxTarget"))
assert(res4.out.contains("foo"))
assert(res4.out.contains("foo.fooCommand"))
assert(res4.out.contains("foo.fooTarget"))
}

test("rootTarget") {
// If we specify a target in the root module, we are not
// affected by the sub-modules failing to initialize
Expand Down
4 changes: 2 additions & 2 deletions integration/src/mill/integration/IntegrationTestSuite.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package mill.integration

import mill.main.SelectMode
import mill.resolve.SelectMode
import mill.runner.RunnerState
import os.{Path, Shellable}
import utest._
Expand Down Expand Up @@ -84,7 +84,7 @@ abstract class IntegrationTestSuite extends TestSuite {

def meta(s: String): String = {
val Seq((List(selector), _)) =
mill.main.ParseArgs.apply(Seq(s), SelectMode.Separated).getOrElse(???)
mill.resolve.ParseArgs.apply(Seq(s), SelectMode.Separated).getOrElse(???)

val segments = selector._2.value.flatMap(_.pathSegments)
os.read(wd / "out" / segments.init / s"${segments.last}.json")
Expand Down
5 changes: 5 additions & 0 deletions main/api/src/mill/api/Lazy.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package mill.api

class Lazy[T](t: () => T) {
lazy val value = t()
}
70 changes: 41 additions & 29 deletions main/define/src/mill/define/Cross.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package mill.define

import mill.api.Lazy

import language.experimental.macros
import scala.collection.SeqView
import scala.reflect.ClassTag
import scala.reflect.macros.blackbox

object Cross {
Expand Down Expand Up @@ -117,11 +120,11 @@ object Cross {
)
}

case class Factory[T](
makeList: Seq[mill.define.Ctx => T],
crossValuesListLists: Seq[Seq[Any]],
crossSegmentsList: Seq[Seq[String]],
crossValuesRaw: Seq[Any]
class Factory[T: ClassTag](
val makeList: Seq[(Class[_], mill.define.Ctx => T)],
val crossValuesListLists: Seq[Seq[Any]],
val crossSegmentsList: Seq[Seq[String]],
val crossValuesRaw: Seq[Any]
)

object Factory {
Expand All @@ -145,7 +148,7 @@ object Cross {
val wrappedT = if (t.tree.tpe <:< typeOf[Seq[_]]) t.tree else q"_root_.scala.Seq($t)"
val v1 = c.freshName(TermName("v1"))
val ctx0 = c.freshName(TermName("ctx0"))
val implicitCtx = c.freshName(TermName("implicitCtx"))
val concreteCls = c.freshName(TypeName(tpe.typeSymbol.name.toString))

val newTrees = collection.mutable.Buffer.empty[Tree]
var valuesTree: Tree = null
Expand Down Expand Up @@ -188,14 +191,17 @@ object Cross {
q"$segments($v1._1) ++ $segments($v1._2) ++ $segments($v1._3) ++ $segments($v1._4) ++ $segments($v1._5)"
}

// We need to create a `class $concreteCls` here, rather than just
// creating an anonymous sub-type of $tpe, because our task resolution
// logic needs to use java reflection to identify sub-modules and java
// reflect can only properly identify nested `object`s inside Scala
// `object` and `class`es.
val tree = q"""
mill.define.Cross.Factory[$tpe](
makeList = $wrappedT.map(($v1: ${tq""}) =>
($ctx0: ${tq""}) => {
implicit val $implicitCtx = $ctx0
new $tpe{..$newTrees}
}
),
new mill.define.Cross.Factory[$tpe](
makeList = $wrappedT.map{($v1: ${tq""}) =>
class $concreteCls()(implicit ctx: mill.define.Ctx) extends $tpe{..$newTrees}
(classOf[$concreteCls], ($ctx0: ${tq""}) => new $concreteCls()($ctx0))
},
crossSegmentsList = $wrappedT.map(($v1: ${tq""}) => $pathSegmentsTree ),
crossValuesListLists = $valuesTree,
crossValuesRaw = $wrappedT
Expand Down Expand Up @@ -269,33 +275,39 @@ object Cross {
* }
* }}}
*/
class Cross[M <: Cross.Module[_]](factories: Cross.Factory[M]*)(implicit ctx: mill.define.Ctx)
extends mill.define.Module()(ctx) {

// We lazily initialize the instances of `Cross.Module` only when they are
// requested, to avoid unexpected failures in one module initialization
// causing problems using others.
private class Lazy[T](t: () => T) {
lazy val value = t()
class Cross[M <: Cross.Module[_]](factories: Cross.Factory[M]*)(implicit
ctx: mill.define.Ctx
) extends mill.define.Module()(ctx) {

trait Item {
def crossValues: List[Any]
def crossSegments: List[String]
def module: Lazy[M]
def cls: Class[_]
}

private val items: List[(List[Any], List[String], Lazy[M])] = for {
val items: List[Item] = for {
factory <- factories.toList
(crossSegments, (crossValues, make)) <-
(crossSegments0, (crossValues0, (cls0, make))) <-
factory.crossSegmentsList.zip(factory.crossValuesListLists.zip(factory.makeList))
} yield {
val relPath = ctx.segment.pathSegments
val sub = new Lazy(() =>
val module0 = new Lazy(() =>
make(
ctx
.withSegments(ctx.segments ++ Seq(ctx.segment))
.withMillSourcePath(ctx.millSourcePath / relPath)
.withSegment(Segment.Cross(crossSegments))
.withSegment(Segment.Cross(crossSegments0))
.withCrossValues(factories.flatMap(_.crossValuesRaw))
)
)

(crossValues.toList, crossSegments.toList, sub)
new Item {
def crossValues = crossValues0.toList
def crossSegments = crossSegments0.toList
def module = module0
def cls = cls0
}
}

override lazy val millModuleDirectChildren: Seq[Module] =
Expand All @@ -305,14 +317,14 @@ class Cross[M <: Cross.Module[_]](factories: Cross.Factory[M]*)(implicit ctx: mi
* A list of the cross modules, in
* the order the original cross values were given in
*/
lazy val crossModules: Seq[M] = items.map { case (_, _, v) => v.value }
lazy val crossModules: Seq[M] = items.map(_.module.value)

/**
* A mapping of the raw cross values to the cross modules, in
* the order the original cross values were given in
*/
val valuesToModules: collection.MapView[List[Any], M] = items
.map { case (values, segments, subs) => (values, subs) }
.map { i => (i.crossValues, i.module) }
.to(collection.mutable.LinkedHashMap)
.view
.mapValues(_.value)
Expand All @@ -322,7 +334,7 @@ class Cross[M <: Cross.Module[_]](factories: Cross.Factory[M]*)(implicit ctx: mi
* the order the original cross values were given in
*/
val segmentsToModules: collection.MapView[List[String], M] = items
.map { case (values, segments, subs) => (segments, subs) }
.map { i => (i.crossSegments, i.module) }
.to(collection.mutable.LinkedHashMap)
.view
.mapValues(_.value)
Expand Down
Loading
Loading