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

Add support for .super suffix in Mill task resolution #4637

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions core/resolve/src/mill/resolve/Resolve.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import mill.define.{
Discover,
Module,
NamedTask,
Segment,
Segments,
TaskModule,
SelectMode
Expand All @@ -27,7 +28,10 @@ private[mill] object Resolve {
resolveToModuleTasks: Boolean,
cache: ResolveCore.Cache
) = {
Result.Success(resolved.map(_.segments))
// For qualified super tasks (super.Something), return the original selector
// Otherwise, return the resolved segments
val hasQualifiedSuper = selector.render.contains(".super.")
Result.Success(if (hasQualifiedSuper) Seq(selector) else resolved.map(_.segments))
}

private[mill] override def deduplicate(items: List[Segments]): List[Segments] = items.distinct
Expand Down Expand Up @@ -58,10 +62,33 @@ private[mill] object Resolve {

val taskList: Seq[Result[Option[NamedTask[?]]]] = resolved.map {
case r: Resolved.NamedTask =>
val instantiated = ResolveCore
.instantiateModule(rootModule, r.segments.init, cache)
.flatMap(instantiateNamedTask(r, _, cache))
instantiated.map(Some(_))
val superIdx = r.segments.value.indexWhere {
case Segment.Label("super") => true
case _ => false
}

if (superIdx >= 0) {
// For tasks with super, create a task with segments before the super segment
val segmentsWithoutSuper = mill.define.Segments(r.segments.value.take(superIdx))
Result.Success(Some(new NamedTask[Any] {
override def ctx0 = mill.define.Ctx.makeRoot(
millModuleEnclosing0 = rootModule.moduleCtx.enclosing,
millModuleLine0 = rootModule.moduleCtx.lineNum,
millSourcePath = rootModule.moduleCtx.millSourcePath,
segments0 = segmentsWithoutSuper,
external0 = rootModule.moduleCtx.external,
fileName = rootModule.moduleCtx.fileName
)
override def isPrivate = None
override val inputs = Nil
override def evaluate0 = ???
}))
} else {
val instantiated = ResolveCore
.instantiateModule(rootModule, r.segments.init, cache)
.flatMap(instantiateNamedTask(r, _, cache))
instantiated.map(Some(_))
}

case r: Resolved.Command =>
val instantiated = ResolveCore
Expand Down
3 changes: 3 additions & 0 deletions core/resolve/src/mill/resolve/ResolveCore.scala
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ private object ResolveCore {
}

(head, current) match {
case (Segment.Label("super"), task: Resolved.NamedTask) =>
Success(Seq(Resolved.NamedTask(task.segments ++ Seq(head))))

case (Segment.Label(singleLabel), m: Resolved.Module) =>
val resOrErr: mill.api.Result[Seq[Resolved]] = singleLabel match {
case "__" =>
Expand Down
86 changes: 86 additions & 0 deletions core/resolve/test/src/mill/resolve/ResolveTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,29 @@ object ResolveTests extends TestSuite {
lazy val millDiscover = Discover[this.type]
}

// Test modules for supertask resolution
trait BaseModule extends TestBaseModule {
def baseTask = Task { "base" }
def multiOverride = Task { "base-multi" }
}

object singleOverrideModule extends BaseModule {
// Single override of baseTask
override def baseTask = Task { "single-override" }
lazy val millDiscover = Discover[this.type]
}

trait MidModule extends BaseModule {
// First level override of multiOverride
override def multiOverride = Task { "mid-override" }
}

object multiOverrideModule extends MidModule {
// Second level override of multiOverride
override def multiOverride = Task { "final-override" }
lazy val millDiscover = Discover[this.type]
}

def isShortError(x: Result[?], s: String) =
x.errorOpt.exists(_.contains(s)) &&
// Make sure the stack traces are truncated and short-ish, and do not
Expand Down Expand Up @@ -250,5 +273,68 @@ object ResolveTests extends TestSuite {
)
}

test("supertasks") {
test("singleOverride") {
val check = new Checker(singleOverrideModule)

// Super task should resolve to the base implementation
test("superTask") - check(
"baseTask.super",
Result.Success(Set(_.baseTask)),
Set("baseTask.super")
)
}

test("multiOverride") {
val check = new Checker(multiOverrideModule)

// Direct super task should resolve to the mid-level implementation
test("directSuperTask") - check(
"multiOverride.super",
Result.Success(Set(_.multiOverride)),
Set("multiOverride.super")
)

// Qualified super task should resolve to the base implementation
test("qualifiedSuperTask") - check(
"multiOverride.super.BaseModule",
Result.Success(Set(_.multiOverride)),
Set("multiOverride.super.BaseModule")
)
}

// Test for complex super task resolution
test("complexSuperTask") {
// Create a more complex module hierarchy to test super task resolution
trait ComplexBase extends TestBaseModule {
def artifactSuffix = Task { "base-suffix" }
}

trait ComplexMid extends ComplexBase {
override def artifactSuffix = Task { "mid-suffix" }
}

object complexModule extends ComplexMid {
override def artifactSuffix = Task { "final-suffix" }
lazy val millDiscover = Discover[this.type]
}

val check = new Checker(complexModule)

// Test direct super task resolution
test("directSuperTask") - check(
"artifactSuffix.super",
Result.Success(Set(_.artifactSuffix)),
Set("artifactSuffix.super")
)

// Test qualified super task resolution
test("qualifiedSuperTask") - check(
"artifactSuffix.super.ComplexBase",
Result.Success(Set(_.artifactSuffix)),
Set("artifactSuffix.super.ComplexBase")
)
}
}
}
}
Loading