diff --git a/ci/mill-bootstrap.patch b/ci/mill-bootstrap.patch index e69de29bb2d1..04de08f24853 100644 --- a/ci/mill-bootstrap.patch +++ b/ci/mill-bootstrap.patch @@ -0,0 +1,550 @@ +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..e8b4b6fa802 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. +@@ -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 = 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" +@@ -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()).toStringMap, + 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 a8c10b9c31a..64eaae4b8a3 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().toStringMap ++ ++ 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/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 45c676ffc4b..a751c5f0995 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..deb7e049a01 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 + +@@ -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 { + } + + 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) + } + +@@ -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 { +- 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/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..0d7cd65b780 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,13 +25,13 @@ 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() + } + +- 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 ++++ 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() + } 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 0dc2e6827578..120fa5074e90 100644 --- a/contrib/scoverage/src/mill/contrib/scoverage/ScoverageModule.scala +++ b/contrib/scoverage/src/mill/contrib/scoverage/ScoverageModule.scala @@ -3,6 +3,7 @@ package mill.contrib.scoverage import coursier.Repository import mill.* import mill.api.{BuildCtx, PathRef, Result} +import mill.api.opt.* import mill.contrib.scoverage.api.ScoverageReportWorkerApi2.ReportType import mill.javalib.api.JvmWorkerUtil import mill.scalalib.{Dep, DepSyntax, JavaModule, ScalaModule} @@ -186,18 +187,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/OptsApi.scala b/core/api/daemon/src/mill/api/daemon/internal/OptsApi.scala new file mode 100644 index 000000000000..4070fafb541a --- /dev/null +++ b/core/api/daemon/src/mill/api/daemon/internal/OptsApi.scala @@ -0,0 +1,12 @@ +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/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/core/api/src/mill/api/opt/Opt.scala b/core/api/src/mill/api/opt/Opt.scala new file mode 100644 index 000000000000..ae1c4f886b4f --- /dev/null +++ b/core/api/src/mill/api/opt/Opt.scala @@ -0,0 +1,117 @@ +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 startString: String = + value.takeWhile(_.isInstanceOf[String]).collect { case s: String => s }.mkString("") + + def startsWith(prefix: String): Boolean = startString.startsWith(prefix) + + def mapStartString(rep: String => String): Opt = { + val rest = value.dropWhile(_.isInstanceOf[String]) + Opt.apply((rep(startString) +: 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 jsonReadWriter: upickle.ReadWriter[Opt] = + 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 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 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 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..c624e5a7d7d2 --- /dev/null +++ b/core/api/src/mill/api/opt/OptGroup.scala @@ -0,0 +1,75 @@ +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 { + + 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 + def headOption: Option[Opt] = value.headOption + + 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: (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 s: String => Opt(s) + case p: os.Path => Opt(p) + case o: Opt => o + } + } + 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() + +// 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)) + + given jsonReadWriter: upickle.ReadWriter[OptGroup] = + upickle.readwriter[Seq[Opt]].bimap( + _.value, + OptGroup(_*) + ) + +} 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/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..f5ff05dafc71 --- /dev/null +++ b/core/api/src/mill/api/opt/Opts.scala @@ -0,0 +1,81 @@ +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: Seq[OptGroup]) extends OptsApi { + require(value.forall(!_.isEmpty)) + + 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.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 { + @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 | 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: 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)) + } + +// given jsonReadWriter: upickle.ReadWriter[Opts] = +// upickle.readwriter[Seq[OptGroup]].bimap( +// _.value, +// Opts(_*) +// ) + + given jsonReadWriter: upickle.ReadWriter[Opts] = + upickle.readwriter[ujson.Arr].bimap( + { opts => + // We always serialize as a seq of groups + 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 => + 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/ApplicativeTests.scala b/core/api/test/src/mill/api/ApplicativeTests.scala index ea0da51eea14..5e5e617b763b 100644 --- a/core/api/test/src/mill/api/ApplicativeTests.scala +++ b/core/api/test/src/mill/api/ApplicativeTests.scala @@ -23,86 +23,118 @@ 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 +142,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 + ) +} 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..bd9cb196bab0 --- /dev/null +++ b/core/api/test/src/mill/api/opt/OptsTests.scala @@ -0,0 +1,150 @@ +package mill.api.opt + +import utest.* +import mill.api.opt.* + +class OptsTests extends TestSuite { + + val homeDir = os.root / "tmp/opts-test" + 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("--extra", opt"-Xplugin=${plugin1}") ++ OptGroup(sources1*), + Opt.mkPath(sources1, sep = ":", prefix = "-special-files=") + ) + + val expectedOpts1 = Opts( + Opt("-deprecation"), + Opt("-verbose"), + OptGroup( + Opt("--release"), + Opt("17") + ), + Opt("-Xplugin=", plugin1), + Opt("-Xplugin:", plugin1), + Opt(srcDir1), + Opt(srcDir2), + OptGroup(Opt(srcDir3), Opt(srcDir4)), + OptGroup( + Opt("--extra"), + Opt("-Xplugin=", plugin1), + Opt(srcDir1), + Opt(srcDir2) + ), + OptGroup( + Opt.mkPath(sources1, sep = ":", prefix = "-special-files=") + ) + ) + + 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()) ++ + Seq(sources1.mkString("-special-files=", ":", "")) + + 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("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) + } + 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, + "[\"-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) + 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( +// 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) +// } + } + } +} diff --git a/example/extending/plugins/2-plugin-integration-tests/build.mill b/example/extending/plugins/2-plugin-integration-tests/build.mill index 0baa49385453..f907c9bd2c72 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.* object myplugin extends ScalaModule, PublishModule { def millVersion = "1.0.6" @@ -25,8 +27,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/declarative/1-common-config/build.mill.yaml b/example/javalib/declarative/1-common-config/build.mill.yaml index 89d659e35d4d..9ffb73ce9cdc 100644 --- a/example/javalib/declarative/1-common-config/build.mill.yaml +++ b/example/javalib/declarative/1-common-config/build.mill.yaml @@ -14,6 +14,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 6d5212b0c157..3b49f2033ffe 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 @@ -37,11 +39,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 d100f958ce4e..c52f04ce4735 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/8-annotation-processors/build.mill b/example/javalib/module/8-annotation-processors/build.mill index 90d7b9653e25..3aed664328ec 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") 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/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/javalib/web/2-hello-micronaut/build.mill b/example/javalib/web/2-hello-micronaut/build.mill index 3952e8e6e14a..523c402e553f 100644 --- a/example/javalib/web/2-hello-micronaut/build.mill +++ b/example/javalib/web/2-hello-micronaut/build.mill @@ -1,5 +1,7 @@ package build + import mill.*, javalib.* +import mill.api.opt.* object `package` extends MicronautModule { def micronautVersion = "4.6.1" @@ -38,14 +40,14 @@ trait MicronautModule extends MavenModule { mvn"io.micronaut:micronaut-inject-java" ) - override def annotationProcessorsJavacOptions = super.annotationProcessorsJavacOptions() ++ Seq( + override def annotationProcessorsJavacOptions = super.annotationProcessorsJavacOptions() ++ Opts( "-Amicronaut.processing.incremental=true", "-Amicronaut.processing.group=example.micronaut", "-Amicronaut.processing.module=hello", "-Amicronaut.processing.annotations=example.micronaut.*" ) - def javacOptions = super.javacOptions() ++ Seq( + def javacOptions = super.javacOptions() ++ Opts( "-parameters" ) } diff --git a/example/javalib/web/3-todo-micronaut/build.mill b/example/javalib/web/3-todo-micronaut/build.mill index 53a8f914fbb3..8a4d362f3de4 100644 --- a/example/javalib/web/3-todo-micronaut/build.mill +++ b/example/javalib/web/3-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" @@ -53,14 +55,14 @@ trait MicronautModule extends MavenModule { mvn"io.micronaut:micronaut-inject-java" ) - override def annotationProcessorsJavacOptions = super.annotationProcessorsJavacOptions() ++ Seq( + override def annotationProcessorsJavacOptions = super.annotationProcessorsJavacOptions() ++ Opts( "-Amicronaut.processing.incremental=true", "-Amicronaut.processing.group=example.micronaut", "-Amicronaut.processing.module=todo", "-Amicronaut.processing.annotations=example.micronaut.*" ) - def javacOptions = super.javacOptions() ++ Seq( + def javacOptions = super.javacOptions() ++ Opts( "-parameters" ) } diff --git a/example/kotlinlib/declarative/5-native-image/build.mill.yaml b/example/kotlinlib/declarative/5-native-image/build.mill.yaml index bf13ed3d14cc..d8c61d63f3de 100644 --- a/example/kotlinlib/declarative/5-native-image/build.mill.yaml +++ b/example/kotlinlib/declarative/5-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 1006a229c9f1..19896e94bac9 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") } def mvnDeps = Seq( diff --git a/example/kotlinlib/module/10-dependency-injection/build.mill b/example/kotlinlib/module/10-dependency-injection/build.mill index ee691628fc66..d715504b8c73 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") // dagger doesn't play well with BtApi's incremental compilation override def kotlincUseBtApi = false @@ -27,7 +28,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 = 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 1f3599e862c0..203f844a3ea7 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 = 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..5acf64eca924 100644 --- a/example/kotlinlib/module/5-compilation-execution-flags/build.mill +++ b/example/kotlinlib/module/5-compilation-execution-flags/build.mill @@ -1,15 +1,17 @@ //// 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") + def kotlincOptions = super.kotlincOptions() ++ Opts("-Werror") } // You can pass flags to the Kotlin compiler via `kotlincOptions`. diff --git a/example/kotlinlib/module/7-resources/build.mill b/example/kotlinlib/module/7-resources/build.mill index be2ca29211ef..11abea5a28d9 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 { @@ -10,7 +12,7 @@ object foo extends KotlinModule { def otherFiles = Task.Source("other-files") def forkEnv = super.forkEnv() ++ Map( - "OTHER_FILES_DIR" -> otherFiles().path.toString + "OTHER_FILES_DIR" -> Opt(otherFiles().path) ) def 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 61778d178f5a..fca638b9fcbe 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/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/kotlinlib/testing/1-test-suite/build.mill b/example/kotlinlib/testing/1-test-suite/build.mill index 7520d01bf0ee..26a5fa4b53ba 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 7d07e73a697b..770839524543 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/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", 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/declarative/4-linting/build.mill b/example/scalalib/declarative/4-linting/build.mill index da1bc96a3835..b0415ceee8db 100644 --- a/example/scalalib/declarative/4-linting/build.mill +++ b/example/scalalib/declarative/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 +error: 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") +//// } +////} diff --git a/example/scalalib/linting/3-acyclic/build.mill b/example/scalalib/linting/3-acyclic/build.mill index 09530489db53..52c1113179cc 100644 --- a/example/scalalib/linting/3-acyclic/build.mill +++ b/example/scalalib/linting/3-acyclic/build.mill @@ -15,13 +15,15 @@ // 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/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 266d764bc6e5..a4bb8fe16d86 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/native/4-common-config/build.mill b/example/scalalib/native/4-common-config/build.mill index 69dd6a3742d9..2eeac56e7f55 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..654343707ada 100644 --- a/example/scalalib/publishing/8-native-image-libs/build.mill +++ b/example/scalalib/publishing/8-native-image-libs/build.mill @@ -1,12 +1,14 @@ //// SNIPPET:BUILD package build + import mill.*, scalalib.* +import mill.api.opt.* 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 = Seq( mvn"com.lihaoyi::scalatags:0.13.1", diff --git a/example/scalalib/spark/1-hello-spark/build.mill b/example/scalalib/spark/1-hello-spark/build.mill index b4a625ce8de5..8e3253f55f33 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" @@ -8,13 +10,13 @@ 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") 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..2220c4953313 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 = "" @@ -16,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/example/thirdparty/android-compose-samples/build.mill b/example/thirdparty/android-compose-samples/build.mill index 84d8d6c5e6f8..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" @@ -35,7 +36,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 +143,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/example/thirdparty/arrow/build.mill b/example/thirdparty/arrow/build.mill index a5ea39324d02..6d9a1dae6404 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/commons-io/build.mill b/example/thirdparty/commons-io/build.mill index 7d2705f73fa8..3d76730c0b2d 100644 --- a/example/thirdparty/commons-io/build.mill +++ b/example/thirdparty/commons-io/build.mill @@ -3,11 +3,12 @@ package build import mill.*, javalib.*, publish.* +import mill.api.opt.* 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( 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 f53ba2d53d4a..985a39957bbb 100644 --- a/example/thirdparty/mockito/build.mill +++ b/example/thirdparty/mockito/build.mill @@ -1,6 +1,8 @@ package build + import mill.*, javalib.* import mill.api.ModuleRef +import mill.api.opt.* object libraries { @@ -39,12 +41,12 @@ 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() def testFramework = "com.novocode.junit.JUnitFramework" - def testForkArgs: T[Seq[String]] = Seq() + def testForkArgs: T[Opts] = Opts() def testFilteredSources: T[Seq[os.Path]] = Task { Seq() } @@ -118,7 +120,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 +134,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 +216,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 { diff --git a/example/thirdparty/netty/build.mill b/example/thirdparty/netty/build.mill index 98a0d25ee981..f4ad93883229 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 @@ -53,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", @@ -81,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 ) 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 d7aad713b023..f9bba102cefe 100644 --- a/integration/ide/bsp-server/resources/project/build.mill +++ b/integration/ide/bsp-server/resources/project/build.mill @@ -5,7 +5,8 @@ //| - "!scripts/ignored-folder-2/negated-not-ignored.java" package build -import mill._ +import mill.* +import mill.api.opt.* // testing a simple Java module object `hello-java` extends scalalib.JavaModule { @@ -63,7 +64,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" @@ -99,7 +100,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 @@ -108,7 +109,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/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 368ecef49ffd..f167fd75f7ec 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-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 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/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) ) } 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/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..b4b503599470 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala @@ -2,14 +2,15 @@ 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, + AndroidDataBindingWorkerModule, GenerateBindingSourcesArgs, - ProcessResourcesArgs, - AndroidDataBindingWorkerModule + ProcessResourcesArgs } import mill.util.Jvm @@ -185,21 +186,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 e8e426a0f337..df3a412be1ad 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidModule.scala @@ -515,7 +515,8 @@ 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( ZincOp.CompileJava( @@ -764,7 +765,8 @@ 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..ec78c743b8d8 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,8 +25,8 @@ import mill.{T, Task} @mill.api.experimental trait AndroidHiltSupport extends KspModule, AndroidKotlinModule { - override def kspProcessorOptions: T[Map[String, String]] = Task { - super.kspProcessorOptions() ++ Map( + override def kspProcessorOptions: T[OptMap] = Task { + super.kspProcessorOptions() ++ OptMap( "dagger.fastInit" -> "enabled", "dagger.hilt.android.internal.disableAndroidSuperclassValidation" -> "true", "dagger.hilt.android.internal.projectType" -> "APP", 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/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 e9fc12debe62..89686adf1717 100644 --- a/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala +++ b/libs/init/buildgen/src/mill/main/buildgen/BuildWriter.scala @@ -101,12 +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.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.opt" for spec <- module.sequence do { import spec.* if (supertypes.isEmpty || crossConfigs.nonEmpty) wildcards += "mill" @@ -236,7 +238,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 +289,7 @@ class BuildWriter(build: BuildSpec, renderCrossValueInTask: String = "crossValue cross(_.errorProneOptions), literalize(_) ), - renderTaskAsSeq( + renderTaskAsOpts( "errorProneJavacEnableOptions", errorProneJavacEnableOptions, cross(_.errorProneJavacEnableOptions), @@ -302,7 +304,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 +606,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 _ => Opts() + |})""".stripMargin + } + } + } + } } 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..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,7 +16,10 @@ 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 + // pass true to update test data on disk + updateSnapshots: Boolean = sys.env + .getOrElse("UTEST_UPDATE_GOLDEN_TESTS", "0") + .equals("1") )(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 b696d391b9d5..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 @@ -1,6 +1,8 @@ //| mill-version: SNAPSHOT package build +import mill.api.* +import mill.api.opt.* import mill.javalib.* import millbuild.* @@ -9,7 +11,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/app/package.mill b/libs/init/gradle/test/resources/expected/gradle-7-0/app/package.mill index b854d0883228..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,5 +1,7 @@ package build.app +import mill.api.* +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 8958ea4ccb06..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 @@ -2,5 +2,7 @@ package build import mill.* +import mill.api.* +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 911aa4e895bb..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,5 +1,7 @@ package build.list +import mill.api.* +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 83a2088d2eea..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,11 +1,13 @@ package millbuild +import mill.api.* +import mill.api.opt.* 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-7-0/utilities/package.mill b/libs/init/gradle/test/resources/expected/gradle-7-0/utilities/package.mill index ed2fbd197899..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,5 +1,7 @@ package build.utilities +import mill.api.* +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 7617c99dfe83..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,5 +1,7 @@ package build.app +import mill.api.* +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 8958ea4ccb06..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 @@ -2,5 +2,7 @@ package build import mill.* +import mill.api.* +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 7f447fc382a6..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,5 +1,7 @@ package build.list +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.errorprone.* import millbuild.* @@ -9,7 +11,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 +23,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..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,11 +1,13 @@ package millbuild +import mill.api.* +import mill.api.opt.* 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..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,5 +1,7 @@ package build.utilities +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.errorprone.* import millbuild.* @@ -11,6 +13,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/app/package.mill b/libs/init/gradle/test/resources/expected/gradle-9-0-0/app/package.mill index dc8cc4b94a1f..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,5 +1,7 @@ package build.app +import mill.api.* +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 890787f10447..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 @@ -3,5 +3,7 @@ package build import mill.* +import mill.api.* +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 38af5a7dea86..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,5 +1,7 @@ package build.list +import mill.api.* +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 220ca6eb4a0c..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,11 +1,13 @@ package millbuild +import mill.api.* +import mill.api.opt.* 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/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..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,5 +1,7 @@ package millbuild +import mill.api.* +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 f05b04a567f9..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,5 +1,7 @@ package build.utilities +import mill.api.* +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 dd6d1bad9ca3..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 @@ -2,6 +2,8 @@ package build import mill.* +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.errorprone.* @@ -15,7 +17,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 +37,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 +58,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 +73,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/build.mill b/libs/init/maven/test/resources/expected/maven-samples/build.mill index c3eebeadbc6e..397d2b4624d1 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.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 48f9326cb9e0..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,5 +1,7 @@ package millbuild +import mill.api.* +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 fa2cb300e2e8..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,5 +1,7 @@ package build.`multi-module` +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* @@ -7,7 +9,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..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,5 +1,7 @@ package build.`multi-module`.server +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* @@ -7,7 +9,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..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,5 +1,7 @@ package build.`multi-module`.webapp +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* @@ -12,7 +14,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..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,5 +1,7 @@ package build.`single-module` +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import millbuild.* @@ -9,7 +11,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..472b4c5b0ba1 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.opt.* import mill.javalib.* import mill.javalib.errorprone.* import mill.javalib.publish.* @@ -8,12 +10,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 +37,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/spring-start/build.mill b/libs/init/maven/test/resources/expected/spring-start/build.mill index 097f12c07bea..75aa1eb5b290 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.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 77032e4ae11d..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 @@ -1,6 +1,8 @@ //| mill-version: SNAPSHOT package build +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* @@ -24,7 +26,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 +58,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 +110,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 +147,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..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 @@ -1,18 +1,21 @@ //| mill-version: SNAPSHOT package build +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.errorprone.* 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 +43,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/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/cross-version/build.mill b/libs/init/sbt/test/resources/expected/cross-version/build.mill index 241a215be4db..e0857503f96c 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.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* @@ -12,7 +14,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/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..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 @@ -1,5 +1,7 @@ package millbuild +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* @@ -9,16 +11,16 @@ 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 _ => Nil + case "2.13.14" => Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") + case _ => Opts() }) def publishVersion = "0.1.0-SNAPSHOT" 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/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.* 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..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 @@ -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/sbt-multi-project-example/common/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/common/package.mill index d83ddd075969..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,5 +1,7 @@ package build.common +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* @@ -18,7 +20,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..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,5 +1,7 @@ package millbuild +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* @@ -8,7 +10,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..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,5 +1,7 @@ package build.multi1 +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* @@ -22,7 +24,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/multi2/package.mill b/libs/init/sbt/test/resources/expected/sbt-multi-project-example/multi2/package.mill index d6b4fba2276e..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,5 +1,7 @@ package build.multi2 +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/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..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,5 +1,7 @@ package build.nested.nested +import mill.api.* +import mill.api.opt.* import mill.javalib.* import mill.javalib.publish.* import mill.scalalib.* @@ -11,7 +13,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.", 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..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 @@ -1,5 +1,7 @@ package build.nested import mill.* +import mill.api.* +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 d2c8210c1848..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 @@ -1,6 +1,8 @@ //| mill-version: SNAPSHOT package build +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/with-args/crossproject-cross-version/build.mill b/libs/init/sbt/test/resources/expected/with-args/crossproject-cross-version/build.mill index 1a225aabe646..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 @@ -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,17 +28,17 @@ 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") - case _ => Nil + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") + case _ => Opts() }) def pomSettings = PomSettings( @@ -62,17 +64,17 @@ 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") - case _ => Nil + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") + case _ => Opts() }) def pomSettings = PomSettings( @@ -101,17 +103,17 @@ 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") - case _ => Nil + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") + case _ => Opts() }) def pomSettings = PomSettings( @@ -144,17 +146,17 @@ 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") - case _ => Nil + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") + case _ => Opts() }) def pomSettings = PomSettings( @@ -182,17 +184,17 @@ 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") - case _ => Nil + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") + case _ => Opts() }) def pomSettings = PomSettings( @@ -221,17 +223,17 @@ 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") - case _ => Nil + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") + case _ => Opts() }) def pomSettings = PomSettings( @@ -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 _ => Opts() }) def pomSettings = PomSettings( @@ -296,17 +299,17 @@ 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") - case _ => Nil + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") + case _ => Opts() }) def pomSettings = PomSettings( @@ -332,17 +335,17 @@ 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") - case _ => Nil + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") + case _ => Opts() }) def pomSettings = PomSettings( @@ -371,17 +374,17 @@ 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") - case _ => Nil + Opts("-Xlint:_,-unused", "-Wnumeric-widen", "-Wunused") + case "3.7.1" => Opts("-Wunused") + case _ => Opts() }) def pomSettings = PomSettings( 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", diff --git a/libs/javalib/src/mill/javalib/AssemblyModule.scala b/libs/javalib/src/mill/javalib/AssemblyModule.scala index 51c37ea8b89b..bcbd0ee6214b 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 @@ -18,17 +19,17 @@ trait AssemblyModule extends OfflineSupportModule { 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 @@ -56,10 +57,10 @@ trait AssemblyModule extends OfflineSupportModule { 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 6ff057609614..31d5b906b89b 100644 --- a/libs/javalib/src/mill/javalib/JavaModule.scala +++ b/libs/javalib/src/mill/javalib/JavaModule.scala @@ -7,7 +7,17 @@ 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, @@ -19,7 +29,6 @@ import mill.api.daemon.internal.bsp.{ 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, ZincOp} import mill.javalib.bsp.{BspJavaModule, BspModule} @@ -86,7 +95,7 @@ trait JavaModule override def resolutionCustomizer: Task[Option[coursier.Resolution => coursier.Resolution]] = outer.resolutionCustomizer - override def annotationProcessorsJavacOptions: T[Seq[String]] = + override def annotationProcessorsJavacOptions: T[Opts] = outer.annotationProcessorsJavacOptions() override def javacOptions = outer.javacOptions() override def jvmWorker = outer.jvmWorker @@ -285,27 +294,26 @@ trait JavaModule /** * Constructs the -processorpath compiler flag using [[annotationProcessorsResolvedMvnDeps]] */ - def annotationProcessorsJavacOptions: T[Seq[String]] = Task { + def annotationProcessorsJavacOptions: T[Opts] = Task { if (annotationProcessorsMvnDeps().nonEmpty) - Seq( + Opts( "-processorpath", - annotationProcessorsResolvedMvnDeps() - .map(_.path).mkString(File.pathSeparator) + Opt.mkPath(annotationProcessorsResolvedMvnDeps().map(_.path), sep = File.pathSeparator) ) else - Seq.empty + Opts() } /** * 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. @@ -897,11 +905,14 @@ trait JavaModule os.makeDir.all(compileGenSources) } - val jOpts = JavaCompilerOptions.split(Seq( - "-s", - compileGenSources.toString - ) ++ javacOptions() ++ mandatoryJavacOptions() ++ annotationProcessorsJavacOptions()) - + val jOpts = JavaCompilerOptions.split( + Opts( + OptGroup("-s", compileGenSources.toString), + javacOptions(), + mandatoryJavacOptions(), + annotationProcessorsJavacOptions() + ).toStringSeq + ) val worker = jvmWorker().internalWorker() worker.apply( @@ -1143,7 +1154,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. @@ -1188,7 +1199,7 @@ trait JavaModule classPath.mkString(java.io.File.pathSeparator) ) - val options = javadocOptions() ++ + val options = javadocOptions().toStringSeq ++ Seq("-d", javadocDir.toString) ++ cpOptions ++ files.map(_.toString) @@ -1266,7 +1277,7 @@ trait JavaModule val cmd = Seq(Jvm.jdkTool("jshell", javaHome().map(_.path))) ++ jshellArgs os.call( cmd = cmd, - env = allForkEnv(), + env = allForkEnv().toStringMap, cwd = forkWorkingDir(), stdin = os.Inherit, stdout = os.Inherit @@ -1596,7 +1607,7 @@ object JavaModule { override def resolutionCustomizer: Task[Option[coursier.Resolution => coursier.Resolution]] = outer.resolutionCustomizer - override def annotationProcessorsJavacOptions: T[Seq[String]] = + override def annotationProcessorsJavacOptions: T[Opts] = outer.annotationProcessorsJavacOptions() override def javacOptions = outer.javacOptions() override def jvmWorker = outer.jvmWorker diff --git a/libs/javalib/src/mill/javalib/JavacOptions.scala b/libs/javalib/src/mill/javalib/JavacOptions.scala new file mode 100644 index 000000000000..afc89a73b616 --- /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/NativeImageModule.scala b/libs/javalib/src/mill/javalib/NativeImageModule.scala index c171a4984647..94ade842da86 100644 --- a/libs/javalib/src/mill/javalib/NativeImageModule.scala +++ b/libs/javalib/src/mill/javalib/NativeImageModule.scala @@ -1,6 +1,7 @@ package mill.javalib import mill.* +import mill.api.opt.* import mill.constants.{DaemonFiles, Util} import coursier.core.VariantSelector.ConfigurationBased import mainargs.Flag @@ -38,7 +39,7 @@ trait NativeImageModule extends WithJvmWorkerModule, OfflineSupportModule { 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()) @@ -104,10 +105,11 @@ trait NativeImageModule extends WithJvmWorkerModule, OfflineSupportModule { /** * Additional options for the `native-image` Tool. */ - def nativeImageOptions: T[Seq[String]] = Task { - nativeMvnDepsMetadata().toSeq.flatMap(md => - Seq("--configurations-path", (md.path / "META-INF").toString) - ) + def nativeImageOptions: T[Opts] = Task { + nativeMvnDepsMetadata() match { + case Some(md) => Opts(OptGroup("--configurations-path", md.path / "META-INF")) + case _ => Opts() + } } /** diff --git a/libs/javalib/src/mill/javalib/RunModule.scala b/libs/javalib/src/mill/javalib/RunModule.scala index 66a11d04b6ad..e9af66299397 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 @@ -33,21 +32,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[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, String]] = Task { - forkEnv() ++ Map( - EnvVars.MILL_WORKSPACE_ROOT -> BuildCtx.workspaceRoot.toString + def allForkEnv: T[OptMap] = Task { + forkEnv() ++ OptMap( + EnvVars.MILL_WORKSPACE_ROOT -> BuildCtx.workspaceRoot ) } @@ -170,8 +169,8 @@ trait RunModule extends WithJvmWorkerModule with RunModuleApi { new RunModule.RunnerImpl( finalMainClassOpt(), runClasspath().map(_.path), - forkArgs(), - allForkEnv(), + forkArgs().toStringSeq, + allForkEnv().toStringMap, runUseArgsFile(), javaHome().map(_.path), propagateEnv() @@ -246,7 +245,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 8bd71efce32d..09e1d6f4367b 100644 --- a/libs/javalib/src/mill/javalib/SemanticDbJavaModule.scala +++ b/libs/javalib/src/mill/javalib/SemanticDbJavaModule.scala @@ -2,6 +2,7 @@ package mill.javalib 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 +35,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 +100,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 +119,7 @@ trait SemanticDbJavaModule extends CoursierModule with SemanticDbJavaModuleApi val javacOpts = SemanticDbJavaModule.javacOptionsTask( javacOptions() ++ mandatoryJavacOptions(), semanticDbJavaVersion() - ) + ).toStringSeq Task.log.debug(s"effective javac options: ${javacOpts}") @@ -226,15 +227,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 3478adddfdab..b2d49f53f9ca 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 @@ -229,9 +226,9 @@ trait TestModule */ def testSandboxWorkingDir: T[Boolean] = true - override def allForkEnv: T[Map[String, String]] = Task { - super.allForkEnv() ++ Map( - EnvVars.MILL_TEST_RESOURCE_DIR -> resources().iterator.map(_.path).mkString(";") + override def allForkEnv: T[OptMap] = Task { + super.allForkEnv() ++ OptMap( + EnvVars.MILL_TEST_RESOURCE_DIR -> Opt.mkPath(resources().map(_.path), sep = ";") ) } @@ -245,7 +242,7 @@ trait TestModule Task.Anon { val testModuleUtil = new TestModuleUtil( testUseArgsFile(), - forkArgs(), + forkArgs().toStringSeq, globSelectors(), jvmWorker().scalalibClasspath(), resources(), @@ -255,7 +252,7 @@ trait TestModule args(), testForkGrouping(), jvmWorker().testrunnerEntrypointClasspath(), - allForkEnv(), + allForkEnv().toStringMap, testSandboxWorkingDir(), forkWorkingDir(), testReportXml(), @@ -466,7 +463,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() ++ @@ -590,7 +587,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 b56e6b2c130c..847f67abc39d 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, internal} +import mill.api.daemon.internal.{EvaluatorApi, OptsApi, 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: 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 3dfb9955faba..e62383e77ba3 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.ModuleCtx import mill.api.JsonFormatters.given +import mill.api.opt.* import mill.javalib.{JavaModule, RunModule, TestModule} import mill.{Args, Task} @@ -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: OptMap, mainClass: Option[String], localMainClasses: Seq[String] )] = @@ -40,9 +40,9 @@ private[mill] trait BspRunModule(runModule: RunModule) extends mill.api.Module { override private[mill] def bspJvmTestEnvironment: Task.Simple[( runClasspath: Seq[Path], - forkArgs: Seq[String], + forkArgs: Opts, forkWorkingDir: Path, - forkEnv: Map[String, String], + forkEnv: OptMap, mainClass: Option[String], testEnvVars: Option[( mainClass: String, 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/errorprone/ErrorProneModule.scala b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala index fab493c3e65a..e8f4f6869309 100644 --- a/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala +++ b/libs/javalib/src/mill/javalib/errorprone/ErrorProneModule.scala @@ -1,11 +1,10 @@ package mill.javalib.errorprone import mill.api.PathRef +import mill.api.opt.* import mill.javalib.{Dep, DepSyntax, JavaModule} import mill.{T, Task} -import java.io.File - /** * Integrated Error Prone into a [[JavaModule]]. * @@ -37,15 +36,17 @@ 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: 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 = 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 +58,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 +67,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[Seq[String]] = Task { Seq() } /** * 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/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 { 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/src/mill/javalib/spring/boot/SpringBootModule.scala b/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala index 56575e521c4d..eb272d259c29 100644 --- a/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala +++ b/libs/javalib/src/mill/javalib/spring/boot/SpringBootModule.scala @@ -3,6 +3,7 @@ package mill.javalib.spring.boot import mainargs.Flag import mill.{T, Task} import mill.api.{ModuleRef, PathRef} +import mill.api.opt.* import mill.javalib.{Dep, DepSyntax, JavaModule, NativeImageModule} /** @@ -155,7 +156,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")) @@ -184,11 +185,10 @@ trait SpringBootModule extends JavaModule { * Uses the configuration path from both [[outer.springBootProcessAOT]] and * [[nativeMvnDepsMetadata]] */ - override def nativeImageOptions: Task.Simple[Seq[String]] = Task { + override def nativeImageOptions: Task.Simple[Opts] = Task { val configurationsPath = outer.springBootProcessAOT().path / "resources/META-INF" - super.nativeImageOptions() ++ Seq( - "--configurations-path", - configurationsPath.toString + super.nativeImageOptions() ++ Opts( + OptGroup("--configurations-path", configurationsPath) ) } } 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/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/javalib/test/src/mill/javalib/errorprone/ErrorProneTests.scala b/libs/javalib/test/src/mill/javalib/errorprone/ErrorProneTests.scala index d4811de2c8a5..b30046ff9e8d 100644 --- a/libs/javalib/test/src/mill/javalib/errorprone/ErrorProneTests.scala +++ b/libs/javalib/test/src/mill/javalib/errorprone/ErrorProneTests.scala @@ -6,7 +6,8 @@ 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 { @@ -44,7 +45,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 3db058101e74..af03dcfbd98b 100644 --- a/libs/kotlinlib/src/mill/kotlinlib/KotlinModule.scala +++ b/libs/kotlinlib/src/mill/kotlinlib/KotlinModule.scala @@ -9,6 +9,7 @@ package kotlinlib import coursier.core.VariantSelector.VariantMatcher import coursier.params.ResolutionParams import mill.api.{BuildCtx, ModuleRef, Result} +import mill.api.opt.* import mill.kotlinlib.worker.api.KotlinWorkerTarget import mill.javalib.api.CompilationResult import mill.javalib.api.JvmWorkerApi as PublicJvmWorkerApi @@ -186,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))() () } @@ -213,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( @@ -257,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. @@ -298,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 @@ -326,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(), workDir = dest @@ -353,8 +354,8 @@ trait KotlinModule extends JavaModule with KotlinModuleApi { outer => when(kotlinExplicitApi())( "-Xexplicit-api=strict" ), - allKotlincOptions(), - extraKotlinArgs + allKotlincOptions().toStringSeq, + extraKotlinArgs.toStringSeq ).flatten val workerResult = @@ -391,7 +392,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). @@ -407,33 +408,35 @@ trait KotlinModule extends JavaModule with KotlinModuleApi { outer => * For JVM, this is `-module-name`. For JS, this is overridden to be empty * (JS uses `-Xir-module-name` set separately in the compile task). */ - protected def kotlinModuleNameOption: T[Seq[String]] = Task { + protected def kotlinModuleNameOption: T[Opts] = Task { // Use artifactName if available, otherwise fall back to "main" for root modules val moduleName = Option(artifactName()).filter(_.nonEmpty).getOrElse("main") - Seq("-module-name", moduleName) + Opts(OptGroup("-module-name", moduleName)) } /** * 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") ++ - kotlinModuleNameOption() ++ - when(!languageVersion.isBlank)("-language-version", languageVersion) ++ - when(!kotlinkotlinApiVersion.isBlank)("-api-version", kotlinkotlinApiVersion) ++ - plugins.map(p => s"-Xplugin=$p") + Opts( + "-no-stdlib", + kotlinModuleNameOption(), + 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() } @@ -499,9 +502,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() } @@ -521,9 +524,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 9198453957ba..6cd0c9385c5a 100644 --- a/libs/kotlinlib/src/mill/kotlinlib/js/KotlinJsModule.scala +++ b/libs/kotlinlib/src/mill/kotlinlib/js/KotlinJsModule.scala @@ -3,10 +3,9 @@ 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.javalib.Lib @@ -71,7 +70,7 @@ trait KotlinJsModule extends KotlinModule { outer => Seq(mvn"org.jetbrains.kotlin:kotlin-stdlib-js:${kotlinVersion()}") // Kotlin/JS doesn't support -module-name (uses -Xir-module-name instead, set in compile task) - override protected def kotlinModuleNameOption: T[Seq[String]] = Task { Seq.empty } + override protected def kotlinModuleNameOption: T[Opts] = Task { Opts() } override def transitiveCompileClasspath: T[Seq[PathRef]] = Task { Task.traverse(transitiveModuleCompileModuleDeps) { @@ -179,7 +178,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 => @@ -199,7 +198,7 @@ trait KotlinJsModule extends KotlinModule { outer => destinationRoot = Task.dest, artifactId = artifactId(), explicitApi = kotlinExplicitApi(), - extraKotlinArgs = allKotlincOptions() ++ extraKotlinArgs, + extraKotlinArgs = (allKotlincOptions() ++ extraKotlinArgs).toStringSeq, worker = kotlinWorker, useBtApi = kotlincUseBtApi() ) @@ -230,7 +229,7 @@ trait KotlinJsModule extends KotlinModule { outer => destinationRoot = Task.dest, artifactId = artifactId(), explicitApi = kotlinExplicitApi(), - extraKotlinArgs = allKotlincOptions(), + extraKotlinArgs = allKotlincOptions().toStringSeq, worker = kotlinWorker, useBtApi = kotlincUseBtApi() ) @@ -515,14 +514,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 7b8b707ad793..633e32e5833a 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[OptMap] = Task { + OptMap() } /** @@ -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() } /** @@ -348,7 +348,9 @@ 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) "" @@ -374,7 +376,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" @@ -455,7 +457,9 @@ 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) "" @@ -481,7 +485,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/scalajslib/test/src/mill/scalajslib/UtestTests.scala b/libs/scalajslib/test/src/mill/scalajslib/UtestTests.scala index e36e7cbf4282..9ae5690a7c76 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") diff --git a/libs/scalalib/src/mill/scalalib/ScalaModule.scala b/libs/scalalib/src/mill/scalalib/ScalaModule.scala index 46e4477faf9f..b40b2aea0c84 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} @@ -31,8 +32,8 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase override def scalacPluginMvnDeps: T[Seq[Dep]] = outer.scalacPluginMvnDeps() override def scalacPluginClasspath: T[Seq[PathRef]] = outer.scalacPluginClasspath() override def scalaCompilerBridge: T[Option[PathRef]] = outer.scalaCompilerBridge() - 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() } } @@ -173,54 +174,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 } @@ -294,7 +297,8 @@ 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() @@ -306,7 +310,7 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase javacOptions = jOpts.compiler, scalaVersion = sv, scalaOrganization = scalaOrganization(), - scalacOptions = allScalacOptions(), + scalacOptions = allScalacOptions().toStringSeq, compilerClasspath = scalaCompilerClasspath(), scalacPluginClasspath = scalacPluginClasspath(), compilerBridgeOpt = scalaCompilerBridge(), @@ -353,7 +357,7 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase scalaDocClasspath(), scalacPluginClasspath(), scalaCompilerBridge(), - options ++ compileCp ++ scalaDocOptions() ++ files.map(_.toString()), + options ++ compileCp ++ scalaDocOptions().toStringSeq ++ files.map(_.toString()), workDir = Task.dest ), javaHome = javaHome().map(_.path) @@ -441,8 +445,8 @@ trait ScalaModule extends JavaModule with TestModule.ScalaModuleBase else "scala.tools.nsc.MainGenericRunner", classPath = runClasspath().map(_.path) ++ scalaConsoleClasspath().map(_.path), - jvmArgs = forkArgs(), - env = allForkEnv(), + jvmArgs = forkArgs().toStringSeq, + env = allForkEnv().toStringMap, mainArgs = Seq(useJavaCp) ++ consoleScalacOptions().filterNot(Set(useJavaCp)) ++ args.value, cwd = forkWorkingDir(), @@ -522,8 +526,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().toStringMap, mainArgs = replOptions, cwd = forkWorkingDir(), stdin = os.Inherit, @@ -637,13 +641,14 @@ 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}") @@ -706,8 +711,8 @@ object ScalaModule { override def scalacPluginMvnDeps: T[Seq[Dep]] = outer.scalacPluginMvnDeps() override def scalacPluginClasspath: T[Seq[PathRef]] = outer.scalacPluginClasspath() override def scalaCompilerBridge: T[Option[PathRef]] = outer.scalaCompilerBridge() - 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 2cc28fbb00fb..2d0d928e864a 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,8 @@ 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 +110,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 +153,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 34cdcb9e9a01..a45d5a74cae6 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 bca41bf5655e..b9820d882aa8 100644 --- a/libs/scalalib/test/src/mill/scalalib/ScalaScaladocTests.scala +++ b/libs/scalalib/test/src/mill/scalalib/ScalaScaladocTests.scala @@ -6,13 +6,15 @@ 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 +22,9 @@ 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 +33,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 +52,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 f813f02ac918..299c55d31a5b 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 @@ -258,8 +259,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, @@ -388,8 +389,8 @@ trait ScalaNativeModule extends ScalaModule with ScalaNativeModuleApi { outer => new NativeRunner( mainClassDefault = finalMainClassOpt(), nativeExe = nativeLink(), - forkArgsDefault = forkArgs(), - forkEnvDefault = allForkEnv(), + forkArgsDefault = forkArgs().toStringSeq, + forkEnvDefault = allForkEnv().toStringMap, propagateEnvDefault = propagateEnv() ) } @@ -398,8 +399,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().toStringMap, propagateEnvDefault = propagateEnv() ) } @@ -490,7 +491,7 @@ trait TestScalaNativeModule extends ScalaNativeModule with TestModule { val (close, framework) = withScalaNativeBridge.apply().apply(_.getFramework( nativeLink().path.toIO, - allForkEnv(), + allForkEnv().toStringMap, 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/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala b/libs/scalanativelib/test/src/mill/scalanativelib/TestingTests.scala index f59d985496fb..7bf8b475375e 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,7 +66,7 @@ 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") 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 {} 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..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 @@ -57,23 +58,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.toStringMap.asJava ) item.setMainClasses(List(testEnvVars.mainClass).map(new JvmMainClass( _, @@ -107,9 +110,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.toStringMap.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/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() diff --git a/runner/meta/src/mill/meta/MillBuildRootModule.scala b/runner/meta/src/mill/meta/MillBuildRootModule.scala index 499df2519e9e..dc9b4cc0c27c 100644 --- a/runner/meta/src/mill/meta/MillBuildRootModule.scala +++ b/runner/meta/src/mill/meta/MillBuildRootModule.scala @@ -1,9 +1,9 @@ package mill.meta import java.nio.file.Path -import mill.api.BuildCtx +import mill.api.{BuildCtx, Result} 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.OutFiles.* @@ -292,11 +292,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 */ @@ -325,7 +325,8 @@ 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( ZincOp.CompileMixed( @@ -335,7 +336,7 @@ trait MillBuildRootModule()(using javacOptions = jOpts.compiler, scalaVersion = scalaVersion(), scalaOrganization = scalaOrganization(), - scalacOptions = allScalacOptions(), + scalacOptions = allScalacOptions().toStringSeq, compilerClasspath = scalaCompilerClasspath(), scalacPluginClasspath = scalacPluginClasspath(), compilerBridgeOpt = scalaCompilerBridge(), 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