From b6468bff55e94784b0332e77fdb06ffd69a236c9 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 5 Nov 2025 14:13:04 +0100 Subject: [PATCH 01/67] Rename test class mill.api.Opt to TestOpt --- .../test/src/mill/api/ApplicativeTests.scala | 114 +++++++++--------- core/api/test/src/mill/api/Opt.scala | 30 ----- core/api/test/src/mill/api/TestOpt.scala | 30 +++++ 3 files changed, 87 insertions(+), 87 deletions(-) delete mode 100644 core/api/test/src/mill/api/Opt.scala create mode 100644 core/api/test/src/mill/api/TestOpt.scala diff --git a/core/api/test/src/mill/api/ApplicativeTests.scala b/core/api/test/src/mill/api/ApplicativeTests.scala index ea0da51eea14..f85db1e5e378 100644 --- a/core/api/test/src/mill/api/ApplicativeTests.scala +++ b/core/api/test/src/mill/api/ApplicativeTests.scala @@ -23,86 +23,86 @@ object ApplicativeTests extends TestSuite { test("selfContained") { - test("simple") - assert(Opt("lol " + 1) == Opt.some("lol 1")) - test("singleSome") - assert(Opt("lol " + Opt.some("hello")()) == Opt.some("lol hello")) + test("simple") - assert(TestOpt("lol " + 1) == TestOpt.some("lol 1")) + test("singleSome") - assert(TestOpt("lol " + TestOpt.some("hello")()) == TestOpt.some("lol hello")) test("twoSomes") - assert( - Opt(Opt.some("lol ")() + Opt.some("hello")()) == Opt.some("lol hello") + TestOpt(TestOpt.some("lol ")() + TestOpt.some("hello")()) == TestOpt.some("lol hello") ) - test("singleNone") - assert(Opt("lol " + Opt.none()) == Opt.none) - test("twoNones") - assert(Opt("lol " + Opt.none() + Opt.none()) == Opt.none) + test("singleNone") - assert(TestOpt("lol " + TestOpt.none()) == TestOpt.none) + test("twoNones") - assert(TestOpt("lol " + TestOpt.none() + TestOpt.none()) == TestOpt.none) test("moreThan22") { assert( - Opt( + TestOpt( "lol " + - Opt.none() + Opt.none() + Opt.none() + Opt.none() + Opt.none() + - Opt.none() + Opt.none() + Opt.none() + Opt.none() + Opt.some(" world")() + - Opt.none() + Opt.none() + Opt.none() + Opt.none() + Opt.none() + - Opt.none() + Opt.none() + Opt.none() + Opt.none() + Opt.none() + - Opt.none() + Opt.none() + Opt.none() + Opt.none() + Opt.some(" moo")() - ) == Opt.none + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.some(" world")() + + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.some(" moo")() + ) == TestOpt.none ) assert( - Opt( + TestOpt( "lol " + - Opt.some("a")() + Opt.some("b")() + Opt.some("c")() + Opt.some("d")() + - Opt.some("e")() + Opt.some("a")() + Opt.some("b")() + Opt.some("c")() + - Opt.some("d")() + Opt.some("e")() + Opt.some("a")() + Opt.some("b")() + - Opt.some("c")() + Opt.some("d")() + Opt.some("e")() + Opt.some("a")() + - Opt.some("b")() + Opt.some("c")() + Opt.some("d")() + Opt.some("e")() + - Opt.some("a")() + Opt.some("b")() + Opt.some("c")() + Opt.some("d")() + - Opt.some("e")() + Opt.some("a")() + Opt.some("b")() + Opt.some("c")() + - Opt.some("d")() + Opt.some("e")() + Opt.some("a")() + Opt.some("b")() + - Opt.some("c")() + Opt.some("d")() + Opt.some("e")() + Opt.some("a")() + - Opt.some("b")() + Opt.some("c")() + Opt.some("d")() + Opt.some("e")() + - Opt.some("a")() + Opt.some("b")() + Opt.some("c")() + Opt.some("d")() + - Opt.some("e")() + Opt.some("a")() + Opt.some("b")() + Opt.some("c")() + - Opt.some("d")() + Opt.some("e")() - ) == Opt.some("lol abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde") + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some("d")() + + TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + + TestOpt.some("d")() + TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + + TestOpt.some("c")() + TestOpt.some("d")() + TestOpt.some("e")() + TestOpt.some("a")() + + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some("d")() + TestOpt.some("e")() + + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some("d")() + + TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + + TestOpt.some("d")() + TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + + TestOpt.some("c")() + TestOpt.some("d")() + TestOpt.some("e")() + TestOpt.some("a")() + + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some("d")() + TestOpt.some("e")() + + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some("d")() + + TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + + TestOpt.some("d")() + TestOpt.some("e")() + ) == TestOpt.some("lol abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde") ) } } test("context") { - assert(Opt(Opt.ctx() + Opt.some("World")()) == Opt.some("hellooooWorld")) + assert(TestOpt(TestOpt.ctx() + TestOpt.some("World")()) == TestOpt.some("hellooooWorld")) } test("capturing") { val lol = "lol " def hell(o: String) = "hell" + o - test("simple") - assert(Opt(lol + 1) == Opt.some("lol 1")) - test("singleSome") - assert(Opt(lol + Opt.some(hell("o"))()) == Opt.some("lol hello")) + test("simple") - assert(TestOpt(lol + 1) == TestOpt.some("lol 1")) + test("singleSome") - assert(TestOpt(lol + TestOpt.some(hell("o"))()) == TestOpt.some("lol hello")) test("twoSomes") - assert( - Opt(Opt.some(lol)() + Opt.some(hell("o"))()) == Opt.some("lol hello") + TestOpt(TestOpt.some(lol)() + TestOpt.some(hell("o"))()) == TestOpt.some("lol hello") ) - test("singleNone") - assert(Opt(lol + Opt.none()) == Opt.none) - test("twoNones") - assert(Opt(lol + Opt.none() + Opt.none()) == Opt.none) + test("singleNone") - assert(TestOpt(lol + TestOpt.none()) == TestOpt.none) + test("twoNones") - assert(TestOpt(lol + TestOpt.none() + TestOpt.none()) == TestOpt.none) } test("allowedLocalDef") { - // Although x is defined inside the Opt{...} block, it is also defined + // Although x is defined inside the TestOpt{...} block, it is also defined // within the LHS of the Applyable#apply call, so it is safe to life it // out into the `zipMap` arguments list. - val res = Opt { "lol " + new Opt(Some("hello").flatMap(x => Some(x))).apply() } - assert(res == Opt.some("lol hello")) + val res = TestOpt { "lol " + new TestOpt(Some("hello").flatMap(x => Some(x))).apply() } + assert(res == TestOpt.some("lol hello")) } test("upstreamAlwaysEvaluated") { // Whether or not control-flow reaches the Applyable#apply call inside an - // Opt{...} block, we always evaluate the LHS of the Applyable#apply + // TestOpt{...} block, we always evaluate the LHS of the Applyable#apply // because it gets lifted out of any control flow statements val counter = new Counter() - def up = Opt { "lol " + counter() } - val down = Opt { if ("lol".length > 10) up() else "fail" } + def up = TestOpt { "lol " + counter() } + val down = TestOpt { if ("lol".length > 10) up() else "fail" } assert( - down == Opt.some("fail"), + down == TestOpt.some("fail"), counter.value == 1 ) } test("upstreamEvaluatedOnlyOnce") { // Even if control-flow reaches the Applyable#apply call more than once, - // it only gets evaluated once due to its lifting out of the Opt{...} block + // it only gets evaluated once due to its lifting out of the TestOpt{...} block val counter = new Counter() - def up = Opt { "lol " + counter() } + def up = TestOpt { "lol " + counter() } def runTwice[T](t: => T) = (t, t) - val down = Opt { runTwice(up()) } + val down = TestOpt { runTwice(up()) } assert( - down == Opt.some(("lol 1", "lol 1")), + down == TestOpt.some(("lol 1", "lol 1")), counter.value == 1 ) } @@ -110,38 +110,38 @@ object ApplicativeTests extends TestSuite { // This required some fiddling with owner chains inside the macro to get // working, so ensure it doesn't regress val counter = new Counter() - def up = Opt { "hello" + counter() } - val down1 = Opt { (() => up())() } - val down2 = Opt { Seq(1, 2, 3).map(n => up() * n) } + def up = TestOpt { "hello" + counter() } + val down1 = TestOpt { (() => up())() } + val down2 = TestOpt { Seq(1, 2, 3).map(n => up() * n) } assert( - down1 == Opt.some("hello1"), - down2 == Opt.some(Seq("hello2", "hello2hello2", "hello2hello2hello2")) + down1 == TestOpt.some("hello1"), + down2 == TestOpt.some(Seq("hello2", "hello2hello2", "hello2hello2hello2")) ) } test("appliesEvaluatedOncePerLexicalCallsite") { // If you have multiple Applyable#apply() lexically in the source code of - // your Opt{...} call, each one gets evaluated once, even if the LHS of each + // your TestOpt{...} call, each one gets evaluated once, even if the LHS of each // apply() call is identical. It's up to the downstream zipMap() // implementation to decide if it wants to dedup them or do other things. val counter = new Counter() - def up = Opt { s"hello${counter()}" } - val down = Opt { Seq(1, 2, 3).map(n => n + up() + up()) } - assert(down == Opt.some(Seq("1hello1hello2", "2hello1hello2", "3hello1hello2"))) + def up = TestOpt { s"hello${counter()}" } + val down = TestOpt { Seq(1, 2, 3).map(n => n + up() + up()) } + assert(down == TestOpt.some(Seq("1hello1hello2", "2hello1hello2", "3hello1hello2"))) } test("appliesEvaluateBeforehand") { - // Every Applyable#apply() within a Opt{...} block evaluates before any + // Every Applyable#apply() within a TestOpt{...} block evaluates before any // other logic within that block, even if they would happen first in the // normal Scala evaluation order val counter = new Counter() - def up = Opt { counter() } - val down = Opt { + def up = TestOpt { counter() } + val down = TestOpt { val res = counter() val one = up() val two = up() val three = up() (res, one, two, three) } - assert(down == Opt.some((4, 1, 2, 3))) + assert(down == TestOpt.some((4, 1, 2, 3))) } } } diff --git a/core/api/test/src/mill/api/Opt.scala b/core/api/test/src/mill/api/Opt.scala deleted file mode 100644 index 2d1dc97100a3..000000000000 --- a/core/api/test/src/mill/api/Opt.scala +++ /dev/null @@ -1,30 +0,0 @@ -package mill.api - -import mill.api.internal.Applicative - -import scala.quoted.* - -case class Opt[+T](self: Option[T]) extends Applicative.Applyable[Opt, T] -object Opt { - def none: Opt[Nothing] = new Opt(None) - def some[T](t: T): Opt[T] = new Opt(Some(t)) - val injectedCtx = "helloooo" - - def ctx()(using c: String): String = c - inline def apply[T](inline t: T): Opt[T] = ${ applyImpl[T]('t) } - - def traverseCtx[I, R](xs: Seq[Opt[I]])(f: (Seq[I], String) => Applicative.Id[R]) - : Opt[R] = { - new Opt( - if (xs.exists(_.self.isEmpty)) None - else Some(f(xs.map(_.self.get).toVector, Opt.injectedCtx)) - ) - } - def applyImpl[T: Type](t: Expr[T])(using - Quotes - ): Expr[Opt[T]] = - Applicative.impl[Opt, Opt, Applicative.Id, T, String]( - (args, fn) => '{ traverseCtx($args)($fn) }, - t - ) -} diff --git a/core/api/test/src/mill/api/TestOpt.scala b/core/api/test/src/mill/api/TestOpt.scala new file mode 100644 index 000000000000..c9ac7d35029a --- /dev/null +++ b/core/api/test/src/mill/api/TestOpt.scala @@ -0,0 +1,30 @@ +package mill.api + +import mill.api.internal.Applicative + +import scala.quoted.* + +case class TestOpt[+T](self: Option[T]) extends Applicative.Applyable[TestOpt, T] +object TestOpt { + def none: TestOpt[Nothing] = new TestOpt(None) + def some[T](t: T): TestOpt[T] = new TestOpt(Some(t)) + val injectedCtx = "helloooo" + + def ctx()(using c: String): String = c + inline def apply[T](inline t: T): TestOpt[T] = ${ applyImpl[T]('t) } + + def traverseCtx[I, R](xs: Seq[TestOpt[I]])(f: (Seq[I], String) => Applicative.Id[R]) + : TestOpt[R] = { + new TestOpt( + if (xs.exists(_.self.isEmpty)) None + else Some(f(xs.map(_.self.get).toVector, TestOpt.injectedCtx)) + ) + } + def applyImpl[T: Type](t: Expr[T])(using + Quotes + ): Expr[TestOpt[T]] = + Applicative.impl[TestOpt, TestOpt, Applicative.Id, T, String]( + (args, fn) => '{ traverseCtx($args)($fn) }, + t + ) +} From 6d5c78114f3d2abf78256b904f36584e67f9e6b3 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 5 Nov 2025 14:14:02 +0100 Subject: [PATCH 02/67] Introduce new mill.api.opt with Opt, OptGroup, Opts and OptSyntax --- .../mill/api/daemon/internal/OptsApi.scala | 13 ++ core/api/src/mill/api/opt/Opt.scala | 93 +++++++++++++++ core/api/src/mill/api/opt/OptGroup.scala | 54 +++++++++ core/api/src/mill/api/opt/OptSyntax.scala | 16 +++ core/api/src/mill/api/opt/Opts.scala | 32 +++++ .../api/test/src/mill/api/opt/OptsTests.scala | 112 ++++++++++++++++++ 6 files changed, 320 insertions(+) create mode 100644 core/api/daemon/src/mill/api/daemon/internal/OptsApi.scala create mode 100644 core/api/src/mill/api/opt/Opt.scala create mode 100644 core/api/src/mill/api/opt/OptGroup.scala create mode 100644 core/api/src/mill/api/opt/OptSyntax.scala create mode 100644 core/api/src/mill/api/opt/Opts.scala create mode 100644 core/api/test/src/mill/api/opt/OptsTests.scala diff --git a/core/api/daemon/src/mill/api/daemon/internal/OptsApi.scala b/core/api/daemon/src/mill/api/daemon/internal/OptsApi.scala new file mode 100644 index 000000000000..37700ac9450e --- /dev/null +++ b/core/api/daemon/src/mill/api/daemon/internal/OptsApi.scala @@ -0,0 +1,13 @@ +package mill.api.daemon.internal + +trait OptsApi { + def toStringSeq: Seq[String] + def value: Seq[OptGroupApi] +} + +trait OptGroupApi { +} + +trait OptApi { + def toString(): String +} diff --git a/core/api/src/mill/api/opt/Opt.scala b/core/api/src/mill/api/opt/Opt.scala new file mode 100644 index 000000000000..e3f9d7305a63 --- /dev/null +++ b/core/api/src/mill/api/opt/Opt.scala @@ -0,0 +1,93 @@ +package mill.api.opt + +import mill.api.daemon.internal.OptApi +import mill.api.JsonFormatters.given + +import scala.annotation.targetName +import scala.language.implicitConversions + +case class Opt private (value: Seq[Opt.OptTypes]) extends OptApi { + override def toString(): String = value.mkString("") + + def map(conv: Opt.OptTypes => Opt.OptTypes): Opt = Opt(value.map(conv)*) + + private def startStrings: Seq[String] = + value.takeWhile(_.isInstanceOf[String]).collect { case s: String => s } + + def startsWith(prefix: String): Boolean = startStrings.mkString("").startsWith(prefix) + + def mapStartString(rep: String => String): Opt = { + val rest = value.dropWhile(_.isInstanceOf[String]) + Opt((rep(startStrings.mkString("")) +: rest)*) + } + + def containsPaths: Boolean = value.exists { + case _: os.Path => true + case _ => false + } +} + +object Opt { + + type OptTypes = (String | os.Path) + + @targetName("applyVarArg") + def apply(value: OptTypes*): Opt = { + // TODO: merge sequential strings + new Opt(value.filter { + case s: String if s.isEmpty => false + case _ => true + }) + } + + /** + * Constructs a path from multiple path elements and a separator string. + * Can be used to render classpaths. + * Each path component will still be handled properly, e.g. mapped according to the current [[MappedPaths]] mapping. + */ + def mkPath(paths: Seq[os.Path], prefix: String = "", sep: String, suffix: String = ""): Opt = { + var needSep = false + Opt( + ( + Seq(prefix) ++ + paths.flatMap { path => + if (needSep) + Seq(sep, path) + else { + needSep = true + Seq(path) + } + } ++ Seq(suffix) + )* + ) + } + + def mkPlatformPath(paths: Seq[os.Path]): Opt = mkPath(paths, sep = java.io.File.pathSeparator) + + given jsonReadWriter: upickle.ReadWriter[Opt] = + upickle.readwriter[Seq[(Option[String], Option[os.Path])]].bimap( + _.value.map { + case path: os.Path => (None, Some(path)) + case str: String => (Some(str), None) + }, + seq => + Opt(seq.map { + case (Some(str), _) => str + case (_, Some(path)) => path + }*) + ) + +// given stringToOpt: Conversion[String, Opt] = (value: String) => Opt(value) +// given osPathToOpt: Conversion[os.Path, Opt] = (value: os.Path) => Opt(value) + +// implicit def IterableToOpt[T](s: Iterable[T])(using f: T => Opt): Opt = +// Opt(s.toSeq.flatMap(f(_).value)) + + + implicit def StringToOpt(s: String): Opt = Opt(s) + + implicit def OsPathToOpt(p: os.Path): Opt = Opt(p) + + implicit def OptToOpt(o: Opt): Opt = o + +} diff --git a/core/api/src/mill/api/opt/OptGroup.scala b/core/api/src/mill/api/opt/OptGroup.scala new file mode 100644 index 000000000000..83fefd77b59f --- /dev/null +++ b/core/api/src/mill/api/opt/OptGroup.scala @@ -0,0 +1,54 @@ +package mill.api.opt + +import mill.api.daemon.internal.OptGroupApi + +import scala.annotation.targetName +import scala.language.implicitConversions + +/** + * A set of options, which are used together + */ +case class OptGroup private (value: Seq[Opt]) extends OptGroupApi + derives upickle.ReadWriter { + override def toString(): String = value.mkString("(", ", ", ")") + + def isEmpty: Boolean = value.isEmpty + + def containsPaths: Boolean = value.exists(_.containsPaths) + + def head: Opt = value.head + + def toStringSeq: Seq[String] = value.map(_.toString()) + + def concat(suffix: OptGroup): OptGroup = new OptGroup(value ++ suffix.value) + + @`inline` final def ++(suffix: OptGroup): OptGroup = concat(suffix) + +} + +object OptGroup { + @targetName("applyVarAar") + def apply(opts: Opt*): OptGroup = new OptGroup(opts) + @targetName("applyIterable") + def apply[T](opts: T*)(using f: T => Opt): OptGroup = new OptGroup(opts.map(f(_))) + + def when(cond: Boolean)(value: Opt*): OptGroup = if (cond) OptGroup(value*) else OptGroup() + +// given optsToOptGroup: Conversion[(OptTypes, OptTypes), OptGroup] = +// (tuple: (OptTypes, OptTypes)) => +// OptGroup(Opt(tuple._1), Opt(tuple._2)) + + implicit def StringToOptGroup(s: String): OptGroup = OptGroup(Seq(Opt(s))) + + implicit def OsPathToOptGroup(p: os.Path): OptGroup = OptGroup(Seq(Opt(p))) + + implicit def OptToOptGroup(o: Opt): OptGroup = OptGroup(Seq(o)) + + implicit def IterableToOptGroup[T](s: Iterable[T])(using f: T => OptGroup): OptGroup = + OptGroup(s.toSeq.flatMap(f(_).value)) + +// implicit def ArrayToOptGroup[T](s: Array[T])(using f: T => OptGroup): OptGroup = +// OptGroup(s.flatMap(f(_).value)) + + +} diff --git a/core/api/src/mill/api/opt/OptSyntax.scala b/core/api/src/mill/api/opt/OptSyntax.scala new file mode 100644 index 000000000000..e0816fcaca07 --- /dev/null +++ b/core/api/src/mill/api/opt/OptSyntax.scala @@ -0,0 +1,16 @@ +package mill.api.opt + +import scala.language.implicitConversions + +implicit class OptSyntax(ctx: StringContext) extends AnyVal { + def opt(opts: Any*): Opt = { + val vals = ctx.parts.take(opts.length).zip(opts).flatMap { case (p, a) => Seq(p, a) } ++ + ctx.parts.drop(opts.length) + + val elems: Seq[(String | os.Path)] = vals.flatMap { + case path: os.Path => Seq(path) + case s => Seq(s.toString).filter(_.nonEmpty) + } + Opt(elems*) + } +} diff --git a/core/api/src/mill/api/opt/Opts.scala b/core/api/src/mill/api/opt/Opts.scala new file mode 100644 index 000000000000..6d5958c09821 --- /dev/null +++ b/core/api/src/mill/api/opt/Opts.scala @@ -0,0 +1,32 @@ +package mill.api.opt + +import mill.api.daemon.internal.OptsApi + +import scala.language.implicitConversions + +case class Opts private (override val value: OptGroup*) extends OptsApi + derives upickle.ReadWriter { + + def toStringSeq: Seq[String] = value.flatMap(_.toStringSeq) + override def toString(): String = value.mkString("Opts(", ", ", ")") + + def concat(suffix: Opts): Opts = Opts(value ++ suffix.value) + @`inline` final def ++(suffix: Opts): Opts = concat(suffix) + + def containsPaths: Boolean = value.exists(_.containsPaths) + + def isEmpty: Boolean = value.isEmpty + def filterGroup(pred: OptGroup => Boolean): Opts = Opts(value.filter(pred)*) + def mapGroup(f: OptGroup => OptGroup): Opts = Opts(value.map(f)*) + def flatMap(f: OptGroup => Seq[OptGroup]): Opts = Opts(value.flatMap(f)*) +} + +object Opts { + def apply(value: OptGroup*): Opts = new Opts(value.filter(!_.isEmpty)) +// @targetName("applyUnion") +// def apply(value: (Opt | OptGroup | Seq[Opt])*): Opts = Opts(value.flatMap { +// case a: Opt => Seq(OptGroup(a)) +// case a: OptGroup => Seq(a) +// case s: Iterable[Opt] => s.map(OptGroup(_)) +// }) +} diff --git a/core/api/test/src/mill/api/opt/OptsTests.scala b/core/api/test/src/mill/api/opt/OptsTests.scala new file mode 100644 index 000000000000..b015bd867f40 --- /dev/null +++ b/core/api/test/src/mill/api/opt/OptsTests.scala @@ -0,0 +1,112 @@ +package mill.api.opt + +import utest.* +import mill.api.opt.* + +class OptsTests extends TestSuite { + + val homeDir = os.home + val workDir = homeDir / "work" + val outDir = workDir / "out" + + val srcDir1 = workDir / "src1" + val srcDir2 = workDir / "src2" + val sources1 = Seq(srcDir1, srcDir2) + + val srcDir3 = workDir / "src3" + val srcDir4 = workDir / "src4" + val sources2 = Seq(srcDir3, srcDir4) + + val plugin1 = homeDir / ".cache" / "plugin1" + + val opts1 = Opts( + // single arg + Opt("-deprecation"), + // implicit single args + "-verbose", + // two args as group + OptGroup("--release", "17"), + // an option including a file via ArgParts + Opt("-Xplugin=", plugin1), + // an option including a file via arg string interpolator + opt"-Xplugin:${plugin1}", + // some files + sources1, + // some files as ArgGroup + OptGroup(sources2*), + // Mixed ArgGroup + OptGroup(opt"--extra", opt"-Xplugin=${plugin1}") ++ OptGroup(sources1*) + ) + + val expectedOpts1 = Opts( + Opt("-deprecation"), + Opt("-verbose"), + OptGroup( + Opt("--release"), + Opt("17") + ), + Opt("-Xplugin=", plugin1), + Opt("-Xplugin:", plugin1), + Opt(srcDir1), + Opt(srcDir2), + Opt(srcDir3), + Opt(srcDir4), + OptGroup( + Opt("--extra"), + Opt("-Xplugin=", plugin1), + Opt(srcDir1), + Opt(srcDir2) + ) + ) + + val expectedSeq1 = Seq( + "-deprecation", + "-verbose", + "--release", + "17", + s"-Xplugin=${plugin1.toString()}", + // an option including a file via arg string interpolator + s"-Xplugin:${plugin1.toString()}" + ) ++ + sources1.map(_.toString()) + ++ + sources2.map(_.toString()) + ++ + Seq( + "--extra", + s"-Xplugin=${plugin1.toString()}" + ) ++ + sources1.map(_.toString()) + + override def tests: Tests = Tests { + test("structure") { + assert(opts1 == expectedOpts1) + } + test("toStringSeq") { + val str = opts1.toStringSeq + assert(str == expectedSeq1) + } + test("jsonify") { + test("without-mapping") { + val json = upickle.write(opts1) + assertGoldenLiteral( + json, + "{\"value\":[{\"value\":[[[\"-deprecation\",null]],[[\"-verbose\",null]],[[\"--release\",null]],[[\"17\",null]],[[\"-Xplugin=\",null],[null,\"/home/lefou/.cache/plugin1\"]],[[\"-Xplugin:\",null],[null,\"/home/lefou/.cache/plugin1\"]],[[null,\"/home/lefou/work/src1\"]],[[null,\"/home/lefou/work/src2\"]],[[null,\"/home/lefou/work/src3\"]],[[null,\"/home/lefou/work/src4\"]],[[\"--extra\",null]],[[\"-Xplugin=\",null],[null,\"/home/lefou/.cache/plugin1\"]],[[null,\"/home/lefou/work/src1\"]],[[null,\"/home/lefou/work/src2\"]]]}]}" + ) + assert(json.split("\\Q$HOME\\E").size == 1) + val back = upickle.read[Opts](json) + assert(opts1 == back) + } +// test("with-mapping-home") { +// val json = upickle.write(opts1) +// assertGoldenLiteral( +// json, +// "{\"value\":[{\"value\":[[[\"-deprecation\",null]],[[\"-verbose\",null]],[[\"--release\",null]],[[\"17\",null]],[[\"-Xplugin=\",null],[null,\"/home/lefou/.cache/plugin1\"]],[[\"-Xplugin:\",null],[null,\"/home/lefou/.cache/plugin1\"]],[[null,\"/home/lefou/work/src1\"]],[[null,\"/home/lefou/work/src2\"]],[[null,\"/home/lefou/work/src3\"]],[[null,\"/home/lefou/work/src4\"]],[[\"--extra\",null]],[[\"-Xplugin=\",null],[null,\"/home/lefou/.cache/plugin1\"]],[[null,\"/home/lefou/work/src1\"]],[[null,\"/home/lefou/work/src2\"]]]}]}" +// ) +// assert(json.split("\\Q$HOME\\E").size == 10) +// val back = upickle.read[Opts](json) +// assert(opts1 == back) +// } + } + } +} From 7fbd722fb07b44dcaef4b5d00ceae9454fa75996 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 5 Nov 2025 14:16:09 +0100 Subject: [PATCH 03/67] WIP Replace `Seq[String]` used for options by `mill.api.opt.Opts` --- .../jmh/src/mill/contrib/jmh/JmhModule.scala | 2 +- .../contrib/scoverage/ScoverageModule.scala | 21 ++++--- .../api/daemon/internal/JavaModuleApi.scala | 4 +- .../internal/bsp/BspJavaModuleApi.scala | 14 +++-- .../daemon/internal/bsp/BspRunModuleApi.scala | 10 ++-- .../androidlib/AndroidAppKotlinModule.scala | 19 ++++--- .../mill/androidlib/AndroidKotlinModule.scala | 29 +++++----- .../src/mill/androidlib/AndroidModule.scala | 4 +- .../androidlib/hilt/AndroidHiltSupport.scala | 11 ++-- .../src/mill/javalib/AssemblyModule.scala | 13 +++-- .../javalib/src/mill/javalib/JavaModule.scala | 24 +++----- .../src/mill/javalib/JavacOptions.scala | 9 +++ libs/javalib/src/mill/javalib/RunModule.scala | 19 +++---- .../mill/javalib/SemanticDbJavaModule.scala | 29 ++++++---- .../javalib/src/mill/javalib/TestModule.scala | 19 +++---- .../src/mill/javalib/bsp/BspJavaModule.scala | 18 +++--- .../src/mill/javalib/bsp/BspRunModule.scala | 10 ++-- .../javalib/errorprone/ErrorProneModule.scala | 19 ++++--- .../src/mill/javalib/idea/GenIdeaModule.scala | 10 ++-- .../javalib/repackage/RepackageModule.scala | 6 +- .../test/src/mill/javalib/LauncherTests.scala | 3 +- .../javalib/errorprone/ErrorProneTests.scala | 10 ++-- .../src/mill/kotlinlib/KotlinModule.scala | 46 ++++++++-------- .../src/mill/kotlinlib/KotlincOptions.scala | 7 +++ .../mill/kotlinlib/js/KotlinJsModule.scala | 27 ++++----- .../mill/kotlinlib/kover/KoverModule.scala | 13 ++--- .../src/mill/kotlinlib/ksp/KspModule.scala | 26 ++++----- .../contrib/kover/KoverModuleTests.scala | 5 +- .../src/mill/scalajslib/ScalaJSModule.scala | 9 +-- .../mill/scalajslib/CompileLinkTests.scala | 10 ++-- .../src/mill/scalalib/ScalaModule.scala | 51 +++++++++-------- .../src/mill/scalalib/ScalacOptions.scala | 9 +++ .../mill/scalalib/idea/GenIdeaModule.scala | 1 + .../src/mill/scalalib/CrossVersionTests.scala | 3 +- .../src/mill/scalalib/HelloWorldTests.scala | 21 +++---- .../mill/scalalib/ScalaColorOutputTests.scala | 3 +- .../src/mill/scalalib/ScalaFlagsTests.scala | 5 +- .../src/mill/scalalib/ScalaMacrosTests.scala | 3 +- .../mill/scalalib/ScalaScaladocTests.scala | 15 ++--- .../scalanativelib/ScalaNativeModule.scala | 10 ++-- .../mill/scalanativelib/CompileRunTests.scala | 3 +- mill-itest-plugin.adoc | 55 +++++++++++++++++++ .../mill/bsp/worker/MillJavaBuildServer.scala | 2 +- .../mill/bsp/worker/MillJvmBuildServer.scala | 30 +++++----- .../bsp/worker/MillScalaBuildServer.scala | 10 ++-- .../src/mill/meta/MillBuildRootModule.scala | 13 ++--- 46 files changed, 393 insertions(+), 287 deletions(-) create mode 100644 libs/javalib/src/mill/javalib/JavacOptions.scala create mode 100644 libs/kotlinlib/src/mill/kotlinlib/KotlincOptions.scala create mode 100644 libs/scalalib/src/mill/scalalib/ScalacOptions.scala create mode 100644 mill-itest-plugin.adoc diff --git a/contrib/jmh/src/mill/contrib/jmh/JmhModule.scala b/contrib/jmh/src/mill/contrib/jmh/JmhModule.scala index 6cb760182bfd..44fc0a52bb8d 100644 --- a/contrib/jmh/src/mill/contrib/jmh/JmhModule.scala +++ b/contrib/jmh/src/mill/contrib/jmh/JmhModule.scala @@ -77,7 +77,7 @@ trait JmhModule extends JavaModule { def generateBenchmarkSources = Task { val dest = Task.ctx().dest - val forkedArgs = forkArgs().toSeq + val forkedArgs = forkArgs().toStringSeq val sourcesDir = dest / "jmh_sources" val resourcesDir = dest / "jmh_resources" diff --git a/contrib/scoverage/src/mill/contrib/scoverage/ScoverageModule.scala b/contrib/scoverage/src/mill/contrib/scoverage/ScoverageModule.scala index 522db75abc4f..a624711b14fa 100644 --- a/contrib/scoverage/src/mill/contrib/scoverage/ScoverageModule.scala +++ b/contrib/scoverage/src/mill/contrib/scoverage/ScoverageModule.scala @@ -1,10 +1,9 @@ package mill.contrib.scoverage import coursier.Repository -import mill._ -import mill.api.{PathRef} -import mill.api.BuildCtx -import mill.api.{Result} +import mill.* +import mill.api.{BuildCtx, PathRef, Result} +import mill.api.opt.* import mill.contrib.scoverage.api.ScoverageReportWorkerApi2.ReportType import mill.util.BuildInfo import mill.javalib.api.JvmWorkerUtil @@ -168,18 +167,18 @@ trait ScoverageModule extends ScalaModule { outer: ScalaModule => Task { outer.scalacPluginMvnDeps() ++ outer.scoveragePluginDeps() } /** Add the scoverage specific plugin settings (`dataDir`). */ - override def scalacOptions: T[Seq[String]] = + override def scalacOptions: T[Opts] = Task { val extras = if (isScala3()) { - Seq( - s"-coverage-out:${data().path.toIO.getPath()}", - s"-sourceroot:${BuildCtx.workspaceRoot}" + Opts( + opt"-coverage-out:${data().path}", + opt"-sourceroot:${BuildCtx.workspaceRoot}" ) } else { - Seq( - s"-P:scoverage:dataDir:${data().path.toIO.getPath()}", - s"-P:scoverage:sourceRoot:${BuildCtx.workspaceRoot}" + Opts( + opt"-P:scoverage:dataDir:${data().path}", + opt"-P:scoverage:sourceRoot:${BuildCtx.workspaceRoot}" ) } diff --git a/core/api/daemon/src/mill/api/daemon/internal/JavaModuleApi.scala b/core/api/daemon/src/mill/api/daemon/internal/JavaModuleApi.scala index 2c94a5baebb9..73f49fdc6b18 100644 --- a/core/api/daemon/src/mill/api/daemon/internal/JavaModuleApi.scala +++ b/core/api/daemon/src/mill/api/daemon/internal/JavaModuleApi.scala @@ -13,8 +13,8 @@ trait JavaModuleApi extends ModuleApi with GenIdeaModuleApi { def transitiveModuleCompileModuleDeps: Seq[JavaModuleApi] - def javacOptions: TaskApi[Seq[String]] - def mandatoryJavacOptions: TaskApi[Seq[String]] + def javacOptions: TaskApi[OptsApi] + def mandatoryJavacOptions: TaskApi[OptsApi] // BSP Tasks that sometimes need to be customized diff --git a/core/api/daemon/src/mill/api/daemon/internal/bsp/BspJavaModuleApi.scala b/core/api/daemon/src/mill/api/daemon/internal/bsp/BspJavaModuleApi.scala index a83955d8ae50..27971f63c998 100644 --- a/core/api/daemon/src/mill/api/daemon/internal/bsp/BspJavaModuleApi.scala +++ b/core/api/daemon/src/mill/api/daemon/internal/bsp/BspJavaModuleApi.scala @@ -1,6 +1,6 @@ package mill.api.daemon.internal.bsp -import mill.api.daemon.internal.{EvaluatorApi, ModuleApi, TaskApi} +import mill.api.daemon.internal.{EvaluatorApi, ModuleApi, OptApi, OptsApi, TaskApi} import java.nio.file.Path @@ -34,7 +34,7 @@ trait BspJavaModuleApi extends ModuleApi { ) : TaskApi[EvaluatorApi => ( classesPath: Path, - javacOptions: Seq[String], + javacOptions: OptsApi, classpath: Seq[String] )] @@ -42,13 +42,17 @@ trait BspJavaModuleApi extends ModuleApi { needsToMergeResourcesIntoCompileDest: Boolean, enableJvmCompileClasspathProvider: Boolean, clientWantsSemanticDb: Boolean - ): TaskApi[(Seq[String], EvaluatorApi => Seq[String], EvaluatorApi => java.nio.file.Path)] + ): TaskApi[( + scalacOptionsTask: OptsApi, + compileClasspathTask: EvaluatorApi => Seq[String], + classPathTask: EvaluatorApi => java.nio.file.Path + )] private[mill] def bspBuildTargetScalaMainClasses : TaskApi[( classes: Seq[String], - forkArgs: Seq[String], - forkEnv: Map[String, String] + forkArgs: OptsApi, + forkEnv: Map[String, OptApi] )] private[mill] def bspLoggingTest: TaskApi[Unit] diff --git a/core/api/daemon/src/mill/api/daemon/internal/bsp/BspRunModuleApi.scala b/core/api/daemon/src/mill/api/daemon/internal/bsp/BspRunModuleApi.scala index 62d1a7d2a128..86f62b63f7f0 100644 --- a/core/api/daemon/src/mill/api/daemon/internal/bsp/BspRunModuleApi.scala +++ b/core/api/daemon/src/mill/api/daemon/internal/bsp/BspRunModuleApi.scala @@ -1,6 +1,6 @@ package mill.api.daemon.internal.bsp -import mill.api.daemon.internal.{ModuleApi, TaskApi} +import mill.api.daemon.internal.{ModuleApi, OptApi, OptsApi, TaskApi} import java.nio.file.Path @@ -10,18 +10,18 @@ trait BspRunModuleApi extends ModuleApi { private[mill] def bspJvmRunEnvironment: TaskApi[( runClasspath: Seq[Path], - forkArgs: Seq[String], + forkArgs: OptsApi, forkWorkingDir: Path, - forkEnv: Map[String, String], + forkEnv: Map[String, OptApi], mainClass: Option[String], localMainClasses: Seq[String] )] private[mill] def bspJvmTestEnvironment: TaskApi[( runClasspath: Seq[Path], - forkArgs: Seq[String], + forkArgs: OptsApi, forkWorkingDir: Path, - forkEnv: Map[String, String], + forkEnv: Map[String, OptApi], mainClass: Option[String], testEnvVars: Option[( mainClass: String, diff --git a/libs/androidlib/src/mill/androidlib/AndroidAppKotlinModule.scala b/libs/androidlib/src/mill/androidlib/AndroidAppKotlinModule.scala index b94d379263fd..5e976318d626 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidAppKotlinModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidAppKotlinModule.scala @@ -2,6 +2,7 @@ package mill.androidlib import coursier.params.ResolutionParams import mill.api.{ModuleRef, PathRef, Task} +import mill.api.opt.* import mill.kotlinlib.{Dep, DepSyntax} import mill.javalib.TestModule.Junit5 import mill.javalib.{JavaModule, TestModule} @@ -293,7 +294,7 @@ trait AndroidAppKotlinModule extends AndroidKotlinModule, AndroidAppModule { out PathRef(diffImageDir) } - override def forkArgs: T[Seq[String]] = super.forkArgs() ++ testJvmArgs() + override def forkArgs: T[Opts] = super.forkArgs() ++ testJvmArgs() override def runClasspath: T[Seq[PathRef]] = super.runClasspath() ++ androidPreviewScreenshotTestEngineClasspath() ++ compileClasspath() @@ -315,18 +316,18 @@ trait AndroidAppKotlinModule extends AndroidKotlinModule, AndroidAppModule { out As defined in [[https://android.googlesource.com/platform/tools/base/+/61923408e5f7dc20f0840844597f9dde17453a0f/preview/screenshot/screenshot-test-gradle-plugin/src/main/java/com/android/compose/screenshot/tasks/PreviewScreenshotValidationTask.kt?#84]] */ - private def testJvmArgs: T[Seq[String]] = Task { + private def testJvmArgs: T[Opts] = Task { val params = Map( - "previews-discovered" -> androidDiscoveredPreviews().previewsDiscoveredJsonFile.path.toString(), - "referenceImageDirPath" -> screenshotResults().path.toString(), - "diffImageDirPath" -> diffImageDirPath().path.toString, - "renderResultsFilePath" -> androidScreenshotGeneratedResults().path.toString, - "renderTaskOutputDir" -> screenshotResults().path.toString(), - "resultsDirPath" -> androidScreenshotTestResultDir().path.toString(), + "previews-discovered" -> androidDiscoveredPreviews().previewsDiscoveredJsonFile.path, + "referenceImageDirPath" -> screenshotResults().path, + "diffImageDirPath" -> diffImageDirPath().path, + "renderResultsFilePath" -> androidScreenshotGeneratedResults().path, + "renderTaskOutputDir" -> screenshotResults().path, + "resultsDirPath" -> androidScreenshotTestResultDir().path, "threshold" -> androidScreenshotTestDiffThreshold.toString ) - params.map { case (k, v) => s"$JvmTestArg$k=$v" }.toSeq + Opts(params.map { case (k, v) => opt"$JvmTestArg$k=$v" }) } private val JvmTestArg = "-Dcom.android.tools.preview.screenshot.junit.engine." diff --git a/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala b/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala index c71449a631c6..0c23379dbe77 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala @@ -2,15 +2,11 @@ package mill.androidlib import mill.* import mill.api.{ModuleRef, PathRef, Result} +import mill.api.opt.* import mill.javalib.{CoursierModule, Dep} -import mill.kotlinlib.{Dep, DepSyntax, KotlinModule} +import mill.kotlinlib.{Dep, DepSyntax, KotlinModule, KotlincOptions} import mill.{T, Task} -import mill.androidlib.databinding.{ - AndroidDataBindingWorker, - GenerateBindingSourcesArgs, - ProcessResourcesArgs, - AndroidDataBindingWorkerModule -} +import mill.androidlib.databinding.{AndroidDataBindingWorker, AndroidDataBindingWorkerModule, GenerateBindingSourcesArgs, ProcessResourcesArgs} import mill.util.Jvm // TODO expose Compose configuration options @@ -185,21 +181,26 @@ trait AndroidKotlinModule extends KotlinModule with AndroidModule { outer => * If this module has any module dependencies, we need to tell the kotlin compiler to * handle the compiled output as a friend path so top level declarations are visible. */ - def kotlincFriendPaths: T[Option[String]] = Task { + def kotlincFriendPaths: T[Opts] = Task { val compiledCodePaths = Task.traverse(transitiveModuleCompileModuleDeps)(m => Task.Anon { Seq(m.compile().classes.path) } )().flatten - val friendlyPathFlag: Option[String] = - compiledCodePaths.headOption.map(_ => s"-Xfriend-paths=${compiledCodePaths.mkString(",")}") - - friendlyPathFlag + Opts( + OptGroup.when(compiledCodePaths.nonEmpty)( + Opt.mkPath( + compiledCodePaths, + prefix = KotlincOptions.`-Xfriend-paths`, + sep = KotlincOptions.friendPathSeparator + ) + ) + ) } - override def kotlincOptions: T[Seq[String]] = Task { - super.kotlincOptions() ++ kotlincFriendPaths().toSeq + override def kotlincOptions: T[Opts] = Task { + super.kotlincOptions() ++ kotlincFriendPaths() } def kspDependencyResolver: Task[CoursierModule.Resolver] = Task.Anon { diff --git a/libs/androidlib/src/mill/androidlib/AndroidModule.scala b/libs/androidlib/src/mill/androidlib/AndroidModule.scala index c754872fa69e..0e93003dd768 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidModule.scala @@ -516,7 +516,7 @@ trait AndroidModule extends JavaModule { outer => * The Java compiled classes of [[androidResources]] */ def androidCompiledRClasses: T[CompilationResult] = Task(persistent = true) { - val jOpts = JavaCompilerOptions.split(javacOptions() ++ mandatoryJavacOptions()) + val jOpts = JavaCompilerOptions.split(javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) val worker = jvmWorker().internalWorker() worker.apply( ZincCompileJava( @@ -728,7 +728,7 @@ trait AndroidModule extends JavaModule { outer => val rJar = Task.dest / "R.jar" - val jOpts = JavaCompilerOptions.split(javacOptions() ++ mandatoryJavacOptions()) + val jOpts = JavaCompilerOptions.split(javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) val worker = jvmWorker().internalWorker() val classesDest = worker .apply( diff --git a/libs/androidlib/src/mill/androidlib/hilt/AndroidHiltSupport.scala b/libs/androidlib/src/mill/androidlib/hilt/AndroidHiltSupport.scala index 506dee24e9d7..7186bf86c154 100644 --- a/libs/androidlib/src/mill/androidlib/hilt/AndroidHiltSupport.scala +++ b/libs/androidlib/src/mill/androidlib/hilt/AndroidHiltSupport.scala @@ -1,6 +1,7 @@ package mill.androidlib.hilt import mill.androidlib.AndroidKotlinModule +import mill.api.opt.* import mill.api.{ModuleRef, PathRef} import mill.kotlinlib.ksp.KspModule import mill.javalib.Dep @@ -24,12 +25,12 @@ import mill.{T, Task} @mill.api.experimental trait AndroidHiltSupport extends KspModule, AndroidKotlinModule { - override def kspProcessorOptions: T[Map[String, String]] = Task { + override def kspProcessorOptions: T[Map[String, Opt]] = Task { super.kspProcessorOptions() ++ Map( - "dagger.fastInit" -> "enabled", - "dagger.hilt.android.internal.disableAndroidSuperclassValidation" -> "true", - "dagger.hilt.android.internal.projectType" -> "APP", - "dagger.hilt.internal.useAggregatingRootProcessor" -> "true" + "dagger.fastInit" -> opt"enabled", + "dagger.hilt.android.internal.disableAndroidSuperclassValidation" -> opt"true", + "dagger.hilt.android.internal.projectType" -> opt"APP", + "dagger.hilt.internal.useAggregatingRootProcessor" -> opt"true" ) } diff --git a/libs/javalib/src/mill/javalib/AssemblyModule.scala b/libs/javalib/src/mill/javalib/AssemblyModule.scala index a3ef4a185f4d..8e04af1cadad 100644 --- a/libs/javalib/src/mill/javalib/AssemblyModule.scala +++ b/libs/javalib/src/mill/javalib/AssemblyModule.scala @@ -4,6 +4,7 @@ import mill.api.PathRef import mill.api.Result import mill.util.JarManifest import mill.api.* +import mill.api.opt.* import mill.api.Task.Simple as T import mill.javalib.Assembly.UnopenedInputStream import mill.util.Jvm @@ -16,17 +17,17 @@ trait AssemblyModule extends mill.api.Module { def finalMainClassOpt: T[Either[String, String]] - def forkArgs: T[Seq[String]] + def forkArgs: T[Opts] /** * Similar to `forkArgs` but only applies to the `sh` launcher script */ - def forkShellArgs: T[Seq[String]] = Task { Seq.empty[String] } + def forkShellArgs: T[Opts] = Task { Opts() } /** * Similar to `forkArgs` but only applies to the `bat` launcher script */ - def forkCmdArgs: T[Seq[String]] = Task { Seq.empty[String] } + def forkCmdArgs: T[Opts] = Task { Opts() } /** * Creates a manifest representation which can be modified or replaced @@ -54,10 +55,10 @@ trait AssemblyModule extends mill.api.Module { mainClass = cls, shellClassPath = Seq("$0"), cmdClassPath = Seq("%~dpnx0"), - jvmArgs = forkArgs(), + jvmArgs = forkArgs().toStringSeq, shebang = false, - shellJvmArgs = forkShellArgs(), - cmdJvmArgs = forkCmdArgs() + shellJvmArgs = forkShellArgs().toStringSeq, + cmdJvmArgs = forkCmdArgs().toStringSeq ) } } diff --git a/libs/javalib/src/mill/javalib/JavaModule.scala b/libs/javalib/src/mill/javalib/JavaModule.scala index aaab34c76938..bde994b4975a 100644 --- a/libs/javalib/src/mill/javalib/JavaModule.scala +++ b/libs/javalib/src/mill/javalib/JavaModule.scala @@ -7,19 +7,13 @@ import coursier.params.ResolutionParams import coursier.parse.{JavaOrScalaModule, ModuleParser} import coursier.util.{EitherT, ModuleMatcher, Monad} import mainargs.Flag -import mill.api.{MillException, Result} +import mill.api.{DefaultTaskModule, MillException, ModuleRef, PathRef, Result, Segment, Task, TaskCtx} +import mill.api.opt.* import mill.api.daemon.internal.{EvaluatorApi, JavaModuleApi, internal} -import mill.api.daemon.internal.bsp.{ - BspBuildTarget, - BspJavaModuleApi, - BspModuleApi, - BspUri, - JvmBuildTarget -} +import mill.api.daemon.internal.bsp.{BspBuildTarget, BspJavaModuleApi, BspModuleApi, BspUri, JvmBuildTarget} import mill.api.daemon.internal.eclipse.GenEclipseInternalApi import mill.javalib.* import mill.api.daemon.internal.idea.GenIdeaInternalApi -import mill.api.{DefaultTaskModule, ModuleRef, PathRef, Segment, Task, TaskCtx} import mill.javalib.api.CompilationResult import mill.javalib.api.internal.{JavaCompilerOptions, ZincCompileJava} import mill.javalib.bsp.{BspJavaModule, BspModule} @@ -263,12 +257,12 @@ trait JavaModule /** * Options to pass to the java compiler */ - override def javacOptions: T[Seq[String]] = Task { Seq.empty[String] } + override def javacOptions: T[Opts] = Task { Opts() } /** * Additional options for the java compiler derived from other module settings. */ - override def mandatoryJavacOptions: T[Seq[String]] = Task { Seq.empty[String] } + override def mandatoryJavacOptions: T[Opts] = Task { Opts() } /** * The direct dependencies of this module. @@ -863,7 +857,7 @@ trait JavaModule val jOpts = JavaCompilerOptions.split(Seq( "-s", compileGenSources.toString - ) ++ javacOptions() ++ mandatoryJavacOptions()) + ) ++ javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) val worker = jvmWorker().internalWorker() @@ -1105,7 +1099,7 @@ trait JavaModule * You should not set the `-d` setting for specifying the target directory, * as that is done in the [[docJar]] task. */ - def javadocOptions: T[Seq[String]] = Task { Seq[String]() } + def javadocOptions: T[Opts] = Task { Opts() } /** * Directories to be processed by the API documentation tool. @@ -1150,7 +1144,7 @@ trait JavaModule classPath.mkString(java.io.File.pathSeparator) ) - val options = javadocOptions() ++ + val options = javadocOptions().toStringSeq ++ Seq("-d", javadocDir.toString) ++ cpOptions ++ files.map(_.toString) @@ -1228,7 +1222,7 @@ trait JavaModule val cmd = Seq(Jvm.jdkTool("jshell", javaHome().map(_.path))) ++ jshellArgs os.call( cmd = cmd, - env = allForkEnv(), + env = allForkEnv().view.mapValues(_.toString).toMap, cwd = forkWorkingDir(), stdin = os.Inherit, stdout = os.Inherit diff --git a/libs/javalib/src/mill/javalib/JavacOptions.scala b/libs/javalib/src/mill/javalib/JavacOptions.scala new file mode 100644 index 000000000000..89d5d13aef40 --- /dev/null +++ b/libs/javalib/src/mill/javalib/JavacOptions.scala @@ -0,0 +1,9 @@ +package mill.javalib + +object JavacOptions { + + val `-target` = "-target" + val `-source` = "-source" + val `-deprecation` = "-deprecation" + +} diff --git a/libs/javalib/src/mill/javalib/RunModule.scala b/libs/javalib/src/mill/javalib/RunModule.scala index cec40c553c6d..5f3680a8e600 100644 --- a/libs/javalib/src/mill/javalib/RunModule.scala +++ b/libs/javalib/src/mill/javalib/RunModule.scala @@ -2,14 +2,13 @@ package mill.javalib import java.lang.reflect.Modifier import scala.util.control.NonFatal -import mill.api.BuildCtx +import mill.api.{BuildCtx, ModuleCtx, ModuleRef, PathRef, Result, Task, TaskCtx} +import mill.api.opt.* import mainargs.arg -import mill.api.Result import mill.api.daemon.internal.RunModuleApi import mill.api.daemon.internal.bsp.BspRunModuleApi import mill.constants.DaemonFiles import mill.api.JsonFormatters.pathReadWrite -import mill.api.{ModuleCtx, ModuleRef, PathRef, Task, TaskCtx} import mill.javalib.bsp.BspRunModule import mill.javalib.classgraph.ClassgraphWorkerModule import mill.util.Jvm @@ -36,21 +35,21 @@ trait RunModule extends WithJvmWorkerModule with RunModuleApi { /** * Any command-line parameters you want to pass to the forked JVM. */ - def forkArgs: T[Seq[String]] = Task { Seq.empty[String] } + def forkArgs: T[Opts] = Task { Opts() } /** * Any environment variables you want to pass to the forked JVM. */ - def forkEnv: T[Map[String, String]] = Task { Map.empty[String, String] } + def forkEnv: T[Map[String, Opt]] = Task { Map.empty[String, Opt] } /** * Environment variables to pass to the forked JVM. * * Includes [[forkEnv]] and the variables defined by Mill itself. */ - def allForkEnv: T[Map[String, String]] = Task { + def allForkEnv: T[Map[String, Opt]] = Task { forkEnv() ++ Map( - EnvVars.MILL_WORKSPACE_ROOT -> BuildCtx.workspaceRoot.toString + EnvVars.MILL_WORKSPACE_ROOT -> Opt(BuildCtx.workspaceRoot) ) } @@ -171,8 +170,8 @@ trait RunModule extends WithJvmWorkerModule with RunModuleApi { new RunModule.RunnerImpl( finalMainClassOpt(), runClasspath().map(_.path), - forkArgs(), - allForkEnv(), + forkArgs().toStringSeq, + allForkEnv().view.mapValues(_.toString()).toMap, runUseArgsFile(), javaHome().map(_.path), propagateEnv() @@ -247,7 +246,7 @@ trait RunModule extends WithJvmWorkerModule with RunModuleApi { Seq(classpathJar) } - Jvm.createLauncher(finalMainClass(), launchClasspath, forkArgs(), Task.dest) + Jvm.createLauncher(finalMainClass(), launchClasspath, forkArgs().toStringSeq, Task.dest) } /** diff --git a/libs/javalib/src/mill/javalib/SemanticDbJavaModule.scala b/libs/javalib/src/mill/javalib/SemanticDbJavaModule.scala index e7c39b07906f..1b593a3d7575 100644 --- a/libs/javalib/src/mill/javalib/SemanticDbJavaModule.scala +++ b/libs/javalib/src/mill/javalib/SemanticDbJavaModule.scala @@ -1,7 +1,16 @@ package mill.javalib -import mill.api.{BuildCtx, Discover, ExternalModule, ModuleRef, PathRef, Result, experimental} +import mill.api.{ + BuildCtx, + Discover, + ExternalModule, + ModuleRef, + PathRef, + Result, + experimental +} import mill.api.daemon.internal.SemanticDbJavaModuleApi +import mill.api.opt.* import mill.constants.CodeGenConstants import mill.util.BuildInfo import mill.javalib.api.{CompilationResult, JvmWorkerUtil} @@ -34,8 +43,8 @@ trait SemanticDbJavaModule extends CoursierModule with SemanticDbJavaModuleApi } private[mill] def bspBuildTarget: BspBuildTarget - def javacOptions: T[Seq[String]] - def mandatoryJavacOptions: T[Seq[String]] + def javacOptions: T[Opts] + def mandatoryJavacOptions: T[Opts] private[mill] def compileClasspathTask(compileFor: CompileFor): Task[Seq[PathRef]] def moduleDeps: Seq[JavaModule] @@ -99,11 +108,11 @@ trait SemanticDbJavaModule extends CoursierModule with SemanticDbJavaModuleApi /** * Scalac options to activate the compiler plugins. */ - protected def semanticDbEnablePluginScalacOptions: T[Seq[String]] = Task { + protected def semanticDbEnablePluginScalacOptions: T[Opts] = Task { val resolvedJars = defaultResolver().classpath( semanticDbPluginMvnDeps().map(_.exclude("*" -> "*")) ) - resolvedJars.iterator.map(jar => s"-Xplugin:${jar.path}").toSeq + Opts(resolvedJars.map(jar => opt"-Xplugin:${jar.path}")) } protected def semanticDbPluginClasspath: T[Seq[PathRef]] = Task { @@ -118,7 +127,7 @@ trait SemanticDbJavaModule extends CoursierModule with SemanticDbJavaModuleApi val javacOpts = SemanticDbJavaModule.javacOptionsTask( javacOptions() ++ mandatoryJavacOptions(), semanticDbJavaVersion() - ) + ).toStringSeq Task.log.debug(s"effective javac options: ${javacOpts}") @@ -225,15 +234,15 @@ object SemanticDbJavaModule extends ExternalModule with CoursierModule { )) } - def javacOptionsTask(javacOptions: Seq[String], semanticDbJavaVersion: String)(using + def javacOptionsTask(javacOptions: Opts, semanticDbJavaVersion: String)(using ctx: mill.api.TaskCtx - ): Seq[String] = { + ): Opts = { val isNewEnough = Version.isAtLeast(semanticDbJavaVersion, "0.8.10")(using Version.IgnoreQualifierOrdering) val buildTool = s" -build-tool:${if (isNewEnough) "mill" else "sbt"}" val verbose = if (ctx.log.debugEnabled) " -verbose" else "" - javacOptions ++ Seq( - s"-Xplugin:semanticdb -sourceroot:${ctx.workspace} -targetroot:${ctx.dest / "classes"}${buildTool}${verbose}" + javacOptions ++ Opts( + opt"-Xplugin:semanticdb -sourceroot:${BuildCtx.workspaceRoot} -targetroot:${ctx.dest / "classes"}${buildTool}${verbose}" ) } diff --git a/libs/javalib/src/mill/javalib/TestModule.scala b/libs/javalib/src/mill/javalib/TestModule.scala index ce2559fb03db..eee0f367a0ab 100644 --- a/libs/javalib/src/mill/javalib/TestModule.scala +++ b/libs/javalib/src/mill/javalib/TestModule.scala @@ -1,14 +1,11 @@ package mill.javalib import mill.T -import mill.api.Result +import mill.api.{DefaultTaskModule, PathRef, Result, Task, TaskCtx} +import mill.api.opt.* import mill.api.daemon.internal.TestModuleApi import mill.api.daemon.internal.TestReporter import mill.api.daemon.internal.bsp.{BspBuildTarget, BspModuleApi} -import mill.api.PathRef -import mill.api.Task -import mill.api.TaskCtx -import mill.api.DefaultTaskModule import mill.javalib.bsp.BspModule import mill.api.JsonFormatters.given import mill.constants.EnvVars @@ -216,9 +213,9 @@ trait TestModule */ def testSandboxWorkingDir: T[Boolean] = true - override def allForkEnv: T[Map[String, String]] = Task { + override def allForkEnv: T[Map[String, Opt]] = Task { super.allForkEnv() ++ Map( - EnvVars.MILL_TEST_RESOURCE_DIR -> resources().iterator.map(_.path).mkString(";") + EnvVars.MILL_TEST_RESOURCE_DIR -> Opt.mkPath(resources().map(_.path), sep = ";") ) } @@ -232,7 +229,7 @@ trait TestModule Task.Anon { val testModuleUtil = new TestModuleUtil( testUseArgsFile(), - forkArgs(), + forkArgs().toStringSeq, globSelectors(), jvmWorker().scalalibClasspath(), resources(), @@ -242,7 +239,7 @@ trait TestModule args(), testForkGrouping(), jvmWorker().testrunnerEntrypointClasspath(), - allForkEnv(), + allForkEnv().view.mapValues(_.toString()).toMap, testSandboxWorkingDir(), forkWorkingDir(), testReportXml(), @@ -453,7 +450,7 @@ object TestModule { def specs2Version: T[String] = Task { "" } override def testFramework: T[String] = "org.specs2.runner.Specs2Framework" override def scalacOptions = Task { - super.scalacOptions() ++ Seq("-Yrangepos") + super.scalacOptions() ++ Opts("-Yrangepos") } override def mandatoryMvnDeps: T[Seq[Dep]] = Task { super.mandatoryMvnDeps() ++ @@ -577,7 +574,7 @@ object TestModule { } trait ScalaModuleBase extends mill.Module { - def scalacOptions: T[Seq[String]] = Seq() + def scalacOptions: T[Opts] = Opts() } } diff --git a/libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala b/libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala index e112c81b6fa4..ed96f47f3477 100644 --- a/libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala +++ b/libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala @@ -1,11 +1,11 @@ package mill.javalib.bsp import java.nio.file.Path - import mill.api.daemon.internal.bsp.BspJavaModuleApi import mill.Task -import mill.api.daemon.internal.{EvaluatorApi, TaskApi, internal} +import mill.api.daemon.internal.{EvaluatorApi, OptsApi, TaskApi, internal} import mill.api.ModuleCtx +import mill.api.opt.* import mill.javalib.{JavaModule, SemanticDbJavaModule} import mill.api.JsonFormatters.given @@ -30,7 +30,7 @@ trait BspJavaModule extends mill.api.Module with BspJavaModuleApi { clientWantsSemanticDb: Boolean ): Task[EvaluatorApi => ( classesPath: Path, - javacOptions: Seq[String], + javacOptions: OptsApi, classpath: Seq[String] )] = { val classesPathTask = jm match { @@ -105,13 +105,17 @@ trait BspJavaModule extends mill.api.Module with BspJavaModuleApi { jm.resources().map(_.path.toNIO) } - def scalacOptionsTask = Task.Anon(Seq.empty[String]) + def scalacOptionsTask: Task[Opts] = Task.Anon(Opts()) override private[mill] def bspBuildTargetScalacOptions( needsToMergeResourcesIntoCompileDest: Boolean, enableJvmCompileClasspathProvider: Boolean, clientWantsSemanticDb: Boolean - ): Task[(Seq[String], EvaluatorApi => Seq[String], EvaluatorApi => java.nio.file.Path)] = { + ): Task[( + scalacOptionsTask: Opts, + compileClasspathTask: EvaluatorApi => Seq[String], + classPathTask: EvaluatorApi => java.nio.file.Path + )] = { val compileClasspathTask: Task[EvaluatorApi => Seq[String]] = if (enableJvmCompileClasspathProvider) { @@ -144,8 +148,8 @@ trait BspJavaModule extends mill.api.Module with BspJavaModuleApi { override private[mill] def bspBuildTargetScalaMainClasses : Task.Simple[( classes: Seq[String], - forkArgs: Seq[String], - forkEnv: Map[String, String] + forkArgs: Opts, + forkEnv: Map[String, Opt] )] = Task { (jm.allLocalMainClasses(), jm.forkArgs(), jm.allForkEnv()) diff --git a/libs/javalib/src/mill/javalib/bsp/BspRunModule.scala b/libs/javalib/src/mill/javalib/bsp/BspRunModule.scala index f18a191229ba..bc486e4bddfb 100644 --- a/libs/javalib/src/mill/javalib/bsp/BspRunModule.scala +++ b/libs/javalib/src/mill/javalib/bsp/BspRunModule.scala @@ -1,11 +1,11 @@ package mill.javalib.bsp import java.nio.file.Path - import mill.api.daemon.internal.bsp.BspRunModuleApi import mill.api.daemon.internal.internal import mill.api.{Discover, ExternalModule, ModuleCtx} import mill.api.JsonFormatters.given +import mill.api.opt.* import mill.javalib.{JavaModule, RunModule, TestModule} import mill.{Args, Task} @@ -33,9 +33,9 @@ private[mill] object BspRunModule extends ExternalModule { override private[mill] def bspJvmRunEnvironment: Task.Simple[( runClasspath: Seq[Path], - forkArgs: Seq[String], + forkArgs: Opts, forkWorkingDir: Path, - forkEnv: Map[String, String], + forkEnv: Map[String, Opt], mainClass: Option[String], localMainClasses: Seq[String] )] = @@ -52,9 +52,9 @@ private[mill] object BspRunModule extends ExternalModule { override private[mill] def bspJvmTestEnvironment: Task.Simple[( runClasspath: Seq[Path], - forkArgs: Seq[String], + forkArgs: Opts, forkWorkingDir: Path, - forkEnv: Map[String, String], + forkEnv: Map[String, Opt], mainClass: Option[String], testEnvVars: Option[( mainClass: String, diff --git a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala index fab493c3e65a..6053471d1adf 100644 --- a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala +++ b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala @@ -1,6 +1,7 @@ package mill.javalib.errorprone import mill.api.PathRef +import mill.api.opt.* import mill.javalib.{Dep, DepSyntax, JavaModule} import mill.{T, Task} @@ -37,15 +38,16 @@ trait ErrorProneModule extends JavaModule { /** * Options used to enable and configure the `error-prone` plugin in the Java compiler. */ - def errorProneJavacEnableOptions: T[Seq[String]] = Task { - val processorPath = errorProneClasspath().map(_.path).mkString(File.pathSeparator) - val enableOpts = Seq( + def errorProneJavacEnableOptions: T[Opts] = Task { + val processorPath: Seq[os.Path] = errorProneClasspath().map(_.path) + + val enableOpts: Opts = Opts( "-XDcompilePolicy=simple", "-processorpath", processorPath, - (Seq("-Xplugin:ErrorProne") ++ errorProneOptions()).mkString(" ") + (Seq("-Xplugin:ErrorProne") ++ errorProneOptions().toStringSeq).mkString(" ") ) - val java17Options = Option.when(scala.util.Properties.isJavaAtLeast(16))(Seq( + val java17Options: Seq[String] = Option.when(scala.util.Properties.isJavaAtLeast(16))(Seq( "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", @@ -57,7 +59,8 @@ trait ErrorProneModule extends JavaModule { "--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", "--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED" ).map(o => s"-J${o}")).toSeq.flatten - java17Options ++ enableOpts + + Opts(java17Options) ++ enableOpts } /** @@ -65,12 +68,12 @@ trait ErrorProneModule extends JavaModule { * * Those are documented as "flags" at https://errorprone.info/docs/flags */ - def errorProneOptions: T[Seq[String]] = Task { Seq.empty[String] } + def errorProneOptions: T[Opts] = Task { Opts() } /** * Appends the [[errorProneJavacEnableOptions]] to the Java compiler options. */ - override def mandatoryJavacOptions: T[Seq[String]] = Task { + override def mandatoryJavacOptions: T[Opts] = Task { super.mandatoryJavacOptions() ++ errorProneJavacEnableOptions() } } diff --git a/libs/javalib/src/mill/javalib/idea/GenIdeaModule.scala b/libs/javalib/src/mill/javalib/idea/GenIdeaModule.scala index 7c6d8fdc31c6..3a1d380df87e 100644 --- a/libs/javalib/src/mill/javalib/idea/GenIdeaModule.scala +++ b/libs/javalib/src/mill/javalib/idea/GenIdeaModule.scala @@ -1,14 +1,14 @@ package mill.javalib.idea import java.nio.file.Path - import mill.Task -import mill.api.Segments +import mill.api.{ModuleCtx, PathRef, Segments} +import mill.api.opt.* import mill.api.daemon.internal.idea.{GenIdeaInternalApi, ResolvedModule} import mill.api.daemon.internal.internal -import mill.api.{ModuleCtx, PathRef} import mill.javalib.{BoundDep, Dep, JavaModule} import mill.api.JsonFormatters.given + trait GenIdeaModule extends mill.api.Module with GenIdeaInternalApi { private[mill] val jarCollector: PartialFunction[PathRef, Path] = { case p if p.path.ext == "jar" => p.path.toNIO @@ -48,7 +48,7 @@ trait GenIdeaModule extends mill.api.Module with GenIdeaInternalApi { private[mill] def scalacPluginsMvnDeps = Task.Anon(Seq.empty[Dep]) - private[mill] def allScalacOptions = Task.Anon(Seq.empty[String]) + private[mill] def allScalacOptions: Task[Opts] = Task.Anon(Opts()) private[mill] def scalaVersion = Task.Anon(Option.empty[String]) @@ -73,7 +73,7 @@ trait GenIdeaModule extends mill.api.Module with GenIdeaInternalApi { val scopedCpEntries = scopedClasspathEntries() val pluginClasspath = scalacPluginDependencies().collect(jarCollector) - val scalacOpts = allScalacOptions() + val scalacOpts = allScalacOptions().toStringSeq val resolvedCompilerCp = scalaCompilerClasspath().map(_.path.toNIO) val resolvedLibraryCp = externalLibraryDependencies().map(_.path.toNIO) val facets = javaModule.ideaJavaModuleFacets(ideaConfigVersion)() diff --git a/libs/javalib/src/mill/javalib/repackage/RepackageModule.scala b/libs/javalib/src/mill/javalib/repackage/RepackageModule.scala index dd8b775091be..b291d7cd4830 100644 --- a/libs/javalib/src/mill/javalib/repackage/RepackageModule.scala +++ b/libs/javalib/src/mill/javalib/repackage/RepackageModule.scala @@ -52,9 +52,9 @@ trait RepackageModule extends mill.api.Module { shellClassPath = Seq("$0"), cmdClassPath = Seq("%~dpnx0"), shebang = false, - jvmArgs = m.forkArgs(), - shellJvmArgs = m.forkShellArgs(), - cmdJvmArgs = m.forkCmdArgs() + jvmArgs = m.forkArgs().toStringSeq, + shellJvmArgs = m.forkShellArgs().toStringSeq, + cmdJvmArgs = m.forkCmdArgs().toStringSeq ) ).filter(_.nonEmpty) } diff --git a/libs/javalib/test/src/mill/javalib/LauncherTests.scala b/libs/javalib/test/src/mill/javalib/LauncherTests.scala index b8e7eab672ed..21d44db5f69d 100644 --- a/libs/javalib/test/src/mill/javalib/LauncherTests.scala +++ b/libs/javalib/test/src/mill/javalib/LauncherTests.scala @@ -1,5 +1,6 @@ package mill.javalib +import mill.api.opt.Opts import mill.api.{Discover, PathRef} import mill.testkit.{TestRootModule, UnitTester} import utest.* @@ -11,7 +12,7 @@ object LauncherTests extends TestSuite { object HelloJava extends TestRootModule with JavaModule { def jvmId = s"temurin:$customJavaVersion" - def javacOptions = Seq("-target", "1.8", "-source", "1.8") + def javacOptions = Opts(JavacOptions.`-target`, "1.8", JavacOptions.`-source`, "1.8") lazy val millDiscover = Discover[this.type] } diff --git a/libs/javalib/test/src/mill/javalib/errorprone/ErrorProneTests.scala b/libs/javalib/test/src/mill/javalib/errorprone/ErrorProneTests.scala index d4811de2c8a5..b0904f117d56 100644 --- a/libs/javalib/test/src/mill/javalib/errorprone/ErrorProneTests.scala +++ b/libs/javalib/test/src/mill/javalib/errorprone/ErrorProneTests.scala @@ -2,11 +2,13 @@ package mill.javalib.errorprone import mill.{T, Task} import mill.api.Discover +import mill.api.opt.* import mill.javalib.JavaModule import mill.testkit.{TestRootModule, UnitTester} import os.Path import utest.* -import mill.util.TokenReaders._ +import mill.util.TokenReaders.* + object ErrorProneTests extends TestSuite { object noErrorProne extends TestRootModule with JavaModule { @@ -16,8 +18,8 @@ object ErrorProneTests extends TestSuite { lazy val millDiscover = Discover[this.type] } object errorProneCustom extends TestRootModule with JavaModule with ErrorProneModule { - override def errorProneOptions: T[Seq[String]] = Task { - Seq("-XepAllErrorsAsWarnings") + override def errorProneOptions: T[Opts] = Task { + Opts("-XepAllErrorsAsWarnings") } lazy val millDiscover = Discover[this.type] } @@ -44,7 +46,7 @@ object ErrorProneTests extends TestSuite { test("compileWarn") { UnitTester(errorProneCustom, testModuleSourcesPath).scoped { eval => val Right(opts) = eval(errorProneCustom.mandatoryJavacOptions): @unchecked - assert(opts.value.exists(_.contains("-XepAllErrorsAsWarnings"))) + assert(opts.value.toStringSeq.exists(_.contains("-XepAllErrorsAsWarnings"))) val res = eval(errorProneCustom.compile) assert(res.isRight) } diff --git a/libs/kotlinlib/src/mill/kotlinlib/KotlinModule.scala b/libs/kotlinlib/src/mill/kotlinlib/KotlinModule.scala index 62dd449500b7..b3da942df347 100644 --- a/libs/kotlinlib/src/mill/kotlinlib/KotlinModule.scala +++ b/libs/kotlinlib/src/mill/kotlinlib/KotlinModule.scala @@ -8,8 +8,8 @@ package kotlinlib import coursier.core.VariantSelector.VariantMatcher import coursier.params.ResolutionParams -import mill.api.Result -import mill.api.ModuleRef +import mill.api.{ModuleRef, Result} +import mill.api.opt.* import mill.kotlinlib.worker.api.KotlinWorkerTarget import mill.javalib.api.CompilationResult import mill.javalib.api.JvmWorkerApi as PublicJvmWorkerApi @@ -187,7 +187,7 @@ trait KotlinModule extends JavaModule with KotlinModuleApi { outer => * You might want to add additional arguments like `-X` to see extra help. */ def kotlincHelp(args: String*): Command[Unit] = Task.Command { - kotlinCompileTask(Seq("-help") ++ args)() + kotlinCompileTask(Opts("-help") ++ Opts(args))() () } @@ -214,7 +214,7 @@ trait KotlinModule extends JavaModule with KotlinModuleApi { outer => // TODO need to provide a dedicated source set for common sources in case of Multiplatform // platforms supported: jvm, js, wasm, native, common - val options = dokkaOptions() ++ + val options = dokkaOptions().toStringSeq ++ Seq("-outputDir", dokkaDir.toString()) ++ pluginClasspathOption ++ Seq( @@ -258,7 +258,7 @@ trait KotlinModule extends JavaModule with KotlinModuleApi { outer => * You should not set the `-outputDir` setting for specifying the target directory, * as that is done in the [[docJar]] target. */ - def dokkaOptions: T[Seq[String]] = Task { Seq[String]() } + def dokkaOptions: T[Opts] = Task { Opts() } /** * Dokka version. @@ -299,7 +299,7 @@ trait KotlinModule extends JavaModule with KotlinModuleApi { outer => /** * The actual Kotlin compile task (used by [[compile]] and [[kotlincHelp]]). */ - protected def kotlinCompileTask(extraKotlinArgs: Seq[String] = Seq()): Task[CompilationResult] = + protected def kotlinCompileTask(extraKotlinArgs: Opts = Opts()): Task[CompilationResult] = Task.Anon { val ctx = Task.ctx() val dest = ctx.dest @@ -327,7 +327,7 @@ trait KotlinModule extends JavaModule with KotlinModuleApi { outer => javaSourceFiles = javaSourceFiles, compileCp = compileCp, javaHome = javaHome().map(_.path), - javacOptions = javacOptions(), + javacOptions = javacOptions().toStringSeq, compileProblemReporter = ctx.reporter(hashCode), reportOldProblems = internalReportOldProblems() ) @@ -353,8 +353,8 @@ trait KotlinModule extends JavaModule with KotlinModuleApi { outer => when(kotlinExplicitApi())( "-Xexplicit-api=strict" ), - allKotlincOptions(), - extraKotlinArgs + allKotlincOptions().toStringSeq, + extraKotlinArgs.toStringSeq ).flatten val workerResult = @@ -391,7 +391,7 @@ trait KotlinModule extends JavaModule with KotlinModuleApi { outer => /** * Additional Kotlin compiler options to be used by [[compile]]. */ - def kotlincOptions: T[Seq[String]] = Task { Seq.empty[String] } + def kotlincOptions: T[Opts] = Task { Opts() } /** * Enable use of new Kotlin Build API (Beta). @@ -406,22 +406,24 @@ trait KotlinModule extends JavaModule with KotlinModuleApi { outer => * Mandatory command-line options to pass to the Kotlin compiler * that shouldn't be removed by overriding `scalacOptions` */ - protected def mandatoryKotlincOptions: T[Seq[String]] = Task { + protected def mandatoryKotlincOptions: T[Opts] = Task { val languageVersion = kotlinLanguageVersion() val kotlinkotlinApiVersion = kotlinApiVersion() val plugins = kotlincPluginJars().map(_.path) - Seq("-no-stdlib") ++ - when(!languageVersion.isBlank)("-language-version", languageVersion) ++ - when(!kotlinkotlinApiVersion.isBlank)("-api-version", kotlinkotlinApiVersion) ++ - plugins.map(p => s"-Xplugin=$p") + Opts( + "-no-stdlib", + OptGroup.when(!languageVersion.isBlank)("-language-version", languageVersion), + OptGroup.when(!kotlinkotlinApiVersion.isBlank)("-api-version", kotlinkotlinApiVersion), + plugins.map(p => opt"-Xplugin=$p") + ) } /** * Aggregation of all the options passed to the Kotlin compiler. * In most cases, instead of overriding this Target you want to override `kotlincOptions` instead. */ - def allKotlincOptions: T[Seq[String]] = Task { + def allKotlincOptions: T[Opts] = Task { mandatoryKotlincOptions() ++ kotlincOptions() } @@ -485,9 +487,9 @@ trait KotlinModule extends JavaModule with KotlinModuleApi { outer => override def kotlincPluginMvnDeps: T[Seq[Dep]] = Task { outer.kotlincPluginMvnDeps() } // TODO: make Xfriend-path an explicit setting - override def kotlincOptions: T[Seq[String]] = Task { - outer.kotlincOptions().filterNot(_.startsWith("-Xcommon-sources")) ++ - Seq(s"-Xfriend-paths=${outer.compile().classes.path.toString()}") + override def kotlincOptions: T[Opts] = Task { + outer.kotlincOptions().filterGroup(!_.head.startsWith(KotlincOptions.`-Xcommon-sources`)) ++ + Opts(opt"${KotlincOptions.`-Xfriend-paths`}=${outer.compile().classes.path}") } override def kotlinUseEmbeddableCompiler: Task[Boolean] = Task.Anon { outer.kotlinUseEmbeddableCompiler() } @@ -507,9 +509,9 @@ object KotlinModule { override def kotlincPluginMvnDeps: T[Seq[Dep]] = Task { outer.kotlincPluginMvnDeps() } // TODO: make Xfriend-path an explicit setting - override def kotlincOptions: T[Seq[String]] = Task { - outer.kotlincOptions().filterNot(_.startsWith("-Xcommon-sources")) ++ - Seq(s"-Xfriend-paths=${outer.compile().classes.path.toString()}") + override def kotlincOptions: T[Opts] = Task { + outer.kotlincOptions().filterGroup(!_.head.startsWith(KotlincOptions.`-Xcommon-sources`)) ++ + Opts(opt"${KotlincOptions.`-Xfriend-paths`}=${outer.compile().classes.path}") } override def kotlinUseEmbeddableCompiler: Task[Boolean] = Task.Anon { outer.kotlinUseEmbeddableCompiler() } diff --git a/libs/kotlinlib/src/mill/kotlinlib/KotlincOptions.scala b/libs/kotlinlib/src/mill/kotlinlib/KotlincOptions.scala new file mode 100644 index 000000000000..fc80ab030f16 --- /dev/null +++ b/libs/kotlinlib/src/mill/kotlinlib/KotlincOptions.scala @@ -0,0 +1,7 @@ +package mill.kotlinlib + +object KotlincOptions { + val `-Xcommon-sources` = "-Xcommon-sources" + val `-Xfriend-paths` = "-Xfriend-paths" + val friendPathSeparator = "," +} diff --git a/libs/kotlinlib/src/mill/kotlinlib/js/KotlinJsModule.scala b/libs/kotlinlib/src/mill/kotlinlib/js/KotlinJsModule.scala index 88c721e855af..b71e26088bbb 100644 --- a/libs/kotlinlib/src/mill/kotlinlib/js/KotlinJsModule.scala +++ b/libs/kotlinlib/src/mill/kotlinlib/js/KotlinJsModule.scala @@ -3,12 +3,11 @@ package mill.kotlinlib.js import coursier.core.VariantSelector.VariantMatcher import coursier.params.ResolutionParams import mainargs.arg -import mill.api.PathRef -import mill.api.Result +import mill.api.{PathRef, Result, Task} +import mill.api.opt.* import mill.api.Task.Command -import mill.api.Task import mill.kotlinlib.worker.api.{KotlinWorker, KotlinWorkerTarget} -import mill.kotlinlib.{Dep, DepSyntax, KotlinModule, KotlinWorkerManager} +import mill.kotlinlib.{Dep, DepSyntax, KotlinModule, KotlinWorkerManager, KotlincOptions} import mill.javalib.Lib import mill.javalib.api.CompilationResult import mill.util.Jvm @@ -176,7 +175,7 @@ trait KotlinJsModule extends KotlinModule { outer => * The actual Kotlin compile task (used by [[compile]] and [[kotlincHelp]]). */ protected override def kotlinCompileTask( - extraKotlinArgs: Seq[String] = Seq.empty[String] + extraKotlinArgs: Opts = Opts() ): Task[CompilationResult] = Task.Anon { KotlinWorkerManager.kotlinWorker().withValue(kotlinCompilerClasspath()) { kotlinWorker => @@ -196,7 +195,7 @@ trait KotlinJsModule extends KotlinModule { outer => destinationRoot = Task.dest, artifactId = artifactId(), explicitApi = kotlinExplicitApi(), - extraKotlinArgs = allKotlincOptions() ++ extraKotlinArgs, + extraKotlinArgs = (allKotlincOptions() ++ extraKotlinArgs).toStringSeq, worker = kotlinWorker, useBtApi = kotlincUseBtApi() ) @@ -227,7 +226,7 @@ trait KotlinJsModule extends KotlinModule { outer => destinationRoot = Task.dest, artifactId = artifactId(), explicitApi = kotlinExplicitApi(), - extraKotlinArgs = allKotlincOptions(), + extraKotlinArgs = allKotlincOptions().toStringSeq, worker = kotlinWorker, useBtApi = kotlincUseBtApi() ) @@ -512,14 +511,12 @@ trait KotlinJsModule extends KotlinModule { outer => // endregion - override def kotlincOptions: T[Seq[String]] = Task { - super.kotlincOptions().map { item => - if (item.startsWith("-Xfriend-paths=")) { - // JVM -> JS option name - item.replace("-Xfriend-paths=", "-Xfriend-modules=") - } else { - item - } + override def kotlincOptions: T[Opts] = Task { + super.kotlincOptions().mapGroup { optGroup => + // JVM -> JS option name + val head = optGroup.head.mapStartString(_.replace("-Xfriend-paths=", "-Xfriend-modules=")) + val tail = optGroup.value.tail + OptGroup((head +: tail)*) } } diff --git a/libs/kotlinlib/src/mill/kotlinlib/kover/KoverModule.scala b/libs/kotlinlib/src/mill/kotlinlib/kover/KoverModule.scala index ce8a41d4f384..3411c61b260b 100644 --- a/libs/kotlinlib/src/mill/kotlinlib/kover/KoverModule.scala +++ b/libs/kotlinlib/src/mill/kotlinlib/kover/KoverModule.scala @@ -5,18 +5,15 @@ package mill.kotlinlib.kover import mill.* -import mill.api.{PathRef} -import mill.api.{Result} -import mill.api.{Discover, Evaluator, ExternalModule} +import mill.api.{BuildCtx, Discover, Evaluator, ExternalModule, PathRef, Result, SelectMode} +import mill.api.opt.* import ReportType.{Html, Xml} import mill.kotlinlib.{Dep, DepSyntax, KotlinModule, TestModule, Versions} -import mill.api.SelectMode import mill.javalib.api.CompilationResult import mill.util.Jvm import os.Path import java.util.Locale -import mill.api.BuildCtx /** * Adds targets to a [[mill.kotlinlib.KotlinModule]] to create test coverage reports. @@ -101,15 +98,15 @@ trait KoverModule extends KotlinModule { outer => /** * Add Kover specific javaagent options. */ - override def forkArgs: T[Seq[String]] = Task { + override def forkArgs: T[Opts] = Task { val argsFile = koverDataDir().path / "kover-agent.args" val content = s"report.file=${koverBinaryReport().path}" BuildCtx.withFilesystemCheckerDisabled { os.write.over(argsFile, content) } super.forkArgs() ++ - Seq( - s"-javaagent:${koverAgentJar().path}=file:$argsFile" + Opts( + opt"-javaagent:${koverAgentJar().path}=file:$argsFile" ) } } diff --git a/libs/kotlinlib/src/mill/kotlinlib/ksp/KspModule.scala b/libs/kotlinlib/src/mill/kotlinlib/ksp/KspModule.scala index f96e66f40968..892f45fce36b 100644 --- a/libs/kotlinlib/src/mill/kotlinlib/ksp/KspModule.scala +++ b/libs/kotlinlib/src/mill/kotlinlib/ksp/KspModule.scala @@ -5,6 +5,7 @@ import coursier.params.ResolutionParams import mill.* import mill.api.daemon.MillURLClassLoader import mill.api.{ModuleRef, PathRef, Task} +import mill.api.opt.* import mill.kotlinlib.ksp2.{KspWorker, KspWorkerArgs} import mill.kotlinlib.worker.api.KotlinWorkerTarget import mill.kotlinlib.{Dep, DepSyntax, KotlinModule, KotlinWorkerManager} @@ -103,8 +104,8 @@ trait KspModule extends KotlinModule { outer => /** * Processor options to be passed to KSP. */ - def kspProcessorOptions: T[Map[String, String]] = Task { - Map.empty[String, String] + def kspProcessorOptions: T[Map[String, Opt]] = Task { + Map.empty[String, Opt] } /** @@ -150,16 +151,15 @@ trait KspModule extends KotlinModule { outer => * * @return */ - def ksp1KotlincOptions: T[Seq[String]] = Task { + def ksp1KotlincOptions: T[Opts] = Task { if (!kspLanguageVersion().startsWith("1.")) { throw new RuntimeException("KSP needs a compatible language version <= 1.9 to be set!") } - kotlincOptions() ++ Seq( + kotlincOptions() ++ Opts( "-Xallow-unstable-dependencies", "-no-reflect", "-no-stdlib", - "-language-version", - kspLanguageVersion() + OptGroup("-language-version", kspLanguageVersion()) ) } @@ -236,7 +236,7 @@ trait KspModule extends KotlinModule { outer => ) ++ kspPluginParameters.map(p => s"$pluginOpt:$p") val kspCompilerArgs = - ksp1KotlincOptions() ++ Seq(xPluginArg) ++ Seq("-P", pluginConfigs.mkString(",")) + ksp1KotlincOptions().toStringSeq ++ Seq(xPluginArg) ++ Seq("-P", pluginConfigs.mkString(",")) Task.log.info( s"Running Kotlin Symbol Processing for ${sourceFiles.size} Kotlin sources to ${kspOutputDir} ..." @@ -279,8 +279,8 @@ trait KspModule extends KotlinModule { outer => * * For more info go to [[https://github.com/google/ksp/blob/main/docs/ksp2cmdline.md]] */ - def ksp2Args: T[Seq[String]] = Task { - Seq.empty[String] + def ksp2Args: T[Opts] = Task { + Opts() } /** @@ -341,7 +341,7 @@ trait KspModule extends KotlinModule { outer => val kspCachesDir = Task.dest / "caches" val processorOptionsValue = - kspProcessorOptions().map((key, value) => s"$key=$value").toSeq.mkString(File.pathSeparator) + kspProcessorOptions().map((key, value) => s"$key=${value.toString}").toSeq.mkString(File.pathSeparator) val processorOptions = if (processorOptionsValue.isEmpty) "" @@ -367,7 +367,7 @@ trait KspModule extends KotlinModule { outer => s"-api-version=${kspApiVersion()}", processorOptions, s"-map-annotation-arguments-in-java=false" - ) ++ ksp2Args() :+ processorClasspath + ) ++ ksp2Args().toStringSeq :+ processorClasspath val kspJvmMainClasspath = ksp2ToolsDepsClasspath().map(_.path) val mainClass = "com.google.devtools.ksp.cmdline.KSPJvmMain" @@ -448,7 +448,7 @@ trait KspModule extends KotlinModule { outer => val kspCachesDir = Task.dest / "caches" val processorOptionsValue = - kspProcessorOptions().map((key, value) => s"$key=$value").toSeq.mkString(File.pathSeparator) + kspProcessorOptions().map((key, value) => s"$key=${value.toString()}").toSeq.mkString(File.pathSeparator) val processorOptions = if (processorOptionsValue.isEmpty) "" @@ -474,7 +474,7 @@ trait KspModule extends KotlinModule { outer => s"-api-version=${kspApiVersion()}", processorOptions, s"-map-annotation-arguments-in-java=false" - ) ++ ksp2Args() + ) ++ ksp2Args().toStringSeq val kspLogLevel = if (Task.log.debugEnabled) mill.kotlinlib.ksp2.LogLevel.Debug diff --git a/libs/kotlinlib/test/src/mill/kotlinlib/contrib/kover/KoverModuleTests.scala b/libs/kotlinlib/test/src/mill/kotlinlib/contrib/kover/KoverModuleTests.scala index 6013ce77cd8e..3117ec9825f5 100644 --- a/libs/kotlinlib/test/src/mill/kotlinlib/contrib/kover/KoverModuleTests.scala +++ b/libs/kotlinlib/test/src/mill/kotlinlib/contrib/kover/KoverModuleTests.scala @@ -7,6 +7,7 @@ import mill.kotlinlib.TestModule import mill.testkit.{TestRootModule, UnitTester} import mill.{T, Task, api} import utest.{TestSuite, Tests, assert, test} +import mill.api.opt.* import scala.xml.{Node, XML} @@ -19,8 +20,8 @@ object KoverModuleTests extends TestSuite { object module extends TestRootModule { trait KotestTestModule extends TestModule.Junit5 { - override def forkArgs: T[Seq[String]] = Task { - super.forkArgs() ++ Seq("-Dkotest.framework.classpath.scanning.autoscan.disable=true") + override def forkArgs: T[Opts] = Task { + super.forkArgs() ++ Opts("-Dkotest.framework.classpath.scanning.autoscan.disable=true") } override def mvnDeps = super.mvnDeps() ++ Seq( diff --git a/libs/scalajslib/src/mill/scalajslib/ScalaJSModule.scala b/libs/scalajslib/src/mill/scalajslib/ScalaJSModule.scala index 1f4941e97815..abeaca5a129d 100644 --- a/libs/scalajslib/src/mill/scalajslib/ScalaJSModule.scala +++ b/libs/scalajslib/src/mill/scalajslib/ScalaJSModule.scala @@ -9,6 +9,7 @@ import mill.api.CrossVersion import mill.scalalib.{Dep, DepSyntax, Lib, TestModule} import mill.javalib.api.JvmWorkerUtil import mill.scalajslib.api.* +import mill.api.opt.* import mill.scalajslib.worker.{ScalaJSWorker, ScalaJSWorkerExternalModule} import mill.* import mill.javalib.testrunner.{TestResult, TestRunner, TestRunnerUtils} @@ -211,15 +212,15 @@ trait ScalaJSModule extends scalalib.ScalaModule with ScalaJSModuleApi { outer = ) } - override def mandatoryScalacOptions: T[Seq[String]] = Task { + override def mandatoryScalacOptions: T[Opts] = Task { // Don't add flag twice, e.g. if a test suite inherits it both directly // ScalaJSModule as well as from the enclosing non-test ScalaJSModule val scalajsFlag = if ( JvmWorkerUtil.isScala3(scalaVersion()) && - !super.mandatoryScalacOptions().contains("-scalajs") - ) Seq("-scalajs") - else Seq.empty + !super.mandatoryScalacOptions().toStringSeq.contains("-scalajs") + ) Opts("-scalajs") + else Opts() super.mandatoryScalacOptions() ++ scalajsFlag } diff --git a/libs/scalajslib/test/src/mill/scalajslib/CompileLinkTests.scala b/libs/scalajslib/test/src/mill/scalajslib/CompileLinkTests.scala index b5f577bc8aa3..efdeb186d643 100644 --- a/libs/scalajslib/test/src/mill/scalajslib/CompileLinkTests.scala +++ b/libs/scalajslib/test/src/mill/scalajslib/CompileLinkTests.scala @@ -1,13 +1,13 @@ package mill.scalajslib -import mill._ +import mill.* import mill.api.Discover -import mill.scalalib.{DepSyntax, PublishModule, ScalaModule, TestModule} +import mill.api.opt.* +import mill.scalalib.{DepSyntax, PublishModule, ScalaModule, ScalacOptions, TestModule} import mill.scalalib.publish.{Developer, License, PomSettings, VersionControl} import mill.testkit.UnitTester import mill.testkit.TestRootModule -import utest._ - +import utest.* import mill.javalib.api.JvmWorkerUtil object CompileLinkTests extends TestSuite { @@ -52,7 +52,7 @@ object CompileLinkTests extends TestSuite { } object inherited extends ScalaJSModule { val (scala, scalaJS) = matrix.head - def scalacOptions = Seq("-deprecation") + def scalacOptions = Opts(ScalacOptions.`-deprecation`) def scalaOrganization = "org.example" def scalaVersion = scala def scalaJSVersion = scalaJS diff --git a/libs/scalalib/src/mill/scalalib/ScalaModule.scala b/libs/scalalib/src/mill/scalalib/ScalaModule.scala index 242cb0920ebd..8bc5de47d850 100644 --- a/libs/scalalib/src/mill/scalalib/ScalaModule.scala +++ b/libs/scalalib/src/mill/scalalib/ScalaModule.scala @@ -3,6 +3,7 @@ package scalalib import mill.util.JarManifest import mill.api.{BuildCtx, DummyInputStream, ModuleRef, PathRef, Result, Task} +import mill.api.opt.* import mill.util.BuildInfo import mill.util.Jvm import mill.javalib.api.{CompilationResult, JvmWorkerUtil, Versions} @@ -30,8 +31,8 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase override def scalaVersion: T[String] = outer.scalaVersion() override def scalacPluginMvnDeps: T[Seq[Dep]] = outer.scalacPluginMvnDeps() override def scalacPluginClasspath: T[Seq[PathRef]] = outer.scalacPluginClasspath() - override def scalacOptions: T[Seq[String]] = outer.scalacOptions() - override def mandatoryScalacOptions: T[Seq[String]] = + override def scalacOptions: T[Opts] = outer.scalacOptions() + override def mandatoryScalacOptions: T[Opts] = Task { super.mandatoryScalacOptions() } } @@ -172,54 +173,56 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase * Mandatory command-line options to pass to the Scala compiler * that shouldn't be removed by overriding `scalacOptions` */ - protected def mandatoryScalacOptions: T[Seq[String]] = Task { Seq.empty[String] } + protected def mandatoryScalacOptions: T[Opts] = Task { Opts() } /** * Scalac options to activate the compiler plugins. */ - private def enablePluginScalacOptions: T[Seq[String]] = Task { + private def enablePluginScalacOptions: T[Opts] = Task { val resolvedJars = defaultResolver().classpath( scalacPluginMvnDeps().map(_.exclude("*" -> "*")) ) - resolvedJars.iterator.map(jar => s"-Xplugin:${jar.path}").toSeq + Opts(resolvedJars.map(jar => opt"-Xplugin:${jar.path}")) } /** * Scalac options to activate the compiler plugins for ScalaDoc generation. */ - private def enableScalaDocPluginScalacOptions: T[Seq[String]] = Task { + private def enableScalaDocPluginScalacOptions: T[Opts] = Task { val resolvedJars = defaultResolver().classpath( scalaDocPluginMvnDeps().map(_.exclude("*" -> "*")) ) - resolvedJars.iterator.map(jar => s"-Xplugin:${jar.path}").toSeq + Opts( + resolvedJars.map(jar => opt"-Xplugin:${jar.path}") + ) } /** * Command-line options to pass to the Scala compiler defined by the user. * Consumers should use `allScalacOptions` to read them. */ - override def scalacOptions: T[Seq[String]] = Task { Seq.empty[String] } + override def scalacOptions: T[Opts] = Task { Opts() } /** * Aggregation of all the options passed to the Scala compiler. * In most cases, instead of overriding this task you want to override `scalacOptions` instead. */ - def allScalacOptions: T[Seq[String]] = Task { + def allScalacOptions: T[Opts] = Task { mandatoryScalacOptions() ++ enablePluginScalacOptions() ++ scalacOptions() } /** * Options to pass directly into Scaladoc. */ - def scalaDocOptions: T[Seq[String]] = Task { + def scalaDocOptions: T[Opts] = Task { val defaults = if (JvmWorkerUtil.isDottyOrScala3(scalaVersion())) - Seq( + Opts( "-project", artifactName() ) - else Seq() + else Opts() mandatoryScalacOptions() ++ enableScalaDocPluginScalacOptions() ++ scalacOptions() ++ defaults } @@ -278,7 +281,7 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase |For details, see: https://github.com/sbt/zinc/issues/1010""".stripMargin ) - val jOpts = JavaCompilerOptions.split(javacOptions() ++ mandatoryJavacOptions()) + val jOpts = JavaCompilerOptions.split(javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) val worker = jvmWorker().internalWorker() @@ -290,7 +293,7 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase javacOptions = jOpts.compiler, scalaVersion = sv, scalaOrganization = scalaOrganization(), - scalacOptions = allScalacOptions(), + scalacOptions = allScalacOptions().toStringSeq, compilerClasspath = scalaCompilerClasspath(), scalacPluginClasspath = scalacPluginClasspath(), incrementalCompilation = zincIncrementalCompilation(), @@ -334,7 +337,7 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase scalaOrganization(), scalaDocClasspath(), scalacPluginClasspath(), - options ++ compileCp ++ scalaDocOptions() ++ files.map(_.toString()) + options ++ compileCp ++ scalaDocOptions().toStringSeq ++ files.map(_.toString()) ), javaHome = javaHome().map(_.path) ) match { @@ -422,8 +425,8 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase classPath = runClasspath().map(_.path) ++ scalaCompilerClasspath().map( _.path ), - jvmArgs = forkArgs(), - env = allForkEnv(), + jvmArgs = forkArgs().toStringSeq, + env = allForkEnv().view.mapValues(_.toString()).toMap, mainArgs = Seq(useJavaCp) ++ consoleScalacOptions().filterNot(Set(useJavaCp)), cwd = forkWorkingDir(), stdin = os.Inherit, @@ -493,8 +496,8 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase Jvm.callProcess( mainClass = mainClass, classPath = ammoniteReplClasspath().map(_.path).toVector, - jvmArgs = forkArgs(), - env = allForkEnv(), + jvmArgs = forkArgs().toStringSeq, + env = allForkEnv().view.mapValues(_.toString()).toMap, mainArgs = replOptions, cwd = forkWorkingDir(), stdin = os.Inherit, @@ -608,13 +611,13 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase } val scalacOptions = ( - allScalacOptions() ++ - semanticDbEnablePluginScalacOptions() ++ + allScalacOptions().toStringSeq ++ + semanticDbEnablePluginScalacOptions().toStringSeq ++ additionalScalacOptions ) .filterNot(_ == "-Xfatal-warnings") - val javacOpts = SemanticDbJavaModule.javacOptionsTask(javacOptions(), semanticDbJavaVersion()) + val javacOpts = SemanticDbJavaModule.javacOptionsTask(javacOptions(), semanticDbJavaVersion()).toStringSeq Task.log.debug(s"effective scalac options: ${scalacOptions}") Task.log.debug(s"effective javac options: ${javacOpts}") @@ -674,8 +677,8 @@ object ScalaModule { override def scalaVersion: T[String] = outer.scalaVersion() override def scalacPluginMvnDeps: T[Seq[Dep]] = outer.scalacPluginMvnDeps() override def scalacPluginClasspath: T[Seq[PathRef]] = outer.scalacPluginClasspath() - override def scalacOptions: T[Seq[String]] = outer.scalacOptions() - override def mandatoryScalacOptions: T[Seq[String]] = + override def scalacOptions: T[Opts] = outer.scalacOptions() + override def mandatoryScalacOptions: T[Opts] = Task { super.mandatoryScalacOptions() } } } diff --git a/libs/scalalib/src/mill/scalalib/ScalacOptions.scala b/libs/scalalib/src/mill/scalalib/ScalacOptions.scala new file mode 100644 index 000000000000..6ed343a1a006 --- /dev/null +++ b/libs/scalalib/src/mill/scalalib/ScalacOptions.scala @@ -0,0 +1,9 @@ +package mill.scalalib + +object ScalacOptions { + + val `-deprecation` = "-deprecation" + val `-Ywarn-unused` = "-Ywarn-unused" + val `-Xfatal-warnings` = "-Xfatal-warnings" + val `-Ypartial-unification` = "-Ypartial-unification" +} diff --git a/libs/scalalib/src/mill/scalalib/idea/GenIdeaModule.scala b/libs/scalalib/src/mill/scalalib/idea/GenIdeaModule.scala index 657d60610d95..e3e693b0643c 100644 --- a/libs/scalalib/src/mill/scalalib/idea/GenIdeaModule.scala +++ b/libs/scalalib/src/mill/scalalib/idea/GenIdeaModule.scala @@ -4,6 +4,7 @@ import mill.scalalib.ScalaModule import mill.Task import mill.api.daemon.internal.internal import mill.api.ModuleCtx + trait GenIdeaModule extends mill.javalib.idea.GenIdeaModule { def javaModuleRef: mill.api.ModuleRef[ScalaModule] override def scalaCompilerClasspath = Task.Anon(javaModuleRef().scalaCompilerClasspath()) diff --git a/libs/scalalib/test/src/mill/scalalib/CrossVersionTests.scala b/libs/scalalib/test/src/mill/scalalib/CrossVersionTests.scala index f275de7b2078..6a4709a66e3e 100644 --- a/libs/scalalib/test/src/mill/scalalib/CrossVersionTests.scala +++ b/libs/scalalib/test/src/mill/scalalib/CrossVersionTests.scala @@ -1,6 +1,7 @@ package mill.scalalib import mill.api.Discover +import mill.api.opt.Opts import mill.util.TokenReaders.* import mill.testkit.UnitTester import mill.testkit.TestRootModule @@ -103,7 +104,7 @@ object CrossVersionTests extends TestSuite { object sandwitch213 extends ScalaModule { override def scalaVersion = "2.13.6" override def moduleDeps = Seq(sandwitch3) - override def scalacOptions = Seq("-Ytasty-reader") + override def scalacOptions = Opts("-Ytasty-reader") val tree = """├─ sandwitch3 |│ ├─ com.lihaoyi:upickle_3:1.4.0 diff --git a/libs/scalalib/test/src/mill/scalalib/HelloWorldTests.scala b/libs/scalalib/test/src/mill/scalalib/HelloWorldTests.scala index edfa402c6639..c5bd49c42dcc 100644 --- a/libs/scalalib/test/src/mill/scalalib/HelloWorldTests.scala +++ b/libs/scalalib/test/src/mill/scalalib/HelloWorldTests.scala @@ -8,6 +8,7 @@ import mill.* import mill.api.ExecResult import mill.api.Discover import mill.api.ExecutionPaths +import mill.api.opt.* import mill.testkit.UnitTester import mill.testkit.TestRootModule import utest.* @@ -75,7 +76,7 @@ object HelloWorldTests extends TestSuite { object HelloWorldFatalWarnings extends TestRootModule { object core extends HelloWorldModule { - override def scalacOptions = Task { Seq("-Ywarn-unused", "-Xfatal-warnings") } + override def scalacOptions = Task { Opts(ScalacOptions.`-Ywarn-unused`, ScalacOptions.`-Xfatal-warnings`) } } lazy val millDiscover = Discover[this.type] } @@ -108,14 +109,14 @@ object HelloWorldTests extends TestSuite { } def compileClassfiles: Seq[os.RelPath] = Seq( - os.rel / "Main.class", - os.rel / "Main$.class", - os.rel / "Main0.class", - os.rel / "Main0$.class", - os.rel / "Main$delayedInit$body.class", - os.rel / "Person.class", - os.rel / "Person$.class" - ) + "Main.class", + "Main$.class", + "Main0.class", + "Main0$.class", + "Main$delayedInit$body.class", + "Person.class", + "Person$.class" + ).map(os.rel / _) def tests: Tests = Tests { test("scalaVersion") { @@ -151,7 +152,7 @@ object HelloWorldTests extends TestSuite { val Right(result) = eval.apply(HelloWorldFatalWarnings.core.scalacOptions): @unchecked assert( - result.value == Seq("-Ywarn-unused", "-Xfatal-warnings"), + result.value.toStringSeq == Seq("-Ywarn-unused", "-Xfatal-warnings"), result.evalCount > 0 ) } diff --git a/libs/scalalib/test/src/mill/scalalib/ScalaColorOutputTests.scala b/libs/scalalib/test/src/mill/scalalib/ScalaColorOutputTests.scala index c93b3ca16c6a..56c6526f6825 100644 --- a/libs/scalalib/test/src/mill/scalalib/ScalaColorOutputTests.scala +++ b/libs/scalalib/test/src/mill/scalalib/ScalaColorOutputTests.scala @@ -1,5 +1,6 @@ package mill.scalalib +import mill.api.opt.Opts import mill.api.{Discover, ExecResult} import mill.scalalib.HelloWorldTests.* import mill.testkit.{TestRootModule, UnitTester} @@ -14,7 +15,7 @@ object ScalaColorOutputTests extends TestSuite { object core extends ScalaModule { def scalaVersion = scala213Version - override def scalacOptions = super.scalacOptions() ++ Seq( + override def scalacOptions = super.scalacOptions() ++ Opts( "-Vimplicits" ) } diff --git a/libs/scalalib/test/src/mill/scalalib/ScalaFlagsTests.scala b/libs/scalalib/test/src/mill/scalalib/ScalaFlagsTests.scala index 4117796b1862..19e5d7c5808b 100644 --- a/libs/scalalib/test/src/mill/scalalib/ScalaFlagsTests.scala +++ b/libs/scalalib/test/src/mill/scalalib/ScalaFlagsTests.scala @@ -5,6 +5,7 @@ import mill.scalalib.HelloWorldTests.* import mill.testkit.{TestRootModule, UnitTester} import mill.util.TokenReaders.* import utest.* +import mill.api.opt.* object ScalaFlagsTests extends TestSuite { @@ -12,8 +13,8 @@ object ScalaFlagsTests extends TestSuite { object core extends ScalaModule { def scalaVersion = scala212Version - override def scalacOptions = super.scalacOptions() ++ Seq( - "-Ypartial-unification" + override def scalacOptions = super.scalacOptions() ++ Opts( + ScalacOptions.`-Ypartial-unification` ) } diff --git a/libs/scalalib/test/src/mill/scalalib/ScalaMacrosTests.scala b/libs/scalalib/test/src/mill/scalalib/ScalaMacrosTests.scala index a071b68a67f1..fcba9bddffdd 100644 --- a/libs/scalalib/test/src/mill/scalalib/ScalaMacrosTests.scala +++ b/libs/scalalib/test/src/mill/scalalib/ScalaMacrosTests.scala @@ -3,6 +3,7 @@ package mill.scalalib import mill.* import mill.testkit.{TestRootModule, UnitTester} import utest.* +import mill.api.opt.* import HelloWorldTests.* import mill.api.Discover @@ -13,7 +14,7 @@ object ScalaMacrosTests extends TestSuite { object core extends ScalaModule { override def scalaVersion = scala213Version override def mvnDeps = Seq(mvn"com.github.julien-truffaut::monocle-macro::2.1.0") - override def scalacOptions = super.scalacOptions() ++ Seq("-Ymacro-annotations") + override def scalacOptions = super.scalacOptions() ++ Opts("-Ymacro-annotations") } lazy val millDiscover = Discover[this.type] } diff --git a/libs/scalalib/test/src/mill/scalalib/ScalaScaladocTests.scala b/libs/scalalib/test/src/mill/scalalib/ScalaScaladocTests.scala index 4e5e043728bb..f2054c18afd2 100644 --- a/libs/scalalib/test/src/mill/scalalib/ScalaScaladocTests.scala +++ b/libs/scalalib/test/src/mill/scalalib/ScalaScaladocTests.scala @@ -6,13 +6,14 @@ import mill.testkit.{TestRootModule, UnitTester} import utest.* import HelloWorldTests.* import mill.api.Discover +import mill.api.opt.* object ScalaScaladocTests extends TestSuite { object HelloWorldWithDocVersion extends TestRootModule { object core extends HelloWorldModule { - override def scalacOptions = Task { Seq("-Ywarn-unused", "-Xfatal-warnings") } - override def scalaDocOptions = super.scalaDocOptions() ++ Seq("-doc-version", "1.2.3") + override def scalacOptions = Task { Opts(ScalacOptions.`-Ywarn-unused`, ScalacOptions.`-Xfatal-warnings`) } + override def scalaDocOptions = super.scalaDocOptions() ++ Opts("-doc-version", "1.2.3") } lazy val millDiscover = Discover[this.type] @@ -20,8 +21,8 @@ object ScalaScaladocTests extends TestSuite { object HelloWorldOnlyDocVersion extends TestRootModule { object core extends HelloWorldModule { - override def scalacOptions = Task { Seq("-Ywarn-unused", "-Xfatal-warnings") } - override def scalaDocOptions = Task { Seq("-doc-version", "1.2.3") } + override def scalacOptions = Task { Opts(ScalacOptions.`-Ywarn-unused`, ScalacOptions.`-Xfatal-warnings`) } + override def scalaDocOptions = Task { Opts("-doc-version", "1.2.3") } } lazy val millDiscover = Discover[this.type] @@ -30,7 +31,7 @@ object ScalaScaladocTests extends TestSuite { object HelloWorldDocTitle extends TestRootModule { object core extends HelloWorldModule { - override def scalaDocOptions = Task { Seq("-doc-title", "Hello World") } + override def scalaDocOptions = Task { Opts("-doc-title", "Hello World") } } lazy val millDiscover = Discover[this.type] @@ -49,14 +50,14 @@ object ScalaScaladocTests extends TestSuite { test("override") - UnitTester(HelloWorldDocTitle, resourcePath).scoped { eval => val Right(result) = eval.apply(HelloWorldDocTitle.core.scalaDocOptions): @unchecked assert( - result.value == Seq("-doc-title", "Hello World"), + result.value == Opts("-doc-title", "Hello World"), result.evalCount > 0 ) } test("extend") - UnitTester(HelloWorldWithDocVersion, resourcePath).scoped { eval => val Right(result) = eval.apply(HelloWorldWithDocVersion.core.scalaDocOptions): @unchecked assert( - result.value == Seq("-Ywarn-unused", "-Xfatal-warnings", "-doc-version", "1.2.3"), + result.value == Opts("-Ywarn-unused", "-Xfatal-warnings", "-doc-version", "1.2.3"), result.evalCount > 0 ) } diff --git a/libs/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala b/libs/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala index 256f6ba3f09e..5255b12c556b 100644 --- a/libs/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala +++ b/libs/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala @@ -358,8 +358,8 @@ trait ScalaNativeModule extends ScalaModule with ScalaNativeModuleApi { outer => new NativeRunner( mainClassDefault = finalMainClassOpt(), nativeExe = nativeLink(), - forkArgsDefault = forkArgs(), - forkEnvDefault = allForkEnv(), + forkArgsDefault = forkArgs().toStringSeq, + forkEnvDefault = allForkEnv().view.mapValues(_.toString()).toMap, propagateEnvDefault = propagateEnv() ) } @@ -368,8 +368,8 @@ trait ScalaNativeModule extends ScalaModule with ScalaNativeModuleApi { outer => new NativeRunner( mainClassDefault = Right(mainClass), nativeExe = nativeLinkOtherMain(mainClass)(), - forkArgsDefault = forkArgs(), - forkEnvDefault = allForkEnv(), + forkArgsDefault = forkArgs().toStringSeq, + forkEnvDefault = allForkEnv().view.mapValues(_.toString()).toMap, propagateEnvDefault = propagateEnv() ) } @@ -460,7 +460,7 @@ trait TestScalaNativeModule extends ScalaNativeModule with TestModule { val (close, framework) = withScalaNativeBridge.apply().apply(_.getFramework( nativeLink().path.toIO, - allForkEnv(), + allForkEnv().view.mapValues(_.toString()).toMap, toWorkerApi(logLevel()), testFramework() )) diff --git a/libs/scalanativelib/test/src/mill/scalanativelib/CompileRunTests.scala b/libs/scalanativelib/test/src/mill/scalanativelib/CompileRunTests.scala index 5e2987700a3d..2c2e9b5c18a3 100644 --- a/libs/scalanativelib/test/src/mill/scalanativelib/CompileRunTests.scala +++ b/libs/scalanativelib/test/src/mill/scalanativelib/CompileRunTests.scala @@ -3,6 +3,7 @@ package mill.scalanativelib import mill._ import mill.api.Discover import mill.api.ExecutionPaths +import mill.api.opt.* import mill.javalib.api.JvmWorkerUtil import mill.scalalib.{PublishModule, ScalaModule, TestModule} import mill.scalalib.publish.{Developer, License, PomSettings, VersionControl} @@ -65,7 +66,7 @@ object CompileRunTests extends TestSuite { object inherited extends ScalaNativeModule { val (scala, scalaNative, _) = matrix.head - def scalacOptions = Seq("-deprecation") + def scalacOptions = Opts("-deprecation") def scalaOrganization = "org.example" def scalaVersion = scala def scalaNativeVersion = scalaNative diff --git a/mill-itest-plugin.adoc b/mill-itest-plugin.adoc new file mode 100644 index 000000000000..390ac551a577 --- /dev/null +++ b/mill-itest-plugin.adoc @@ -0,0 +1,55 @@ += Draft for a new mill-itest plugin +:version: 0.7.1 +:mill-version: 1.0.0-RC2 + + +.`build.mill` +[,scala,subs="attributes"] +---- +//| mill-version: {mill-version} +//| mvnDeps: +//| - de.tototec::de.tobiasroeser.mill.integrationtest::{version} +package build + +import de.tobiasroeser.mill.integrationtest._ + +object demo extends ScalaModule with PublishModule { + // ... +} + +object itest extends Cross[ITestCross]("0.11.13", "0.12.14", "{mill-version}") +trait ItestCross extends MillIntegrationTestCrossModule { + def pluginsUnderTest = Seq(demo) +} +---- + +Plugin creates automatically a meta-build and loads the plugin under test into the classpath. + +You can write the test cases in the `/* Usage */` blocks + +.`itest/src/simple/build.mill` +[,scala] +---- +package build + +object simple extends Module { + def hello() = Task.Command { + println("hello") + } +} + + + +/* Usage + +> mill simple +hello + + */ +---- + +.`itest/src/simple/checks.itest.mill` +---- +// Test file + +---- \ No newline at end of file diff --git a/runner/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala b/runner/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala index a96f39da832a..7bb27b9892a1 100644 --- a/runner/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala +++ b/runner/bsp/worker/src/mill/bsp/worker/MillJavaBuildServer.scala @@ -34,7 +34,7 @@ private trait MillJavaBuildServer extends JavaBuildServer { this: MillBuildServe val res = f(ev) new JavacOptionsItem( id, - res.javacOptions.asJava, + res.javacOptions.toStringSeq.asJava, res.classpath.asJava, sanitizeUri(res.classesPath) ) diff --git a/runner/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala b/runner/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala index d214d7f215ca..b9357dad0977 100644 --- a/runner/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala +++ b/runner/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala @@ -57,23 +57,25 @@ private trait MillJvmBuildServer extends JvmBuildServer { this: MillBuildServer _, id, _, - ( - _, - forkArgs, - forkWorkingDir, - forkEnv, - _, - Some(testEnvVars) - ) - ) => + res +// ( +// _, +// forkArgs, +// forkWorkingDir, +// forkEnv, +// _, +// Some(testEnvVars) +// ) + ) if res.testEnvVars.isDefined => + val testEnvVars = res.testEnvVars.get val fullMainArgs: List[String] = List(testEnvVars.testRunnerClasspathArg, testEnvVars.argsFile) val item = new JvmEnvironmentItem( id, testEnvVars.classpath.map(sanitizeUri).asJava, - forkArgs.asJava, - forkWorkingDir.toString(), - forkEnv.asJava + res.forkArgs.toStringSeq.asJava, + res.forkWorkingDir.toString(), + res.forkEnv.view.mapValues(_.toString()).toMap.asJava ) item.setMainClasses(List(testEnvVars.mainClass).map(new JvmMainClass( _, @@ -107,9 +109,9 @@ private trait MillJvmBuildServer extends JvmBuildServer { this: MillBuildServer val item = new JvmEnvironmentItem( id, classpath.asJava, - res.forkArgs.asJava, + res.forkArgs.toStringSeq.asJava, res.forkWorkingDir.toString(), - res.forkEnv.asJava + res.forkEnv.view.mapValues(_.toString()).toMap.asJava ) val classes = res.mainClass.toList ++ res.localMainClasses diff --git a/runner/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala b/runner/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala index ef2e0bdaaae0..94717de218c8 100644 --- a/runner/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala +++ b/runner/bsp/worker/src/mill/bsp/worker/MillScalaBuildServer.scala @@ -41,13 +41,13 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer _, id, _, - (allScalacOptions, compileClasspath, classesPathTask) + res ) => new ScalacOptionsItem( id, - allScalacOptions.asJava, - compileClasspath(ev).asJava, - sanitizeUri(classesPathTask(ev)) + res.scalacOptionsTask.toStringSeq.asJava, + res.compileClasspathTask(ev).asJava, + sanitizeUri(res.classPathTask(ev)) ) } { values => @@ -67,7 +67,7 @@ private trait MillScalaBuildServer extends ScalaBuildServer { this: MillBuildSer val mainClasses = res.classes // val mainMain = m.mainClass().orElse(if(mainClasses.size == 1) mainClasses.headOption else None) val items = mainClasses.map { mc => - val scalaMc = new ScalaMainClass(mc, Seq().asJava, res.forkArgs.asJava) + val scalaMc = new ScalaMainClass(mc, Seq().asJava, res.forkArgs.toStringSeq.asJava) scalaMc.setEnvironmentVariables(res.forkEnv.map(e => s"${e._1}=${e._2}").toSeq.asJava) scalaMc } diff --git a/runner/meta/src/mill/meta/MillBuildRootModule.scala b/runner/meta/src/mill/meta/MillBuildRootModule.scala index c88b8373e306..183dbb055b81 100644 --- a/runner/meta/src/mill/meta/MillBuildRootModule.scala +++ b/runner/meta/src/mill/meta/MillBuildRootModule.scala @@ -1,13 +1,12 @@ package mill.meta import java.nio.file.Path -import mill.api.BuildCtx +import mill.api.{BuildCtx, Discover, PathRef, Result, Task} import mill.* -import mill.api.Result +import mill.api.opt.* import mill.api.daemon.internal.internal import mill.constants.CodeGenConstants.buildFileExtensions import mill.constants.OutFiles.* -import mill.api.{Discover, PathRef, Task} import mill.api.internal.RootModule import mill.scalalib.{Dep, DepSyntax, Lib, ScalaModule} import mill.javalib.api.{CompilationResult, Versions} @@ -255,11 +254,11 @@ trait MillBuildRootModule()(using .exclude("com.lihaoyi" -> "sourcecode_3") ) - override def scalacOptions: T[Seq[String]] = Task { + override def scalacOptions: T[Opts] = Task { super.scalacOptions() ++ // This warning comes up for package names with dashes in them like "package build.`foo-bar`", // but Mill generally handles these fine, so no need to warn the user - Seq("-deprecation", "-Wconf:msg=will be encoded on the classpath:silent") + Opts("-deprecation", "-Wconf:msg=will be encoded on the classpath:silent") } /** Used in BSP IntelliJ, which can only work with directories */ @@ -288,7 +287,7 @@ trait MillBuildRootModule()(using } // copied from `ScalaModule` - val jOpts = JavaCompilerOptions.split(javacOptions() ++ mandatoryJavacOptions()) + val jOpts = JavaCompilerOptions.split(javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) val worker = jvmWorker().internalWorker() worker.apply( ZincCompileMixed( @@ -298,7 +297,7 @@ trait MillBuildRootModule()(using javacOptions = jOpts.compiler, scalaVersion = scalaVersion(), scalaOrganization = scalaOrganization(), - scalacOptions = allScalacOptions(), + scalacOptions = allScalacOptions().toStringSeq, compilerClasspath = scalaCompilerClasspath(), scalacPluginClasspath = scalacPluginClasspath(), incrementalCompilation = zincIncrementalCompilation(), From 84c9c7e9ec12c63e4edeec3879445f1a50b14d28 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:20:42 +0000 Subject: [PATCH 04/67] [autofix.ci] apply automated fixes --- .../mill/api/daemon/internal/OptsApi.scala | 3 +- core/api/src/mill/api/opt/Opt.scala | 1 - core/api/src/mill/api/opt/OptGroup.scala | 1 - .../test/src/mill/api/ApplicativeTests.scala | 64 ++++++++++++++----- .../mill/androidlib/AndroidKotlinModule.scala | 7 +- .../src/mill/androidlib/AndroidModule.scala | 6 +- .../javalib/src/mill/javalib/JavaModule.scala | 19 +++++- .../src/mill/javalib/JavacOptions.scala | 2 +- .../mill/javalib/SemanticDbJavaModule.scala | 10 +-- .../javalib/errorprone/ErrorProneModule.scala | 1 - .../mill/kotlinlib/js/KotlinJsModule.scala | 2 +- .../src/mill/kotlinlib/ksp/KspModule.scala | 8 ++- .../src/mill/scalalib/ScalaModule.scala | 6 +- .../src/mill/scalalib/HelloWorldTests.scala | 3 +- .../mill/scalalib/ScalaScaladocTests.scala | 6 +- .../src/mill/meta/MillBuildRootModule.scala | 3 +- 16 files changed, 97 insertions(+), 45 deletions(-) diff --git a/core/api/daemon/src/mill/api/daemon/internal/OptsApi.scala b/core/api/daemon/src/mill/api/daemon/internal/OptsApi.scala index 37700ac9450e..4070fafb541a 100644 --- a/core/api/daemon/src/mill/api/daemon/internal/OptsApi.scala +++ b/core/api/daemon/src/mill/api/daemon/internal/OptsApi.scala @@ -5,8 +5,7 @@ trait OptsApi { def value: Seq[OptGroupApi] } -trait OptGroupApi { -} +trait OptGroupApi {} trait OptApi { def toString(): String diff --git a/core/api/src/mill/api/opt/Opt.scala b/core/api/src/mill/api/opt/Opt.scala index e3f9d7305a63..7e6396823d93 100644 --- a/core/api/src/mill/api/opt/Opt.scala +++ b/core/api/src/mill/api/opt/Opt.scala @@ -83,7 +83,6 @@ object Opt { // implicit def IterableToOpt[T](s: Iterable[T])(using f: T => Opt): Opt = // Opt(s.toSeq.flatMap(f(_).value)) - implicit def StringToOpt(s: String): Opt = Opt(s) implicit def OsPathToOpt(p: os.Path): Opt = Opt(p) diff --git a/core/api/src/mill/api/opt/OptGroup.scala b/core/api/src/mill/api/opt/OptGroup.scala index 83fefd77b59f..2d2e3c484527 100644 --- a/core/api/src/mill/api/opt/OptGroup.scala +++ b/core/api/src/mill/api/opt/OptGroup.scala @@ -50,5 +50,4 @@ object OptGroup { // implicit def ArrayToOptGroup[T](s: Array[T])(using f: T => OptGroup): OptGroup = // OptGroup(s.flatMap(f(_).value)) - } diff --git a/core/api/test/src/mill/api/ApplicativeTests.scala b/core/api/test/src/mill/api/ApplicativeTests.scala index f85db1e5e378..5e5e617b763b 100644 --- a/core/api/test/src/mill/api/ApplicativeTests.scala +++ b/core/api/test/src/mill/api/ApplicativeTests.scala @@ -24,7 +24,9 @@ object ApplicativeTests extends TestSuite { test("selfContained") { test("simple") - assert(TestOpt("lol " + 1) == TestOpt.some("lol 1")) - test("singleSome") - assert(TestOpt("lol " + TestOpt.some("hello")()) == TestOpt.some("lol hello")) + test("singleSome") - assert( + TestOpt("lol " + TestOpt.some("hello")()) == TestOpt.some("lol hello") + ) test("twoSomes") - assert( TestOpt(TestOpt.some("lol ")() + TestOpt.some("hello")()) == TestOpt.some("lol hello") ) @@ -35,27 +37,55 @@ object ApplicativeTests extends TestSuite { TestOpt( "lol " + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + - TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.some(" world")() + + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.some( + " world" + )() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + - TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.some(" moo")() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.none() + TestOpt.some( + " moo" + )() ) == TestOpt.none ) assert( TestOpt( "lol " + - TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some("d")() + - TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + - TestOpt.some("d")() + TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + - TestOpt.some("c")() + TestOpt.some("d")() + TestOpt.some("e")() + TestOpt.some("a")() + - TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some("d")() + TestOpt.some("e")() + - TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some("d")() + - TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + - TestOpt.some("d")() + TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + - TestOpt.some("c")() + TestOpt.some("d")() + TestOpt.some("e")() + TestOpt.some("a")() + - TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some("d")() + TestOpt.some("e")() + - TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some("d")() + - TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some( + "d" + )() + + TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some( + "c" + )() + + TestOpt.some("d")() + TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some( + "b" + )() + + TestOpt.some("c")() + TestOpt.some("d")() + TestOpt.some("e")() + TestOpt.some( + "a" + )() + + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some("d")() + TestOpt.some( + "e" + )() + + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some( + "d" + )() + + TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some( + "c" + )() + + TestOpt.some("d")() + TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some( + "b" + )() + + TestOpt.some("c")() + TestOpt.some("d")() + TestOpt.some("e")() + TestOpt.some( + "a" + )() + + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some("d")() + TestOpt.some( + "e" + )() + + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some("c")() + TestOpt.some( + "d" + )() + + TestOpt.some("e")() + TestOpt.some("a")() + TestOpt.some("b")() + TestOpt.some( + "c" + )() + TestOpt.some("d")() + TestOpt.some("e")() ) == TestOpt.some("lol abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde") ) @@ -68,7 +98,9 @@ object ApplicativeTests extends TestSuite { val lol = "lol " def hell(o: String) = "hell" + o test("simple") - assert(TestOpt(lol + 1) == TestOpt.some("lol 1")) - test("singleSome") - assert(TestOpt(lol + TestOpt.some(hell("o"))()) == TestOpt.some("lol hello")) + test("singleSome") - assert( + TestOpt(lol + TestOpt.some(hell("o"))()) == TestOpt.some("lol hello") + ) test("twoSomes") - assert( TestOpt(TestOpt.some(lol)() + TestOpt.some(hell("o"))()) == TestOpt.some("lol hello") ) diff --git a/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala b/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala index 0c23379dbe77..b4b503599470 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala @@ -6,7 +6,12 @@ import mill.api.opt.* import mill.javalib.{CoursierModule, Dep} import mill.kotlinlib.{Dep, DepSyntax, KotlinModule, KotlincOptions} import mill.{T, Task} -import mill.androidlib.databinding.{AndroidDataBindingWorker, AndroidDataBindingWorkerModule, GenerateBindingSourcesArgs, ProcessResourcesArgs} +import mill.androidlib.databinding.{ + AndroidDataBindingWorker, + AndroidDataBindingWorkerModule, + GenerateBindingSourcesArgs, + ProcessResourcesArgs +} import mill.util.Jvm // TODO expose Compose configuration options diff --git a/libs/androidlib/src/mill/androidlib/AndroidModule.scala b/libs/androidlib/src/mill/androidlib/AndroidModule.scala index 0e93003dd768..9ea29657588c 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidModule.scala @@ -516,7 +516,8 @@ trait AndroidModule extends JavaModule { outer => * The Java compiled classes of [[androidResources]] */ def androidCompiledRClasses: T[CompilationResult] = Task(persistent = true) { - val jOpts = JavaCompilerOptions.split(javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) + val jOpts = + JavaCompilerOptions.split(javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) val worker = jvmWorker().internalWorker() worker.apply( ZincCompileJava( @@ -728,7 +729,8 @@ trait AndroidModule extends JavaModule { outer => val rJar = Task.dest / "R.jar" - val jOpts = JavaCompilerOptions.split(javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) + val jOpts = + JavaCompilerOptions.split(javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) val worker = jvmWorker().internalWorker() val classesDest = worker .apply( diff --git a/libs/javalib/src/mill/javalib/JavaModule.scala b/libs/javalib/src/mill/javalib/JavaModule.scala index bde994b4975a..7dcdb646ee9f 100644 --- a/libs/javalib/src/mill/javalib/JavaModule.scala +++ b/libs/javalib/src/mill/javalib/JavaModule.scala @@ -7,10 +7,25 @@ import coursier.params.ResolutionParams import coursier.parse.{JavaOrScalaModule, ModuleParser} import coursier.util.{EitherT, ModuleMatcher, Monad} import mainargs.Flag -import mill.api.{DefaultTaskModule, MillException, ModuleRef, PathRef, Result, Segment, Task, TaskCtx} +import mill.api.{ + DefaultTaskModule, + MillException, + ModuleRef, + PathRef, + Result, + Segment, + Task, + TaskCtx +} import mill.api.opt.* import mill.api.daemon.internal.{EvaluatorApi, JavaModuleApi, internal} -import mill.api.daemon.internal.bsp.{BspBuildTarget, BspJavaModuleApi, BspModuleApi, BspUri, JvmBuildTarget} +import mill.api.daemon.internal.bsp.{ + BspBuildTarget, + BspJavaModuleApi, + BspModuleApi, + BspUri, + JvmBuildTarget +} import mill.api.daemon.internal.eclipse.GenEclipseInternalApi import mill.javalib.* import mill.api.daemon.internal.idea.GenIdeaInternalApi diff --git a/libs/javalib/src/mill/javalib/JavacOptions.scala b/libs/javalib/src/mill/javalib/JavacOptions.scala index 89d5d13aef40..afc89a73b616 100644 --- a/libs/javalib/src/mill/javalib/JavacOptions.scala +++ b/libs/javalib/src/mill/javalib/JavacOptions.scala @@ -5,5 +5,5 @@ object JavacOptions { val `-target` = "-target" val `-source` = "-source" val `-deprecation` = "-deprecation" - + } diff --git a/libs/javalib/src/mill/javalib/SemanticDbJavaModule.scala b/libs/javalib/src/mill/javalib/SemanticDbJavaModule.scala index 1b593a3d7575..7d41e82652d3 100644 --- a/libs/javalib/src/mill/javalib/SemanticDbJavaModule.scala +++ b/libs/javalib/src/mill/javalib/SemanticDbJavaModule.scala @@ -1,14 +1,6 @@ package mill.javalib -import mill.api.{ - BuildCtx, - Discover, - ExternalModule, - ModuleRef, - PathRef, - Result, - experimental -} +import mill.api.{BuildCtx, Discover, ExternalModule, ModuleRef, PathRef, Result, experimental} import mill.api.daemon.internal.SemanticDbJavaModuleApi import mill.api.opt.* import mill.constants.CodeGenConstants diff --git a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala index 6053471d1adf..911a60a01549 100644 --- a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala +++ b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala @@ -5,7 +5,6 @@ import mill.api.opt.* import mill.javalib.{Dep, DepSyntax, JavaModule} import mill.{T, Task} -import java.io.File /** * Integrated Error Prone into a [[JavaModule]]. diff --git a/libs/kotlinlib/src/mill/kotlinlib/js/KotlinJsModule.scala b/libs/kotlinlib/src/mill/kotlinlib/js/KotlinJsModule.scala index b71e26088bbb..67eb4c9dcb31 100644 --- a/libs/kotlinlib/src/mill/kotlinlib/js/KotlinJsModule.scala +++ b/libs/kotlinlib/src/mill/kotlinlib/js/KotlinJsModule.scala @@ -7,7 +7,7 @@ import mill.api.{PathRef, Result, Task} import mill.api.opt.* import mill.api.Task.Command import mill.kotlinlib.worker.api.{KotlinWorker, KotlinWorkerTarget} -import mill.kotlinlib.{Dep, DepSyntax, KotlinModule, KotlinWorkerManager, KotlincOptions} +import mill.kotlinlib.{Dep, DepSyntax, KotlinModule, KotlinWorkerManager} import mill.javalib.Lib import mill.javalib.api.CompilationResult import mill.util.Jvm diff --git a/libs/kotlinlib/src/mill/kotlinlib/ksp/KspModule.scala b/libs/kotlinlib/src/mill/kotlinlib/ksp/KspModule.scala index 892f45fce36b..8952fa1dedf9 100644 --- a/libs/kotlinlib/src/mill/kotlinlib/ksp/KspModule.scala +++ b/libs/kotlinlib/src/mill/kotlinlib/ksp/KspModule.scala @@ -341,7 +341,9 @@ trait KspModule extends KotlinModule { outer => val kspCachesDir = Task.dest / "caches" val processorOptionsValue = - kspProcessorOptions().map((key, value) => s"$key=${value.toString}").toSeq.mkString(File.pathSeparator) + kspProcessorOptions().map((key, value) => s"$key=${value.toString}").toSeq.mkString( + File.pathSeparator + ) val processorOptions = if (processorOptionsValue.isEmpty) "" @@ -448,7 +450,9 @@ trait KspModule extends KotlinModule { outer => val kspCachesDir = Task.dest / "caches" val processorOptionsValue = - kspProcessorOptions().map((key, value) => s"$key=${value.toString()}").toSeq.mkString(File.pathSeparator) + kspProcessorOptions().map((key, value) => s"$key=${value.toString()}").toSeq.mkString( + File.pathSeparator + ) val processorOptions = if (processorOptionsValue.isEmpty) "" diff --git a/libs/scalalib/src/mill/scalalib/ScalaModule.scala b/libs/scalalib/src/mill/scalalib/ScalaModule.scala index 8bc5de47d850..01a56e497d04 100644 --- a/libs/scalalib/src/mill/scalalib/ScalaModule.scala +++ b/libs/scalalib/src/mill/scalalib/ScalaModule.scala @@ -281,7 +281,8 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase |For details, see: https://github.com/sbt/zinc/issues/1010""".stripMargin ) - val jOpts = JavaCompilerOptions.split(javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) + val jOpts = + JavaCompilerOptions.split(javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) val worker = jvmWorker().internalWorker() @@ -617,7 +618,8 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase ) .filterNot(_ == "-Xfatal-warnings") - val javacOpts = SemanticDbJavaModule.javacOptionsTask(javacOptions(), semanticDbJavaVersion()).toStringSeq + val javacOpts = + SemanticDbJavaModule.javacOptionsTask(javacOptions(), semanticDbJavaVersion()).toStringSeq Task.log.debug(s"effective scalac options: ${scalacOptions}") Task.log.debug(s"effective javac options: ${javacOpts}") diff --git a/libs/scalalib/test/src/mill/scalalib/HelloWorldTests.scala b/libs/scalalib/test/src/mill/scalalib/HelloWorldTests.scala index c5bd49c42dcc..8862ce444b09 100644 --- a/libs/scalalib/test/src/mill/scalalib/HelloWorldTests.scala +++ b/libs/scalalib/test/src/mill/scalalib/HelloWorldTests.scala @@ -76,7 +76,8 @@ object HelloWorldTests extends TestSuite { object HelloWorldFatalWarnings extends TestRootModule { object core extends HelloWorldModule { - override def scalacOptions = Task { Opts(ScalacOptions.`-Ywarn-unused`, ScalacOptions.`-Xfatal-warnings`) } + override def scalacOptions = + Task { Opts(ScalacOptions.`-Ywarn-unused`, ScalacOptions.`-Xfatal-warnings`) } } lazy val millDiscover = Discover[this.type] } diff --git a/libs/scalalib/test/src/mill/scalalib/ScalaScaladocTests.scala b/libs/scalalib/test/src/mill/scalalib/ScalaScaladocTests.scala index f2054c18afd2..283fabd5eab8 100644 --- a/libs/scalalib/test/src/mill/scalalib/ScalaScaladocTests.scala +++ b/libs/scalalib/test/src/mill/scalalib/ScalaScaladocTests.scala @@ -12,7 +12,8 @@ object ScalaScaladocTests extends TestSuite { object HelloWorldWithDocVersion extends TestRootModule { object core extends HelloWorldModule { - override def scalacOptions = Task { Opts(ScalacOptions.`-Ywarn-unused`, ScalacOptions.`-Xfatal-warnings`) } + override def scalacOptions = + Task { Opts(ScalacOptions.`-Ywarn-unused`, ScalacOptions.`-Xfatal-warnings`) } override def scalaDocOptions = super.scalaDocOptions() ++ Opts("-doc-version", "1.2.3") } @@ -21,7 +22,8 @@ object ScalaScaladocTests extends TestSuite { object HelloWorldOnlyDocVersion extends TestRootModule { object core extends HelloWorldModule { - override def scalacOptions = Task { Opts(ScalacOptions.`-Ywarn-unused`, ScalacOptions.`-Xfatal-warnings`) } + override def scalacOptions = + Task { Opts(ScalacOptions.`-Ywarn-unused`, ScalacOptions.`-Xfatal-warnings`) } override def scalaDocOptions = Task { Opts("-doc-version", "1.2.3") } } diff --git a/runner/meta/src/mill/meta/MillBuildRootModule.scala b/runner/meta/src/mill/meta/MillBuildRootModule.scala index 183dbb055b81..739724f445a2 100644 --- a/runner/meta/src/mill/meta/MillBuildRootModule.scala +++ b/runner/meta/src/mill/meta/MillBuildRootModule.scala @@ -287,7 +287,8 @@ trait MillBuildRootModule()(using } // copied from `ScalaModule` - val jOpts = JavaCompilerOptions.split(javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) + val jOpts = + JavaCompilerOptions.split(javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq) val worker = jvmWorker().internalWorker() worker.apply( ZincCompileMixed( From 57af960ac836d5ad10c3cd27f440225766fe7949 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:37:58 +0000 Subject: [PATCH 05/67] [autofix.ci] apply automated fixes (attempt 2/3) --- libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala index 911a60a01549..707f7c19e4bb 100644 --- a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala +++ b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala @@ -5,7 +5,6 @@ import mill.api.opt.* import mill.javalib.{Dep, DepSyntax, JavaModule} import mill.{T, Task} - /** * Integrated Error Prone into a [[JavaModule]]. * From 3bdb2e91ed1f311afa611e632db67d5de304e8ce Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 5 Nov 2025 21:28:38 +0100 Subject: [PATCH 06/67] Don't use Opts for errorProneOptions --- .../src/mill/javalib/errorprone/ErrorProneModule.scala | 4 ++-- .../test/src/mill/javalib/errorprone/ErrorProneTests.scala | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala index 707f7c19e4bb..e5f0cebb062e 100644 --- a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala +++ b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala @@ -43,7 +43,7 @@ trait ErrorProneModule extends JavaModule { "-XDcompilePolicy=simple", "-processorpath", processorPath, - (Seq("-Xplugin:ErrorProne") ++ errorProneOptions().toStringSeq).mkString(" ") + (Seq("-Xplugin:ErrorProne") ++ errorProneOptions()).mkString(" ") ) val java17Options: Seq[String] = Option.when(scala.util.Properties.isJavaAtLeast(16))(Seq( "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", @@ -66,7 +66,7 @@ trait ErrorProneModule extends JavaModule { * * Those are documented as "flags" at https://errorprone.info/docs/flags */ - def errorProneOptions: T[Opts] = Task { Opts() } + def errorProneOptions: T[Seq[String]] = Task { Seq() } /** * Appends the [[errorProneJavacEnableOptions]] to the Java compiler options. diff --git a/libs/javalib/test/src/mill/javalib/errorprone/ErrorProneTests.scala b/libs/javalib/test/src/mill/javalib/errorprone/ErrorProneTests.scala index b0904f117d56..b30046ff9e8d 100644 --- a/libs/javalib/test/src/mill/javalib/errorprone/ErrorProneTests.scala +++ b/libs/javalib/test/src/mill/javalib/errorprone/ErrorProneTests.scala @@ -2,7 +2,6 @@ package mill.javalib.errorprone import mill.{T, Task} import mill.api.Discover -import mill.api.opt.* import mill.javalib.JavaModule import mill.testkit.{TestRootModule, UnitTester} import os.Path @@ -18,8 +17,8 @@ object ErrorProneTests extends TestSuite { lazy val millDiscover = Discover[this.type] } object errorProneCustom extends TestRootModule with JavaModule with ErrorProneModule { - override def errorProneOptions: T[Opts] = Task { - Opts("-XepAllErrorsAsWarnings") + override def errorProneOptions: T[Seq[String]] = Task { + Seq("-XepAllErrorsAsWarnings") } lazy val millDiscover = Discover[this.type] } From 3e40f64b3914c40bffed0ab60fc7c6667517f475 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 5 Nov 2025 22:12:30 +0100 Subject: [PATCH 07/67] Fix ErrorProneModule --- .../src/mill/javalib/errorprone/ErrorProneModule.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala index e5f0cebb062e..83f8871a60cb 100644 --- a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala +++ b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala @@ -37,12 +37,12 @@ trait ErrorProneModule extends JavaModule { * Options used to enable and configure the `error-prone` plugin in the Java compiler. */ def errorProneJavacEnableOptions: T[Opts] = Task { - val processorPath: Seq[os.Path] = errorProneClasspath().map(_.path) + val processorPath: Opt = Opt.mkPath(errorProneClasspath().map(_.path), sep = java.io.File.pathSeparator) val enableOpts: Opts = Opts( "-XDcompilePolicy=simple", - "-processorpath", - processorPath, + OptGroup("-processorpath", processorPath), + // ErrorProne options are given as a single argument containing spaces (Seq("-Xplugin:ErrorProne") ++ errorProneOptions()).mkString(" ") ) val java17Options: Seq[String] = Option.when(scala.util.Properties.isJavaAtLeast(16))(Seq( From 033832aea6675c10cb825701ebd253dc9c8b3e50 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 5 Nov 2025 22:13:48 +0100 Subject: [PATCH 08/67] Experiemnt with OptGroup.apply --- core/api/src/mill/api/opt/Opt.scala | 14 ++++++++++---- core/api/src/mill/api/opt/OptGroup.scala | 15 ++++++++++++--- core/api/test/src/mill/api/opt/OptsTests.scala | 2 +- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/core/api/src/mill/api/opt/Opt.scala b/core/api/src/mill/api/opt/Opt.scala index 7e6396823d93..ce8e6c9bba84 100644 --- a/core/api/src/mill/api/opt/Opt.scala +++ b/core/api/src/mill/api/opt/Opt.scala @@ -83,10 +83,16 @@ object Opt { // implicit def IterableToOpt[T](s: Iterable[T])(using f: T => Opt): Opt = // Opt(s.toSeq.flatMap(f(_).value)) - implicit def StringToOpt(s: String): Opt = Opt(s) - - implicit def OsPathToOpt(p: os.Path): Opt = Opt(p) + implicit def AllToOpt(o: String | os.Path | Opt): Opt = o match { + case s: String => Opt(s) + case p: os.Path => Opt(p) + case o: Opt => o + } - implicit def OptToOpt(o: Opt): Opt = o +// implicit def StringToOpt(s: String): Opt = Opt(s) +// +// implicit def OsPathToOpt(p: os.Path): Opt = Opt(p) +// +// implicit def OptToOpt(o: Opt): Opt = o } diff --git a/core/api/src/mill/api/opt/OptGroup.scala b/core/api/src/mill/api/opt/OptGroup.scala index 2d2e3c484527..68a5c7502102 100644 --- a/core/api/src/mill/api/opt/OptGroup.scala +++ b/core/api/src/mill/api/opt/OptGroup.scala @@ -28,9 +28,18 @@ case class OptGroup private (value: Seq[Opt]) extends OptGroupApi object OptGroup { @targetName("applyVarAar") - def apply(opts: Opt*): OptGroup = new OptGroup(opts) - @targetName("applyIterable") - def apply[T](opts: T*)(using f: T => Opt): OptGroup = new OptGroup(opts.map(f(_))) + def apply(opts: (String | os.Path | Opt | Seq[(String | os.Path | Opt)])*): OptGroup = new OptGroup(opts.flatMap { + case s: String => Seq(Opt(s)) + case p: os.Path => Seq(Opt(p)) + case o: Opt => Seq(o) + case o: Seq[(String | os.Path | Opt)] => o.map { + case s: String => Opt(s) + case p: os.Path => Opt(p) + case o: Opt => o + } + }) +// @targetName("applyIterable") +// def apply[T](opts: T*)(using f: T => Opt): OptGroup = new OptGroup(opts.map(f(_))) def when(cond: Boolean)(value: Opt*): OptGroup = if (cond) OptGroup(value*) else OptGroup() diff --git a/core/api/test/src/mill/api/opt/OptsTests.scala b/core/api/test/src/mill/api/opt/OptsTests.scala index b015bd867f40..afb663ab932e 100644 --- a/core/api/test/src/mill/api/opt/OptsTests.scala +++ b/core/api/test/src/mill/api/opt/OptsTests.scala @@ -35,7 +35,7 @@ class OptsTests extends TestSuite { // some files as ArgGroup OptGroup(sources2*), // Mixed ArgGroup - OptGroup(opt"--extra", opt"-Xplugin=${plugin1}") ++ OptGroup(sources1*) + OptGroup("--extra", opt"-Xplugin=${plugin1}") ++ OptGroup(sources1*) ) val expectedOpts1 = Opts( From ef8a23beefd662c687b95d77065198696ba6b580 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 5 Nov 2025 21:57:50 +0000 Subject: [PATCH 09/67] [autofix.ci] apply automated fixes --- core/api/src/mill/api/opt/OptGroup.scala | 21 ++++++++++--------- .../javalib/errorprone/ErrorProneModule.scala | 3 ++- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/core/api/src/mill/api/opt/OptGroup.scala b/core/api/src/mill/api/opt/OptGroup.scala index 68a5c7502102..e35a747ce526 100644 --- a/core/api/src/mill/api/opt/OptGroup.scala +++ b/core/api/src/mill/api/opt/OptGroup.scala @@ -28,16 +28,17 @@ case class OptGroup private (value: Seq[Opt]) extends OptGroupApi object OptGroup { @targetName("applyVarAar") - def apply(opts: (String | os.Path | Opt | Seq[(String | os.Path | Opt)])*): OptGroup = new OptGroup(opts.flatMap { - case s: String => Seq(Opt(s)) - case p: os.Path => Seq(Opt(p)) - case o: Opt => Seq(o) - case o: Seq[(String | os.Path | Opt)] => o.map { - case s: String => Opt(s) - case p: os.Path => Opt(p) - case o: Opt => o - } - }) + def apply(opts: (String | os.Path | Opt | Seq[(String | os.Path | Opt)])*): OptGroup = + new OptGroup(opts.flatMap { + case s: String => Seq(Opt(s)) + case p: os.Path => Seq(Opt(p)) + case o: Opt => Seq(o) + case o: Seq[(String | os.Path | Opt)] => o.map { + case s: String => Opt(s) + case p: os.Path => Opt(p) + case o: Opt => o + } + }) // @targetName("applyIterable") // def apply[T](opts: T*)(using f: T => Opt): OptGroup = new OptGroup(opts.map(f(_))) diff --git a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala index 83f8871a60cb..e8f4f6869309 100644 --- a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala +++ b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala @@ -37,7 +37,8 @@ trait ErrorProneModule extends JavaModule { * Options used to enable and configure the `error-prone` plugin in the Java compiler. */ def errorProneJavacEnableOptions: T[Opts] = Task { - val processorPath: Opt = Opt.mkPath(errorProneClasspath().map(_.path), sep = java.io.File.pathSeparator) + val processorPath: Opt = + Opt.mkPath(errorProneClasspath().map(_.path), sep = java.io.File.pathSeparator) val enableOpts: Opts = Opts( "-XDcompilePolicy=simple", From b8c7b7667c12ef7f7de7e7aa3256b8612544e6f9 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 08:30:57 +0100 Subject: [PATCH 10/67] make test path non-user specific --- core/api/test/src/mill/api/opt/OptsTests.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/api/test/src/mill/api/opt/OptsTests.scala b/core/api/test/src/mill/api/opt/OptsTests.scala index afb663ab932e..d35a6e1bc077 100644 --- a/core/api/test/src/mill/api/opt/OptsTests.scala +++ b/core/api/test/src/mill/api/opt/OptsTests.scala @@ -5,7 +5,7 @@ import mill.api.opt.* class OptsTests extends TestSuite { - val homeDir = os.home + val homeDir = os.root / "tmp/opts-test" val workDir = homeDir / "work" val outDir = workDir / "out" @@ -91,7 +91,7 @@ class OptsTests extends TestSuite { val json = upickle.write(opts1) assertGoldenLiteral( json, - "{\"value\":[{\"value\":[[[\"-deprecation\",null]],[[\"-verbose\",null]],[[\"--release\",null]],[[\"17\",null]],[[\"-Xplugin=\",null],[null,\"/home/lefou/.cache/plugin1\"]],[[\"-Xplugin:\",null],[null,\"/home/lefou/.cache/plugin1\"]],[[null,\"/home/lefou/work/src1\"]],[[null,\"/home/lefou/work/src2\"]],[[null,\"/home/lefou/work/src3\"]],[[null,\"/home/lefou/work/src4\"]],[[\"--extra\",null]],[[\"-Xplugin=\",null],[null,\"/home/lefou/.cache/plugin1\"]],[[null,\"/home/lefou/work/src1\"]],[[null,\"/home/lefou/work/src2\"]]]}]}" + "{\"value\":[{\"value\":[[[\"-deprecation\",null]],[[\"-verbose\",null]],[[\"--release\",null]],[[\"17\",null]],[[\"-Xplugin=\",null],[null,\"/tmp/opts-test/.cache/plugin1\"]],[[\"-Xplugin:\",null],[null,\"/tmp/opts-test/.cache/plugin1\"]],[[null,\"/tmp/opts-test/work/src1\"]],[[null,\"/tmp/opts-test/work/src2\"]],[[null,\"/tmp/opts-test/work/src3\"]],[[null,\"/tmp/opts-test/work/src4\"]],[[\"--extra\",null]],[[\"-Xplugin=\",null],[null,\"/tmp/opts-test/.cache/plugin1\"]],[[null,\"/tmp/opts-test/work/src1\"]],[[null,\"/tmp/opts-test/work/src2\"]]]}]}" ) assert(json.split("\\Q$HOME\\E").size == 1) val back = upickle.read[Opts](json) From 9810fb8b0536690bd3ba39b45d76859035aee9ec Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 09:06:46 +0100 Subject: [PATCH 11/67] More Opts construction tweaks --- core/api/src/mill/api/opt/OptGroup.scala | 16 ++++++------ core/api/src/mill/api/opt/Opts.scala | 26 ++++++++++++++----- .../api/test/src/mill/api/opt/OptsTests.scala | 19 +++++++++++--- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/core/api/src/mill/api/opt/OptGroup.scala b/core/api/src/mill/api/opt/OptGroup.scala index e35a747ce526..f65015469fba 100644 --- a/core/api/src/mill/api/opt/OptGroup.scala +++ b/core/api/src/mill/api/opt/OptGroup.scala @@ -48,14 +48,14 @@ object OptGroup { // (tuple: (OptTypes, OptTypes)) => // OptGroup(Opt(tuple._1), Opt(tuple._2)) - implicit def StringToOptGroup(s: String): OptGroup = OptGroup(Seq(Opt(s))) - - implicit def OsPathToOptGroup(p: os.Path): OptGroup = OptGroup(Seq(Opt(p))) - - implicit def OptToOptGroup(o: Opt): OptGroup = OptGroup(Seq(o)) - - implicit def IterableToOptGroup[T](s: Iterable[T])(using f: T => OptGroup): OptGroup = - OptGroup(s.toSeq.flatMap(f(_).value)) +// implicit def StringToOptGroup(s: String): OptGroup = OptGroup(Seq(Opt(s))) +// +// implicit def OsPathToOptGroup(p: os.Path): OptGroup = OptGroup(Seq(Opt(p))) +// +// implicit def OptToOptGroup(o: Opt): OptGroup = OptGroup(Seq(o)) +// +// implicit def IterableToOptGroup[T](s: Iterable[T])(using f: T => OptGroup): OptGroup = +// OptGroup(s.toSeq.flatMap(f(_).value)) // implicit def ArrayToOptGroup[T](s: Array[T])(using f: T => OptGroup): OptGroup = // OptGroup(s.flatMap(f(_).value)) diff --git a/core/api/src/mill/api/opt/Opts.scala b/core/api/src/mill/api/opt/Opts.scala index 6d5958c09821..1e1407e405fa 100644 --- a/core/api/src/mill/api/opt/Opts.scala +++ b/core/api/src/mill/api/opt/Opts.scala @@ -2,9 +2,10 @@ package mill.api.opt import mill.api.daemon.internal.OptsApi +import scala.annotation.targetName import scala.language.implicitConversions -case class Opts private (override val value: OptGroup*) extends OptsApi +case class Opts private (override val value: Seq[OptGroup]) extends OptsApi derives upickle.ReadWriter { def toStringSeq: Seq[String] = value.flatMap(_.toStringSeq) @@ -16,17 +17,28 @@ case class Opts private (override val value: OptGroup*) extends OptsApi def containsPaths: Boolean = value.exists(_.containsPaths) def isEmpty: Boolean = value.isEmpty - def filterGroup(pred: OptGroup => Boolean): Opts = Opts(value.filter(pred)*) - def mapGroup(f: OptGroup => OptGroup): Opts = Opts(value.map(f)*) - def flatMap(f: OptGroup => Seq[OptGroup]): Opts = Opts(value.flatMap(f)*) + def filterGroup(pred: OptGroup => Boolean): Opts = Opts.apply(value.filter(pred)*) + def mapGroup(f: OptGroup => OptGroup): Opts = Opts.apply(value.map(f)*) + def flatMap(f: OptGroup => Seq[OptGroup]): Opts = Opts.apply(value.flatMap(f)*) } object Opts { - def apply(value: OptGroup*): Opts = new Opts(value.filter(!_.isEmpty)) -// @targetName("applyUnion") -// def apply(value: (Opt | OptGroup | Seq[Opt])*): Opts = Opts(value.flatMap { + @targetName("applyVarArgUnion") +// def apply(value: OptGroup*): Opts = new Opts(value.filter(!_.isEmpty)) +// def apply(value: (String | os.Path | Opt | OptGroup | Seq[Opt])*): Opts = Opts(value.flatMap { // case a: Opt => Seq(OptGroup(a)) // case a: OptGroup => Seq(a) // case s: Iterable[Opt] => s.map(OptGroup(_)) // }) + + def apply(opts: (String | os.Path | Opt | Seq[(String | os.Path | Opt)] | OptGroup | Opts)*): Opts = + new Opts(opts.flatMap { + // Seq of OptGroup + case s: String => Seq(OptGroup(s)) + case p: os.Path => Seq(OptGroup(p)) + case o: Opt => Seq(OptGroup(o)) + case o: Seq[(String | os.Path | Opt)] => o.map(OptGroup(_)) + case o: OptGroup => Seq(o) + case o: Opts => o.value + }) } diff --git a/core/api/test/src/mill/api/opt/OptsTests.scala b/core/api/test/src/mill/api/opt/OptsTests.scala index d35a6e1bc077..57b438654215 100644 --- a/core/api/test/src/mill/api/opt/OptsTests.scala +++ b/core/api/test/src/mill/api/opt/OptsTests.scala @@ -49,8 +49,7 @@ class OptsTests extends TestSuite { Opt("-Xplugin:", plugin1), Opt(srcDir1), Opt(srcDir2), - Opt(srcDir3), - Opt(srcDir4), + OptGroup(Opt(srcDir3), Opt(srcDir4)), OptGroup( Opt("--extra"), Opt("-Xplugin=", plugin1), @@ -79,7 +78,18 @@ class OptsTests extends TestSuite { sources1.map(_.toString()) override def tests: Tests = Tests { + test("OptGroup.isEmpty") { + val emptyGroup = OptGroup() + assert(emptyGroup.isEmpty) + assert(emptyGroup.toStringSeq.isEmpty) + } + test("Opts.isEmpty") { + val empty = Opts() + assert(empty.isEmpty) + assert(empty.toStringSeq.isEmpty) + } test("structure") { + assert(Opts("arg1").toStringSeq == Seq("arg1")) assert(opts1 == expectedOpts1) } test("toStringSeq") { @@ -91,8 +101,11 @@ class OptsTests extends TestSuite { val json = upickle.write(opts1) assertGoldenLiteral( json, - "{\"value\":[{\"value\":[[[\"-deprecation\",null]],[[\"-verbose\",null]],[[\"--release\",null]],[[\"17\",null]],[[\"-Xplugin=\",null],[null,\"/tmp/opts-test/.cache/plugin1\"]],[[\"-Xplugin:\",null],[null,\"/tmp/opts-test/.cache/plugin1\"]],[[null,\"/tmp/opts-test/work/src1\"]],[[null,\"/tmp/opts-test/work/src2\"]],[[null,\"/tmp/opts-test/work/src3\"]],[[null,\"/tmp/opts-test/work/src4\"]],[[\"--extra\",null]],[[\"-Xplugin=\",null],[null,\"/tmp/opts-test/.cache/plugin1\"]],[[null,\"/tmp/opts-test/work/src1\"]],[[null,\"/tmp/opts-test/work/src2\"]]]}]}" + "{\"value\":[{\"value\":[[[\"-deprecation\",null]]]},{\"value\":[[[\"-verbose\",null]]]},{\"value\":[[[\"--release\",null]],[[\"17\",null]]]},{\"value\":[[[\"-Xplugin=\",null],[null,\"/tmp/opts-test/.cache/plugin1\"]]]},{\"value\":[[[\"-Xplugin:\",null],[null,\"/tmp/opts-test/.cache/plugin1\"]]]},{\"value\":[[[null,\"/tmp/opts-test/work/src1\"]]]},{\"value\":[[[null,\"/tmp/opts-test/work/src2\"]]]},{\"value\":[[[null,\"/tmp/opts-test/work/src3\"]],[[null,\"/tmp/opts-test/work/src4\"]]]},{\"value\":[[[\"--extra\",null]],[[\"-Xplugin=\",null],[null,\"/tmp/opts-test/.cache/plugin1\"]],[[null,\"/tmp/opts-test/work/src1\"]],[[null,\"/tmp/opts-test/work/src2\"]]]}]}" ) +// pprint.log(upickle.write(opts1, indent = 4)) + pprint.log(opts1) + pprint.log(opts1.toString) assert(json.split("\\Q$HOME\\E").size == 1) val back = upickle.read[Opts](json) assert(opts1 == back) From 8af03cd8f5478955c3a8eb78a887546544c5708e Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 09:33:45 +0100 Subject: [PATCH 12/67] WIP --- core/api/src/mill/api/opt/Opt.scala | 8 ++++---- core/api/src/mill/api/opt/OptGroup.scala | 14 +++++++++----- core/api/src/mill/api/opt/Opts.scala | 11 +++++++---- .../src/mill/scalanativelib/TestingTests.scala | 5 +++-- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/core/api/src/mill/api/opt/Opt.scala b/core/api/src/mill/api/opt/Opt.scala index ce8e6c9bba84..c3c284922ac2 100644 --- a/core/api/src/mill/api/opt/Opt.scala +++ b/core/api/src/mill/api/opt/Opt.scala @@ -11,14 +11,14 @@ case class Opt private (value: Seq[Opt.OptTypes]) extends OptApi { def map(conv: Opt.OptTypes => Opt.OptTypes): Opt = Opt(value.map(conv)*) - private def startStrings: Seq[String] = - value.takeWhile(_.isInstanceOf[String]).collect { case s: String => s } + private def startString: String = + value.takeWhile(_.isInstanceOf[String]).collect { case s: String => s }.mkString("") - def startsWith(prefix: String): Boolean = startStrings.mkString("").startsWith(prefix) + def startsWith(prefix: String): Boolean = startString.startsWith(prefix) def mapStartString(rep: String => String): Opt = { val rest = value.dropWhile(_.isInstanceOf[String]) - Opt((rep(startStrings.mkString("")) +: rest)*) + Opt.apply((rep(startString) +: rest)*) } def containsPaths: Boolean = value.exists { diff --git a/core/api/src/mill/api/opt/OptGroup.scala b/core/api/src/mill/api/opt/OptGroup.scala index f65015469fba..5c1e578a8644 100644 --- a/core/api/src/mill/api/opt/OptGroup.scala +++ b/core/api/src/mill/api/opt/OptGroup.scala @@ -17,6 +17,7 @@ case class OptGroup private (value: Seq[Opt]) extends OptGroupApi def containsPaths: Boolean = value.exists(_.containsPaths) def head: Opt = value.head + def headOption: Option[Opt] = value.headOption def toStringSeq: Seq[String] = value.map(_.toString()) @@ -28,18 +29,21 @@ case class OptGroup private (value: Seq[Opt]) extends OptGroupApi object OptGroup { @targetName("applyVarAar") - def apply(opts: (String | os.Path | Opt | Seq[(String | os.Path | Opt)])*): OptGroup = - new OptGroup(opts.flatMap { + def apply(opts: (String | os.Path | Opt | Seq[(String | os.Path | Opt)])*): OptGroup = { + val opts0 = opts.flatMap { case s: String => Seq(Opt(s)) case p: os.Path => Seq(Opt(p)) case o: Opt => Seq(o) - case o: Seq[(String | os.Path | Opt)] => o.map { + case o: Seq[(String | os.Path | Opt)] => + o.map { case s: String => Opt(s) case p: os.Path => Opt(p) case o: Opt => o } - }) -// @targetName("applyIterable") + } + new OptGroup(opts0) + } + // @targetName("applyIterable") // def apply[T](opts: T*)(using f: T => Opt): OptGroup = new OptGroup(opts.map(f(_))) def when(cond: Boolean)(value: Opt*): OptGroup = if (cond) OptGroup(value*) else OptGroup() diff --git a/core/api/src/mill/api/opt/Opts.scala b/core/api/src/mill/api/opt/Opts.scala index 1e1407e405fa..a9c209434e72 100644 --- a/core/api/src/mill/api/opt/Opts.scala +++ b/core/api/src/mill/api/opt/Opts.scala @@ -7,6 +7,7 @@ import scala.language.implicitConversions case class Opts private (override val value: Seq[OptGroup]) extends OptsApi derives upickle.ReadWriter { + require(value.forall(!_.isEmpty)) def toStringSeq: Seq[String] = value.flatMap(_.toStringSeq) override def toString(): String = value.mkString("Opts(", ", ", ")") @@ -31,14 +32,16 @@ object Opts { // case s: Iterable[Opt] => s.map(OptGroup(_)) // }) - def apply(opts: (String | os.Path | Opt | Seq[(String | os.Path | Opt)] | OptGroup | Opts)*): Opts = - new Opts(opts.flatMap { + def apply(opts: (String | os.Path | Opt | IterableOnce[(String | os.Path | Opt)] | OptGroup | Opts)*): Opts = { + val groups = opts.flatMap { // Seq of OptGroup case s: String => Seq(OptGroup(s)) case p: os.Path => Seq(OptGroup(p)) case o: Opt => Seq(OptGroup(o)) - case o: Seq[(String | os.Path | Opt)] => o.map(OptGroup(_)) + case o: IterableOnce[(String | os.Path | Opt)] => Seq.from(o).map(OptGroup(_)) case o: OptGroup => Seq(o) case o: Opts => o.value - }) + } + new Opts(groups.filter(!_.isEmpty)) + } } diff --git a/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala b/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala index 4a5062c93c0f..69901ec5c325 100644 --- a/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala +++ b/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala @@ -2,6 +2,7 @@ package mill.scalanativelib import mill.* import mill.api.ExecResult +import mill.api.opt.Opts import mill.javalib.testrunner.TestResult import mill.scalanativelib.api.* import mill.testkit.UnitTester @@ -65,10 +66,10 @@ object TestingTests extends TestSuite { assert(testResult.value == expected) } test("test-scalacOptions") { - checkInheritedTasks(_.scalacOptions, Seq("-deprecation")) + checkInheritedTasks(_.scalacOptions, Opts("-deprecation")) } test("test-scalaOrganization") { - checkInheritedTasks(_.scalaOrganization, "org.example") + checkInheritedTasks(_.scalaOrganization, Opts("org.example")) } } From ce9c8a54e4bcaf9f52369d78db4fbe67aca08efa Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Thu, 6 Nov 2025 08:42:43 +0000 Subject: [PATCH 13/67] [autofix.ci] apply automated fixes --- core/api/src/mill/api/opt/Opts.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/api/src/mill/api/opt/Opts.scala b/core/api/src/mill/api/opt/Opts.scala index a9c209434e72..09d8f689ace8 100644 --- a/core/api/src/mill/api/opt/Opts.scala +++ b/core/api/src/mill/api/opt/Opts.scala @@ -32,7 +32,9 @@ object Opts { // case s: Iterable[Opt] => s.map(OptGroup(_)) // }) - def apply(opts: (String | os.Path | Opt | IterableOnce[(String | os.Path | Opt)] | OptGroup | Opts)*): Opts = { + def apply( + opts: (String | os.Path | Opt | IterableOnce[(String | os.Path | Opt)] | OptGroup | Opts)* + ): Opts = { val groups = opts.flatMap { // Seq of OptGroup case s: String => Seq(OptGroup(s)) From c0e15f6d90cf80cda5f5d0f381c8852e0bda71bb Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 10:24:59 +0100 Subject: [PATCH 14/67] Fix test --- .../test/src/mill/scalanativelib/TestingTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala b/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala index 69901ec5c325..23c9ac8efae0 100644 --- a/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala +++ b/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala @@ -69,7 +69,7 @@ object TestingTests extends TestSuite { checkInheritedTasks(_.scalacOptions, Opts("-deprecation")) } test("test-scalaOrganization") { - checkInheritedTasks(_.scalaOrganization, Opts("org.example")) + checkInheritedTasks(_.scalaOrganization, Seq("org.example")) } } From a72cdc0f47d9e63bc6c44ce897333f2c50544483 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 10:28:24 +0100 Subject: [PATCH 15/67] fix test --- libs/scalajslib/test/src/mill/scalajslib/UtestTests.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libs/scalajslib/test/src/mill/scalajslib/UtestTests.scala b/libs/scalajslib/test/src/mill/scalajslib/UtestTests.scala index 0eb0a9c2f201..a467f7aff15e 100644 --- a/libs/scalajslib/test/src/mill/scalajslib/UtestTests.scala +++ b/libs/scalajslib/test/src/mill/scalajslib/UtestTests.scala @@ -1,10 +1,11 @@ package mill.scalajslib -import mill._ +import mill.* import mill.api.ExecResult +import mill.api.opt.Opts import mill.javalib.testrunner.TestResult import mill.testkit.UnitTester -import utest._ +import utest.* object UtestTests extends TestSuite { import CompileLinkTests._ @@ -76,7 +77,7 @@ object UtestTests extends TestSuite { assert(testResult.value == expected) } test("test-scalacOptions") { - checkInheritedTasks(_.scalacOptions, Seq("-deprecation")) + checkInheritedTasks(_.scalacOptions, Opts("-deprecation")) } test("test-scalaOrganization") { checkInheritedTasks(_.scalaOrganization, "org.example") From 1159e4ac535f4021481a9d38ede5a53238874b48 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 14:29:37 +0100 Subject: [PATCH 16/67] Use a more compact JSON format --- core/api/src/mill/api/opt/Opt.scala | 41 ++++++++++++++----- core/api/src/mill/api/opt/OptGroup.scala | 12 +++++- core/api/src/mill/api/opt/Opts.scala | 9 +++- .../api/test/src/mill/api/opt/OptsTests.scala | 21 +++++++--- 4 files changed, 63 insertions(+), 20 deletions(-) diff --git a/core/api/src/mill/api/opt/Opt.scala b/core/api/src/mill/api/opt/Opt.scala index c3c284922ac2..ae1c4f886b4f 100644 --- a/core/api/src/mill/api/opt/Opt.scala +++ b/core/api/src/mill/api/opt/Opt.scala @@ -64,20 +64,39 @@ object Opt { def mkPlatformPath(paths: Seq[os.Path]): Opt = mkPath(paths, sep = java.io.File.pathSeparator) +// given jsonReadWriter: upickle.ReadWriter[Opt] = +// upickle.readwriter[Seq[(Option[String], Option[os.Path])]].bimap( +// _.value.map { +// case path: os.Path => (None, Some(path)) +// case str: String => (Some(str), None) +// }, +// seq => +// Opt(seq.map { +// case (Some(str), _) => str +// case (_, Some(path)) => path +// }*) +// ) + given jsonReadWriter: upickle.ReadWriter[Opt] = - upickle.readwriter[Seq[(Option[String], Option[os.Path])]].bimap( - _.value.map { - case path: os.Path => (None, Some(path)) - case str: String => (Some(str), None) - }, - seq => - Opt(seq.map { - case (Some(str), _) => str - case (_, Some(path)) => path - }*) + upickle.readwriter[ujson.Value].bimap( + opt => + if (!opt.containsPaths) ujson.Str(opt.toString()) + else opt.value.map { + case str: String => ujson.Str(str) + case path: os.Path => ujson.Obj("path" -> upickle.transform(path).to[ujson.Value]) + }, + { + case ujson.Str(opt) => Opt(opt) + case arr: ujson.Arr => + val elems = arr.value.map { + case ujson.Str(opt) => opt + case ujson.Obj(map) => upickle.read[os.Path](map("path")) + } + Opt(elems.toSeq*) + } ) -// given stringToOpt: Conversion[String, Opt] = (value: String) => Opt(value) + // given stringToOpt: Conversion[String, Opt] = (value: String) => Opt(value) // given osPathToOpt: Conversion[os.Path, Opt] = (value: os.Path) => Opt(value) // implicit def IterableToOpt[T](s: Iterable[T])(using f: T => Opt): Opt = diff --git a/core/api/src/mill/api/opt/OptGroup.scala b/core/api/src/mill/api/opt/OptGroup.scala index 5c1e578a8644..c624e5a7d7d2 100644 --- a/core/api/src/mill/api/opt/OptGroup.scala +++ b/core/api/src/mill/api/opt/OptGroup.scala @@ -8,12 +8,14 @@ import scala.language.implicitConversions /** * A set of options, which are used together */ -case class OptGroup private (value: Seq[Opt]) extends OptGroupApi - derives upickle.ReadWriter { +case class OptGroup private (value: Seq[Opt]) extends OptGroupApi { + override def toString(): String = value.mkString("(", ", ", ")") def isEmpty: Boolean = value.isEmpty + def size: Int = value.size + def containsPaths: Boolean = value.exists(_.containsPaths) def head: Opt = value.head @@ -64,4 +66,10 @@ object OptGroup { // implicit def ArrayToOptGroup[T](s: Array[T])(using f: T => OptGroup): OptGroup = // OptGroup(s.flatMap(f(_).value)) + given jsonReadWriter: upickle.ReadWriter[OptGroup] = + upickle.readwriter[Seq[Opt]].bimap( + _.value, + OptGroup(_*) + ) + } diff --git a/core/api/src/mill/api/opt/Opts.scala b/core/api/src/mill/api/opt/Opts.scala index 09d8f689ace8..e3d79e1d9399 100644 --- a/core/api/src/mill/api/opt/Opts.scala +++ b/core/api/src/mill/api/opt/Opts.scala @@ -5,8 +5,7 @@ import mill.api.daemon.internal.OptsApi import scala.annotation.targetName import scala.language.implicitConversions -case class Opts private (override val value: Seq[OptGroup]) extends OptsApi - derives upickle.ReadWriter { +case class Opts private (override val value: Seq[OptGroup]) extends OptsApi { require(value.forall(!_.isEmpty)) def toStringSeq: Seq[String] = value.flatMap(_.toStringSeq) @@ -46,4 +45,10 @@ object Opts { } new Opts(groups.filter(!_.isEmpty)) } + + given jsonReadWriter: upickle.ReadWriter[Opts] = + upickle.readwriter[Seq[OptGroup]].bimap( + _.value, + Opts(_*) + ) } diff --git a/core/api/test/src/mill/api/opt/OptsTests.scala b/core/api/test/src/mill/api/opt/OptsTests.scala index 57b438654215..bb811966b22a 100644 --- a/core/api/test/src/mill/api/opt/OptsTests.scala +++ b/core/api/test/src/mill/api/opt/OptsTests.scala @@ -92,6 +92,14 @@ class OptsTests extends TestSuite { assert(Opts("arg1").toStringSeq == Seq("arg1")) assert(opts1 == expectedOpts1) } + test("toString") { + val a = Opts(Opt("-arg", "1")).toString() + assertGoldenLiteral(a, "Opts((-arg1))") + val b = Opts(OptGroup("-arg", "1")).toString() + assertGoldenLiteral(b, "Opts((-arg, 1))") + + assert(a != b) + } test("toStringSeq") { val str = opts1.toStringSeq assert(str == expectedSeq1) @@ -99,14 +107,17 @@ class OptsTests extends TestSuite { test("jsonify") { test("without-mapping") { val json = upickle.write(opts1) + +// pprint.log(upickle.write(opts1, indent = 4)) +// pprint.log(opts1) +// pprint.log(opts1.toString) + assertGoldenLiteral( json, - "{\"value\":[{\"value\":[[[\"-deprecation\",null]]]},{\"value\":[[[\"-verbose\",null]]]},{\"value\":[[[\"--release\",null]],[[\"17\",null]]]},{\"value\":[[[\"-Xplugin=\",null],[null,\"/tmp/opts-test/.cache/plugin1\"]]]},{\"value\":[[[\"-Xplugin:\",null],[null,\"/tmp/opts-test/.cache/plugin1\"]]]},{\"value\":[[[null,\"/tmp/opts-test/work/src1\"]]]},{\"value\":[[[null,\"/tmp/opts-test/work/src2\"]]]},{\"value\":[[[null,\"/tmp/opts-test/work/src3\"]],[[null,\"/tmp/opts-test/work/src4\"]]]},{\"value\":[[[\"--extra\",null]],[[\"-Xplugin=\",null],[null,\"/tmp/opts-test/.cache/plugin1\"]],[[null,\"/tmp/opts-test/work/src1\"]],[[null,\"/tmp/opts-test/work/src2\"]]]}]}" + "[[\"-deprecation\"],[\"-verbose\"],[\"--release\",\"17\"],[[\"-Xplugin=\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}]],[[\"-Xplugin:\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}]],[[{\"path\":\"/tmp/opts-test/work/src1\"}]],[[{\"path\":\"/tmp/opts-test/work/src2\"}]],[[{\"path\":\"/tmp/opts-test/work/src3\"}],[{\"path\":\"/tmp/opts-test/work/src4\"}]],[\"--extra\",[\"-Xplugin=\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}],[{\"path\":\"/tmp/opts-test/work/src1\"}],[{\"path\":\"/tmp/opts-test/work/src2\"}]]]" ) -// pprint.log(upickle.write(opts1, indent = 4)) - pprint.log(opts1) - pprint.log(opts1.toString) - assert(json.split("\\Q$HOME\\E").size == 1) + + assert(json.split("\\Q$HOME\\E").size == 1 + 0) val back = upickle.read[Opts](json) assert(opts1 == back) } From dd67e4d833f9cae4be7a162fb35d4dc06d6c4259 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 15:34:51 +0100 Subject: [PATCH 17/67] adapt examples --- example/javalib/config/1-common-config/build.mill.yaml | 4 ++-- example/javalib/module/15-jni/build.mill | 6 ++++-- example/javalib/module/2-common-config/build.mill | 6 ++++-- example/javalib/module/3-custom-tasks/build.mill | 4 +++- .../module/5-compilation-execution-flags/build.mill | 8 +++++--- example/javalib/module/7-resources/build.mill | 4 +++- example/javalib/module/9-docjar/build.mill | 4 +++- example/javalib/web/4-hello-micronaut/build.mill | 10 +++++++--- example/javalib/web/5-todo-micronaut/build.mill | 10 +++++++--- .../kotlinlib/config/4-native-image/build.mill.yaml | 2 +- example/kotlinlib/linting/4-kover/build.mill | 5 +++-- .../module/10-dependency-injection/build.mill | 7 ++++--- example/kotlinlib/module/15-jni/build.mill | 6 ++++-- example/kotlinlib/module/2-common-config/build.mill | 6 ++++-- example/kotlinlib/module/3-custom-tasks/build.mill | 4 +++- .../module/5-compilation-execution-flags/build.mill | 6 ++++-- example/kotlinlib/module/7-resources/build.mill | 6 ++++-- .../module/8-kotlin-compiler-plugins/build.mill | 5 +++-- example/kotlinlib/testing/1-test-suite/build.mill | 6 ++++-- example/kotlinlib/web/8-hello-micronaut/build.mill | 7 ++++--- example/scalalib/module/2-common-config/build.mill | 8 +++++--- example/scalalib/module/3-custom-tasks/build.mill | 3 ++- .../module/5-compilation-execution-flags/build.mill | 8 +++++--- example/scalalib/module/7-resources/build.mill | 4 +++- .../module/8-scala-compiler-plugins/build.mill | 4 +++- example/scalalib/module/9-docjar/build.mill | 4 +++- example/scalalib/spark/1-hello-spark/build.mill | 4 +++- example/scalalib/spark/3-semi-realistic/build.mill | 4 +++- example/springboot/kotlin/1-web-initializr/build.mill | 3 ++- example/thirdparty/mockito/build.mill | 9 +++++---- 30 files changed, 110 insertions(+), 57 deletions(-) diff --git a/example/javalib/config/1-common-config/build.mill.yaml b/example/javalib/config/1-common-config/build.mill.yaml index 54e57b339ab3..ea09b3436f62 100644 --- a/example/javalib/config/1-common-config/build.mill.yaml +++ b/example/javalib/config/1-common-config/build.mill.yaml @@ -13,6 +13,6 @@ sources: ["./src", "./custom-src"] resources: ["./resources", "./custom-resources"] # Configure java compiler and runtime options and env vars -javacOptions: ["-deprecation"] -forkArgs: ["-Dmy.custom.property=my-prop-value"] +javacOptions: [["-deprecation"]] +forkArgs: [["-Dmy.custom.property=my-prop-value"]] forkEnv: { "MY_CUSTOM_ENV": "my-env-value" } \ No newline at end of file diff --git a/example/javalib/module/15-jni/build.mill b/example/javalib/module/15-jni/build.mill index 084412e0e44e..1c23a4c66b22 100644 --- a/example/javalib/module/15-jni/build.mill +++ b/example/javalib/module/15-jni/build.mill @@ -2,7 +2,9 @@ // code using JNI. package build + import mill.*, javalib.*, util.Jvm +import mill.api.opt.* object `package` extends JavaModule { // Additional source folder to put C sources @@ -46,10 +48,10 @@ object `package` extends JavaModule { PathRef(Task.dest / output) } - def forkEnv = Map("HELLO_WORLD_BINARY" -> nativeCompiled().path.toString) + def forkEnv = Map("HELLO_WORLD_BINARY" -> Opt(nativeCompiled().path)) object test extends JavaTests, TestModule.Junit4 { - def forkEnv = Map("HELLO_WORLD_BINARY" -> nativeCompiled().path.toString) + def forkEnv = Map("HELLO_WORLD_BINARY" -> Opt(nativeCompiled().path)) } } diff --git a/example/javalib/module/2-common-config/build.mill b/example/javalib/module/2-common-config/build.mill index 4ed007eb8ffc..a3d205840d2c 100644 --- a/example/javalib/module/2-common-config/build.mill +++ b/example/javalib/module/2-common-config/build.mill @@ -1,6 +1,8 @@ //// SNIPPET:BUILD package build + import mill.*, javalib.* +import mill.api.opt.* object `package` extends JavaModule { // You can have arbitrary numbers of third-party dependencies @@ -36,11 +38,11 @@ object `package` extends JavaModule { // Pass additional JVM flags when `.run` is called or in the executable // generated by `.assembly` - def forkArgs: T[Seq[String]] = Seq("-Dmy.custom.property=my-prop-value") + def forkArgs: T[Opts] = Opts("-Dmy.custom.property=my-prop-value") // Pass additional environmental variables when `.run` is called. Note that // this does not apply to running externally via `.assembly - def forkEnv: T[Map[String, String]] = Map("MY_CUSTOM_ENV" -> "my-env-value") + def forkEnv: T[Map[String, Opt]] = Map("MY_CUSTOM_ENV" -> opt"my-env-value") } // If you want to better understand how the various upstream tasks feed into // a task of interest, such as `run`, you can visualize their relationships via diff --git a/example/javalib/module/3-custom-tasks/build.mill b/example/javalib/module/3-custom-tasks/build.mill index b5de6fb781cb..29836b7d1afb 100644 --- a/example/javalib/module/3-custom-tasks/build.mill +++ b/example/javalib/module/3-custom-tasks/build.mill @@ -1,6 +1,8 @@ //// SNIPPET:BUILD package build + import mill.*, javalib.* +import mill.api.opt.* object `package` extends JavaModule { def mvnDeps = Seq(mvn"net.sourceforge.argparse4j:argparse4j:0.9.0") @@ -35,7 +37,7 @@ object `package` extends JavaModule { .sum } - def forkArgs: T[Seq[String]] = Seq(s"-Dmy.line.count=${lineCount()}") + def forkArgs: T[Opts] = Opts(s"-Dmy.line.count=${lineCount()}") def printLineCount() = Task.Command { println(lineCount()) } } diff --git a/example/javalib/module/5-compilation-execution-flags/build.mill b/example/javalib/module/5-compilation-execution-flags/build.mill index 45d0da9f4fab..6b1d459907cd 100644 --- a/example/javalib/module/5-compilation-execution-flags/build.mill +++ b/example/javalib/module/5-compilation-execution-flags/build.mill @@ -1,11 +1,13 @@ //// SNIPPET:BUILD package build + import mill.*, javalib.* +import mill.api.opt.* object `package` extends JavaModule { - def forkArgs = Seq("-Xmx4g", "-Dmy.jvm.property=hello") - def forkEnv = Map("MY_ENV_VAR" -> "WORLD") - def javacOptions = Seq("-deprecation") + def forkArgs = Opts("-Xmx4g", "-Dmy.jvm.property=hello") + def forkEnv = Map("MY_ENV_VAR" -> opt"WORLD") + def javacOptions = Opts("-deprecation") } // You can pass flags to the Java compiler via `javacOptions`. diff --git a/example/javalib/module/7-resources/build.mill b/example/javalib/module/7-resources/build.mill index 31588e6a4fde..170208b34da7 100644 --- a/example/javalib/module/7-resources/build.mill +++ b/example/javalib/module/7-resources/build.mill @@ -1,13 +1,15 @@ //// SNIPPET:BUILD package build + import mill.*, javalib.* +import mill.api.opt.* object foo extends JavaModule { object test extends JavaTests, TestModule.Junit4 { def otherFiles = Task.Source("other-files") def forkEnv = super.forkEnv() ++ Map( - "OTHER_FILES_DIR" -> otherFiles().path.toString + "OTHER_FILES_DIR" -> Opt(otherFiles().path) ) } } diff --git a/example/javalib/module/9-docjar/build.mill b/example/javalib/module/9-docjar/build.mill index 92c282337fb6..bc29555b2aa7 100644 --- a/example/javalib/module/9-docjar/build.mill +++ b/example/javalib/module/9-docjar/build.mill @@ -1,9 +1,11 @@ //// SNIPPET:BUILD package build + import mill.*, javalib.* +import mill.api.opt.* object foo extends JavaModule { - def javadocOptions = Seq("-quiet") + def javadocOptions = Opts("-quiet") } /** Usage diff --git a/example/javalib/web/4-hello-micronaut/build.mill b/example/javalib/web/4-hello-micronaut/build.mill index f8ca939fca1e..4992d227241c 100644 --- a/example/javalib/web/4-hello-micronaut/build.mill +++ b/example/javalib/web/4-hello-micronaut/build.mill @@ -1,5 +1,7 @@ package build + import mill.*, javalib.* +import mill.api.opt.* object `package` extends MicronautModule { def micronautVersion = "4.5.3" @@ -37,9 +39,11 @@ trait MicronautModule extends MavenModule { ) } - def javacOptions = Seq( - "-processorpath", - processors().map(_.path).mkString(":"), + def javacOptions = Opts( + OptGroup( + "-processorpath", + Opt.mkPath(processors().map(_.path), sep = ":") + ), "-parameters", "-Amicronaut.processing.incremental=true", "-Amicronaut.processing.group=example.micronaut", diff --git a/example/javalib/web/5-todo-micronaut/build.mill b/example/javalib/web/5-todo-micronaut/build.mill index fb4eb08019e0..ecf307a75b8f 100644 --- a/example/javalib/web/5-todo-micronaut/build.mill +++ b/example/javalib/web/5-todo-micronaut/build.mill @@ -1,5 +1,7 @@ package build + import mill.*, javalib.* +import mill.api.opt.* object `package` extends MicronautModule { def micronautVersion = "4.4.3" @@ -50,9 +52,11 @@ trait MicronautModule extends MavenModule { ) } - def javacOptions = Seq( - "-processorpath", - processors().map(_.path).mkString(":"), + def javacOptions = Opts( + OptGroup( + "-processorpath", + Opt.mkPath(processors().map(_.path), ":") + ), "-parameters", "-Amicronaut.processing.incremental=true", "-Amicronaut.processing.group=example.micronaut", diff --git a/example/kotlinlib/config/4-native-image/build.mill.yaml b/example/kotlinlib/config/4-native-image/build.mill.yaml index bf13ed3d14cc..d8c61d63f3de 100644 --- a/example/kotlinlib/config/4-native-image/build.mill.yaml +++ b/example/kotlinlib/config/4-native-image/build.mill.yaml @@ -1,4 +1,4 @@ extends: [mill.kotlinlib.KotlinModule, mill.kotlinlib.NativeImageModule] kotlinVersion: 2.0.20 jvmId: "graalvm-community:24" -nativeImageOptions: ["--no-fallback"] +nativeImageOptions: [["--no-fallback"]] diff --git a/example/kotlinlib/linting/4-kover/build.mill b/example/kotlinlib/linting/4-kover/build.mill index 37a393ff13cd..d6e7c4e6d31f 100644 --- a/example/kotlinlib/linting/4-kover/build.mill +++ b/example/kotlinlib/linting/4-kover/build.mill @@ -2,12 +2,13 @@ package build import mill.*, kotlinlib.* import kotlinlib.kover.KoverModule +import mill.api.opt.* object `package` extends KotlinModule, KoverModule { trait KotestTests extends TestModule.Junit5 { - override def forkArgs: T[Seq[String]] = Task { - super.forkArgs() ++ Seq("-Dkotest.framework.classpath.scanning.autoscan.disable=true") + override def forkArgs: T[Opts] = Task { + super.forkArgs() ++ Opts("-Dkotest.framework.classpath.scanning.autoscan.disable=true") } override def mvnDeps = super.mvnDeps() ++ Seq( diff --git a/example/kotlinlib/module/10-dependency-injection/build.mill b/example/kotlinlib/module/10-dependency-injection/build.mill index ed47d4eafa03..dc636171f9d1 100644 --- a/example/kotlinlib/module/10-dependency-injection/build.mill +++ b/example/kotlinlib/module/10-dependency-injection/build.mill @@ -1,8 +1,9 @@ //// SNIPPET:BUILD - package build + import mill.*, kotlinlib.* import kotlinlib.ksp.KspModule +import mill.api.opt.* object dagger extends KspModule { @@ -12,7 +13,7 @@ object dagger extends KspModule { def mainClass = Some("com.example.dagger.MainKt") - def kotlincOptions = super.kotlincOptions() ++ Seq("-no-reflect", "-verbose") + def kotlincOptions = super.kotlincOptions() ++ Opts("-no-reflect", "-verbose") // override def kotlincUseBtApi = false @@ -26,7 +27,7 @@ object dagger extends KspModule { object test extends KspTests, TestModule.Junit5 { - def kotlincOptions = super.kotlincOptions() ++ Seq("-no-reflect", "-verbose") + def kotlincOptions = super.kotlincOptions() ++ Opts("-no-reflect", "-verbose") def mvnDeps = super.mvnDeps() ++ Seq( mvn"com.google.dagger:dagger-compiler:2.57", diff --git a/example/kotlinlib/module/15-jni/build.mill b/example/kotlinlib/module/15-jni/build.mill index b09c8e0a83ed..c6b8489413a2 100644 --- a/example/kotlinlib/module/15-jni/build.mill +++ b/example/kotlinlib/module/15-jni/build.mill @@ -1,5 +1,7 @@ package build + import mill.*, kotlinlib.*, util.Jvm +import mill.api.opt.* object `package` extends KotlinModule { @@ -32,13 +34,13 @@ object `package` extends KotlinModule { PathRef(Task.dest / output) } - def forkEnv = Map("HELLO_WORLD_BINARY" -> nativeCompiled().path.toString) + def forkEnv = Map("HELLO_WORLD_BINARY" -> Opt(nativeCompiled().path)) object test extends KotlinTests, TestModule.Junit5 { def mvnDeps = super.mvnDeps() ++ Seq( mvn"io.kotest:kotest-runner-junit5:5.9.1" ) - def forkEnv = Map("HELLO_WORLD_BINARY" -> nativeCompiled().path.toString) + def forkEnv = Map("HELLO_WORLD_BINARY" -> Opt(nativeCompiled().path)) } } diff --git a/example/kotlinlib/module/2-common-config/build.mill b/example/kotlinlib/module/2-common-config/build.mill index 6f4bfb14f6e3..5c8b89bfbf66 100644 --- a/example/kotlinlib/module/2-common-config/build.mill +++ b/example/kotlinlib/module/2-common-config/build.mill @@ -1,6 +1,8 @@ //// SNIPPET:BUILD package build + import mill.*, kotlinlib.* +import mill.api.opt.* object `package` extends KotlinModule { // You can have arbitrary numbers of third-party dependencies @@ -39,11 +41,11 @@ object `package` extends KotlinModule { // Pass additional JVM flags when `.run` is called or in the executable // generated by `.assembly` - def forkArgs: T[Seq[String]] = Seq("-Dmy.custom.property=my-prop-value") + def forkArgs: T[Opts] = Opts("-Dmy.custom.property=my-prop-value") // Pass additional environmental variables when `.run` is called. Note that // this does not apply to running externally via `.assembly - def forkEnv: T[Map[String, String]] = Map("MY_CUSTOM_ENV" -> "my-env-value") + def forkEnv: T[Map[String, Opt]] = Map("MY_CUSTOM_ENV" -> opt"my-env-value") } // If you want to better understand how the various upstream tasks feed into // a task of interest, such as `run`, you can visualize their relationships via diff --git a/example/kotlinlib/module/3-custom-tasks/build.mill b/example/kotlinlib/module/3-custom-tasks/build.mill index 686fb66d034e..0765d33d6024 100644 --- a/example/kotlinlib/module/3-custom-tasks/build.mill +++ b/example/kotlinlib/module/3-custom-tasks/build.mill @@ -1,6 +1,8 @@ //// SNIPPET:BUILD package build + import mill.*, kotlinlib.* +import mill.api.opt.* object `package` extends KotlinModule { @@ -38,7 +40,7 @@ object `package` extends KotlinModule { .sum } - def forkArgs: T[Seq[String]] = Seq(s"-Dmy.line.count=${lineCount()}") + def forkArgs: T[Opts] = Opts(s"-Dmy.line.count=${lineCount()}") def printLineCount() = Task.Command { println(lineCount()) } } diff --git a/example/kotlinlib/module/5-compilation-execution-flags/build.mill b/example/kotlinlib/module/5-compilation-execution-flags/build.mill index 3745f3acda58..59a6341be8c3 100644 --- a/example/kotlinlib/module/5-compilation-execution-flags/build.mill +++ b/example/kotlinlib/module/5-compilation-execution-flags/build.mill @@ -1,13 +1,15 @@ //// SNIPPET:BUILD package build + import mill.*, kotlinlib.* +import mill.api.opt.* object `package` extends KotlinModule { def kotlinVersion = "1.9.24" - def forkArgs = Seq("-Xmx4g", "-Dmy.jvm.property=hello") - def forkEnv = Map("MY_ENV_VAR" -> "WORLD") + def forkArgs = Opts("-Xmx4g", "-Dmy.jvm.property=hello") + def forkEnv = Map("MY_ENV_VAR" -> opt"WORLD") def kotlincOptions = super.kotlincOptions() ++ Seq("-Werror") } diff --git a/example/kotlinlib/module/7-resources/build.mill b/example/kotlinlib/module/7-resources/build.mill index fc2fc355f2b7..cb2f7d5f5b55 100644 --- a/example/kotlinlib/module/7-resources/build.mill +++ b/example/kotlinlib/module/7-resources/build.mill @@ -1,6 +1,8 @@ //// SNIPPET:BUILD package build + import mill.*, kotlinlib.* +import mill.api.opt.* object foo extends KotlinModule { @@ -9,8 +11,8 @@ object foo extends KotlinModule { object test extends KotlinTests, TestModule.Junit5 { def otherFiles = Task.Source("other-files") - def forkEnv = super.forkEnv() ++ Map( - "OTHER_FILES_DIR" -> otherFiles().path.toString + def forkEnv = super.forkEnv() ++ Opt( + "OTHER_FILES_DIR" -> Opt(otherFiles().path) ) def mvnDeps = super.mvnDeps() ++ Seq( diff --git a/example/kotlinlib/module/8-kotlin-compiler-plugins/build.mill b/example/kotlinlib/module/8-kotlin-compiler-plugins/build.mill index 93f4e665006a..78b80db0b1dc 100644 --- a/example/kotlinlib/module/8-kotlin-compiler-plugins/build.mill +++ b/example/kotlinlib/module/8-kotlin-compiler-plugins/build.mill @@ -6,6 +6,7 @@ package build import mill.*, kotlinlib.* import java.io.File +import mill.api.opt.* object foo extends KotlinModule { @@ -23,8 +24,8 @@ object foo extends KotlinModule { ) } - def kotlincOptions = super.kotlincOptions() ++ Seq( - s"-Xplugin=${processors().head.path}" + def kotlincOptions = super.kotlincOptions() ++ Opts( + opt"-Xplugin=${processors().head.path}" ) object test extends KotlinTests, TestModule.Junit5 { diff --git a/example/kotlinlib/testing/1-test-suite/build.mill b/example/kotlinlib/testing/1-test-suite/build.mill index dc4d323ec68e..bbf664b3acc4 100644 --- a/example/kotlinlib/testing/1-test-suite/build.mill +++ b/example/kotlinlib/testing/1-test-suite/build.mill @@ -1,6 +1,8 @@ //// SNIPPET:BUILD1 package build + import mill.*, kotlinlib.* +import mill.api.opt.* object foo extends KotlinModule { @@ -15,7 +17,7 @@ object foo extends KotlinModule { ) // This is needed because of the "mockito-kotlin" - def kotlincOptions = super.kotlincOptions() ++ Seq("-jvm-target", "11") + def kotlincOptions = super.kotlincOptions() ++ Opts("-jvm-target", "11") } } @@ -40,7 +42,7 @@ object bar extends KotlinModule { ) // This is needed because of the "mockito-kotlin" - def kotlincOptions = super.kotlincOptions() ++ Seq("-jvm-target", "11") + def kotlincOptions = super.kotlincOptions() ++ Opts("-jvm-target", "11") } } diff --git a/example/kotlinlib/web/8-hello-micronaut/build.mill b/example/kotlinlib/web/8-hello-micronaut/build.mill index 89e859a29704..17156bd7446c 100644 --- a/example/kotlinlib/web/8-hello-micronaut/build.mill +++ b/example/kotlinlib/web/8-hello-micronaut/build.mill @@ -5,6 +5,7 @@ import coursier.{MavenRepository, Repository} import mill.* import kotlinlib.* import kotlinlib.ksp.KspModule +import mill.api.opt.* object micronaut extends MicronautModule { @@ -42,10 +43,10 @@ trait MicronautModule extends KspModule { outer => mvn"io.micronaut:micronaut-inject-kotlin:4.9.9" ) - override def kspProcessorOptions: T[Map[String, String]] = Task { + override def kspProcessorOptions: T[Map[String, Opt]] = Task { super.kspProcessorOptions() ++ Map( - "micronaut.processing.module" -> moduleSegments.render, - "micronaut.processing.incremental" -> "true" + "micronaut.processing.module" -> Opt(moduleSegments.render), + "micronaut.processing.incremental" -> opt"true" ) } diff --git a/example/scalalib/module/2-common-config/build.mill b/example/scalalib/module/2-common-config/build.mill index 6103b6ff4cea..f8c96618f494 100644 --- a/example/scalalib/module/2-common-config/build.mill +++ b/example/scalalib/module/2-common-config/build.mill @@ -7,7 +7,9 @@ //// SNIPPET:BUILD package build + import mill.*, scalalib.* +import mill.api.opt.* object `package` extends ScalaModule { def scalaVersion = "2.13.16" @@ -46,14 +48,14 @@ object `package` extends ScalaModule { // Pass additional JVM flags when `.run` is called or in the executable // generated by `.assembly` - def forkArgs: T[Seq[String]] = Seq("-Dmy.custom.property=my-prop-value") + def forkArgs: T[Opts] = Opts("-Dmy.custom.property=my-prop-value") // Pass additional environmental variables when `.run` is called. Note that // this does not apply to running externally via `.assembly - def forkEnv: T[Map[String, String]] = Map("MY_CUSTOM_ENV" -> "my-env-value") + def forkEnv: T[Map[String, Opt]] = Map("MY_CUSTOM_ENV" -> opt"my-env-value") // Additional Scala compiler options, e.g. to turn warnings into errors - def scalacOptions: T[Seq[String]] = Seq("-deprecation", "-Xfatal-warnings") + def scalacOptions: T[Opts] = Opts("-deprecation", "-Xfatal-warnings") } // If you want to better understand how the various upstream tasks feed into // a task of interest, such as `run`, you can visualize their relationships via diff --git a/example/scalalib/module/3-custom-tasks/build.mill b/example/scalalib/module/3-custom-tasks/build.mill index 79c177635e38..d3e4d5310133 100644 --- a/example/scalalib/module/3-custom-tasks/build.mill +++ b/example/scalalib/module/3-custom-tasks/build.mill @@ -11,6 +11,7 @@ //// SNIPPET:BUILD package build import mill.*, scalalib.* +import mill.api.opt.* object `package` extends ScalaModule { def scalaVersion = "3.7.1" @@ -46,7 +47,7 @@ object `package` extends ScalaModule { .sum } - def forkArgs: T[Seq[String]] = Seq(s"-Dmy.line.count=${lineCount()}") + def forkArgs: T[Opts] = Opts(s"-Dmy.line.count=${lineCount()}") def printLineCount() = Task.Command { println(lineCount()) } } diff --git a/example/scalalib/module/5-compilation-execution-flags/build.mill b/example/scalalib/module/5-compilation-execution-flags/build.mill index ca81ce863857..ec19296c6713 100644 --- a/example/scalalib/module/5-compilation-execution-flags/build.mill +++ b/example/scalalib/module/5-compilation-execution-flags/build.mill @@ -1,12 +1,14 @@ //// SNIPPET:BUILD package build + import mill.*, scalalib.* +import mill.api.opt.* object `package` extends ScalaModule { def scalaVersion = "3.7.1" - def scalacOptions = Seq("-Ydelambdafy:inline") - def forkArgs = Seq("-Xmx4g", "-Dmy.jvm.property=hello") - def forkEnv = Map("MY_ENV_VAR" -> "WORLD") + def scalacOptions = Opts("-Ydelambdafy:inline") + def forkArgs = Opts("-Xmx4g", "-Dmy.jvm.property=hello") + def forkEnv = Map("MY_ENV_VAR" -> opt"WORLD") } // You can pass flags to the Scala compiler via `scalacOptions`. diff --git a/example/scalalib/module/7-resources/build.mill b/example/scalalib/module/7-resources/build.mill index 9ca927227db7..6667df7e06ef 100644 --- a/example/scalalib/module/7-resources/build.mill +++ b/example/scalalib/module/7-resources/build.mill @@ -1,6 +1,8 @@ //// SNIPPET:BUILD package build + import mill.*, scalalib.* +import mill.api.opt.* object foo extends ScalaModule { def scalaVersion = "3.7.1" @@ -15,7 +17,7 @@ object foo extends ScalaModule { def otherFiles = Task.Source("other-files") def forkEnv = super.forkEnv() ++ Map( - "OTHER_FILES_DIR" -> otherFiles().path.toString + "OTHER_FILES_DIR" -> Opt(otherFiles().path) ) } } diff --git a/example/scalalib/module/8-scala-compiler-plugins/build.mill b/example/scalalib/module/8-scala-compiler-plugins/build.mill index 4c2eb952effa..d90dc8ecafa1 100644 --- a/example/scalalib/module/8-scala-compiler-plugins/build.mill +++ b/example/scalalib/module/8-scala-compiler-plugins/build.mill @@ -1,11 +1,13 @@ package build + import mill.*, scalalib.* +import mill.api.opt.* object `package` extends ScalaModule { def scalaVersion = "2.13.16" def compileMvnDeps = Seq(mvn"com.lihaoyi:::acyclic:0.3.18") - def scalacOptions = Seq("-P:acyclic:force") + def scalacOptions = Opts("-P:acyclic:force") def scalacPluginMvnDeps = Seq(mvn"com.lihaoyi:::acyclic:0.3.18") } diff --git a/example/scalalib/module/9-docjar/build.mill b/example/scalalib/module/9-docjar/build.mill index ac78d9447890..47a0911eec5d 100644 --- a/example/scalalib/module/9-docjar/build.mill +++ b/example/scalalib/module/9-docjar/build.mill @@ -3,12 +3,14 @@ //// SNIPPET:BUILD package build + import mill.*, scalalib.* +import mill.api.opt.* object foo extends ScalaModule { def scalaVersion = "3.3.6" - def scalaDocOptions = Seq("-siteroot", "mydocs", "-no-link-warnings") + def scalaDocOptions = Opts("-siteroot", "mydocs", "-no-link-warnings") } /** Usage diff --git a/example/scalalib/spark/1-hello-spark/build.mill b/example/scalalib/spark/1-hello-spark/build.mill index b4a625ce8de5..854fed482c3e 100644 --- a/example/scalalib/spark/1-hello-spark/build.mill +++ b/example/scalalib/spark/1-hello-spark/build.mill @@ -1,5 +1,7 @@ package build + import mill.*, scalalib.* +import mill.api.opt.* object foo extends ScalaModule { def scalaVersion = "2.12.20" @@ -14,7 +16,7 @@ object foo extends ScalaModule { def mvnDeps = Seq(mvn"com.lihaoyi::utest:0.9.1") def testFramework = "utest.runner.Framework" - def forkArgs = Seq("--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED") + def forkArgs = Opts("--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED") } } diff --git a/example/scalalib/spark/3-semi-realistic/build.mill b/example/scalalib/spark/3-semi-realistic/build.mill index 73668b29a008..a2cf1d6c54af 100644 --- a/example/scalalib/spark/3-semi-realistic/build.mill +++ b/example/scalalib/spark/3-semi-realistic/build.mill @@ -1,5 +1,7 @@ package build + import mill.*, scalalib.* +import mill.api.opt.* object `package` extends ScalaModule { def scalaVersion = "2.12.20" @@ -8,7 +10,7 @@ object `package` extends ScalaModule { mvn"org.apache.spark::spark-sql:3.5.6" ) - def forkArgs = Seq("--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED") + def forkArgs = Opts("--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED") def prependShellScript = "" diff --git a/example/springboot/kotlin/1-web-initializr/build.mill b/example/springboot/kotlin/1-web-initializr/build.mill index 62785513d86e..7063c49c6ba1 100644 --- a/example/springboot/kotlin/1-web-initializr/build.mill +++ b/example/springboot/kotlin/1-web-initializr/build.mill @@ -3,12 +3,13 @@ package build import mill.* import mill.javalib.* import mill.kotlinlib.KotlinMavenModule +import mill.api.opt.* object `package` extends KotlinMavenModule { def kotlinVersion = "1.9.25" - override def kotlincOptions: T[Seq[String]] = super.kotlincOptions() ++ Seq("-jvm-target", "17") + override def kotlincOptions: T[Opts] = super.kotlincOptions() ++ Opts("-jvm-target", "17") def bomMvnDeps = Seq( mvn"org.springframework.boot:spring-boot-dependencies:3.5.7" diff --git a/example/thirdparty/mockito/build.mill b/example/thirdparty/mockito/build.mill index 5b226f6019d4..90484c256c73 100644 --- a/example/thirdparty/mockito/build.mill +++ b/example/thirdparty/mockito/build.mill @@ -1,6 +1,7 @@ package build import mill.*, javalib.* import mill.api.ModuleRef +import mill.api.opt.* object libraries { @@ -44,7 +45,7 @@ trait MockitoModule extends MavenModule { def testMvnDeps: T[Seq[Dep]] = Seq() def testRuntimeMvnDeps: T[Seq[Dep]] = Seq() def testFramework = "com.novocode.junit.JUnitFramework" - def testForkArgs: T[Seq[String]] = Seq() + def testForkArgs: T[Opts] = Seq() def testFilteredSources: T[Seq[os.Path]] = Task { Seq() } @@ -118,7 +119,7 @@ object `package` extends MockitoModule { def mvnDeps = Seq(libraries.errorprone) def testMvnDeps = Seq(libraries.errorproneTestApi) - def forkArgs = Seq( + def forkArgs = Opts( // "-processorpath", libraries.autoservice, "-Xbootclasspath/a:${configurations.errorproneJavac.asPath}", "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", @@ -132,7 +133,7 @@ object `package` extends MockitoModule { "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED" ) - def javacOptions = Seq( + def javacOptions = Opts( "--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" @@ -214,7 +215,7 @@ object `package` extends MockitoModule { object `memory-test` extends MockitoModule { def testModuleDeps = Seq(build) def testMvnDeps = Seq(libraries.assertj) - def testForkArgs = Seq("-Xmx128m") + def testForkArgs = Opts("-Xmx128m") } // object `osgi-test` extends MockitoModule { From c9e11a4484121ff8f3f2d7bd58a624064d9686b4 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 15:35:04 +0100 Subject: [PATCH 18/67] Adapt BuildWriter --- .../src/mill/main/buildgen/BuildWriter.scala | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala index 3ee93e876059..7d71eeab4fa5 100644 --- a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala +++ b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala @@ -236,7 +236,7 @@ class BuildWriter(build: BuildSpec, renderCrossValueInTask: String = "crossValue renderModuleDep ), renderMemberAsSeq("runModuleDeps", runModuleDeps, cross(_.runModuleDeps), renderModuleDep), - renderTaskAsSeq("javacOptions", javacOptions, cross(_.javacOptions), literalize(_)), + renderTaskAsOpts("javacOptions", javacOptions, cross(_.javacOptions), literalize(_)), renderTask("artifactName", artifactName, cross(_.artifactName), literalize(_)) ) } @@ -287,7 +287,7 @@ class BuildWriter(build: BuildSpec, renderCrossValueInTask: String = "crossValue cross(_.errorProneOptions), literalize(_) ), - renderTaskAsSeq( + renderTaskAsOpts( "errorProneJavacEnableOptions", errorProneJavacEnableOptions, cross(_.errorProneJavacEnableOptions), @@ -302,7 +302,7 @@ class BuildWriter(build: BuildSpec, renderCrossValueInTask: String = "crossValue import config.* renderBlocks( renderTask("scalaVersion", scalaVersion, cross(_.scalaVersion), literalize(_)), - renderTaskAsSeq("scalacOptions", scalacOptions, cross(_.scalacOptions), literalize(_)), + renderTaskAsOpts("scalacOptions", scalacOptions, cross(_.scalacOptions), literalize(_)), renderTaskAsSeq( "scalacPluginMvnDeps", scalacPluginMvnDeps, @@ -604,4 +604,34 @@ class BuildWriter(build: BuildSpec, renderCrossValueInTask: String = "crossValue } } } + + private def renderTaskAsOpts[A]( + name: String, + value: Seq[A], + crossValues: Seq[(String, Seq[A])], + renderValue: A => String + ) = { + val crossValues0 = crossValues.filter(_._2.nonEmpty) + if (value.isEmpty && crossValues0.isEmpty) "" + else { + def renderSeq(value: Seq[A]) = value.map(renderValue).mkString("Opts(", ", ", ")") + + s"def $name = super.$name()" + { + if (value.isEmpty) "" else " ++ " + renderSeq(value) + } + { + if (crossValues0.isEmpty) "" + else { + val crossCases = crossValues0.groupMap(_._2)(_._1).toSeq.sortBy(_._2).map { + (value, crosses) => + val matchValues = crosses.sorted.map(literalize(_)).mkString(" | ") + s"case $matchValues => ${renderSeq(value)}" + } + s""" ++ ($renderCrossValueInTask match { + | ${renderLines(crossCases)} + | case _ => Nil + |})""".stripMargin + } + } + } + } } From bc0595362c02a2e5e7193621e5095fe480582c16 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 17:32:54 +0100 Subject: [PATCH 19/67] Update expected --- .../test/resources/expected/gradle-6-0/build.mill | 2 +- .../mill-build/src/ProjectBaseModule.scala | 2 +- .../resources/expected/gradle-8-0/list/package.mill | 4 ++-- .../mill-build/src/ProjectBaseModule.scala | 2 +- .../expected/gradle-8-0/utilities/package.mill | 2 +- .../mill-build/src/ProjectBaseModule.scala | 2 +- .../expected/with-args/gradle-8-0/build.mill | 12 ++++++------ .../expected/maven-samples/multi-module/package.mill | 2 +- .../maven-samples/multi-module/server/package.mill | 2 +- .../maven-samples/multi-module/webapp/package.mill | 2 +- .../maven-samples/single-module/package.mill | 2 +- .../test/resources/expected/quickstart/build.mill | 7 ++++--- .../expected/with-args/maven-samples/build.mill | 8 ++++---- .../expected/with-args/quickstart/build.mill | 7 ++++--- .../test/resources/expected/cross-version/build.mill | 2 +- .../sbt-multi-project-example/common/package.mill | 2 +- .../src/SbtMultiProjectExampleBaseModule.scala | 2 +- .../sbt-multi-project-example/multi1/package.mill | 2 +- .../nested/nested/package.mill | 2 +- 19 files changed, 34 insertions(+), 32 deletions(-) diff --git a/libs/init/gradle/test/resources/expected/gradle-6-0/build.mill b/libs/init/gradle/test/resources/expected/gradle-6-0/build.mill index b696d391b9d5..a968b085285e 100644 --- a/libs/init/gradle/test/resources/expected/gradle-6-0/build.mill +++ b/libs/init/gradle/test/resources/expected/gradle-6-0/build.mill @@ -9,7 +9,7 @@ object `package` extends MavenModule { def mvnDeps = super.mvnDeps() ++ Seq(Deps.guava) def javacOptions = super.javacOptions() ++ - Seq("-source", "11", "-target", "11") + Opts("-source", "11", "-target", "11") def jvmId = "zulu:11" diff --git a/libs/init/gradle/test/resources/expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala b/libs/init/gradle/test/resources/expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala index 83a2088d2eea..fbd4d4ae2d11 100644 --- a/libs/init/gradle/test/resources/expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala +++ b/libs/init/gradle/test/resources/expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala @@ -5,7 +5,7 @@ import mill.javalib.* trait ProjectBaseModule extends MavenModule { def javacOptions = super.javacOptions() ++ - Seq("-source", "11", "-target", "11") + Opts("-source", "11", "-target", "11") def jvmId = "zulu:11" diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/list/package.mill b/libs/init/gradle/test/resources/expected/gradle-8-0/list/package.mill index 7f447fc382a6..438c8c414452 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/list/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/list/package.mill @@ -9,7 +9,7 @@ object `package` extends ErrorProneModule with ProjectBaseModule { def errorProneVersion = "2.28.0" def errorProneJavacEnableOptions = super.errorProneJavacEnableOptions() ++ - Seq("-XDshould-stop.ifError=FLOW", "-XDshouldStopPolicyIfError=FLOW") + Opts("-XDshould-stop.ifError=FLOW", "-XDshouldStopPolicyIfError=FLOW") object test extends MavenTests with ErrorProneModule with TestModule.Junit5 { @@ -21,7 +21,7 @@ object `package` extends ErrorProneModule with ProjectBaseModule { Seq("-XepCompilingTestOnlyCode") def errorProneJavacEnableOptions = super.errorProneJavacEnableOptions() ++ - Seq("-XDshould-stop.ifError=FLOW", "-XDshouldStopPolicyIfError=FLOW") + Opts("-XDshould-stop.ifError=FLOW", "-XDshouldStopPolicyIfError=FLOW") def testParallelism = false diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala b/libs/init/gradle/test/resources/expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala index 83a2088d2eea..fbd4d4ae2d11 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala @@ -5,7 +5,7 @@ import mill.javalib.* trait ProjectBaseModule extends MavenModule { def javacOptions = super.javacOptions() ++ - Seq("-source", "11", "-target", "11") + Opts("-source", "11", "-target", "11") def jvmId = "zulu:11" diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/utilities/package.mill b/libs/init/gradle/test/resources/expected/gradle-8-0/utilities/package.mill index f2e7c18dada1..a6390faa5df1 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/utilities/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/utilities/package.mill @@ -11,6 +11,6 @@ object `package` extends ErrorProneModule with ProjectBaseModule { def errorProneVersion = "2.28.0" def errorProneJavacEnableOptions = super.errorProneJavacEnableOptions() ++ - Seq("-XDshould-stop.ifError=FLOW", "-XDshouldStopPolicyIfError=FLOW") + Opts("-XDshould-stop.ifError=FLOW", "-XDshouldStopPolicyIfError=FLOW") } diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectBaseModule.scala b/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectBaseModule.scala index 220ca6eb4a0c..a7048f70dc4c 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectBaseModule.scala +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectBaseModule.scala @@ -5,7 +5,7 @@ import mill.javalib.* trait ProjectBaseModule extends MavenModule { def javacOptions = super.javacOptions() ++ - Seq("-source", "21", "-target", "21") + Opts("-source", "21", "-target", "21") def jvmId = "zulu:21" diff --git a/libs/init/gradle/test/resources/expected/with-args/gradle-8-0/build.mill b/libs/init/gradle/test/resources/expected/with-args/gradle-8-0/build.mill index dd6d1bad9ca3..f6add7c26b2e 100644 --- a/libs/init/gradle/test/resources/expected/with-args/gradle-8-0/build.mill +++ b/libs/init/gradle/test/resources/expected/with-args/gradle-8-0/build.mill @@ -15,7 +15,7 @@ object `package` extends Module { def moduleDeps = super.moduleDeps ++ Seq(build.utilities) def javacOptions = super.javacOptions() ++ - Seq("-source", "17", "-target", "17") + Opts("-source", "17", "-target", "17") def jvmId = "zulu:17" @@ -35,12 +35,12 @@ object `package` extends Module { object list extends MavenModule with ErrorProneModule { def javacOptions = super.javacOptions() ++ - Seq("-source", "17", "-target", "17") + Opts("-source", "17", "-target", "17") def errorProneVersion = "2.28.0" def errorProneJavacEnableOptions = super.errorProneJavacEnableOptions() ++ - Seq("-XDshould-stop.ifError=FLOW", "-XDshouldStopPolicyIfError=FLOW") + Opts("-XDshould-stop.ifError=FLOW", "-XDshouldStopPolicyIfError=FLOW") def jvmId = "zulu:17" @@ -56,7 +56,7 @@ object `package` extends Module { Seq("-XepCompilingTestOnlyCode") def errorProneJavacEnableOptions = super.errorProneJavacEnableOptions() ++ - Seq("-XDshould-stop.ifError=FLOW", "-XDshouldStopPolicyIfError=FLOW") + Opts("-XDshould-stop.ifError=FLOW", "-XDshouldStopPolicyIfError=FLOW") def testParallelism = false @@ -71,12 +71,12 @@ object `package` extends Module { def moduleDeps = super.moduleDeps ++ Seq(build.list) def javacOptions = super.javacOptions() ++ - Seq("-source", "17", "-target", "17") + Opts("-source", "17", "-target", "17") def errorProneVersion = "2.28.0" def errorProneJavacEnableOptions = super.errorProneJavacEnableOptions() ++ - Seq("-XDshould-stop.ifError=FLOW", "-XDshouldStopPolicyIfError=FLOW") + Opts("-XDshould-stop.ifError=FLOW", "-XDshouldStopPolicyIfError=FLOW") def jvmId = "zulu:17" diff --git a/libs/init/maven/test/resources/expected/maven-samples/multi-module/package.mill b/libs/init/maven/test/resources/expected/maven-samples/multi-module/package.mill index fa2cb300e2e8..4f8e0ba07dcc 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/multi-module/package.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/multi-module/package.mill @@ -7,7 +7,7 @@ import millbuild.* object `package` extends MavenSamplesBaseModule { def javacOptions = super.javacOptions() ++ - Seq("-source", "1.6", "-target", "1.6") + Opts("-source", "1.6", "-target", "1.6") def artifactName = "multi-module-parent" diff --git a/libs/init/maven/test/resources/expected/maven-samples/multi-module/server/package.mill b/libs/init/maven/test/resources/expected/maven-samples/multi-module/server/package.mill index 74071cee72f3..ad9f6bf86255 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/multi-module/server/package.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/multi-module/server/package.mill @@ -7,7 +7,7 @@ import millbuild.* object `package` extends MavenSamplesBaseModule { def javacOptions = super.javacOptions() ++ - Seq("-source", "1.6", "-target", "1.6") + Opts("-source", "1.6", "-target", "1.6") def artifactName = "server" diff --git a/libs/init/maven/test/resources/expected/maven-samples/multi-module/webapp/package.mill b/libs/init/maven/test/resources/expected/maven-samples/multi-module/webapp/package.mill index 04d63535f5bf..4468b1517c96 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/multi-module/webapp/package.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/multi-module/webapp/package.mill @@ -12,7 +12,7 @@ object `package` extends MavenSamplesBaseModule { def moduleDeps = super.moduleDeps ++ Seq(build.`multi-module`.server) def javacOptions = super.javacOptions() ++ - Seq("-source", "1.6", "-target", "1.6") + Opts("-source", "1.6", "-target", "1.6") def artifactName = "webapp" diff --git a/libs/init/maven/test/resources/expected/maven-samples/single-module/package.mill b/libs/init/maven/test/resources/expected/maven-samples/single-module/package.mill index 42deca2fc205..cd9615ecf95f 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/single-module/package.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/single-module/package.mill @@ -9,7 +9,7 @@ object `package` extends MavenSamplesBaseModule { def mvnDeps = super.mvnDeps() ++ Seq(Deps.servletApi, Deps.jspApi) def javacOptions = super.javacOptions() ++ - Seq("-source", "1.6", "-target", "1.6") + Opts("-source", "1.6", "-target", "1.6") def artifactName = "single-module-project" diff --git a/libs/init/maven/test/resources/expected/quickstart/build.mill b/libs/init/maven/test/resources/expected/quickstart/build.mill index 73ca114dcf8a..8376bf2db5e5 100644 --- a/libs/init/maven/test/resources/expected/quickstart/build.mill +++ b/libs/init/maven/test/resources/expected/quickstart/build.mill @@ -8,12 +8,13 @@ import millbuild.* object `package` extends MavenModule with ErrorProneModule with PublishModule { - def javacOptions = super.javacOptions() ++ Seq("-source", "8", "-target", "8") + def javacOptions = super.javacOptions() ++ + Opts("-source", "8", "-target", "8") def artifactName = "maven-3-9-11" def errorProneJavacEnableOptions = super.errorProneJavacEnableOptions() ++ - Seq("-XDshould-stop=ifError=FLOW") + Opts("-XDshould-stop=ifError=FLOW") def jvmId = "zulu:11" @@ -34,7 +35,7 @@ object `package` extends MavenModule with ErrorProneModule with PublishModule { Seq(Deps.junitJupiterApi, Deps.junitJupiterParams) def errorProneJavacEnableOptions = super.errorProneJavacEnableOptions() ++ - Seq("-XDshould-stop=ifError=FLOW") + Opts("-XDshould-stop=ifError=FLOW") def forkWorkingDir = moduleDir diff --git a/libs/init/maven/test/resources/expected/with-args/maven-samples/build.mill b/libs/init/maven/test/resources/expected/with-args/maven-samples/build.mill index 77032e4ae11d..4c93e79ec69c 100644 --- a/libs/init/maven/test/resources/expected/with-args/maven-samples/build.mill +++ b/libs/init/maven/test/resources/expected/with-args/maven-samples/build.mill @@ -24,7 +24,7 @@ object `package` extends MavenModule with PublishModule { object `multi-module` extends MavenModule with PublishModule { def javacOptions = super.javacOptions() ++ - Seq("-source", "1.6", "-target", "1.6") + Opts("-source", "1.6", "-target", "1.6") def artifactName = "multi-module-parent" @@ -56,7 +56,7 @@ object `package` extends MavenModule with PublishModule { object server extends MavenModule with PublishModule { def javacOptions = super.javacOptions() ++ - Seq("-source", "1.6", "-target", "1.6") + Opts("-source", "1.6", "-target", "1.6") def artifactName = "server" @@ -108,7 +108,7 @@ object `package` extends MavenModule with PublishModule { def moduleDeps = super.moduleDeps ++ Seq(build.`multi-module`.server) def javacOptions = super.javacOptions() ++ - Seq("-source", "1.6", "-target", "1.6") + Opts("-source", "1.6", "-target", "1.6") def artifactName = "webapp" @@ -145,7 +145,7 @@ object `package` extends MavenModule with PublishModule { ) def javacOptions = super.javacOptions() ++ - Seq("-source", "1.6", "-target", "1.6") + Opts("-source", "1.6", "-target", "1.6") def artifactName = "single-module-project" diff --git a/libs/init/maven/test/resources/expected/with-args/quickstart/build.mill b/libs/init/maven/test/resources/expected/with-args/quickstart/build.mill index 458044a36b60..8d4c0769a37b 100644 --- a/libs/init/maven/test/resources/expected/with-args/quickstart/build.mill +++ b/libs/init/maven/test/resources/expected/with-args/quickstart/build.mill @@ -7,12 +7,13 @@ import mill.javalib.publish.* object `package` extends MavenModule with ErrorProneModule with PublishModule { - def javacOptions = super.javacOptions() ++ Seq("-source", "8", "-target", "8") + def javacOptions = super.javacOptions() ++ + Opts("-source", "8", "-target", "8") def artifactName = "maven-3-9-11" def errorProneJavacEnableOptions = super.errorProneJavacEnableOptions() ++ - Seq("-XDshould-stop=ifError=FLOW") + Opts("-XDshould-stop=ifError=FLOW") def jvmId = "zulu:11" @@ -40,7 +41,7 @@ object `package` extends MavenModule with ErrorProneModule with PublishModule { ) def errorProneJavacEnableOptions = super.errorProneJavacEnableOptions() ++ - Seq("-XDshould-stop=ifError=FLOW") + Opts("-XDshould-stop=ifError=FLOW") def forkWorkingDir = moduleDir diff --git a/libs/init/sbt/test/resources/expected/cross-version/build.mill b/libs/init/sbt/test/resources/expected/cross-version/build.mill index 241a215be4db..c075a3671cf5 100644 --- a/libs/init/sbt/test/resources/expected/cross-version/build.mill +++ b/libs/init/sbt/test/resources/expected/cross-version/build.mill @@ -12,7 +12,7 @@ object `package` extends Cross[CrossVersionModule]("2.12.18", "2.13.12", "3.3.1") trait CrossVersionModule extends PublishModule with CrossSbtModule { - def javacOptions = super.javacOptions() ++ Seq("--release", "8") + def javacOptions = super.javacOptions() ++ Opts("--release", "8") def artifactName = "my-cross-project" diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill index d83ddd075969..5006c9f3afd9 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill @@ -18,7 +18,7 @@ object `package` extends SbtMultiProjectExampleBaseModule { def artifactName = "common" - def scalacOptions = super.scalacOptions() ++ Seq("-encoding", "utf8") + def scalacOptions = super.scalacOptions() ++ Opts("-encoding", "utf8") def pomSettings = PomSettings( "This is the common module.", diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/mill-build/src/SbtMultiProjectExampleBaseModule.scala b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/mill-build/src/SbtMultiProjectExampleBaseModule.scala index af1b7f85c54d..9506ab29dc27 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/mill-build/src/SbtMultiProjectExampleBaseModule.scala +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/mill-build/src/SbtMultiProjectExampleBaseModule.scala @@ -8,7 +8,7 @@ trait SbtMultiProjectExampleBaseModule extends PublishModule with SbtModule { def scalaVersion = "2.12.3" - def scalacOptions = super.scalacOptions() ++ Seq( + def scalacOptions = super.scalacOptions() ++ Opts( "-unchecked", "-feature", "-language:existentials", diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi1/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi1/package.mill index 87e7ced59315..5d791d852b3b 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi1/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi1/package.mill @@ -22,7 +22,7 @@ object `package` extends SbtMultiProjectExampleBaseModule { def artifactName = "multi1" - def scalacOptions = super.scalacOptions() ++ Seq("-encoding", "utf8", "-V") + def scalacOptions = super.scalacOptions() ++ Opts("-encoding", "utf8", "-V") def pomSettings = PomSettings( "This is an sbt sample project for testing Mill's init command.", diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/nested/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/nested/package.mill index 4d12b13f7f96..46377a0fb8e7 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/nested/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/nested/package.mill @@ -11,7 +11,7 @@ object `package` extends SbtMultiProjectExampleBaseModule { def artifactName = "nested" - def scalacOptions = super.scalacOptions() ++ Seq("-encoding", "utf8") + def scalacOptions = super.scalacOptions() ++ Opts("-encoding", "utf8") def pomSettings = PomSettings( "This is an sbt sample project for testing Mill's init command.", From e37054a3c3a0cb2e30499df85e49407900e645ce Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 17:49:01 +0100 Subject: [PATCH 20/67] Avoid mutating parameters --- .../src/mill/main/buildgen/BuildWriter.scala | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala index 7d71eeab4fa5..70740671a45e 100644 --- a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala +++ b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala @@ -101,7 +101,7 @@ class BuildWriter(build: BuildSpec, renderCrossValueInTask: String = "crossValue private def renderBaseModuleImports(baseModule: ModuleSpec) = { val wildcards = mutable.SortedSet.empty[String] import baseModule.* - configs.foreach(addImports(wildcards, _)) + wildcards ++= configs.flatMap(imports) renderLines(wildcards.map(s => s"import $s.*")) } @@ -111,22 +111,22 @@ class BuildWriter(build: BuildSpec, renderCrossValueInTask: String = "crossValue import spec.* if (supertypes.isEmpty || crossConfigs.nonEmpty) wildcards += "mill" if (configs.nonEmpty) wildcards ++= build.metaBuild.map(_.rootModuleName) - configs.foreach(addImports(wildcards, _)) + wildcards ++= configs.flatMap(imports) } renderLines(wildcards.map(s => s"import $s.*")) } - private def addImports(wildcards: mutable.SortedSet[String], config: ModuleConfig) = + private def imports(config: ModuleConfig): Set[String] = { config match { - case _: PublishModule => wildcards += "mill.javalib" += "mill.javalib.publish" - case _: ErrorProneModule => wildcards += "mill.javalib" += "mill.javalib.errorprone" - case _: ScalaModule => wildcards += "mill.scalalib" - case _: ScalaJSModule => - wildcards += "mill.scalalib" += "mill.scalajslib" += "mill.scalajslib.api" - case _: ScalaNativeModule => wildcards += "mill.scalalib" += "mill.scalanativelib" - case _: SbtPlatformModule => wildcards += "mill.scalalib" - case _ => wildcards += "mill.javalib" + case _: PublishModule => Set("mill.javalib", "mill.javalib.publish") + case _: ErrorProneModule => Set("mill.javalib", "mill.javalib.errorprone") + case _: ScalaModule => Set("mill.scalalib") + case _: ScalaJSModule => Set("mill.scalalib", "mill.scalajslib", "mill.scalajslib.api") + case _: ScalaNativeModule => Set("mill.scalalib", "mill.scalanativelib") + case _: SbtPlatformModule => Set("mill.scalalib") + case _ => Set("mill.javalib") } + } private def renderModule(module: ModuleSpec, isPackageRoot: Boolean = false): String = { import module.* From 34a4320e76cb79184b2a72ce95b1ffe8df4a0c6f Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 17:49:21 +0100 Subject: [PATCH 21/67] Add imports --- libs/init/buildgen/api/src/mill/main/buildgen/ModuleConfig.scala | 1 + libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala | 1 + 2 files changed, 2 insertions(+) diff --git a/libs/init/buildgen/api/src/mill/main/buildgen/ModuleConfig.scala b/libs/init/buildgen/api/src/mill/main/buildgen/ModuleConfig.scala index 00f87d016834..bc4abcf77e9c 100644 --- a/libs/init/buildgen/api/src/mill/main/buildgen/ModuleConfig.scala +++ b/libs/init/buildgen/api/src/mill/main/buildgen/ModuleConfig.scala @@ -10,6 +10,7 @@ import upickle.default.{ReadWriter, macroRW} * to configure tasks/members like `mvnDeps`/`moduleDeps`. */ sealed trait ModuleConfig + object ModuleConfig { case class Artifact(group: String, id: String, version: String) object Artifact { diff --git a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala index 70740671a45e..d55d81148f83 100644 --- a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala +++ b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala @@ -101,6 +101,7 @@ class BuildWriter(build: BuildSpec, renderCrossValueInTask: String = "crossValue private def renderBaseModuleImports(baseModule: ModuleSpec) = { val wildcards = mutable.SortedSet.empty[String] import baseModule.* + wildcards += "mill.api" += "mill.api.opts" wildcards ++= configs.flatMap(imports) renderLines(wildcards.map(s => s"import $s.*")) } From 39838caf05fa3f2341f5bd9a65f0f4bd8b142dfb Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 18:01:33 +0100 Subject: [PATCH 22/67] Add imports --- .../expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala | 2 ++ .../expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala | 2 ++ .../gradle-9-0-0/mill-build/src/ProjectBaseModule.scala | 2 ++ .../gradle-9-0-0/mill-build/src/ProjectPublishModule.scala | 2 ++ .../maven-samples/mill-build/src/MavenSamplesBaseModule.scala | 2 ++ .../mill-build/src/SbtMultiProjectExampleBaseModule.scala | 2 ++ 6 files changed, 12 insertions(+) diff --git a/libs/init/gradle/test/resources/expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala b/libs/init/gradle/test/resources/expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala index fbd4d4ae2d11..cf5cf15e8f6c 100644 --- a/libs/init/gradle/test/resources/expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala +++ b/libs/init/gradle/test/resources/expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala @@ -1,5 +1,7 @@ package millbuild +import mill.api.* +import mill.api.opts.* import mill.javalib.* trait ProjectBaseModule extends MavenModule { diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala b/libs/init/gradle/test/resources/expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala index fbd4d4ae2d11..cf5cf15e8f6c 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala @@ -1,5 +1,7 @@ package millbuild +import mill.api.* +import mill.api.opts.* import mill.javalib.* trait ProjectBaseModule extends MavenModule { diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectBaseModule.scala b/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectBaseModule.scala index a7048f70dc4c..61164d62d78b 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectBaseModule.scala +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectBaseModule.scala @@ -1,5 +1,7 @@ package millbuild +import mill.api.* +import mill.api.opts.* import mill.javalib.* trait ProjectBaseModule extends MavenModule { diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectPublishModule.scala b/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectPublishModule.scala index 4dda0873edb0..7bfc0715ca4a 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectPublishModule.scala +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectPublishModule.scala @@ -1,5 +1,7 @@ package millbuild +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* diff --git a/libs/init/maven/test/resources/expected/maven-samples/mill-build/src/MavenSamplesBaseModule.scala b/libs/init/maven/test/resources/expected/maven-samples/mill-build/src/MavenSamplesBaseModule.scala index 48f9326cb9e0..e4cf622b96ab 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/mill-build/src/MavenSamplesBaseModule.scala +++ b/libs/init/maven/test/resources/expected/maven-samples/mill-build/src/MavenSamplesBaseModule.scala @@ -1,5 +1,7 @@ package millbuild +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/mill-build/src/SbtMultiProjectExampleBaseModule.scala b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/mill-build/src/SbtMultiProjectExampleBaseModule.scala index 9506ab29dc27..a37140cd775b 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/mill-build/src/SbtMultiProjectExampleBaseModule.scala +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/mill-build/src/SbtMultiProjectExampleBaseModule.scala @@ -1,5 +1,7 @@ package millbuild +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* From e05881f00e3ac1ded3ea7ecc20a5b286af7834d7 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 6 Nov 2025 18:17:53 +0100 Subject: [PATCH 23/67] Add imports --- libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala | 1 + libs/init/gradle/test/resources/expected/gradle-6-0/build.mill | 2 ++ .../gradle/test/resources/expected/gradle-7-0/app/package.mill | 2 ++ libs/init/gradle/test/resources/expected/gradle-7-0/build.mill | 2 ++ .../gradle/test/resources/expected/gradle-7-0/list/package.mill | 2 ++ .../test/resources/expected/gradle-7-0/utilities/package.mill | 2 ++ .../gradle/test/resources/expected/gradle-8-0/app/package.mill | 2 ++ libs/init/gradle/test/resources/expected/gradle-8-0/build.mill | 2 ++ .../gradle/test/resources/expected/gradle-8-0/list/package.mill | 2 ++ .../test/resources/expected/gradle-8-0/utilities/package.mill | 2 ++ .../test/resources/expected/gradle-9-0-0/app/package.mill | 2 ++ .../init/gradle/test/resources/expected/gradle-9-0-0/build.mill | 2 ++ .../test/resources/expected/gradle-9-0-0/list/package.mill | 2 ++ .../test/resources/expected/gradle-9-0-0/utilities/package.mill | 2 ++ .../test/resources/expected/with-args/gradle-8-0/build.mill | 2 ++ .../init/maven/test/resources/expected/maven-samples/build.mill | 2 ++ .../resources/expected/maven-samples/multi-module/package.mill | 2 ++ .../expected/maven-samples/multi-module/server/package.mill | 2 ++ .../expected/maven-samples/multi-module/webapp/package.mill | 2 ++ .../resources/expected/maven-samples/single-module/package.mill | 2 ++ libs/init/maven/test/resources/expected/quickstart/build.mill | 2 ++ libs/init/maven/test/resources/expected/spring-start/build.mill | 2 ++ .../test/resources/expected/with-args/maven-samples/build.mill | 2 ++ .../test/resources/expected/with-args/quickstart/build.mill | 2 ++ libs/init/sbt/test/resources/expected/cross-version/build.mill | 2 ++ .../resources/expected/sbt-multi-project-example/build.mill | 2 ++ .../expected/sbt-multi-project-example/common/package.mill | 2 ++ .../expected/sbt-multi-project-example/multi1/package.mill | 2 ++ .../expected/sbt-multi-project-example/multi2/package.mill | 2 ++ .../sbt-multi-project-example/nested/nested/package.mill | 2 ++ .../expected/sbt-multi-project-example/nested/package.mill | 2 ++ .../sbt/test/resources/expected/scala-seed-project/build.mill | 2 ++ 32 files changed, 63 insertions(+) diff --git a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala index d55d81148f83..35120b18ad9a 100644 --- a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala +++ b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala @@ -108,6 +108,7 @@ class BuildWriter(build: BuildSpec, renderCrossValueInTask: String = "crossValue private def renderModuleImports(module: ModuleSpec) = { val wildcards = mutable.SortedSet.empty[String] + wildcards += "mill.api" += "mill.api.opts" for spec <- module.sequence do { import spec.* if (supertypes.isEmpty || crossConfigs.nonEmpty) wildcards += "mill" diff --git a/libs/init/gradle/test/resources/expected/gradle-6-0/build.mill b/libs/init/gradle/test/resources/expected/gradle-6-0/build.mill index a968b085285e..8316a7b8af8c 100644 --- a/libs/init/gradle/test/resources/expected/gradle-6-0/build.mill +++ b/libs/init/gradle/test/resources/expected/gradle-6-0/build.mill @@ -1,6 +1,8 @@ //| mill-version: SNAPSHOT package build +import mill.api.* +import mill.api.opts.* import mill.javalib.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-7-0/app/package.mill b/libs/init/gradle/test/resources/expected/gradle-7-0/app/package.mill index b854d0883228..4c98e7e89b8f 100644 --- a/libs/init/gradle/test/resources/expected/gradle-7-0/app/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-7-0/app/package.mill @@ -1,5 +1,7 @@ package build.app +import mill.api.* +import mill.api.opts.* import mill.javalib.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-7-0/build.mill b/libs/init/gradle/test/resources/expected/gradle-7-0/build.mill index 8958ea4ccb06..7dbc474fa239 100644 --- a/libs/init/gradle/test/resources/expected/gradle-7-0/build.mill +++ b/libs/init/gradle/test/resources/expected/gradle-7-0/build.mill @@ -2,5 +2,7 @@ package build import mill.* +import mill.api.* +import mill.api.opts.* object `package` extends Module {} diff --git a/libs/init/gradle/test/resources/expected/gradle-7-0/list/package.mill b/libs/init/gradle/test/resources/expected/gradle-7-0/list/package.mill index 911aa4e895bb..8f4d7e36d5b1 100644 --- a/libs/init/gradle/test/resources/expected/gradle-7-0/list/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-7-0/list/package.mill @@ -1,5 +1,7 @@ package build.list +import mill.api.* +import mill.api.opts.* import mill.javalib.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-7-0/utilities/package.mill b/libs/init/gradle/test/resources/expected/gradle-7-0/utilities/package.mill index ed2fbd197899..649cd0be4c57 100644 --- a/libs/init/gradle/test/resources/expected/gradle-7-0/utilities/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-7-0/utilities/package.mill @@ -1,5 +1,7 @@ package build.utilities +import mill.api.* +import mill.api.opts.* import mill.javalib.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/app/package.mill b/libs/init/gradle/test/resources/expected/gradle-8-0/app/package.mill index 7617c99dfe83..7a3c062e24b5 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/app/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/app/package.mill @@ -1,5 +1,7 @@ package build.app +import mill.api.* +import mill.api.opts.* import mill.javalib.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/build.mill b/libs/init/gradle/test/resources/expected/gradle-8-0/build.mill index 8958ea4ccb06..7dbc474fa239 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/build.mill +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/build.mill @@ -2,5 +2,7 @@ package build import mill.* +import mill.api.* +import mill.api.opts.* object `package` extends Module {} diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/list/package.mill b/libs/init/gradle/test/resources/expected/gradle-8-0/list/package.mill index 438c8c414452..b2ebb0a17310 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/list/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/list/package.mill @@ -1,5 +1,7 @@ package build.list +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.errorprone.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/utilities/package.mill b/libs/init/gradle/test/resources/expected/gradle-8-0/utilities/package.mill index a6390faa5df1..444b7517dfbd 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/utilities/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/utilities/package.mill @@ -1,5 +1,7 @@ package build.utilities +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.errorprone.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/app/package.mill b/libs/init/gradle/test/resources/expected/gradle-9-0-0/app/package.mill index dc8cc4b94a1f..7d79151c9bdc 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/app/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/app/package.mill @@ -1,5 +1,7 @@ package build.app +import mill.api.* +import mill.api.opts.* import mill.javalib.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/build.mill b/libs/init/gradle/test/resources/expected/gradle-9-0-0/build.mill index 890787f10447..13a2db102d16 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/build.mill +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/build.mill @@ -3,5 +3,7 @@ package build import mill.* +import mill.api.* +import mill.api.opts.* object `package` extends Module {} diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/list/package.mill b/libs/init/gradle/test/resources/expected/gradle-9-0-0/list/package.mill index 38af5a7dea86..f255608b29e8 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/list/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/list/package.mill @@ -1,5 +1,7 @@ package build.list +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/utilities/package.mill b/libs/init/gradle/test/resources/expected/gradle-9-0-0/utilities/package.mill index f05b04a567f9..058c8926a0f9 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/utilities/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/utilities/package.mill @@ -1,5 +1,7 @@ package build.utilities +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/with-args/gradle-8-0/build.mill b/libs/init/gradle/test/resources/expected/with-args/gradle-8-0/build.mill index f6add7c26b2e..4ffd8d096d8a 100644 --- a/libs/init/gradle/test/resources/expected/with-args/gradle-8-0/build.mill +++ b/libs/init/gradle/test/resources/expected/with-args/gradle-8-0/build.mill @@ -2,6 +2,8 @@ package build import mill.* +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.errorprone.* diff --git a/libs/init/maven/test/resources/expected/maven-samples/build.mill b/libs/init/maven/test/resources/expected/maven-samples/build.mill index c3eebeadbc6e..a937819422ac 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/build.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/build.mill @@ -1,6 +1,8 @@ //| mill-version: SNAPSHOT package build +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/maven/test/resources/expected/maven-samples/multi-module/package.mill b/libs/init/maven/test/resources/expected/maven-samples/multi-module/package.mill index 4f8e0ba07dcc..41eb89d68f24 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/multi-module/package.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/multi-module/package.mill @@ -1,5 +1,7 @@ package build.`multi-module` +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/maven/test/resources/expected/maven-samples/multi-module/server/package.mill b/libs/init/maven/test/resources/expected/maven-samples/multi-module/server/package.mill index ad9f6bf86255..957a2a20f442 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/multi-module/server/package.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/multi-module/server/package.mill @@ -1,5 +1,7 @@ package build.`multi-module`.server +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/maven/test/resources/expected/maven-samples/multi-module/webapp/package.mill b/libs/init/maven/test/resources/expected/maven-samples/multi-module/webapp/package.mill index 4468b1517c96..38151735a17d 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/multi-module/webapp/package.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/multi-module/webapp/package.mill @@ -1,5 +1,7 @@ package build.`multi-module`.webapp +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/maven/test/resources/expected/maven-samples/single-module/package.mill b/libs/init/maven/test/resources/expected/maven-samples/single-module/package.mill index cd9615ecf95f..ab5ddd26937d 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/single-module/package.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/single-module/package.mill @@ -1,5 +1,7 @@ package build.`single-module` +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/maven/test/resources/expected/quickstart/build.mill b/libs/init/maven/test/resources/expected/quickstart/build.mill index 8376bf2db5e5..62ce7136f3a9 100644 --- a/libs/init/maven/test/resources/expected/quickstart/build.mill +++ b/libs/init/maven/test/resources/expected/quickstart/build.mill @@ -1,6 +1,8 @@ //| mill-version: SNAPSHOT package build +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.errorprone.* import mill.javalib.publish.* diff --git a/libs/init/maven/test/resources/expected/spring-start/build.mill b/libs/init/maven/test/resources/expected/spring-start/build.mill index 097f12c07bea..421b11487658 100644 --- a/libs/init/maven/test/resources/expected/spring-start/build.mill +++ b/libs/init/maven/test/resources/expected/spring-start/build.mill @@ -1,6 +1,8 @@ //| mill-version: SNAPSHOT package build +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/maven/test/resources/expected/with-args/maven-samples/build.mill b/libs/init/maven/test/resources/expected/with-args/maven-samples/build.mill index 4c93e79ec69c..a25a11501ea7 100644 --- a/libs/init/maven/test/resources/expected/with-args/maven-samples/build.mill +++ b/libs/init/maven/test/resources/expected/with-args/maven-samples/build.mill @@ -1,6 +1,8 @@ //| mill-version: SNAPSHOT package build +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* diff --git a/libs/init/maven/test/resources/expected/with-args/quickstart/build.mill b/libs/init/maven/test/resources/expected/with-args/quickstart/build.mill index 8d4c0769a37b..cc05bdfae586 100644 --- a/libs/init/maven/test/resources/expected/with-args/quickstart/build.mill +++ b/libs/init/maven/test/resources/expected/with-args/quickstart/build.mill @@ -1,6 +1,8 @@ //| mill-version: SNAPSHOT package build +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.errorprone.* import mill.javalib.publish.* diff --git a/libs/init/sbt/test/resources/expected/cross-version/build.mill b/libs/init/sbt/test/resources/expected/cross-version/build.mill index c075a3671cf5..32dd2a646f82 100644 --- a/libs/init/sbt/test/resources/expected/cross-version/build.mill +++ b/libs/init/sbt/test/resources/expected/cross-version/build.mill @@ -3,6 +3,8 @@ package build import mill.* +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/build.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/build.mill index 8958ea4ccb06..7dbc474fa239 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/build.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/build.mill @@ -2,5 +2,7 @@ package build import mill.* +import mill.api.* +import mill.api.opts.* object `package` extends Module {} diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill index 5006c9f3afd9..70b067d0d497 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill @@ -1,5 +1,7 @@ package build.common +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi1/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi1/package.mill index 5d791d852b3b..9ff351267bcf 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi1/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi1/package.mill @@ -1,5 +1,7 @@ package build.multi1 +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi2/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi2/package.mill index d6b4fba2276e..646a226255b9 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi2/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi2/package.mill @@ -1,5 +1,7 @@ package build.multi2 +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/nested/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/nested/package.mill index 46377a0fb8e7..c7380175478a 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/nested/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/nested/package.mill @@ -1,5 +1,7 @@ package build.nested.nested +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/package.mill index 2ba917ae0300..3aa5969e613d 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/package.mill @@ -1,5 +1,7 @@ package build.nested import mill.* +import mill.api.* +import mill.api.opts.* object `package` extends Module {} diff --git a/libs/init/sbt/test/resources/expected/scala-seed-project/build.mill b/libs/init/sbt/test/resources/expected/scala-seed-project/build.mill index d2c8210c1848..5fcef3a10116 100644 --- a/libs/init/sbt/test/resources/expected/scala-seed-project/build.mill +++ b/libs/init/sbt/test/resources/expected/scala-seed-project/build.mill @@ -1,6 +1,8 @@ //| mill-version: SNAPSHOT package build +import mill.api.* +import mill.api.opts.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* From 37846fd5f121fb7bbe8036d1e256245a9fac4424 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Fri, 7 Nov 2025 14:14:40 +0100 Subject: [PATCH 24/67] Fix test --- .../test/src/mill/scalanativelib/TestingTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala b/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala index 23c9ac8efae0..01e113604d0a 100644 --- a/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala +++ b/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala @@ -69,7 +69,7 @@ object TestingTests extends TestSuite { checkInheritedTasks(_.scalacOptions, Opts("-deprecation")) } test("test-scalaOrganization") { - checkInheritedTasks(_.scalaOrganization, Seq("org.example")) + checkInheritedTasks(_.scalaOrganization, "org.example") } } From c8cc3bee7aefe1448a95cbfd797a3bf0e71e4dda Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Fri, 7 Nov 2025 14:37:13 +0100 Subject: [PATCH 25/67] More Seq -> Opts fixes --- .../javalib/module/8-annotation-processors/build.mill | 6 ++++-- example/javalib/publishing/7-native-image/build.mill | 4 +++- .../javalib/publishing/8-native-image-libs/build.mill | 4 +++- .../module/5-compilation-execution-flags/build.mill | 2 +- .../kotlinlib/publishing/8-native-image-libs/build.mill | 4 +++- example/scalalib/linting/3-acyclic/build.mill | 5 ++++- example/scalalib/native/4-common-config/build.mill | 4 +++- example/scalalib/publishing/7-native-image/build.mill | 4 +++- .../scalalib/publishing/8-native-image-libs/build.mill | 4 +++- example/thirdparty/jimfs/build.mill | 4 +++- example/thirdparty/mockito/build.mill | 3 ++- example/thirdparty/netty/build.mill | 3 ++- .../feature/codesig-javamodule/resources/build.mill | 4 +++- integration/ide/bsp-server/resources/project/build.mill | 7 ++++--- integration/ide/gen-idea/resources/hello-idea/build.mill | 5 +++-- .../zinc-incremental-compilation/resources/build.mill | 3 ++- libs/javalib/src/mill/javalib/NativeImageModule.scala | 5 +++-- .../src/mill/javalib/checkstyle/CheckstyleModule.scala | 9 +++++---- libs/javalib/src/mill/javalib/pmd/PmdModule.scala | 9 ++++----- 19 files changed, 58 insertions(+), 31 deletions(-) diff --git a/example/javalib/module/8-annotation-processors/build.mill b/example/javalib/module/8-annotation-processors/build.mill index ccb1a6d4b478..b85518c4bffe 100644 --- a/example/javalib/module/8-annotation-processors/build.mill +++ b/example/javalib/module/8-annotation-processors/build.mill @@ -1,6 +1,8 @@ package build + import mill.*, javalib.* import java.io.File +import mill.api.opt.* object foo extends JavaModule { def compileMvnDeps = Seq(mvn"org.projectlombok:lombok:1.18.34") @@ -40,9 +42,9 @@ object bar extends JavaModule { defaultResolver().classpath(Seq(mvn"org.projectlombok:lombok:1.18.34")) } - def javacOptions = Seq( + def javacOptions = Opts( "-processorpath", - processors().map(_.path).mkString(File.pathSeparator) + Opt.mkPath(processors().map(_.path), sep = File.pathSeparator) ) object test extends JavaTests, TestModule.Junit4 diff --git a/example/javalib/publishing/7-native-image/build.mill b/example/javalib/publishing/7-native-image/build.mill index 592d42bece56..45d8ab8c42ec 100644 --- a/example/javalib/publishing/7-native-image/build.mill +++ b/example/javalib/publishing/7-native-image/build.mill @@ -1,12 +1,14 @@ //// SNIPPET:BUILD package build + import mill.*, javalib.* +import mill.api.opt.* import mill.api.ModuleRef object foo extends JavaModule, NativeImageModule { def jvmId = "graalvm-community:17.0.7" - def nativeImageOptions = Seq("--no-fallback") + def nativeImageOptions = Opts("--no-fallback") } //// SNIPPET:END diff --git a/example/javalib/publishing/8-native-image-libs/build.mill b/example/javalib/publishing/8-native-image-libs/build.mill index b0f0e96470cf..1463ae033c8c 100644 --- a/example/javalib/publishing/8-native-image-libs/build.mill +++ b/example/javalib/publishing/8-native-image-libs/build.mill @@ -1,6 +1,8 @@ //// SNIPPET:BUILD package build + import mill.*, javalib.* +import mill.api.opt.* import mill.api.ModuleRef object foo extends JavaModule, NativeImageModule { @@ -10,7 +12,7 @@ object foo extends JavaModule, NativeImageModule { mvn"org.slf4j:slf4j-nop:2.0.7" ) - def nativeImageOptions = Seq( + def nativeImageOptions = Opts( "--no-fallback", "-H:IncludeResourceBundles=net.sourceforge.argparse4j.internal.ArgumentParserImpl", "-Os" diff --git a/example/kotlinlib/module/5-compilation-execution-flags/build.mill b/example/kotlinlib/module/5-compilation-execution-flags/build.mill index 59a6341be8c3..c1b268d34c2d 100644 --- a/example/kotlinlib/module/5-compilation-execution-flags/build.mill +++ b/example/kotlinlib/module/5-compilation-execution-flags/build.mill @@ -11,7 +11,7 @@ object `package` extends KotlinModule { def forkArgs = Opts("-Xmx4g", "-Dmy.jvm.property=hello") def forkEnv = Map("MY_ENV_VAR" -> opt"WORLD") - def kotlincOptions = super.kotlincOptions() ++ Seq("-Werror") + def kotlincOptions = super.kotlincOptions() ++ Opt("-Werror") } // You can pass flags to the Kotlin compiler via `kotlincOptions`. diff --git a/example/kotlinlib/publishing/8-native-image-libs/build.mill b/example/kotlinlib/publishing/8-native-image-libs/build.mill index 81469e6e0175..3ef491f5d7a2 100644 --- a/example/kotlinlib/publishing/8-native-image-libs/build.mill +++ b/example/kotlinlib/publishing/8-native-image-libs/build.mill @@ -1,12 +1,14 @@ //// SNIPPET:BUILD package build + import mill.*, kotlinlib.* +import mill.api.opt.* import mill.api.ModuleRef object foo extends KotlinModule, NativeImageModule { def kotlinVersion = "1.9.24" - def nativeImageOptions = Seq( + def nativeImageOptions = Opts( "--no-fallback", "-Os", "--initialize-at-build-time=com.github.ajalt.mordant.internal.nativeimage.NativeImagePosixMppImpls" diff --git a/example/scalalib/linting/3-acyclic/build.mill b/example/scalalib/linting/3-acyclic/build.mill index 2b25b5a36fc3..0496a4a68cab 100644 --- a/example/scalalib/linting/3-acyclic/build.mill +++ b/example/scalalib/linting/3-acyclic/build.mill @@ -15,13 +15,16 @@ // shown below: package build + import mill.*, scalalib.* +import mill.api.opt.* + object `package` extends ScalaModule { def scalaVersion = "2.13.16" def compileMvnDeps = Seq(mvn"com.lihaoyi:::acyclic:0.3.18") def scalacPluginMvnDeps = Seq(mvn"com.lihaoyi:::acyclic:0.3.18") - def scalacOptions = Seq("-P:acyclic:force") + def scalacOptions = Opts("-P:acyclic:force") } /** See Also: src/Foo.scala */ diff --git a/example/scalalib/native/4-common-config/build.mill b/example/scalalib/native/4-common-config/build.mill index 69dd6a3742d9..f34782f4e1cd 100644 --- a/example/scalalib/native/4-common-config/build.mill +++ b/example/scalalib/native/4-common-config/build.mill @@ -1,5 +1,7 @@ package build + import mill.*, scalalib.*, scalanativelib.*, scalanativelib.api.* +import mill.api.opt.* object `package` extends ScalaNativeModule { def scalaVersion = "3.3.6" @@ -18,7 +20,7 @@ object `package` extends ScalaNativeModule { def nativeIncrementalCompilation: T[Boolean] = true // Set nativeLinkingOptions path to a directory named `target`. - def nativeLinkingOptions = Seq("-L" + moduleDir.toString + "/target") + def nativeLinkingOptions = Opts(opt"-L${moduleDir}/target") // Set nativeWorkdir directory to `newDir` def nativeWorkdir = Task.dest / "newDir" diff --git a/example/scalalib/publishing/7-native-image/build.mill b/example/scalalib/publishing/7-native-image/build.mill index c6fdbae6d875..33c8c2609c68 100644 --- a/example/scalalib/publishing/7-native-image/build.mill +++ b/example/scalalib/publishing/7-native-image/build.mill @@ -1,6 +1,8 @@ //// SNIPPET:BUILD package build + import mill.*, scalalib.* +import mill.api.opt.* import mill.api.ModuleRef object foo extends ScalaModule, NativeImageModule { @@ -8,7 +10,7 @@ object foo extends ScalaModule, NativeImageModule { def jvmId = "graalvm-community:17.0.7" - def nativeImageOptions = Seq("--no-fallback") + def nativeImageOptions = Opts("--no-fallback") } //// SNIPPET:END diff --git a/example/scalalib/publishing/8-native-image-libs/build.mill b/example/scalalib/publishing/8-native-image-libs/build.mill index a41da94a385c..9e718ce87009 100644 --- a/example/scalalib/publishing/8-native-image-libs/build.mill +++ b/example/scalalib/publishing/8-native-image-libs/build.mill @@ -1,6 +1,8 @@ //// SNIPPET:BUILD package build + import mill.*, scalalib.* +import mill.api.opt.* import mill.api.ModuleRef object foo extends ScalaModule, NativeImageModule { @@ -8,7 +10,7 @@ object foo extends ScalaModule, NativeImageModule { def nativeImageOptions = Seq("--no-fallback", "-Os") - def mvnDeps = Seq( + def mvnDeps = Opts( mvn"com.lihaoyi::scalatags:0.13.1", mvn"com.lihaoyi::mainargs:0.7.7" ) diff --git a/example/thirdparty/jimfs/build.mill b/example/thirdparty/jimfs/build.mill index 54d57487e3f2..6d60bac1a1e1 100644 --- a/example/thirdparty/jimfs/build.mill +++ b/example/thirdparty/jimfs/build.mill @@ -1,5 +1,7 @@ package build + import mill.*, javalib.*, publish.* +import mill.api.opt.* def sharedCompileMvnDeps = Task { Seq( @@ -26,7 +28,7 @@ object jimfs extends PublishModule, MavenModule { mvn"com.google.guava:guava:31.1-android" ) - def javacOptions = Seq("-processor", "com.google.auto.service.processor.AutoServiceProcessor") + def javacOptions = Opts("-processor", "com.google.auto.service.processor.AutoServiceProcessor") object test extends MavenTests, TestModule.Junit4 { def junit4Version = "4.13.2" diff --git a/example/thirdparty/mockito/build.mill b/example/thirdparty/mockito/build.mill index 90484c256c73..bbf8c2adb8b5 100644 --- a/example/thirdparty/mockito/build.mill +++ b/example/thirdparty/mockito/build.mill @@ -1,4 +1,5 @@ package build + import mill.*, javalib.* import mill.api.ModuleRef import mill.api.opt.* @@ -40,7 +41,7 @@ object libraries { trait MockitoModule extends MavenModule { def jvmId = "temurin:11.0.24" - def javacOptions = Seq("-encoding", "UTF-8") + def javacOptions = Opts("-encoding", "UTF-8") def testModuleDeps: Seq[JavaModule] = Nil def testMvnDeps: T[Seq[Dep]] = Seq() def testRuntimeMvnDeps: T[Seq[Dep]] = Seq() diff --git a/example/thirdparty/netty/build.mill b/example/thirdparty/netty/build.mill index 98a0d25ee981..a3502af2fd5f 100644 --- a/example/thirdparty/netty/build.mill +++ b/example/thirdparty/netty/build.mill @@ -6,6 +6,7 @@ package build import mill.*, javalib.* import mill.api.BuildCtx +import mill.api.opt.* // TODO: // testsuite-shading @@ -15,7 +16,7 @@ import mill.api.BuildCtx def isOSX = System.getProperty("os.name").toLowerCase.contains("mac") trait NettyBaseModule extends MavenModule { - def javacOptions = Seq("-source", "1.8", "-target", "1.8") + def javacOptions = Opts("-source", "1.8", "-target", "1.8") } trait NettyBaseTestSuiteModule extends NettyBaseModule, TestModule.Junit5 { def testSandboxWorkingDir = false diff --git a/integration/feature/codesig-javamodule/resources/build.mill b/integration/feature/codesig-javamodule/resources/build.mill index b6250b170825..c62bfa48b186 100644 --- a/integration/feature/codesig-javamodule/resources/build.mill +++ b/integration/feature/codesig-javamodule/resources/build.mill @@ -1,8 +1,10 @@ package build + import mill._, javalib._ +import mill.api.opt.* object foo extends JavaModule { - def javacOptions = Seq("-source", "11", "-target", "11") + def javacOptions = Opts("-source", "11", "-target", "11") def sources = Task { println("Foo generating sources...") os.write( diff --git a/integration/ide/bsp-server/resources/project/build.mill b/integration/ide/bsp-server/resources/project/build.mill index 2bdf4141df51..a553ca82d0bd 100644 --- a/integration/ide/bsp-server/resources/project/build.mill +++ b/integration/ide/bsp-server/resources/project/build.mill @@ -1,6 +1,7 @@ package build -import mill._ +import mill.* +import mill.api.opt.* // testing a simple Java module object `hello-java` extends scalalib.JavaModule { @@ -94,7 +95,7 @@ object delayed extends scalalib.ScalaModule { object diag extends scalalib.ScalaModule { def scalaVersion = Option(System.getenv("TEST_SCALA_2_13_VERSION")).getOrElse(???) - def scalacOptions = Seq("-deprecation") + def scalacOptions = Opts("-deprecation") @deprecated("deprecated", "0.0.1") def thing = 2 @@ -103,7 +104,7 @@ object diag extends scalalib.ScalaModule { object many extends scalalib.ScalaModule { def scalaVersion = Option(System.getenv("TEST_SCALA_2_13_VERSION")).getOrElse(???) - def scalacOptions = Seq("-deprecation") + def scalacOptions = Opts("-deprecation") } } diff --git a/integration/ide/gen-idea/resources/hello-idea/build.mill b/integration/ide/gen-idea/resources/hello-idea/build.mill index 3446c1b129b4..eecb34362979 100644 --- a/integration/ide/gen-idea/resources/hello-idea/build.mill +++ b/integration/ide/gen-idea/resources/hello-idea/build.mill @@ -1,8 +1,9 @@ package build -import mill._ +import mill.* import mill.scalajslib.ScalaJSModule import mill.scalalib.{Dep, DepSyntax, JavaModule, ScalaModule, TestModule} +import mill.api.opt.* trait HelloIdeaModule extends scalalib.ScalaModule { def scalaVersion = "2.12.5" @@ -63,5 +64,5 @@ object moduleF extends JavaModule { object moduleG extends Cross[ModuleG]("2.12.5", "2.13.6") trait ModuleG extends ScalaModule with Cross.Module[String] { def scalaVersion = crossValue - def scalacOptions = Seq("-Xsource:3") + def scalacOptions = Opts("-Xsource:3") } diff --git a/integration/invalidation/zinc-incremental-compilation/resources/build.mill b/integration/invalidation/zinc-incremental-compilation/resources/build.mill index 740140ec52c2..265dd514d363 100644 --- a/integration/invalidation/zinc-incremental-compilation/resources/build.mill +++ b/integration/invalidation/zinc-incremental-compilation/resources/build.mill @@ -2,12 +2,13 @@ package build // Issue https://github.com/com-lihaoyi/mill/issues/1901 import mill._ import mill.scalalib._ +import mill.api.opt.* object app extends SbtModule { def scalaVersion = "2.13.16" - def scalacOptions = Seq("-Vclasspath") + def scalacOptions = Opts("-Vclasspath") def mvnDeps = Seq( mvn"io.getquill::quill-sql:3.18.0" diff --git a/libs/javalib/src/mill/javalib/NativeImageModule.scala b/libs/javalib/src/mill/javalib/NativeImageModule.scala index 8877aa16f4d2..499d687a2e8b 100644 --- a/libs/javalib/src/mill/javalib/NativeImageModule.scala +++ b/libs/javalib/src/mill/javalib/NativeImageModule.scala @@ -2,6 +2,7 @@ package mill.javalib import mill.* import mill.constants.Util +import mill.api.opt.* import scala.util.Properties @@ -32,7 +33,7 @@ trait NativeImageModule extends WithJvmWorkerModule { val executeableName = "native-executable" val command = Seq.newBuilder[String] .+=(nativeImageTool().path.toString) - .++=(nativeImageOptions()) + .++=(nativeImageOptions().toStringSeq) .+=("-cp") .+=(nativeImageClasspath().iterator.map(_.path).mkString(java.io.File.pathSeparator)) .+=(finalMainClass()) @@ -57,7 +58,7 @@ trait NativeImageModule extends WithJvmWorkerModule { /** * Additional options for the `native-image` Tool. */ - def nativeImageOptions: T[Seq[String]] = Seq() + def nativeImageOptions: T[Opts] = Opts() /** * Path to the [[https://www.graalvm.org/latest/reference-manual/native-image/ `native-image` Tool]]. diff --git a/libs/javalib/src/mill/javalib/checkstyle/CheckstyleModule.scala b/libs/javalib/src/mill/javalib/checkstyle/CheckstyleModule.scala index c7ee10c4b789..b86588989c7d 100644 --- a/libs/javalib/src/mill/javalib/checkstyle/CheckstyleModule.scala +++ b/libs/javalib/src/mill/javalib/checkstyle/CheckstyleModule.scala @@ -1,7 +1,8 @@ package mill.javalib.checkstyle import mill._ -import mill.api.{PathRef} +import mill.api.PathRef +import mill.api.opt.* import mill.javalib.{DepSyntax, JavaModule} import mill.util.Jvm import mill.api.BuildCtx @@ -27,7 +28,7 @@ trait CheckstyleModule extends JavaModule { protected def checkstyle0(stdout: Boolean, leftover: mainargs.Leftover[String]) = Task.Anon { val output = checkstyleOutput().path - val args = checkstyleOptions() ++ + val args = checkstyleOptions().toStringSeq ++ Seq("-c", checkstyleConfig().path.toString()) ++ Seq("-f", checkstyleFormat()) ++ (if (stdout) Seq.empty else Seq("-o", output.toString())) ++ @@ -106,8 +107,8 @@ trait CheckstyleModule extends JavaModule { /** * Additional arguments for Checkstyle. */ - def checkstyleOptions: T[Seq[String]] = Task { - Seq.empty[String] + def checkstyleOptions: T[Opts] = Task { + Opts() } /** diff --git a/libs/javalib/src/mill/javalib/pmd/PmdModule.scala b/libs/javalib/src/mill/javalib/pmd/PmdModule.scala index 226fa0eb4169..ebf7c360364b 100644 --- a/libs/javalib/src/mill/javalib/pmd/PmdModule.scala +++ b/libs/javalib/src/mill/javalib/pmd/PmdModule.scala @@ -3,6 +3,7 @@ package mill.javalib.pmd import mill.* import mill.api.{Discover, ExternalModule, TaskCtx} import mill.api.daemon.experimental +import mill.api.opt.* import mill.javalib.api.Versions import mill.javalib.{CoursierModule, Dep, DepSyntax, OfflineSupportModule} import mill.util.{Jvm, Version} @@ -51,8 +52,8 @@ trait PmdModule extends CoursierModule, OfflineSupportModule { ) val args = - if (isPmd6OrOlder(this.pmdVersion())) pmdOptions() ++ baseArgs - else pmdOptions() ++ (Seq("check") ++ baseArgs) + if (isPmd6OrOlder(this.pmdVersion())) pmdOptions().toStringSeq ++ baseArgs + else pmdOptions().toStringSeq ++ (Seq("check") ++ baseArgs) val mainCls = if (isPmd6OrOlder(this.pmdVersion())) "net.sourceforge.pmd.PMD" else "net.sourceforge.pmd.cli.PmdCli" @@ -148,9 +149,7 @@ trait PmdModule extends CoursierModule, OfflineSupportModule { def pmdRulesets: T[Seq[PathRef]] = Task.Sources(moduleDir / "pmd-ruleset.xml") /** Additional arguments for PMD. */ - def pmdOptions: T[Seq[String]] = Task { - Seq.empty[String] - } + def pmdOptions: T[Opts] = Task { Opts() } /** User language of the JVM running PMD. */ def pmdLanguage: T[Option[String]] = Task.Input { From 138cda3104109f05c371512502a538a29e4c79e3 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Fri, 7 Nov 2025 15:15:42 +0100 Subject: [PATCH 26/67] Fix opts in YAML --- example/cli/header/2-tasks-yaml/build.mill.yaml | 2 +- example/javalib/config/4-native-image/build.mill.yaml | 2 +- example/javalib/script/6-packaging/Bar.java | 2 +- example/kotlinlib/script/6-packaging/Bar.kt | 2 +- example/scalalib/config/4-native-image/build.mill.yaml | 2 +- example/scalalib/script/6-packaging/Bar.scala | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example/cli/header/2-tasks-yaml/build.mill.yaml b/example/cli/header/2-tasks-yaml/build.mill.yaml index 883e669c3d6f..6d567304d4c1 100644 --- a/example/cli/header/2-tasks-yaml/build.mill.yaml +++ b/example/cli/header/2-tasks-yaml/build.mill.yaml @@ -1,2 +1,2 @@ mill-build: - scalacOptions: ["-verbose"] + scalacOptions: [["-verbose"]] diff --git a/example/javalib/config/4-native-image/build.mill.yaml b/example/javalib/config/4-native-image/build.mill.yaml index 686ac50ff159..a09851c2fe07 100644 --- a/example/javalib/config/4-native-image/build.mill.yaml +++ b/example/javalib/config/4-native-image/build.mill.yaml @@ -1,3 +1,3 @@ extends: [mill.javalib.JavaModule, mill.javalib.NativeImageModule] jvmId: "graalvm-community:24" -nativeImageOptions: ["--no-fallback"] \ No newline at end of file +nativeImageOptions: [["--no-fallback"]] \ No newline at end of file diff --git a/example/javalib/script/6-packaging/Bar.java b/example/javalib/script/6-packaging/Bar.java index 0b71b3355f94..e6ff417050e8 100644 --- a/example/javalib/script/6-packaging/Bar.java +++ b/example/javalib/script/6-packaging/Bar.java @@ -1,5 +1,5 @@ //| jvmId: "graalvm-community:17" -//| nativeImageOptions: ["--no-fallback"] +//| nativeImageOptions: [["--no-fallback"]] public class Bar { public static void main(String[] args) { System.out.println("Hello World"); diff --git a/example/kotlinlib/script/6-packaging/Bar.kt b/example/kotlinlib/script/6-packaging/Bar.kt index 055d54c7cf65..a1ecccdc3894 100644 --- a/example/kotlinlib/script/6-packaging/Bar.kt +++ b/example/kotlinlib/script/6-packaging/Bar.kt @@ -1,6 +1,6 @@ //| kotlinVersion: 2.0.20 //| jvmId: "graalvm-community:17" -//| nativeImageOptions: ["--no-fallback"] +//| nativeImageOptions: [["--no-fallback"]] fun main(args: Array) { println("Hello World") } diff --git a/example/scalalib/config/4-native-image/build.mill.yaml b/example/scalalib/config/4-native-image/build.mill.yaml index 47a8dc0e737c..af857aff1805 100644 --- a/example/scalalib/config/4-native-image/build.mill.yaml +++ b/example/scalalib/config/4-native-image/build.mill.yaml @@ -1,4 +1,4 @@ extends: [mill.scalalib.ScalaModule, mill.scalalib.NativeImageModule] scalaVersion: 3.7.3 jvmId: "graalvm-community:24" -nativeImageOptions: ["--no-fallback"] +nativeImageOptions: [["--no-fallback"]] diff --git a/example/scalalib/script/6-packaging/Bar.scala b/example/scalalib/script/6-packaging/Bar.scala index e56b76464801..8fe18949de53 100644 --- a/example/scalalib/script/6-packaging/Bar.scala +++ b/example/scalalib/script/6-packaging/Bar.scala @@ -1,6 +1,6 @@ //| scalaVersion: 3.7.3 //| jvmId: "graalvm-community:17" -//| nativeImageOptions: ["--no-fallback"] +//| nativeImageOptions: [["--no-fallback"]] @main def main() = { println("Hello World") } From 1274f2429a1c43268678d2a299a0a9c7fb859369 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Fri, 7 Nov 2025 15:15:55 +0100 Subject: [PATCH 27/67] Fix opts usage --- example/scalalib/publishing/8-native-image-libs/build.mill | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/scalalib/publishing/8-native-image-libs/build.mill b/example/scalalib/publishing/8-native-image-libs/build.mill index 9e718ce87009..345d347aa649 100644 --- a/example/scalalib/publishing/8-native-image-libs/build.mill +++ b/example/scalalib/publishing/8-native-image-libs/build.mill @@ -8,7 +8,7 @@ import mill.api.ModuleRef object foo extends ScalaModule, NativeImageModule { def scalaVersion = "3.7.1" - def nativeImageOptions = Seq("--no-fallback", "-Os") + def nativeImageOptions = Opts("--no-fallback", "-Os") def mvnDeps = Opts( mvn"com.lihaoyi::scalatags:0.13.1", From 7a777a6405034c02048ef94d6cfe0105fa325ad3 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Fri, 7 Nov 2025 15:20:37 +0100 Subject: [PATCH 28/67] Fix import --- libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala index 35120b18ad9a..a4f1624d4e51 100644 --- a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala +++ b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala @@ -101,14 +101,14 @@ class BuildWriter(build: BuildSpec, renderCrossValueInTask: String = "crossValue private def renderBaseModuleImports(baseModule: ModuleSpec) = { val wildcards = mutable.SortedSet.empty[String] import baseModule.* - wildcards += "mill.api" += "mill.api.opts" + wildcards += "mill.api" += "mill.api.opt" wildcards ++= configs.flatMap(imports) renderLines(wildcards.map(s => s"import $s.*")) } private def renderModuleImports(module: ModuleSpec) = { val wildcards = mutable.SortedSet.empty[String] - wildcards += "mill.api" += "mill.api.opts" + wildcards += "mill.api" += "mill.api.opt" for spec <- module.sequence do { import spec.* if (supertypes.isEmpty || crossConfigs.nonEmpty) wildcards += "mill" From e639d9088a68e59db7937974957a9dec570d50b0 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sat, 8 Nov 2025 17:25:41 +0100 Subject: [PATCH 29/67] Add support to read Opts from simplified JSON, like `[ "opt1", "opt2" ]` --- core/api/src/mill/api/opt/Opts.scala | 27 ++++++++++++++++--- .../api/test/src/mill/api/opt/OptsTests.scala | 9 +++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/core/api/src/mill/api/opt/Opts.scala b/core/api/src/mill/api/opt/Opts.scala index e3d79e1d9399..5611457fceb3 100644 --- a/core/api/src/mill/api/opt/Opts.scala +++ b/core/api/src/mill/api/opt/Opts.scala @@ -46,9 +46,30 @@ object Opts { new Opts(groups.filter(!_.isEmpty)) } +// given jsonReadWriter: upickle.ReadWriter[Opts] = +// upickle.readwriter[Seq[OptGroup]].bimap( +// _.value, +// Opts(_*) +// ) + given jsonReadWriter: upickle.ReadWriter[Opts] = - upickle.readwriter[Seq[OptGroup]].bimap( - _.value, - Opts(_*) + upickle.readwriter[ujson.Value].bimap( + { opts => + // We always serialize as a seq of groups + upickle.transform(opts.value).to[ujson.Value] + }, + { + case arr: ujson.Arr => + Opts( + arr.value.map { + // The default case, a seq of groups + case e: ujson.Str => OptGroup(upickle.read[Opt](e)) + // special case, a flat Opt, so we can also read simple ["opt1", "opt2"] arrays + // which is what we want to use in YAML build files + case g => upickle.read[OptGroup](g) + }.toSeq* + ) + } ) + } diff --git a/core/api/test/src/mill/api/opt/OptsTests.scala b/core/api/test/src/mill/api/opt/OptsTests.scala index bb811966b22a..8a56eeef3bb0 100644 --- a/core/api/test/src/mill/api/opt/OptsTests.scala +++ b/core/api/test/src/mill/api/opt/OptsTests.scala @@ -121,6 +121,15 @@ class OptsTests extends TestSuite { val back = upickle.read[Opts](json) assert(opts1 == back) } + test("read-flat-opt-sequences") { + val flatOpts = Seq("opt1", "opt2") + val expected = Opts("opt1", "opt2") + assert(flatOpts == expected.toStringSeq) + + val json = upickle.write(flatOpts) + val back = upickle.read[Opts](json) + assert(back == expected) + } // test("with-mapping-home") { // val json = upickle.write(opts1) // assertGoldenLiteral( From 3480bd8a744afb86147fc5b87bf941cd217944c9 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sat, 8 Nov 2025 17:25:59 +0100 Subject: [PATCH 30/67] fix example --- example/kotlinlib/module/7-resources/build.mill | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/kotlinlib/module/7-resources/build.mill b/example/kotlinlib/module/7-resources/build.mill index cb2f7d5f5b55..c54877799690 100644 --- a/example/kotlinlib/module/7-resources/build.mill +++ b/example/kotlinlib/module/7-resources/build.mill @@ -11,7 +11,7 @@ object foo extends KotlinModule { object test extends KotlinTests, TestModule.Junit5 { def otherFiles = Task.Source("other-files") - def forkEnv = super.forkEnv() ++ Opt( + def forkEnv = super.forkEnv() ++ Map( "OTHER_FILES_DIR" -> Opt(otherFiles().path) ) From 410dee89b5eb7a9855470d1df83e4118025eaa01 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sat, 8 Nov 2025 17:26:16 +0100 Subject: [PATCH 31/67] Revert "Fix opts in YAML" This reverts commit 138cda3104109f05c371512502a538a29e4c79e3. --- example/cli/header/2-tasks-yaml/build.mill.yaml | 2 +- example/javalib/config/4-native-image/build.mill.yaml | 2 +- example/javalib/script/6-packaging/Bar.java | 2 +- example/kotlinlib/script/6-packaging/Bar.kt | 2 +- example/scalalib/config/4-native-image/build.mill.yaml | 2 +- example/scalalib/script/6-packaging/Bar.scala | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example/cli/header/2-tasks-yaml/build.mill.yaml b/example/cli/header/2-tasks-yaml/build.mill.yaml index 6d567304d4c1..883e669c3d6f 100644 --- a/example/cli/header/2-tasks-yaml/build.mill.yaml +++ b/example/cli/header/2-tasks-yaml/build.mill.yaml @@ -1,2 +1,2 @@ mill-build: - scalacOptions: [["-verbose"]] + scalacOptions: ["-verbose"] diff --git a/example/javalib/config/4-native-image/build.mill.yaml b/example/javalib/config/4-native-image/build.mill.yaml index a09851c2fe07..686ac50ff159 100644 --- a/example/javalib/config/4-native-image/build.mill.yaml +++ b/example/javalib/config/4-native-image/build.mill.yaml @@ -1,3 +1,3 @@ extends: [mill.javalib.JavaModule, mill.javalib.NativeImageModule] jvmId: "graalvm-community:24" -nativeImageOptions: [["--no-fallback"]] \ No newline at end of file +nativeImageOptions: ["--no-fallback"] \ No newline at end of file diff --git a/example/javalib/script/6-packaging/Bar.java b/example/javalib/script/6-packaging/Bar.java index e6ff417050e8..0b71b3355f94 100644 --- a/example/javalib/script/6-packaging/Bar.java +++ b/example/javalib/script/6-packaging/Bar.java @@ -1,5 +1,5 @@ //| jvmId: "graalvm-community:17" -//| nativeImageOptions: [["--no-fallback"]] +//| nativeImageOptions: ["--no-fallback"] public class Bar { public static void main(String[] args) { System.out.println("Hello World"); diff --git a/example/kotlinlib/script/6-packaging/Bar.kt b/example/kotlinlib/script/6-packaging/Bar.kt index a1ecccdc3894..055d54c7cf65 100644 --- a/example/kotlinlib/script/6-packaging/Bar.kt +++ b/example/kotlinlib/script/6-packaging/Bar.kt @@ -1,6 +1,6 @@ //| kotlinVersion: 2.0.20 //| jvmId: "graalvm-community:17" -//| nativeImageOptions: [["--no-fallback"]] +//| nativeImageOptions: ["--no-fallback"] fun main(args: Array) { println("Hello World") } diff --git a/example/scalalib/config/4-native-image/build.mill.yaml b/example/scalalib/config/4-native-image/build.mill.yaml index af857aff1805..47a8dc0e737c 100644 --- a/example/scalalib/config/4-native-image/build.mill.yaml +++ b/example/scalalib/config/4-native-image/build.mill.yaml @@ -1,4 +1,4 @@ extends: [mill.scalalib.ScalaModule, mill.scalalib.NativeImageModule] scalaVersion: 3.7.3 jvmId: "graalvm-community:24" -nativeImageOptions: [["--no-fallback"]] +nativeImageOptions: ["--no-fallback"] diff --git a/example/scalalib/script/6-packaging/Bar.scala b/example/scalalib/script/6-packaging/Bar.scala index 8fe18949de53..e56b76464801 100644 --- a/example/scalalib/script/6-packaging/Bar.scala +++ b/example/scalalib/script/6-packaging/Bar.scala @@ -1,6 +1,6 @@ //| scalaVersion: 3.7.3 //| jvmId: "graalvm-community:17" -//| nativeImageOptions: [["--no-fallback"]] +//| nativeImageOptions: ["--no-fallback"] @main def main() = { println("Hello World") } From 4c9f723bdef59ec2e0903fcc3e72d0d6b53724dc Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sat, 8 Nov 2025 17:49:24 +0100 Subject: [PATCH 32/67] fix test --- .../kotlinlib/module/5-compilation-execution-flags/build.mill | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/kotlinlib/module/5-compilation-execution-flags/build.mill b/example/kotlinlib/module/5-compilation-execution-flags/build.mill index c1b268d34c2d..5acf64eca924 100644 --- a/example/kotlinlib/module/5-compilation-execution-flags/build.mill +++ b/example/kotlinlib/module/5-compilation-execution-flags/build.mill @@ -11,7 +11,7 @@ object `package` extends KotlinModule { def forkArgs = Opts("-Xmx4g", "-Dmy.jvm.property=hello") def forkEnv = Map("MY_ENV_VAR" -> opt"WORLD") - def kotlincOptions = super.kotlincOptions() ++ Opt("-Werror") + def kotlincOptions = super.kotlincOptions() ++ Opts("-Werror") } // You can pass flags to the Kotlin compiler via `kotlincOptions`. From 1926d924884e7b57cbaa502d454391b84439e707 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sat, 8 Nov 2025 18:04:36 +0100 Subject: [PATCH 33/67] Use Opts for `ScalaNativeModule.native{Compile,Linking}Options` --- example/scalalib/native/4-common-config/build.mill | 2 +- .../src/mill/scalanativelib/ScalaNativeModule.scala | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/example/scalalib/native/4-common-config/build.mill b/example/scalalib/native/4-common-config/build.mill index f34782f4e1cd..2eeac56e7f55 100644 --- a/example/scalalib/native/4-common-config/build.mill +++ b/example/scalalib/native/4-common-config/build.mill @@ -20,7 +20,7 @@ object `package` extends ScalaNativeModule { def nativeIncrementalCompilation: T[Boolean] = true // Set nativeLinkingOptions path to a directory named `target`. - def nativeLinkingOptions = Opts(opt"-L${moduleDir}/target") + def nativeLinkingOptions = Opts(opt"-L${moduleDir / "target"}") // Set nativeWorkdir directory to `newDir` def nativeWorkdir = Task.dest / "newDir" diff --git a/libs/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala b/libs/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala index 5255b12c556b..a0e3b4f3c744 100644 --- a/libs/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala +++ b/libs/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala @@ -7,6 +7,7 @@ import mill.api.{CrossVersion, Result, TaskCtx} import mill.api.daemon.internal.bsp.ScalaBuildTarget import mill.javalib.api.JvmWorkerUtil import mill.api.daemon.internal.{ScalaNativeModuleApi, ScalaPlatform, internal} +import mill.api.opt.* import mill.javalib.RunModule import mill.javalib.testrunner.{TestResult, TestRunner, TestRunnerUtils} import mill.scalalib.{Dep, DepSyntax, Lib, SbtModule, ScalaModule, TestModule} @@ -177,13 +178,13 @@ trait ScalaNativeModule extends ScalaModule with ScalaNativeModuleApi { outer => def nativeTarget: T[Option[String]] = Task { None } // Options that are passed to clang during compilation - def nativeCompileOptions = Task { - withScalaNativeBridge.apply().apply(_.discoverCompileOptions()) + def nativeCompileOptions: T[Opts] = Task { + Opts(withScalaNativeBridge.apply().apply(_.discoverCompileOptions())) } // Options that are passed to clang during linking - def nativeLinkingOptions = Task { - withScalaNativeBridge.apply().apply(_.discoverLinkingOptions()) + def nativeLinkingOptions: T[Opts] = Task { + Opts(withScalaNativeBridge.apply().apply(_.discoverLinkingOptions())) } // Whether to link `@stub` methods, or ignore them @@ -245,8 +246,8 @@ trait ScalaNativeModule extends ScalaModule with ScalaNativeModuleApi { outer => nativeClang().path.toIO, nativeClangPP().path.toIO, nativeTarget(), - nativeCompileOptions(), - nativeLinkingOptions(), + nativeCompileOptions().toStringSeq, + nativeLinkingOptions().toStringSeq, nativeGC(), nativeLinkStubs(), nativeLTO().value, From 2c4d96e981f77738378446b54f97eae93493cf78 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sat, 8 Nov 2025 18:04:45 +0100 Subject: [PATCH 34/67] fix tests --- example/scalalib/publishing/8-native-image-libs/build.mill | 2 +- example/scalalib/spark/1-hello-spark/build.mill | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/scalalib/publishing/8-native-image-libs/build.mill b/example/scalalib/publishing/8-native-image-libs/build.mill index 345d347aa649..654343707ada 100644 --- a/example/scalalib/publishing/8-native-image-libs/build.mill +++ b/example/scalalib/publishing/8-native-image-libs/build.mill @@ -10,7 +10,7 @@ object foo extends ScalaModule, NativeImageModule { def nativeImageOptions = Opts("--no-fallback", "-Os") - def mvnDeps = Opts( + def mvnDeps = Seq( mvn"com.lihaoyi::scalatags:0.13.1", mvn"com.lihaoyi::mainargs:0.7.7" ) diff --git a/example/scalalib/spark/1-hello-spark/build.mill b/example/scalalib/spark/1-hello-spark/build.mill index 854fed482c3e..8e3253f55f33 100644 --- a/example/scalalib/spark/1-hello-spark/build.mill +++ b/example/scalalib/spark/1-hello-spark/build.mill @@ -10,7 +10,7 @@ object foo extends ScalaModule { mvn"org.apache.spark::spark-sql:3.5.4" ) - def forkArgs = Seq("--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED") + def forkArgs = Opts("--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED") object test extends ScalaTests { def mvnDeps = Seq(mvn"com.lihaoyi::utest:0.9.1") From 5441806c867f10830462e20d34f91137913bde9d Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sat, 8 Nov 2025 18:40:33 +0100 Subject: [PATCH 35/67] fix tests --- .../plugins/2-plugin-integration-tests/build.mill | 6 ++++-- example/javalib/web/5-todo-micronaut/build.mill | 2 +- example/large/multifile/11-helper-files/build.mill | 6 ++++-- example/large/multifile/11-helper-files/foo/package.mill | 7 +++++-- example/scalalib/spark/3-semi-realistic/build.mill | 2 +- integration/ide/bsp-server/resources/project/build.mill | 2 +- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/example/extending/plugins/2-plugin-integration-tests/build.mill b/example/extending/plugins/2-plugin-integration-tests/build.mill index d058ad20b937..c61fce19a127 100644 --- a/example/extending/plugins/2-plugin-integration-tests/build.mill +++ b/example/extending/plugins/2-plugin-integration-tests/build.mill @@ -5,7 +5,9 @@ // command. Integration tests require further build configuration, which is shown below: package build + import mill.*, scalalib.*, publish.* +import mill.api.opt.* import mill.util.BuildInfo.{millVersion, millBinPlatform} object myplugin extends ScalaModule, PublishModule { @@ -22,8 +24,8 @@ object myplugin extends ScalaModule, PublishModule { def mvnDeps = Seq(mvn"com.lihaoyi::mill-testkit:$millVersion") def forkEnv = Task { Map( - "MILL_EXECUTABLE_PATH" -> millExecutable.assembly().path.toString, - "MILL_USER_TEST_REPO" -> publishLocalTestRepo().path.toString + "MILL_EXECUTABLE_PATH" -> Opt(millExecutable.assembly().path), + "MILL_USER_TEST_REPO" -> Opt(publishLocalTestRepo().path) ) } diff --git a/example/javalib/web/5-todo-micronaut/build.mill b/example/javalib/web/5-todo-micronaut/build.mill index ecf307a75b8f..30d4767911b5 100644 --- a/example/javalib/web/5-todo-micronaut/build.mill +++ b/example/javalib/web/5-todo-micronaut/build.mill @@ -55,7 +55,7 @@ trait MicronautModule extends MavenModule { def javacOptions = Opts( OptGroup( "-processorpath", - Opt.mkPath(processors().map(_.path), ":") + Opt.mkPath(processors().map(_.path), sep = ":") ), "-parameters", "-Amicronaut.processing.incremental=true", diff --git a/example/large/multifile/11-helper-files/build.mill b/example/large/multifile/11-helper-files/build.mill index 4962a774c0b9..3932a0afe0a6 100644 --- a/example/large/multifile/11-helper-files/build.mill +++ b/example/large/multifile/11-helper-files/build.mill @@ -3,12 +3,14 @@ // as your `build.mill` or a `package.mill`. package build + import mill.*, scalalib.* +import mill.api.opt.* object `package` extends MyModule { def forkEnv = Map( - "MY_SCALA_VERSION" -> build.scalaVersion(), - "MY_PROJECT_VERSION" -> foo.myProjectVersion + "MY_SCALA_VERSION" -> Opt(build.scalaVersion()), + "MY_PROJECT_VERSION" -> Opt(foo.myProjectVersion) ) } diff --git a/example/large/multifile/11-helper-files/foo/package.mill b/example/large/multifile/11-helper-files/foo/package.mill index 6a701b2ce09e..cfc83be4b475 100644 --- a/example/large/multifile/11-helper-files/foo/package.mill +++ b/example/large/multifile/11-helper-files/foo/package.mill @@ -1,8 +1,11 @@ package build.foo + import mill.*, scalalib.* +import mill.api.opt.* + object `package` extends build.MyModule { def forkEnv = Map( - "MY_SCALA_VERSION" -> build.myScalaVersion, - "MY_PROJECT_VERSION" -> myProjectVersion + "MY_SCALA_VERSION" -> Opt(build.myScalaVersion), + "MY_PROJECT_VERSION" -> Opt(myProjectVersion) ) } diff --git a/example/scalalib/spark/3-semi-realistic/build.mill b/example/scalalib/spark/3-semi-realistic/build.mill index a2cf1d6c54af..2220c4953313 100644 --- a/example/scalalib/spark/3-semi-realistic/build.mill +++ b/example/scalalib/spark/3-semi-realistic/build.mill @@ -18,7 +18,7 @@ object `package` extends ScalaModule { def mvnDeps = Seq(mvn"com.lihaoyi::utest:0.9.1") def testFramework = "utest.runner.Framework" - def forkArgs = Seq("--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED") + def forkArgs = Opts("--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED") } } diff --git a/integration/ide/bsp-server/resources/project/build.mill b/integration/ide/bsp-server/resources/project/build.mill index a553ca82d0bd..5de96d88844d 100644 --- a/integration/ide/bsp-server/resources/project/build.mill +++ b/integration/ide/bsp-server/resources/project/build.mill @@ -59,7 +59,7 @@ object app extends scalalib.JavaModule { mvn"com.mysql:mysql-connector-j:9.1.0" ) - def forkEnv = Map("MY_ENV_VAR" -> "my-value") + def forkEnv = Map("MY_ENV_VAR" -> opt"my-value") object test extends JavaTests { def testFramework = "com.novocode.junit.JUnitFramework" From 008972db35adb5aba14d2e0e3a25132d7d93c191 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sun, 9 Nov 2025 10:51:53 +0100 Subject: [PATCH 36/67] Move setDaemon calls to use-site --- libs/daemon/client/src/mill/client/FileToStreamTailer.java | 1 - runner/daemon/src/mill/daemon/TailManager.scala | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/daemon/client/src/mill/client/FileToStreamTailer.java b/libs/daemon/client/src/mill/client/FileToStreamTailer.java index 856172052c15..cf879fba1deb 100644 --- a/libs/daemon/client/src/mill/client/FileToStreamTailer.java +++ b/libs/daemon/client/src/mill/client/FileToStreamTailer.java @@ -22,7 +22,6 @@ public class FileToStreamTailer extends Thread implements AutoCloseable { public FileToStreamTailer(File file, PrintStream stream, int intervalMsec) { super("FileToStreamTailerThread"); this.intervalMsec = intervalMsec; - setDaemon(true); this.file = file; this.stream = stream; } diff --git a/runner/daemon/src/mill/daemon/TailManager.scala b/runner/daemon/src/mill/daemon/TailManager.scala index aba119d35a53..f329b80f1ee3 100644 --- a/runner/daemon/src/mill/daemon/TailManager.scala +++ b/runner/daemon/src/mill/daemon/TailManager.scala @@ -29,6 +29,9 @@ class TailManager(daemonDir: os.Path) extends AutoCloseable { tailerRefreshIntervalMillis ) + stdoutTailer.setDaemon(true) + stderrTailer.setDaemon(true) + stdoutTailer.start() stderrTailer.start() From 2e91883823d4388baeb7a528bc95e9328762dcfc Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sun, 9 Nov 2025 10:57:19 +0100 Subject: [PATCH 37/67] Fix potential logic error (used variable) --- .../mill/androidlib/databinding/AndroidDataBindingImpl.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/androidlib/databinding/impl/src/mill/androidlib/databinding/AndroidDataBindingImpl.scala b/libs/androidlib/databinding/impl/src/mill/androidlib/databinding/AndroidDataBindingImpl.scala index 5389e89b5d1a..ab2830329767 100644 --- a/libs/androidlib/databinding/impl/src/mill/androidlib/databinding/AndroidDataBindingImpl.scala +++ b/libs/androidlib/databinding/impl/src/mill/androidlib/databinding/AndroidDataBindingImpl.scala @@ -83,7 +83,7 @@ class AndroidDataBindingImpl extends AndroidDataBindingWorker { private def toFile(canonicalName: String): File = { val asPath = canonicalName.replace('.', '/') - os.Path(s"base/${asPath}.java").toIO + os.Path(s"${base}/${asPath}.java").toIO } override def deleteFile(canonicalName: String): Unit = { From dc065d57f3ceb131d8c987be8baf3f409341649e Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sun, 9 Nov 2025 11:05:03 +0100 Subject: [PATCH 38/67] Read and show a ignore reason from the `ignoreErrorsOnCI` file --- testkit/src/mill/testkit/UtestExampleTestSuite.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/testkit/src/mill/testkit/UtestExampleTestSuite.scala b/testkit/src/mill/testkit/UtestExampleTestSuite.scala index 8ed32891d271..5819d743001a 100644 --- a/testkit/src/mill/testkit/UtestExampleTestSuite.scala +++ b/testkit/src/mill/testkit/UtestExampleTestSuite.scala @@ -28,14 +28,16 @@ object UtestExampleTestSuite extends TestSuite { ) } + val ignoreFile = workspaceSourcePath / "ignoreErrorsOnCI" val ignoreErrors = System.getenv("CI") != null && - os.exists(workspaceSourcePath / "ignoreErrorsOnCI") + os.exists(ignoreFile) if (ignoreErrors) try run() catch { case _: TimeoutException => System.err.println( - s"Found ignoreErrorsOnCI under $workspaceSourcePath, ignoring timeout exception" + s"Found ignoreErrorsOnCI under $workspaceSourcePath, ignoring timeout exception" + + Option(os.read(ignoreFile)).filter(_.isBlank).mkString("Reason: ", "", "") ) } else From ac90771c948ca5ab7c4bc21650f6807b3813ffe1 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sun, 9 Nov 2025 11:06:21 +0100 Subject: [PATCH 39/67] Ignore bin-incompat mill-scalafix example for now --- example/scalalib/config/3-linting/ignoreErrorsOnCI | 1 + 1 file changed, 1 insertion(+) create mode 100644 example/scalalib/config/3-linting/ignoreErrorsOnCI diff --git a/example/scalalib/config/3-linting/ignoreErrorsOnCI b/example/scalalib/config/3-linting/ignoreErrorsOnCI new file mode 100644 index 000000000000..7b87248a8116 --- /dev/null +++ b/example/scalalib/config/3-linting/ignoreErrorsOnCI @@ -0,0 +1 @@ +mill-scalafix does not have a binary compatible release yet \ No newline at end of file From 288aa4e4b9172f3823915b2f126e4caa0b66e20c Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sun, 9 Nov 2025 13:33:43 +0100 Subject: [PATCH 40/67] Update expected test outcomes --- .../buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala | 2 +- libs/init/gradle/test/resources/expected/gradle-6-0/build.mill | 2 +- .../gradle/test/resources/expected/gradle-7-0/app/package.mill | 2 +- libs/init/gradle/test/resources/expected/gradle-7-0/build.mill | 2 +- .../gradle/test/resources/expected/gradle-7-0/list/package.mill | 2 +- .../expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala | 2 +- .../test/resources/expected/gradle-7-0/utilities/package.mill | 2 +- .../gradle/test/resources/expected/gradle-8-0/app/package.mill | 2 +- libs/init/gradle/test/resources/expected/gradle-8-0/build.mill | 2 +- .../gradle/test/resources/expected/gradle-8-0/list/package.mill | 2 +- .../expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala | 2 +- .../test/resources/expected/gradle-8-0/utilities/package.mill | 2 +- .../test/resources/expected/gradle-9-0-0/app/package.mill | 2 +- .../init/gradle/test/resources/expected/gradle-9-0-0/build.mill | 2 +- .../test/resources/expected/gradle-9-0-0/list/package.mill | 2 +- .../gradle-9-0-0/mill-build/src/ProjectBaseModule.scala | 2 +- .../gradle-9-0-0/mill-build/src/ProjectPublishModule.scala | 2 +- .../test/resources/expected/gradle-9-0-0/utilities/package.mill | 2 +- .../test/resources/expected/with-args/gradle-8-0/build.mill | 2 +- .../init/maven/test/resources/expected/maven-samples/build.mill | 2 +- .../maven-samples/mill-build/src/MavenSamplesBaseModule.scala | 2 +- .../resources/expected/maven-samples/multi-module/package.mill | 2 +- .../expected/maven-samples/multi-module/server/package.mill | 2 +- .../expected/maven-samples/multi-module/webapp/package.mill | 2 +- .../resources/expected/maven-samples/single-module/package.mill | 2 +- libs/init/maven/test/resources/expected/quickstart/build.mill | 2 +- libs/init/maven/test/resources/expected/spring-start/build.mill | 2 +- .../test/resources/expected/with-args/maven-samples/build.mill | 2 +- .../test/resources/expected/with-args/quickstart/build.mill | 2 +- libs/init/sbt/test/resources/expected/cross-version/build.mill | 2 +- .../resources/expected/sbt-multi-project-example/build.mill | 2 +- .../expected/sbt-multi-project-example/common/package.mill | 2 +- .../mill-build/src/SbtMultiProjectExampleBaseModule.scala | 2 +- .../expected/sbt-multi-project-example/multi1/package.mill | 2 +- .../expected/sbt-multi-project-example/multi2/package.mill | 2 +- .../sbt-multi-project-example/nested/nested/package.mill | 2 +- .../expected/sbt-multi-project-example/nested/package.mill | 2 +- .../sbt/test/resources/expected/scala-seed-project/build.mill | 2 +- 38 files changed, 38 insertions(+), 38 deletions(-) diff --git a/libs/init/buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala b/libs/init/buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala index 580fffd79a97..814eb1c778ee 100644 --- a/libs/init/buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala +++ b/libs/init/buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala @@ -16,7 +16,7 @@ class BuildGenChecker(sourceRoot: os.Path, scalafmtConfigFile: os.Path) { generate: => Unit, sourceRel: os.SubPath, expectedRel: os.SubPath, - updateSnapshots: Boolean = false // pass true to update test data on disk + updateSnapshots: Boolean = sys.env.getOrElse("UTEST_UPDATE_GOLDEN_TESTS", "0").equals("1") // pass true to update test data on disk )(using tp: TestPath ): Boolean = { diff --git a/libs/init/gradle/test/resources/expected/gradle-6-0/build.mill b/libs/init/gradle/test/resources/expected/gradle-6-0/build.mill index 8316a7b8af8c..f882ae36d47a 100644 --- a/libs/init/gradle/test/resources/expected/gradle-6-0/build.mill +++ b/libs/init/gradle/test/resources/expected/gradle-6-0/build.mill @@ -2,7 +2,7 @@ package build import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-7-0/app/package.mill b/libs/init/gradle/test/resources/expected/gradle-7-0/app/package.mill index 4c98e7e89b8f..8ccbf444bf97 100644 --- a/libs/init/gradle/test/resources/expected/gradle-7-0/app/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-7-0/app/package.mill @@ -1,7 +1,7 @@ package build.app import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-7-0/build.mill b/libs/init/gradle/test/resources/expected/gradle-7-0/build.mill index 7dbc474fa239..cb36ea2ea721 100644 --- a/libs/init/gradle/test/resources/expected/gradle-7-0/build.mill +++ b/libs/init/gradle/test/resources/expected/gradle-7-0/build.mill @@ -3,6 +3,6 @@ package build import mill.* import mill.api.* -import mill.api.opts.* +import mill.api.opt.* object `package` extends Module {} diff --git a/libs/init/gradle/test/resources/expected/gradle-7-0/list/package.mill b/libs/init/gradle/test/resources/expected/gradle-7-0/list/package.mill index 8f4d7e36d5b1..450d3dfe752d 100644 --- a/libs/init/gradle/test/resources/expected/gradle-7-0/list/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-7-0/list/package.mill @@ -1,7 +1,7 @@ package build.list import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala b/libs/init/gradle/test/resources/expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala index cf5cf15e8f6c..9006e19bb870 100644 --- a/libs/init/gradle/test/resources/expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala +++ b/libs/init/gradle/test/resources/expected/gradle-7-0/mill-build/src/ProjectBaseModule.scala @@ -1,7 +1,7 @@ package millbuild import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* trait ProjectBaseModule extends MavenModule { diff --git a/libs/init/gradle/test/resources/expected/gradle-7-0/utilities/package.mill b/libs/init/gradle/test/resources/expected/gradle-7-0/utilities/package.mill index 649cd0be4c57..de2132d9798c 100644 --- a/libs/init/gradle/test/resources/expected/gradle-7-0/utilities/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-7-0/utilities/package.mill @@ -1,7 +1,7 @@ package build.utilities import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/app/package.mill b/libs/init/gradle/test/resources/expected/gradle-8-0/app/package.mill index 7a3c062e24b5..b21421a5222f 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/app/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/app/package.mill @@ -1,7 +1,7 @@ package build.app import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/build.mill b/libs/init/gradle/test/resources/expected/gradle-8-0/build.mill index 7dbc474fa239..cb36ea2ea721 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/build.mill +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/build.mill @@ -3,6 +3,6 @@ package build import mill.* import mill.api.* -import mill.api.opts.* +import mill.api.opt.* object `package` extends Module {} diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/list/package.mill b/libs/init/gradle/test/resources/expected/gradle-8-0/list/package.mill index b2ebb0a17310..4639e3c38896 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/list/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/list/package.mill @@ -1,7 +1,7 @@ package build.list import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.errorprone.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala b/libs/init/gradle/test/resources/expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala index cf5cf15e8f6c..9006e19bb870 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/mill-build/src/ProjectBaseModule.scala @@ -1,7 +1,7 @@ package millbuild import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* trait ProjectBaseModule extends MavenModule { diff --git a/libs/init/gradle/test/resources/expected/gradle-8-0/utilities/package.mill b/libs/init/gradle/test/resources/expected/gradle-8-0/utilities/package.mill index 444b7517dfbd..fcd7f7aa675b 100644 --- a/libs/init/gradle/test/resources/expected/gradle-8-0/utilities/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-8-0/utilities/package.mill @@ -1,7 +1,7 @@ package build.utilities import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.errorprone.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/app/package.mill b/libs/init/gradle/test/resources/expected/gradle-9-0-0/app/package.mill index 7d79151c9bdc..148fb81209d6 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/app/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/app/package.mill @@ -1,7 +1,7 @@ package build.app import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/build.mill b/libs/init/gradle/test/resources/expected/gradle-9-0-0/build.mill index 13a2db102d16..74ee3455e8b0 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/build.mill +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/build.mill @@ -4,6 +4,6 @@ package build import mill.* import mill.api.* -import mill.api.opts.* +import mill.api.opt.* object `package` extends Module {} diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/list/package.mill b/libs/init/gradle/test/resources/expected/gradle-9-0-0/list/package.mill index f255608b29e8..893529fc4077 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/list/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/list/package.mill @@ -1,7 +1,7 @@ package build.list import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectBaseModule.scala b/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectBaseModule.scala index 61164d62d78b..c6c7787b2f85 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectBaseModule.scala +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectBaseModule.scala @@ -1,7 +1,7 @@ package millbuild import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* trait ProjectBaseModule extends MavenModule { diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectPublishModule.scala b/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectPublishModule.scala index 7bfc0715ca4a..5a40117a4893 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectPublishModule.scala +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/mill-build/src/ProjectPublishModule.scala @@ -1,7 +1,7 @@ package millbuild import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* diff --git a/libs/init/gradle/test/resources/expected/gradle-9-0-0/utilities/package.mill b/libs/init/gradle/test/resources/expected/gradle-9-0-0/utilities/package.mill index 058c8926a0f9..e3c88690edaa 100644 --- a/libs/init/gradle/test/resources/expected/gradle-9-0-0/utilities/package.mill +++ b/libs/init/gradle/test/resources/expected/gradle-9-0-0/utilities/package.mill @@ -1,7 +1,7 @@ package build.utilities import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/gradle/test/resources/expected/with-args/gradle-8-0/build.mill b/libs/init/gradle/test/resources/expected/with-args/gradle-8-0/build.mill index 4ffd8d096d8a..67cbb7bd8ef2 100644 --- a/libs/init/gradle/test/resources/expected/with-args/gradle-8-0/build.mill +++ b/libs/init/gradle/test/resources/expected/with-args/gradle-8-0/build.mill @@ -3,7 +3,7 @@ package build import mill.* import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.errorprone.* diff --git a/libs/init/maven/test/resources/expected/maven-samples/build.mill b/libs/init/maven/test/resources/expected/maven-samples/build.mill index a937819422ac..397d2b4624d1 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/build.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/build.mill @@ -2,7 +2,7 @@ package build import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/maven/test/resources/expected/maven-samples/mill-build/src/MavenSamplesBaseModule.scala b/libs/init/maven/test/resources/expected/maven-samples/mill-build/src/MavenSamplesBaseModule.scala index e4cf622b96ab..e6179eec98f2 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/mill-build/src/MavenSamplesBaseModule.scala +++ b/libs/init/maven/test/resources/expected/maven-samples/mill-build/src/MavenSamplesBaseModule.scala @@ -1,7 +1,7 @@ package millbuild import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* diff --git a/libs/init/maven/test/resources/expected/maven-samples/multi-module/package.mill b/libs/init/maven/test/resources/expected/maven-samples/multi-module/package.mill index 41eb89d68f24..3dd952c0c7e0 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/multi-module/package.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/multi-module/package.mill @@ -1,7 +1,7 @@ package build.`multi-module` import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/maven/test/resources/expected/maven-samples/multi-module/server/package.mill b/libs/init/maven/test/resources/expected/maven-samples/multi-module/server/package.mill index 957a2a20f442..b379d8b3ea96 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/multi-module/server/package.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/multi-module/server/package.mill @@ -1,7 +1,7 @@ package build.`multi-module`.server import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/maven/test/resources/expected/maven-samples/multi-module/webapp/package.mill b/libs/init/maven/test/resources/expected/maven-samples/multi-module/webapp/package.mill index 38151735a17d..ed1321f53229 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/multi-module/webapp/package.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/multi-module/webapp/package.mill @@ -1,7 +1,7 @@ package build.`multi-module`.webapp import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/maven/test/resources/expected/maven-samples/single-module/package.mill b/libs/init/maven/test/resources/expected/maven-samples/single-module/package.mill index ab5ddd26937d..0fb8eaeebfb3 100644 --- a/libs/init/maven/test/resources/expected/maven-samples/single-module/package.mill +++ b/libs/init/maven/test/resources/expected/maven-samples/single-module/package.mill @@ -1,7 +1,7 @@ package build.`single-module` import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/maven/test/resources/expected/quickstart/build.mill b/libs/init/maven/test/resources/expected/quickstart/build.mill index 62ce7136f3a9..472b4c5b0ba1 100644 --- a/libs/init/maven/test/resources/expected/quickstart/build.mill +++ b/libs/init/maven/test/resources/expected/quickstart/build.mill @@ -2,7 +2,7 @@ package build import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.errorprone.* import mill.javalib.publish.* diff --git a/libs/init/maven/test/resources/expected/spring-start/build.mill b/libs/init/maven/test/resources/expected/spring-start/build.mill index 421b11487658..75aa1eb5b290 100644 --- a/libs/init/maven/test/resources/expected/spring-start/build.mill +++ b/libs/init/maven/test/resources/expected/spring-start/build.mill @@ -2,7 +2,7 @@ package build import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* diff --git a/libs/init/maven/test/resources/expected/with-args/maven-samples/build.mill b/libs/init/maven/test/resources/expected/with-args/maven-samples/build.mill index a25a11501ea7..a20df9557534 100644 --- a/libs/init/maven/test/resources/expected/with-args/maven-samples/build.mill +++ b/libs/init/maven/test/resources/expected/with-args/maven-samples/build.mill @@ -2,7 +2,7 @@ package build import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* diff --git a/libs/init/maven/test/resources/expected/with-args/quickstart/build.mill b/libs/init/maven/test/resources/expected/with-args/quickstart/build.mill index cc05bdfae586..3347cdf925a3 100644 --- a/libs/init/maven/test/resources/expected/with-args/quickstart/build.mill +++ b/libs/init/maven/test/resources/expected/with-args/quickstart/build.mill @@ -2,7 +2,7 @@ package build import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.errorprone.* import mill.javalib.publish.* diff --git a/libs/init/sbt/test/resources/expected/cross-version/build.mill b/libs/init/sbt/test/resources/expected/cross-version/build.mill index 32dd2a646f82..e0857503f96c 100644 --- a/libs/init/sbt/test/resources/expected/cross-version/build.mill +++ b/libs/init/sbt/test/resources/expected/cross-version/build.mill @@ -4,7 +4,7 @@ package build import mill.* import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/build.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/build.mill index 7dbc474fa239..cb36ea2ea721 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/build.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/build.mill @@ -3,6 +3,6 @@ package build import mill.* import mill.api.* -import mill.api.opts.* +import mill.api.opt.* object `package` extends Module {} diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill index 70b067d0d497..1d8071e6931f 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill @@ -1,7 +1,7 @@ package build.common import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/mill-build/src/SbtMultiProjectExampleBaseModule.scala b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/mill-build/src/SbtMultiProjectExampleBaseModule.scala index a37140cd775b..7ef6be3b7d17 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/mill-build/src/SbtMultiProjectExampleBaseModule.scala +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/mill-build/src/SbtMultiProjectExampleBaseModule.scala @@ -1,7 +1,7 @@ package millbuild import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi1/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi1/package.mill index 9ff351267bcf..a32677d07517 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi1/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi1/package.mill @@ -1,7 +1,7 @@ package build.multi1 import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi2/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi2/package.mill index 646a226255b9..b3f2653397ba 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi2/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi2/package.mill @@ -1,7 +1,7 @@ package build.multi2 import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/nested/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/nested/package.mill index c7380175478a..7fab989b1d99 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/nested/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/nested/package.mill @@ -1,7 +1,7 @@ package build.nested.nested import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/package.mill index 3aa5969e613d..bccecf3d1d4a 100644 --- a/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/package.mill +++ b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/nested/package.mill @@ -2,6 +2,6 @@ package build.nested import mill.* import mill.api.* -import mill.api.opts.* +import mill.api.opt.* object `package` extends Module {} diff --git a/libs/init/sbt/test/resources/expected/scala-seed-project/build.mill b/libs/init/sbt/test/resources/expected/scala-seed-project/build.mill index 5fcef3a10116..f7a63203aa09 100644 --- a/libs/init/sbt/test/resources/expected/scala-seed-project/build.mill +++ b/libs/init/sbt/test/resources/expected/scala-seed-project/build.mill @@ -2,7 +2,7 @@ package build import mill.api.* -import mill.api.opts.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* From 59b5e1c5cb7b9c0b75bf54eed1ab0814f6438354 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sun, 9 Nov 2025 15:12:29 +0100 Subject: [PATCH 41/67] Test fixes --- example/thirdparty/arrow/build.mill | 17 +++++++++-------- example/thirdparty/mockito/build.mill | 2 +- example/thirdparty/netty/build.mill | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/example/thirdparty/arrow/build.mill b/example/thirdparty/arrow/build.mill index a18923d6375b..25e73e1978af 100644 --- a/example/thirdparty/arrow/build.mill +++ b/example/thirdparty/arrow/build.mill @@ -3,6 +3,7 @@ package build import mill.*, kotlinlib.*, kotlinlib.js.* import mill.scalalib.CoursierModule import mill.api.Result +import mill.api.opt.* import mill.javalib.testrunner.TestResult import mill.javalib.api.CompilationResult import mill.kotlinlib.kover.KoverModule @@ -113,7 +114,7 @@ object `package` extends Module { def kotlinExplicitApi: T[Boolean] = true - protected def commonSourcesArg(sources: Seq[PathRef], commonSourcesDirName: String): String = { + protected def commonSourcesArg(sources: Seq[PathRef], commonSourcesDirName: String): Opt = { val files = sources .flatMap(pr => os.walk(pr.path)) @@ -123,7 +124,7 @@ object `package` extends Module { // This is allowed with `-Xcommon-sources` flag, but probably will be prohibited in the future. // Ideally, it should be in the [[KotlinModule]] directly, but this implies [[KotlinModule]] should know where // common sources are, making some assumptions about layout. - s"-Xcommon-sources=${files.mkString(",")}" + Opt.mkPath(files, sep = ",", prefix = "-Xcommon-sources=") } trait ArrowPlatformModule extends KotlinMavenModule, PlatformKotlinModule { outer => @@ -148,7 +149,7 @@ object `package` extends Module { override def kotlincOptions = super.kotlincOptions() ++ - Seq("-Xexpect-actual-classes", commonSourcesArg(sources(), "commonMain")) + Opts("-Xexpect-actual-classes", commonSourcesArg(sources(), "commonMain")) trait ArrowPlatformTests extends KotlinMavenTests { @@ -252,7 +253,7 @@ object `package` extends Module { libraries.coroutinesTestJvm, libraries.kotestAssertionsCoreJvm ) - def kotlincOptions = super.kotlincOptions() ++ Seq("-Xcontext-receivers") + def kotlincOptions = super.kotlincOptions() ++ Opts("-Xcontext-receivers") } } object js extends ArrowPlatformJsModule { @@ -354,7 +355,7 @@ object `package` extends Module { object jvm extends ArrowPlatformJvmModule { def moduleDeps = super.moduleDeps ++ Seq(`arrow-atomic`.jvm, `arrow-annotations`.jvm) def mvnDeps = super.mvnDeps() ++ Seq(libraries.kotlinxSerializationCoreJvm) - def kotlincOptions = super.kotlincOptions() ++ Seq("-Xcontext-receivers") + def kotlincOptions = super.kotlincOptions() ++ Opts("-Xcontext-receivers") object test extends ArrowPlatformJvmTests { def moduleDeps = super.moduleDeps ++ Seq(fx.`arrow-fx-coroutines`.jvm) @@ -521,7 +522,7 @@ object `package` extends Module { def testTimeout = 60_000L } } - val additionalKotlincOptions = Seq("-Xconsistent-data-class-copy-visibility") + val additionalKotlincOptions = Opts("-Xconsistent-data-class-copy-visibility") } } @@ -569,7 +570,7 @@ object `package` extends Module { def moduleDeps = super.moduleDeps ++ Seq(core.`arrow-core`.jvm) object test extends ArrowPlatformJvmTests { def kotlincOptions = - super.kotlincOptions() ++ Seq(commonSourcesArg(jvm.test.sources(), "commonTest")) + super.kotlincOptions() ++ Opts(commonSourcesArg(jvm.test.sources(), "commonTest")) def mvnDeps = super.mvnDeps() ++ Seq( libraries.kotlinTestJunit5, libraries.coroutinesTestJvm, @@ -582,7 +583,7 @@ object `package` extends Module { def moduleDeps = super.moduleDeps ++ Seq(core.`arrow-core`.js) object test extends ArrowPlatformJsTests { def kotlincOptions = - super.kotlincOptions() ++ Seq(commonSourcesArg(js.test.sources(), "commonTest")) + super.kotlincOptions() ++ Opts(commonSourcesArg(js.test.sources(), "commonTest")) def mvnDeps = super.mvnDeps() ++ Seq( libraries.coroutinesTestJs, libraries.kotestAssertionsCoreJs, diff --git a/example/thirdparty/mockito/build.mill b/example/thirdparty/mockito/build.mill index bbf8c2adb8b5..8f654127ab14 100644 --- a/example/thirdparty/mockito/build.mill +++ b/example/thirdparty/mockito/build.mill @@ -46,7 +46,7 @@ trait MockitoModule extends MavenModule { def testMvnDeps: T[Seq[Dep]] = Seq() def testRuntimeMvnDeps: T[Seq[Dep]] = Seq() def testFramework = "com.novocode.junit.JUnitFramework" - def testForkArgs: T[Opts] = Seq() + def testForkArgs: T[Opts] = Opts() def testFilteredSources: T[Seq[os.Path]] = Task { Seq() } diff --git a/example/thirdparty/netty/build.mill b/example/thirdparty/netty/build.mill index a3502af2fd5f..f4ad93883229 100644 --- a/example/thirdparty/netty/build.mill +++ b/example/thirdparty/netty/build.mill @@ -54,7 +54,7 @@ trait NettyBaseTestSuiteModule extends NettyBaseModule, TestModule.Junit5 { mvn"org.bouncycastle:bctls-jdk15on:1.69" ) - def forkArgs = Seq( + def forkArgs = Opts( "-DnativeImage.handlerMetadataGroupId=io.netty", "-Dio.netty.bootstrap.extensions=serviceload", "-XX:+AllowRedefinitionToAddDeleteMethods", @@ -82,7 +82,7 @@ trait NettyModule extends NettyBaseModule { def moduleDeps = super.moduleDeps ++ testModuleDeps def mvnDeps = super.mvnDeps() ++ testMvnDeps() def forkWorkingDir = NettyModule.this.moduleDir - def forkArgs = super.forkArgs() ++ Seq( + def forkArgs = super.forkArgs() ++ Opts( "-Dnativeimage.handlerMetadataArtifactId=netty-" + NettyModule.this.moduleSegments.last.value ) From 1d4c16086ff35e10f69ecb05e8ae47cd46570dc1 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sun, 9 Nov 2025 15:53:39 +0100 Subject: [PATCH 42/67] Added `mkPath` to test case --- core/api/test/src/mill/api/opt/OptsTests.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/api/test/src/mill/api/opt/OptsTests.scala b/core/api/test/src/mill/api/opt/OptsTests.scala index 8a56eeef3bb0..4b8639fc144b 100644 --- a/core/api/test/src/mill/api/opt/OptsTests.scala +++ b/core/api/test/src/mill/api/opt/OptsTests.scala @@ -35,7 +35,8 @@ class OptsTests extends TestSuite { // some files as ArgGroup OptGroup(sources2*), // Mixed ArgGroup - OptGroup("--extra", opt"-Xplugin=${plugin1}") ++ OptGroup(sources1*) + OptGroup("--extra", opt"-Xplugin=${plugin1}") ++ OptGroup(sources1*), + Opt.mkPath(sources1, sep = ":", prefix = "-special-files=") ) val expectedOpts1 = Opts( @@ -55,6 +56,9 @@ class OptsTests extends TestSuite { Opt("-Xplugin=", plugin1), Opt(srcDir1), Opt(srcDir2) + ), + OptGroup( + Opt.mkPath(sources1, sep = ":", prefix = "-special-files=") ) ) @@ -114,7 +118,7 @@ class OptsTests extends TestSuite { assertGoldenLiteral( json, - "[[\"-deprecation\"],[\"-verbose\"],[\"--release\",\"17\"],[[\"-Xplugin=\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}]],[[\"-Xplugin:\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}]],[[{\"path\":\"/tmp/opts-test/work/src1\"}]],[[{\"path\":\"/tmp/opts-test/work/src2\"}]],[[{\"path\":\"/tmp/opts-test/work/src3\"}],[{\"path\":\"/tmp/opts-test/work/src4\"}]],[\"--extra\",[\"-Xplugin=\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}],[{\"path\":\"/tmp/opts-test/work/src1\"}],[{\"path\":\"/tmp/opts-test/work/src2\"}]]]" + "[[\"-deprecation\"],[\"-verbose\"],[\"--release\",\"17\"],[[\"-Xplugin=\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}]],[[\"-Xplugin:\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}]],[[{\"path\":\"/tmp/opts-test/work/src1\"}]],[[{\"path\":\"/tmp/opts-test/work/src2\"}]],[[{\"path\":\"/tmp/opts-test/work/src3\"}],[{\"path\":\"/tmp/opts-test/work/src4\"}]],[\"--extra\",[\"-Xplugin=\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}],[{\"path\":\"/tmp/opts-test/work/src1\"}],[{\"path\":\"/tmp/opts-test/work/src2\"}]],[[\"-special-files=\",{\"path\":\"/tmp/opts-test/work/src1\"},\":\",{\"path\":\"/tmp/opts-test/work/src2\"}]]]" ) assert(json.split("\\Q$HOME\\E").size == 1 + 0) From 63f1abf9392ee15b301b8df1b25df02993a6a1ba Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sun, 9 Nov 2025 16:05:03 +0100 Subject: [PATCH 43/67] fix tests --- example/thirdparty/android-compose-samples/build.mill | 4 ++-- .../ide/bsp-server/resources/snapshots/diagnostics.json | 8 ++++---- .../invalidation/multi-level-editing/resources/build.mill | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/example/thirdparty/android-compose-samples/build.mill b/example/thirdparty/android-compose-samples/build.mill index 84d8d6c5e6f8..38645bda3e3f 100644 --- a/example/thirdparty/android-compose-samples/build.mill +++ b/example/thirdparty/android-compose-samples/build.mill @@ -35,7 +35,7 @@ object JetLagged extends mill.api.Module { override def androidApplicationId = "com.example.jetlagged" - override def kotlincOptions = super.kotlincOptions() ++ Seq( + override def kotlincOptions = super.kotlincOptions() ++ Opts( "-jvm-target", "17" ) @@ -142,7 +142,7 @@ object JetNews extends mill.api.Module { override def androidApplicationId = "com.example.jetnews" - override def kotlincOptions = super.kotlincOptions() ++ Seq( + override def kotlincOptions = super.kotlincOptions() ++ Opts( "-jvm-target", "17" ) diff --git a/integration/ide/bsp-server/resources/snapshots/diagnostics.json b/integration/ide/bsp-server/resources/snapshots/diagnostics.json index bd6e771f2830..626ff49c91b2 100644 --- a/integration/ide/bsp-server/resources/snapshots/diagnostics.json +++ b/integration/ide/bsp-server/resources/snapshots/diagnostics.json @@ -22,11 +22,11 @@ { "range": { "start": { - "line": 101, + "line": 102, "character": 17 }, "end": { - "line": 101, + "line": 102, "character": 22 } }, @@ -52,11 +52,11 @@ { "range": { "start": { - "line": 101, + "line": 102, "character": 17 }, "end": { - "line": 101, + "line": 102, "character": 22 } }, diff --git a/integration/invalidation/multi-level-editing/resources/build.mill b/integration/invalidation/multi-level-editing/resources/build.mill index 95ee301ebe79..80add7536aa9 100644 --- a/integration/invalidation/multi-level-editing/resources/build.mill +++ b/integration/invalidation/multi-level-editing/resources/build.mill @@ -1,10 +1,11 @@ package build import mill._, scalalib._ +import mill.api.opt.* import scalatags.Text.all._ object foo extends JavaModule { def forkEnv = Map( - "snippet" -> frag(h1("hello"), p("world"), p(constant.Constant.scalatagsVersion)).render + "snippet" -> Opt(frag(h1("hello"), p("world"), p(constant.Constant.scalatagsVersion)).render) ) } From bf8723b19f0dc938969a4f29ccc2132ed071a14d Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sun, 9 Nov 2025 18:51:10 +0100 Subject: [PATCH 44/67] . --- core/api/test/src/mill/api/opt/OptsTests.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/api/test/src/mill/api/opt/OptsTests.scala b/core/api/test/src/mill/api/opt/OptsTests.scala index 4b8639fc144b..dd08c7949b6d 100644 --- a/core/api/test/src/mill/api/opt/OptsTests.scala +++ b/core/api/test/src/mill/api/opt/OptsTests.scala @@ -79,7 +79,8 @@ class OptsTests extends TestSuite { "--extra", s"-Xplugin=${plugin1.toString()}" ) ++ - sources1.map(_.toString()) + sources1.map(_.toString()) ++ + Seq(sources1.mkString("-special-files=", ":", "")) override def tests: Tests = Tests { test("OptGroup.isEmpty") { From 2ec818981fd5399ee2acbaca05faf67bb66ba2c1 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sun, 9 Nov 2025 19:58:36 +0100 Subject: [PATCH 45/67] Futher minimize json serialization --- core/api/src/mill/api/opt/Opts.scala | 11 +++++++++-- core/api/test/src/mill/api/opt/OptsTests.scala | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/core/api/src/mill/api/opt/Opts.scala b/core/api/src/mill/api/opt/Opts.scala index 5611457fceb3..357745dac25c 100644 --- a/core/api/src/mill/api/opt/Opts.scala +++ b/core/api/src/mill/api/opt/Opts.scala @@ -53,10 +53,17 @@ object Opts { // ) given jsonReadWriter: upickle.ReadWriter[Opts] = - upickle.readwriter[ujson.Value].bimap( + upickle.readwriter[ujson.Arr].bimap( { opts => // We always serialize as a seq of groups - upickle.transform(opts.value).to[ujson.Value] + opts.value.map { group => + if(group.size == 1 && !group.head.containsPaths) { + ujson.Str(group.head.toString()) + } + else + upickle.transform(group).to[ujson.Value] + } +// upickle.transform(opts.value).to[ujson.Value] }, { case arr: ujson.Arr => diff --git a/core/api/test/src/mill/api/opt/OptsTests.scala b/core/api/test/src/mill/api/opt/OptsTests.scala index dd08c7949b6d..bd9cb196bab0 100644 --- a/core/api/test/src/mill/api/opt/OptsTests.scala +++ b/core/api/test/src/mill/api/opt/OptsTests.scala @@ -119,7 +119,7 @@ class OptsTests extends TestSuite { assertGoldenLiteral( json, - "[[\"-deprecation\"],[\"-verbose\"],[\"--release\",\"17\"],[[\"-Xplugin=\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}]],[[\"-Xplugin:\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}]],[[{\"path\":\"/tmp/opts-test/work/src1\"}]],[[{\"path\":\"/tmp/opts-test/work/src2\"}]],[[{\"path\":\"/tmp/opts-test/work/src3\"}],[{\"path\":\"/tmp/opts-test/work/src4\"}]],[\"--extra\",[\"-Xplugin=\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}],[{\"path\":\"/tmp/opts-test/work/src1\"}],[{\"path\":\"/tmp/opts-test/work/src2\"}]],[[\"-special-files=\",{\"path\":\"/tmp/opts-test/work/src1\"},\":\",{\"path\":\"/tmp/opts-test/work/src2\"}]]]" + "[\"-deprecation\",\"-verbose\",[\"--release\",\"17\"],[[\"-Xplugin=\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}]],[[\"-Xplugin:\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}]],[[{\"path\":\"/tmp/opts-test/work/src1\"}]],[[{\"path\":\"/tmp/opts-test/work/src2\"}]],[[{\"path\":\"/tmp/opts-test/work/src3\"}],[{\"path\":\"/tmp/opts-test/work/src4\"}]],[\"--extra\",[\"-Xplugin=\",{\"path\":\"/tmp/opts-test/.cache/plugin1\"}],[{\"path\":\"/tmp/opts-test/work/src1\"}],[{\"path\":\"/tmp/opts-test/work/src2\"}]],[[\"-special-files=\",{\"path\":\"/tmp/opts-test/work/src1\"},\":\",{\"path\":\"/tmp/opts-test/work/src2\"}]]]" ) assert(json.split("\\Q$HOME\\E").size == 1 + 0) From 5085667be131183d3b1818cdd0e018b5618ccf3a Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Sun, 9 Nov 2025 21:08:30 +0100 Subject: [PATCH 46/67] . --- example/thirdparty/commons-io/build.mill | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/thirdparty/commons-io/build.mill b/example/thirdparty/commons-io/build.mill index 7d2705f73fa8..4f6812fda255 100644 --- a/example/thirdparty/commons-io/build.mill +++ b/example/thirdparty/commons-io/build.mill @@ -7,7 +7,7 @@ import contrib.jmh.JmhModule object `package` extends PublishModule, MavenModule { def jvmId = "temurin:11.0.24" - def javacOptions = Seq("-encoding", "UTF-8") + def javacOptions = Opts("-encoding", "UTF-8") def publishVersion = "2.17.0-SNAPSHOT" def pomSettings = PomSettings( From 4ee23218e9edffc311ce4a75dba29e2cf3eacb85 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Mon, 24 Nov 2025 17:22:27 +0100 Subject: [PATCH 47/67] Fix merge errors --- libs/javalib/src/mill/javalib/JavaModule.scala | 17 ++++++++++------- .../src/mill/javalib/bsp/BspRunModule.scala | 4 ++-- .../javalib/spring/boot/SpringBootModule.scala | 7 ++++--- .../checkstyle/CheckstyleModuleTest.scala | 3 ++- .../src/mill/scalalib/ScalaModule.scala | 2 +- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/libs/javalib/src/mill/javalib/JavaModule.scala b/libs/javalib/src/mill/javalib/JavaModule.scala index ce017e2a71fa..291ce774bfc7 100644 --- a/libs/javalib/src/mill/javalib/JavaModule.scala +++ b/libs/javalib/src/mill/javalib/JavaModule.scala @@ -298,10 +298,10 @@ trait JavaModule if (annotationProcessorsMvnDeps().nonEmpty) Opts( "-processorpath", - Opt.mkPath(annotationProcessorsResolvedMvnDeps(), sep = File.pathSeparator) + Opt.mkPath(annotationProcessorsResolvedMvnDeps().map(_.path), sep = File.pathSeparator) ) else - Seq.empty + Opts() } @@ -905,11 +905,14 @@ trait JavaModule os.makeDir.all(compileGenSources) } - val jOpts = JavaCompilerOptions.split(Seq( - "-s", - compileGenSources.toString - ) ++ javacOptions().toStringSeq ++ mandatoryJavacOptions().toStringSeq ++ annotationProcessorsJavacOptions()) - + val jOpts = JavaCompilerOptions.split( + Opts( + OptGroup("-s", compileGenSources.toString), + javacOptions(), + mandatoryJavacOptions(), + annotationProcessorsJavacOptions() + ).toStringSeq + ) val worker = jvmWorker().internalWorker() worker.apply( diff --git a/libs/javalib/src/mill/javalib/bsp/BspRunModule.scala b/libs/javalib/src/mill/javalib/bsp/BspRunModule.scala index ceddbbcddfc3..726d31b00947 100644 --- a/libs/javalib/src/mill/javalib/bsp/BspRunModule.scala +++ b/libs/javalib/src/mill/javalib/bsp/BspRunModule.scala @@ -21,9 +21,9 @@ private[mill] trait BspRunModule(runModule: RunModule) extends mill.api.Module { override private[mill] def bspJvmRunEnvironment: Task.Simple[( runClasspath: Seq[Path], - forkArgs: Seq[String], + forkArgs: Opts, forkWorkingDir: Path, - forkEnv: Map[String, String], + forkEnv: Map[String, Opt], mainClass: Option[String], localMainClasses: Seq[String] )] = diff --git a/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala b/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala index 4d30ef6cbe79..c8adfa858993 100644 --- a/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala +++ b/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala @@ -2,6 +2,7 @@ package mill.javalib.spring.boot import mill.{T, Task} import mill.api.{ModuleRef, PathRef} +import mill.api.opt.* import mill.javalib.{Dep, DepSyntax, JavaModule, NativeImageModule} import java.util.Properties @@ -150,7 +151,7 @@ trait SpringBootModule extends JavaModule { /** * Enables AOT for running the application under this module */ - override def forkArgs = super.forkArgs() ++ Seq("-Dspring.aot.enabled=true") + override def forkArgs = super.forkArgs() ++ Opts("-Dspring.aot.enabled=true") override def generatedSources: Task.Simple[Seq[PathRef]] = Task { val aotGeneratedSources = Seq(PathRef(outer.springBootProcessAOT().path / "sources")) @@ -174,7 +175,7 @@ trait SpringBootModule extends JavaModule { * parent module as a native GraalVM application, provided the [[outer.springBootProcessAOT]] works. */ trait NativeSpringBootBuildModule extends SpringBootOptimisedBuildModule, NativeImageModule { - override def nativeImageOptions: Task.Simple[Seq[String]] = Task { + override def nativeImageOptions: Task.Simple[Opts] = Task { val nativeImageArgs: Seq[String] = val nativeImageProps = outer.springBootAOTNativeProperties().path @@ -188,7 +189,7 @@ trait SpringBootModule extends JavaModule { } else Seq.empty - nativeImageArgs + Opts(nativeImageArgs) } } diff --git a/libs/javalib/test/src/mill/javalib/checkstyle/CheckstyleModuleTest.scala b/libs/javalib/test/src/mill/javalib/checkstyle/CheckstyleModuleTest.scala index 6aae9114b9c8..9c5969f7e391 100644 --- a/libs/javalib/test/src/mill/javalib/checkstyle/CheckstyleModuleTest.scala +++ b/libs/javalib/test/src/mill/javalib/checkstyle/CheckstyleModuleTest.scala @@ -3,6 +3,7 @@ package mill.javalib.checkstyle import mill._ import mainargs.Leftover import mill.api.Discover +import mill.api.opt.* import mill.javalib.JavaModule import mill.testkit.{TestRootModule, UnitTester} import utest._ @@ -135,7 +136,7 @@ object CheckstyleModuleTest extends TestSuite { object module extends TestRootModule with JavaModule with CheckstyleModule { override def checkstyleFormat: T[String] = format - override def checkstyleOptions: T[Seq[String]] = options + override def checkstyleOptions: T[Opts] = Opts(options) override def checkstyleVersion: T[String] = version lazy val millDiscover = Discover[this.type] } diff --git a/libs/scalalib/src/mill/scalalib/ScalaModule.scala b/libs/scalalib/src/mill/scalalib/ScalaModule.scala index 1b7fe85cd932..cd68fed866ef 100644 --- a/libs/scalalib/src/mill/scalalib/ScalaModule.scala +++ b/libs/scalalib/src/mill/scalalib/ScalaModule.scala @@ -343,7 +343,7 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase scalaOrganization(), scalaDocClasspath(), scalacPluginClasspath(), - options ++ compileCp ++ scalaDocOptions().toStringSeq ++ files.map(_.toString()) + options ++ compileCp ++ scalaDocOptions().toStringSeq ++ files.map(_.toString()), workDir = Task.dest ), javaHome = javaHome().map(_.path) From 505c29f7a6346aa6f5269547c5caf6f1a78ec0c0 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 16:32:05 +0000 Subject: [PATCH 48/67] [autofix.ci] apply automated fixes --- core/api/src/mill/api/opt/Opts.scala | 5 ++--- example/scalalib/linting/3-acyclic/build.mill | 1 - .../test/src/mill/main/buildgen/BuildGenChecker.scala | 5 ++++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/api/src/mill/api/opt/Opts.scala b/core/api/src/mill/api/opt/Opts.scala index 357745dac25c..f5ff05dafc71 100644 --- a/core/api/src/mill/api/opt/Opts.scala +++ b/core/api/src/mill/api/opt/Opts.scala @@ -57,10 +57,9 @@ object Opts { { opts => // We always serialize as a seq of groups opts.value.map { group => - if(group.size == 1 && !group.head.containsPaths) { + if (group.size == 1 && !group.head.containsPaths) { ujson.Str(group.head.toString()) - } - else + } else upickle.transform(group).to[ujson.Value] } // upickle.transform(opts.value).to[ujson.Value] diff --git a/example/scalalib/linting/3-acyclic/build.mill b/example/scalalib/linting/3-acyclic/build.mill index d337442bb9b2..52c1113179cc 100644 --- a/example/scalalib/linting/3-acyclic/build.mill +++ b/example/scalalib/linting/3-acyclic/build.mill @@ -19,7 +19,6 @@ package build import mill.*, scalalib.* import mill.api.opt.* - object `package` extends ScalaModule { def scalaVersion = "2.13.16" def compileMvnDeps = Seq(mvn"com.lihaoyi:::acyclic:0.3.18") diff --git a/libs/init/buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala b/libs/init/buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala index 814eb1c778ee..b3fe2a844d2e 100644 --- a/libs/init/buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala +++ b/libs/init/buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala @@ -16,7 +16,10 @@ class BuildGenChecker(sourceRoot: os.Path, scalafmtConfigFile: os.Path) { generate: => Unit, sourceRel: os.SubPath, expectedRel: os.SubPath, - updateSnapshots: Boolean = sys.env.getOrElse("UTEST_UPDATE_GOLDEN_TESTS", "0").equals("1") // pass true to update test data on disk + updateSnapshots: Boolean = sys.env.getOrElse( + "UTEST_UPDATE_GOLDEN_TESTS", + "0" + ).equals("1") // pass true to update test data on disk )(using tp: TestPath ): Boolean = { From 602cbf86c5ebadb89f974a85aed48ea4d1740cc2 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 25 Nov 2025 11:11:48 +0100 Subject: [PATCH 49/67] Update test expectations --- .../crossproject-cross-version/build.mill | 2 + .../dummy/package.mill | 2 + .../full/package.mill | 2 + .../jvm-util/package.mill | 2 + .../CrossprojectCrossVersionBaseModule.scala | 10 ++- .../pure/package.mill | 2 + .../crossproject-cross-version/build.mill | 85 ++++++++++--------- .../sbt-multi-project-example/build.mill | 10 ++- 8 files changed, 66 insertions(+), 49 deletions(-) diff --git a/libs/init/sbt/test/resources/expected/crossproject-cross-version/build.mill b/libs/init/sbt/test/resources/expected/crossproject-cross-version/build.mill index 8958ea4ccb06..cb36ea2ea721 100644 --- a/libs/init/sbt/test/resources/expected/crossproject-cross-version/build.mill +++ b/libs/init/sbt/test/resources/expected/crossproject-cross-version/build.mill @@ -2,5 +2,7 @@ package build import mill.* +import mill.api.* +import mill.api.opt.* object `package` extends Module {} diff --git a/libs/init/sbt/test/resources/expected/crossproject-cross-version/dummy/package.mill b/libs/init/sbt/test/resources/expected/crossproject-cross-version/dummy/package.mill index fb171f025b3f..0874687d9e50 100644 --- a/libs/init/sbt/test/resources/expected/crossproject-cross-version/dummy/package.mill +++ b/libs/init/sbt/test/resources/expected/crossproject-cross-version/dummy/package.mill @@ -1,6 +1,8 @@ package build.dummy import mill.* +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalajslib.* diff --git a/libs/init/sbt/test/resources/expected/crossproject-cross-version/full/package.mill b/libs/init/sbt/test/resources/expected/crossproject-cross-version/full/package.mill index 54f283b6c7df..cf4bc261c8f9 100644 --- a/libs/init/sbt/test/resources/expected/crossproject-cross-version/full/package.mill +++ b/libs/init/sbt/test/resources/expected/crossproject-cross-version/full/package.mill @@ -1,6 +1,8 @@ package build.full import mill.* +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalajslib.* diff --git a/libs/init/sbt/test/resources/expected/crossproject-cross-version/jvm-util/package.mill b/libs/init/sbt/test/resources/expected/crossproject-cross-version/jvm-util/package.mill index 8cf027b7e48d..d9d7f53f396a 100644 --- a/libs/init/sbt/test/resources/expected/crossproject-cross-version/jvm-util/package.mill +++ b/libs/init/sbt/test/resources/expected/crossproject-cross-version/jvm-util/package.mill @@ -1,6 +1,8 @@ package build.`jvm-util` import mill.* +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/crossproject-cross-version/mill-build/src/CrossprojectCrossVersionBaseModule.scala b/libs/init/sbt/test/resources/expected/crossproject-cross-version/mill-build/src/CrossprojectCrossVersionBaseModule.scala index 58a0bef3f3b4..37ee87d9d0c6 100644 --- a/libs/init/sbt/test/resources/expected/crossproject-cross-version/mill-build/src/CrossprojectCrossVersionBaseModule.scala +++ b/libs/init/sbt/test/resources/expected/crossproject-cross-version/mill-build/src/CrossprojectCrossVersionBaseModule.scala @@ -1,5 +1,7 @@ package millbuild +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* @@ -9,15 +11,15 @@ trait CrossprojectCrossVersionBaseModule def mvnDeps = super.mvnDeps() ++ Seq(Deps.upickle) - def scalacOptions = super.scalacOptions() ++ Seq("-deprecation") ++ + def scalacOptions = super.scalacOptions() ++ Opts("-deprecation") ++ (scalaVersion() match { - case "2.12.20" => Seq( + case "2.12.20" => Opts( "-Xlint:_,-unused", "-Ywarn-numeric-widen", "-Ywarn-unused:_,-nowarn,-privates" ) - case "2.13.14" => Seq("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") - case "3.7.1" => Seq("-Wunused") + case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") case _ => Nil }) diff --git a/libs/init/sbt/test/resources/expected/crossproject-cross-version/pure/package.mill b/libs/init/sbt/test/resources/expected/crossproject-cross-version/pure/package.mill index 1446ca396c25..a0e5ad32a2d2 100644 --- a/libs/init/sbt/test/resources/expected/crossproject-cross-version/pure/package.mill +++ b/libs/init/sbt/test/resources/expected/crossproject-cross-version/pure/package.mill @@ -1,6 +1,8 @@ package build.pure import mill.* +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalajslib.* diff --git a/libs/init/sbt/test/resources/expected/with-args/crossproject-cross-version/build.mill b/libs/init/sbt/test/resources/expected/with-args/crossproject-cross-version/build.mill index 1a225aabe646..8e109d7178ee 100644 --- a/libs/init/sbt/test/resources/expected/with-args/crossproject-cross-version/build.mill +++ b/libs/init/sbt/test/resources/expected/with-args/crossproject-cross-version/build.mill @@ -2,6 +2,8 @@ package build import mill.* +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalajslib.* @@ -26,16 +28,16 @@ object `package` extends Module { def artifactName = "dummy" - def scalacOptions = super.scalacOptions() ++ Seq("-deprecation") ++ + def scalacOptions = super.scalacOptions() ++ Opts("-deprecation") ++ (scalaVersion() match { - case "2.12.20" => Seq( + case "2.12.20" => Opts( "-Xlint:_,-unused", "-Ywarn-numeric-widen", "-Ywarn-unused:_,-nowarn,-privates" ) case "2.13.14" => - Seq("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") - case "3.7.1" => Seq("-Wunused") + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") case _ => Nil }) @@ -62,16 +64,16 @@ object `package` extends Module { def artifactName = "dummy" - def scalacOptions = super.scalacOptions() ++ Seq("-deprecation") ++ + def scalacOptions = super.scalacOptions() ++ Opts("-deprecation") ++ (scalaVersion() match { - case "2.12.20" => Seq( + case "2.12.20" => Opts( "-Xlint:_,-unused", "-Ywarn-numeric-widen", "-Ywarn-unused:_,-nowarn,-privates" ) case "2.13.14" => - Seq("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") - case "3.7.1" => Seq("-Wunused") + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") case _ => Nil }) @@ -101,16 +103,16 @@ object `package` extends Module { def artifactName = "dummy" - def scalacOptions = super.scalacOptions() ++ Seq("-deprecation") ++ + def scalacOptions = super.scalacOptions() ++ Opts("-deprecation") ++ (scalaVersion() match { - case "2.12.20" => Seq( + case "2.12.20" => Opts( "-Xlint:_,-unused", "-Ywarn-numeric-widen", "-Ywarn-unused:_,-nowarn,-privates" ) case "2.13.14" => - Seq("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") - case "3.7.1" => Seq("-Wunused") + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") case _ => Nil }) @@ -144,16 +146,16 @@ object `package` extends Module { def artifactName = "full" - def scalacOptions = super.scalacOptions() ++ Seq("-deprecation") ++ + def scalacOptions = super.scalacOptions() ++ Opts("-deprecation") ++ (scalaVersion() match { - case "2.12.20" => Seq( + case "2.12.20" => Opts( "-Xlint:_,-unused", "-Ywarn-numeric-widen", "-Ywarn-unused:_,-nowarn,-privates" ) case "2.13.14" => - Seq("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") - case "3.7.1" => Seq("-Wunused") + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") case _ => Nil }) @@ -182,16 +184,16 @@ object `package` extends Module { def artifactName = "full" - def scalacOptions = super.scalacOptions() ++ Seq("-deprecation") ++ + def scalacOptions = super.scalacOptions() ++ Opts("-deprecation") ++ (scalaVersion() match { - case "2.12.20" => Seq( + case "2.12.20" => Opts( "-Xlint:_,-unused", "-Ywarn-numeric-widen", "-Ywarn-unused:_,-nowarn,-privates" ) case "2.13.14" => - Seq("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") - case "3.7.1" => Seq("-Wunused") + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") case _ => Nil }) @@ -221,16 +223,16 @@ object `package` extends Module { def artifactName = "full" - def scalacOptions = super.scalacOptions() ++ Seq("-deprecation") ++ + def scalacOptions = super.scalacOptions() ++ Opts("-deprecation") ++ (scalaVersion() match { - case "2.12.20" => Seq( + case "2.12.20" => Opts( "-Xlint:_,-unused", "-Ywarn-numeric-widen", "-Ywarn-unused:_,-nowarn,-privates" ) case "2.13.14" => - Seq("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") - case "3.7.1" => Seq("-Wunused") + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") case _ => Nil }) @@ -256,16 +258,17 @@ object `package` extends Module { def artifactName = "jvmutil" - def scalacOptions = super.scalacOptions() ++ Seq("-deprecation") ++ + def scalacOptions = super.scalacOptions() ++ Opts("-deprecation") ++ (scalaVersion() match { - case "2.12.20" => Seq( + case "2.12.20" => Opts( "-Xlint:_,-unused", "-Ywarn-numeric-widen", "-Ywarn-unused:_,-nowarn,-privates" ) - case "2.13.14" => Seq("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") - case "3.7.1" => Seq("-Wunused") - case _ => Nil + case "2.13.14" => + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") + case _ => Nil }) def pomSettings = PomSettings( @@ -296,16 +299,16 @@ object `package` extends Module { def artifactName = "pure" - def scalacOptions = super.scalacOptions() ++ Seq("-deprecation") ++ + def scalacOptions = super.scalacOptions() ++ Opts("-deprecation") ++ (scalaVersion() match { - case "2.12.20" => Seq( + case "2.12.20" => Opts( "-Xlint:_,-unused", "-Ywarn-numeric-widen", "-Ywarn-unused:_,-nowarn,-privates" ) case "2.13.14" => - Seq("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") - case "3.7.1" => Seq("-Wunused") + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") case _ => Nil }) @@ -332,16 +335,16 @@ object `package` extends Module { def artifactName = "pure" - def scalacOptions = super.scalacOptions() ++ Seq("-deprecation") ++ + def scalacOptions = super.scalacOptions() ++ Opts("-deprecation") ++ (scalaVersion() match { - case "2.12.20" => Seq( + case "2.12.20" => Opts( "-Xlint:_,-unused", "-Ywarn-numeric-widen", "-Ywarn-unused:_,-nowarn,-privates" ) case "2.13.14" => - Seq("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") - case "3.7.1" => Seq("-Wunused") + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") case _ => Nil }) @@ -371,16 +374,16 @@ object `package` extends Module { def artifactName = "pure" - def scalacOptions = super.scalacOptions() ++ Seq("-deprecation") ++ + def scalacOptions = super.scalacOptions() ++ Opts("-deprecation") ++ (scalaVersion() match { - case "2.12.20" => Seq( + case "2.12.20" => Opts( "-Xlint:_,-unused", "-Ywarn-numeric-widen", "-Ywarn-unused:_,-nowarn,-privates" ) case "2.13.14" => - Seq("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") - case "3.7.1" => Seq("-Wunused") + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") case _ => Nil }) diff --git a/libs/init/sbt/test/resources/expected/with-args/sbt-multi-project-example/build.mill b/libs/init/sbt/test/resources/expected/with-args/sbt-multi-project-example/build.mill index 905a39c01346..ac61e34904c1 100644 --- a/libs/init/sbt/test/resources/expected/with-args/sbt-multi-project-example/build.mill +++ b/libs/init/sbt/test/resources/expected/with-args/sbt-multi-project-example/build.mill @@ -2,6 +2,8 @@ package build import mill.* +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* @@ -23,7 +25,7 @@ object `package` extends Module { def scalaVersion = "2.12.3" - def scalacOptions = super.scalacOptions() ++ Seq( + def scalacOptions = super.scalacOptions() ++ Opts( "-unchecked", "-feature", "-language:existentials", @@ -102,7 +104,7 @@ object `package` extends Module { def scalaVersion = "2.12.3" - def scalacOptions = super.scalacOptions() ++ Seq( + def scalacOptions = super.scalacOptions() ++ Opts( "-unchecked", "-feature", "-language:existentials", @@ -181,7 +183,7 @@ object `package` extends Module { def scalaVersion = "2.12.3" - def scalacOptions = super.scalacOptions() ++ Seq( + def scalacOptions = super.scalacOptions() ++ Opts( "-unchecked", "-feature", "-language:existentials", @@ -251,7 +253,7 @@ object `package` extends Module { def scalaVersion = "2.12.3" - def scalacOptions = super.scalacOptions() ++ Seq( + def scalacOptions = super.scalacOptions() ++ Opts( "-unchecked", "-feature", "-language:existentials", From e720525aed7869aa96681b3d88b1b135a00ed81f Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 25 Nov 2025 11:33:53 +0100 Subject: [PATCH 50/67] Update test --- .../sbt/test/resources/crossproject/project/build.properties | 2 +- libs/init/sbt/test/resources/expected/crossproject/build.mill | 2 ++ .../sbt/test/resources/expected/crossproject/dummy/package.mill | 2 ++ .../sbt/test/resources/expected/crossproject/full/package.mill | 2 ++ .../crossproject/mill-build/src/CrossprojectBaseModule.scala | 2 ++ .../sbt/test/resources/expected/crossproject/pure/package.mill | 2 ++ 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libs/init/sbt/test/resources/crossproject/project/build.properties b/libs/init/sbt/test/resources/crossproject/project/build.properties index fdb242913064..e33f4dab9e9f 100644 --- a/libs/init/sbt/test/resources/crossproject/project/build.properties +++ b/libs/init/sbt/test/resources/crossproject/project/build.properties @@ -1 +1 @@ -sbt.version=1.8.3 \ No newline at end of file +sbt.version=1.10.10 \ No newline at end of file diff --git a/libs/init/sbt/test/resources/expected/crossproject/build.mill b/libs/init/sbt/test/resources/expected/crossproject/build.mill index 8958ea4ccb06..cb36ea2ea721 100644 --- a/libs/init/sbt/test/resources/expected/crossproject/build.mill +++ b/libs/init/sbt/test/resources/expected/crossproject/build.mill @@ -2,5 +2,7 @@ package build import mill.* +import mill.api.* +import mill.api.opt.* object `package` extends Module {} diff --git a/libs/init/sbt/test/resources/expected/crossproject/dummy/package.mill b/libs/init/sbt/test/resources/expected/crossproject/dummy/package.mill index 80d36507e8bf..54d80571e833 100644 --- a/libs/init/sbt/test/resources/expected/crossproject/dummy/package.mill +++ b/libs/init/sbt/test/resources/expected/crossproject/dummy/package.mill @@ -1,6 +1,8 @@ package build.dummy import mill.* +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalajslib.* diff --git a/libs/init/sbt/test/resources/expected/crossproject/full/package.mill b/libs/init/sbt/test/resources/expected/crossproject/full/package.mill index 48bb1ba0c703..8f28765f4f5d 100644 --- a/libs/init/sbt/test/resources/expected/crossproject/full/package.mill +++ b/libs/init/sbt/test/resources/expected/crossproject/full/package.mill @@ -1,6 +1,8 @@ package build.full import mill.* +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalajslib.* diff --git a/libs/init/sbt/test/resources/expected/crossproject/mill-build/src/CrossprojectBaseModule.scala b/libs/init/sbt/test/resources/expected/crossproject/mill-build/src/CrossprojectBaseModule.scala index 75ed6f4db394..3cec27918ab8 100644 --- a/libs/init/sbt/test/resources/expected/crossproject/mill-build/src/CrossprojectBaseModule.scala +++ b/libs/init/sbt/test/resources/expected/crossproject/mill-build/src/CrossprojectBaseModule.scala @@ -1,5 +1,7 @@ package millbuild +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* diff --git a/libs/init/sbt/test/resources/expected/crossproject/pure/package.mill b/libs/init/sbt/test/resources/expected/crossproject/pure/package.mill index da498f3e6d4f..12006dc0b3b7 100644 --- a/libs/init/sbt/test/resources/expected/crossproject/pure/package.mill +++ b/libs/init/sbt/test/resources/expected/crossproject/pure/package.mill @@ -1,6 +1,8 @@ package build.pure import mill.* +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalajslib.* From 5f8ffa5e74d69e1f616f4e21130de927b58bc2de Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 25 Nov 2025 11:39:51 +0100 Subject: [PATCH 51/67] . --- .../test/src/mill/main/buildgen/BuildGenChecker.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/init/buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala b/libs/init/buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala index b3fe2a844d2e..dcf1ea7db6c7 100644 --- a/libs/init/buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala +++ b/libs/init/buildgen/test/src/mill/main/buildgen/BuildGenChecker.scala @@ -16,10 +16,10 @@ class BuildGenChecker(sourceRoot: os.Path, scalafmtConfigFile: os.Path) { generate: => Unit, sourceRel: os.SubPath, expectedRel: os.SubPath, - updateSnapshots: Boolean = sys.env.getOrElse( - "UTEST_UPDATE_GOLDEN_TESTS", - "0" - ).equals("1") // pass true to update test data on disk + // pass true to update test data on disk + updateSnapshots: Boolean = sys.env + .getOrElse("UTEST_UPDATE_GOLDEN_TESTS", "0") + .equals("1") )(using tp: TestPath ): Boolean = { From 9a72ca5be935f255b27707afe213eb563e6ba026 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 25 Nov 2025 11:46:52 +0100 Subject: [PATCH 52/67] fix/disable test for unsupported mill-scalafix --- example/scalalib/config/4-linting/build.mill | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/example/scalalib/config/4-linting/build.mill b/example/scalalib/config/4-linting/build.mill index 76c06f9dc444..191285abbf23 100644 --- a/example/scalalib/config/4-linting/build.mill +++ b/example/scalalib/config/4-linting/build.mill @@ -48,14 +48,16 @@ object Foo { /** See Also: .scalafix.conf */ /** Usage -> ./mill __.fix - -> cat src/Foo.scala -package foo -object Foo { - def main(args: Array[String]) = { - println("Hello world") - } -} +> ./mill __.fix # mill-scalafix not compatible with new Opts class +error: fix java.lang.ClassCastException: class mill.api.opt.Opts cannot be cast to class scala.collection.immutable.Seq ... */ +//// +////> cat src/Foo.scala +////package foo +////object Foo { +//// def main(args: Array[String]) = { +//// println("Hello world") +//// } +////} + From d74278c763d94de786ef7a434c6f882ec0c7178d Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 25 Nov 2025 12:49:27 +0100 Subject: [PATCH 53/67] Add missing import --- example/thirdparty/android-compose-samples/build.mill | 1 + 1 file changed, 1 insertion(+) diff --git a/example/thirdparty/android-compose-samples/build.mill b/example/thirdparty/android-compose-samples/build.mill index 38645bda3e3f..c235cf8e159b 100644 --- a/example/thirdparty/android-compose-samples/build.mill +++ b/example/thirdparty/android-compose-samples/build.mill @@ -1,4 +1,5 @@ import mill.*, androidlib.*, kotlinlib.* +import mill.api.opt.* object Versions { val kotlinVersion = "2.1.20" From 6018b98e77f0e1a19c47a2d8859c7ae0a87e56aa Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 25 Nov 2025 13:09:47 +0100 Subject: [PATCH 54/67] Fix BuildWriter for Opts --- libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala index a4f1624d4e51..7f280b2eb2ce 100644 --- a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala +++ b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala @@ -630,7 +630,7 @@ class BuildWriter(build: BuildSpec, renderCrossValueInTask: String = "crossValue } s""" ++ ($renderCrossValueInTask match { | ${renderLines(crossCases)} - | case _ => Nil + | case _ => Opts() |})""".stripMargin } } From 7a172e356349bbc7a025966d95d4b0617b1a8ec4 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 12:26:03 +0000 Subject: [PATCH 55/67] [autofix.ci] apply automated fixes --- example/scalalib/config/4-linting/build.mill | 1 - 1 file changed, 1 deletion(-) diff --git a/example/scalalib/config/4-linting/build.mill b/example/scalalib/config/4-linting/build.mill index 191285abbf23..cd33a4410fa2 100644 --- a/example/scalalib/config/4-linting/build.mill +++ b/example/scalalib/config/4-linting/build.mill @@ -60,4 +60,3 @@ error: fix java.lang.ClassCastException: class mill.api.opt.Opts cannot be cast //// println("Hello world") //// } ////} - From d31db2bffc98ce12bcae6a32099e02d1f32560e5 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 25 Nov 2025 13:28:08 +0100 Subject: [PATCH 56/67] Update test literals --- .../ide/bsp-server/resources/snapshots/diagnostics.json | 8 ++++---- integration/ide/bsp-server/resources/snapshots/logging | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/integration/ide/bsp-server/resources/snapshots/diagnostics.json b/integration/ide/bsp-server/resources/snapshots/diagnostics.json index 61958c399914..6e23832a0ab0 100644 --- a/integration/ide/bsp-server/resources/snapshots/diagnostics.json +++ b/integration/ide/bsp-server/resources/snapshots/diagnostics.json @@ -22,11 +22,11 @@ { "range": { "start": { - "line": 106, + "line": 107, "character": 17 }, "end": { - "line": 106, + "line": 107, "character": 22 } }, @@ -52,11 +52,11 @@ { "range": { "start": { - "line": 106, + "line": 107, "character": 17 }, "end": { - "line": 106, + "line": 107, "character": 22 } }, diff --git a/integration/ide/bsp-server/resources/snapshots/logging b/integration/ide/bsp-server/resources/snapshots/logging index cf76c5fc8a5e..7314e1c6999e 100644 --- a/integration/ide/bsp-server/resources/snapshots/logging +++ b/integration/ide/bsp-server/resources/snapshots/logging @@ -6,7 +6,7 @@ bsp] BSP server started bsp-init-mill-build/build.mill-60] compiling * Scala sources to * ... bsp-init-mill-build/build.mill-60] done compiling bsp-init-build.mill-60] compiling * Scala sources to * ... -bsp-init-build.mill-60] [warn] build.mill:107:18 +bsp-init-build.mill-60] [warn] build.mill:108:18 bsp-init-build.mill-60] def theThing = thing bsp-init-build.mill-60] ^^^^^ bsp-init-build.mill-60] method thing in object diag is deprecated since 0.0.1: deprecated From 7e874920ee8b9063992991f080e5ae76840125bc Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 25 Nov 2025 13:32:17 +0100 Subject: [PATCH 57/67] Bootstrap Patch --- ci/mill-bootstrap.patch | 9 +++++++++ mill-build/src/millbuild/package.scala | 1 + 2 files changed, 10 insertions(+) create mode 100644 mill-build/src/millbuild/package.scala diff --git a/ci/mill-bootstrap.patch b/ci/mill-bootstrap.patch index e69de29bb2d1..fe0181203a8a 100644 --- a/ci/mill-bootstrap.patch +++ b/ci/mill-bootstrap.patch @@ -0,0 +1,9 @@ +diff --git a/mill-build/src/millbuild/package.scala b/mill-build/src/millbuild/package.scala +index b64a97c8e44..9335010790c 100644 +--- a/mill-build/src/millbuild/package.scala ++++ b/mill-build/src/millbuild/package.scala +@@ -1 +1,3 @@ +-package object millbuild {} ++package object millbuild { ++ implicit def toOpts(seq: Seq[String]): mill.api.opt.Opts = mill.api.opt.Opts(seq) ++} diff --git a/mill-build/src/millbuild/package.scala b/mill-build/src/millbuild/package.scala new file mode 100644 index 000000000000..b64a97c8e441 --- /dev/null +++ b/mill-build/src/millbuild/package.scala @@ -0,0 +1 @@ +package object millbuild {} From b005074ad6f2513a6c2cac43a9ed4f1e59c3a691 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 25 Nov 2025 22:49:58 +0100 Subject: [PATCH 58/67] Update mill-bootstrap.patch --- ci/mill-bootstrap.patch | 402 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 393 insertions(+), 9 deletions(-) diff --git a/ci/mill-bootstrap.patch b/ci/mill-bootstrap.patch index fe0181203a8a..e616918e6256 100644 --- a/ci/mill-bootstrap.patch +++ b/ci/mill-bootstrap.patch @@ -1,9 +1,393 @@ -diff --git a/mill-build/src/millbuild/package.scala b/mill-build/src/millbuild/package.scala -index b64a97c8e44..9335010790c 100644 ---- a/mill-build/src/millbuild/package.scala -+++ b/mill-build/src/millbuild/package.scala -@@ -1 +1,3 @@ --package object millbuild {} -+package object millbuild { -+ implicit def toOpts(seq: Seq[String]): mill.api.opt.Opts = mill.api.opt.Opts(seq) -+} +diff --git a/dist/package.mill b/dist/package.mill +index d9d8e2e05f1..af820b9c1d1 100644 +--- a/dist/package.mill ++++ b/dist/package.mill +@@ -13,6 +13,7 @@ import scala.util.Using + import scala.util.Properties + import java.nio.file.Files + import java.nio.file.attribute.PosixFilePermission ++import mill.api.opt.* + + trait DistModule extends Module { + // All modules that we want to aggregate as part of this `dev` assembly. +@@ -173,7 +174,7 @@ object `package` extends MillJavaModule with DistModule { + + def localBinName = "mill-assembly.jar" + +- private def millClientJvmArgs = Seq( ++ private def millClientJvmArgs = Opts( + // Avoid reserving a lot of memory for the client, as the client only forward information + "-Xmx128m" + ) +@@ -206,7 +207,7 @@ object `package` extends MillJavaModule with DistModule { + mainClass = mainClass().get, + shellClassPath = classpath, + cmdClassPath = Seq(classpathJar.toString()), +- jvmArgs = jvmArgs ++ jvmArgs = jvmArgs.toStringSeq + ) + + os.write(outputPath, script) +@@ -220,7 +221,7 @@ object `package` extends MillJavaModule with DistModule { + mill.scalalib.Assembly.Rule.ExcludePattern("mill/local-test-overrides/.*") + ) + +- def forkArgs = millClientJvmArgs ++ Seq( ++ def forkArgs = millClientJvmArgs ++ Opts( + // Workaround for Zinc/JNA bug + // https://github.com/sbt/sbt/blame/6718803ee6023ab041b045a6988fafcfae9d15b5/main/src/main/scala/sbt/Main.scala#L130 + "-Djna.nosys=true" +@@ -243,7 +244,7 @@ object `package` extends MillJavaModule with DistModule { + try { + os.call( + cmd = (launcher().path.toString, rest), +- env = forkEnv() ++ build.dist.localTestOverridesEnv(), ++ env = (forkEnv() ++ build.dist.localTestOverridesEnv()).view.mapValues(_.toString).toMap, + cwd = wd, + stdin = os.Inherit, + stdout = os.Inherit, +@@ -357,7 +358,7 @@ object `package` extends MillJavaModule with DistModule { + + def executableRaw = nativeImage() + +- def nativeImageOptions = Seq( ++ def nativeImageOptions = Opts( + "--no-fallback", + "--enable-url-protocols=https", + "-Os", +diff --git a/dist/scripts/package.mill b/dist/scripts/package.mill +index 89262ef2b35..4afac12dd18 100644 +--- a/dist/scripts/package.mill ++++ b/dist/scripts/package.mill +@@ -7,6 +7,7 @@ import mill.* + import mill.scalalib.* + import mill.api.Result + import millbuild.* ++import mill.api.opt.* + + object `package` extends mill.Module { scripts => + +@@ -77,9 +78,9 @@ object `package` extends mill.Module { scripts => + def mvnDeps = Seq(millbuild.Deps.osLib, millbuild.Deps.pprint) + def utestVersion = millbuild.Deps.TestDeps.utest.version + def forkEnv = Map( +- "MILL_TEST_SH_SCRIPT" -> millSh.compile0().path.toString, +- "MILL_TEST_BAT_SCRIPT" -> millBat.compile0().path.toString, +- "MILL_NATIVE_SUFFIX" -> build.dist.native.nativeSuffix() ++ "MILL_TEST_SH_SCRIPT" -> Opt(millSh.compile0().path), ++ "MILL_TEST_BAT_SCRIPT" -> Opt(millBat.compile0().path), ++ "MILL_NATIVE_SUFFIX" -> Opt(build.dist.native.nativeSuffix()) + ) + } + def scriptsModules: Seq[BootstrapScriptModule] = Seq(millSh, millBat) +diff --git a/example/package.mill b/example/package.mill +index e4e29b18b5e..2f5e02d302e 100644 +--- a/example/package.mill ++++ b/example/package.mill +@@ -14,6 +14,7 @@ import mill.T + import mill.api.Cross + import mill.api.BuildCtx + import mill.testkit.Chunk ++import mill.api.opt.* + + object `package` extends Module { + def exampleModules: Seq[ExampleCrossModule] = moduleInternal +@@ -238,8 +239,8 @@ object `package` extends Module { + def runClasspath = build.libs.util.test.runClasspath() + def localRunClasspath = build.testkit.localRunClasspath() + +- def forkEnv = Map("LANG" -> "C") +- def forkArgs: T[Seq[String]] = Task(List.empty[String]) ++ def forkEnv = Map("LANG" -> opt"C") ++ def forkArgs: T[Opts] = Task(Opts()) + + /** + * Parses a `build.mill` for specific comments and return the split-by-type content +diff --git a/integration/package.mill b/integration/package.mill +index cd35e6d0763..870b0b99f39 100644 +--- a/integration/package.mill ++++ b/integration/package.mill +@@ -16,6 +16,7 @@ import mill.javalib.testrunner.TestResult + import millbuild.* + import upickle.implicits.namedTuples.default.given + import mill.api.BuildCtx ++import mill.api.opt.* + + object `package` extends mill.Module { + // We compile the test code once and then offer multiple modes to +@@ -48,8 +49,8 @@ object `package` extends mill.Module { + def resources: T[Seq[PathRef]] + def runClasspath: T[Seq[PathRef]] + def localRunClasspath: T[Seq[PathRef]] +- def forkEnv: T[Map[String, String]] +- def forkArgs: T[Seq[String]] ++ def forkEnv: T[Map[String, Opt]] ++ def forkArgs: T[Opts] + def testExclusive = false + + trait ModeModule extends MillBaseTestsModule { +@@ -59,7 +60,7 @@ object `package` extends mill.Module { + localOutFolder().withValue(()) { sharedOutFolder => + val testModuleUtil = new mill.javalib.TestModuleUtil( + testUseArgsFile(), +- forkArgs(), ++ forkArgs().toStringSeq, + Seq.empty[String], + jvmWorker().scalalibClasspath(), + resources(), +@@ -69,7 +70,8 @@ object `package` extends mill.Module { + args, + testForkGrouping(), + jvmWorker().testrunnerEntrypointClasspath(), +- allForkEnv() ++ Option.when(useSharedOut) { "MILL_TEST_SHARED_OUTPUT_DIR" -> "1" }, ++ allForkEnv().view.mapValues(_.toString).toMap ++ ++ Option.when(useSharedOut) { "MILL_TEST_SHARED_OUTPUT_DIR" -> "1" }, + testSandboxWorkingDir = !useSharedOut, + if (useSharedOut) sharedOutFolder else forkWorkingDir(), + testReportXml(), +@@ -85,15 +87,15 @@ object `package` extends mill.Module { + def mode: String = moduleSegments.parts.last + def scalaVersion = Deps.scalaVersion + +- def forkEnv = Task { ++ def forkEnv: T[Map[String, Opt]] = Task { + super.forkEnv() ++ + IntegrationTestModule.this.forkEnv() ++ + Map( +- "MILL_INTEGRATION_DAEMON_MODE" -> (mode == "daemon").toString, +- "MILL_INTEGRATION_IS_PACKAGED_LAUNCHER" -> millIntegrationIsPackagedLauncher().toString, +- "MILL_LAUNCHER" -> build.dist.bootstrapLauncher().path.toString, +- "MILL_LAUNCHER_BAT" -> build.dist.bootstrapLauncherBat().path.toString, +- "MILL_INTEGRATION_LAUNCHER" -> millIntegrationLauncher().path.toString ++ "MILL_INTEGRATION_DAEMON_MODE" -> Opt((mode == "daemon").toString), ++ "MILL_INTEGRATION_IS_PACKAGED_LAUNCHER" -> Opt(millIntegrationIsPackagedLauncher().toString), ++ "MILL_LAUNCHER" -> Opt(build.dist.bootstrapLauncher().path), ++ "MILL_LAUNCHER_BAT" -> Opt(build.dist.bootstrapLauncherBat().path), ++ "MILL_INTEGRATION_LAUNCHER" -> Opt(millIntegrationLauncher().path) + ) ++ + (if (millIntegrationIsPackagedLauncher()) Map() else build.dist.localTestOverridesEnv()) + } +@@ -155,12 +157,12 @@ object `package` extends mill.Module { + def enableBsp = false + } + override def moduleDeps = super[IntegrationTestModule].moduleDeps +- def forkArgs: T[Seq[String]] = Task(List.empty[String]) ++ def forkArgs: T[Opts] = Task(Opts()) + def forkEnv = super.forkEnv() ++ Seq( + // "UTEST_UPDATE_GOLDEN_TESTS" -> "1", +- "MILL_PROJECT_ROOT" -> BuildCtx.workspaceRoot.toString, +- "TEST_SCALA_2_13_VERSION" -> Deps.testScala213Version, +- "TEST_KOTLIN_VERSION" -> Deps.kotlinCompiler.version ++ "MILL_PROJECT_ROOT" -> Opt(BuildCtx.workspaceRoot), ++ "TEST_SCALA_2_13_VERSION" -> Opt(Deps.testScala213Version), ++ "TEST_KOTLIN_VERSION" -> Opt(Deps.kotlinCompiler.version) + ) + } + trait IdeIntegrationCrossModule extends IntegrationCrossModule { +@@ -168,7 +170,7 @@ object `package` extends mill.Module { + def mvnDeps = super.mvnDeps() ++ Seq( + Deps.bsp4j + ) +- def forkArgs = super.forkArgs() ++ Seq( ++ def forkArgs = super.forkArgs() ++ Opts( + s"-Dmill.integration.coursier-version=${Deps.coursier.dep.versionConstraint.asString}" + ) + } +diff --git a/libs/javalib/package.mill b/libs/javalib/package.mill +index 7ed81bc6843..c580c7fc5f1 100644 +--- a/libs/javalib/package.mill ++++ b/libs/javalib/package.mill +@@ -15,6 +15,7 @@ import mill.contrib.buildinfo.BuildInfo + import mill.T + import mill.api.Cross + import millbuild.* ++import mill.api.opt.* + + object `package` extends MillStableScalaModule { + +@@ -44,7 +45,7 @@ object `package` extends MillStableScalaModule { + ) + def testForkEnv = { + val locale = if (Properties.isMac) "en_US.UTF-8" else "C.utf8" +- super.testForkEnv() ++ Map("LC_ALL" -> locale) ++ super.testForkEnv() ++ Map("LC_ALL" -> Opt(locale)) + } + + override def mimaBinaryIssueFilters: T[Seq[ProblemFilter]] = +diff --git a/libs/scalalib/package.mill b/libs/scalalib/package.mill +index acb0ed5daa8..8317f1d6971 100644 +--- a/libs/scalalib/package.mill ++++ b/libs/scalalib/package.mill +@@ -13,6 +13,7 @@ import mill.contrib.buildinfo.BuildInfo + import mill.T + import mill.api.Cross + import millbuild.* ++import mill.api.opt.* + + object `package` extends MillStableScalaModule { + def moduleDeps = Seq(build.libs.javalib) +@@ -30,6 +31,6 @@ object `package` extends MillStableScalaModule { + + def testForkEnv = { + val locale = if (Properties.isMac) "en_US.UTF-8" else "C.utf8" +- super.testForkEnv() ++ Map("LC_ALL" -> locale) ++ super.testForkEnv() ++ Map("LC_ALL" -> Opt(locale)) + } + } +diff --git a/mill-build/src/millbuild/MillBaseTestsModule.scala b/mill-build/src/millbuild/MillBaseTestsModule.scala +index 80fdd82d16c..0b10e69157c 100644 +--- a/mill-build/src/millbuild/MillBaseTestsModule.scala ++++ b/mill-build/src/millbuild/MillBaseTestsModule.scala +@@ -2,10 +2,11 @@ package millbuild + + import mill.* + import mill.scalalib.* ++import mill.api.opt.* + + trait MillBaseTestsModule extends TestModule { + def forkArgs = Task { +- Seq( ++ Opts( + s"-DMILL_SCALA_3_NEXT_VERSION=${Deps.scalaVersion}", + s"-DMILL_SCALA_2_13_VERSION=${Deps.scala2Version}", + s"-DMILL_SCALA_2_12_VERSION=${Deps.workerScalaVersion212}", +diff --git a/mill-build/src/millbuild/MillJavaModule.scala b/mill-build/src/millbuild/MillJavaModule.scala +index f82f0d10ec5..089349df5c5 100644 +--- a/mill-build/src/millbuild/MillJavaModule.scala ++++ b/mill-build/src/millbuild/MillJavaModule.scala +@@ -8,6 +8,7 @@ import mill.T + import mill.Task + import mill.scalalib.Dep + import mill.scalalib.JavaModule ++import mill.api.opt.* + + import java.io.File + +@@ -59,13 +60,13 @@ trait MillJavaModule extends JavaModule { + } + + def testMvnDeps: T[Seq[Dep]] = Seq(Deps.TestDeps.utest) +- def testForkEnv: T[Map[String, String]] = forkEnv() ++ localTestOverridesEnv() ++ def testForkEnv: T[Map[String, Opt]] = forkEnv() ++ localTestOverridesEnv() + def testModuleDeps: Seq[JavaModule] = + if (this == build.core.api) Seq(build.core.api) + else Seq(this, build.core.api.test) + +- def localTestOverridesEnv = Task { +- val localRepos = localTestRepositories().map(_.path.toString).mkString(File.pathSeparator) ++ def localTestOverridesEnv: T[Seq[(String, Opt)]] = Task { ++ val localRepos = Opt.mkPath(localTestRepositories().map(_.path), sep = File.pathSeparator) + Seq("MILL_LOCAL_TEST_REPO" -> localRepos) + } + +@@ -107,14 +108,14 @@ trait MillJavaModule extends JavaModule { + } + + override def javacOptions = Task { +- super.javacOptions() ++ ciJavacOptions() ++ Seq( ++ super.javacOptions() ++ ciJavacOptions() ++ Opts( + "-Xlint", + "-Xlint:-serial", // we don't care about java serialization + "-Xlint:-try" // TODO: a bunch of code needs reviewing with this lint) + ) + } + +- def javadocOptions = super.javadocOptions() ++ Seq( ++ def javadocOptions = super.javadocOptions() ++ Opts( + // Disable warnings for missing documentation comments or tags (for example, + // a missing comment or class, or a missing @return tag or similar tag on a method). + // We have many methods without JavaDoc comments, so those warnings are useless +diff --git a/mill-build/src/millbuild/MillPublishJavaModule.scala b/mill-build/src/millbuild/MillPublishJavaModule.scala +index 342747153c6..6730228fe51 100644 +--- a/mill-build/src/millbuild/MillPublishJavaModule.scala ++++ b/mill-build/src/millbuild/MillPublishJavaModule.scala +@@ -4,6 +4,7 @@ import build_.package_ as build + import mill.Task + import mill.scalalib.PublishModule + import mill.scalalib.publish.{Developer, License, PomSettings, VersionControl} ++import mill.api.opt.* + + trait MillPublishJavaModule extends MillJavaModule with PublishModule { + +@@ -14,7 +15,7 @@ trait MillPublishJavaModule extends MillJavaModule with PublishModule { + ) + def pomSettings = MillPublishJavaModule.commonPomSettings(artifactName()) + def javacOptions = +- super.javacOptions() ++ Seq("--release", "11", "-encoding", "UTF-8", "-deprecation") ++ super.javacOptions() ++ Opts("--release", "11", "-encoding", "UTF-8", "-deprecation") + } + + object MillPublishJavaModule { +diff --git a/runner/bsp/package.mill b/runner/bsp/package.mill +index 5c511891e2d..0cdae63e94e 100644 +--- a/runner/bsp/package.mill ++++ b/runner/bsp/package.mill +@@ -4,6 +4,7 @@ import mill._ + import mill.contrib.buildinfo.BuildInfo + import mill.T + import millbuild.* ++import mill.api.opt.* + + object `package` extends MillPublishScalaModule with BuildInfo { + def compileModuleDeps = Seq(build.libs.javalib) +@@ -24,7 +25,7 @@ object `package` extends MillPublishScalaModule with BuildInfo { + + override lazy val test: MillScalaTests = new Test {} + trait Test extends MillScalaTests { +- def forkEnv: T[Map[String, String]] = Task { ++ def forkEnv: T[Map[String, Opt]] = Task { + // We try to fetch this dependency with coursier in the tests + worker.publishLocalCached() + super.forkEnv() +diff --git a/runner/codesig/package.mill b/runner/codesig/package.mill +index c10f27f0ec5..579df2817e2 100644 +--- a/runner/codesig/package.mill ++++ b/runner/codesig/package.mill +@@ -3,6 +3,7 @@ import mill._ + import mill.scalalib._ + import millbuild.* + import mill.api.BuildCtx ++import mill.api.opt.* + + /** + * The CodeSig module implements a conservative call-graph analyzer at the JVM +@@ -27,14 +28,14 @@ object `package` extends MillPublishScalaModule { + + def testLogFolder = Task { Task.dest } + +- def caseEnvs[V](f1: CaseModule => Task[V])(s: String, f2: V => String) = { ++ def caseEnvs[V](f1: CaseModule => Task[V])(s: String, f2: V => Opt) = { + Task.traverse(caseKeys) { i => f1(cases(i)).map(v => s"MILL_TEST_${s}_$i" -> f2(v)) } + } + def forkEnv = Task { +- Map("MILL_TEST_LOGS" -> testLogFolder().toString) ++ +- caseEnvs(_.compile)("CLASSES", _.classes.path.toString)() ++ +- caseEnvs(_.compileClasspath)("CLASSPATH", _.map(_.path).mkString(","))() ++ +- caseEnvs(_.sources)("SOURCES", _.head.path.toString)() ++ Map("MILL_TEST_LOGS" -> Opt(testLogFolder())) ++ ++ caseEnvs(_.compile)("CLASSES", cr => Opt(cr.classes.path))() ++ ++ caseEnvs(_.compileClasspath)("CLASSPATH", prs => Opt.mkPath(prs.map(_.path), sep = ","))() ++ ++ caseEnvs(_.sources)("SOURCES", s => Opt(s.head.path))() + } + + object cases extends Cross[CaseModule](caseKeys) +diff --git a/testkit/package.mill b/testkit/package.mill +index a8693a3834c..3b713079acf 100644 +--- a/testkit/package.mill ++++ b/testkit/package.mill +@@ -3,6 +3,7 @@ package build.testkit + import mill._ + import millbuild.* + import mill.api.BuildCtx ++import mill.api.opt.* + + /** + * Mill unit/integration/example-testing helpers. Both used internally +@@ -20,6 +21,6 @@ object `package` extends MillPublishScalaModule { + + def forkEnv = + super.forkEnv() ++ +- Map("MILL_EXECUTABLE_PATH" -> build.dist.launcher().path.toString()) ++ ++ Map("MILL_EXECUTABLE_PATH" -> Opt(build.dist.launcher().path)) ++ + build.dist.testForkEnv() + } From a405b6cd616d63ba4f098ca5929c7ac4a58e08c4 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 26 Nov 2025 10:58:40 +0100 Subject: [PATCH 59/67] Update patchfile --- ci/mill-bootstrap.patch | 209 +++++++++++++++++++++++++++++++++++----- 1 file changed, 183 insertions(+), 26 deletions(-) diff --git a/ci/mill-bootstrap.patch b/ci/mill-bootstrap.patch index e616918e6256..b61bdddf65ce 100644 --- a/ci/mill-bootstrap.patch +++ b/ci/mill-bootstrap.patch @@ -1,5 +1,35 @@ +diff --git a/contrib/package.mill b/contrib/package.mill +index e27aacc8c66..5f46f114336 100644 +--- a/contrib/package.mill ++++ b/contrib/package.mill +@@ -13,6 +13,7 @@ import mill.contrib.buildinfo.BuildInfo + import mill.T + import mill.api.Cross + import millbuild.* ++import mill.api.opt.* + + /** + * [[build.contrib]] contains user-contributed Mill plugins that satisfy +@@ -66,7 +67,7 @@ object `package` extends mill.Module { + + def testArgs = Task { + super.testArgs() ++ +- Seq( ++ Opts( + s"-DTEST_PLAY_VERSION_2_6=${Deps.Play_2_6.playVersion}", + s"-DTEST_PLAY_VERSION_2_7=${Deps.Play_2_7.playVersion}", + s"-DTEST_PLAY_VERSION_2_8=${Deps.Play_2_8.playVersion}", +@@ -114,7 +115,7 @@ object `package` extends mill.Module { + + def testArgs = Task { + super.testArgs() ++ +- Seq( ++ Opts( + s"-DMILL_SCOVERAGE2_VERSION=${Deps.scalacScoverage2Plugin.version}" + ) + } diff --git a/dist/package.mill b/dist/package.mill -index d9d8e2e05f1..af820b9c1d1 100644 +index d9d8e2e05f1..e8b4b6fa802 100644 --- a/dist/package.mill +++ b/dist/package.mill @@ -13,6 +13,7 @@ import scala.util.Using @@ -10,30 +40,21 @@ index d9d8e2e05f1..af820b9c1d1 100644 trait DistModule extends Module { // All modules that we want to aggregate as part of this `dev` assembly. -@@ -173,7 +174,7 @@ object `package` extends MillJavaModule with DistModule { - - def localBinName = "mill-assembly.jar" - -- private def millClientJvmArgs = Seq( -+ private def millClientJvmArgs = Opts( - // Avoid reserving a lot of memory for the client, as the client only forward information - "-Xmx128m" - ) -@@ -206,7 +207,7 @@ object `package` extends MillJavaModule with DistModule { - mainClass = mainClass().get, - shellClassPath = classpath, - cmdClassPath = Seq(classpathJar.toString()), -- jvmArgs = jvmArgs -+ jvmArgs = jvmArgs.toStringSeq - ) - - os.write(outputPath, script) +@@ -182,7 +183,7 @@ object `package` extends MillJavaModule with DistModule { + val isWin = scala.util.Properties.isWin + val outputPath = Task.dest / (if (isWin) "run.bat" else "run") + +- val launcherForkArgs = testArgs() ++ val launcherForkArgs = testArgs().toStringSeq + val (millArgs, otherArgs) = + launcherForkArgs.partition(arg => + arg.startsWith("-DMILL") && !arg.startsWith("-DMILL_VERSION") @@ -220,7 +221,7 @@ object `package` extends MillJavaModule with DistModule { mill.scalalib.Assembly.Rule.ExcludePattern("mill/local-test-overrides/.*") ) - def forkArgs = millClientJvmArgs ++ Seq( -+ def forkArgs = millClientJvmArgs ++ Opts( ++ def forkArgs = Opts(millClientJvmArgs) ++ Opts( // Workaround for Zinc/JNA bug // https://github.com/sbt/sbt/blame/6718803ee6023ab041b045a6988fafcfae9d15b5/main/src/main/scala/sbt/Main.scala#L130 "-Djna.nosys=true" @@ -81,7 +102,7 @@ index 89262ef2b35..4afac12dd18 100644 } def scriptsModules: Seq[BootstrapScriptModule] = Seq(millSh, millBat) diff --git a/example/package.mill b/example/package.mill -index e4e29b18b5e..2f5e02d302e 100644 +index a8c10b9c31a..64eaae4b8a3 100644 --- a/example/package.mill +++ b/example/package.mill @@ -14,6 +14,7 @@ import mill.T @@ -193,8 +214,31 @@ index cd35e6d0763..870b0b99f39 100644 s"-Dmill.integration.coursier-version=${Deps.coursier.dep.versionConstraint.asString}" ) } +diff --git a/libs/androidlib/package.mill b/libs/androidlib/package.mill +index fc386b7efd2..e8b3ecf27c0 100644 +--- a/libs/androidlib/package.mill ++++ b/libs/androidlib/package.mill +@@ -5,6 +5,7 @@ import mill.* + import mill.contrib.buildinfo.BuildInfo + import mill.javalib.* + import millbuild.* ++import mill.api.opt.* + + // TODO when android hardcoded versions are fixed, generate a build info + // TODO change MillPublishScalaModule to MillStableScalaModule after mill version when androidlib is stable and released. +@@ -56,8 +57,8 @@ object `package` extends MillPublishScalaModule with BuildInfo { + + trait MillAndroidModule extends MillPublishScalaModule { + override def javacOptions = super.javacOptions() ++ { +- val release = Seq("-source", "1.8", "-target", "1.8") +- release ++ Seq("-encoding", "UTF-8", "-deprecation") ++ val release = Opts("-source", "1.8", "-target", "1.8") ++ release ++ Opts("-encoding", "UTF-8", "-deprecation") + } + + override def repositoriesTask = Task.Anon { diff --git a/libs/javalib/package.mill b/libs/javalib/package.mill -index 7ed81bc6843..c580c7fc5f1 100644 +index 45c676ffc4b..a751c5f0995 100644 --- a/libs/javalib/package.mill +++ b/libs/javalib/package.mill @@ -15,6 +15,7 @@ import mill.contrib.buildinfo.BuildInfo @@ -252,7 +296,7 @@ index 80fdd82d16c..0b10e69157c 100644 s"-DMILL_SCALA_2_13_VERSION=${Deps.scala2Version}", s"-DMILL_SCALA_2_12_VERSION=${Deps.workerScalaVersion212}", diff --git a/mill-build/src/millbuild/MillJavaModule.scala b/mill-build/src/millbuild/MillJavaModule.scala -index f82f0d10ec5..089349df5c5 100644 +index f82f0d10ec5..deb7e049a01 100644 --- a/mill-build/src/millbuild/MillJavaModule.scala +++ b/mill-build/src/millbuild/MillJavaModule.scala @@ -8,6 +8,7 @@ import mill.T @@ -263,6 +307,24 @@ index f82f0d10ec5..089349df5c5 100644 import java.io.File +@@ -15,13 +16,13 @@ import scala.util.Properties + + trait MillJavaModule extends JavaModule { + +- def testArgs: T[Seq[String]] = Task { ++ def testArgs: T[Opts] = Task { + // Workaround for Zinc/JNA bug + // https://github.com/sbt/sbt/blame/6718803ee6023ab041b045a6988fafcfae9d15b5/main/src/main/scala/sbt/Main.scala#L130 +- val jnaArgs = Seq("-Djna.nosys=true") ++ val jnaArgs = Opts("-Djna.nosys=true") + val userLang = +- if (Properties.isMac || Properties.isWin) Seq("-Duser.language=en") +- else Nil ++ if (Properties.isMac || Properties.isWin) Opts("-Duser.language=en") ++ else Opts() + jnaArgs ++ userLang + } + @@ -59,13 +60,13 @@ trait MillJavaModule extends JavaModule { } @@ -280,7 +342,19 @@ index f82f0d10ec5..089349df5c5 100644 Seq("MILL_LOCAL_TEST_REPO" -> localRepos) } -@@ -107,14 +108,14 @@ trait MillJavaModule extends JavaModule { +@@ -98,23 +99,23 @@ trait MillJavaModule extends JavaModule { + Task.env.get("CI").contains("1") + } + +- def ciJavacOptions: Task[Seq[String]] = Task { +- if (isCI()) Seq( ++ def ciJavacOptions: Task[Opts] = Task { ++ if (isCI()) Opts( + // When in CI make the warnings fatal + "-Werror" + ) +- else Nil ++ else Opts() } override def javacOptions = Task { @@ -318,8 +392,84 @@ index 342747153c6..6730228fe51 100644 } object MillPublishJavaModule { +diff --git a/mill-build/src/millbuild/MillScalaModule.scala b/mill-build/src/millbuild/MillScalaModule.scala +index fcd2fdcda0b..6ace3435eb4 100644 +--- a/mill-build/src/millbuild/MillScalaModule.scala ++++ b/mill-build/src/millbuild/MillScalaModule.scala +@@ -5,6 +5,7 @@ import mill.scalalib.* + import mill.javalib.api.JvmWorkerUtil + import mill.api.BuildCtx + import com.goyeau.mill.scalafix.ScalafixModule ++import mill.api.opt.* + + /** + * Some custom scala settings and test convenience +@@ -24,19 +25,19 @@ trait MillScalaModule extends ScalaModule with MillJavaModule with ScalafixModul + + def isScala3: T[Boolean] = Task { JvmWorkerUtil.isScala3(scalaVersion()) } + +- def ciScalacOptions: T[Seq[String]] = Task { ++ def ciScalacOptions: T[Opts] = Task { + if (isCI()) { + // Turn warnings into errors on CI +- if (isScala3()) Seq("-Werror") else Seq("-Xfatal-warnings") +- } else Nil ++ if (isScala3()) Opts("-Werror") else Opts("-Xfatal-warnings") ++ } else Opts() + } + + def scalacOptions = +- super.scalacOptions() ++ Seq( ++ super.scalacOptions() ++ Opts( + "-deprecation", + "-feature" + ) ++ ciScalacOptions() ++ ( +- if (isScala3()) Seq( ++ if (isScala3()) Opts( + "-explain-cyclic", + "-Wunused:all", + "-Wconf:msg=An existential type that came from a Scala-2 classfile:silent", +@@ -53,7 +54,7 @@ trait MillScalaModule extends ScalaModule with MillJavaModule with ScalafixModul + // "-Wimplausible-patterns", + // "-rewrite", "-source", "3.7-migration" + ) +- else Seq( ++ else Opts( + "-P:acyclic:force", + "-Xlint:unused", + "-Xlint:adapted-args", +@@ -90,7 +91,7 @@ trait MillScalaModule extends ScalaModule with MillJavaModule with ScalafixModul + trait MillScalaTests extends ScalaTests with MillJavaModule with MillBaseTestsModule + with ScalafixModule { + def scalafixConfig = Task { Some(BuildCtx.workspaceRoot / ".scalafix.conf") } +- def forkArgs = super.forkArgs() ++ outer.testArgs() ++ def forkArgs = super.forkArgs() ++ Opts(outer.testArgs()) + def moduleDeps = outer.testModuleDeps + def mvnDeps = super.mvnDeps() ++ outer.testMvnDeps() + def forkEnv = super.forkEnv() ++ outer.testForkEnv() +diff --git a/runner/autooverride/package.mill b/runner/autooverride/package.mill +index 959d0d64e60..8967fbb3561 100644 +--- a/runner/autooverride/package.mill ++++ b/runner/autooverride/package.mill +@@ -3,6 +3,7 @@ package build.runner.autooverride + import mill.* + import mill.scalalib.* + import millbuild.* ++import mill.api.opt.* + + /** + * AutoOverride compiler plugin for Scala 3 that automatically implements +@@ -40,7 +41,7 @@ object `package` extends Module { + millbuild.Deps.TestDeps.utest + ) + +- def scalacOptions = super.scalacOptions() ++ Seq( ++ def scalacOptions = super.scalacOptions() ++ Opts( + s"-Xplugin:${plugin.jar().path}", + s"-Xplugin-require:auto-override" + ) diff --git a/runner/bsp/package.mill b/runner/bsp/package.mill -index 5c511891e2d..0cdae63e94e 100644 +index 5c511891e2d..0d7cd65b780 100644 --- a/runner/bsp/package.mill +++ b/runner/bsp/package.mill @@ -4,6 +4,7 @@ import mill._ @@ -330,7 +480,7 @@ index 5c511891e2d..0cdae63e94e 100644 object `package` extends MillPublishScalaModule with BuildInfo { def compileModuleDeps = Seq(build.libs.javalib) -@@ -24,7 +25,7 @@ object `package` extends MillPublishScalaModule with BuildInfo { +@@ -24,13 +25,13 @@ object `package` extends MillPublishScalaModule with BuildInfo { override lazy val test: MillScalaTests = new Test {} trait Test extends MillScalaTests { @@ -339,6 +489,13 @@ index 5c511891e2d..0cdae63e94e 100644 // We try to fetch this dependency with coursier in the tests worker.publishLocalCached() super.forkEnv() + } + +- def forkArgs = super.forkArgs() ++ Seq(s"-DBSP4J_VERSION=${Deps.bsp4j.version}") ++ def forkArgs = super.forkArgs() ++ Opts(s"-DBSP4J_VERSION=${Deps.bsp4j.version}") + } + + object worker extends MillPublishScalaModule { diff --git a/runner/codesig/package.mill b/runner/codesig/package.mill index c10f27f0ec5..579df2817e2 100644 --- a/runner/codesig/package.mill From 399a3a9d4140fddafe599c79d9269be1799e5928 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 26 Nov 2025 13:04:48 +0100 Subject: [PATCH 60/67] Fix more tests --- example/thirdparty/commons-io/build.mill | 1 + .../CrossprojectCrossVersionBaseModule.scala | 2 +- .../crossproject-cross-version/build.mill | 20 +++++++++---------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/example/thirdparty/commons-io/build.mill b/example/thirdparty/commons-io/build.mill index 4f6812fda255..3d76730c0b2d 100644 --- a/example/thirdparty/commons-io/build.mill +++ b/example/thirdparty/commons-io/build.mill @@ -3,6 +3,7 @@ package build import mill.*, javalib.*, publish.* +import mill.api.opt.* import contrib.jmh.JmhModule object `package` extends PublishModule, MavenModule { diff --git a/libs/init/sbt/test/resources/expected/crossproject-cross-version/mill-build/src/CrossprojectCrossVersionBaseModule.scala b/libs/init/sbt/test/resources/expected/crossproject-cross-version/mill-build/src/CrossprojectCrossVersionBaseModule.scala index 37ee87d9d0c6..3746db9f9faf 100644 --- a/libs/init/sbt/test/resources/expected/crossproject-cross-version/mill-build/src/CrossprojectCrossVersionBaseModule.scala +++ b/libs/init/sbt/test/resources/expected/crossproject-cross-version/mill-build/src/CrossprojectCrossVersionBaseModule.scala @@ -20,7 +20,7 @@ trait CrossprojectCrossVersionBaseModule ) case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") case "3.7.1" => Opts("-Wunused") - case _ => Nil + case _ => Opts() }) def publishVersion = "0.1.0-SNAPSHOT" diff --git a/libs/init/sbt/test/resources/expected/with-args/crossproject-cross-version/build.mill b/libs/init/sbt/test/resources/expected/with-args/crossproject-cross-version/build.mill index 8e109d7178ee..171dfd663500 100644 --- a/libs/init/sbt/test/resources/expected/with-args/crossproject-cross-version/build.mill +++ b/libs/init/sbt/test/resources/expected/with-args/crossproject-cross-version/build.mill @@ -38,7 +38,7 @@ object `package` extends Module { case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") case "3.7.1" => Opts("-Wunused") - case _ => Nil + case _ => Opts() }) def pomSettings = PomSettings( @@ -74,7 +74,7 @@ object `package` extends Module { case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") case "3.7.1" => Opts("-Wunused") - case _ => Nil + case _ => Opts() }) def pomSettings = PomSettings( @@ -113,7 +113,7 @@ object `package` extends Module { case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") case "3.7.1" => Opts("-Wunused") - case _ => Nil + case _ => Opts() }) def pomSettings = PomSettings( @@ -156,7 +156,7 @@ object `package` extends Module { case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") case "3.7.1" => Opts("-Wunused") - case _ => Nil + case _ => Opts() }) def pomSettings = PomSettings( @@ -194,7 +194,7 @@ object `package` extends Module { case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") case "3.7.1" => Opts("-Wunused") - case _ => Nil + case _ => Opts() }) def pomSettings = PomSettings( @@ -233,7 +233,7 @@ object `package` extends Module { case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") case "3.7.1" => Opts("-Wunused") - case _ => Nil + case _ => Opts() }) def pomSettings = PomSettings( @@ -268,7 +268,7 @@ object `package` extends Module { case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") case "3.7.1" => Opts("-Wunused") - case _ => Nil + case _ => Opts() }) def pomSettings = PomSettings( @@ -309,7 +309,7 @@ object `package` extends Module { case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") case "3.7.1" => Opts("-Wunused") - case _ => Nil + case _ => Opts() }) def pomSettings = PomSettings( @@ -345,7 +345,7 @@ object `package` extends Module { case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") case "3.7.1" => Opts("-Wunused") - case _ => Nil + case _ => Opts() }) def pomSettings = PomSettings( @@ -384,7 +384,7 @@ object `package` extends Module { case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") case "3.7.1" => Opts("-Wunused") - case _ => Nil + case _ => Opts() }) def pomSettings = PomSettings( From b4598fdfe784ed870613cae54a4b07425266f042 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 16:23:54 +0000 Subject: [PATCH 61/67] [autofix.ci] apply automated fixes --- libs/javalib/src/mill/javalib/NativeImageModule.scala | 1 - libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala | 2 +- .../javalib/src/mill/javalib/spring/boot/SpringBootModule.scala | 1 + runner/meta/src/mill/meta/MillBuildRootModule.scala | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/javalib/src/mill/javalib/NativeImageModule.scala b/libs/javalib/src/mill/javalib/NativeImageModule.scala index f5b294cebb8f..ed65b4530918 100644 --- a/libs/javalib/src/mill/javalib/NativeImageModule.scala +++ b/libs/javalib/src/mill/javalib/NativeImageModule.scala @@ -1,7 +1,6 @@ package mill.javalib import mill.* -import mill.api.BuildCtx import mill.api.opt.* import mill.constants.{DaemonFiles, Util} import coursier.core.VariantSelector.ConfigurationBased diff --git a/libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala b/libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala index ed96f47f3477..9943bed77b54 100644 --- a/libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala +++ b/libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala @@ -3,7 +3,7 @@ package mill.javalib.bsp import java.nio.file.Path import mill.api.daemon.internal.bsp.BspJavaModuleApi import mill.Task -import mill.api.daemon.internal.{EvaluatorApi, OptsApi, TaskApi, internal} +import mill.api.daemon.internal.{EvaluatorApi, OptsApi, internal} import mill.api.ModuleCtx import mill.api.opt.* import mill.javalib.{JavaModule, SemanticDbJavaModule} diff --git a/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala b/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala index 8fdbd4cb64bb..3548f27729a7 100644 --- a/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala +++ b/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala @@ -180,6 +180,7 @@ trait SpringBootModule extends JavaModule { * parent module as a native GraalVM application, provided the [[outer.springBootProcessAOT]] works. */ trait NativeSpringBootBuildModule extends SpringBootOptimisedBuildModule, NativeImageModule { + /** * Uses the configuration path from both [[outer.springBootProcessAOT]] and * [[nativeMvnDepsMetadata]] diff --git a/runner/meta/src/mill/meta/MillBuildRootModule.scala b/runner/meta/src/mill/meta/MillBuildRootModule.scala index 72c0e08852f2..dc9b4cc0c27c 100644 --- a/runner/meta/src/mill/meta/MillBuildRootModule.scala +++ b/runner/meta/src/mill/meta/MillBuildRootModule.scala @@ -1,7 +1,7 @@ package mill.meta import java.nio.file.Path -import mill.api.{BuildCtx, Discover, PathRef, Result, Task} +import mill.api.{BuildCtx, Result} import mill.* import mill.api.opt.* import mill.api.daemon.internal.internal From 24af5e837ffca00b4ff6c3affa07a23ae7148e1e Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 9 Dec 2025 21:05:20 +0100 Subject: [PATCH 62/67] fix --- .../javalib/src/mill/javalib/spring/boot/SpringBootModule.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala b/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala index 3548f27729a7..eb272d259c29 100644 --- a/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala +++ b/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala @@ -188,7 +188,7 @@ trait SpringBootModule extends JavaModule { override def nativeImageOptions: Task.Simple[Opts] = Task { val configurationsPath = outer.springBootProcessAOT().path / "resources/META-INF" super.nativeImageOptions() ++ Opts( - Opt("--configurations-path", configurationsPath) + OptGroup("--configurations-path", configurationsPath) ) } } From 64840f8192dfdb5e34ee62eb3f899e06017f9c2c Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Tue, 9 Dec 2025 21:23:54 +0100 Subject: [PATCH 63/67] fix test --- example/scalalib/config/4-linting/build.mill | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/example/scalalib/config/4-linting/build.mill b/example/scalalib/config/4-linting/build.mill index da807d567d0d..d5931fac4807 100644 --- a/example/scalalib/config/4-linting/build.mill +++ b/example/scalalib/config/4-linting/build.mill @@ -49,7 +49,8 @@ object Foo { /** Usage > ./mill __.fix # mill-scalafix not compatible with new Opts class -error: fix java.lang.ClassCastException: class mill.api.opt.Opts cannot be cast to class scala.collection.immutable.Seq ... +error: fix +error: java.lang.ClassCastException: class mill.api.opt.Opts cannot be cast to class scala.collection.immutable.Seq ... */ //// From 89e07d22703ad63f4021caa840a7738929a6e3c2 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 10 Dec 2025 09:56:39 +0100 Subject: [PATCH 64/67] fix test --- libs/javalib/src/mill/javalib/NativeImageModule.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libs/javalib/src/mill/javalib/NativeImageModule.scala b/libs/javalib/src/mill/javalib/NativeImageModule.scala index ed65b4530918..94ade842da86 100644 --- a/libs/javalib/src/mill/javalib/NativeImageModule.scala +++ b/libs/javalib/src/mill/javalib/NativeImageModule.scala @@ -106,9 +106,10 @@ trait NativeImageModule extends WithJvmWorkerModule, OfflineSupportModule { * Additional options for the `native-image` Tool. */ def nativeImageOptions: T[Opts] = Task { - Opts(nativeMvnDepsMetadata().map(md => - Opt("--configurations-path", md.path / "META-INF") - )) + nativeMvnDepsMetadata() match { + case Some(md) => Opts(OptGroup("--configurations-path", md.path / "META-INF")) + case _ => Opts() + } } /** From d495d6f56bb1c804375c9e0f9b8e1353cee10b52 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 10 Dec 2025 10:03:46 +0100 Subject: [PATCH 65/67] fix --- example/kotlinlib/web/9-spring-boot-aot/build.mill | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/example/kotlinlib/web/9-spring-boot-aot/build.mill b/example/kotlinlib/web/9-spring-boot-aot/build.mill index ed5045b8a32d..c2be25c93781 100644 --- a/example/kotlinlib/web/9-spring-boot-aot/build.mill +++ b/example/kotlinlib/web/9-spring-boot-aot/build.mill @@ -1,6 +1,7 @@ package build import mill.* +import mill.api.opt.* import mill.kotlinlib.* import mill.javalib.spring.boot.SpringBootModule import mill.javalib.TestModule.{Junit4, Junit5} @@ -13,7 +14,7 @@ object `package` extends SpringBootModule, KotlinModule { outer => override def kotlinVersion = "2.2.21" override def artifactName: T[String] = "spring-boot-native-demo" - override def kotlincOptions: T[Seq[String]] = super.kotlincOptions() ++ Seq( + override def kotlincOptions: T[Opts] = super.kotlincOptions() ++ Opts( "-jvm-target", "17", "-Xjsr305=strict", From 2e31c444b700902071f5452bc12b16e92db90b08 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 10 Dec 2025 10:36:59 +0100 Subject: [PATCH 66/67] fix test --- .../ide/bsp-server/resources/snapshots/logging | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/integration/ide/bsp-server/resources/snapshots/logging b/integration/ide/bsp-server/resources/snapshots/logging index 32d101d8be60..f167fd75f7ec 100644 --- a/integration/ide/bsp-server/resources/snapshots/logging +++ b/integration/ide/bsp-server/resources/snapshots/logging @@ -3,24 +3,10 @@ bsp] BSP server started 1-buildInitialize] Entered buildInitialize 1-buildInitialize] Got client semanticdbVersion: * Enabling SemanticDB support. 1-buildInitialize] buildInitialize took * msec -<<<<<<< HEAD -bsp-init-mill-build/build.mill-60] compiling * Scala sources to * ... -bsp-init-mill-build/build.mill-60] done compiling -bsp-init-build.mill-60] compiling * Scala sources to * ... -bsp-init-build.mill-60] [warn] build.mill:108:18 -bsp-init-build.mill-60] def theThing = thing -bsp-init-build.mill-60] ^^^^^ -bsp-init-build.mill-60] method thing in object diag is deprecated since 0.0.1: deprecated -bsp-init-build.mill-60] [warn] one warning found -bsp-init-build.mill-60] done compiling -bsp-init-113] compiling * Scala source to * ... -bsp-init-113] done compiling -bsp-init] BSP disabled for target file:///workspace/dependsOnSkipped because of its dependencies file:///workspace/skipped -======= bsp-init-mill-build/build.mill-61] compiling * Scala sources to * ... bsp-init-mill-build/build.mill-61] done compiling bsp-init-build.mill-61] compiling * Scala sources to * ... -bsp-init-build.mill-61] [warn] build.mill:107:18 +bsp-init-build.mill-61] [warn] build.mill:108:18 bsp-init-build.mill-61] def theThing = thing bsp-init-build.mill-61] ^^^^^ bsp-init-build.mill-61] method thing in object diag is deprecated since 0.0.1: deprecated @@ -30,7 +16,6 @@ bsp-init-build.mill-61] done compiling bsp-init-114] compiling * Scala source to * ... bsp-init-114] done compiling bsp-init] [warn] BSP disabled for target file:///workspace/dependsOnSkipped because of its dependencies file:///workspace/skipped ->>>>>>> origin/main bsp-init] BSP disabled for target file:///workspace/skipped via BspModuleApi#enableBsp bsp-init] SNAPSHOT 2-workspaceBuildTargets] Entered workspaceBuildTargets From 48db696e4458f30e7e6d3937d55eca080c1c3cbb Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 10 Dec 2025 13:21:54 +0100 Subject: [PATCH 67/67] Add OptMap type alias for Map[String, Opt] and some convenience --- ci/mill-bootstrap.patch | 4 +-- core/api/src/mill/api/opt/OptMap.scala | 29 +++++++++++++++++++ .../androidlib/hilt/AndroidHiltSupport.scala | 12 ++++---- .../javalib/src/mill/javalib/JavaModule.scala | 2 +- libs/javalib/src/mill/javalib/RunModule.scala | 10 +++---- .../javalib/src/mill/javalib/TestModule.scala | 6 ++-- .../src/mill/javalib/bsp/BspJavaModule.scala | 2 +- .../src/mill/javalib/bsp/BspRunModule.scala | 4 +-- .../src/mill/kotlinlib/ksp/KspModule.scala | 4 +-- .../src/mill/scalalib/ScalaModule.scala | 4 +-- .../scalanativelib/ScalaNativeModule.scala | 6 ++-- .../mill/bsp/worker/MillJvmBuildServer.scala | 5 ++-- 12 files changed, 59 insertions(+), 29 deletions(-) create mode 100644 core/api/src/mill/api/opt/OptMap.scala diff --git a/ci/mill-bootstrap.patch b/ci/mill-bootstrap.patch index b61bdddf65ce..04de08f24853 100644 --- a/ci/mill-bootstrap.patch +++ b/ci/mill-bootstrap.patch @@ -63,7 +63,7 @@ index d9d8e2e05f1..e8b4b6fa802 100644 os.call( cmd = (launcher().path.toString, rest), - env = forkEnv() ++ build.dist.localTestOverridesEnv(), -+ env = (forkEnv() ++ build.dist.localTestOverridesEnv()).view.mapValues(_.toString).toMap, ++ env = (forkEnv() ++ build.dist.localTestOverridesEnv()).toStringMap, cwd = wd, stdin = os.Inherit, stdout = os.Inherit, @@ -161,7 +161,7 @@ index cd35e6d0763..870b0b99f39 100644 testForkGrouping(), jvmWorker().testrunnerEntrypointClasspath(), - allForkEnv() ++ Option.when(useSharedOut) { "MILL_TEST_SHARED_OUTPUT_DIR" -> "1" }, -+ allForkEnv().view.mapValues(_.toString).toMap ++ ++ allForkEnv().toStringMap ++ + Option.when(useSharedOut) { "MILL_TEST_SHARED_OUTPUT_DIR" -> "1" }, testSandboxWorkingDir = !useSharedOut, if (useSharedOut) sharedOutFolder else forkWorkingDir(), diff --git a/core/api/src/mill/api/opt/OptMap.scala b/core/api/src/mill/api/opt/OptMap.scala new file mode 100644 index 000000000000..980f7851f5d7 --- /dev/null +++ b/core/api/src/mill/api/opt/OptMap.scala @@ -0,0 +1,29 @@ +package mill.api.opt + +import mill.api.daemon.internal.OptApi + +type OptMap = Map[String, Opt] + +extension (map: Map[String, OptApi]) { + def toStringMap: Map[String, String] = map.view.mapValues(_.toString()).toMap +} + +object OptMap { + + def apply(elems: (String, String | os.Path | Opt)*): OptMap = Map.from( + elems + .map { (k, v) => + ( + k, + v match { + case o: Opt => o + case o: (String | os.Path) => Opt(o) + } + ) + } + ) + +// given jsonReadWriter: upickle.ReadWriter[OptMap] = +// upickle.readwriter[Map[String, Opt]].bimap(_.map, OptMap(_)) + +} diff --git a/libs/androidlib/src/mill/androidlib/hilt/AndroidHiltSupport.scala b/libs/androidlib/src/mill/androidlib/hilt/AndroidHiltSupport.scala index 7186bf86c154..ec78c743b8d8 100644 --- a/libs/androidlib/src/mill/androidlib/hilt/AndroidHiltSupport.scala +++ b/libs/androidlib/src/mill/androidlib/hilt/AndroidHiltSupport.scala @@ -25,12 +25,12 @@ import mill.{T, Task} @mill.api.experimental trait AndroidHiltSupport extends KspModule, AndroidKotlinModule { - override def kspProcessorOptions: T[Map[String, Opt]] = Task { - super.kspProcessorOptions() ++ Map( - "dagger.fastInit" -> opt"enabled", - "dagger.hilt.android.internal.disableAndroidSuperclassValidation" -> opt"true", - "dagger.hilt.android.internal.projectType" -> opt"APP", - "dagger.hilt.internal.useAggregatingRootProcessor" -> opt"true" + override def kspProcessorOptions: T[OptMap] = Task { + super.kspProcessorOptions() ++ OptMap( + "dagger.fastInit" -> "enabled", + "dagger.hilt.android.internal.disableAndroidSuperclassValidation" -> "true", + "dagger.hilt.android.internal.projectType" -> "APP", + "dagger.hilt.internal.useAggregatingRootProcessor" -> "true" ) } diff --git a/libs/javalib/src/mill/javalib/JavaModule.scala b/libs/javalib/src/mill/javalib/JavaModule.scala index 3399ada40216..31d5b906b89b 100644 --- a/libs/javalib/src/mill/javalib/JavaModule.scala +++ b/libs/javalib/src/mill/javalib/JavaModule.scala @@ -1277,7 +1277,7 @@ trait JavaModule val cmd = Seq(Jvm.jdkTool("jshell", javaHome().map(_.path))) ++ jshellArgs os.call( cmd = cmd, - env = allForkEnv().view.mapValues(_.toString).toMap, + env = allForkEnv().toStringMap, cwd = forkWorkingDir(), stdin = os.Inherit, stdout = os.Inherit diff --git a/libs/javalib/src/mill/javalib/RunModule.scala b/libs/javalib/src/mill/javalib/RunModule.scala index 805387b84e53..e9af66299397 100644 --- a/libs/javalib/src/mill/javalib/RunModule.scala +++ b/libs/javalib/src/mill/javalib/RunModule.scala @@ -37,16 +37,16 @@ trait RunModule extends WithJvmWorkerModule with RunModuleApi { /** * Any environment variables you want to pass to the forked JVM. */ - def forkEnv: T[Map[String, Opt]] = Task { Map.empty[String, Opt] } + def forkEnv: T[OptMap] = Task { OptMap() } /** * Environment variables to pass to the forked JVM. * * Includes [[forkEnv]] and the variables defined by Mill itself. */ - def allForkEnv: T[Map[String, Opt]] = Task { - forkEnv() ++ Map( - EnvVars.MILL_WORKSPACE_ROOT -> Opt(BuildCtx.workspaceRoot) + def allForkEnv: T[OptMap] = Task { + forkEnv() ++ OptMap( + EnvVars.MILL_WORKSPACE_ROOT -> BuildCtx.workspaceRoot ) } @@ -170,7 +170,7 @@ trait RunModule extends WithJvmWorkerModule with RunModuleApi { finalMainClassOpt(), runClasspath().map(_.path), forkArgs().toStringSeq, - allForkEnv().view.mapValues(_.toString()).toMap, + allForkEnv().toStringMap, runUseArgsFile(), javaHome().map(_.path), propagateEnv() diff --git a/libs/javalib/src/mill/javalib/TestModule.scala b/libs/javalib/src/mill/javalib/TestModule.scala index 5ecd1d709607..b2d49f53f9ca 100644 --- a/libs/javalib/src/mill/javalib/TestModule.scala +++ b/libs/javalib/src/mill/javalib/TestModule.scala @@ -226,8 +226,8 @@ trait TestModule */ def testSandboxWorkingDir: T[Boolean] = true - override def allForkEnv: T[Map[String, Opt]] = Task { - super.allForkEnv() ++ Map( + override def allForkEnv: T[OptMap] = Task { + super.allForkEnv() ++ OptMap( EnvVars.MILL_TEST_RESOURCE_DIR -> Opt.mkPath(resources().map(_.path), sep = ";") ) } @@ -252,7 +252,7 @@ trait TestModule args(), testForkGrouping(), jvmWorker().testrunnerEntrypointClasspath(), - allForkEnv().view.mapValues(_.toString()).toMap, + allForkEnv().toStringMap, testSandboxWorkingDir(), forkWorkingDir(), testReportXml(), diff --git a/libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala b/libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala index 9943bed77b54..847f67abc39d 100644 --- a/libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala +++ b/libs/javalib/src/mill/javalib/bsp/BspJavaModule.scala @@ -149,7 +149,7 @@ trait BspJavaModule extends mill.api.Module with BspJavaModuleApi { : Task.Simple[( classes: Seq[String], forkArgs: Opts, - forkEnv: Map[String, Opt] + forkEnv: OptMap )] = Task { (jm.allLocalMainClasses(), jm.forkArgs(), jm.allForkEnv()) diff --git a/libs/javalib/src/mill/javalib/bsp/BspRunModule.scala b/libs/javalib/src/mill/javalib/bsp/BspRunModule.scala index 726d31b00947..e62383e77ba3 100644 --- a/libs/javalib/src/mill/javalib/bsp/BspRunModule.scala +++ b/libs/javalib/src/mill/javalib/bsp/BspRunModule.scala @@ -23,7 +23,7 @@ private[mill] trait BspRunModule(runModule: RunModule) extends mill.api.Module { runClasspath: Seq[Path], forkArgs: Opts, forkWorkingDir: Path, - forkEnv: Map[String, Opt], + forkEnv: OptMap, mainClass: Option[String], localMainClasses: Seq[String] )] = @@ -42,7 +42,7 @@ private[mill] trait BspRunModule(runModule: RunModule) extends mill.api.Module { runClasspath: Seq[Path], forkArgs: Opts, forkWorkingDir: Path, - forkEnv: Map[String, Opt], + forkEnv: OptMap, mainClass: Option[String], testEnvVars: Option[( mainClass: String, diff --git a/libs/kotlinlib/src/mill/kotlinlib/ksp/KspModule.scala b/libs/kotlinlib/src/mill/kotlinlib/ksp/KspModule.scala index 1fce4d825106..633e32e5833a 100644 --- a/libs/kotlinlib/src/mill/kotlinlib/ksp/KspModule.scala +++ b/libs/kotlinlib/src/mill/kotlinlib/ksp/KspModule.scala @@ -104,8 +104,8 @@ trait KspModule extends KotlinModule { outer => /** * Processor options to be passed to KSP. */ - def kspProcessorOptions: T[Map[String, Opt]] = Task { - Map.empty[String, Opt] + def kspProcessorOptions: T[OptMap] = Task { + OptMap() } /** diff --git a/libs/scalalib/src/mill/scalalib/ScalaModule.scala b/libs/scalalib/src/mill/scalalib/ScalaModule.scala index aba65639de69..b40b2aea0c84 100644 --- a/libs/scalalib/src/mill/scalalib/ScalaModule.scala +++ b/libs/scalalib/src/mill/scalalib/ScalaModule.scala @@ -446,7 +446,7 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase "scala.tools.nsc.MainGenericRunner", classPath = runClasspath().map(_.path) ++ scalaConsoleClasspath().map(_.path), jvmArgs = forkArgs().toStringSeq, - env = allForkEnv().view.mapValues(_.toString()).toMap, + env = allForkEnv().toStringMap, mainArgs = Seq(useJavaCp) ++ consoleScalacOptions().filterNot(Set(useJavaCp)) ++ args.value, cwd = forkWorkingDir(), @@ -527,7 +527,7 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase mainClass = mainClass, classPath = ammoniteReplClasspath().map(_.path).toVector, jvmArgs = forkArgs().toStringSeq, - env = allForkEnv().view.mapValues(_.toString()).toMap, + env = allForkEnv().toStringMap, mainArgs = replOptions, cwd = forkWorkingDir(), stdin = os.Inherit, diff --git a/libs/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala b/libs/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala index 16a73ff54530..299c55d31a5b 100644 --- a/libs/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala +++ b/libs/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala @@ -390,7 +390,7 @@ trait ScalaNativeModule extends ScalaModule with ScalaNativeModuleApi { outer => mainClassDefault = finalMainClassOpt(), nativeExe = nativeLink(), forkArgsDefault = forkArgs().toStringSeq, - forkEnvDefault = allForkEnv().view.mapValues(_.toString()).toMap, + forkEnvDefault = allForkEnv().toStringMap, propagateEnvDefault = propagateEnv() ) } @@ -400,7 +400,7 @@ trait ScalaNativeModule extends ScalaModule with ScalaNativeModuleApi { outer => mainClassDefault = Right(mainClass), nativeExe = nativeLinkOtherMain(mainClass)(), forkArgsDefault = forkArgs().toStringSeq, - forkEnvDefault = allForkEnv().view.mapValues(_.toString()).toMap, + forkEnvDefault = allForkEnv().toStringMap, propagateEnvDefault = propagateEnv() ) } @@ -491,7 +491,7 @@ trait TestScalaNativeModule extends ScalaNativeModule with TestModule { val (close, framework) = withScalaNativeBridge.apply().apply(_.getFramework( nativeLink().path.toIO, - allForkEnv().view.mapValues(_.toString()).toMap, + allForkEnv().toStringMap, toWorkerApi(logLevel()), testFramework() )) diff --git a/runner/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala b/runner/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala index b9357dad0977..95a0d8612bb4 100644 --- a/runner/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala +++ b/runner/bsp/worker/src/mill/bsp/worker/MillJvmBuildServer.scala @@ -14,6 +14,7 @@ import ch.epfl.scala.bsp4j.{ JvmTestEnvironmentResult } import mill.api.daemon.internal.{JavaModuleApi, RunModuleApi, TestModuleApi} +import mill.api.opt.* import mill.bsp.worker.Utils.sanitizeUri import java.util.concurrent.CompletableFuture @@ -75,7 +76,7 @@ private trait MillJvmBuildServer extends JvmBuildServer { this: MillBuildServer testEnvVars.classpath.map(sanitizeUri).asJava, res.forkArgs.toStringSeq.asJava, res.forkWorkingDir.toString(), - res.forkEnv.view.mapValues(_.toString()).toMap.asJava + res.forkEnv.toStringMap.asJava ) item.setMainClasses(List(testEnvVars.mainClass).map(new JvmMainClass( _, @@ -111,7 +112,7 @@ private trait MillJvmBuildServer extends JvmBuildServer { this: MillBuildServer classpath.asJava, res.forkArgs.toStringSeq.asJava, res.forkWorkingDir.toString(), - res.forkEnv.view.mapValues(_.toString()).toMap.asJava + res.forkEnv.toStringMap.asJava ) val classes = res.mainClass.toList ++ res.localMainClasses