From d33ec1502158dfdde5e6275a46784c28c9dbbce5 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Thu, 4 Sep 2025 12:11:09 +0200 Subject: [PATCH] Bump Mill to 1.0.5 (was 0.12.16) --- .github/scripts/check-cross-version-deps.sc | 4 +- .github/workflows/ci.yml | 2 +- .mill-version | 2 +- build.mill.scala | 454 ++++++++++---------- mill | 2 +- mill.bat | 2 +- millw | 2 +- project/deps/package.mill.scala | 8 +- project/publish/package.mill.scala | 45 +- project/settings/package.mill.scala | 183 ++++---- 10 files changed, 370 insertions(+), 334 deletions(-) diff --git a/.github/scripts/check-cross-version-deps.sc b/.github/scripts/check-cross-version-deps.sc index 64f16dcea5..64c23335ba 100755 --- a/.github/scripts/check-cross-version-deps.sc +++ b/.github/scripts/check-cross-version-deps.sc @@ -11,9 +11,9 @@ val modules = for { module <- modules } { println(s"Checking for $module...") - val depRegex = "\\[\\d+]\\s+[│└├─\\S\\s]+\\s([\\w.-]+):([\\w.-]+):([\\w\\s\\S.-]+)".r + val depRegex = "[│└├─\\S\\s]+\\s([\\w.-]+):([\\w.-]+):([\\w\\s\\S.-]+)".r val scalaDepSuffixRegex = "^(.+?)(_[23](?:\\.\\d{2})?)?$".r - val deps = os.proc(os.pwd / "mill", "-i", s"$module.ivyDepsTree") + val deps = os.proc(os.pwd / "mill", "-i", s"$module.showMvnDepsTree") .call(cwd = os.pwd) .out .lines() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7e0bcd21c5..204c9e28c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1536,7 +1536,7 @@ jobs: - name: Check native-image config format run: ./mill -i __.checkNativeImageConfFormat - name: Check Ammonite availability - run: ./mill -i 'dummy.amm[_].resolvedRunIvyDeps' + run: ./mill -i 'dummy.amm[_].resolvedRunMvnDeps' - name: Check for cross Scala version conflicts run: .github/scripts/check-cross-version-deps.sc - name: Scalafix check diff --git a/.mill-version b/.mill-version index bcc7c361e1..90a27f9cea 100644 --- a/.mill-version +++ b/.mill-version @@ -1 +1 @@ -0.12.16 +1.0.5 diff --git a/build.mill.scala b/build.mill.scala index 95a0914dbf..298d7c356c 100644 --- a/build.mill.scala +++ b/build.mill.scala @@ -1,9 +1,12 @@ +//| mvnDeps: +//| - io.github.alexarchambault.mill::mill-native-image::0.2.2 +//| - io.github.alexarchambault.mill::mill-native-image-upload:0.2.2 +//| - com.goyeau::mill-scalafix::0.6.0 +//| - com.lumidion::sonatype-central-client-requests:0.6.0 +//| - io.get-coursier:coursier-launcher_2.13:2.1.24 +//| - org.eclipse.jgit:org.eclipse.jgit:7.3.0.202506031305-r package build -import $packages._ -import $ivy.`com.lihaoyi::mill-contrib-bloop:$MILL_VERSION` -import $ivy.`io.get-coursier::coursier-launcher:2.1.24` -import $ivy.`io.github.alexarchambault.mill::mill-native-image-upload:0.1.31-1` import build.ci.publishVersion import build.project.deps import deps.{Cli, Deps, Docker, InternalDeps, Java, Scala, TestDeps} @@ -15,6 +18,7 @@ import settings.{ FormatNativeImageConf, HasTests, LocalRepo, + LocatedInModules, PublishLocalNoFluff, ScalaCliCrossSbtModule, ScalaCliScalafixLegacyModule, @@ -29,43 +33,38 @@ import deps.customRepositories import deps.alpineVersion import build.project.website import coursier.Repository - import java.io.File import java.net.URL import java.nio.charset.Charset import java.util.Locale -import de.tobiasroeser.mill.vcs.version.VcsVersion import io.github.alexarchambault.millnativeimage.upload.Upload -import mill._ -import mill.api.Loose -import scalalib.{publish => _, _} -import mill.contrib.bloop.Bloop -import mill.testrunner.TestResult +import mill.* +import mill.api.{BuildCtx, ModuleCtx, Task} +import mill.scalalib.* +import scalalib.{publish as _, *} +import mill.javalib.testrunner.TestResult +import mill.util.{Tasks, VcsVersion} import _root_.scala.util.{Properties, Using} -// Tell mill modules are under modules/ -implicit def millModuleBasePath: define.Ctx.BasePath = - define.Ctx.BasePath(super.millModuleBasePath.value / "modules") - object cli extends Cross[Cli](Scala.scala3MainVersions) with CrossScalaDefaultToInternal -trait CrossScalaDefault { _: mill.define.Cross[_] => +trait CrossScalaDefault { self: Cross[?] => def crossScalaDefaultVersion: String override def defaultCrossSegments: Seq[String] = Seq(crossScalaDefaultVersion) } -trait CrossScalaDefaultToInternal extends CrossScalaDefault { _: mill.define.Cross[_] => +trait CrossScalaDefaultToInternal extends CrossScalaDefault { self: Cross[?] => override def crossScalaDefaultVersion: String = Scala.defaultInternal } -trait CrossScalaDefaultToRunner extends CrossScalaDefault { _: mill.define.Cross[_] => +trait CrossScalaDefaultToRunner extends CrossScalaDefault { self: Cross[?] => override def crossScalaDefaultVersion: String = Scala.runnerScala3 } // Publish a bootstrapped, executable jar for a restricted environments object cliBootstrapped extends ScalaCliPublishModule { - override def unmanagedClasspath: T[Agg[PathRef]] = + override def unmanagedClasspath: T[Seq[PathRef]] = Task(cli(Scala.defaultInternal).nativeImageClassPath()) override def jar: T[PathRef] = assembly() @@ -80,9 +79,8 @@ object cliBootstrapped extends ScalaCliPublishModule { Assembly.Rule.ExcludePattern(".*\\.semanticdb") ) ++ super.assemblyRules - override def resources: T[Seq[PathRef]] = Task.Sources { + override def resources: T[Seq[PathRef]] = super.resources() ++ Seq(propertiesFilesResources()) - } def propertiesFilesResources: T[PathRef] = Task(persistent = true) { val dir = Task.dest / "resources" @@ -119,8 +117,8 @@ object `scala3-graal` extends Cross[Scala3Graal](Scala.scala3MainVersions) object `scala3-graal-processor` extends Cross[Scala3GraalProcessor](Scala.scala3MainVersions) with CrossScalaDefaultToInternal -object `scala-cli-bsp` extends JavaModule with ScalaCliPublishModule { - override def ivyDeps: T[Agg[Dep]] = super.ivyDeps() ++ Seq( +object `scala-cli-bsp` extends JavaModule with ScalaCliPublishModule with LocatedInModules { + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.bsp4j ) override def javacOptions: T[Seq[String]] = Task { @@ -129,17 +127,15 @@ object `scala-cli-bsp` extends JavaModule with ScalaCliPublishModule { } object integration extends CliIntegration { object test extends IntegrationScalaTests { - override def ivyDeps: T[Loose.Agg[Dep]] = super.ivyDeps() ++ Seq( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.jgit, Deps.jsoup ) } object docker extends CliIntegrationDocker { object test extends ScalaCliTests { - override def sources: T[Seq[PathRef]] = Task.Sources { - super.sources() ++ integration.sources() - } - def tmpDirBase: T[PathRef] = Task(persistent = true) { + override def sources: T[Seq[PathRef]] = super.sources() ++ integration.sources() + def tmpDirBase: T[PathRef] = Task(persistent = true) { PathRef(Task.dest / "working-dir") } override def forkEnv: T[Map[String, String]] = super.forkEnv() ++ Seq( @@ -152,10 +148,8 @@ object integration extends CliIntegration { object `docker-slim` extends CliIntegrationDocker { object test extends ScalaCliTests { - override def sources: T[Seq[PathRef]] = Task.Sources { - integration.docker.test.sources() - } - def tmpDirBase: T[PathRef] = Task(persistent = true) { + override def sources: T[Seq[PathRef]] = integration.docker.test.sources() + def tmpDirBase: T[PathRef] = Task(persistent = true) { PathRef(Task.dest / "working-dir") } override def forkEnv: T[Map[String, String]] = super.forkEnv() ++ Seq( @@ -170,8 +164,9 @@ object integration extends CliIntegration { object `docs-tests` extends Cross[DocsTests](Scala.scala3MainVersions) with CrossScalaDefaultToInternal -trait DocsTests extends CrossSbtModule with ScalaCliScalafixModule with HasTests { main => - override def ivyDeps: T[Agg[Dep]] = Agg( +trait DocsTests extends CrossSbtModule with ScalaCliScalafixModule with HasTests + with LocatedInModules { main => + override def mvnDeps: T[Seq[Dep]] = Seq( Deps.fansi, Deps.osLib, Deps.pprint @@ -210,26 +205,28 @@ trait DocsTests extends CrossSbtModule with ScalaCliScalafixModule with HasTests object test extends ScalaCliTests with ScalaCliScalafixModule { override def forkEnv: T[Map[String, String]] = super.forkEnv() ++ extraEnv() ++ Seq( - "SCALA_CLI_EXAMPLES" -> (Task.workspace / "examples").toString, - "SCALA_CLI_GIF_SCENARIOS" -> (Task.workspace / "gifs" / "scenarios").toString, - "SCALA_CLI_WEBSITE_IMG" -> (Task.workspace / "website" / "static" / "img").toString, - "SCALA_CLI_GIF_RENDERER_DOCKER_DIR" -> (Task.workspace / "gifs").toString, - "SCALA_CLI_SVG_RENDERER_DOCKER_DIR" -> (Task.workspace / "gifs" / "svg_render").toString + "SCALA_CLI_EXAMPLES" -> (BuildCtx.workspaceRoot / "examples").toString, + "SCALA_CLI_GIF_SCENARIOS" -> (BuildCtx.workspaceRoot / "gifs" / "scenarios").toString, + "SCALA_CLI_WEBSITE_IMG" -> (BuildCtx.workspaceRoot / "website" / "static" / "img").toString, + "SCALA_CLI_GIF_RENDERER_DOCKER_DIR" -> (BuildCtx.workspaceRoot / "gifs").toString, + "SCALA_CLI_SVG_RENDERER_DOCKER_DIR" -> (BuildCtx.workspaceRoot / "gifs" / "svg_render").toString ) - override def resources: T[Seq[PathRef]] = Task.Sources { - // Adding markdown directories here, so that they're watched for changes in watch mode - Seq( - PathRef(Task.workspace / "website" / "docs" / "commands"), - PathRef(Task.workspace / "website" / "docs" / "cookbooks") - ) ++ super.resources() + private def customResources: T[Seq[PathRef]] = { + val customPaths: Seq[os.Path] = Seq( + BuildCtx.workspaceRoot / "website" / "docs" / "commands", + BuildCtx.workspaceRoot / "website" / "docs" / "cookbooks" + ) + Task.Sources(customPaths*) } + def resources: T[Seq[PathRef]] = + // Adding markdown directories here, so that they're watched for changes in watch mode + super.resources() ++ customResources() } } -object packager extends ScalaModule with Bloop.Module { - override def skipBloop = true +object packager extends ScalaModule { override def scalaVersion: T[String] = Scala.scala3Lts - override def ivyDeps: T[Agg[Dep]] = Agg( + override def mvnDeps: T[Seq[Dep]] = Seq( Deps.scalaPackagerCli ) override def mainClass: T[Option[String]] = Some("packager.cli.PackagerCli") @@ -238,13 +235,14 @@ object packager extends ScalaModule with Bloop.Module { object `generate-reference-doc` extends Cross[GenerateReferenceDoc](Scala.scala3MainVersions) with CrossScalaDefaultToInternal -trait GenerateReferenceDoc extends CrossSbtModule with ScalaCliScalafixModule { +trait GenerateReferenceDoc extends CrossSbtModule with ScalaCliScalafixModule + with LocatedInModules { override def moduleDeps: Seq[JavaModule] = Seq( cli(crossScalaVersion) ) override def repositoriesTask: Task[Seq[Repository]] = Task.Anon(super.repositoriesTask() ++ customRepositories) - override def ivyDeps: T[Agg[Dep]] = Agg( + override def mvnDeps: T[Seq[Dep]] = Seq( Deps.argonautShapeless, Deps.caseApp, Deps.munit @@ -256,45 +254,40 @@ trait GenerateReferenceDoc extends CrossSbtModule with ScalaCliScalafixModule { ) } -object dummy extends Module { +object dummy extends LocatedInModules { // dummy projects to get scala steward updates for Ammonite and scalafmt, whose // versions are used in the fmt and repl commands, and ensure Ammonite is available // for all Scala versions we support. object amm extends Cross[Amm](Scala.listMaxAmmoniteScalaVersion) - trait Amm extends Cross.Module[String] with CrossScalaModule with Bloop.Module { + trait Amm extends Cross.Module[String] with CrossScalaModule { override def crossScalaVersion: String = crossValue - override def skipBloop = true - override def ivyDeps: T[Agg[Dep]] = { + override def mvnDeps: T[Seq[Dep]] = { val ammoniteDep = if (crossValue == Scala.scala3Lts) Deps.ammoniteForScala3Lts else Deps.ammonite - Agg(ammoniteDep) + Seq(ammoniteDep) } } - object scalafmt extends ScalaModule with Bloop.Module { - override def skipBloop = true + object scalafmt extends ScalaModule { override def scalaVersion: T[String] = Scala.defaultInternal - override def ivyDeps: T[Agg[Dep]] = Agg( + override def mvnDeps: T[Seq[Dep]] = Seq( Deps.scalafmtCli ) } - object pythonInterface extends JavaModule with Bloop.Module { - override def skipBloop = true - override def ivyDeps: T[Agg[Dep]] = Agg( + object pythonInterface extends JavaModule { + override def mvnDeps: T[Seq[Dep]] = Seq( Deps.pythonInterface ) } - object scalaPy extends ScalaModule with Bloop.Module { - override def skipBloop = true + object scalaPy extends ScalaModule { override def scalaVersion: T[String] = Scala.defaultInternal - override def ivyDeps: T[Agg[Dep]] = Agg( + override def mvnDeps: T[Seq[Dep]] = Seq( Deps.scalaPy ) } - object scalafix extends ScalaModule with Bloop.Module { - override def skipBloop = true + object scalafix extends ScalaModule { override def scalaVersion: T[String] = Scala.defaultInternal - override def ivyDeps: T[Agg[Dep]] = Agg( + override def mvnDeps: T[Seq[Dep]] = Seq( Deps.scalafixInterfaces ) } @@ -303,11 +296,12 @@ object dummy extends Module { trait BuildMacros extends ScalaCliCrossSbtModule with ScalaCliPublishModule with ScalaCliScalafixModule - with HasTests { + with HasTests + with LocatedInModules { override def crossScalaVersion: String = crossValue - override def compileIvyDeps: T[Agg[Dep]] = Task { - if (crossScalaVersion.startsWith("3")) super.compileIvyDeps() - else super.compileIvyDeps() ++ Agg(Deps.scalaReflect(crossScalaVersion)) + override def compileMvnDeps: T[Seq[Dep]] = Task { + if (crossScalaVersion.startsWith("3")) super.compileMvnDeps() + else super.compileMvnDeps() ++ Seq(Deps.scalaReflect(crossScalaVersion)) } object test extends ScalaCliTests { @@ -316,7 +310,7 @@ trait BuildMacros extends ScalaCliCrossSbtModule } def testNegativeCompilation(): Command[Unit] = Task.Command(exclusive = true) { - val base = Task.workspace / "modules" / "build-macros" / "src" + val base = BuildCtx.workspaceRoot / "modules" / "build-macros" / "src" val negativeTests = Seq( "MismatchedLeft.scala" -> Seq( "Found: +EE1".r, @@ -336,7 +330,7 @@ trait BuildMacros extends ScalaCliCrossSbtModule os.proc("scala-cli", "compile", "-S", sv, cpsSource, extraSources).call( check = false, mergeErrIntoOut = true, - cwd = Task.workspace + cwd = BuildCtx.workspaceRoot ) val compileResult = compile() if (compileResult.exitCode != 0) { @@ -385,7 +379,8 @@ trait ProtoBuildModule extends ScalaCliPublishModule with HasTests trait Core extends ScalaCliCrossSbtModule with ScalaCliPublishModule with HasTests - with ScalaCliScalafixModule { + with ScalaCliScalafixModule + with LocatedInModules { override def crossScalaVersion: String = crossValue override def moduleDeps: Seq[SonatypeCentralPublishModule] = Seq( @@ -401,7 +396,7 @@ trait Core extends ScalaCliCrossSbtModule override def repositoriesTask: Task[Seq[Repository]] = Task.Anon(super.repositoriesTask() ++ deps.customRepositories) - override def ivyDeps: T[Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.bloopRifle.exclude(("org.scala-lang.modules", "scala-collection-compat_2.13")), Deps.collectionCompat, Deps.coursierJvm @@ -422,7 +417,7 @@ trait Core extends ScalaCliCrossSbtModule Deps.scalaJsLogging, Deps.swoval ) - override def compileIvyDeps: T[Agg[Dep]] = super.compileIvyDeps() ++ Seq( + override def compileMvnDeps: T[Seq[Dep]] = super.compileMvnDeps() ++ Seq( Deps.jsoniterMacros ) @@ -578,7 +573,8 @@ trait Core extends ScalaCliCrossSbtModule trait Directives extends ScalaCliCrossSbtModule with ScalaCliPublishModule with HasTests - with ScalaCliScalafixModule { + with ScalaCliScalafixModule + with LocatedInModules { override def crossScalaVersion: String = crossValue override def moduleDeps: Seq[SonatypeCentralPublishModule] = Seq( options(crossScalaVersion), @@ -590,11 +586,11 @@ trait Directives extends ScalaCliCrossSbtModule super.scalacOptions() ++ asyncScalacOptions(crossScalaVersion) } - override def compileIvyDeps: T[Agg[Dep]] = super.compileIvyDeps() ++ Agg( + override def compileMvnDeps: T[Seq[Dep]] = super.compileMvnDeps() ++ Seq( Deps.jsoniterMacros, Deps.svm ) - override def ivyDeps: T[Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( // Deps.asm, Deps.bloopConfig, Deps.jsoniterCore, @@ -606,7 +602,7 @@ trait Directives extends ScalaCliCrossSbtModule Task.Anon(super.repositoriesTask() ++ deps.customRepositories) object test extends ScalaCliTests { - override def ivyDeps: T[Loose.Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.pprint ) override def runClasspath: T[Seq[PathRef]] = Task { @@ -641,19 +637,20 @@ trait Directives extends ScalaCliCrossSbtModule trait Config extends ScalaCliCrossSbtModule with ScalaCliPublishModule - with ScalaCliScalafixModule { + with ScalaCliScalafixModule + with LocatedInModules { override def crossScalaVersion: String = crossValue override def moduleDeps: Seq[SonatypeCentralPublishModule] = Seq(`specification-level`(crossScalaVersion)) - override def ivyDeps: T[Agg[Dep]] = { + override def mvnDeps: T[Seq[Dep]] = { val maybeCollectionCompat = if (crossScalaVersion.startsWith("2.12.")) Seq(Deps.collectionCompat) else Nil - super.ivyDeps() ++ maybeCollectionCompat ++ Agg( + super.mvnDeps() ++ maybeCollectionCompat ++ Seq( Deps.jsoniterCoreJava8 ) } - override def compileIvyDeps: T[Agg[Dep]] = super.compileIvyDeps() ++ Agg( + override def compileMvnDeps: T[Seq[Dep]] = super.compileMvnDeps() ++ Seq( Deps.jsoniterMacrosJava8 ) override def scalacOptions: T[Seq[String]] = Task { @@ -664,12 +661,12 @@ trait Config extends ScalaCliCrossSbtModule // some compatibility-related imports, that are actually only used // in Scala 2.12. override def fix(args: String*): Command[Unit] = - if (crossScalaVersion.startsWith("2.12.")) super.fix(args: _*) + if (crossScalaVersion.startsWith("2.12.")) super.fix(args*) else Task.Command(()) } trait Options extends ScalaCliCrossSbtModule with ScalaCliPublishModule with HasTests - with ScalaCliScalafixModule { + with ScalaCliScalafixModule with LocatedInModules { override def crossScalaVersion: String = crossValue override def moduleDeps: Seq[SonatypeCentralPublishModule] = Seq( core(crossScalaVersion) @@ -681,11 +678,11 @@ trait Options extends ScalaCliCrossSbtModule with ScalaCliPublishModule with Has super.scalacOptions() ++ asyncScalacOptions(crossScalaVersion) } - override def ivyDeps: T[Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.bloopConfig, Deps.signingCliShared ) - override def compileIvyDeps: T[Agg[Dep]] = super.compileIvyDeps() ++ Seq( + override def compileMvnDeps: T[Seq[Dep]] = super.compileMvnDeps() ++ Seq( Deps.jsoniterMacros ) @@ -700,20 +697,20 @@ trait Options extends ScalaCliCrossSbtModule with ScalaCliPublishModule with Has } } -trait Scala3Runtime extends CrossSbtModule with ScalaCliPublishModule { +trait Scala3Runtime extends CrossSbtModule with ScalaCliPublishModule with LocatedInModules { override def crossScalaVersion: String = crossValue - override def ivyDeps: T[Agg[Dep]] = super.ivyDeps() + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() } trait Scala3Graal extends ScalaCliCrossSbtModule - with ScalaCliPublishModule with ScalaCliScalafixModule { + with ScalaCliPublishModule with ScalaCliScalafixModule with LocatedInModules { override def crossScalaVersion: String = crossValue - override def ivyDeps: T[Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.asm, Deps.osLib ) - override def resources: T[Seq[PathRef]] = Task.Sources { + override def resources: T[Seq[PathRef]] = Task { val extraResourceDir = Task.dest / "extra" // scala3RuntimeFixes.jar is also used within // resource-config.json and BytecodeProcessor.scala @@ -726,7 +723,8 @@ trait Scala3Graal extends ScalaCliCrossSbtModule } } -trait Scala3GraalProcessor extends CrossScalaModule with ScalaCliPublishModule { +trait Scala3GraalProcessor extends CrossScalaModule with ScalaCliPublishModule + with LocatedInModules { override def moduleDeps: Seq[SonatypeCentralPublishModule] = Seq(`scala3-graal`(crossScalaVersion)) override def finalMainClass: T[String] = "scala.cli.graal.CoursierCacheProcessor" @@ -735,9 +733,10 @@ trait Scala3GraalProcessor extends CrossScalaModule with ScalaCliPublishModule { trait Build extends ScalaCliCrossSbtModule with ScalaCliPublishModule with HasTests - with ScalaCliScalafixModule { - override def crossScalaVersion: String = crossValue - override def millSourcePath: os.Path = super.millSourcePath / os.up / "build" + with ScalaCliScalafixModule + with LocatedInModules { + override def crossScalaVersion: String = crossValue + override def moduleDir: os.Path = super.moduleDir / os.up / "build" override def moduleDeps: Seq[SonatypeCentralPublishModule] = Seq( options(crossScalaVersion), directives(crossScalaVersion), @@ -749,11 +748,11 @@ trait Build extends ScalaCliCrossSbtModule super.scalacOptions() ++ asyncScalacOptions(crossScalaVersion) } - override def compileIvyDeps: T[Agg[Dep]] = super.compileIvyDeps() ++ Agg( + override def compileMvnDeps: T[Seq[Dep]] = super.compileMvnDeps() ++ Seq( Deps.jsoniterMacros, Deps.svm ) - override def ivyDeps: T[Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.asm, Deps.collectionCompat, Deps.javaClassName, @@ -772,7 +771,7 @@ trait Build extends ScalaCliCrossSbtModule Task.Anon(super.repositoriesTask() ++ deps.customRepositories) object test extends ScalaCliTests { - override def ivyDeps: T[Loose.Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.pprint, Deps.slf4jNop ) @@ -818,7 +817,7 @@ trait Build extends ScalaCliCrossSbtModule } trait SpecificationLevel extends ScalaCliCrossSbtModule - with ScalaCliPublishModule { + with ScalaCliPublishModule with LocatedInModules { override def crossScalaVersion: String = crossValue override def scalacOptions: T[Seq[String]] = Task { val isScala213 = crossScalaVersion.startsWith("2.13.") @@ -830,7 +829,7 @@ trait SpecificationLevel extends ScalaCliCrossSbtModule } trait Cli extends CrossSbtModule with ProtoBuildModule with CliLaunchers - with FormatNativeImageConf { + with FormatNativeImageConf with LocatedInModules { // Copied from Mill: https://github.com/com-lihaoyi/mill/blob/ea367c09bd31a30464ca901cb29863edde5340be/scalalib/src/mill/scalalib/JavaModule.scala#L792 def debug(port: Int, args: Task[Args] = Task.Anon(Args())): Command[Unit] = Task.Command { try mill.api.Result.Success( @@ -927,9 +926,7 @@ trait Cli extends CrossSbtModule with ProtoBuildModule with CliLaunchers } PathRef(dir) } - override def resources: T[Seq[PathRef]] = Task.Sources { - super.resources() ++ Seq(defaultFilesResources()) - } + override def resources: T[Seq[PathRef]] = super.resources() ++ Seq(defaultFilesResources()) override def scalacOptions: T[Seq[String]] = Task { super.scalacOptions() ++ asyncScalacOptions(crossScalaVersion) @@ -947,7 +944,7 @@ trait Cli extends CrossSbtModule with ProtoBuildModule with CliLaunchers override def repositoriesTask: Task[Seq[Repository]] = Task.Anon(super.repositoriesTask() ++ customRepositories) - override def ivyDeps: T[Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.caseApp, Deps.coursierLauncher, Deps.coursierProxySetup, @@ -964,7 +961,7 @@ trait Cli extends CrossSbtModule with ProtoBuildModule with CliLaunchers Deps.sttp, Deps.scalafixInterfaces ) - override def compileIvyDeps: T[Agg[Dep]] = super.compileIvyDeps() ++ Agg( + override def compileMvnDeps: T[Seq[Dep]] = super.compileMvnDeps() ++ Seq( Deps.jsoniterMacros, Deps.svm ) @@ -993,7 +990,7 @@ trait Cli extends CrossSbtModule with ProtoBuildModule with CliLaunchers super.runClasspath() ++ Seq(localRepoJar()) } - override def compileIvyDeps: T[Agg[Dep]] = super.ivyDeps() ++ Agg( + override def compileMvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.jsoniterMacros ) @@ -1005,7 +1002,7 @@ trait Cli extends CrossSbtModule with ProtoBuildModule with CliLaunchers } trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests - with ScalaCliScalafixModule { + with ScalaCliScalafixModule with LocatedInModules { override def scalaVersion: T[String] = sv def sv: String = Scala.scala213 @@ -1017,12 +1014,12 @@ trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests super.scalacOptions() ++ Seq("-Xasync", "-deprecation") } - override def ivyDeps: T[Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.osLib ) trait IntegrationScalaTests extends super.ScalaCliTests with ScalaCliScalafixModule { - override def ivyDeps: T[Loose.Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.bsp4j, Deps.coursier .exclude(("com.github.plokhotnyuk.jsoniter-scala", "jsoniter-scala-macros")), @@ -1034,7 +1031,7 @@ trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests Deps.slf4jNop, Deps.usingDirectives ) - override def compileIvyDeps: T[Agg[Dep]] = super.compileIvyDeps() ++ Seq( + override def compileMvnDeps: T[Seq[Dep]] = super.compileMvnDeps() ++ Seq( Deps.jsoniterMacros ) override def forkEnv: T[Map[String, String]] = super.forkEnv() ++ Seq( @@ -1047,7 +1044,7 @@ trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests val dir = Task.dest / "constants" val dest = dir / "Constants.scala" val mostlyStaticDockerfile = - Task.workspace / ".github" / "scripts" / "docker" / "ScalaCliSlimDockerFile" + BuildCtx.workspaceRoot / ".github" / "scripts" / "docker" / "ScalaCliSlimDockerFile" assert( os.exists(mostlyStaticDockerfile), s"Error: $mostlyStaticDockerfile not found" @@ -1133,48 +1130,61 @@ trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests override def generatedSources: T[Seq[PathRef]] = super.generatedSources() ++ Seq(constantsFile()) - override def test(args: String*): Command[(String, Seq[TestResult])] = jvm(args: _*) + override def testForked(args: String*): Command[(msg: String, results: Seq[TestResult])] = + jvm(args*) def forcedLauncher: T[PathRef] = Task(persistent = true) { val ext = if (Properties.isWin) ".exe" else "" val launcher = Task.dest / s"scala-cli$ext" - if (!os.exists(launcher)) { - val dir = Option(System.getenv("SCALA_CLI_IT_FORCED_LAUNCHER_DIRECTORY")).getOrElse { - sys.error("SCALA_CLI_IT_FORCED_LAUNCHER_DIRECTORY not set") + if !os.exists(launcher) then + BuildCtx.withFilesystemCheckerDisabled { + val dir = Option(System.getenv("SCALA_CLI_IT_FORCED_LAUNCHER_DIRECTORY")).getOrElse { + sys.error("SCALA_CLI_IT_FORCED_LAUNCHER_DIRECTORY not set") + } + System.err.println(s"SCALA_CLI_IT_FORCED_LAUNCHER_DIRECTORY was set to $dir") + val content = importedLauncher(dir, BuildCtx.workspaceRoot) + System.err.println(s"writing launcher to $launcher") + os.write( + launcher, + content, + createFolders = true, + perms = if Properties.isWin then null else "rwxr-xr-x" + ) } - val content = importedLauncher(dir, Task.workspace) - os.write( - launcher, - content, - createFolders = true, - perms = if (Properties.isWin) null else "rwxr-xr-x" - ) - } PathRef(launcher) } def forcedStaticLauncher: T[PathRef] = Task(persistent = true) { val launcher = Task.dest / "scala-cli" - if (!os.exists(launcher)) { - val dir = Option(System.getenv("SCALA_CLI_IT_FORCED_STATIC_LAUNCHER_DIRECTORY")).getOrElse { - sys.error("SCALA_CLI_IT_FORCED_STATIC_LAUNCHER_DIRECTORY not set") + if !os.exists(launcher) then + BuildCtx.withFilesystemCheckerDisabled { + val dir = + Option(System.getenv("SCALA_CLI_IT_FORCED_STATIC_LAUNCHER_DIRECTORY")).getOrElse { + sys.error("SCALA_CLI_IT_FORCED_STATIC_LAUNCHER_DIRECTORY not set") + } + System.err.println(s"SCALA_CLI_IT_FORCED_STATIC_LAUNCHER_DIRECTORY was set to $dir") + val content = importedLauncher(dir, BuildCtx.workspaceRoot) + System.err.println(s"writing launcher to $launcher") + os.write(launcher, content, createFolders = true) } - val content = importedLauncher(dir, Task.workspace) - os.write(launcher, content, createFolders = true) - } PathRef(launcher) } def forcedMostlyStaticLauncher: T[PathRef] = Task(persistent = true) { val launcher = Task.dest / "scala-cli" - if (!os.exists(launcher)) { - val dir = - Option(System.getenv("SCALA_CLI_IT_FORCED_MOSTLY_STATIC_LAUNCHER_DIRECTORY")).getOrElse { - sys.error("SCALA_CLI_IT_FORCED_MOSTLY_STATIC_LAUNCHER_DIRECTORY not set") - } - val content = importedLauncher(dir, Task.workspace) - os.write(launcher, content, createFolders = true) - } + if !os.exists(launcher) then + BuildCtx.withFilesystemCheckerDisabled { + val dir = + Option(System.getenv("SCALA_CLI_IT_FORCED_MOSTLY_STATIC_LAUNCHER_DIRECTORY")).getOrElse { + sys.error("SCALA_CLI_IT_FORCED_MOSTLY_STATIC_LAUNCHER_DIRECTORY not set") + } + System.err.println( + s"SCALA_CLI_IT_FORCED_MOSTLY_STATIC_LAUNCHER_DIRECTORY was set to $dir" + ) + val content = importedLauncher(dir, BuildCtx.workspaceRoot) + System.err.println(s"writing launcher to $launcher") + os.write(launcher, content, createFolders = true) + } PathRef(launcher) } @@ -1227,59 +1237,63 @@ trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests private def testArgs(args: Seq[String], launcher: os.Path, cliKind: String): Seq[String] = extraTestArgs(launcher, cliKind) ++ debugTestArgs(args) - def jvm(args: String*): Command[(String, Seq[TestResult])] = Task.Command { + def jvm(args: String*): Command[(msg: String, results: Seq[TestResult])] = Task.Command { testTask( Task.Anon(args ++ testArgs(args, Launchers.jvm().path, "jvm")), Task.Anon(Seq.empty[String]) )() } - def jvmBootstrapped(args: String*): Command[(String, Seq[TestResult])] = Task.Command { - testTask( - Task.Anon(args ++ testArgs(args, Launchers.jvmBootstrapped().path, "jvmBootstrapped")), - Task.Anon(Seq.empty[String]) - )() - } - def native(args: String*): Command[(String, Seq[TestResult])] = Task.Command { + def jvmBootstrapped(args: String*): Command[(msg: String, results: Seq[TestResult])] = + Task.Command { + testTask( + Task.Anon(args ++ testArgs(args, Launchers.jvmBootstrapped().path, "jvmBootstrapped")), + Task.Anon(Seq.empty[String]) + )() + } + def native(args: String*): Command[(msg: String, results: Seq[TestResult])] = Task.Command { testTask( Task.Anon(args ++ testArgs(args, Launchers.native().path, "native")), Task.Anon(Seq.empty[String]) )() } - def nativeStatic(args: String*): Command[(String, Seq[TestResult])] = Task.Command { - testTask( - Task.Anon(args ++ testArgs(args, Launchers.nativeStatic().path, "native-static")), - Task.Anon(Seq.empty[String]) - )() - } - def nativeMostlyStatic(args: String*): Command[(String, Seq[TestResult])] = Task.Command { - testTask( - Task.Anon(args ++ testArgs( - args, - Launchers.nativeMostlyStatic().path, - "native-mostly-static" - )), - Task.Anon(Seq.empty[String]) - )() - } + def nativeStatic(args: String*): Command[(msg: String, results: Seq[TestResult])] = + Task.Command { + testTask( + Task.Anon(args ++ testArgs(args, Launchers.nativeStatic().path, "native-static")), + Task.Anon(Seq.empty[String]) + )() + } + def nativeMostlyStatic(args: String*): Command[(msg: String, results: Seq[TestResult])] = + Task.Command { + testTask( + Task.Anon(args ++ testArgs( + args, + Launchers.nativeMostlyStatic().path, + "native-mostly-static" + )), + Task.Anon(Seq.empty[String]) + )() + } } } trait CliIntegrationDocker extends SbtModule with ScalaCliPublishModule with HasTests { override def scalaVersion: T[String] = Scala.scala213 - override def ivyDeps: T[Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.osLib ) } trait Runner extends ScalaCliCrossSbtModule with ScalaCliPublishModule - with ScalaCliScalafixLegacyModule { + with ScalaCliScalafixLegacyModule + with LocatedInModules { override def crossScalaVersion: String = crossValue override def scalacOptions: T[Seq[String]] = Task { super.scalacOptions() ++ Seq("-release", "8") } override def mainClass: T[Option[String]] = Some("scala.cli.runner.Runner") - override def sources: T[Seq[PathRef]] = Task.Sources { + override def sources: T[Seq[PathRef]] = { val scala3DirNames = if (crossScalaVersion.startsWith("3.")) { val name = @@ -1296,12 +1310,13 @@ trait Runner extends ScalaCliCrossSbtModule trait TestRunner extends ScalaCliCrossSbtModule with ScalaCliPublishModule - with ScalaCliScalafixLegacyModule { + with ScalaCliScalafixLegacyModule + with LocatedInModules { override def crossScalaVersion: String = crossValue override def scalacOptions: T[Seq[String]] = Task { super.scalacOptions() ++ Seq("-release", "8") } - override def ivyDeps: T[Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.asm, Deps.collectionCompat, Deps.testInterface @@ -1311,7 +1326,8 @@ trait TestRunner extends ScalaCliCrossSbtModule trait TastyLib extends ScalaCliCrossSbtModule with ScalaCliPublishModule - with ScalaCliScalafixLegacyModule { + with ScalaCliScalafixLegacyModule + with LocatedInModules { override def crossScalaVersion: String = crossValue def constantsFile: T[PathRef] = Task(persistent = true) { val dir = Task.dest / "constants" @@ -1350,7 +1366,7 @@ object `local-repo` extends LocalRepo { } // Helper CI commands -def publishSonatype(tasks: mill.main.Tasks[PublishModule.PublishData]) = Task.Command { +def publishSonatype(tasks: Tasks[PublishModule.PublishData]) = Task.Command { val taskNames = tasks.value.map(_.toString()) System.err.println( s"""Tasks producing artifacts to be included in the bundle: @@ -1361,16 +1377,16 @@ def publishSonatype(tasks: mill.main.Tasks[PublishModule.PublishData]) = Task.Co val bundleName = s"$organization-$ghName-$pv" System.err.println(s"Publishing bundle: $bundleName") publish.publishSonatype( - data = define.Task.sequence(tasks.value)(), + data = Task.sequence(tasks.value)(), log = Task.ctx().log, - workspace = Task.workspace, + workspace = BuildCtx.workspaceRoot, env = Task.env, bundleName = bundleName ) } -def copyTo(task: mill.main.Tasks[PathRef], dest: String): Command[Unit] = Task.Command { - val destPath = os.Path(dest, Task.workspace) +def copyTo(task: Tasks[PathRef], dest: String): Command[Unit] = Task.Command { + val destPath = os.Path(dest, BuildCtx.workspaceRoot) if (task.value.length > 1) sys.error("Expected a single task") val ref = task.value.head() @@ -1379,7 +1395,7 @@ def copyTo(task: mill.main.Tasks[PathRef], dest: String): Command[Unit] = Task.C } def writePackageVersionTo(dest: String): Command[Unit] = Task.Command { - val destPath = os.Path(dest, Task.workspace) + val destPath = os.Path(dest, BuildCtx.workspaceRoot) val rawVersion = cli(Scala.defaultInternal).publishVersion() val version = if (rawVersion.contains("+")) rawVersion.stripSuffix("-SNAPSHOT") @@ -1388,7 +1404,7 @@ def writePackageVersionTo(dest: String): Command[Unit] = Task.Command { } def writeShortPackageVersionTo(dest: String): Command[Unit] = Task.Command { - val destPath = os.Path(dest, Task.workspace) + val destPath = os.Path(dest, BuildCtx.workspaceRoot) val rawVersion = cli(Scala.defaultInternal).publishVersion() val version = rawVersion.takeWhile(c => c != '-' && c != '+') os.write.over(destPath, version) @@ -1429,7 +1445,7 @@ def copyLauncher(directory: String = "artifacts"): Command[os.Path] = Task.Comma directory = directory, name = "scala-cli", compress = true, - workspace = Task.workspace + workspace = BuildCtx.workspaceRoot ) } @@ -1437,7 +1453,7 @@ def copyJvmLauncher(directory: String = "artifacts"): Command[Unit] = Task.Comma val launcher = cli(Scala.defaultInternal).standaloneLauncher().path os.copy( launcher, - os.Path(directory, Task.workspace) / s"scala-cli$platformExecutableJarExtension", + os.Path(directory, BuildCtx.workspaceRoot) / s"scala-cli$platformExecutableJarExtension", createFolders = true, replaceExisting = true ) @@ -1446,7 +1462,7 @@ def copyJvmBootstrappedLauncher(directory: String = "artifacts"): Command[Unit] val launcher = cliBootstrapped.jar().path os.copy( launcher, - os.Path(directory, Task.workspace) / s"scala-cli.jar", + os.Path(directory, BuildCtx.workspaceRoot) / s"scala-cli.jar", createFolders = true, replaceExisting = true ) @@ -1455,7 +1471,7 @@ def copyJvmBootstrappedLauncher(directory: String = "artifacts"): Command[Unit] def uploadLaunchers(directory: String = "artifacts"): Command[Unit] = Task.Command { val version = cli(Scala.defaultInternal).publishVersion() - val path = os.Path(directory, Task.workspace) + val path = os.Path(directory, BuildCtx.workspaceRoot) val launchers = os.list(path).filter(os.isFile(_)).map { path => path -> path.last } @@ -1464,16 +1480,16 @@ def uploadLaunchers(directory: String = "artifacts"): Command[Unit] = Task.Comma else ("v" + version, false) System.err.println(s"Uploading to tag $tag (overwrite assets: $overwriteAssets)") Upload.upload(ghOrg, ghName, ghToken(), tag, dryRun = false, overwrite = overwriteAssets)( - launchers: _* + launchers* ) } -def unitTests(): Command[(String, Seq[TestResult])] = Task.Command { - `build-module`(Scala.defaultInternal).test.test()() - `build-macros`(Scala.defaultInternal).test.test()() - cli(Scala.defaultInternal).test.test()() - directives(Scala.defaultInternal).test.test()() - options(Scala.defaultInternal).test.test()() +def unitTests(): Command[(msg: String, results: Seq[TestResult])] = Task.Command { + `build-module`(Scala.defaultInternal).test.testForked()() + `build-macros`(Scala.defaultInternal).test.testForked()() + cli(Scala.defaultInternal).test.testForked()() + directives(Scala.defaultInternal).test.testForked()() + options(Scala.defaultInternal).test.testForked()() } def scala(args: Task[Args] = Task.Anon(Args())) = Task.Command { @@ -1489,11 +1505,8 @@ def defaultNativeImage(): Command[PathRef] = cli(Scala.defaultInternal).nativeImage() } -def nativeIntegrationTests(): Command[(String, Seq[TestResult])] = - Task.Command { - integration.test.native()() - } - +def nativeIntegrationTests(): Command[(msg: String, results: Seq[TestResult])] = + integration.test.native() def copyDefaultLauncher(directory: String = "artifacts"): Command[os.Path] = Task.Command { copyLauncher(directory)() @@ -1506,7 +1519,7 @@ def copyMostlyStaticLauncher(directory: String = "artifacts"): Command[os.Path] directory = directory, name = "scala-cli", compress = true, - workspace = Task.workspace, + workspace = BuildCtx.workspaceRoot, suffix = "-mostly-static" ) } @@ -1518,7 +1531,7 @@ def copyStaticLauncher(directory: String = "artifacts"): Command[os.Path] = Task directory = directory, name = "scala-cli", compress = true, - workspace = Task.workspace, + workspace = BuildCtx.workspaceRoot, suffix = "-static" ) } @@ -1561,7 +1574,7 @@ object ci extends Module { def updateScalaCliSetup(): Command[Unit] = Task.Command { val version = cli(Scala.defaultInternal).publishVersion() - val targetDir = Task.workspace / "target-scala-cli-setup" + val targetDir = BuildCtx.workspaceRoot / "target-scala-cli-setup" val mainDir = targetDir / "scala-cli-setup" val setupScriptPath = mainDir / "src" / "main.ts" @@ -1590,7 +1603,7 @@ object ci extends Module { def updateStandaloneLauncher(): Command[os.CommandResult] = Task.Command { val version = cli(Scala.defaultInternal).publishVersion() - val targetDir = Task.workspace / "target" + val targetDir = BuildCtx.workspaceRoot / "target" val scalaCliDir = targetDir / "scala-cli" val standaloneLauncherPath = scalaCliDir / "scala-cli.sh" val standaloneWindowsLauncherPath = scalaCliDir / "scala-cli.bat" @@ -1659,7 +1672,7 @@ object ci extends Module { def updateScalaCliBrewFormula(): Command[Unit] = Task.Command { val version = cli(Scala.defaultInternal).publishVersion() - val targetDir = Task.workspace / "target" + val targetDir = BuildCtx.workspaceRoot / "target" val homebrewFormulaDir = targetDir / "homebrew-scala-cli" // clean target directory @@ -1679,13 +1692,15 @@ object ci extends Module { val arm64LauncherURL = s"https://github.com/Virtuslab/scala-cli/releases/download/v$version/scala-cli-aarch64-apple-darwin.gz" - val x86LauncherPath = os.Path("artifacts", Task.workspace) / "scala-cli-x86_64-apple-darwin.gz" + val x86LauncherPath = + os.Path("artifacts", BuildCtx.workspaceRoot) / "scala-cli-x86_64-apple-darwin.gz" val arm64LauncherPath = - os.Path("artifacts", Task.workspace) / "scala-cli-aarch64-apple-darwin.gz" + os.Path("artifacts", BuildCtx.workspaceRoot) / "scala-cli-aarch64-apple-darwin.gz" val (x86Sha256, arm64Sha256) = brewLaunchersSha(x86LauncherPath, arm64LauncherPath, targetDir) - val templateFormulaPath = Task.workspace / ".github" / "scripts" / "scala-cli.rb.template" - val template = os.read(templateFormulaPath) + val templateFormulaPath = + BuildCtx.workspaceRoot / ".github" / "scripts" / "scala-cli.rb.template" + val template = os.read(templateFormulaPath) val updatedFormula = template .replace("@X86_LAUNCHER_URL@", x86LauncherURL) @@ -1702,7 +1717,7 @@ object ci extends Module { def updateScalaExperimentalBrewFormula(): Command[Unit] = Task.Command { val version = cli(Scala.defaultInternal).publishVersion() - val targetDir = Task.workspace / "target" + val targetDir = BuildCtx.workspaceRoot / "target" val homebrewFormulaDir = targetDir / "homebrew-scala-experimental" // clean homebrew-scala-experimental directory @@ -1722,12 +1737,13 @@ object ci extends Module { val arm64LauncherURL = s"https://github.com/Virtuslab/scala-cli/releases/download/v$version/scala-cli-aarch64-apple-darwin.gz" - val x86LauncherPath = os.Path("artifacts", Task.workspace) / "scala-cli-x86_64-apple-darwin.gz" + val x86LauncherPath = + os.Path("artifacts", BuildCtx.workspaceRoot) / "scala-cli-x86_64-apple-darwin.gz" val arm64LauncherPath = - os.Path("artifacts", Task.workspace) / "scala-cli-aarch64-apple-darwin.gz" + os.Path("artifacts", BuildCtx.workspaceRoot) / "scala-cli-aarch64-apple-darwin.gz" val (x86Sha256, arm64Sha256) = brewLaunchersSha(x86LauncherPath, arm64LauncherPath, targetDir) - val templateFormulaPath = Task.workspace / ".github" / "scripts" / "scala.rb.template" + val templateFormulaPath = BuildCtx.workspaceRoot / ".github" / "scripts" / "scala.rb.template" val template = os.read(templateFormulaPath) val updatedFormula = template @@ -1745,7 +1761,7 @@ object ci extends Module { def updateInstallationScript(): Command[Unit] = Task.Command { val version = cli(Scala.defaultInternal).publishVersion() - val targetDir = Task.workspace / "target" + val targetDir = BuildCtx.workspaceRoot / "target" val packagesDir = targetDir / "scala-cli-packages" val installationScriptPath = packagesDir / "scala-setup.sh" @@ -1772,7 +1788,7 @@ object ci extends Module { def updateDebianPackages(): Command[Unit] = Task.Command { val version = cli(Scala.defaultInternal).publishVersion() - val targetDir = Task.workspace / "target" + val targetDir = BuildCtx.workspaceRoot / "target" val packagesDir = targetDir / "scala-cli-packages" val debianDir = packagesDir / "debian" @@ -1790,7 +1806,7 @@ object ci extends Module { // copy deb package to repository os.copy( - os.Path("artifacts", Task.workspace) / "scala-cli-x86_64-pc-linux.deb", + os.Path("artifacts", BuildCtx.workspaceRoot) / "scala-cli-x86_64-pc-linux.deb", debianDir / s"scala-cli_$version.deb" ) @@ -1840,12 +1856,12 @@ object ci extends Module { def updateChocolateyPackage(): Command[os.CommandResult] = Task.Command { val version = cli(Scala.defaultInternal).publishVersion() - val packagesDir = Task.workspace / "target" / "scala-cli-packages" - val chocoDir = Task.workspace / ".github" / "scripts" / "choco" + val packagesDir = BuildCtx.workspaceRoot / "target" / "scala-cli-packages" + val chocoDir = BuildCtx.workspaceRoot / ".github" / "scripts" / "choco" val msiPackagePath = packagesDir / s"scala-cli_$version.msi" os.copy( - Task.workspace / "artifacts" / "scala-cli-x86_64-pc-win32.msi", + BuildCtx.workspaceRoot / "artifacts" / "scala-cli-x86_64-pc-win32.msi", msiPackagePath, createFolders = true ) @@ -1884,7 +1900,7 @@ object ci extends Module { def updateCentOsPackages(): Command[Unit] = Task.Command { val version = cli(Scala.defaultInternal).publishVersion() - val targetDir = Task.workspace / "target" + val targetDir = BuildCtx.workspaceRoot / "target" val packagesDir = targetDir / "scala-cli-packages" val centOsDir = packagesDir / "CentOS" @@ -1902,7 +1918,7 @@ object ci extends Module { // copy rpm package to repository os.copy( - os.Path("artifacts", Task.workspace) / "scala-cli-x86_64-pc-linux.rpm", + os.Path("artifacts", BuildCtx.workspaceRoot) / "scala-cli-x86_64-pc-linux.rpm", centOsDir / "Packages" / s"scala-cli_$version.rpm" ) @@ -1973,7 +1989,7 @@ object ci extends Module { .mkString(System.lineSeparator()) ) } - val destDir = os.Path(directory, Task.workspace) + val destDir = os.Path(directory, BuildCtx.workspaceRoot) os.copy(orig, destDir / distName, createFolders = true, replaceExisting = true) } def writeWixConfigExtra(dest: String = "wix-visual-cpp-redist.xml"): Command[Unit] = @@ -2017,7 +2033,7 @@ object ci extends Module { | | |""".stripMargin - val dest0 = os.Path(dest, Task.workspace) + val dest0 = os.Path(dest, BuildCtx.workspaceRoot) os.write.over(dest0, content.getBytes(Charset.defaultCharset()), createFolders = true) } def setShouldPublish(): Command[Unit] = publish.setShouldPublish() @@ -2036,9 +2052,9 @@ object ci extends Module { "--ttl", "0" ) - val baseJavaHome = os.Path(command.!!.trim, Task.workspace) + val baseJavaHome = os.Path(command.!!.trim, BuildCtx.workspaceRoot) System.err.println(s"Initial Java home $baseJavaHome") - val destJavaHome = os.Path(dest, Task.workspace) + val destJavaHome = os.Path(dest, BuildCtx.workspaceRoot) os.copy(baseJavaHome, destJavaHome, createFolders = true) System.err.println(s"New Java home $destJavaHome") destJavaHome @@ -2046,10 +2062,10 @@ object ci extends Module { def checkScalaVersions(): Command[Unit] = Task.Command { website.checkMainScalaVersions( - Task.workspace / "website" / "docs" / "reference" / "scala-versions.md" + BuildCtx.workspaceRoot / "website" / "docs" / "reference" / "scala-versions.md" ) website.checkScalaJsVersions( - Task.workspace / "website" / "docs" / "guides" / "advanced" / "scala-js.md" + BuildCtx.workspaceRoot / "website" / "docs" / "guides" / "advanced" / "scala-js.md" ) } } diff --git a/mill b/mill index 931612bef3..7b3ccead5a 100755 --- a/mill +++ b/mill @@ -84,7 +84,7 @@ export USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM=false DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)" if [[ $IS_WINDOWS ]]; then - exec "$DIR/millw" "$@" + exec "$DIR/mill.bat" "$@" else exec "$DIR/millw" $COMMAND fi diff --git a/mill.bat b/mill.bat index 7f99598658..40734823cb 100755 --- a/mill.bat +++ b/mill.bat @@ -34,7 +34,7 @@ rem setlocal seems to be unavailable on Windows 95/98/ME rem but I don't think we need to support them in 2019 setlocal enabledelayedexpansion -if [!DEFAULT_MILL_VERSION!]==[] ( set "DEFAULT_MILL_VERSION=0.12.16" ) +if [!DEFAULT_MILL_VERSION!]==[] ( set "DEFAULT_MILL_VERSION=1.0.5" ) if [!MILL_GITHUB_RELEASE_CDN!]==[] ( set "MILL_GITHUB_RELEASE_CDN=" ) diff --git a/millw b/millw index 97db4e237e..3b0bae978c 100755 --- a/millw +++ b/millw @@ -33,7 +33,7 @@ set -e if [ -z "${DEFAULT_MILL_VERSION}" ] ; then - DEFAULT_MILL_VERSION="0.12.16" + DEFAULT_MILL_VERSION="1.0.5" fi diff --git a/project/deps/package.mill.scala b/project/deps/package.mill.scala index 7c61181b70..7ce69d60df 100644 --- a/project/deps/package.mill.scala +++ b/project/deps/package.mill.scala @@ -1,6 +1,8 @@ package build.project.deps -import mill._ -import scalalib._ + +import mill.* +import mill.api.BuildInfo +import scalalib.* object Cli { def runnerLegacyVersion = "1.7.1" // last runner version to support pre-LTS Scala 3 versions @@ -100,7 +102,7 @@ object TestDeps { object InternalDeps { object Versions { - def mill: String = _root_.mill.main.BuildInfo.millVersion + def mill: String = BuildInfo.millVersion def lefouMillwRef = "166bcdf5741de8569e0630e18c3b2ef7e252cd96" } } diff --git a/project/publish/package.mill.scala b/project/publish/package.mill.scala index 0151871a20..ad071fd02b 100644 --- a/project/publish/package.mill.scala +++ b/project/publish/package.mill.scala @@ -1,20 +1,20 @@ package build.project.publish -import $ivy.`de.tototec::de.tobiasroeser.mill.vcs.version::0.4.0` -import $ivy.`org.eclipse.jgit:org.eclipse.jgit:7.3.0.202506031305-r` + import build.project.settings import com.lumidion.sonatype.central.client.core.{PublishingType, SonatypeCredentials} import settings.{PublishLocalNoFluff, workspaceDirName} -import de.tobiasroeser.mill.vcs.version._ -import mill._ +import mill.* import mill.javalib.publish.Artifact -import scalalib._ +import mill.util.{Tasks, VcsVersion} +import scalalib.* import org.eclipse.jgit.api.Git +import mill.api.{BuildCtx, ModuleCtx, Task} import java.nio.charset.Charset -import scala.concurrent.duration._ -import scala.jdk.CollectionConverters._ +import scala.concurrent.duration.* +import scala.jdk.CollectionConverters.* -lazy val (ghOrg: String, ghName: String) = { +def gh: (ghOrg: String, ghName: String) = { def default = ("VirtusLab", "scala-cli") val isCI = System.getenv("CI") != null if (isCI) { @@ -62,7 +62,9 @@ lazy val (ghOrg: String, ghName: String) = { default } -private def computePublishVersion(state: VcsState, simple: Boolean): String = +lazy val (ghOrg: String, ghName: String) = gh + +private def computePublishVersion(state: VcsVersion.State, simple: Boolean): String = if (state.commitsSinceLastTag > 0) if (simple) { val versionOrEmpty = state.lastTag @@ -141,15 +143,18 @@ trait ScalaCliPublishModule extends SonatypeCentralPublishModule with PublishLoc ) override def publishVersion: T[String] = finalPublishVersion() override def sourceJar: T[PathRef] = Task { - import mill.util.Jvm.createJar - val allSources0 = allSources().map(_.path).filter(os.exists).toSet - createJar( - allSources0 ++ resources().map(_.path).filter(os.exists), - manifest(), - (input, relPath) => - !allSources0(input) || - (!relPath.segments.contains(".scala") && !relPath.segments.contains(workspaceDirName)) - ) + PathRef { + import mill.util.Jvm.createJar + val allSources0 = allSources().map(_.path).filter(os.exists) + createJar( + jar = Task.dest / "out.jar", + inputPaths = allSources0 ++ resources().map(_.path).filter(os.exists), + manifest = manifest(), + fileFilter = (input, relPath) => + !allSources0.toSet(input) || + (!relPath.segments.contains(".scala") && !relPath.segments.contains(workspaceDirName)) + ) + } } } @@ -211,7 +216,7 @@ def publishSonatype( publisher.publishAll( publishingType = publishingType, singleBundleName = finalBundleName, - artifacts = artifacts: _* + artifacts = artifacts* ) } @@ -235,7 +240,7 @@ def setShouldPublish() = Task.Command { val charSet = Charset.defaultCharset() val nl = System.lineSeparator() os.write.append( - os.Path(envFile, Task.workspace), + os.Path(envFile, BuildCtx.workspaceRoot), s"SHOULD_PUBLISH=${shouldPublish()}$nl".getBytes(charSet) ) } diff --git a/project/settings/package.mill.scala b/project/settings/package.mill.scala index 1bb925db1f..2951634a17 100644 --- a/project/settings/package.mill.scala +++ b/project/settings/package.mill.scala @@ -1,6 +1,5 @@ package build.project.settings -import $ivy.`com.goyeau::mill-scalafix::0.5.1` -import $ivy.`io.github.alexarchambault.mill::mill-native-image::0.1.31-1` + import build.project.deps import deps.{ Deps, @@ -15,18 +14,18 @@ import build.project.utils import utils.isArmArchitecture import com.goyeau.mill.scalafix.ScalafixModule import coursier.Repository -import de.tobiasroeser.mill.vcs.version.{VcsState, VcsVersion} import io.github.alexarchambault.millnativeimage.NativeImage -import mill._ -import mill.api.Loose -import mill.scalalib._ -import upickle.default._ +import mill.* +import mill.scalalib.* +import upickle.default.* import java.io.File import java.nio.charset.StandardCharsets import java.util.Locale import scala.annotation.unused import scala.util.Properties +import mill.util.{Tasks, VcsVersion} +import mill.api.{BuildCtx, Task} private def isCI = System.getenv("CI") != null @@ -101,12 +100,12 @@ def cs: T[String] = Task(persistent = true) { val archiveCache = coursier.cache.ArchiveCache().withCache(cache) val task = cache.logger.using(archiveCache.get(coursier.util.Artifact(url))) val maybeFile = - try task.unsafeRun()(cache.ec) + try task.unsafeRun()(using cache.ec) catch { case t: Throwable => throw new Exception(s"Error getting and extracting $url", t) } - val f = maybeFile.fold(ex => throw new Exception(ex), os.Path(_, Task.workspace)) + val f = maybeFile.fold(ex => throw new Exception(ex), os.Path(_, BuildCtx.workspaceRoot)) val exec = if (Properties.isWin && os.isDir(f) && f.last.endsWith(".zip")) os.list(f).find(_.last.endsWith(".exe")).getOrElse( @@ -143,6 +142,13 @@ def platformSuffix: String = { def localRepoResourcePath = "local-repo.zip" +trait LocatedInModules extends Module { + override def moduleDir: os.Path = { + val oldModuleDir: os.Path = super.moduleDir + oldModuleDir / os.up / "modules" / oldModuleDir.last + } +} + trait CliLaunchers extends SbtModule { self => def launcherTypeResourcePath: os.RelPath = @@ -150,6 +156,7 @@ trait CliLaunchers extends SbtModule { self => def defaultFilesResourcePath: os.RelPath = os.rel / "scala" / "cli" / "commands" / "publish" trait CliNativeImage extends NativeImage { + override def generateNativeImageWithFileSystemChecker: Boolean = false def writeDefaultNativeImageScript(scriptDest: String): Command[Unit] = Task.Command(super.writeNativeImageScript(scriptDest, "")()) @@ -275,21 +282,23 @@ trait CliLaunchers extends SbtModule { self => proc.call(stdin = os.Inherit, stdout = os.Inherit) } def staticLibDir: T[PathRef] = Task { - val dir = nativeImageDockerWorkingDir() / staticLibDirName - os.makeDir.all(dir) + BuildCtx.withFilesystemCheckerDisabled { + val dir = nativeImageDockerWorkingDir() / staticLibDirName + os.makeDir.all(dir) + + if (Properties.isWin) { + copyLibsodiumStaticTo(cs(), dir, BuildCtx.workspaceRoot) + copyLibsodiumjniTo(cs(), dir, BuildCtx.workspaceRoot) + copyCsjniutilTo(cs(), dir, BuildCtx.workspaceRoot) + } - if (Properties.isWin) { - copyLibsodiumStaticTo(cs(), dir, Task.workspace) - copyLibsodiumjniTo(cs(), dir, Task.workspace) - copyCsjniutilTo(cs(), dir, Task.workspace) - } + if (launcherKind == "static") { + copyAlpineLibsodiumTo(cs(), dir, BuildCtx.workspaceRoot) + copyLibsodiumjniTo(cs(), dir, BuildCtx.workspaceRoot) + } - if (launcherKind == "static") { - copyAlpineLibsodiumTo(cs(), dir, Task.workspace) - copyLibsodiumjniTo(cs(), dir, Task.workspace) + PathRef(dir) } - - PathRef(dir) } } @@ -355,7 +364,7 @@ trait CliLaunchers extends SbtModule { self => } def buildHelperImage: T[Unit] = Task { os.proc("docker", "build", "-t", Docker.customMuslBuilderImageName, ".") - .call(cwd = Task.workspace / "project" / "musl-image", stdout = os.Inherit) + .call(cwd = BuildCtx.workspaceRoot / "project" / "musl-image", stdout = os.Inherit) () } override def writeDefaultNativeImageScript(scriptDest: String): Command[Unit] = @@ -383,7 +392,7 @@ trait CliLaunchers extends SbtModule { self => mainClass().getOrElse(sys.error("Don't know what main class to use")) } - def transitiveJarsAgg: T[Agg[PathRef]] = { + def transitiveJarsSeq: T[Seq[PathRef]] = { def allModuleDeps(todo: List[JavaModule]): List[JavaModule] = todo match { case Nil => Nil @@ -392,7 +401,7 @@ trait CliLaunchers extends SbtModule { self => } Task { - mill.define.Task.traverse(allModuleDeps(this :: Nil).distinct)(m => + Task.traverse(allModuleDeps(this :: Nil).distinct)(m => Task.Anon(m.jar()) )() } @@ -429,11 +438,13 @@ trait CliLaunchers extends SbtModule { self => cp, mainClass0 ) ++ args - os.proc(command.map(x => x: os.Shellable): _*).call( + os.proc(command.map(x => x: os.Shellable)*).call( stdin = os.Inherit, stdout = os.Inherit ) - Task.log.streams.out.println(s"Config generated in ${outputDir.relativeTo(Task.workspace)}") + Task.log.streams.out.println( + s"Config generated in ${outputDir.relativeTo(BuildCtx.workspaceRoot)}" + ) } @unused @@ -441,7 +452,7 @@ trait CliLaunchers extends SbtModule { self => val cp = jarClassPath().map(_.path).mkString(File.pathSeparator) val mainClass0 = mainClass().getOrElse(sys.error("No main class")) val command = Seq("java", "-cp", cp, mainClass0) ++ args - os.proc(command.map(x => x: os.Shellable): _*).call( + os.proc(command.map(x => x: os.Shellable)*).call( stdin = os.Inherit, stdout = os.Inherit ) @@ -452,7 +463,7 @@ trait CliLaunchers extends SbtModule { self => } def jarClassPath: T[Seq[PathRef]] = Task { - val cp = runClasspath() ++ transitiveJarsAgg() + val cp = runClasspath() ++ transitiveJarsSeq() cp.filter(ref => os.exists(ref.path) && !os.isDir(ref.path)) } @@ -480,7 +491,7 @@ trait CliLaunchers extends SbtModule { self => } def standaloneLauncher: T[PathRef] = Task { - val cachePath = os.Path(coursier.cache.FileCache().location, Task.workspace) + val cachePath = os.Path(coursier.cache.FileCache().location, BuildCtx.workspaceRoot) def urlOf(path: os.Path): Option[String] = if (path.startsWith(cachePath)) { val segments = path.relativeTo(cachePath).segments @@ -532,7 +543,7 @@ trait HasTests extends SbtModule { super.scalacOptions() ++ extraOptions } trait ScalaCliTests extends ScalaCliModule with super.SbtTests with TestModule.Munit { - override def ivyDeps: T[Agg[Dep]] = super.ivyDeps() ++ Agg( + override def mvnDeps: T[Seq[Dep]] = super.mvnDeps() ++ Seq( Deps.expecty, Deps.munit ) @@ -559,23 +570,23 @@ trait PublishLocalNoFluff extends SonatypeCentralPublishModule { } // adapted from https://github.com/com-lihaoyi/mill/blob/fea79f0515dda1def83500f0f49993e93338c3de/scalalib/src/PublishModule.scala#L70-L85 // writes empty zips as source and doc JARs - def publishLocalNoFluff(localIvyRepo: String = null): define.Command[PathRef] = Task.Command { + def publishLocalNoFluff(localIvyRepo: String = null): Command[PathRef] = Task.Command { import mill.scalalib.publish.LocalIvyPublisher val publisher = localIvyRepo match { case null => LocalIvyPublisher case repo => - new LocalIvyPublisher(os.Path(repo.replace("{VERSION}", publishVersion()), Task.workspace)) + new LocalIvyPublisher(os.Path( + repo.replace("{VERSION}", publishVersion()), + BuildCtx.workspaceRoot + )) } publisher.publishLocal( - jar = jar().path, - sourcesJar = emptyZip().path, - docJar = emptyZip().path, pom = pom().path, - ivy = ivy().path, + ivy = Right(ivy().path), artifact = artifactMetadata(), - extras = extraPublish() + publishInfos = Seq.empty ) jar() @@ -586,13 +597,13 @@ trait LocalRepo extends Module { def stubsModules: Seq[PublishLocalNoFluff] def version: T[String] - def localRepo: T[Seq[PathRef]] = Task { - val repoRoot = os.rel / "out" / "repo" / "{VERSION}" - val tasks = stubsModules.map(_.publishLocalNoFluff(repoRoot.toString)) - define.Task.sequence(tasks) + def localRepo: T[Seq[PathRef]] = { + val repoRoot = os.rel / "out" / "repo" / "{VERSION}" + val tasks: Seq[Command[PathRef]] = stubsModules.map(_.publishLocalNoFluff(repoRoot.toString)) + Task.sequence(tasks)() } - private def vcsState: T[VcsState] = + private def vcsState: T[VcsVersion.State] = if (isCI) Task(persistent = true) { VcsVersion.vcsState() @@ -605,45 +616,47 @@ trait LocalRepo extends Module { val repoVer = vcsState().format() val ver = version() localRepo() - val repoDir = Task.workspace / "out" / "repo" / ver + val repoDir = BuildCtx.workspaceRoot / "out" / "repo" / ver val destDir = Task.dest / ver / "repo.zip" val dest = destDir / "repo.zip" - import java.io._ - import java.util.zip._ - os.makeDir.all(destDir) - var fos: FileOutputStream = null - var zos: ZipOutputStream = null - try { - fos = new FileOutputStream(dest.toIO) - zos = new ZipOutputStream(new BufferedOutputStream(fos)) - - val versionEntry = new ZipEntry("version") - versionEntry.setTime(0L) - zos.putNextEntry(versionEntry) - zos.write(repoVer.getBytes(StandardCharsets.UTF_8)) - zos.flush() - - os.walk(repoDir).filter(_ != repoDir).foreach { p => - val isDir = os.isDir(p) - val name = p.relativeTo(repoDir).toString + (if (isDir) "/" else "") - val entry = new ZipEntry(name) - entry.setTime(os.mtime(p)) - zos.putNextEntry(entry) - if (!isDir) { - zos.write(os.read.bytes(p)) - zos.flush() + BuildCtx.withFilesystemCheckerDisabled { + import java.io._ + import java.util.zip._ + os.makeDir.all(destDir) + var fos: FileOutputStream = null + var zos: ZipOutputStream = null + try { + fos = new FileOutputStream(dest.toIO) + zos = new ZipOutputStream(new BufferedOutputStream(fos)) + + val versionEntry = new ZipEntry("version") + versionEntry.setTime(0L) + zos.putNextEntry(versionEntry) + zos.write(repoVer.getBytes(StandardCharsets.UTF_8)) + zos.flush() + + os.walk(repoDir).filter(_ != repoDir).foreach { p => + val isDir = os.isDir(p) + val name = p.relativeTo(repoDir).toString + (if (isDir) "/" else "") + val entry = new ZipEntry(name) + entry.setTime(os.mtime(p)) + zos.putNextEntry(entry) + if (!isDir) { + zos.write(os.read.bytes(p)) + zos.flush() + } + zos.closeEntry() } - zos.closeEntry() + zos.finish() + } + finally { + if (zos != null) zos.close() + if (fos != null) fos.close() } - zos.finish() - } - finally { - if (zos != null) zos.close() - if (fos != null) fos.close() - } - PathRef(dest) + PathRef(dest) + } } def localRepoJar: T[PathRef] = Task { @@ -703,12 +716,12 @@ private def doFormatNativeImageConf(dir: os.Path, format: Boolean): List[os.Path entries -= "methods" ujson.Obj(entries) } - ujson.Arr(values: _*) + ujson.Arr(values*) } else if (sortByName(name)) json.arrOpt.fold(json) { arr => val values = arr.toVector.sortBy(_("name").str) - ujson.Arr(values: _*) + ujson.Arr(values*) } else json @@ -750,7 +763,7 @@ trait FormatNativeImageConf extends JavaModule { for (f <- needsFormatting) System.err.println( s" ${ - if (f.startsWith(Task.workspace)) f.relativeTo(Task.workspace).toString + if (f.startsWith(BuildCtx.workspaceRoot)) f.relativeTo(BuildCtx.workspaceRoot).toString else f.toString }" ) @@ -776,20 +789,20 @@ trait ScalaCliScalafixModule extends ScalafixModule { override def semanticDbVersion: T[String] = Deps.Versions.scalaMeta - def scalafixConfig: T[Option[os.Path]] = Task { + override def scalafixConfig: T[Option[os.Path]] = Task { if (scalaVersion().startsWith("2.")) super.scalafixConfig() - else Some(Task.workspace / ".scalafix3.conf") + else Some(BuildCtx.workspaceRoot / ".scalafix3.conf") } - def scalacPluginIvyDeps: T[Loose.Agg[Dep]] = super.scalacPluginIvyDeps() ++ { + override def scalacPluginMvnDeps: T[Seq[Dep]] = super.scalacPluginMvnDeps() ++ { if (scalaVersion().startsWith("2.")) Seq(Deps.semanticDbScalac) else Nil } // Explicitly setting sourceroot, so that Scala CLI doesn't use a wrong one. - // Using Task.workspace is more or less required, for scalafix stuff to work fine. - def scalacOptions: T[Seq[String]] = Task { + // Using BuildCtx.workspaceRoot is more or less required, for scalafix stuff to work fine. + override def scalacOptions: T[Seq[String]] = Task { val sv = scalaVersion() val isScala2 = sv.startsWith("2.") - val sourceRoot = Task.workspace + val sourceRoot = BuildCtx.workspaceRoot val parentOptions = { val l = super.scalacOptions() if (isScala2) l.filterNot(_.startsWith("-P:semanticdb:sourceroot:")) @@ -818,7 +831,7 @@ trait ScalaCliScalafixModule extends ScalafixModule { // meant to be used with modules which still have to be cross-compiled on Scala 2.12 trait ScalaCliScalafixLegacyModule extends ScalaCliScalafixModule { override def scalafixConfig: T[Option[os.Path]] = Task { - Some(Task.workspace / ".scalafix.legacy.conf") + Some(BuildCtx.workspaceRoot / ".scalafix.legacy.conf") } }