From 345f5a588afb240bbf128631226e7e4a2baa15f5 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Tue, 29 Oct 2024 06:07:11 -0700 Subject: [PATCH 1/7] Add stub `mill.define.Ctx` to trick IntelliJ into not erroring (#3856) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same as https://github.com/com-lihaoyi/mill/pull/3558, but for `mill.define.Ctx` rather than `mill.main.RootModule.Info`. Because it's provided by the enclosing code-generation, we need to trick IntelliJ into thinking there is something it can use, and so I define a low priority implicit to fall back upon if the main `def make` doesn't work (but `@compileTimeOnly` to show an error message if it ends up being needed) I moved the bulk of the cacher logic from `mill-moduledefs` to `mill.define`. We just need a marker trait in `mill-moduledefs`, and having the rest of the logic in Mill itself simplifies maintenance and evolution of the code Before Screenshot 2024-10-28 at 5 55 39 PM After Screenshot 2024-10-28 at 5 54 22 PM --- main/define/src/mill/define/Cacher.scala | 33 +++++++++++++++++++ main/define/src/mill/define/Ctx.scala | 14 ++++++-- main/define/src/mill/define/Module.scala | 2 +- main/define/src/mill/define/Task.scala | 24 +++++++------- .../src/mill/define/MacroErrorTests.scala | 33 ++++++++++++------- 5 files changed, 80 insertions(+), 26 deletions(-) create mode 100644 main/define/src/mill/define/Cacher.scala diff --git a/main/define/src/mill/define/Cacher.scala b/main/define/src/mill/define/Cacher.scala new file mode 100644 index 00000000000..5de33167c5b --- /dev/null +++ b/main/define/src/mill/define/Cacher.scala @@ -0,0 +1,33 @@ +package mill.define + +import scala.collection.mutable +import scala.reflect.macros.blackbox.Context + +private[mill] trait Cacher extends mill.moduledefs.Cacher { + private[this] lazy val cacherLazyMap = mutable.Map.empty[sourcecode.Enclosing, Any] + + override protected[this] def cachedTarget[T](t: => T)(implicit c: sourcecode.Enclosing): T = + synchronized { + cacherLazyMap.getOrElseUpdate(c, t).asInstanceOf[T] + } +} + +private[mill] object Cacher { + def impl0[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]): c.Expr[T] = { + c.Expr[T](wrapCached[T](c)(t.tree)) + } + def wrapCached[R: c.WeakTypeTag](c: Context)(t: c.Tree): c.universe.Tree = { + + import c.universe._ + val owner = c.internal.enclosingOwner + val ownerIsCacherClass = + owner.owner.isClass && + owner.owner.asClass.baseClasses.exists(_.fullName == "mill.define.Cacher") + + if (ownerIsCacherClass && owner.isMethod) q"this.cachedTarget[${weakTypeTag[R]}]($t)" + else c.abort( + c.enclosingPosition, + "Task{} members must be defs defined in a Module class/trait/object body" + ) + } +} diff --git a/main/define/src/mill/define/Ctx.scala b/main/define/src/mill/define/Ctx.scala index 33a6582e180..78ebfa93681 100644 --- a/main/define/src/mill/define/Ctx.scala +++ b/main/define/src/mill/define/Ctx.scala @@ -1,6 +1,6 @@ package mill.define -import scala.annotation.implicitNotFound +import scala.annotation.{compileTimeOnly, implicitNotFound} /** * The contextual information provided by a [[mill.define.Module]]. @@ -39,7 +39,7 @@ trait Ctx { private[mill] def withEnclosingModule(enclosingModule: Any): Ctx = this } -object Ctx { +object Ctx extends LowPriCtx { private case class Impl( enclosing: String, lineNum: Int, @@ -106,3 +106,13 @@ object Ctx { ) } } + +trait LowPriCtx { + // Dummy `Ctx` available in implicit scope but never actually used. + // as it is provided by the codegen. Defined for IDEs to think that one is available + // and not show errors in build.mill/package.mill even though they can't see the codegen + @compileTimeOnly( + "Modules and Tasks can only be defined within a mill Module" + ) + implicit def dummyInfo: Ctx = sys.error("implicit Ctx must be provided") +} diff --git a/main/define/src/mill/define/Module.scala b/main/define/src/mill/define/Module.scala index 3b59c1d197c..73e3e7fcea2 100644 --- a/main/define/src/mill/define/Module.scala +++ b/main/define/src/mill/define/Module.scala @@ -55,7 +55,7 @@ object Module { * messes up the module discovery process */ @internal - class BaseClass(implicit outerCtx0: mill.define.Ctx) extends mill.moduledefs.Cacher { + class BaseClass(implicit outerCtx0: mill.define.Ctx) extends mill.define.Cacher { def millOuterCtx = outerCtx0 } diff --git a/main/define/src/mill/define/Task.scala b/main/define/src/mill/define/Task.scala index 8273aaba3cf..37ce4f31d54 100644 --- a/main/define/src/mill/define/Task.scala +++ b/main/define/src/mill/define/Task.scala @@ -359,7 +359,7 @@ object Target extends TaskBase { val lhs = Applicative.impl0[Task, T, mill.api.Ctx](c)(reify(Result.create(t.splice)).tree) - mill.moduledefs.Cacher.impl0[Target[T]](c)( + mill.define.Cacher.impl0[Target[T]](c)( reify( new TargetImpl[T]( lhs.splice, @@ -379,7 +379,7 @@ object Target extends TaskBase { val taskIsPrivate = isPrivateTargetOption(c) - mill.moduledefs.Cacher.impl0[Target[T]](c)( + mill.define.Cacher.impl0[Target[T]](c)( reify( new TargetImpl[T]( Applicative.impl0[Task, T, mill.api.Ctx](c)(t.tree).splice, @@ -398,7 +398,7 @@ object Target extends TaskBase { val taskIsPrivate = isPrivateTargetOption(c) - mill.moduledefs.Cacher.impl0[Target[T]](c)( + mill.define.Cacher.impl0[Target[T]](c)( reify { val s1 = Applicative.impl0[Task, T, mill.api.Ctx](c)(t.tree).splice val c1 = ctx.splice @@ -421,7 +421,7 @@ object Target extends TaskBase { val taskIsPrivate = isPrivateTargetOption(c) - mill.moduledefs.Cacher.impl0[Target[T]](c)( + mill.define.Cacher.impl0[Target[T]](c)( reify( new TargetImpl[T]( t.splice, @@ -444,7 +444,7 @@ object Target extends TaskBase { val taskIsPrivate = isPrivateTargetOption(c) - mill.moduledefs.Cacher.impl0[SourcesImpl](c)( + mill.define.Cacher.impl0[SourcesImpl](c)( reify( new SourcesImpl( Target.sequence(c.Expr[List[Task[PathRef]]](q"_root_.scala.List(..$wrapped)").splice), @@ -461,7 +461,7 @@ object Target extends TaskBase { val taskIsPrivate = isPrivateTargetOption(c) - mill.moduledefs.Cacher.impl0[SourcesImpl](c)( + mill.define.Cacher.impl0[SourcesImpl](c)( reify( new SourcesImpl( Applicative.impl0[Task, Seq[PathRef], mill.api.Ctx](c)(values.tree).splice, @@ -483,7 +483,7 @@ object Target extends TaskBase { val taskIsPrivate = isPrivateTargetOption(c) - mill.moduledefs.Cacher.impl0[Target[PathRef]](c)( + mill.define.Cacher.impl0[Target[PathRef]](c)( reify( new SourceImpl( wrapped.splice, @@ -500,7 +500,7 @@ object Target extends TaskBase { val taskIsPrivate = isPrivateTargetOption(c) - mill.moduledefs.Cacher.impl0[Target[PathRef]](c)( + mill.define.Cacher.impl0[Target[PathRef]](c)( reify( new SourceImpl( Applicative.impl0[Task, PathRef, mill.api.Ctx](c)(value.tree).splice, @@ -519,7 +519,7 @@ object Target extends TaskBase { val taskIsPrivate = isPrivateTargetOption(c) - mill.moduledefs.Cacher.impl0[InputImpl[T]](c)( + mill.define.Cacher.impl0[InputImpl[T]](c)( reify( new InputImpl[T]( Applicative.impl[Task, T, mill.api.Ctx](c)(value).splice, @@ -598,7 +598,7 @@ object Target extends TaskBase { val taskIsPrivate = isPrivateTargetOption(c) - mill.moduledefs.Cacher.impl0[Worker[T]](c)( + mill.define.Cacher.impl0[Worker[T]](c)( reify( new Worker[T](t.splice, ctx.splice, taskIsPrivate.splice) ) @@ -611,7 +611,7 @@ object Target extends TaskBase { val taskIsPrivate = isPrivateTargetOption(c) - mill.moduledefs.Cacher.impl0[Worker[T]](c)( + mill.define.Cacher.impl0[Worker[T]](c)( reify( new Worker[T]( Applicative.impl[Task, T, mill.api.Ctx](c)(t).splice, @@ -630,7 +630,7 @@ object Target extends TaskBase { val taskIsPrivate = isPrivateTargetOption(c) - mill.moduledefs.Cacher.impl0[PersistentImpl[T]](c)( + mill.define.Cacher.impl0[PersistentImpl[T]](c)( reify( new PersistentImpl[T]( Applicative.impl[Task, T, mill.api.Ctx](c)(t).splice, diff --git a/main/define/test/src/mill/define/MacroErrorTests.scala b/main/define/test/src/mill/define/MacroErrorTests.scala index 69774203a4e..8c84c5cbc21 100644 --- a/main/define/test/src/mill/define/MacroErrorTests.scala +++ b/main/define/test/src/mill/define/MacroErrorTests.scala @@ -10,7 +10,7 @@ object MacroErrorTests extends TestSuite { test("errors") { val expectedMsg = - "Task{} members must be defs defined in a Cacher class/trait/object body" + "Task{} members must be defs defined in a Module class/trait/object body" val err = compileError("object Foo extends TestBaseModule{ val x = Task {1} }") assert(err.msg == expectedMsg) @@ -84,21 +84,32 @@ object MacroErrorTests extends TestSuite { // of our `Target#apply()` calls, but we cannot reference any values that // come from inside the Task{...} block test("pos") { - val e = compileError(""" - val a = Task { 1 } + // This hsould compile + object foo extends TestBaseModule { + def a = Task { 1 } val arr = Array(a) - val b = { + def b = { val c = 0 - Task{ + Task { arr(c)() } } - """) + } + } + test("neg1") { + val e = compileError("""def a = Task { 1 }""") assert(e.msg.contains( - "Modules and Tasks can only be defined within a mill Module" + "Task{} members must be defs defined in a Module class/trait/object body" )) } - test("neg") { + + test("neg2") { + val e = compileError("object foo extends TestBaseModule{ val a = Task { 1 } }") + assert(e.msg.contains( + "Task{} members must be defs defined in a Module class/trait/object body" + )) + } + test("neg3") { val expectedMsg = "Target#apply() call cannot use `value n` defined within the Task{...} block" @@ -114,7 +125,7 @@ object MacroErrorTests extends TestSuite { }""") assert(err.msg == expectedMsg) } - test("neg2") { + test("neg4") { val expectedMsg = "Target#apply() call cannot use `value x` defined within the Task{...} block" @@ -129,7 +140,7 @@ object MacroErrorTests extends TestSuite { }""") assert(err.msg == expectedMsg) } - test("neg3") { + test("neg5") { val borkedCachedDiamond1 = utest.compileError(""" object borkedCachedDiamond1 { def up = Task { TestUtil.test() } @@ -139,7 +150,7 @@ object MacroErrorTests extends TestSuite { } """) assert(borkedCachedDiamond1.msg.contains( - "Modules and Tasks can only be defined within a mill Module" + "Task{} members must be defs defined in a Module class/trait/object body" )) } } From ad9ff0a26b6c6eaeef3b1dc77e08a8180e17504f Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 29 Oct 2024 15:08:20 +0100 Subject: [PATCH 2/7] Rename `millImport` variable to `metaBuild` (#3848) We have various things to import, but this parameter is for the enabled-state of the meta-build, so reflect it in the name. Pull request: https://github.com/com-lihaoyi/mill/pull/3848 --- runner/src/mill/runner/FileImportGraph.scala | 4 ++-- runner/src/mill/runner/MillBuildBootstrap.scala | 2 +- runner/src/mill/runner/MillBuildRootModule.scala | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/runner/src/mill/runner/FileImportGraph.scala b/runner/src/mill/runner/FileImportGraph.scala index 05fd98dd095..cb8f2f7570b 100644 --- a/runner/src/mill/runner/FileImportGraph.scala +++ b/runner/src/mill/runner/FileImportGraph.scala @@ -13,7 +13,7 @@ import scala.collection.mutable * @param ivyDeps * @param importGraphEdges * @param errors - * @param millImport If `true`, a meta-build is enabled + * @param metaBuild If `true`, a meta-build is enabled */ @internal case class FileImportGraph( @@ -21,7 +21,7 @@ case class FileImportGraph( repos: Seq[(String, os.Path)], ivyDeps: Set[String], errors: Seq[String], - millImport: Boolean, + metaBuild: Boolean, buildFile: String ) diff --git a/runner/src/mill/runner/MillBuildBootstrap.scala b/runner/src/mill/runner/MillBuildBootstrap.scala index 4ac6af2e6fa..5d6451a7b9e 100644 --- a/runner/src/mill/runner/MillBuildBootstrap.scala +++ b/runner/src/mill/runner/MillBuildBootstrap.scala @@ -107,7 +107,7 @@ class MillBuildBootstrap( output ) - if (parsedScriptFiles.millImport) evaluateRec(depth + 1) + if (parsedScriptFiles.metaBuild) evaluateRec(depth + 1) else { val bootstrapModule = new MillBuildRootModule.BootstrapModule()( diff --git a/runner/src/mill/runner/MillBuildRootModule.scala b/runner/src/mill/runner/MillBuildRootModule.scala index cfc219e30c1..2a193463f59 100644 --- a/runner/src/mill/runner/MillBuildRootModule.scala +++ b/runner/src/mill/runner/MillBuildRootModule.scala @@ -193,13 +193,13 @@ abstract class MillBuildRootModule()(implicit override def sources: T[Seq[PathRef]] = Task { scriptSources() ++ { - if (parseBuildFiles().millImport) super.sources() + if (parseBuildFiles().metaBuild) super.sources() else Seq.empty[PathRef] } } override def resources: T[Seq[PathRef]] = Task { - if (parseBuildFiles().millImport) super.resources() + if (parseBuildFiles().metaBuild) super.resources() else Seq.empty[PathRef] } From 24e56e68f05c5fbc9c1c7393d9d181a9d6564eb7 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Tue, 29 Oct 2024 08:16:59 -0700 Subject: [PATCH 3/7] Replace direct discord invite link with link to scala discord and instructions to join channel (#3866) Fixes https://github.com/com-lihaoyi/mill/issues/3864 Somehow the direct channel links always expire even when specifically configured not to --- CONTRIBUTING.adoc | 4 ++-- docs/modules/ROOT/pages/index.adoc | 4 ++++ docs/supplemental-ui/partials/header-content.hbs | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index 1dd014f43c4..66a0c2f2a29 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -1,6 +1,6 @@ = Contributing to Mill :link-github: https://github.com/com-lihaoyi/mill -:link-chat: https://discord.gg/xJCYRVMS + Thank you for considering contributing to Mill. @@ -16,6 +16,6 @@ Here are some direct links: * {link-github}/discussions[Discussion Forum on GitHub] - A place to ask question and discuss all kind of questions around Mill * {link-github}/issues[Issue Tracker on GitHub] - Our issue tracker for bugs and features * {link-github}/pulls[Pull Requests on GitHub] - All new features and bug fixes find their way into Mill via a pull request. You can also sketch new ideas by creating a draft pull requests. -{link-chat}[Discord Chat] - You can also join our chat room if you like more direct communication or to just say hello + To build docs locally, `mill docs.localPages`. The last line of the command tells you where to browse the generated pages. From there you can follow the breadcrumbs. diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index ac3570125f5..5fd99199d09 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -107,3 +107,7 @@ they are interesting: * https://www.youtube.com/watch?v=UsXgCeU-ovI[Video: A Deep Dive into the Mill Build Tool] +To engage Mill with the community, you can use the channels below: + +* https://github.com/com-lihaoyi/mill/discussions[Mill Github Discussions] +* https://discord.com/invite/scala[Scala Discord], in the TOOLING#mill channel \ No newline at end of file diff --git a/docs/supplemental-ui/partials/header-content.hbs b/docs/supplemental-ui/partials/header-content.hbs index 5f134d0e22b..e3a6630f666 100644 --- a/docs/supplemental-ui/partials/header-content.hbs +++ b/docs/supplemental-ui/partials/header-content.hbs @@ -20,7 +20,7 @@ API Issues Discuss - Chat +