diff --git a/ci/mill-bootstrap.patch b/ci/mill-bootstrap.patch index e69de29bb2d..dfa131363b9 100644 --- a/ci/mill-bootstrap.patch +++ b/ci/mill-bootstrap.patch @@ -0,0 +1,119 @@ +diff --git a/build.sc b/build.sc +index be462bb7c..50eb14412 100644 +--- a/build.sc ++++ b/build.sc +@@ -2,22 +2,10 @@ + import $file.ci.shared + import $file.ci.upload + import $ivy.`org.scalaj::scalaj-http:2.4.2` +-import $ivy.`de.tototec::de.tobiasroeser.mill.vcs.version_mill0.10:0.3.0` +-import $ivy.`com.github.lolgab::mill-mima_mill0.10:0.0.13` + import $ivy.`net.sourceforge.htmlcleaner:htmlcleaner:2.25` + + // imports +-import com.github.lolgab.mill.mima +-import com.github.lolgab.mill.mima.{ +- CheckDirection, +- DirectMissingMethodProblem, +- IncompatibleMethTypeProblem, +- IncompatibleSignatureProblem, +- ProblemFilter, +- ReversedMissingMethodProblem +-} + import coursier.maven.MavenRepository +-import de.tobiasroeser.mill.vcs.version.VcsVersion + import mill._ + import mill.define.{Command, Source, Sources, Target, Task} + import mill.eval.Evaluator +@@ -180,12 +168,8 @@ object Deps { + val requests = ivy"com.lihaoyi::requests:0.8.0" + } + +-def millVersion: T[String] = T { VcsVersion.vcsState().format() } +-def millLastTag: T[String] = T { +- VcsVersion.vcsState().lastTag.getOrElse( +- sys.error("No (last) git tag found. Your git history seems incomplete!") +- ) +-} ++def millVersion: T[String] = T { "0.0.0.test" } ++def millLastTag: T[String] = T { "0.0.0.test" } + def millBinPlatform: T[String] = T { + val tag = millLastTag() + if (tag.contains("-M")) tag +@@ -244,20 +228,7 @@ trait MillCoursierModule extends CoursierModule { + ) + } + +-trait MillMimaConfig extends mima.Mima { +- override def mimaPreviousVersions: T[Seq[String]] = Settings.mimaBaseVersions +- override def mimaPreviousArtifacts = +- if (Settings.mimaBaseVersions.isEmpty) T { Agg[Dep]() } +- else super.mimaPreviousArtifacts +- override def mimaExcludeAnnotations: T[Seq[String]] = Seq( +- "mill.api.internal", +- "mill.api.experimental" +- ) +- override def mimaCheckDirection: Target[CheckDirection] = T { CheckDirection.Backward } +- override def mimaBinaryIssueFilters: Target[Seq[ProblemFilter]] = T { +- issueFilterByModule.getOrElse(this, Seq()) +- } +- lazy val issueFilterByModule: Map[MillMimaConfig, Seq[ProblemFilter]] = Map() ++trait MillMimaConfig extends Module { + } + + /** A Module compiled with applied Mill-specific compiler plugins: mill-moduledefs. */ +@@ -1549,53 +1520,7 @@ def launcher = T { + } + + def uploadToGithub(authKey: String) = T.command { +- val vcsState = VcsVersion.vcsState() +- val label = vcsState.format() +- if (label != millVersion()) sys.error("Modified mill version detected, aborting upload") +- val releaseTag = vcsState.lastTag.getOrElse(sys.error( +- "Incomplete git history. No tag found.\nIf on CI, make sure your git checkout job includes enough history." +- )) +- +- if (releaseTag == label) { +- // TODO: check if the tag already exists (e.g. because we created it manually) and do not fail +- scalaj.http.Http( +- s"https://api.github.com/repos/${Settings.githubOrg}/${Settings.githubRepo}/releases" +- ) +- .postData( +- ujson.write( +- ujson.Obj( +- "tag_name" -> releaseTag, +- "name" -> releaseTag +- ) +- ) +- ) +- .header("Authorization", "token " + authKey) +- .asString +- } +- +- val exampleZips = Seq("example-1", "example-2", "example-3") +- .map { example => +- os.copy(T.workspace / "example" / example, T.dest / example) +- os.copy(launcher().path, T.dest / example / "mill") +- os.proc("zip", "-r", T.dest / s"$example.zip", example).call(cwd = T.dest) +- (T.dest / s"$example.zip", label + "-" + example + ".zip") +- } +- +- val zips = exampleZips ++ Seq( +- (assembly().path, label + "-assembly"), +- (launcher().path, label) +- ) +- +- for ((zip, name) <- zips) { +- upload.apply( +- zip, +- releaseTag, +- name, +- authKey, +- Settings.githubOrg, +- Settings.githubRepo +- ) +- } ++ // never upload a bootstrapped version + } + + def validate(ev: Evaluator): Command[Unit] = T.command { diff --git a/main/core/src/mill/define/Task.scala b/main/core/src/mill/define/Task.scala index 2b993a263ad..f9e5d0ac496 100644 --- a/main/core/src/mill/define/Task.scala +++ b/main/core/src/mill/define/Task.scala @@ -45,6 +45,7 @@ trait NamedTask[+T] extends Task[T] { def ctx: mill.define.Ctx def label: String = ctx.segment match { case Segment.Label(v) => v } override def toString = ctx.segments.render + def isPrivate: Option[Boolean] = None } trait Target[+T] extends NamedTask[T] { // TODO: change from Some[Target[T]] to Option[Target[T]] in 0.11 @@ -71,15 +72,28 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { ctx: c.Expr[mill.define.Ctx] ): c.Expr[Target[T]] = { import c.universe._ + +// val _isPrivate = reify(Some(c.internal.enclosingOwner.isPrivate)) +// val _isPublic = reify(Some(c.internal.enclosingOwner.isPublic)) +// println(s"isPrivate: ${isPrivate}, isPublic: ${isPublic}") + + val taskIsPrivate = isPrivateTargetOption(c) + val lhs = Applicative.impl0[Task, T, mill.api.Ctx](c)(reify(Result.Success(t.splice)).tree) mill.moduledefs.Cacher.impl0[TargetImpl[T]](c)( reify( - new TargetImpl[T](lhs.splice, ctx.splice, rw.splice) + new TargetImpl[T](lhs.splice, ctx.splice, rw.splice, taskIsPrivate.splice) ) ) } + def isPrivateTargetOption(c: Context): c.Expr[Option[Boolean]] = { + import c.universe._ + if (c.internal.enclosingOwner.isPrivate) reify(Some(true)) + else reify(Some(false)) + } + implicit def apply[T](t: Result[T])(implicit rw: RW[T], ctx: mill.define.Ctx): Target[T] = macro targetResultImpl[T] @@ -88,12 +102,16 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { ctx: c.Expr[mill.define.Ctx] ): c.Expr[Target[T]] = { import c.universe._ + + val taskIsPrivate = isPrivateTargetOption(c) + mill.moduledefs.Cacher.impl0[Target[T]](c)( reify( new TargetImpl[T]( Applicative.impl0[Task, T, mill.api.Ctx](c)(t.tree).splice, ctx.splice, - rw.splice + rw.splice, + taskIsPrivate.splice ) ) ) @@ -107,9 +125,12 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { ctx: c.Expr[mill.define.Ctx] ): c.Expr[Target[T]] = { import c.universe._ + + val taskIsPrivate = isPrivateTargetOption(c) + mill.moduledefs.Cacher.impl0[Target[T]](c)( reify( - new TargetImpl[T](t.splice, ctx.splice, rw.splice) + new TargetImpl[T](t.splice, ctx.splice, rw.splice, taskIsPrivate.splice) ) ) } @@ -125,11 +146,14 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { reify(value.splice.map(PathRef(_))).tree ).tree + val taskIsPrivate = isPrivateTargetOption(c) + mill.moduledefs.Cacher.impl0[Sources](c)( reify( new Sources( Target.sequence(c.Expr[List[Task[PathRef]]](q"_root_.scala.List(..$wrapped)").splice), - ctx.splice + ctx.splice, + taskIsPrivate.splice ) ) ) @@ -142,11 +166,14 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { : c.Expr[Sources] = { import c.universe._ + val taskIsPrivate = isPrivateTargetOption(c) + mill.moduledefs.Cacher.impl0[Sources](c)( reify( new Sources( Applicative.impl0[Task, Seq[PathRef], mill.api.Ctx](c)(values.tree).splice, - ctx.splice + ctx.splice, + taskIsPrivate.splice ) ) ) @@ -162,11 +189,14 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { reify(value.splice.map(PathRef(_))).tree ) + val taskIsPrivate = isPrivateTargetOption(c) + mill.moduledefs.Cacher.impl0[Source](c)( reify( new Source( wrapped.splice, - ctx.splice + ctx.splice, + taskIsPrivate.splice ) ) ) @@ -177,11 +207,15 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { def sourceImpl2(c: Context)(value: c.Expr[Result[PathRef]])(ctx: c.Expr[mill.define.Ctx]) : c.Expr[Source] = { import c.universe._ + + val taskIsPrivate = isPrivateTargetOption(c) + mill.moduledefs.Cacher.impl0[Source](c)( reify( new Source( Applicative.impl0[Task, PathRef, mill.api.Ctx](c)(value.tree).splice, - ctx.splice + ctx.splice, + taskIsPrivate.splice ) ) ) @@ -198,12 +232,15 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { ): c.Expr[Input[T]] = { import c.universe._ + val taskIsPrivate = isPrivateTargetOption(c) + mill.moduledefs.Cacher.impl0[Input[T]](c)( reify( new Input[T]( Applicative.impl[Task, T, mill.api.Ctx](c)(value).splice, ctx.splice, - w.splice + w.splice, + taskIsPrivate.splice ) ) ) @@ -213,8 +250,30 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { ctx: mill.define.Ctx, w: W[T], cls: EnclosingClass - ): Command[T] = { - new Command(t, ctx, w, cls.value) + ): Command[T] = macro commandFromTask[T] +// { +// // TODO replace by macro to get isPrivate +// new Command(t, ctx, w, cls.value, isPrivate = None) +// } + + def commandFromTask[T: c.WeakTypeTag](c: Context)(t: c.Expr[Task[T]])( + ctx: c.Expr[mill.define.Ctx], + w: c.Expr[W[T]], + cls: c.Expr[EnclosingClass] + ): c.Expr[Command[T]] = { + import c.universe._ + + val taskIsPrivate = isPrivateTargetOption(c) + + reify( + new Command[T]( + t.splice, + ctx.splice, + w.splice, + cls.splice.value, + taskIsPrivate.splice + ) + ) } def command[T](t: Result[T])(implicit @@ -229,12 +288,16 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { cls: c.Expr[EnclosingClass] ): c.Expr[Command[T]] = { import c.universe._ + + val taskIsPrivate = isPrivateTargetOption(c) + reify( new Command[T]( Applicative.impl[Task, T, mill.api.Ctx](c)(t).splice, ctx.splice, w.splice, - cls.splice.value + cls.splice.value, + taskIsPrivate.splice ) ) } @@ -244,9 +307,12 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { def workerImpl1[T: c.WeakTypeTag](c: Context)(t: c.Expr[Task[T]])(ctx: c.Expr[mill.define.Ctx]) : c.Expr[Worker[T]] = { import c.universe._ + + val taskIsPrivate = isPrivateTargetOption(c) + mill.moduledefs.Cacher.impl0[Worker[T]](c)( reify( - new Worker[T](t.splice, ctx.splice) + new Worker[T](t.splice, ctx.splice, taskIsPrivate.splice) ) ) } @@ -255,9 +321,16 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { def workerImpl2[T: c.WeakTypeTag](c: Context)(t: c.Expr[T])(ctx: c.Expr[mill.define.Ctx]) : c.Expr[Worker[T]] = { import c.universe._ + + val taskIsPrivate = isPrivateTargetOption(c) + mill.moduledefs.Cacher.impl0[Worker[T]](c)( reify( - new Worker[T](Applicative.impl[Task, T, mill.api.Ctx](c)(t).splice, ctx.splice) + new Worker[T]( + Applicative.impl[Task, T, mill.api.Ctx](c)(t).splice, + ctx.splice, + taskIsPrivate.splice + ) ) ) } @@ -273,12 +346,15 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { ): c.Expr[Persistent[T]] = { import c.universe._ + val taskIsPrivate = isPrivateTargetOption(c) + mill.moduledefs.Cacher.impl0[Persistent[T]](c)( reify( new Persistent[T]( Applicative.impl[Task, T, mill.api.Ctx](c)(t).splice, ctx.splice, - rw.splice + rw.splice, + taskIsPrivate.splice ) ) ) @@ -294,53 +370,73 @@ object Target extends Applicative.Applyer[Task, Task, Result, mill.api.Ctx] { } } -abstract class NamedTaskImpl[+T](ctx0: mill.define.Ctx, t: Task[T]) extends NamedTask[T] { +abstract class NamedTaskImpl[+T]( + ctx0: mill.define.Ctx, + t: Task[T], + override val isPrivate: Option[Boolean] +) extends NamedTask[T] { def evaluate(args: mill.api.Ctx) = args[T](0) val ctx = ctx0.copy(segments = ctx0.segments ++ Seq(ctx0.segment)) val inputs = Seq(t) } -class TargetImpl[+T](t: Task[T], ctx0: mill.define.Ctx, val readWrite: RW[_]) - extends NamedTaskImpl[T](ctx0, t) +class TargetImpl[+T]( + t: Task[T], + ctx0: mill.define.Ctx, + val readWrite: RW[_], + isPrivate: Option[Boolean] +) extends NamedTaskImpl[T](ctx0, t, isPrivate) with Target[T] {} class Command[+T]( t: Task[T], ctx0: mill.define.Ctx, val writer: W[_], - val cls: Class[_] -) extends NamedTaskImpl[T](ctx0, t) { + val cls: Class[_], + isPrivate: Option[Boolean] +) extends NamedTaskImpl[T](ctx0, t, isPrivate) { override def asCommand = Some(this) } -class Worker[+T](t: Task[T], ctx0: mill.define.Ctx) extends NamedTaskImpl[T](ctx0, t) { +class Worker[+T](t: Task[T], ctx0: mill.define.Ctx, isPrivate: Option[Boolean]) + extends NamedTaskImpl[T](ctx0, t, isPrivate) { override def flushDest = false override def asWorker = Some(this) } -class Persistent[+T](t: Task[T], ctx0: mill.define.Ctx, readWrite: RW[_]) - extends TargetImpl[T](t, ctx0, readWrite) { +class Persistent[+T]( + t: Task[T], + ctx0: mill.define.Ctx, + readWrite: RW[_], + isPrivate: Option[Boolean] +) extends TargetImpl[T](t, ctx0, readWrite, isPrivate) { override def flushDest = false } -class Input[T](t: Task[T], ctx0: mill.define.Ctx, val writer: upickle.default.Writer[_]) - extends NamedTaskImpl[T](ctx0, t) { +class Input[T]( + t: Task[T], + ctx0: mill.define.Ctx, + val writer: upickle.default.Writer[_], + isPrivate: Option[Boolean] +) extends NamedTaskImpl[T](ctx0, t, isPrivate) { override def sideHash = util.Random.nextInt() } -class Sources(t: Task[Seq[PathRef]], ctx0: mill.define.Ctx) +class Sources(t: Task[Seq[PathRef]], ctx0: mill.define.Ctx, isPrivate: Option[Boolean]) extends Input[Seq[PathRef]]( t, ctx0, - upickle.default.SeqLikeWriter[Seq, PathRef] + upickle.default.SeqLikeWriter[Seq, PathRef], + isPrivate ) -class Source(t: Task[PathRef], ctx0: mill.define.Ctx) +class Source(t: Task[PathRef], ctx0: mill.define.Ctx, isPrivate: Option[Boolean]) extends Input[PathRef]( t, ctx0, - PathRef.jsonFormatter + PathRef.jsonFormatter, + isPrivate ) object Task { diff --git a/main/core/src/mill/eval/Evaluator.scala b/main/core/src/mill/eval/Evaluator.scala index cec535fc723..7ac5a0c4a79 100644 --- a/main/core/src/mill/eval/Evaluator.scala +++ b/main/core/src/mill/eval/Evaluator.scala @@ -812,6 +812,9 @@ object Evaluator { val seen = collection.mutable.Set.empty[Segments] val overridden = collection.mutable.Set.empty[Task[_]] topoSorted.values.reverse.iterator.foreach { + case x: NamedTask[_] if x.isPrivate == Some(true) => + // we always need to store them in the super-path + overridden.add(x) case x: NamedTask[_] => if (!seen.contains(x.ctx.segments)) seen.add(x.ctx.segments) else overridden.add(x) diff --git a/main/test/src/eval/EvaluationTests.scala b/main/test/src/eval/EvaluationTests.scala index 96a0226395c..36098a27fd8 100644 --- a/main/test/src/eval/EvaluationTests.scala +++ b/main/test/src/eval/EvaluationTests.scala @@ -361,7 +361,7 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { // the main publicly-available command import StackableOverrides._ - val checker = new Checker(canOverrideSuper) + val checker = new Checker(StackableOverrides) checker( m.f, 6, @@ -382,5 +382,25 @@ class EvaluationTests(threadCount: Option[Int]) extends TestSuite { ) assert(os.read(checker.evaluator.outPath / "m" / "f.json").contains(" 6,")) } + "privateTasksInMixedTraits" - { + // Make sure we can have private cached targets in different trait with the same name, + // and caching still works when these traits are mixed together + import PrivateTasksInMixedTraits._ + val checker = new Checker(PrivateTasksInMixedTraits) + checker( + mod.bar, + "foo-m1", + Agg(mod.bar), + extraEvaled = -1 + ) + // If we evaluate to "foo-m1" instead of "foo-m2", + // we don't properly distinguish between the two private `foo` targets + checker( + mod.baz, + "foo-m2", + Agg(mod.baz), + extraEvaled = -1 + ) + } } } diff --git a/main/test/src/util/TestGraphs.scala b/main/test/src/util/TestGraphs.scala index c2f016f3c20..c418ffc48a4 100644 --- a/main/test/src/util/TestGraphs.scala +++ b/main/test/src/util/TestGraphs.scala @@ -297,4 +297,16 @@ object TestGraphs { } object m extends A with B {} } + + object PrivateTasksInMixedTraits extends TestUtil.BaseModule { + trait M1 extends Module { + private def foo = T { "foo-m1" } + def bar = T { foo() } + } + trait M2 extends Module { + private def foo = T { "foo-m2" } + def baz = T { foo() } + } + object mod extends M1 with M2 + } }