diff --git a/core/api/src/mill/api/JsonFormatters.scala b/core/api/src/mill/api/JsonFormatters.scala index 2ebb0bdf127a..3caa447db858 100644 --- a/core/api/src/mill/api/JsonFormatters.scala +++ b/core/api/src/mill/api/JsonFormatters.scala @@ -23,8 +23,8 @@ trait JsonFormatters { implicit val pathReadWrite: RW[os.Path] = upickle.readwriter[String] .bimap[os.Path]( - _.toString, - os.Path(_) + p => MappedRoots.encodeKnownRootsInPath(p), + s => os.Path(MappedRoots.decodeKnownRootsInPath(s)) ) implicit val relPathRW: RW[os.RelPath] = upickle.readwriter[String] diff --git a/core/api/src/mill/api/MappedRoots.scala b/core/api/src/mill/api/MappedRoots.scala new file mode 100644 index 000000000000..96c23ae89ce3 --- /dev/null +++ b/core/api/src/mill/api/MappedRoots.scala @@ -0,0 +1,95 @@ +package mill.api + +import mill.api.internal.NamedParameterOnlyDummy +import mill.constants.PathVars + +import scala.annotation.unused +import scala.util.DynamicVariable + +type MappedRoots = Seq[(key: String, path: os.Path)] + +object MappedRoots extends MappedRootsImpl + +trait MappedRootsImpl { + + private val rootMapping: DynamicVariable[MappedRoots] = DynamicVariable(Seq()) + + def get: MappedRoots = rootMapping.value + + def toMap: Map[String, os.Path] = get.map(m => (m.key, m.path)).toMap + + def withMillDefaults[T]( + @unused t: NamedParameterOnlyDummy = new NamedParameterOnlyDummy, + outPath: os.Path, + workspacePath: os.Path = BuildCtx.workspaceRoot, + homePath: os.Path = os.home + )(thunk: => T): T = withMapping( + Seq( + ("MILL_OUT", outPath), + ("WORKSPACE", workspacePath), + // TODO: add coursier here + ("HOME", homePath) + ) + )(thunk) + + def withMapping[T](mapping: MappedRoots)(thunk: => T): T = withMapping(_ => mapping)(thunk) + + def withMapping[T](mapping: MappedRoots => MappedRoots)(thunk: => T): T = { + val newMapping = mapping(rootMapping.value) + var seenKeys = Set[String]() + var seenPaths = Set[os.Path]() + newMapping.foreach { case m => + require(!m.key.startsWith("$"), "Key must not start with a `$`.") + require(m.key != PathVars.ROOT, s"Invalid key, '${PathVars.ROOT}' is a reserved key name.") + require( + !seenKeys.contains(m.key), + s"Key must be unique, but '${m.key}' was given multiple times." + ) + require( + !seenPaths.contains(m.path), + s"Paths must be unique, but '${m.path}' was given multiple times." + ) + seenKeys += m.key + seenPaths += m.path + } + rootMapping.withValue(newMapping)(thunk) + } + + def encodeKnownRootsInPath(p: os.Path): String = { + MappedRoots.get.collectFirst { + case rep if p.startsWith(rep.path) => + s"$$${rep.key}${ + if (p != rep.path) { + s"/${p.subRelativeTo(rep.path).toString()}" + } else "" + }" + }.getOrElse(p.toString) + } + + def decodeKnownRootsInPath(encoded: String): String = { + if (encoded.startsWith("$")) { + val offset = 1 // "$".length + MappedRoots.get.collectFirst { + case mapping if encoded.startsWith(mapping.key, offset) => + s"${mapping.path.toString}${encoded.substring(mapping.key.length + offset)}" + }.getOrElse(encoded) + } else { + encoded + } + } + + /** + * Use this to assert at runtime, that a root path with the given `key` is defined. + * @throws NoSuchElementException when no path was mapped under the given `key`. + */ + def requireMappedPaths(key: String*): Unit = { + val map = toMap + for { + singleKey <- key + } { + if (!map.contains(singleKey)) + throw new NoSuchElementException(s"No root path mapping defined for '${key}'") + } + } + +} diff --git a/core/api/src/mill/api/PathRef.scala b/core/api/src/mill/api/PathRef.scala index 83bbc3b14cfe..29d72057ea09 100644 --- a/core/api/src/mill/api/PathRef.scala +++ b/core/api/src/mill/api/PathRef.scala @@ -2,7 +2,6 @@ package mill.api import mill.api.DummyOutputStream import mill.api.daemon.internal.PathRefApi -import upickle.ReadWriter as RW import java.nio.file as jnio import java.security.{DigestOutputStream, MessageDigest} @@ -10,11 +9,12 @@ import java.util.concurrent.ConcurrentHashMap import scala.annotation.nowarn import scala.language.implicitConversions import scala.util.DynamicVariable +import scala.util.hashing.MurmurHash3 /** - * A wrapper around `os.Path` that calculates it's hashcode based - * on the contents of the filesystem underneath it. Used to ensure filesystem - * changes can bust caches which are keyed off hashcodes. + * A wrapper around `os.Path` that calculates a `sig` (which ends up in the [[hashCode]]) + * based on the contents of the filesystem underneath it. + * Used to ensure filesystem changes can bust caches which are keyed off hashcodes. */ case class PathRef private[mill] ( path: os.Path, @@ -24,6 +24,18 @@ case class PathRef private[mill] ( ) extends PathRefApi { private[mill] def javaPath = path.toNIO + /** + * The path with common mapped path roots replaced, to make it relocatable. + * See [[MappedRoots]]. + */ + private val mappedPath: String = MappedRoots.encodeKnownRootsInPath(path) + + /** + * Apply the current contextual path mapping to this PathRef. + * Updates [[mappedPath]] but does not recalculate the [[sig]]. + */ + def remap: PathRef = PathRef(path, quick, sig, revalidate) + def recomputeSig(): Int = PathRef.apply(path, quick).sig def validate(): Boolean = recomputeSig() == sig @@ -38,16 +50,33 @@ case class PathRef private[mill] ( def withRevalidate(revalidate: PathRef.Revalidate): PathRef = copy(revalidate = revalidate) def withRevalidateOnce: PathRef = copy(revalidate = PathRef.Revalidate.Once) - override def toString: String = { + private def toStringPrefix: String = { val quick = if (this.quick) "qref:" else "ref:" + val valid = revalidate match { case PathRef.Revalidate.Never => "v0:" case PathRef.Revalidate.Once => "v1:" case PathRef.Revalidate.Always => "vn:" } val sig = String.format("%08x", this.sig: Integer) - quick + valid + sig + ":" + path.toString() + s"${quick}${valid}${sig}:" + } + + override def toString: String = { + toStringPrefix + path.toString() } + + // Instead of using `path` we need to use `mappedPath` to make the hashcode stable as cache key + override def hashCode(): Int = { + var h = MurmurHash3.productSeed + h = MurmurHash3.mix(h, "PathRef".hashCode) + h = MurmurHash3.mix(h, mappedPath.hashCode) + h = MurmurHash3.mix(h, quick.##) + h = MurmurHash3.mix(h, sig.##) + h = MurmurHash3.mix(h, revalidate.##) + MurmurHash3.finalizeHash(h, 4) + } + } object PathRef { @@ -192,37 +221,38 @@ object PathRef { /** * Default JSON formatter for [[PathRef]]. */ - implicit def jsonFormatter: RW[PathRef] = upickle.readwriter[String].bimap[PathRef]( - p => { - storeSerializedPaths(p) - p.toString() - }, - { - case s"$prefix:$valid0:$hex:$pathString" if prefix == "ref" || prefix == "qref" => - - val path = os.Path(pathString) - val quick = prefix match { - case "qref" => true - case "ref" => false - } - val validOrig = valid0 match { - case "v0" => Revalidate.Never - case "v1" => Revalidate.Once - case "vn" => Revalidate.Always - } - // Parsing to a long and casting to an int is the only way to make - // round-trip handling of negative numbers work =( - val sig = java.lang.Long.parseLong(hex, 16).toInt - val pr = PathRef(path, quick, sig, revalidate = validOrig) - validatedPaths.value.revalidateIfNeededOrThrow(pr) - storeSerializedPaths(pr) - pr - case s => - mill.api.BuildCtx.withFilesystemCheckerDisabled( - PathRef(os.Path(s, currentOverrideModulePath.value)) - ) - } - ) + implicit def jsonFormatter: upickle.ReadWriter[PathRef] = + upickle.readwriter[String].bimap[PathRef]( + p => { + storeSerializedPaths(p) + p.toStringPrefix + MappedRoots.encodeKnownRootsInPath(p.path) + }, + { + case s"$prefix:$valid0:$hex:$pathVal" if prefix == "ref" || prefix == "qref" => + + val path = os.Path(MappedRoots.decodeKnownRootsInPath(pathVal)) + val quick = prefix match { + case "qref" => true + case "ref" => false + } + val validOrig = valid0 match { + case "v0" => Revalidate.Never + case "v1" => Revalidate.Once + case "vn" => Revalidate.Always + } + // Parsing to a long and casting to an int is the only way to make + // round-trip handling of negative numbers work =( + val sig = java.lang.Long.parseLong(hex, 16).toInt + val pr = PathRef(path, quick, sig, revalidate = validOrig) + validatedPaths.value.revalidateIfNeededOrThrow(pr) + storeSerializedPaths(pr) + pr + case s => + mill.api.BuildCtx.withFilesystemCheckerDisabled( + PathRef(os.Path(MappedRoots.decodeKnownRootsInPath(s), currentOverrideModulePath.value)) + ) + } + ) private[mill] val currentOverrideModulePath = DynamicVariable[os.Path](null) // scalafix:off; we want to hide the unapply method diff --git a/core/api/test/src/mill/api/MappedRootsTests.scala b/core/api/test/src/mill/api/MappedRootsTests.scala new file mode 100644 index 000000000000..63ac9a391fff --- /dev/null +++ b/core/api/test/src/mill/api/MappedRootsTests.scala @@ -0,0 +1,48 @@ +package mill.api + +import utest.* + +import java.nio.file.Files +import mill.api.{MappedRoots => MR} + +object MappedRootsTests extends TestSuite { + val tests: Tests = Tests { + test("encode") { + withTmpDir { tmpDir => + val workspaceDir = tmpDir / "workspace" + val outDir = workspaceDir / "out" + MR.withMillDefaults(outPath = outDir, workspacePath = workspaceDir) { + + def check(path: os.Path, encContains: Seq[String], containsNot: Seq[String]) = { + val enc = MR.encodeKnownRootsInPath(path) + val dec = MR.decodeKnownRootsInPath(enc) + assert(path.toString == dec) + encContains.foreach(s => assert(enc.containsSlice(s))) + containsNot.foreach(s => assert(!enc.containsSlice(s))) + + path -> enc + } + + val file1 = tmpDir / "file1" + val file2 = workspaceDir / "file2" + val file3 = outDir / "file3" + + Seq( + "mapping" -> MR.get, + check(file1, Seq(file1.toString), Seq("$WORKSPACE", "$MILL_OUT")), + check(file2, Seq("$WORKSPACE/file2"), Seq("$MILL_OUT")), + check(file3, Seq("$MILL_OUT/file3"), Seq("$WORKSPACE")) + ) + } + } + } + } + + private def withTmpDir[T](body: os.Path => T): T = { + val tmpDir = os.Path(Files.createTempDirectory("")) + val res = body(tmpDir) + os.remove.all(tmpDir) + res + } + +} diff --git a/core/api/test/src/mill/api/PathRefTests.scala b/core/api/test/src/mill/api/PathRefTests.scala index dd8717a6949d..5c4f9790cd8c 100644 --- a/core/api/test/src/mill/api/PathRefTests.scala +++ b/core/api/test/src/mill/api/PathRefTests.scala @@ -19,6 +19,7 @@ object PathRefTests extends TestSuite { val sig2 = PathRef(file, quick).sig assert(sig1 != sig2) } + test("qref") - check(quick = true) test("ref") - check(quick = false) } @@ -43,12 +44,18 @@ object PathRefTests extends TestSuite { val file = tmpDir / "foo.txt" val content = "hello" os.write.over(file, content) - Files.setPosixFilePermissions(file.wrapped, PosixFilePermissions.fromString("rw-rw----")) + Files.setPosixFilePermissions( + file.wrapped, + PosixFilePermissions.fromString("rw-rw----") + ) val rwSig = PathRef(file, quick).sig val rwSigb = PathRef(file, quick).sig assert(rwSig == rwSigb) - Files.setPosixFilePermissions(file.wrapped, PosixFilePermissions.fromString("rwxrw----")) + Files.setPosixFilePermissions( + file.wrapped, + PosixFilePermissions.fromString("rwxrw----") + ) val rwxSig = PathRef(file, quick).sig assert(rwSig != rwxSig) @@ -76,6 +83,7 @@ object PathRefTests extends TestSuite { val sig2 = PathRef(tmpDir, quick).sig assert(sig1 == sig2) } + test("qref") - check(quick = true) test("ref") - check(quick = false) } diff --git a/core/constants/src/mill/constants/PathVars.java b/core/constants/src/mill/constants/PathVars.java new file mode 100644 index 000000000000..574f5c61c5a1 --- /dev/null +++ b/core/constants/src/mill/constants/PathVars.java @@ -0,0 +1,22 @@ +package mill.constants; + +/** + * Central place containing all the path variables that Mill uses in PathRef or os.Path. + */ +public interface PathVars { + + /** + * Output directory where Mill workers' state and Mill tasks output should be + * written to + */ + String MILL_OUT = "MILL_OUT"; + + /** + * The Mill project workspace root directory. + */ + String WORKSPACE = "WORKSPACE"; + + String HOME = "HOME"; + + String ROOT = "ROOT"; +} diff --git a/core/exec/src/mill/exec/Execution.scala b/core/exec/src/mill/exec/Execution.scala index 5caa217abb4d..40219e333df4 100644 --- a/core/exec/src/mill/exec/Execution.scala +++ b/core/exec/src/mill/exec/Execution.scala @@ -54,24 +54,24 @@ private[mill] case class Execution( offline: Boolean, enableTicker: Boolean ) = this( - baseLogger, - new JsonArrayLogger.Profile(os.Path(outPath) / millProfile), - os.Path(workspace), - os.Path(outPath), - os.Path(externalOutPath), - rootModule, - classLoaderSigHash, - classLoaderIdentityHash, - workerCache, - env, - failFast, - ec, - codeSignatures, - systemExit, - exclusiveSystemStreams, - getEvaluator, - offline, - enableTicker + baseLogger = baseLogger, + profileLogger = new JsonArrayLogger.Profile(os.Path(outPath) / millProfile), + workspace = os.Path(workspace), + outPath = os.Path(outPath), + externalOutPath = os.Path(externalOutPath), + rootModule = rootModule, + classLoaderSigHash = classLoaderSigHash, + classLoaderIdentityHash = classLoaderIdentityHash, + workerCache = workerCache, + env = env, + failFast = failFast, + ec = ec, + codeSignatures = codeSignatures, + systemExit = systemExit, + exclusiveSystemStreams = exclusiveSystemStreams, + getEvaluator = getEvaluator, + offline = offline, + enableTicker = enableTicker ) def withBaseLogger(newBaseLogger: Logger) = this.copy(baseLogger = newBaseLogger) diff --git a/core/exec/src/mill/exec/GroupExecution.scala b/core/exec/src/mill/exec/GroupExecution.scala index 2ffe980ff0a8..93c45df2b3ab 100644 --- a/core/exec/src/mill/exec/GroupExecution.scala +++ b/core/exec/src/mill/exec/GroupExecution.scala @@ -88,7 +88,7 @@ trait GroupExecution { executionContext: mill.api.TaskCtx.Fork.Api, exclusive: Boolean, upstreamPathRefs: Seq[PathRef] - ): GroupExecution.Results = { + ): GroupExecution.Results = MappedRoots.withMillDefaults(outPath = outPath) { val inputsHash = { val externalInputsHash = MurmurHash3.orderedHash( @@ -244,8 +244,8 @@ trait GroupExecution { newEvaluated = newEvaluated.toSeq, cached = if (labelled.isInstanceOf[Task.Input[?]]) null else false, inputsHash = inputsHash, - previousInputsHash = cached.map(_._1).getOrElse(-1), - valueHashChanged = !cached.map(_._3).contains(valueHash), + previousInputsHash = cached.map(_.inputsHash).getOrElse(-1), + valueHashChanged = !cached.map(_.valueHash).contains(valueHash), serializedPaths = serializedPaths ) } @@ -455,7 +455,11 @@ trait GroupExecution { inputsHash: Int, labelled: Task.Named[?], paths: ExecutionPaths - ): Option[(Int, Option[(Val, Seq[PathRef])], Int)] = { + ): Option[( + inputsHash: Int, + valOpt: Option[(Val, Seq[PathRef])], + valueHash: Int + )] = { for { cached <- try Some(upickle.read[Cached](paths.meta.toIO, trace = false)) @@ -463,8 +467,8 @@ trait GroupExecution { case NonFatal(_) => None } } yield ( - cached.inputsHash, - for { + inputsHash = cached.inputsHash, + valOpt = for { _ <- Option.when(cached.inputsHash == inputsHash)(()) reader <- labelled.readWriterOpt (parsed, serializedPaths) <- @@ -480,7 +484,7 @@ trait GroupExecution { case NonFatal(_) => None } } yield (Val(parsed), serializedPaths), - cached.valueHash + valueHash = cached.valueHash ) } @@ -620,7 +624,7 @@ object GroupExecution { classLoader: ClassLoader )(t: => T): T = { // Tasks must be allowed to write to upstream worker's dest folders, because - // the point of workers is to manualy manage long-lived state which includes + // the point of workers is to manually manage long-lived state which includes // state on disk. val validWriteDests = deps.collect { case n: Task.Worker[?] => diff --git a/example/androidlib/java/1-hello-world/build.mill b/example/androidlib/java/1-hello-world/build.mill index 3d6a9be7d269..4edd80e4d573 100644 --- a/example/androidlib/java/1-hello-world/build.mill +++ b/example/androidlib/java/1-hello-world/build.mill @@ -64,7 +64,7 @@ object app extends AndroidAppModule { /** Usage > ./mill show app.androidApk -".../out/app/androidApk.dest/app.apk" +"...$MILL_OUT/app/androidApk.dest/app.apk" */ diff --git a/example/androidlib/java/2-app-bundle/build.mill b/example/androidlib/java/2-app-bundle/build.mill index f05d58782d5d..007a41475265 100644 --- a/example/androidlib/java/2-app-bundle/build.mill +++ b/example/androidlib/java/2-app-bundle/build.mill @@ -37,7 +37,7 @@ object bundle extends AndroidAppBundle { /** Usage > ./mill show bundle.androidBundle -".../out/bundle/androidBundle.dest/signedBundle.aab" +"...$MILL_OUT/bundle/androidBundle.dest/signedBundle.aab" */ diff --git a/example/androidlib/java/4-sum-lib-java/build.mill b/example/androidlib/java/4-sum-lib-java/build.mill index 20ef34f00105..97dfd203dc93 100644 --- a/example/androidlib/java/4-sum-lib-java/build.mill +++ b/example/androidlib/java/4-sum-lib-java/build.mill @@ -125,7 +125,7 @@ Publish ... to /home/.../.m2/repository/... }, "payload": [ [ - ".../out/lib/androidAar.dest/library.aar", + "...$MILL_OUT/lib/androidAar.dest/library.aar", "lib-0.0.1.aar" ], ... diff --git a/example/androidlib/java/6-native-libs/build.mill b/example/androidlib/java/6-native-libs/build.mill index 3ffb464d1258..bb29666daab1 100644 --- a/example/androidlib/java/6-native-libs/build.mill +++ b/example/androidlib/java/6-native-libs/build.mill @@ -66,7 +66,7 @@ object app extends AndroidNativeAppModule { // <1> /** Usage > ./mill show app.androidApk -".../out/app/androidApk.dest/app.apk" +"...$MILL_OUT/app/androidApk.dest/app.apk" > ./mill show app.createAndroidVirtualDevice ...Name: java-test, DeviceId: medium_phone... diff --git a/example/androidlib/kotlin/1-hello-kotlin/build.mill b/example/androidlib/kotlin/1-hello-kotlin/build.mill index eccccd80c698..9d639729af04 100644 --- a/example/androidlib/kotlin/1-hello-kotlin/build.mill +++ b/example/androidlib/kotlin/1-hello-kotlin/build.mill @@ -72,7 +72,7 @@ object app extends AndroidAppKotlinModule { /** Usage > ./mill show app.androidApk -".../out/app/androidApk.dest/app.apk" +"...$MILL_OUT/app/androidApk.dest/app.apk" */ diff --git a/example/androidlib/kotlin/2-compose/build.mill b/example/androidlib/kotlin/2-compose/build.mill index 64fb8212e99e..4d3e9b9b8326 100644 --- a/example/androidlib/kotlin/2-compose/build.mill +++ b/example/androidlib/kotlin/2-compose/build.mill @@ -60,7 +60,7 @@ object app extends AndroidAppKotlinModule { /** Usage > ./mill show app.androidApk -".../out/app/androidApk.dest/app.apk" +"...$MILL_OUT/app/androidApk.dest/app.apk" > ./mill show app.createAndroidVirtualDevice diff --git a/example/androidlib/kotlin/4-sum-lib-kotlin/build.mill b/example/androidlib/kotlin/4-sum-lib-kotlin/build.mill index f38252c4c6ca..bc88718f9d46 100644 --- a/example/androidlib/kotlin/4-sum-lib-kotlin/build.mill +++ b/example/androidlib/kotlin/4-sum-lib-kotlin/build.mill @@ -129,7 +129,7 @@ Publish ... to /home/.../.m2/repository/... }, "payload": [ [ - ".../out/lib/androidAar.dest/library.aar", + "...$MILL_OUT/lib/androidAar.dest/library.aar", "lib-0.0.1.aar" ], ... diff --git a/example/cli/builtins/1-builtin-commands/build.mill b/example/cli/builtins/1-builtin-commands/build.mill index 4ac5ba3b98a4..e33ca895b722 100644 --- a/example/cli/builtins/1-builtin-commands/build.mill +++ b/example/cli/builtins/1-builtin-commands/build.mill @@ -146,8 +146,8 @@ Inputs: > ./mill show foo.compile { - "analysisFile": ".../out/foo/compile.dest/...", - "classes": ".../out/foo/compile.dest/classes" + "analysisFile": "...$MILL_OUT/foo/compile.dest/...", + "classes": "...$MILL_OUT/foo/compile.dest/classes" } */ diff --git a/example/depth/sandbox/2-test/build.mill b/example/depth/sandbox/2-test/build.mill index 70f409653e32..3288e086f056 100644 --- a/example/depth/sandbox/2-test/build.mill +++ b/example/depth/sandbox/2-test/build.mill @@ -47,8 +47,8 @@ object bar extends MyModule /** Usage > find . | grep generated.html -.../out/foo/test/testForked.dest/sandbox/generated.html -.../out/bar/test/testForked.dest/sandbox/generated.html +./out/foo/test/testForked.dest/sandbox/generated.html +./out/bar/test/testForked.dest/sandbox/generated.html > cat out/foo/test/testForked.dest/sandbox/generated.html

hello

@@ -81,7 +81,7 @@ object qux extends JavaModule { > find . | grep .html ... -.../out/qux/test/testForked.dest/sandbox/foo.html +./out/qux/test/testForked.dest/sandbox/foo.html > cat out/qux/test/testForked.dest/sandbox/foo.html

foo

diff --git a/example/extending/imports/1-mvn-deps/build.mill b/example/extending/imports/1-mvn-deps/build.mill index fda9104f287d..b47f2011ff0c 100644 --- a/example/extending/imports/1-mvn-deps/build.mill +++ b/example/extending/imports/1-mvn-deps/build.mill @@ -44,7 +44,7 @@ compiling 1 Java source... generated snippet.txt resource:

hello

world

> ./mill show foo.assembly -".../out/foo/assembly.dest/out.jar" +"...$MILL_OUT/foo/assembly.dest/out.jar" > ./out/foo/assembly.dest/out.jar # mac/linux generated snippet.txt resource:

hello

world

diff --git a/example/extending/imports/2-mvn-deps-scala/build.mill b/example/extending/imports/2-mvn-deps-scala/build.mill index da924f68e671..96352e65d657 100644 --- a/example/extending/imports/2-mvn-deps-scala/build.mill +++ b/example/extending/imports/2-mvn-deps-scala/build.mill @@ -34,7 +34,7 @@ compiling 1 Scala source... generated snippet.txt resource:

hello

world

> ./mill show bar.assembly -".../out/bar/assembly.dest/out.jar" +"...$MILL_OUT/bar/assembly.dest/out.jar" > ./out/bar/assembly.dest/out.jar # mac/linux generated snippet.txt resource:

hello

world

diff --git a/example/extending/metabuild/4-meta-build/build.mill b/example/extending/metabuild/4-meta-build/build.mill index b8b0a56cfd43..4beaa6e39c7e 100644 --- a/example/extending/metabuild/4-meta-build/build.mill +++ b/example/extending/metabuild/4-meta-build/build.mill @@ -48,7 +48,7 @@ Build-time HTML snippet:

hello

Run-time HTML snippet:

world

> ./mill show assembly -".../out/assembly.dest/out.jar" +"...$MILL_OUT/assembly.dest/out.jar" > ./out/assembly.dest/out.jar # mac/linux Build-time HTML snippet:

hello

diff --git a/example/extending/python/4-python-libs-bundle/build.mill b/example/extending/python/4-python-libs-bundle/build.mill index b1da6f0571a3..cfb86a1cf5b1 100644 --- a/example/extending/python/4-python-libs-bundle/build.mill +++ b/example/extending/python/4-python-libs-bundle/build.mill @@ -109,7 +109,7 @@ object qux extends PythonModule { Numpy : Sum: 150 | Pandas: Mean: 30.0, Max: 50 > ./mill show qux.bundle -".../out/qux/bundle.dest/bundle.pex" +"...$MILL_OUT/qux/bundle.dest/bundle.pex" > out/qux/bundle.dest/bundle.pex # running the PEX binary outside of Mill Numpy : Sum: 150 | Pandas: Mean: 30.0, Max: 50 diff --git a/example/extending/typescript/4-npm-deps-bundle/build.mill b/example/extending/typescript/4-npm-deps-bundle/build.mill index 006a4749c8a0..d44808e68ffb 100644 --- a/example/extending/typescript/4-npm-deps-bundle/build.mill +++ b/example/extending/typescript/4-npm-deps-bundle/build.mill @@ -117,7 +117,7 @@ object qux extends TypeScriptModule { Hello James Bond Professor > ./mill show qux.bundle -".../out/qux/bundle.dest/bundle.js" +"...$MILL_OUT/qux/bundle.dest/bundle.js" > node out/qux/bundle.dest/bundle.js James Bond prof Hello James Bond Professor diff --git a/example/fundamentals/cross/10-static-blog/build.mill b/example/fundamentals/cross/10-static-blog/build.mill index 0cb186843ed6..77d53d2886cd 100644 --- a/example/fundamentals/cross/10-static-blog/build.mill +++ b/example/fundamentals/cross/10-static-blog/build.mill @@ -113,7 +113,7 @@ def dist = Task { /** Usage > ./mill show "post[1-My-First-Post.md].render" -".../out/post/1-My-First-Post.md/render.dest/1-my-first-post.html" +"...$MILL_OUT/post/1-My-First-Post.md/render.dest/1-my-first-post.html" > cat out/post/1-My-First-Post.md/render.dest/1-my-first-post.html ... diff --git a/example/fundamentals/libraries/2-upickle/build.mill b/example/fundamentals/libraries/2-upickle/build.mill index fcac91f6de98..1a0dc0aa6a92 100644 --- a/example/fundamentals/libraries/2-upickle/build.mill +++ b/example/fundamentals/libraries/2-upickle/build.mill @@ -74,7 +74,7 @@ def taskPath = Task { /** Usage > ./mill show taskPath -".../out/taskPath.dest/file.txt" +"...$MILL_OUT/taskPath.dest/file.txt" */ @@ -92,7 +92,7 @@ def taskPathRef = Task { /** Usage > ./mill show taskPathRef -"ref.../out/taskPathRef.dest/file.txt" +"ref...$MILL_OUT/taskPathRef.dest/file.txt" */ diff --git a/example/fundamentals/modules/8-diy-java-modules/build.mill b/example/fundamentals/modules/8-diy-java-modules/build.mill index 4b6a508fd561..524bf846a5c4 100644 --- a/example/fundamentals/modules/8-diy-java-modules/build.mill +++ b/example/fundamentals/modules/8-diy-java-modules/build.mill @@ -150,7 +150,7 @@ object qux extends DiyJavaModule { } > ./mill show qux.assembly -".../out/qux/assembly.dest/assembly.jar" +"...$MILL_OUT/qux/assembly.dest/assembly.jar" > java -jar out/qux/assembly.dest/assembly.jar Foo.value: 31337 @@ -158,7 +158,7 @@ Bar.value: 271828 Qux.value: 9000 > ./mill show foo.assembly -".../out/foo/assembly.dest/assembly.jar" +"...$MILL_OUT/foo/assembly.dest/assembly.jar" > java -jar out/foo/assembly.dest/assembly.jar Foo.value: 31337 diff --git a/example/fundamentals/tasks/1-task-graph/build.mill b/example/fundamentals/tasks/1-task-graph/build.mill index a512437f7652..1c855464b708 100644 --- a/example/fundamentals/tasks/1-task-graph/build.mill +++ b/example/fundamentals/tasks/1-task-graph/build.mill @@ -55,7 +55,7 @@ def run(args: String*) = Task.Command { /** Usage > ./mill show assembly -".../out/assembly.dest/assembly.jar" +"...$MILL_OUT/assembly.dest/assembly.jar" > java -jar out/assembly.dest/assembly.jar i am cow Foo.value: 31337 diff --git a/example/fundamentals/tasks/2-primary-tasks/build.mill b/example/fundamentals/tasks/2-primary-tasks/build.mill index 570dd57b59ce..115a64d1657f 100644 --- a/example/fundamentals/tasks/2-primary-tasks/build.mill +++ b/example/fundamentals/tasks/2-primary-tasks/build.mill @@ -167,7 +167,7 @@ Generating classfiles Generating jar > ./mill show jar -".../out/jar.dest/foo.jar" +"...$MILL_OUT/jar.dest/foo.jar" */ diff --git a/example/javalib/basic/1-script/build.mill b/example/javalib/basic/1-script/build.mill index 9f7c5dadb44d..9ca3528a3096 100644 --- a/example/javalib/basic/1-script/build.mill +++ b/example/javalib/basic/1-script/build.mill @@ -18,7 +18,7 @@ compiling 1 Java source to... /** Usage > ./mill show Foo.java:assembly # show the output of the assembly task -".../out/Foo.java/assembly.dest/out.jar" +"...$MILL_OUT/Foo.java/assembly.dest/out.jar" > java -jar ./out/Foo.java/assembly.dest/out.jar --text hello

hello

diff --git a/example/javalib/basic/10-realistic/build.mill b/example/javalib/basic/10-realistic/build.mill index f23038a5b082..5a10ccda2820 100644 --- a/example/javalib/basic/10-realistic/build.mill +++ b/example/javalib/basic/10-realistic/build.mill @@ -101,7 +101,7 @@ Publishing Artifact(com.lihaoyi,qux,0.0.1) to ivy repo... ... > ./mill show foo.assembly # mac/linux -".../out/foo/assembly.dest/out.jar" +"...$MILL_OUT/foo/assembly.dest/out.jar" > ./out/foo/assembly.dest/out.jar # mac/linux foo version 0.0.1 diff --git a/example/javalib/publishing/5-jlink/build.mill b/example/javalib/publishing/5-jlink/build.mill index d9031d13d04f..f44598072418 100644 --- a/example/javalib/publishing/5-jlink/build.mill +++ b/example/javalib/publishing/5-jlink/build.mill @@ -47,7 +47,7 @@ object foo extends JavaModule, JlinkModule { > ./mill foo.jlinkAppImage > ./mill show foo.jlinkAppImage -".../out/foo/jlinkAppImage.dest/jlink-runtime" +"...$MILL_OUT/foo/jlinkAppImage.dest/jlink-runtime" > ./out/foo/jlinkAppImage.dest/jlink-runtime/bin/jlink ... foo.Bar main diff --git a/example/javalib/publishing/6-jpackage/build.mill b/example/javalib/publishing/6-jpackage/build.mill index 150c9f8be48a..db1d7535fb3a 100644 --- a/example/javalib/publishing/6-jpackage/build.mill +++ b/example/javalib/publishing/6-jpackage/build.mill @@ -50,7 +50,7 @@ object foo extends JavaModule, JpackageModule { > ./mill foo.jpackageAppImage > ./mill show foo.jpackageAppImage -".../out/foo/jpackageAppImage.dest/image" +"...$MILL_OUT/foo/jpackageAppImage.dest/image" */ // diff --git a/example/javalib/publishing/9-repackage-config/build.mill b/example/javalib/publishing/9-repackage-config/build.mill index 26d2b4706319..68b5b61fab2a 100644 --- a/example/javalib/publishing/9-repackage-config/build.mill +++ b/example/javalib/publishing/9-repackage-config/build.mill @@ -45,7 +45,7 @@ Qux.value: 31337 ...Test run bar.BarTests finished: 0 failed, 0 ignored, 1 total, ...s > ./mill show foo.repackagedJar -".../out/foo/repackagedJar.dest/out.jar" +"...$MILL_OUT/foo/repackagedJar.dest/out.jar" > ./out/foo/repackagedJar.dest/out.jar Foo.value:

hello

diff --git a/example/javalib/script/10-resources/build.mill b/example/javalib/script/10-resources/build.mill index e511c0b7ae96..a197381daf17 100644 --- a/example/javalib/script/10-resources/build.mill +++ b/example/javalib/script/10-resources/build.mill @@ -13,7 +13,7 @@ Hello World Resource File /** Usage > ./mill show Foo.java:assembly -".../out/Foo.java/assembly.dest/out.jar" +"...$MILL_OUT/Foo.java/assembly.dest/out.jar" > out/Foo.java/assembly.dest/out.jar Hello World Resource File diff --git a/example/kotlinlib/basic/1-script/build.mill b/example/kotlinlib/basic/1-script/build.mill index 679cd5d33ce1..b76ba7996a1b 100644 --- a/example/kotlinlib/basic/1-script/build.mill +++ b/example/kotlinlib/basic/1-script/build.mill @@ -18,7 +18,7 @@ Compiling 1 Kotlin sources to... /** Usage > ./mill show Foo.kt:assembly # show the output of the assembly task -".../out/Foo.kt/assembly.dest/out.jar" +"...$MILL_OUT/Foo.kt/assembly.dest/out.jar" > java -jar ./out/Foo.kt/assembly.dest/out.jar --text hello

hello

diff --git a/example/kotlinlib/basic/10-realistic/build.mill b/example/kotlinlib/basic/10-realistic/build.mill index 250c18f6f16c..89ecc57ee291 100644 --- a/example/kotlinlib/basic/10-realistic/build.mill +++ b/example/kotlinlib/basic/10-realistic/build.mill @@ -109,7 +109,7 @@ Publishing Artifact(com.lihaoyi,qux,0.0.1) to ivy repo... ... > ./mill show foo.assembly # mac/linux -".../out/foo/assembly.dest/out.jar" +"...$MILL_OUT/foo/assembly.dest/out.jar" > ./out/foo/assembly.dest/out.jar # mac/linux foo version 0.0.1 diff --git a/example/kotlinlib/linting/4-kover/build.mill b/example/kotlinlib/linting/4-kover/build.mill index 1006a229c9f1..296aa141c7c0 100644 --- a/example/kotlinlib/linting/4-kover/build.mill +++ b/example/kotlinlib/linting/4-kover/build.mill @@ -57,7 +57,7 @@ kover.xmlReport > ./mill show kover.htmlReport ... -...out/kover/htmlReport.dest/kover-report... +...$MILL_OUT/kover/htmlReport.dest/kover-report... > cat out/kover/htmlReport.dest/kover-report/index.html ... @@ -65,7 +65,7 @@ kover.xmlReport > ./mill show mill.kotlinlib.kover/htmlReportAll # collect reports from all modules ... -...out/mill.kotlinlib.kover.Kover/htmlReportAll.dest/kover-report... +...$MILL_OUT/mill.kotlinlib.kover.Kover/htmlReportAll.dest/kover-report... > cat out/mill.kotlinlib.kover.Kover/htmlReportAll.dest/kover-report/index.html ... diff --git a/example/kotlinlib/module/10-dependency-injection/build.mill b/example/kotlinlib/module/10-dependency-injection/build.mill index 788946dcf6b4..a3a0b2af6aa9 100644 --- a/example/kotlinlib/module/10-dependency-injection/build.mill +++ b/example/kotlinlib/module/10-dependency-injection/build.mill @@ -47,8 +47,8 @@ object dagger extends KspModule { > ./mill show dagger.generatedSources [ - "ref:v0:.../out/dagger/generatedSourcesWithKsp2.dest/generated/java", - "ref:v0:.../out/dagger/generatedSourcesWithKsp2.dest/generated/kotlin" + "ref:v0:...$MILL_OUT/dagger/generatedSourcesWithKsp2.dest/generated/java", + "ref:v0:...$MILL_OUT/dagger/generatedSourcesWithKsp2.dest/generated/kotlin" ] > ls out/dagger/generatedSourcesWithKsp2.dest/generated/java/com/example/dagger/ diff --git a/example/kotlinlib/publishing/9-repackage-config/build.mill b/example/kotlinlib/publishing/9-repackage-config/build.mill index 83a97c99ff14..96627654f8d8 100644 --- a/example/kotlinlib/publishing/9-repackage-config/build.mill +++ b/example/kotlinlib/publishing/9-repackage-config/build.mill @@ -47,7 +47,7 @@ Qux.value: 31337 ...Test run bar.BarTests finished: 0 failed, 0 ignored, 1 total, ...s > ./mill show foo.repackagedJar -".../out/foo/repackagedJar.dest/out.jar" +"...$MILL_OUT/foo/repackagedJar.dest/out.jar" > ./out/foo/repackagedJar.dest/out.jar Foo.value:

hello

diff --git a/example/kotlinlib/script/10-resources/build.mill b/example/kotlinlib/script/10-resources/build.mill index 6985db0a0b9b..e5104f1f1955 100644 --- a/example/kotlinlib/script/10-resources/build.mill +++ b/example/kotlinlib/script/10-resources/build.mill @@ -13,7 +13,7 @@ Hello World Resource File /** Usage > ./mill show Foo.kt:assembly -".../out/Foo.kt/assembly.dest/out.jar" +"...$MILL_OUT/Foo.kt/assembly.dest/out.jar" > out/Foo.kt/assembly.dest/out.jar Hello World Resource File diff --git a/example/pythonlib/basic/1-simple/build.mill b/example/pythonlib/basic/1-simple/build.mill index 21ee94f61468..0982f38afd7a 100644 --- a/example/pythonlib/basic/1-simple/build.mill +++ b/example/pythonlib/basic/1-simple/build.mill @@ -87,7 +87,7 @@ OK ... > ./mill show foo.bundle # Creates Bundle for the python file -".../out/foo/bundle.dest/bundle.pex" +"...$MILL_OUT/foo/bundle.dest/bundle.pex" > out/foo/bundle.dest/bundle.pex --text "Hello Mill" # running the PEX binary outside of Mill

Hello Mill

diff --git a/example/pythonlib/module/1-common-config/build.mill b/example/pythonlib/module/1-common-config/build.mill index a399d898f067..95bf44f45294 100644 --- a/example/pythonlib/module/1-common-config/build.mill +++ b/example/pythonlib/module/1-common-config/build.mill @@ -75,7 +75,7 @@ MY_CUSTOM_ENV: my-env-value ... > ./mill show foo.bundle -".../out/foo/bundle.dest/bundle.pex" +"...$MILL_OUT/foo/bundle.dest/bundle.pex" > out/foo/bundle.dest/bundle.pex ... diff --git a/example/pythonlib/module/6-pex-config/build.mill b/example/pythonlib/module/6-pex-config/build.mill index ef6454532025..f27112c56e7a 100644 --- a/example/pythonlib/module/6-pex-config/build.mill +++ b/example/pythonlib/module/6-pex-config/build.mill @@ -44,7 +44,7 @@ object foo extends PythonModule { /** Usage > ./mill show foo.bundle -".../out/foo/bundle.dest/bundle.pex" +"...$MILL_OUT/foo/bundle.dest/bundle.pex" > out/foo/bundle.dest/bundle.pex ... diff --git a/example/pythonlib/publishing/1-publish-module/build.mill b/example/pythonlib/publishing/1-publish-module/build.mill index 75f91333158e..b6df9a67e92b 100644 --- a/example/pythonlib/publishing/1-publish-module/build.mill +++ b/example/pythonlib/publishing/1-publish-module/build.mill @@ -44,10 +44,10 @@ object `package` extends PythonModule, PublishModule { /** Usage > ./mill show sdist -".../out/sdist.dest/dist/testpkg_mill-0.0.2.tar.gz" +"...$MILL_OUT/sdist.dest/dist/testpkg_mill-0.0.2.tar.gz" > ./mill show wheel -".../out/wheel.dest/dist/testpkg_mill-0.0.2-py3-none-any.whl" +"...$MILL_OUT/wheel.dest/dist/testpkg_mill-0.0.2-py3-none-any.whl" */ // These files can then be `pip-installed` by other projects, or, if you're using Mill, you can diff --git a/example/scalalib/basic/1-script/build.mill b/example/scalalib/basic/1-script/build.mill index 4a1032593878..975b59718ca7 100644 --- a/example/scalalib/basic/1-script/build.mill +++ b/example/scalalib/basic/1-script/build.mill @@ -70,7 +70,7 @@ Jvm Version: 11.0.28 /** Usage > ./mill show Foo.scala:assembly # show the output of the assembly task -".../out/Foo.scala/assembly.dest/out.jar" +"...$MILL_OUT/Foo.scala/assembly.dest/out.jar" > java -jar ./out/Foo.scala/assembly.dest/out.jar --text hello

hello

diff --git a/example/scalalib/basic/10-realistic/build.mill b/example/scalalib/basic/10-realistic/build.mill index b9ea519a6e6e..2ec7435d5e2f 100644 --- a/example/scalalib/basic/10-realistic/build.mill +++ b/example/scalalib/basic/10-realistic/build.mill @@ -126,7 +126,7 @@ Publishing Artifact(com.lihaoyi,bar_3,0.0.1) to ivy repo... Publishing Artifact(com.lihaoyi,qux,0.0.1) to ivy repo... > ./mill show foo[2.13.16].assembly # mac/linux -".../out/foo/2.13.16/assembly.dest/out.jar" +"...$MILL_OUT/foo/2.13.16/assembly.dest/out.jar" > ./out/foo/2.13.16/assembly.dest/out.jar # mac/linux foo version 0.0.1 diff --git a/example/scalalib/basic/3-simple/build.mill b/example/scalalib/basic/3-simple/build.mill index 1138995a9734..976dd2c6bab3 100644 --- a/example/scalalib/basic/3-simple/build.mill +++ b/example/scalalib/basic/3-simple/build.mill @@ -101,7 +101,7 @@ compiling 1 Scala source to... > ./mill assembly # bundle classfiles and libraries into a jar for deployment > ./mill show assembly # show the output of the assembly task -".../out/assembly.dest/out.jar" +"...$MILL_OUT/assembly.dest/out.jar" > java -jar ./out/assembly.dest/out.jar --text hello

hello

diff --git a/example/scalalib/basic/6-programmatic/build.mill b/example/scalalib/basic/6-programmatic/build.mill index 8a2bcb597a9c..85824ede4b1c 100644 --- a/example/scalalib/basic/6-programmatic/build.mill +++ b/example/scalalib/basic/6-programmatic/build.mill @@ -83,7 +83,7 @@ foo.run > ./mill foo.assembly # bundle classfiles and libraries into a jar for deployment > ./mill show foo.assembly # show the output of the assembly task -".../out/foo/assembly.dest/out.jar" +"...$MILL_OUT/foo/assembly.dest/out.jar" > java -jar ./out/foo/assembly.dest/out.jar --text hello

hello

diff --git a/example/scalalib/config/1-common-config/build.mill b/example/scalalib/config/1-common-config/build.mill index 0a8cee6fc8f7..40240b0f8319 100644 --- a/example/scalalib/config/1-common-config/build.mill +++ b/example/scalalib/config/1-common-config/build.mill @@ -14,7 +14,7 @@ my.custom.property: my-prop-value MY_CUSTOM_ENV: my-env-value > ./mill show assembly -".../out/assembly.dest/out.jar" +"...$MILL_OUT/assembly.dest/out.jar" > ./out/assembly.dest/out.jar # mac/linux Foo2.value:

hello2

diff --git a/example/scalalib/module/15-unidoc/build.mill b/example/scalalib/module/15-unidoc/build.mill index 94f1f27fb1d2..38d594591792 100644 --- a/example/scalalib/module/15-unidoc/build.mill +++ b/example/scalalib/module/15-unidoc/build.mill @@ -34,7 +34,7 @@ object foo extends ScalaModule, UnidocModule { /** Usage > ./mill show foo.unidocLocal -".../out/foo/unidocLocal.dest" +"...$MILL_OUT/foo/unidocLocal.dest" > cat out/foo/unidocLocal.dest/foo/Foo.html ... diff --git a/example/scalalib/module/2-common-config/build.mill b/example/scalalib/module/2-common-config/build.mill index 6103b6ff4cea..30d516f56333 100644 --- a/example/scalalib/module/2-common-config/build.mill +++ b/example/scalalib/module/2-common-config/build.mill @@ -105,7 +105,7 @@ my.custom.property: my-prop-value MY_CUSTOM_ENV: my-env-value > ./mill show assembly -".../out/assembly.dest/out.jar" +"...$MILL_OUT/assembly.dest/out.jar" > ./out/assembly.dest/out.jar # mac/linux Foo2.value:

hello2

diff --git a/example/scalalib/native/1-simple/build.mill b/example/scalalib/native/1-simple/build.mill index f6a43a8451e8..0566d3473c52 100644 --- a/example/scalalib/native/1-simple/build.mill +++ b/example/scalalib/native/1-simple/build.mill @@ -26,7 +26,7 @@ object `package` extends ScalaNativeModule {

hello

> ./mill show nativeLink # Build and link native binary -".../out/nativeLink.dest/out" +"...$MILL_OUT/nativeLink.dest/out" > ./out/nativeLink.dest/out --text hello # Run the executable

hello

diff --git a/example/scalalib/publishing/9-repackage-config/build.mill b/example/scalalib/publishing/9-repackage-config/build.mill index 48cda4ce64b7..30e22ab17008 100644 --- a/example/scalalib/publishing/9-repackage-config/build.mill +++ b/example/scalalib/publishing/9-repackage-config/build.mill @@ -59,7 +59,7 @@ Qux.value: 31337 ...Test run bar.BarTests finished: 0 failed, 0 ignored, 1 total, ...s > ./mill show foo.repackagedJar -".../out/foo/repackagedJar.dest/out.jar" +"...$MILL_OUT/foo/repackagedJar.dest/out.jar" > ./out/foo/repackagedJar.dest/out.jar Foo.value:

hello

diff --git a/example/scalalib/script/10-resources/build.mill b/example/scalalib/script/10-resources/build.mill index 664f45838f8e..ae6cb540c380 100644 --- a/example/scalalib/script/10-resources/build.mill +++ b/example/scalalib/script/10-resources/build.mill @@ -23,7 +23,7 @@ Hello World Resource File /** Usage > ./mill show Foo.scala:assembly -".../out/Foo.scala/assembly.dest/out.jar" +"...$MILL_OUT/Foo.scala/assembly.dest/out.jar" > out/Foo.scala/assembly.dest/out.jar Hello World Resource File diff --git a/example/scalalib/spark/3-semi-realistic/build.mill b/example/scalalib/spark/3-semi-realistic/build.mill index 73668b29a008..66d4c8678555 100644 --- a/example/scalalib/spark/3-semi-realistic/build.mill +++ b/example/scalalib/spark/3-semi-realistic/build.mill @@ -46,7 +46,7 @@ Summary Statistics by Category: > chmod +x spark-submit.sh > ./mill show assembly # prepare for spark-submit -".../out/assembly.dest/out.jar" +"...$MILL_OUT/assembly.dest/out.jar" > ./spark-submit.sh out/assembly.dest/out.jar foo.Foo resources/transactions.csv ... diff --git a/example/scalalib/web/4-scalajs-module/build.mill b/example/scalalib/web/4-scalajs-module/build.mill index b9eae71f61c6..6d56f90ae0d4 100644 --- a/example/scalalib/web/4-scalajs-module/build.mill +++ b/example/scalalib/web/4-scalajs-module/build.mill @@ -41,7 +41,7 @@ stringifiedJsObject: ["hello","world","!"] { ... ..."jsFileName": "main.js", - "dest": ".../out/foo/fullLinkJS.dest" + "dest": "...$MILL_OUT/foo/fullLinkJS.dest" } > node out/foo/fullLinkJS.dest/main.js # mac/linux diff --git a/example/scalalib/web/9-wasm/build.mill b/example/scalalib/web/9-wasm/build.mill index f85403e81e10..a8443d6e1643 100644 --- a/example/scalalib/web/9-wasm/build.mill +++ b/example/scalalib/web/9-wasm/build.mill @@ -27,7 +27,7 @@ object wasm extends ScalaJSModule { ... ..."jsFileName": "main.js", ... - "dest": ".../out/wasm/fastLinkJS.dest" + "dest": "...$MILL_OUT/wasm/fastLinkJS.dest" } > node --experimental-wasm-exnref out/wasm/fastLinkJS.dest/main.js # mac/linux diff --git a/example/springboot/java/1-web-initializr/build.mill b/example/springboot/java/1-web-initializr/build.mill index c22f48d4b9b5..729995098fdb 100644 --- a/example/springboot/java/1-web-initializr/build.mill +++ b/example/springboot/java/1-web-initializr/build.mill @@ -50,6 +50,6 @@ object `package` extends MavenModule { > ./mill clean runBackground > ./mill show assembly -.../out/assembly.dest/out.jar... +...$MILL_OUT/assembly.dest/out.jar... */ diff --git a/example/springboot/kotlin/1-web-initializr/build.mill b/example/springboot/kotlin/1-web-initializr/build.mill index 62785513d86e..3c31ae30bd24 100644 --- a/example/springboot/kotlin/1-web-initializr/build.mill +++ b/example/springboot/kotlin/1-web-initializr/build.mill @@ -59,6 +59,6 @@ object `package` extends KotlinMavenModule { > ./mill clean runBackground > ./mill show assembly -.../out/assembly.dest/out.jar... +...$MILL_OUT/assembly.dest/out.jar... */ diff --git a/example/thirdparty/android-endless-tunnel/build.mill b/example/thirdparty/android-endless-tunnel/build.mill index 7bbec86eb8fc..081b3aefb782 100644 --- a/example/thirdparty/android-endless-tunnel/build.mill +++ b/example/thirdparty/android-endless-tunnel/build.mill @@ -53,7 +53,7 @@ object `endless-tunnel` extends mill.api.Module { /** Usage > ./mill show endless-tunnel.app.androidApk -".../out/endless-tunnel/app/androidApk.dest/app.apk" +"...$MILL_OUT/endless-tunnel/app/androidApk.dest/app.apk" > ./mill show endless-tunnel.app.createAndroidVirtualDevice ...Name: cpp-test, DeviceId: medium_phone... diff --git a/integration/ide/build-classpath-contents/src/BuildClasspathContentsTests.scala b/integration/ide/build-classpath-contents/src/BuildClasspathContentsTests.scala index fad8eaa2ccec..14c7e1484118 100644 --- a/integration/ide/build-classpath-contents/src/BuildClasspathContentsTests.scala +++ b/integration/ide/build-classpath-contents/src/BuildClasspathContentsTests.scala @@ -1,4 +1,4 @@ -import mill.api.BuildCtx +import mill.api.{BuildCtx, MappedRoots, PathRef} import mill.testkit.UtestIntegrationTestSuite import utest.* @@ -6,56 +6,61 @@ object BuildClasspathContentsTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { test("test") - integrationTest { tester => - val result1 = - tester.eval(("--meta-level", "1", "show", "compileClasspath"), stderr = os.Inherit) - val deserialized = upickle.read[Seq[mill.api.PathRef]](result1.out) - val millPublishedJars = deserialized - .map(_.path.last) - .filter(_.startsWith("mill-")) - .sorted - val millLocalClasspath = deserialized - .map(_.path) - .filter(_.startsWith(BuildCtx.workspaceRoot)) - .map(_.subRelativeTo(BuildCtx.workspaceRoot)) - .filter(!_.startsWith("out/integration")) - .filter(!_.startsWith("out/dist/localRepo.dest")) - .map(_.toString) - .sorted - if (sys.env("MILL_INTEGRATION_IS_PACKAGED_LAUNCHER") == "true") { - assertGoldenLiteral( - millPublishedJars, - List( - "mill-core-api-daemon_3-SNAPSHOT.jar", - "mill-core-api_3-SNAPSHOT.jar", - "mill-core-constants-SNAPSHOT.jar", - "mill-libs-androidlib-databinding_3-SNAPSHOT.jar", - "mill-libs-androidlib_3-SNAPSHOT.jar", - "mill-libs-daemon-client-SNAPSHOT.jar", - "mill-libs-daemon-server_3-SNAPSHOT.jar", - "mill-libs-javalib-api_3-SNAPSHOT.jar", - "mill-libs-javalib-testrunner-entrypoint-SNAPSHOT.jar", - "mill-libs-javalib-testrunner_3-SNAPSHOT.jar", - "mill-libs-javalib_3-SNAPSHOT.jar", - "mill-libs-javascriptlib_3-SNAPSHOT.jar", - "mill-libs-kotlinlib-api_3-SNAPSHOT.jar", - "mill-libs-kotlinlib-ksp2-api_3-SNAPSHOT.jar", - "mill-libs-kotlinlib_3-SNAPSHOT.jar", - "mill-libs-pythonlib_3-SNAPSHOT.jar", - "mill-libs-rpc_3-SNAPSHOT.jar", - "mill-libs-scalajslib-api_3-SNAPSHOT.jar", - "mill-libs-scalajslib_3-SNAPSHOT.jar", - "mill-libs-scalalib_3-SNAPSHOT.jar", - "mill-libs-scalanativelib-api_3-SNAPSHOT.jar", - "mill-libs-scalanativelib_3-SNAPSHOT.jar", - "mill-libs-script_3-SNAPSHOT.jar", - "mill-libs-util_3-SNAPSHOT.jar", - "mill-libs_3-SNAPSHOT.jar", - "mill-moduledefs_3-0.11.10.jar" + MappedRoots.withMapping(Seq( + "HOME" -> os.home, + "WORKSPACE" -> tester.workspacePath + )) { + val result1 = + tester.eval(("--meta-level", "1", "show", "compileClasspath"), stderr = os.Inherit) + val deserialized = upickle.read[Seq[mill.api.PathRef]](result1.out) + val millPublishedJars = deserialized + .map(_.path.last) + .filter(_.startsWith("mill-")) + .sorted + val millLocalClasspath = deserialized + .map(_.path) + .filter(_.startsWith(BuildCtx.workspaceRoot)) + .map(_.subRelativeTo(BuildCtx.workspaceRoot)) + .filter(!_.startsWith("out/integration")) + .filter(!_.startsWith("out/dist/localRepo.dest")) + .map(_.toString) + .sorted + if (sys.env("MILL_INTEGRATION_IS_PACKAGED_LAUNCHER") == "true") { + assertGoldenLiteral( + millPublishedJars, + List( + "mill-core-api-daemon_3-SNAPSHOT.jar", + "mill-core-api_3-SNAPSHOT.jar", + "mill-core-constants-SNAPSHOT.jar", + "mill-libs-androidlib-databinding_3-SNAPSHOT.jar", + "mill-libs-androidlib_3-SNAPSHOT.jar", + "mill-libs-daemon-client-SNAPSHOT.jar", + "mill-libs-daemon-server_3-SNAPSHOT.jar", + "mill-libs-javalib-api_3-SNAPSHOT.jar", + "mill-libs-javalib-testrunner-entrypoint-SNAPSHOT.jar", + "mill-libs-javalib-testrunner_3-SNAPSHOT.jar", + "mill-libs-javalib_3-SNAPSHOT.jar", + "mill-libs-javascriptlib_3-SNAPSHOT.jar", + "mill-libs-kotlinlib-api_3-SNAPSHOT.jar", + "mill-libs-kotlinlib-ksp2-api_3-SNAPSHOT.jar", + "mill-libs-kotlinlib_3-SNAPSHOT.jar", + "mill-libs-pythonlib_3-SNAPSHOT.jar", + "mill-libs-rpc_3-SNAPSHOT.jar", + "mill-libs-scalajslib-api_3-SNAPSHOT.jar", + "mill-libs-scalajslib_3-SNAPSHOT.jar", + "mill-libs-scalalib_3-SNAPSHOT.jar", + "mill-libs-scalanativelib-api_3-SNAPSHOT.jar", + "mill-libs-scalanativelib_3-SNAPSHOT.jar", + "mill-libs-script_3-SNAPSHOT.jar", + "mill-libs-util_3-SNAPSHOT.jar", + "mill-libs_3-SNAPSHOT.jar", + "mill-moduledefs_3-0.11.10.jar" + ) ) - ) - assert(millLocalClasspath == Nil) - } else { - sys.error("This test must be run in `packaged` mode, not `local`") + assert(millLocalClasspath == Nil) + } else { + sys.error("This test must be run in `packaged` mode, not `local`") + } } } } diff --git a/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala b/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala index 8fabf73fab97..4625dba1a362 100644 --- a/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala +++ b/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala @@ -1,5 +1,6 @@ package mill.integration +import mill.api.MappedRoots import mill.testkit.{IntegrationTester, UtestIntegrationTestSuite} import mill.constants.OutFiles.* import mill.daemon.RunnerState @@ -48,7 +49,13 @@ trait MultiLevelBuildTests extends UtestIntegrationTestSuite { yield { val path = tester.workspacePath / "out" / Seq.fill(depth)(millBuild) / millRunnerState - if (os.exists(path)) upickle.read[RunnerState.Frame.Logged](os.read(path)) -> path + if (os.exists(path)) + MappedRoots.withMillDefaults( + outPath = tester.workspacePath / "out", + workspacePath = tester.workspacePath + ) { + upickle.read[RunnerState.Frame.Logged](os.read(path)) -> path + } else RunnerState.Frame.Logged(Map(), Seq(), Seq(), None, Seq(), 0) -> path } } diff --git a/libs/javalib/src/mill/javalib/TestModule.scala b/libs/javalib/src/mill/javalib/TestModule.scala index 3925b9bd78bd..1f58c779bdc3 100644 --- a/libs/javalib/src/mill/javalib/TestModule.scala +++ b/libs/javalib/src/mill/javalib/TestModule.scala @@ -1,14 +1,10 @@ package mill.javalib import mill.T -import mill.api.Result +import mill.api.{DefaultTaskModule, MappedRoots, PathRef, Result, Task, TaskCtx} import mill.api.daemon.internal.TestModuleApi import mill.api.daemon.internal.TestReporter import mill.api.daemon.internal.bsp.{BspBuildTarget, BspModuleApi} -import mill.api.PathRef -import mill.api.Task -import mill.api.TaskCtx -import mill.api.DefaultTaskModule import mill.javalib.bsp.BspModule import mill.api.JsonFormatters.given import mill.constants.EnvVars @@ -195,7 +191,10 @@ trait TestModule ) val argsFile = Task.dest / "testargs" - os.write(argsFile, upickle.write(testArgs)) + MappedRoots.withMapping(Seq()) { + // Don't use placeholders, so we only have local absolute paths + os.write(argsFile, upickle.write(testArgs)) + } val testRunnerClasspathArg = jvmWorker().scalalibClasspath() diff --git a/libs/javalib/src/mill/javalib/TestModuleUtil.scala b/libs/javalib/src/mill/javalib/TestModuleUtil.scala index f80e59c3e435..227e27f58ab6 100644 --- a/libs/javalib/src/mill/javalib/TestModuleUtil.scala +++ b/libs/javalib/src/mill/javalib/TestModuleUtil.scala @@ -1,7 +1,6 @@ package mill.javalib -import mill.api.{PathRef, TaskCtx} -import mill.api.Result +import mill.api.{Logger, MappedRoots, PathRef, Result, TaskCtx} import mill.api.daemon.internal.TestReporter import mill.util.Jvm import mill.api.internal.Util @@ -13,8 +12,6 @@ import java.time.temporal.ChronoUnit import java.time.{Instant, LocalDateTime, ZoneId} import scala.xml.Elem import scala.collection.mutable -import mill.api.Logger - import java.util.concurrent.ConcurrentHashMap import mill.api.BuildCtx import mill.javalib.api.internal.ZincOp @@ -136,7 +133,10 @@ final class TestModuleUtil( val argsFile = baseFolder / "testargs" val sandbox = baseFolder / "sandbox" - os.write(argsFile, upickle.write(testArgs), createFolders = true) + MappedRoots.withMapping(Seq()) { + // Don't use placeholders, so we only have local absolute paths + os.write(argsFile, upickle.write(testArgs), createFolders = true) + } os.makeDir.all(sandbox) diff --git a/libs/javalib/test/src/mill/javalib/HelloJavaTests.scala b/libs/javalib/test/src/mill/javalib/HelloJavaTests.scala index 303dc58ad854..fada1674bca3 100644 --- a/libs/javalib/test/src/mill/javalib/HelloJavaTests.scala +++ b/libs/javalib/test/src/mill/javalib/HelloJavaTests.scala @@ -40,9 +40,9 @@ object HelloJavaTests extends TestSuite { assert( result1.value == result2.value, + result1.evalCount != 0, result2.evalCount == 0, result3.evalCount != 0, - result3.evalCount != 0, os.walk(result1.value.classes.path).exists(_.last == "Core.class"), !os.walk(result1.value.classes.path).exists(_.last == "Main.class"), os.walk(result3.value.classes.path).exists(_.last == "Main.class"), diff --git a/libs/javalib/testrunner/entrypoint/src/mill/javalib/testrunner/entrypoint/TestRunnerMain.java b/libs/javalib/testrunner/entrypoint/src/mill/javalib/testrunner/entrypoint/TestRunnerMain.java index 5930e98e6198..18e8d21283ec 100644 --- a/libs/javalib/testrunner/entrypoint/src/mill/javalib/testrunner/entrypoint/TestRunnerMain.java +++ b/libs/javalib/testrunner/entrypoint/src/mill/javalib/testrunner/entrypoint/TestRunnerMain.java @@ -14,6 +14,10 @@ * nested classloaders. */ public class TestRunnerMain { + /** + * + * @param args arg1: classpath, arg2 testArgs-file + */ public static void main(String[] args) throws Exception { URL[] testRunnerClasspath = Stream.of(args[0].split(",")) .map(s -> { diff --git a/libs/javalib/worker/src/mill/javalib/worker/NoMappedRootsMillRcpWireTransport.scala b/libs/javalib/worker/src/mill/javalib/worker/NoMappedRootsMillRcpWireTransport.scala new file mode 100644 index 000000000000..ce3f418714d0 --- /dev/null +++ b/libs/javalib/worker/src/mill/javalib/worker/NoMappedRootsMillRcpWireTransport.scala @@ -0,0 +1,25 @@ +package mill.javalib.worker + +import mill.api.MappedRoots +import mill.rpc.MillRpcWireTransport + +import java.io.{BufferedReader, PrintStream} + +class NoMappedRootsMillRcpWireTransport( + name: String, + serverToClient: BufferedReader, + clientToServer: PrintStream, + writeSynchronizer: AnyRef +) extends MillRpcWireTransport( + name = name, + serverToClient = serverToClient, + clientToServer = clientToServer, + writeSynchronizer = writeSynchronizer + ) { + override def writeSerialized[A: upickle.Writer](message: A, log: String => Unit): Unit = { + // RPC communication is local and uncached, so we don't want to use any root mapping + MappedRoots.withMapping(Seq()) { + super.writeSerialized(message, log) + } + } +} diff --git a/libs/javalib/worker/src/mill/javalib/worker/SubprocessZincApi.scala b/libs/javalib/worker/src/mill/javalib/worker/SubprocessZincApi.scala index 28bdc91d9443..f3c67fb83759 100644 --- a/libs/javalib/worker/src/mill/javalib/worker/SubprocessZincApi.scala +++ b/libs/javalib/worker/src/mill/javalib/worker/SubprocessZincApi.scala @@ -1,4 +1,5 @@ package mill.javalib.worker + import mill.api.* import mill.api.daemon.internal.CompileProblemReporter import mill.client.{LaunchedServer, ServerLauncher} @@ -6,7 +7,7 @@ import mill.javalib.api.internal.* import mill.javalib.internal.{RpcProblemMessage, ZincCompilerBridgeProvider} import mill.javalib.zinc.ZincWorkerRpcServer.ReporterMode import mill.javalib.zinc.{ZincApi, ZincWorker, ZincWorkerRpcServer} -import mill.rpc.{MillRpcChannel, MillRpcClient, MillRpcWireTransport} +import mill.rpc.{MillRpcChannel, MillRpcClient} import mill.util.CachedFactoryWithInitData import java.io.* @@ -93,13 +94,12 @@ class SubprocessZincApi( (in, out) => { val serverToClient = use(BufferedReader(InputStreamReader(in))) val clientToServer = use(PrintStream(out)) - val wireTransport = - MillRpcWireTransport( - debugName, - serverToClient, - clientToServer, - writeSynchronizer = clientToServer - ) + val wireTransport = NoMappedRootsMillRcpWireTransport( + name = debugName, + serverToClient = serverToClient, + clientToServer = clientToServer, + writeSynchronizer = clientToServer + ) val init = ZincWorkerRpcServer.Initialize(compilerBridgeWorkspace = compilerBridge.workspace) diff --git a/libs/javalib/worker/src/mill/javalib/zinc/ZincWorkerMain.scala b/libs/javalib/worker/src/mill/javalib/zinc/ZincWorkerMain.scala index 322e229a949d..9b5beb209bb3 100644 --- a/libs/javalib/worker/src/mill/javalib/zinc/ZincWorkerMain.scala +++ b/libs/javalib/worker/src/mill/javalib/zinc/ZincWorkerMain.scala @@ -1,9 +1,9 @@ package mill.javalib.zinc -import mill.api.SystemStreamsUtils import mill.api.daemon.{DummyInputStream, SystemStreams} +import mill.api.SystemStreamsUtils import mill.client.lock.Locks -import mill.rpc.MillRpcWireTransport +import mill.javalib.worker.NoMappedRootsMillRcpWireTransport import mill.server.Server import mill.server.Server.ConnectionData import pprint.{TPrint, TPrintColors} @@ -63,7 +63,8 @@ object ZincWorkerMain { Using.Manager { use => val stdin = use(BufferedReader(InputStreamReader(connectionData.clientToServer))) val stdout = use(PrintStream(connectionData.serverToClient)) - val transport = MillRpcWireTransport(serverName, stdin, stdout, writeSynchronizer) + val transport = + NoMappedRootsMillRcpWireTransport(serverName, stdin, stdout, writeSynchronizer) val server = ZincWorkerRpcServer(worker, serverName, transport, setIdle, serverLog) // Make sure stdout and stderr is sent to the client diff --git a/libs/rpc/src/mill/rpc/MillRpcWireTransport.scala b/libs/rpc/src/mill/rpc/MillRpcWireTransport.scala index abb6d3a31924..d859c4347604 100644 --- a/libs/rpc/src/mill/rpc/MillRpcWireTransport.scala +++ b/libs/rpc/src/mill/rpc/MillRpcWireTransport.scala @@ -5,6 +5,7 @@ import upickle.{Reader, Writer} import java.io.{BufferedReader, PrintStream} import scala.annotation.tailrec + class MillRpcWireTransport( val name: String, serverToClient: BufferedReader, diff --git a/libs/scalalib/test/src/mill/scalalib/HelloWorldTests.scala b/libs/scalalib/test/src/mill/scalalib/HelloWorldTests.scala index edfa402c6639..eb2a7e5f2d4a 100644 --- a/libs/scalalib/test/src/mill/scalalib/HelloWorldTests.scala +++ b/libs/scalalib/test/src/mill/scalalib/HelloWorldTests.scala @@ -159,101 +159,121 @@ object HelloWorldTests extends TestSuite { test("compile") { test("fromScratch") - UnitTester(HelloWorld, sourceRoot = resourcePath).scoped { eval => - val Right(result) = eval.apply(HelloWorld.core.compile): @unchecked - - val classesPath = eval.outPath / "core/compile.dest/classes" - val analysisFile = result.value.analysisFile - val outputFiles = os.walk(result.value.classes.path) - val expectedClassfiles = compileClassfiles.map(classesPath / _) - assert( - result.value.classes.path == classesPath, - os.exists(analysisFile), - outputFiles.nonEmpty, - outputFiles.forall(expectedClassfiles.contains), - result.evalCount > 0 - ) + if (scala.util.Properties.isJavaAtLeast(21)) + "Skipping on Java 21+ due to too old Scala version" + else { + val Right(result) = eval.apply(HelloWorld.core.compile): @unchecked + + val classesPath = eval.outPath / "core/compile.dest/classes" + val analysisFile = result.value.analysisFile + val outputFiles = os.walk(result.value.classes.path) + val expectedClassfiles = compileClassfiles.map(classesPath / _) + assert( + result.value.classes.path == classesPath, + os.exists(analysisFile), + outputFiles.nonEmpty, + outputFiles.forall(expectedClassfiles.contains), + result.evalCount > 0 + ) - // don't recompile if nothing changed - val Right(result2) = eval.apply(HelloWorld.core.compile): @unchecked + // don't recompile if nothing changed + val Right(result2) = eval.apply(HelloWorld.core.compile): @unchecked - assert(result2.evalCount == 0) + assert(result2.evalCount == 0) - // Make sure we *do not* end up compiling the compiler bridge, since - // it's using a pre-compiled bridge value - assert(!os.exists( - eval.outPath / "mill/scalalib/JvmWorkerModule/internalWorker.dest" / s"zinc-${zincVersion}" - )) + // Make sure we *do not* end up compiling the compiler bridge, since + // it's using a pre-compiled bridge value + assert(!os.exists( + eval.outPath / "mill/scalalib/JvmWorkerModule/internalWorker.dest" / s"zinc-${zincVersion}" + )) + } } test("nonPreCompiledBridge") - UnitTester( HelloWorldNonPrecompiledBridge, sourceRoot = resourcePath ).scoped { eval => - val Right(result) = eval.apply(HelloWorldNonPrecompiledBridge.core.compile): @unchecked + if (scala.util.Properties.isJavaAtLeast(21)) + "Skipping on Java 21+ due to too old Scala version" + else { + val Right(result) = eval.apply(HelloWorldNonPrecompiledBridge.core.compile): @unchecked - val classesPath = eval.outPath / "core/compile.dest/classes" + val classesPath = eval.outPath / "core/compile.dest/classes" - val analysisFile = result.value.analysisFile - val outputFiles = os.walk(result.value.classes.path) - val expectedClassfiles = compileClassfiles.map(classesPath / _) - assert( - result.value.classes.path == classesPath, - os.exists(analysisFile), - outputFiles.nonEmpty, - outputFiles.forall(expectedClassfiles.contains), - result.evalCount > 0 - ) + val analysisFile = result.value.analysisFile + val outputFiles = os.walk(result.value.classes.path) + val expectedClassfiles = compileClassfiles.map(classesPath / _) + assert( + result.value.classes.path == classesPath, + os.exists(analysisFile), + outputFiles.nonEmpty, + outputFiles.forall(expectedClassfiles.contains), + result.evalCount > 0 + ) - // don't recompile if nothing changed - val Right(result2) = eval.apply(HelloWorldNonPrecompiledBridge.core.compile): @unchecked + // don't recompile if nothing changed + val Right(result2) = eval.apply(HelloWorldNonPrecompiledBridge.core.compile): @unchecked - assert(result2.evalCount == 0) + assert(result2.evalCount == 0) - // Make sure we *do* end up compiling the compiler bridge, since it's - // *not* using a pre-compiled bridge value - assert(os.exists( - eval.outPath / "mill.javalib.JvmWorkerModule/internalWorker.dest" / s"zinc-${zincVersion}" - )) + // Make sure we *do* end up compiling the compiler bridge, since it's + // *not* using a pre-compiled bridge value + assert(os.exists( + eval.outPath / "mill.javalib.JvmWorkerModule/internalWorker.dest" / s"zinc-${zincVersion}" + )) + } } test("recompileOnChange") - UnitTester(HelloWorld, sourceRoot = resourcePath).scoped { eval => - val Right(result) = eval.apply(HelloWorld.core.compile): @unchecked - assert(result.evalCount > 0) + if (scala.util.Properties.isJavaAtLeast(21)) + "Skipping on Java 21+ due to too old Scala version" + else { + val Right(result) = eval.apply(HelloWorld.core.compile): @unchecked + assert(result.evalCount > 0) - os.write.append(HelloWorld.moduleDir / "core/src/Main.scala", "\n") + os.write.append(HelloWorld.moduleDir / "core/src/Main.scala", "\n") - val Right(result2) = eval.apply(HelloWorld.core.compile): @unchecked - assert(result2.evalCount > 0, result2.evalCount < result.evalCount) + val Right(result2) = eval.apply(HelloWorld.core.compile): @unchecked + assert(result2.evalCount > 0, result2.evalCount < result.evalCount) + } } test("failOnError") - UnitTester(HelloWorld, sourceRoot = resourcePath).scoped { eval => - os.write.append(HelloWorld.moduleDir / "core/src/Main.scala", "val x: ") + if (scala.util.Properties.isJavaAtLeast(21)) + "Skipping on Java 21+ due to too old Scala version" + else { + os.write.append(HelloWorld.moduleDir / "core/src/Main.scala", "val x: ") - val Left(ExecResult.Failure("Compilation failed")) = - eval.apply(HelloWorld.core.compile): @unchecked + val Left(ExecResult.Failure("Compilation failed")) = + eval.apply(HelloWorld.core.compile): @unchecked - val paths = ExecutionPaths.resolve(eval.outPath, HelloWorld.core.compile) + val paths = ExecutionPaths.resolve(eval.outPath, HelloWorld.core.compile) - assert( - os.walk(paths.dest / "classes").isEmpty, - !os.exists(paths.meta) - ) - // Works when fixed - os.write.over( - HelloWorld.moduleDir / "core/src/Main.scala", - os.read(HelloWorld.moduleDir / "core/src/Main.scala").dropRight( - "val x: ".length + assert( + os.walk(paths.dest / "classes").isEmpty, + !os.exists(paths.meta) + ) + // Works when fixed + os.write.over( + HelloWorld.moduleDir / "core/src/Main.scala", + os.read(HelloWorld.moduleDir / "core/src/Main.scala").dropRight( + "val x: ".length + ) ) - ) - val Right(_) = eval.apply(HelloWorld.core.compile): @unchecked + val Right(_) = eval.apply(HelloWorld.core.compile): @unchecked + } } test("passScalacOptions") - UnitTester( HelloWorldFatalWarnings, sourceRoot = resourcePath ).scoped { eval => - // compilation fails because of "-Xfatal-warnings" flag - val Left(ExecResult.Failure("Compilation failed")) = - eval.apply(HelloWorldFatalWarnings.core.compile): @unchecked + if (scala.util.Properties.isJavaAtLeast(21)) + "Skipping on Java 21+ due to too old Scala version" + else { + // compilation fails because of "-Xfatal-warnings" flag + val Left(ExecResult.Failure("Compilation failed")) = + eval.apply(HelloWorldFatalWarnings.core.compile): @unchecked + } } } @@ -266,39 +286,47 @@ object HelloWorldTests extends TestSuite { test("jar") { test("nonEmpty") - UnitTester(HelloWorldWithMain, resourcePath).scoped { eval => - val Right(result) = eval.apply(HelloWorldWithMain.core.jar): @unchecked + if (scala.util.Properties.isJavaAtLeast(21)) + "Skipping on Java 21+ due to too old Scala version" + else { + val Right(result) = eval.apply(HelloWorldWithMain.core.jar): @unchecked - assert( - os.exists(result.value.path), - result.evalCount > 0 - ) + assert( + os.exists(result.value.path), + result.evalCount > 0 + ) - Using.resource(new JarFile(result.value.path.toIO)) { jarFile => - val entries = jarFile.entries().asScala.map(_.getName).toSeq.sorted + Using.resource(new JarFile(result.value.path.toIO)) { jarFile => + val entries = jarFile.entries().asScala.map(_.getName).toSeq.sorted - val otherFiles = Seq( - "META-INF/", - "META-INF/MANIFEST.MF", - "reference.conf" - ) - val expectedFiles = (compileClassfiles.map(_.toString()) ++ otherFiles).sorted + val otherFiles = Seq( + "META-INF/", + "META-INF/MANIFEST.MF", + "reference.conf" + ) + val expectedFiles = (compileClassfiles.map(_.toString()) ++ otherFiles).sorted - assert( - entries.nonEmpty, - entries == expectedFiles - ) + assert( + entries.nonEmpty, + entries == expectedFiles + ) - val mainClass = jarMainClass(jarFile) - assert(mainClass.contains("Main")) + val mainClass = jarMainClass(jarFile) + assert(mainClass.contains("Main")) + } } } test("logOutputToFile") - UnitTester(HelloWorld, resourcePath).scoped { eval => - val outPath = eval.outPath - eval.apply(HelloWorld.core.compile) - - val logFile = outPath / "core/compile.log" - assert(os.exists(logFile)) + if (scala.util.Properties.isJavaAtLeast(21)) + "Skipping on Java 21+ due to too old Scala version" + else { + val outPath = eval.outPath + eval.apply(HelloWorld.core.compile) + + val logFile = outPath / "core/compile.log" + assert(os.exists(logFile)) + } } } } diff --git a/runner/daemon/src/mill/daemon/MillBuildBootstrap.scala b/runner/daemon/src/mill/daemon/MillBuildBootstrap.scala index 3a19d2ce9721..10e668f3739f 100644 --- a/runner/daemon/src/mill/daemon/MillBuildBootstrap.scala +++ b/runner/daemon/src/mill/daemon/MillBuildBootstrap.scala @@ -7,12 +7,12 @@ import mill.api.daemon.internal.{ PathRefApi, RootModuleApi } -import mill.api.{Logger, Result, SystemStreams, Val} +import mill.api.{BuildCtx, Logger, MappedRoots, PathRef, Result, SelectMode, SystemStreams, Val} import mill.constants.CodeGenConstants.* import mill.constants.OutFiles.{millBuild, millRunnerState} import mill.api.daemon.Watchable import mill.api.internal.RootModule -import mill.api.{BuildCtx, PathRef, SelectMode} +import mill.constants.PathVars import mill.internal.PrefixLogger import mill.meta.MillBuildRootModule import mill.meta.CliImports @@ -70,11 +70,13 @@ class MillBuildBootstrap( val runnerState = evaluateRec(0) for ((frame, depth) <- runnerState.frames.zipWithIndex) { - os.write.over( - recOut(output, depth) / millRunnerState, - upickle.write(frame.loggedData, indent = 4), - createFolders = true - ) + MappedRoots.withMillDefaults(outPath = output) { + os.write.over( + recOut(output, depth) / millRunnerState, + upickle.write(frame.loggedData, indent = 4), + createFolders = true + ) + } } Watching.Result( @@ -85,6 +87,10 @@ class MillBuildBootstrap( } def evaluateRec(depth: Int): RunnerState = { + + // We need relocatable PathRef for meta-builds for a stable classpathSig + MappedRoots.requireMappedPaths(PathVars.WORKSPACE, PathVars.HOME, PathVars.MILL_OUT) + logger.withChromeProfile(s"meta-level $depth") { // println(s"+evaluateRec($depth) " + recRoot(projectRoot, depth)) val currentRoot = recRoot(projectRoot, depth) @@ -253,24 +259,25 @@ class MillBuildBootstrap( case Result.Success((buildFileApi)) => Using.resource(makeEvaluator( - projectRoot, - output, - keepGoing, - env, - logger, - ec, - allowPositionalCommandArgs, - systemExit, - streams0, - selectiveExecution, - offline, - newWorkerCache, - nestedState.frames.headOption.map(_.codeSignatures).getOrElse(Map.empty), - buildFileApi.rootModule, + projectRoot = projectRoot, + output = output, + keepGoing = keepGoing, + env = env, + logger = logger, + ec = ec, + allowPositionalCommandArgs = allowPositionalCommandArgs, + systemExit = systemExit, + streams0 = streams0, + selectiveExecution = selectiveExecution, + offline = offline, + workerCache = newWorkerCache, + codeSignatures = + nestedState.frames.headOption.map(_.codeSignatures).getOrElse(Map.empty), + rootModule = buildFileApi.rootModule, // We want to use the grandparent buildHash, rather than the parent // buildHash, because the parent build changes are instead detected // by analyzing the scriptImportGraph in a more fine-grained manner. - nestedState + millClassloaderSigHash = nestedState .frames .dropRight(1) .headOption @@ -278,13 +285,13 @@ class MillBuildBootstrap( .getOrElse(millBootClasspathPathRefs) .map(p => (os.Path(p.javaPath), p.sig)) .hashCode(), - nestedState + millClassloaderIdentityHash = nestedState .frames .headOption .flatMap(_.classLoaderOpt) .map(_.hashCode()) .getOrElse(0), - depth, + depth = depth, actualBuildFileName = nestedState.buildFile, enableTicker = enableTicker )) { evaluator => diff --git a/runner/daemon/src/mill/daemon/MillDaemonMain.scala b/runner/daemon/src/mill/daemon/MillDaemonMain.scala index 0eeaaecb876e..00ea81c6e782 100644 --- a/runner/daemon/src/mill/daemon/MillDaemonMain.scala +++ b/runner/daemon/src/mill/daemon/MillDaemonMain.scala @@ -1,27 +1,29 @@ package mill.daemon -import mill.api.{BuildCtx, SystemStreams} +import mill.api.{MappedRoots, SystemStreams} import mill.client.lock.{Lock, Locks} -import mill.constants.{OutFiles, OutFolderMode} +import mill.constants.OutFolderMode import mill.server.Server import scala.concurrent.duration.* import scala.util.{Failure, Properties, Success, Try} object MillDaemonMain { - case class Args(daemonDir: os.Path, outMode: OutFolderMode, rest: Seq[String]) + case class Args(daemonDir: os.Path, outMode: OutFolderMode, outDir: os.Path, rest: Seq[String]) + object Args { def apply(appName: String, args: Array[String]): Either[String, Args] = { def usage(extra: String = "") = - s"usage: $appName $extra" + s"usage: $appName $extra" args match { - case Array(daemonDir, outModeStr, rest*) => + case Array(daemonDir, outModeStr, outDir, rest*) => Try(OutFolderMode.fromString(outModeStr)) match { case Failure(_) => val possibleValues = OutFolderMode.values.map(_.asString).mkString(", ") Left(usage(s"\n\n must be one of $possibleValues but was '$outModeStr'")) - case Success(outMode) => Right(apply(os.Path(daemonDir), outMode, rest)) + case Success(outMode) => + Right(apply(os.Path(daemonDir), outMode, os.Path(outDir), rest)) } case _ => Left(usage()) } @@ -36,27 +38,30 @@ object MillDaemonMain { val args = Args(getClass.getName, args0).fold(err => throw IllegalArgumentException(err), identity) - // temporarily disabling FFM use by coursier, which has issues with the way - // Mill manages class loaders, throwing things like - // UnsatisfiedLinkError: Native Library C:\Windows\System32\ole32.dll already loaded in another classloader - if (Properties.isWin) sys.props("coursier.windows.disable-ffm") = "true" + MappedRoots.withMillDefaults(outPath = args.outDir) { + // temporarily disabling FFM use by coursier, which has issues with the way + // Mill manages class loaders, throwing things like + // UnsatisfiedLinkError: Native Library C:\Windows\System32\ole32.dll already loaded in another classloader + if (Properties.isWin) sys.props("coursier.windows.disable-ffm") = "true" - coursier.Resolve.proxySetup() // Take into account proxy-related Java properties + coursier.Resolve.proxySetup() // Take into account proxy-related Java properties - mill.api.SystemStreamsUtils.withTopLevelSystemStreamProxy { - Server.overrideSigIntHandling() + mill.api.SystemStreamsUtils.withTopLevelSystemStreamProxy { + Server.overrideSigIntHandling() - val acceptTimeout = - Try(System.getProperty("mill.server_timeout").toInt.millis).getOrElse(30.minutes) + val acceptTimeout = + Try(System.getProperty("mill.server_timeout").toInt.millis).getOrElse(30.minutes) - val exitCode = new MillDaemonMain( - daemonDir = args.daemonDir, - acceptTimeout = acceptTimeout, - Locks.files(args.daemonDir.toString), - outMode = args.outMode - ).run().getOrElse(0) + val exitCode = new MillDaemonMain( + daemonDir = args.daemonDir, + acceptTimeout = acceptTimeout, + Locks.files(args.daemonDir.toString), + outMode = args.outMode, + outDir = args.outDir + ).run().getOrElse(0) - System.exit(exitCode) + System.exit(exitCode) + } } } } @@ -65,18 +70,18 @@ class MillDaemonMain( daemonDir: os.Path, acceptTimeout: FiniteDuration, locks: Locks, - outMode: OutFolderMode + outMode: OutFolderMode, + outDir: os.Path ) extends mill.server.MillDaemonServer[RunnerState]( - daemonDir, - acceptTimeout, - locks + daemonDir = daemonDir, + acceptTimeout = acceptTimeout, + locks = locks, + outDir = outDir ) { def initialStateCache = RunnerState.empty - val outFolder: os.Path = os.Path(OutFiles.outFor(outMode), BuildCtx.workspaceRoot) - - val outLock = MillMain0.doubleLock(outFolder) + val outLock = MillMain0.doubleLock(outDir) def main0( args: Array[String], @@ -100,7 +105,8 @@ class MillDaemonMain( initialSystemProperties = initialSystemProperties, systemExit = systemExit, daemonDir = daemonDir, - outLock = outLock + outLock = outLock, + outDir = outDir ) catch MillMain0.handleMillException(streams.err, stateCache) } diff --git a/runner/daemon/src/mill/daemon/MillMain0.scala b/runner/daemon/src/mill/daemon/MillMain0.scala index a4d721231e2a..6688cca76943 100644 --- a/runner/daemon/src/mill/daemon/MillMain0.scala +++ b/runner/daemon/src/mill/daemon/MillMain0.scala @@ -3,11 +3,10 @@ package mill.daemon import ch.epfl.scala.bsp4j.BuildClient import mill.api.daemon.internal.bsp.BspServerHandle import mill.api.daemon.internal.{CompileProblemReporter, EvaluatorApi} -import mill.api.{Logger, MillException, Result, SystemStreams} +import mill.api.{BuildCtx, Logger, MappedRoots, MillException, Result, SystemStreams} import mill.bsp.BSP import mill.client.lock.{DoubleLock, Lock} -import mill.constants.{DaemonFiles, OutFiles, OutFolderMode} -import mill.api.BuildCtx +import mill.constants.{DaemonFiles, OutFiles} import mill.internal.{ Colors, JsonArrayLogger, @@ -65,12 +64,12 @@ object MillMain0 { private def withStreams[T]( bspMode: Boolean, - streams: SystemStreams + streams: SystemStreams, + outDir: os.Path )(thunk: SystemStreams => T): T = if (bspMode) { // In BSP mode, don't let anything other than the BSP server write to stdout and read from stdin - val outDir = BuildCtx.workspaceRoot / os.RelPath(OutFiles.outFor(OutFolderMode.BSP)) val outFileStream = os.write.outputStream( outDir / "mill-bsp/out.log", createFolders = true @@ -109,8 +108,9 @@ object MillMain0 { initialSystemProperties: Map[String, String], systemExit: Server.StopServer, daemonDir: os.Path, - outLock: Lock - ): (Boolean, RunnerState) = + outLock: Lock, + outDir: os.Path + ): (Boolean, RunnerState) = MappedRoots.withMillDefaults(outPath = outDir) { mill.api.daemon.internal.MillScalaParser.current.withValue(MillScalaParserImpl) { os.SubProcess.env.withValue(env) { val parserResult = MillCliConfig.parse(args) @@ -121,7 +121,7 @@ object MillMain0 { // This is especially helpful if anything unexpectedly goes wrong // early on, when developing on Mill or debugging things for example. val bspMode = parserResult.toOption.exists(_.bsp.value) - withStreams(bspMode, streams0) { streams => + withStreams(bspMode, streams0, outDir) { streams => parserResult match { // Cannot parse args case Result.Failure(msg) => @@ -178,7 +178,7 @@ object MillMain0 { // special BSP mode, in which we spawn a server and register the current evaluator when-ever we start to eval a dedicated command val bspMode = config.bsp.value && config.leftoverArgs.value.isEmpty - val outMode = if (bspMode) OutFolderMode.BSP else OutFolderMode.REGULAR + val bspInstallModeJobCountOpt = { def defaultJobCount = maybeThreadCount.toOption.getOrElse(BSP.defaultJobCount) @@ -241,7 +241,6 @@ object MillMain0 { if (threadCount == 1) None else Some(mill.exec.ExecutionContexts.createExecutor(threadCount)) - val out = os.Path(OutFiles.outFor(outMode), BuildCtx.workspaceRoot) Using.resources(new TailManager(daemonDir), createEc()) { (tailManager, ec) => def runMillBootstrap( skipSelectiveExecution: Boolean, @@ -257,7 +256,7 @@ object MillMain0 { ): Watching.Result[RunnerState] = MillDaemonServer.withOutLock( noBuildLock = config.noBuildLock.value, noWaitForBuildLock = config.noWaitForBuildLock.value, - out = out, + out = outDir, millActiveCommandMessage = millActiveCommandMessage, streams = streams, outLock = outLock, @@ -270,7 +269,8 @@ object MillMain0 { // Do this by removing the file rather than disabling selective execution, // because we still want to generate the selective execution metadata json // for subsequent runs that may use it - if (skipSelectiveExecution) os.remove(out / OutFiles.millSelectiveExecution) + if (skipSelectiveExecution) + os.remove(outDir / OutFiles.millSelectiveExecution) mill.api.SystemStreamsUtils.withStreams(logger.streams) { mill.api.FilesystemCheckerEnabled.withValue( !config.noFilesystemChecker.value @@ -278,7 +278,7 @@ object MillMain0 { tailManager.withOutErr(logger.streams.out, logger.streams.err) { new MillBuildBootstrap( projectRoot = BuildCtx.workspaceRoot, - output = out, + output = outDir, // In BSP server, we want to evaluate as many tasks as possible, // in order to give as many results as available in BSP responses keepGoing = bspMode || config.keepGoing.value, @@ -313,7 +313,7 @@ object MillMain0 { daemonDir = daemonDir, colored = colored, colors = colors, - out = out + out = outDir )) { logger => proceed(logger) } @@ -358,7 +358,7 @@ object MillMain0 { val bspLogger = getBspLogger(streams, config) var prevRunnerStateOpt = Option.empty[RunnerState] val (bspServerHandle, buildClient) = - startBspServer(streams0, outLock, bspLogger) + startBspServer(streams0, outLock, bspLogger, outDir) var keepGoing = true var errored = false val initCommandLogger = new PrefixLogger(bspLogger, Seq("init")) @@ -510,6 +510,7 @@ object MillMain0 { } } } + if (config.ringBell.value) { if (success) println("\u0007") else { @@ -524,6 +525,7 @@ object MillMain0 { } } } + } /** * Starts the BSP server @@ -533,13 +535,13 @@ object MillMain0 { def startBspServer( bspStreams: SystemStreams, outLock: Lock, - bspLogger: Logger + bspLogger: Logger, + outDir: os.Path ): (BspServerHandle, BuildClient) = { bspLogger.info("Trying to load BSP server...") - val wsRoot = BuildCtx.workspaceRoot - val outFolder = wsRoot / os.RelPath(OutFiles.outFor(OutFolderMode.BSP)) - val logDir = outFolder / "mill-bsp" + BuildCtx.workspaceRoot + val logDir = outDir / "mill-bsp" os.makeDir.all(logDir) val bspServerHandleRes = @@ -550,7 +552,7 @@ object MillMain0 { true, outLock, bspLogger, - outFolder + outDir ).get bspLogger.info("BSP server started") diff --git a/runner/daemon/src/mill/daemon/MillNoDaemonMain.scala b/runner/daemon/src/mill/daemon/MillNoDaemonMain.scala index f70dbd2282a7..bcbb5754876a 100644 --- a/runner/daemon/src/mill/daemon/MillNoDaemonMain.scala +++ b/runner/daemon/src/mill/daemon/MillNoDaemonMain.scala @@ -2,13 +2,13 @@ package mill.daemon import mill.constants.{DaemonFiles, OutFiles, Util} import mill.daemon.MillMain0.{handleMillException, main0} -import mill.api.BuildCtx import mill.server.Server import scala.jdk.CollectionConverters.* import scala.util.Properties object MillNoDaemonMain { + def main(args0: Array[String]): Unit = mill.api.SystemStreamsUtils.withTopLevelSystemStreamProxy { val initialSystemStreams = mill.api.SystemStreams.original @@ -28,9 +28,8 @@ object MillNoDaemonMain { .fold(err => throw IllegalArgumentException(err), identity) val processId = Server.computeProcessId() - val out = os.Path(OutFiles.outFor(args.outMode), BuildCtx.workspaceRoot) Server.watchProcessIdFile( - out / OutFiles.millNoDaemon / s"pid-$processId" / DaemonFiles.processId, + args.outDir / OutFiles.millNoDaemon / s"pid-$processId" / DaemonFiles.processId, processId, running = () => true, exit = msg => { @@ -39,7 +38,7 @@ object MillNoDaemonMain { } ) - val outLock = MillMain0.doubleLock(out) + val outLock = MillMain0.doubleLock(args.outDir) val (result, _) = try main0( @@ -53,7 +52,8 @@ object MillNoDaemonMain { initialSystemProperties = sys.props.toMap, systemExit = ( /*reason*/ _, exitCode) => sys.exit(exitCode), daemonDir = args.daemonDir, - outLock = outLock + outLock = outLock, + outDir = args.outDir ) catch handleMillException(initialSystemStreams.err, ()) diff --git a/runner/launcher/src/mill/launcher/MillLauncherMain.java b/runner/launcher/src/mill/launcher/MillLauncherMain.java index a914102421af..233a0369424b 100644 --- a/runner/launcher/src/mill/launcher/MillLauncherMain.java +++ b/runner/launcher/src/mill/launcher/MillLauncherMain.java @@ -1,5 +1,6 @@ package mill.launcher; +import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -54,6 +55,7 @@ public static void main(String[] args) throws Exception { var outMode = bspMode ? OutFolderMode.BSP : OutFolderMode.REGULAR; exitInTestsAfterBspCheck(); var outDir = OutFiles.outFor(outMode); + var outPath = new File(outDir).getAbsoluteFile(); if (outMode == OutFolderMode.BSP) { System.err.println( @@ -87,8 +89,8 @@ public static void main(String[] args) throws Exception { if (runNoDaemon) { String mainClass = bspMode ? "mill.daemon.MillBspMain" : "mill.daemon.MillNoDaemonMain"; // start in no-server mode - int exitCode = - MillProcessLauncher.launchMillNoDaemon(args, outMode, runnerClasspath, mainClass); + int exitCode = MillProcessLauncher.launchMillNoDaemon( + args, outMode, outPath, runnerClasspath, mainClass); System.exit(exitCode); } else { var logs = new java.util.ArrayList(); @@ -107,9 +109,9 @@ public static void main(String[] args) throws Exception { Optional.empty(), -1) { public LaunchedServer initServer(Path daemonDir, Locks locks) throws Exception { - return new LaunchedServer.OsProcess( - MillProcessLauncher.launchMillDaemon(daemonDir, outMode, runnerClasspath) - .toHandle()); + return new LaunchedServer.OsProcess(MillProcessLauncher.launchMillDaemon( + daemonDir, outMode, outPath, runnerClasspath) + .toHandle()); } }; diff --git a/runner/launcher/src/mill/launcher/MillProcessLauncher.java b/runner/launcher/src/mill/launcher/MillProcessLauncher.java index 2042ec335ce9..3e8d7291a19d 100644 --- a/runner/launcher/src/mill/launcher/MillProcessLauncher.java +++ b/runner/launcher/src/mill/launcher/MillProcessLauncher.java @@ -20,7 +20,7 @@ public class MillProcessLauncher { static int launchMillNoDaemon( - String[] args, OutFolderMode outMode, String[] runnerClasspath, String mainClass) + String[] args, OutFolderMode outMode, File outDir, String[] runnerClasspath, String mainClass) throws Exception { final String sig = String.format("%08x", UUID.randomUUID().hashCode()); final Path processDir = @@ -35,6 +35,7 @@ static int launchMillNoDaemon( l.add(mainClass); l.add(processDir.toAbsolutePath().toString()); l.add(outMode.asString()); + l.add(outDir.toString()); l.addAll(millOpts(outMode)); l.addAll(Arrays.asList(args)); @@ -60,12 +61,14 @@ static int launchMillNoDaemon( } } - static Process launchMillDaemon(Path daemonDir, OutFolderMode outMode, String[] runnerClasspath) + static Process launchMillDaemon( + Path daemonDir, OutFolderMode outMode, File outDir, String[] runnerClasspath) throws Exception { List l = new ArrayList<>(millLaunchJvmCommand(outMode, runnerClasspath)); l.add("mill.daemon.MillDaemonMain"); l.add(daemonDir.toFile().getCanonicalPath()); l.add(outMode.asString()); + l.add(outDir.toString()); ProcessBuilder builder = new ProcessBuilder() .command(l) @@ -265,11 +268,6 @@ static List millLaunchJvmCommand(OutFolderMode outMode, String[] runnerC return vmOptions; } - static String[] cachedComputedValue( - OutFolderMode outMode, String name, String key, Supplier block) { - return cachedComputedValue0(outMode, name, key, block, arr -> true); - } - static String[] cachedComputedValue0( OutFolderMode outMode, String name, @@ -307,6 +305,11 @@ static String[] cachedComputedValue0( } } + static String[] cachedComputedValue( + OutFolderMode outMode, String name, String key, Supplier block) { + return cachedComputedValue0(outMode, name, key, block, arr -> true); + } + static int getTerminalDim(String s, boolean inheritError) throws Exception { Process proc = new ProcessBuilder() .command("tput", s) diff --git a/runner/server/src/mill/server/MillDaemonServer.scala b/runner/server/src/mill/server/MillDaemonServer.scala index 76a9c386661b..a9dab2f857b4 100644 --- a/runner/server/src/mill/server/MillDaemonServer.scala +++ b/runner/server/src/mill/server/MillDaemonServer.scala @@ -25,6 +25,7 @@ abstract class MillDaemonServer[State]( daemonDir: os.Path, acceptTimeout: FiniteDuration, locks: Locks, + outDir: os.Path, testLogEvenWhenServerIdWrong: Boolean = false ) extends Server[DaemonServerData, Int](Server.Args( daemonDir = daemonDir, @@ -35,7 +36,6 @@ abstract class MillDaemonServer[State]( )) { def outLock: mill.client.lock.Lock - def outFolder: os.Path private var stateCache: State = initialStateCache @@ -90,7 +90,7 @@ abstract class MillDaemonServer[State]( MillDaemonServer.withOutLock( noBuildLock = false, noWaitForBuildLock = false, - out = outFolder, + out = outDir, millActiveCommandMessage = "checking server mill version and java version", streams = new mill.api.daemon.SystemStreams( new PrintStream(mill.api.daemon.DummyOutputStream), diff --git a/runner/server/test/src/mill/server/ClientServerTests.scala b/runner/server/test/src/mill/server/ClientServerTests.scala index d5ce210e4399..b0d87e9989fd 100644 --- a/runner/server/test/src/mill/server/ClientServerTests.scala +++ b/runner/server/test/src/mill/server/ClientServerTests.scala @@ -26,16 +26,15 @@ object ClientServerTests extends TestSuite { testLogEvenWhenServerIdWrong: Boolean, commandSleepMillis: Int = 0 ) extends MillDaemonServer[Option[Int]]( - daemonDir, - 1000.millis, - locks, - testLogEvenWhenServerIdWrong + daemonDir = daemonDir, + acceptTimeout = 1000.millis, + locks = locks, + outDir = os.temp.dir(), + testLogEvenWhenServerIdWrong = testLogEvenWhenServerIdWrong ) { override def outLock = mill.client.lock.Lock.memory() - override def outFolder = os.temp.dir() - def initialStateCache = None override def serverLog0(s: String) = { diff --git a/testkit/src/mill/testkit/UnitTester.scala b/testkit/src/mill/testkit/UnitTester.scala index 3b90d4771683..8b9e8b3d6dc9 100644 --- a/testkit/src/mill/testkit/UnitTester.scala +++ b/testkit/src/mill/testkit/UnitTester.scala @@ -1,12 +1,20 @@ package mill.testkit import mill.Task -import mill.api.{BuildCtx, DummyInputStream, ExecResult, Result, SystemStreams, Val} +import mill.api.{ + BuildCtx, + DummyInputStream, + Evaluator, + ExecResult, + MappedRoots, + Result, + SelectMode, + SystemStreams, + Val +} import mill.api.ExecResult.OuterStack import mill.constants.OutFiles.millChromeProfile import mill.constants.OutFiles.millProfile -import mill.api.Evaluator -import mill.api.SelectMode import mill.internal.JsonArrayLogger import mill.resolve.Resolve @@ -229,7 +237,9 @@ class UnitTester( def scoped[T](tester: UnitTester => T): T = { try { BuildCtx.workspaceRoot0.withValue(module.moduleDir) { - tester(this) + MappedRoots.withMillDefaults(outPath = outPath) { + tester(this) + } } } finally close() } diff --git a/website/blog/modules/ROOT/pages/12-direct-style-build-tool.adoc b/website/blog/modules/ROOT/pages/12-direct-style-build-tool.adoc index a58837e17ede..d16806d8ee01 100644 --- a/website/blog/modules/ROOT/pages/12-direct-style-build-tool.adoc +++ b/website/blog/modules/ROOT/pages/12-direct-style-build-tool.adoc @@ -74,7 +74,7 @@ Test foo.FooTest.testSimple finished, ... 0 failed, 0 ignored, 2 total, ... > ./mill show foo.assembly -".../out/foo/assembly.dest/out.jar" +"...$MILL_OUT/foo/assembly.dest/out.jar" > ./out/foo/assembly.dest/out.jar --text hello

hello

diff --git a/website/blog/modules/ROOT/pages/7-graal-native-executables.adoc b/website/blog/modules/ROOT/pages/7-graal-native-executables.adoc index 2eeb3eff3cf9..1e952c1aae48 100644 --- a/website/blog/modules/ROOT/pages/7-graal-native-executables.adoc +++ b/website/blog/modules/ROOT/pages/7-graal-native-executables.adoc @@ -107,7 +107,7 @@ outside of the build tool: [source,console] ---- $ ./mill show foo.assembly -".../out/foo/assembly.dest/out.jar" +"...$MILL_OUT/foo/assembly.dest/out.jar" $ out/foo/assembly.dest/out.jar --text "hello world"

hello world

@@ -159,7 +159,7 @@ Now, we can use build a native image using `foo.nativeImage`: [source,console] ---- $ ./mill show foo.nativeImage -".../out/foo/nativeImage.dest/native-executable" +"...$MILL_OUT/foo/nativeImage.dest/native-executable" $ out/foo/nativeImage.dest/native-executable --text "hello world"

hello world

@@ -229,7 +229,7 @@ _Executable Assembly_ ---- $ time ./mill show foo.assembly [1-41] [info] compiling 1 Java source... -".../out/foo/assembly.dest/out.jar" +"...$MILL_OUT/foo/assembly.dest/out.jar" ./mill show foo.assembly 0.12s user 0.06s system 21% cpu 0.818 total ---- @@ -243,7 +243,7 @@ $ time ./mill show foo.nativeImage [1-50] [2/8] Performing analysis... [****] (7.9s @ 0.77GB) ... [1-50] Finished generating 'native-executable' in 26.0s. -".../out/foo/nativeImage.dest/native-executable" +"...$MILL_OUT/foo/nativeImage.dest/native-executable" ./mill show foo.nativeImage 0.70s user 1.11s system 7% cpu 24.762 total ---- diff --git a/website/blog/modules/ROOT/pages/9-mill-faster-assembly-jars.adoc b/website/blog/modules/ROOT/pages/9-mill-faster-assembly-jars.adoc index 2818d48fb406..69f00125d926 100644 --- a/website/blog/modules/ROOT/pages/9-mill-faster-assembly-jars.adoc +++ b/website/blog/modules/ROOT/pages/9-mill-faster-assembly-jars.adoc @@ -124,7 +124,7 @@ to build an assembly that we can run using `java -jar`: [source,console] ---- > ./mill show assembly -".../out/assembly.dest/out.jar" +"...$MILL_OUT/assembly.dest/out.jar" Total time: 27s $ ls -lh out/assembly.dest/out.jar @@ -325,7 +325,7 @@ the code and re-build the assembly: > echo "class dummy" >> src/main/scala/foo/Foo.scala > ./mill show assembly -".../out/assembly.dest/out.jar" +"...$MILL_OUT/assembly.dest/out.jar" Total time: 1s > sbt assembly