diff --git a/.github/scripts/build-linux-aarch64-from-docker.sh b/.github/scripts/build-linux-aarch64-from-docker.sh index 0f9c0d974d..ad33bd5390 100755 --- a/.github/scripts/build-linux-aarch64-from-docker.sh +++ b/.github/scripts/build-linux-aarch64-from-docker.sh @@ -11,7 +11,7 @@ eval "$(cs java --env --jvm temurin:17 --jvm-index https://github.com/coursier/j git config --global --add safe.directory "$(pwd)" -./mill -i show cli.nativeImage +./mill -i show 'cli[]'.nativeImage ./mill -i copyDefaultLauncher ./artifacts if "true" == $(./mill -i ci.shouldPublish); then .github/scripts/generate-os-packages.sh diff --git a/.github/scripts/generate-docker-image.sh b/.github/scripts/generate-docker-image.sh index 7bf7958a15..3ff00ce82a 100755 --- a/.github/scripts/generate-docker-image.sh +++ b/.github/scripts/generate-docker-image.sh @@ -5,7 +5,7 @@ ROOT="$(cd "$(dirname "$0")/../.." && pwd)" WORKDIR="$ROOT/out/docker-workdir" mkdir -p "$WORKDIR" -./mill -i copyTo cli.nativeImageStatic "$WORKDIR/scala-cli" 1>&2 +./mill -i copyTo 'cli[]'.nativeImageStatic "$WORKDIR/scala-cli" 1>&2 cd "$WORKDIR" docker build -t scala-cli -f "$ROOT/.github/scripts/docker/ScalaCliDockerFile" . diff --git a/.github/scripts/generate-native-image.sh b/.github/scripts/generate-native-image.sh index fecdd84ecd..f9a48629ce 100755 --- a/.github/scripts/generate-native-image.sh +++ b/.github/scripts/generate-native-image.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -COMMAND="cli.base-image.writeNativeImageScript" +COMMAND="cli[].base-image.writeNativeImageScript" # temporary, until we pass JPMS options to native-image, # see https://www.graalvm.org/release-notes/22_2/#native-image @@ -20,7 +20,7 @@ if [[ "$OSTYPE" == "msys" ]]; then else if [ $# == "0" ]; then if [[ "$OSTYPE" == "linux-gnu" ]]; then - COMMAND="cli.linux-docker-image.writeNativeImageScript" + COMMAND="cli[].linux-docker-image.writeNativeImageScript" CLEANUP=("sudo" "rm" "-rf" "out/cli/linux-docker-image/nativeImageDockerWorkingDir") else CLEANUP=("true") @@ -28,11 +28,11 @@ else else case "$1" in "static") - COMMAND="cli.static-image.writeNativeImageScript" + COMMAND="cli[].static-image.writeNativeImageScript" CLEANUP=("sudo" "rm" "-rf" "out/cli/static-image/nativeImageDockerWorkingDir") ;; "mostly-static") - COMMAND="cli.mostly-static-image.writeNativeImageScript" + COMMAND="cli[].mostly-static-image.writeNativeImageScript" CLEANUP=("sudo" "rm" "-rf" "out/cli/mostly-static-image/nativeImageDockerWorkingDir") ;; *) diff --git a/.github/scripts/generate-os-packages.sh b/.github/scripts/generate-os-packages.sh index 059a3f575c..1b2181bc22 100755 --- a/.github/scripts/generate-os-packages.sh +++ b/.github/scripts/generate-os-packages.sh @@ -25,7 +25,7 @@ packager() { } launcher() { - local launcherMillCommand="cli.nativeImage" + local launcherMillCommand="cli[].nativeImage" local launcherName if [[ "${OS-}" == "Windows_NT" ]]; then diff --git a/.github/scripts/generate-slim-docker-image.sh b/.github/scripts/generate-slim-docker-image.sh index f6bc6a3cfd..a648683fd4 100755 --- a/.github/scripts/generate-slim-docker-image.sh +++ b/.github/scripts/generate-slim-docker-image.sh @@ -5,7 +5,7 @@ ROOT="$(cd "$(dirname "$0")/../.." && pwd)" WORKDIR="$ROOT/out/docker-slim-workdir" mkdir -p "$WORKDIR" -./mill -i copyTo cli.nativeImageMostlyStatic "$WORKDIR/scala-cli" 1>&2 +./mill -i copyTo 'cli[]'.nativeImageMostlyStatic "$WORKDIR/scala-cli" 1>&2 cd "$WORKDIR" docker build -t scala-cli-slim -f "$ROOT/.github/scripts/docker/ScalaCliSlimDockerFile" . diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cfa27f899..a2c6978759 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -912,7 +912,7 @@ jobs: - name: Build documentation run: .github/scripts/build-website.sh - name: Test documentation - run: ./mill -i docs-tests.test + run: ./mill -i 'docs-tests[]'.test - name: Convert Mill test reports to JUnit XML format if: success() || failure() run: .github/scripts/generate-junit-reports.sc docs-tests 'Scala CLI Docs Tests' test-report.xml out/ @@ -975,9 +975,9 @@ jobs: jvm: "temurin:17" - name: Check that reference doc is up-to-date run: | - ./mill -i generate-reference-doc.run --check || ( + ./mill -i 'generate-reference-doc[]'.run --check || ( echo "Reference doc is not up-to-date. Run" - echo " ./mill -i generate-reference-doc.run" + echo " ./mill -i 'generate-reference-doc[]'.run" echo "to update it, then commit the result." exit 1 ) diff --git a/.scala-steward.conf b/.scala-steward.conf index a269222420..9b2032e729 100644 --- a/.scala-steward.conf +++ b/.scala-steward.conf @@ -3,6 +3,6 @@ updates.ignore = [ { groupId = "com.github.plokhotnyuk.jsoniter-scala", artifactId="jsoniter-scala-core", version="2.13.5.2" } ] postUpdateHooks = [{ - command = ["./mill", "-i", "generate-reference-doc.run"], + command = ["./mill", "-i", "'generate-reference-doc[]'.run"], commitMessage = "Generate the reference doc" }] \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5e81926269..08fa9c9af0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,7 +47,7 @@ will save you from getting a load of comments and speed up the code review. - ensure everything compiles at every commit (`./mill -i __.compile`); - ensure everything is well formatted at every commit (`scala-cli fmt .` or `scalafmt`); - ensure imports are well-ordered at every commit (`./mill -i __.fix`); - - ensure reference docs are up-to date at every commit (`./mill -i generate-reference-doc.run`); + - ensure reference docs are up-to date at every commit (`./mill -i 'generate-reference-doc[]'.run`); - ensure all tests pass at every commit (refer to the [dev docs](DEV.md) on how to run tests); - nobody expects you to run all the unit and integration tests for all platforms locally, that'd take too long; - just make sure the test suites relevant to your changes pass on your local machine. diff --git a/DEV.md b/DEV.md index e6ec7173a6..a088bfc08e 100644 --- a/DEV.md +++ b/DEV.md @@ -13,18 +13,29 @@ The Scala CLI sources ship with Mill launchers, so that Mill itself doesn't need #### Running the CLI from sources +Run the `scala` target with Mill: ```bash ./mill -i scala …arguments… ``` +This is the equivalent of running the `cli` task with the default Scala version: +```bash +./mill -i 'cli[]'.run …arguments… +``` + #### Debugging the CLI from sources ```bash ./mill -i debug debug-port …arguments… ``` + +which is short for: +```bash +./mill -i 'cli[]'.debug debug-port …arguments… +``` E.g: ```bash -./mill -i cli.debug 5050 ~/Main.scala -S 3.3.0 +./mill -i 'cli[]'.debug 5050 ~/Main.scala -S 3.3.0 ``` #### Run unit tests @@ -129,7 +140,7 @@ Otherwise, some IDE features may not work correctly, i.e. the debugger might cra #### Generate a native launcher ```bash -./mill -i show cli.nativeImage +./mill -i show 'cli[]'.nativeImage ``` This prints the path to the generated native image. @@ -140,7 +151,7 @@ whether the files it points at exists or not.) #### Generate a JVM launcher ```bash -./mill -i show cli.launcher +./mill -i show 'cli[]'.launcher ``` This prints the path to the generated launcher. This launcher is a JAR, @@ -153,7 +164,7 @@ JVM one (see below). #### Generate a standalone JVM launcher ```bash -./mill -i show cli.standaloneLauncher +./mill -i show 'cli[]'.standaloneLauncher ``` This prints the path to the generated launcher. This launcher is a JAR, @@ -224,36 +235,36 @@ We have a built-in tool to validate `.md` files called [Sclicheck](/sclicheck/Re All `Sclicheck` tests can be run with `Mill` + `munit`: (and this is what we run on the CI, too) ```bash -./mill -i docs-tests.test +./mill -i 'docs-tests[]'.test ``` The former also includes testing gifs and `Sclicheck` itself. To just check the documents, run: ```bash -./mill -i docs-tests.test 'sclicheck.DocTests.*' +./mill -i 'docs-tests[]'.test 'sclicheck.DocTests.*' ``` You can also check all root docs, commands, reference docs, guides or cookbooks: ```bash -./mill -i docs-tests.test 'sclicheck.DocTests.root*' -./mill -i docs-tests.test 'sclicheck.DocTests.guide*' -./mill -i docs-tests.test 'sclicheck.DocTests.command*' -./mill -i docs-tests.test 'sclicheck.DocTests.cookbook*' -./mill -i docs-tests.test 'sclicheck.DocTests.reference*' +./mill -i 'docs-tests[]'.test 'sclicheck.DocTests.root*' +./mill -i 'docs-tests[]'.test 'sclicheck.DocTests.guide*' +./mill -i 'docs-tests[]'.test 'sclicheck.DocTests.command*' +./mill -i 'docs-tests[]'.test 'sclicheck.DocTests.cookbook*' +./mill -i 'docs-tests[]'.test 'sclicheck.DocTests.reference*' ``` Similarly, you can check single files: ```bash -./mill -i docs-tests.test 'sclicheck.DocTests. ' +./mill -i 'docs-tests[]'.test 'sclicheck.DocTests. ' ``` For example, to run the check on `compile.md` ```bash -./mill -i docs-tests.test 'sclicheck.DocTests.command compile' +./mill -i 'docs-tests[]'.test 'sclicheck.DocTests.command compile' ``` ## Scala CLI logos @@ -296,7 +307,7 @@ image. To generate the relevant configuration automatically, you can run: ```bash -./mill -i cli.runWithAssistedConfig +./mill -i 'cli[]'.runWithAssistedConfig ``` Just make sure to run it exactly the same as the native image would have been run, as the configuration is generated for @@ -304,7 +315,7 @@ a particular invocation path. The run has to succeed as well, as the configurati exit code 0. ```text -Config generated in out/cli/runWithAssistedConfig.dest/config +Config generated in out/cli//runWithAssistedConfig.dest/config ``` As a result, you should get the path to the generated configuration file. It might contain some unnecessary entries, so diff --git a/build.sc b/build.sc index 570f60025c..7a1a174f94 100644 --- a/build.sc +++ b/build.sc @@ -37,32 +37,15 @@ import _root_.scala.util.{Properties, Using} implicit def millModuleBasePath: define.Ctx.BasePath = define.Ctx.BasePath(super.millModuleBasePath.value / "modules") -object cli extends Cli { - // 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] = T.task(Args())): Command[Unit] = T.command { - try mill.api.Result.Success( - mill.util.Jvm.runSubprocess( - finalMainClass(), - runClasspath().map(_.path), - forkArgs() ++ Seq( - s"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=$port,quiet=y" - ), - forkEnv(), - args().value, - workingDir = forkWorkingDir(), - useCpPassingJar = runUseArgsFile() - ) - ) - catch { - case e: Exception => - mill.api.Result.Failure("subprocess failed") - } - } +object cli extends Cross[Cli](Scala.scala3MainVersions) with CrossScalaDefaultToInternal + +trait CrossScalaDefaultToInternal { _: mill.define.Cross[_] => + def defaultCrossSegments = Seq(Scala.defaultInternal) } // Publish a bootstrapped, executable jar for a restricted environments object cliBootstrapped extends ScalaCliPublishModule { - override def unmanagedClasspath = T(cli.nativeImageClassPath()) + override def unmanagedClasspath = T(cli(Scala.defaultInternal).nativeImageClassPath()) override def jar = assembly() import mill.scalalib.Assembly @@ -89,21 +72,29 @@ object cliBootstrapped extends ScalaCliPublishModule { } object `specification-level` extends Cross[SpecificationLevel](Scala.all) -object `build-macros` extends BuildMacros -object config extends Cross[Config](Scala.all) -object options extends Options -object directives extends Directives -object core extends Core -object `build-module` extends Build -object runner extends Cross[Runner](Scala.runnerScalaVersions) -object `test-runner` extends Cross[TestRunner](Scala.runnerScalaVersions :+ Scala.scala3) -object `tasty-lib` extends Cross[TastyLib](Scala.all) + with CrossScalaDefaultToInternal +object `build-macros` extends Cross[BuildMacros](Scala.scala3MainVersions) + with CrossScalaDefaultToInternal +object config extends Cross[Config](Scala.all) with CrossScalaDefaultToInternal +object options extends Cross[Options](Scala.scala3MainVersions) with CrossScalaDefaultToInternal +object directives extends Cross[Directives](Scala.scala3MainVersions) + with CrossScalaDefaultToInternal +object core extends Cross[Core](Scala.scala3MainVersions) with CrossScalaDefaultToInternal +object `build-module` extends Cross[Build](Scala.scala3MainVersions) + with CrossScalaDefaultToInternal +object runner extends Cross[Runner](Scala.runnerScalaVersions) with CrossScalaDefaultToInternal +object `test-runner` extends Cross[TestRunner](Scala.testRunnerScalaVersions) + with CrossScalaDefaultToInternal +object `tasty-lib` extends Cross[TastyLib](Scala.all) with CrossScalaDefaultToInternal // Runtime classes used within native image on Scala 3 replacing runtime from Scala -object `scala3-runtime` extends Scala3Runtime +object `scala3-runtime` extends Cross[Scala3Runtime](Scala.scala3MainVersions) + with CrossScalaDefaultToInternal // Logic to process classes that is shared between build and the scala-cli itself object `scala3-graal` extends Cross[Scala3Graal](Scala.mainVersions) + with CrossScalaDefaultToInternal // Main app used to process classpath within build itself -object `scala3-graal-processor` extends Scala3GraalProcessor +object `scala3-graal-processor` extends Cross[Scala3GraalProcessor](Scala.scala3MainVersions) + with CrossScalaDefaultToInternal object `scala-cli-bsp` extends JavaModule with ScalaCliPublishModule { def ivyDeps = super.ivyDeps() ++ Seq( @@ -151,8 +142,10 @@ object integration extends CliIntegration { } } -object `docs-tests` extends SbtModule with ScalaCliScalafixModule with HasTests { main => - def scalaVersion = Scala.defaultInternal +object `docs-tests` extends Cross[DocsTests](Scala.scala3MainVersions) + with CrossScalaDefaultToInternal + +trait DocsTests extends CrossSbtModule with ScalaCliScalafixModule with HasTests { main => def ivyDeps = Agg( Deps.fansi, Deps.osLib, @@ -163,7 +156,7 @@ object `docs-tests` extends SbtModule with ScalaCliScalafixModule with HasTests } def extraEnv = T { Seq( - "SCLICHECK_SCALA_CLI" -> cli.standaloneLauncher().path.toString, + "SCLICHECK_SCALA_CLI" -> cli(crossScalaVersion).standaloneLauncher().path.toString, "SCALA_CLI_CONFIG" -> (tmpDirBase().path / "config" / "config.json").toString ) } @@ -196,10 +189,12 @@ object packager extends ScalaModule with Bloop.Module { def mainClass = Some("packager.cli.PackagerCli") } -object `generate-reference-doc` extends SbtModule with ScalaCliScalafixModule { - def scalaVersion = Scala.defaultInternal +object `generate-reference-doc` extends Cross[GenerateReferenceDoc](Scala.scala3MainVersions) + with CrossScalaDefaultToInternal + +trait GenerateReferenceDoc extends CrossSbtModule with ScalaCliScalafixModule { def moduleDeps = Seq( - cli + cli(crossScalaVersion) ) def repositoriesTask = T.task(super.repositoriesTask() ++ customRepositories) def ivyDeps = Agg( @@ -247,18 +242,14 @@ object dummy extends Module { } } -trait BuildMacros extends ScalaCliSbtModule +trait BuildMacros extends ScalaCliCrossSbtModule with ScalaCliPublishModule with ScalaCliScalafixModule with HasTests { - def scalaVersion = Scala.defaultInternal + def crossScalaVersion = crossValue def compileIvyDeps = T { - if (scalaVersion().startsWith("3")) - super.compileIvyDeps() - else - super.compileIvyDeps() ++ Agg( - Deps.scalaReflect(scalaVersion()) - ) + if (crossScalaVersion.startsWith("3")) super.compileIvyDeps() + else super.compileIvyDeps() ++ Agg(Deps.scalaReflect(crossScalaVersion)) } object test extends ScalaCliTests { @@ -331,22 +322,19 @@ def asyncScalacOptions(scalaVersion: String) = trait ProtoBuildModule extends ScalaCliPublishModule with HasTests with ScalaCliScalafixModule -private def prefer3(sv: String): String = - if (sv == Scala.scala213) Scala.scala3 - else sv - -trait Core extends ScalaCliSbtModule with ScalaCliPublishModule with HasTests +trait Core extends ScalaCliCrossSbtModule + with ScalaCliPublishModule + with HasTests with ScalaCliScalafixModule { - private def scalaVer = Scala.defaultInternal - def scalaVersion = scalaVer + def crossScalaVersion = crossValue def moduleDeps = Seq( - config(scalaVer) + config(crossScalaVersion) ) def compileModuleDeps = Seq( - `build-macros` + `build-macros`(crossScalaVersion) ) def scalacOptions = T { - super.scalacOptions() ++ asyncScalacOptions(scalaVersion()) + super.scalacOptions() ++ asyncScalacOptions(crossScalaVersion) } def ivyDeps = super.ivyDeps() ++ Agg( @@ -452,7 +440,7 @@ trait Core extends ScalaCliSbtModule with ScalaCliPublishModule with HasTests | def defaultScalaVersion = "${Scala.defaultUser}" | def defaultScala212Version = "${Scala.scala212}" | def defaultScala213Version = "${Scala.scala213}" - | def scala3Lts = "${Scala.scala3Lts}" + | def scala3LtsPrefix = "${Scala.scala3LtsPrefix}" | | def workspaceDirName = "$workspaceDirName" | def projectFileName = "$projectFileName" @@ -489,17 +477,19 @@ trait Core extends ScalaCliSbtModule with ScalaCliPublishModule with HasTests def generatedSources = super.generatedSources() ++ Seq(constantsFile()) } -trait Directives extends ScalaCliSbtModule with ScalaCliPublishModule with HasTests +trait Directives extends ScalaCliCrossSbtModule + with ScalaCliPublishModule + with HasTests with ScalaCliScalafixModule { - def scalaVersion = Scala.defaultInternal + def crossScalaVersion = crossValue def moduleDeps = Seq( - options, - core, - `build-macros`, - `specification-level`(Scala.scala3) + options(crossScalaVersion), + core(crossScalaVersion), + `build-macros`(crossScalaVersion), + `specification-level`(crossScalaVersion) ) def scalacOptions = T { - super.scalacOptions() ++ asyncScalacOptions(scalaVersion()) + super.scalacOptions() ++ asyncScalacOptions(crossScalaVersion) } def compileIvyDeps = super.compileIvyDeps() ++ Agg( @@ -578,17 +568,17 @@ trait Config extends ScalaCliCrossSbtModule else T.command(()) } -trait Options extends ScalaCliSbtModule with ScalaCliPublishModule with HasTests +trait Options extends ScalaCliCrossSbtModule with ScalaCliPublishModule with HasTests with ScalaCliScalafixModule { - def scalaVersion = Scala.defaultInternal + def crossScalaVersion = crossValue def moduleDeps = Seq( - core + core(crossScalaVersion) ) def compileModuleDeps = Seq( - `build-macros` + `build-macros`(crossScalaVersion) ) def scalacOptions = T { - super.scalacOptions() ++ asyncScalacOptions(scalaVersion()) + super.scalacOptions() ++ asyncScalacOptions(crossScalaVersion) } def ivyDeps = super.ivyDeps() ++ Agg( @@ -610,9 +600,9 @@ trait Options extends ScalaCliSbtModule with ScalaCliPublishModule with HasTests } } -trait Scala3Runtime extends SbtModule with ScalaCliPublishModule { - def ivyDeps = super.ivyDeps() - def scalaVersion = Scala.scala3 +trait Scala3Runtime extends CrossSbtModule with ScalaCliPublishModule { + def crossScalaVersion = crossValue + def ivyDeps = super.ivyDeps() } trait Scala3Graal extends ScalaCliCrossSbtModule @@ -628,7 +618,7 @@ trait Scala3Graal extends ScalaCliCrossSbtModule // scala3RuntimeFixes.jar is also used within // resource-config.json and BytecodeProcessor.scala os.copy.over( - `scala3-runtime`.jar().path, + `scala3-runtime`(crossScalaVersion).jar().path, extraResourceDir / "scala3RuntimeFixes.jar", createFolders = true ) @@ -636,26 +626,26 @@ trait Scala3Graal extends ScalaCliCrossSbtModule } } -trait Scala3GraalProcessor extends ScalaModule with ScalaCliPublishModule { - def moduleDeps = Seq(`scala3-graal`(Scala.scala3)) - def scalaVersion = Scala.scala3 +trait Scala3GraalProcessor extends CrossScalaModule with ScalaCliPublishModule { + def moduleDeps = Seq(`scala3-graal`(crossScalaVersion)) def finalMainClass = "scala.cli.graal.CoursierCacheProcessor" } -trait Build extends ScalaCliSbtModule with ScalaCliPublishModule with HasTests +trait Build extends ScalaCliCrossSbtModule + with ScalaCliPublishModule + with HasTests with ScalaCliScalafixModule { - private def scalaVer = Scala.defaultInternal - def scalaVersion = scalaVer - def millSourcePath = super.millSourcePath / os.up / "build" + def crossScalaVersion = crossValue + def millSourcePath = super.millSourcePath / os.up / "build" def moduleDeps = Seq( - options, - directives, + options(crossScalaVersion), + directives(crossScalaVersion), `scala-cli-bsp`, - `test-runner`(scalaVer), - `tasty-lib`(scalaVer) + `test-runner`(crossScalaVersion), + `tasty-lib`(crossScalaVersion) ) def scalacOptions = T { - super.scalacOptions() ++ asyncScalacOptions(scalaVersion()) + super.scalacOptions() ++ asyncScalacOptions(crossScalaVersion) } def compileIvyDeps = super.compileIvyDeps() ++ Agg( @@ -736,8 +726,28 @@ trait SpecificationLevel extends ScalaCliCrossSbtModule } } -trait Cli extends SbtModule with ProtoBuildModule with CliLaunchers +trait Cli extends CrossSbtModule with ProtoBuildModule with CliLaunchers with FormatNativeImageConf { + // 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] = T.task(Args())): Command[Unit] = T.command { + try mill.api.Result.Success( + mill.util.Jvm.runSubprocess( + finalMainClass(), + runClasspath().map(_.path), + forkArgs() ++ Seq( + s"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=$port,quiet=y" + ), + forkEnv(), + args().value, + workingDir = forkWorkingDir(), + useCpPassingJar = runUseArgsFile() + ) + ) + catch { + case e: Exception => + mill.api.Result.Failure("subprocess failed") + } + } def constantsFile = T.persistent { val dir = T.dest / "constants" @@ -816,21 +826,17 @@ trait Cli extends SbtModule with ProtoBuildModule with CliLaunchers super.resources() ++ Seq(defaultFilesResources()) } - private def myScalaVersion: String = Scala.defaultInternal - - def scalaVersion = T(myScalaVersion) - def scalacOptions = T { - super.scalacOptions() ++ asyncScalacOptions(scalaVersion()) + super.scalacOptions() ++ asyncScalacOptions(crossScalaVersion) } def javacOptions = T { super.javacOptions() ++ Seq("--release", "16") } def moduleDeps = Seq( - `build-module`, - config(Scala.scala3), - `scala3-graal`(Scala.scala3), - `specification-level`(Scala.scala3) + `build-module`(crossScalaVersion), + config(crossScalaVersion), + `scala3-graal`(crossScalaVersion), + `specification-level`(crossScalaVersion) ) def repositoriesTask = T.task(super.repositoriesTask() ++ customRepositories) @@ -862,8 +868,8 @@ trait Cli extends SbtModule with ProtoBuildModule with CliLaunchers val cache = T.dest / "native-cp" // `scala3-graal-processor`.run() do not give me output and I cannot pass dynamically computed values like classpath val res = mill.util.Jvm.callSubprocess( - mainClass = `scala3-graal-processor`.finalMainClass(), - classPath = `scala3-graal-processor`.runClasspath().map(_.path), + mainClass = `scala3-graal-processor`(crossScalaVersion).finalMainClass(), + classPath = `scala3-graal-processor`(crossScalaVersion).runClasspath().map(_.path), mainArgs = Seq(cache.toNIO.toString, classpath), workingDir = os.pwd ) @@ -875,7 +881,7 @@ trait Cli extends SbtModule with ProtoBuildModule with CliLaunchers object test extends ScalaCliTests with ScalaCliScalafixModule { def moduleDeps = super.moduleDeps ++ Seq( - `build-module`.test + `build-module`(crossScalaVersion).test ) def runClasspath = T { super.runClasspath() ++ Seq(localRepoJar()) @@ -948,39 +954,43 @@ trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests | |/** Build-time constants. Generated by mill. */ |object Constants { - | def bspVersion = "${Deps.bsp4j.dep.version}" - | def scala212 = "${Scala.scala212}" - | def scala213 = "${Scala.scala213}" - | def scalaSnapshot213 = "${TestDeps.scalaSnapshot213}" - | def scala3 = "${Scala.scala3}" - | def defaultScala = "${Scala.defaultUser}" - | def defaultScalafmtVersion = "${Deps.scalafmtCli.dep.version}" + | def bspVersion = "${Deps.bsp4j.dep.version}" + | def scala212 = "${Scala.scala212}" + | def scala213 = "${Scala.scala213}" + | def scalaSnapshot213 = "${TestDeps.scalaSnapshot213}" + | def scala3Lts = "${Scala.scala3Lts}" + | def scala3Next = "${Scala.scala3Next}" + | def defaultScala = "${Scala.defaultUser}" + | def defaultScalafmtVersion = "${Deps.scalafmtCli.dep.version}" | def maxAmmoniteScala212Version = "${Scala.maxAmmoniteScala212Version}" | def maxAmmoniteScala213Version = "${Scala.maxAmmoniteScala213Version}" | def maxAmmoniteScala3Version = "${Scala.maxAmmoniteScala3Version}" - | def scalaJsVersion = "${Scala.scalaJs}" - | def scalaJsCliVersion = "${Scala.scalaJsCli}" - | def scalaNativeVersion = "${Deps.nativeTools.dep.version}" - | def ammoniteVersion = "${Deps.ammonite.dep.version}" - | def defaultGraalVMJavaVersion = "${deps.graalVmJavaVersion}" - | def defaultGraalVMVersion = "${deps.graalVmVersion}" - | def scalaPyVersion = "${Deps.scalaPy.dep.version}" - | def bloopVersion = "${Deps.bloopRifle.dep.version}" - | def pprintVersion = "${TestDeps.pprint.dep.version}" - | def munitVersion = "${TestDeps.munit.dep.version}" - | def dockerTestImage = "${Docker.testImage}" - | def dockerAlpineTestImage = "${Docker.alpineTestImage}" - | def authProxyTestImage = "${Docker.authProxyTestImage}" - | def mostlyStaticDockerfile = "${mostlyStaticDockerfile.toString.replace("\\", "\\\\")}" - | def cs = "${settings.cs().replace("\\", "\\\\")}" - | def workspaceDirName = "$workspaceDirName" - | def libsodiumVersion = "${deps.libsodiumVersion}" - | def dockerArchLinuxImage = "${TestDeps.archLinuxImage}" + | def scalaJsVersion = "${Scala.scalaJs}" + | def scalaJsCliVersion = "${Scala.scalaJsCli}" + | def scalaNativeVersion = "${Deps.nativeTools.dep.version}" + | def ammoniteVersion = "${Deps.ammonite.dep.version}" + | def defaultGraalVMJavaVersion = "${deps.graalVmJavaVersion}" + | def defaultGraalVMVersion = "${deps.graalVmVersion}" + | def scalaPyVersion = "${Deps.scalaPy.dep.version}" + | def bloopVersion = "${Deps.bloopRifle.dep.version}" + | def pprintVersion = "${TestDeps.pprint.dep.version}" + | def munitVersion = "${TestDeps.munit.dep.version}" + | def dockerTestImage = "${Docker.testImage}" + | def dockerAlpineTestImage = "${Docker.alpineTestImage}" + | def authProxyTestImage = "${Docker.authProxyTestImage}" + | def mostlyStaticDockerfile = "${mostlyStaticDockerfile.toString.replace( + "\\", + "\\\\" + )}" + | def cs = "${settings.cs().replace("\\", "\\\\")}" + | def workspaceDirName = "$workspaceDirName" + | def libsodiumVersion = "${deps.libsodiumVersion}" + | def dockerArchLinuxImage = "${TestDeps.archLinuxImage}" | - | def toolkitVersion = "${Deps.toolkitVersion}" + | def toolkitVersion = "${Deps.toolkitVersion}" | def typelevelToolkitVersion = "${Deps.typelevelToolkitVersion}" | - | def ghOrg = "$ghOrg" + | def ghOrg = "$ghOrg" | def ghName = "$ghName" |} |""".stripMargin @@ -1061,26 +1071,26 @@ trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests } private object Launchers { - def jvm = cli.standaloneLauncher + def jvm = cli(Scala.defaultInternal).standaloneLauncher def jvmBootstrapped = cliBootstrapped.jar def native = Option(System.getenv("SCALA_CLI_IT_FORCED_LAUNCHER_DIRECTORY")) match { case Some(_) => forcedLauncher - case None => cli.nativeImage + case None => cli(Scala.defaultInternal).nativeImage } def nativeStatic = Option(System.getenv("SCALA_CLI_IT_FORCED_STATIC_LAUNCHER_DIRECTORY")) match { case Some(_) => forcedStaticLauncher - case None => cli.nativeImageStatic + case None => cli(Scala.defaultInternal).nativeImageStatic } def nativeMostlyStatic = Option(System.getenv("SCALA_CLI_IT_FORCED_MOSTLY_STATIC_LAUNCHER_DIRECTORY")) match { case Some(_) => forcedMostlyStaticLauncher - case None => cli.nativeImageMostlyStatic + case None => cli(Scala.defaultInternal).nativeImageMostlyStatic } } @@ -1200,7 +1210,7 @@ def copyTo(task: mill.main.Tasks[PathRef], dest: String) = T.command { def writePackageVersionTo(dest: String) = T.command { val destPath = os.Path(dest, os.pwd) - val rawVersion = cli.publishVersion() + val rawVersion = cli(Scala.defaultInternal).publishVersion() val version = if (rawVersion.contains("+")) rawVersion.stripSuffix("-SNAPSHOT") else rawVersion @@ -1209,7 +1219,7 @@ def writePackageVersionTo(dest: String) = T.command { def writeShortPackageVersionTo(dest: String) = T.command { val destPath = os.Path(dest, os.pwd) - val rawVersion = cli.publishVersion() + val rawVersion = cli(Scala.defaultInternal).publishVersion() val version = rawVersion.takeWhile(c => c != '-' && c != '+') os.write.over(destPath, version) } @@ -1243,7 +1253,7 @@ def importedLauncher(directory: String = "artifacts"): Array[Byte] = { } def copyLauncher(directory: String = "artifacts") = T.command { - val nativeLauncher = cli.nativeImage().path + val nativeLauncher = cli(Scala.defaultInternal).nativeImage().path Upload.copyLauncher( nativeLauncher, directory, @@ -1253,7 +1263,7 @@ def copyLauncher(directory: String = "artifacts") = T.command { } def copyJvmLauncher(directory: String = "artifacts") = T.command { - val launcher = cli.standaloneLauncher().path + val launcher = cli(Scala.defaultInternal).standaloneLauncher().path os.copy( launcher, os.Path(directory, os.pwd) / s"scala-cli$platformExecutableJarExtension", @@ -1272,7 +1282,7 @@ def copyJvmBootstrappedLauncher(directory: String = "artifacts") = T.command { } def uploadLaunchers(directory: String = "artifacts") = T.command { - val version = cli.publishVersion() + val version = cli(Scala.defaultInternal).publishVersion() val path = os.Path(directory, os.pwd) val launchers = os.list(path).filter(os.isFile(_)).map { path => @@ -1288,20 +1298,24 @@ def uploadLaunchers(directory: String = "artifacts") = T.command { } def unitTests() = T.command { - `build-module`.test.test()() - `build-macros`.test.test()() - cli.test.test()() - directives.test.test()() - options.test.test()() + `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 scala(args: Task[Args] = T.task(Args())) = T.command { - cli.run(args)() + cli(Scala.defaultInternal).run(args)() +} + +def debug(port: Int, args: Task[Args] = T.task(Args())) = T.command { + cli(Scala.defaultInternal).debug(port, args)() } def defaultNativeImage() = T.command { - cli.nativeImage() + cli(Scala.defaultInternal).nativeImage() } def nativeIntegrationTests() = @@ -1315,7 +1329,7 @@ def copyDefaultLauncher(directory: String = "artifacts") = } def copyMostlyStaticLauncher(directory: String = "artifacts") = T.command { - val nativeLauncher = cli.nativeImageMostlyStatic().path + val nativeLauncher = cli(Scala.defaultInternal).nativeImageMostlyStatic().path Upload.copyLauncher( nativeLauncher, directory, @@ -1326,7 +1340,7 @@ def copyMostlyStaticLauncher(directory: String = "artifacts") = T.command { } def copyStaticLauncher(directory: String = "artifacts") = T.command { - val nativeLauncher = cli.nativeImageStatic().path + val nativeLauncher = cli(Scala.defaultInternal).nativeImageStatic().path Upload.copyLauncher( nativeLauncher, directory, @@ -1369,10 +1383,10 @@ private def commitChanges( // TODO Move most CI-specific tasks there object ci extends Module { def publishVersion() = T.command { - println(cli.publishVersion()) + println(cli(Scala.defaultInternal).publishVersion()) } def updateScalaCliSetup() = T.command { - val version = cli.publishVersion() + val version = cli(Scala.defaultInternal).publishVersion() val targetDir = os.pwd / "target-scala-cli-setup" val mainDir = targetDir / "scala-cli-setup" @@ -1401,7 +1415,7 @@ object ci extends Module { commitChanges(s"Update scala-cli version to $version", targetBranch, mainDir, force = true) } def updateStandaloneLauncher() = T.command { - val version = cli.publishVersion() + val version = cli(Scala.defaultInternal).publishVersion() val targetDir = os.pwd / "target" val scalaCliDir = targetDir / "scala-cli" @@ -1466,7 +1480,7 @@ object ci extends Module { (x86Sha256, arm64Sha256) } def updateScalaCliBrewFormula() = T.command { - val version = cli.publishVersion() + val version = cli(Scala.defaultInternal).publishVersion() val targetDir = os.pwd / "target" val homebrewFormulaDir = targetDir / "homebrew-scala-cli" @@ -1508,7 +1522,7 @@ object ci extends Module { commitChanges(s"Update for $version", branch, homebrewFormulaDir) } def updateScalaExperimentalBrewFormula() = T.command { - val version = cli.publishVersion() + val version = cli(Scala.defaultInternal).publishVersion() val targetDir = os.pwd / "target" val homebrewFormulaDir = targetDir / "homebrew-scala-experimental" @@ -1550,7 +1564,7 @@ object ci extends Module { commitChanges(s"Update for $version", branch, homebrewFormulaDir) } def updateInstallationScript() = T.command { - val version = cli.publishVersion() + val version = cli(Scala.defaultInternal).publishVersion() val targetDir = os.pwd / "target" val packagesDir = targetDir / "scala-cli-packages" @@ -1577,7 +1591,7 @@ object ci extends Module { commitChanges(s"Update installation script for $version", branch, packagesDir) } def updateDebianPackages() = T.command { - val version = cli.publishVersion() + val version = cli(Scala.defaultInternal).publishVersion() val targetDir = os.pwd / "target" val packagesDir = targetDir / "scala-cli-packages" @@ -1645,7 +1659,7 @@ object ci extends Module { commitChanges(s"Update Debian packages for $version", branch, packagesDir) } def updateChocolateyPackage() = T.command { - val version = cli.publishVersion() + val version = cli(Scala.defaultInternal).publishVersion() val packagesDir = os.pwd / "target" / "scala-cli-packages" val chocoDir = os.pwd / ".github" / "scripts" / "choco" @@ -1689,7 +1703,7 @@ object ci extends Module { ).call(cwd = chocoDir) } def updateCentOsPackages() = T.command { - val version = cli.publishVersion() + val version = cli(Scala.defaultInternal).publishVersion() val targetDir = os.pwd / "target" val packagesDir = targetDir / "scala-cli-packages" diff --git a/modules/docs-tests/README.md b/modules/docs-tests/README.md index 2fd14e13f0..73af9617ef 100644 --- a/modules/docs-tests/README.md +++ b/modules/docs-tests/README.md @@ -24,7 +24,7 @@ Sclicheck accepts following arguments: `[--dest ] [--step] [--stopAtFailur Sclicheck can be run from the Scala CLI sources root with ```text -$ ./mill -i docs-tests.run …args… +$ ./mill -i 'docs-tests[]'.run …args… ``` ## Example diff --git a/modules/integration/src/test/scala/scala/cli/integration/ExportJsonTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/ExportJsonTestDefinitions.scala index ca75c2a32c..e58190c407 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/ExportJsonTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/ExportJsonTestDefinitions.scala @@ -47,7 +47,7 @@ abstract class ExportJsonTestDefinitions(val scalaVersionOpt: Option[String]) expect(jsonContents == s"""{ |"projectVersion":"1.1.2", - |"scalaVersion":"${Constants.scala3}", + |"scalaVersion":"${Constants.scala3Next}", |"platform":"JVM", |"jvmVersion":"adopt:11", |"scopes": [[ diff --git a/modules/integration/src/test/scala/scala/cli/integration/MetaCheck.scala b/modules/integration/src/test/scala/scala/cli/integration/MetaCheck.scala index 673e93abb7..c61879a5d1 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/MetaCheck.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/MetaCheck.scala @@ -50,7 +50,7 @@ class MetaCheck extends ScalaCliSuite { // --ttl 0s so that we are sure we use the latest supported Scala versions listing val res = os.proc(TestUtil.cli, ".", "--ttl", "0s").call(cwd = root) val scalaVersion = res.out.trim() - expect(scalaVersion == Constants.scala3) + expect(scalaVersion == Constants.defaultScala) } } } diff --git a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala index 1b6080bbf0..92b191bd37 100644 --- a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala @@ -332,7 +332,7 @@ final case class BuildOptions( svInput match { case sv if ScalaVersionUtil.scala3Lts.contains(sv) => ScalaVersionUtil.validateStable( - Constants.scala3Lts, + Constants.scala3LtsPrefix, cache, repositories ) diff --git a/project/deps.sc b/project/deps.sc index 3c1df34fbf..14686e75e7 100644 --- a/project/deps.sc +++ b/project/deps.sc @@ -1,23 +1,27 @@ import mill._, scalalib._ object Scala { - def scala212 = "2.12.19" - def scala213 = "2.13.12" - def runnerScala3 = "3.0.2" // the newest version that is compatible with all Scala 3.x versions - def scala3 = "3.4.0" - def scala3Lts = "3.3" // the full version should be resolved later + def scala212 = "2.12.19" + def scala213 = "2.13.12" + def runnerScala3 = "3.0.2" // the newest version that is compatible with all Scala 3.x versions + def scala3LtsPrefix = "3.3" // used for the LTS version tags + def scala3Lts = s"$scala3LtsPrefix.2" // the LTS version currently used in the build + def scala3Next = "3.4.0" // the newest/next version of Scala // The Scala version used to build the CLI itself. - def defaultInternal = sys.props.get("scala.version.internal").getOrElse(scala3) + def defaultInternal = sys.props.get("scala.version.internal").getOrElse(scala3Lts) // The Scala version used by default to compile user input. - def defaultUser = sys.props.get("scala.version.user").getOrElse(scala3) + def defaultUser = sys.props.get("scala.version.user").getOrElse(scala3Next) - val allScala2 = Seq(scala213, scala212) - val defaults = Seq(defaultInternal, defaultUser).distinct - val all = (allScala2 ++ Seq(scala3) ++ defaults).distinct - val mainVersions = (Seq(scala3, scala213) ++ defaults).distinct - val runnerScalaVersions = runnerScala3 +: allScala2 + val allScala2 = Seq(scala213, scala212) + val defaults = Seq(defaultInternal, defaultUser).distinct + val allScala3 = Seq(scala3Lts, scala3Next) + val all = (allScala2 ++ allScala3 ++ defaults).distinct + val scala3MainVersions = (defaults ++ allScala3).distinct + val mainVersions = (Seq(scala213) ++ scala3MainVersions).distinct + val runnerScalaVersions = runnerScala3 +: allScala2 + val testRunnerScalaVersions = runnerScalaVersions ++ allScala3 def scalaJs = "1.15.0" def scalaJsCli = "1.15.0.1" // this must be compatible with the Scala.js version @@ -30,13 +34,15 @@ object Scala { val max30 = 2 val max31 = 3 val max32 = 2 - val max33 = patchVer(scala3) + val max33 = patchVer(scala3Lts) + val max34 = patchVer(scala3Next) (8 until max212).map(i => s"2.12.$i") ++ Seq(scala212) ++ (0 until max213).map(i => s"2.13.$i") ++ Seq(scala213) ++ (0 to max30).map(i => s"3.0.$i") ++ (0 to max31).map(i => s"3.1.$i") ++ (0 to max32).map(i => s"3.2.$i") ++ - (0 until max33).map(i => s"3.3.$i") ++ Seq(scala3) + (0 until max33).map(i => s"3.3.$i") ++ + (0 until max34).map(i => s"3.4.$i") ++ Seq(scala3Next) } def maxAmmoniteScala212Version = "2.12.18" diff --git a/project/website.sc b/project/website.sc index 98798c9655..9bffdec43b 100644 --- a/project/website.sc +++ b/project/website.sc @@ -24,7 +24,7 @@ def checkMainScalaVersions(path: os.Path): Unit = { val cells = lastTableLine(path, 4) val lastCells = cells.drop(1) assert(lastCells.length == 3) - val expectedLastCells = Seq(Scala.scala3, Scala.scala213, Scala.scala212) + val expectedLastCells = Seq(Scala.scala3Next, Scala.scala213, Scala.scala212) if (lastCells != expectedLastCells) sys.error( s"Unexpected last line in Scala version table in $path " + diff --git a/scala-cli b/scala-cli index 856aafdbd4..d5311075e3 100755 --- a/scala-cli +++ b/scala-cli @@ -17,7 +17,7 @@ if [ ! -x "$LAUNCHER_DIR/scala-cli" ]; then echo "native-image launcher not built yet." 1>&2 echo "In order to build it, go in $DIR, and run" 1>&2 echo 1>&2 - echo " ./mill cli.nativeImage" 1>&2 + echo " ./mill 'cli[]'.nativeImage" 1>&2 exit 1 fi diff --git a/scala-cli-src b/scala-cli-src index 121813ed9f..913c3a0bdf 100755 --- a/scala-cli-src +++ b/scala-cli-src @@ -1,5 +1,5 @@ #!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )" -LAUNCHER="$(cd "$SCRIPT_DIR" && ./mill show cli.launcher