From 9aa0e81ec7f80e2269d3aa403498a9748661bbd0 Mon Sep 17 00:00:00 2001 From: Alex Archambault Date: Fri, 21 Feb 2025 16:43:16 +0100 Subject: [PATCH 1/8] Fix file name in developer doc --- developer.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developer.adoc b/developer.adoc index aeebcc93885..959345321c7 100644 --- a/developer.adoc +++ b/developer.adoc @@ -168,7 +168,7 @@ To test bootstrapping of Mill's own Mill build using a version of Mill built fro ci/patch-mill-bootstrap.sh ---- -This creates a standalone assembly at `target/mill-release` you can use, which references jars +This creates a standalone assembly at `mill-assembly.jar` you can use, which references jars published locally in your `~/.ivy2/local` cache, and applies any necessary patches to `build.mill` to deal with changes in Mill between the version specified in `.config/mill-version` that is normally used to build Mill and the `HEAD` version your assembly was created from. From f883fac917e9bd570fc2eda87a5d665942706cef Mon Sep 17 00:00:00 2001 From: Alex Archambault Date: Fri, 21 Feb 2025 16:15:54 +0100 Subject: [PATCH 2/8] Remove superfluous test The test right after tests the same thing and more --- integration/ide/bloop/src/BloopTests.scala | 7 ------- 1 file changed, 7 deletions(-) diff --git a/integration/ide/bloop/src/BloopTests.scala b/integration/ide/bloop/src/BloopTests.scala index e17a79fd4e8..1a54c3af30b 100644 --- a/integration/ide/bloop/src/BloopTests.scala +++ b/integration/ide/bloop/src/BloopTests.scala @@ -15,13 +15,6 @@ object BloopTests extends UtestIntegrationTestSuite { assert(installResult) assert(os.exists(workspacePath / ".bloop/root-module.json")) } - test("mill-build module bloop config should be created") - integrationTest { tester => - import tester._ - val installResult: Boolean = eval("mill.contrib.bloop.Bloop/install").isSuccess - val millBuildJsonFile = workspacePath / ".bloop/mill-build-.json" - assert(installResult) - assert(os.exists(millBuildJsonFile)) - } test("mill-build config should contain build.mill source") - integrationTest { tester => import tester._ From 27a45e34d97e887f9714f0fbef8bce746e129f4e Mon Sep 17 00:00:00 2001 From: Alex Archambault Date: Fri, 21 Feb 2025 16:43:49 +0100 Subject: [PATCH 3/8] Allow integration tests to know whether Mill was published locally --- integration/package.mill | 8 ++++++++ testkit/src/mill/testkit/UtestIntegrationTestSuite.scala | 2 ++ 2 files changed, 10 insertions(+) diff --git a/integration/package.mill b/integration/package.mill index 553b28593cc..4a3c692dd3e 100644 --- a/integration/package.mill +++ b/integration/package.mill @@ -49,12 +49,14 @@ object `package` extends RootModule { IntegrationTestModule.this.forkEnv() ++ Map( "MILL_INTEGRATION_SERVER_MODE" -> (mode == "local" || mode == "server").toString, + "MILL_INTEGRATION_IS_PACKAGED_LAUNCHER" -> millIntegrationIsPackagedLauncher().toString, "MILL_LAUNCHER" -> build.dist.bootstrapLauncher().path.toString, "MILL_LAUNCHER_BAT" -> build.dist.bootstrapLauncherBat().path.toString, "MILL_INTEGRATION_LAUNCHER" -> millIntegrationLauncher().path.toString ) def millIntegrationLauncher: T[PathRef] + def millIntegrationIsPackagedLauncher: Task[Boolean] def forkArgs = Task { super.forkArgs() ++ build.dist.forkArgs() } @@ -72,20 +74,26 @@ object `package` extends RootModule { object local extends IntegrationLauncherModule { def millIntegrationLauncher = build.dist.launcher() + def millIntegrationIsPackagedLauncher = Task(false) } object packaged extends IntegrationLauncherModule { def millIntegrationLauncher = build.dist.executable() + def millIntegrationIsPackagedLauncher = Task(true) } object native extends IntegrationLauncherModule { def millIntegrationLauncher = build.dist.native.executable() + def millIntegrationIsPackagedLauncher = Task(true) } trait IntegrationLauncherModule extends Module { def millIntegrationLauncher: T[PathRef] + def millIntegrationIsPackagedLauncher: Task[Boolean] object fork extends ModeModule { def millIntegrationLauncher = IntegrationLauncherModule.this.millIntegrationLauncher + def millIntegrationIsPackagedLauncher = IntegrationLauncherModule.this.millIntegrationIsPackagedLauncher } object server extends ModeModule { def millIntegrationLauncher = IntegrationLauncherModule.this.millIntegrationLauncher + def millIntegrationIsPackagedLauncher = IntegrationLauncherModule.this.millIntegrationIsPackagedLauncher } } } diff --git a/testkit/src/mill/testkit/UtestIntegrationTestSuite.scala b/testkit/src/mill/testkit/UtestIntegrationTestSuite.scala index 6c1b5efb25b..56dea79c899 100644 --- a/testkit/src/mill/testkit/UtestIntegrationTestSuite.scala +++ b/testkit/src/mill/testkit/UtestIntegrationTestSuite.scala @@ -7,6 +7,8 @@ import scala.concurrent.{ExecutionContext, Future} abstract class UtestIntegrationTestSuite extends utest.TestSuite with IntegrationTestSuite { protected def workspaceSourcePath: os.Path = os.Path(sys.env("MILL_TEST_RESOURCE_DIR")) protected def clientServerMode: Boolean = sys.env("MILL_INTEGRATION_SERVER_MODE").toBoolean + protected def isPackagedLauncher: Boolean = + sys.env("MILL_INTEGRATION_IS_PACKAGED_LAUNCHER").toBoolean protected def millExecutable: os.Path = os.Path(System.getenv("MILL_INTEGRATION_LAUNCHER"), os.pwd) From 89aa2ba51f95120b53111a4531aec5e7c6de3cfc Mon Sep 17 00:00:00 2001 From: Alex Archambault Date: Fri, 21 Feb 2025 16:47:28 +0100 Subject: [PATCH 4/8] Keep versions in mill.main.BuildInfo.millEmbeddedDeps --- main/package.mill | 7 +++++-- runner/src/mill/runner/MillBuildRootModule.scala | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/main/package.mill b/main/package.mill index 5d63a4081fc..d1e2fcfcaf8 100644 --- a/main/package.mill +++ b/main/package.mill @@ -62,7 +62,10 @@ object `package` extends RootModule with build.MillStableScalaModule with BuildI ) { mod => Task.Anon { val selfDep = mod.publishSelfDependency() - (mod.coursierDependency.module.repr, s"${selfDep.group}:${selfDep.id}") + ( + s"${mod.coursierDependency.module.repr}:${mod.coursierDependency.version}", + s"${selfDep.group}:${selfDep.id}:${selfDep.version}" + ) } }().toMap @@ -75,7 +78,7 @@ object `package` extends RootModule with build.MillStableScalaModule with BuildI dist.coursierCacheCustomizer() ) result.getOrThrow.orderedDependencies - .map(_.module.repr) + .map(dep => s"${dep.module.repr}:${dep.version}") .distinct .map(mod => internalToPublishedModuleMap.getOrElse(mod, mod)) .mkString(",") diff --git a/runner/src/mill/runner/MillBuildRootModule.scala b/runner/src/mill/runner/MillBuildRootModule.scala index ff27f014a1a..33730f3a9c5 100644 --- a/runner/src/mill/runner/MillBuildRootModule.scala +++ b/runner/src/mill/runner/MillBuildRootModule.scala @@ -226,8 +226,8 @@ abstract class MillBuildRootModule()(implicit .split(',') .filter(_.nonEmpty) .map { str => - str.split(":", 2) match { - case Array(org, name) => (org, name) + str.split(":", 3) match { + case Array(org, name, _) => (org, name) case other => sys.error( s"Unexpected misshapen entry in BuildInfo.millEmbeddedDeps ('$str', expected 'org:name')" From 3e9c41cb40ab4b41519b2fe965063f29537c64dd Mon Sep 17 00:00:00 2001 From: Alex Archambault Date: Fri, 21 Feb 2025 16:55:58 +0100 Subject: [PATCH 5/8] Don't evaluate tasks that were not meant to be evaluated in BloopImpl --- .../src/mill/contrib/bloop/BloopImpl.scala | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala b/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala index 3f92a26da66..fa83624e173 100644 --- a/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala +++ b/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala @@ -212,11 +212,20 @@ class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule { module.localCompileClasspath().map(_.path) } - val runtimeClasspath = Task.Anon { - module.transitiveModuleDeps.map(classes) ++ - module.resolvedRunIvyDeps().map(_.path) ++ - module.unmanagedClasspath().map(_.path) + val isTestModule = module match { + case _: TestModule => true + case _ => false } + val runtimeClasspathOpt = + if (isTestModule || !runtime) + Task.Anon(None) + else + Task.Anon { + val cp = module.transitiveModuleDeps.map(classes) ++ + module.resolvedRunIvyDeps().map(_.path) ++ + module.unmanagedClasspath().map(_.path) + Some(cp.map(_.toNIO).toList) + } val compileResources = Task.Anon(module.compileResources().map(_.path.toNIO).toList) @@ -283,10 +292,7 @@ class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule { ), mainClass = module.mainClass(), runtimeConfig = None, - classpath = module match { - case _: TestModule => None - case _ => Some(runtimeClasspath().map(_.toNIO).toList) - }, + classpath = runtimeClasspathOpt(), resources = Some(runtimeResources()) ) } From b763535808660f17fa2e3cf81df74f1d83ef2733 Mon Sep 17 00:00:00 2001 From: Alex Archambault Date: Fri, 21 Feb 2025 16:59:55 +0100 Subject: [PATCH 6/8] Pass Mill source JARs to Bloop --- .../bloop/src/mill/contrib/bloop/Bloop.scala | 3 +- .../src/mill/contrib/bloop/BloopImpl.scala | 145 +++++++++++++++--- .../src/mill/contrib/bloop/BloopTests.scala | 6 +- integration/ide/bloop/src/BloopTests.scala | 17 ++ main/util/src/mill/util/CoursierSupport.scala | 78 +++++++--- .../src/mill/scalalib/CoursierModule.scala | 23 +++ 6 files changed, 225 insertions(+), 47 deletions(-) diff --git a/contrib/bloop/src/mill/contrib/bloop/Bloop.scala b/contrib/bloop/src/mill/contrib/bloop/Bloop.scala index c45e5b336e0..b505f6f39ec 100644 --- a/contrib/bloop/src/mill/contrib/bloop/Bloop.scala +++ b/contrib/bloop/src/mill/contrib/bloop/Bloop.scala @@ -8,5 +8,6 @@ import mill.api.WorkspaceRoot */ object Bloop extends BloopImpl( () => Evaluator.allBootstrapEvaluators.value.value, - WorkspaceRoot.workspaceRoot + WorkspaceRoot.workspaceRoot, + addMillSources = None ) diff --git a/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala b/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala index fa83624e173..9a6328a1bd4 100644 --- a/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala +++ b/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala @@ -5,6 +5,7 @@ import mill._ import mill.api.Result import mill.define.{Discover, ExternalModule, Module => MillModule} import mill.eval.Evaluator +import mill.main.BuildInfo import mill.scalalib.internal.JavaModuleUtils import mill.scalajslib.ScalaJSModule import mill.scalajslib.api.{JsEnvConfig, ModuleKind} @@ -12,12 +13,18 @@ import mill.scalalib._ import mill.scalanativelib.ScalaNativeModule import mill.scalanativelib.api.ReleaseMode +import java.nio.file.{FileSystemNotFoundException, Files, Paths} + /** * Implementation of the Bloop related tasks. Inherited by the * `mill.contrib.bloop.Bloop` object, and usable in tests by passing * a custom evaluator. */ -class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule { +class BloopImpl( + evs: () => Seq[Evaluator], + wd: os.Path, + addMillSources: Option[Boolean] +) extends ExternalModule { outer => import BloopFormats._ @@ -28,7 +35,10 @@ class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule { * under pwd/.bloop. */ def install() = Task.Command { - val res = Task.traverse(computeModules)(_.bloop.writeConfigFile())() + val res = Task.traverse(computeModules0) { + case (mod, isRoot) => + mod.bloop.writeConfigFile(isRoot) + }() val written = res.map(_._2).map(_.path) // Make bloopDir if it doesn't exists if (!os.exists(bloopDir)) { @@ -62,7 +72,7 @@ class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule { object bloop extends MillModule { def config = Task { - new BloopOps(self).bloop.config() + bloopConfig(self, false) } } @@ -85,19 +95,20 @@ class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule { override def millOuterCtx = jm.millOuterCtx object bloop extends MillModule { - def config = Task { outer.bloopConfig(jm) } + @deprecated("", "") + def config = Task.Anon { outer.bloopConfig(jm, false) } - def writeConfigFile(): Command[(String, PathRef)] = Task.Command { + def writeConfigFile(isRootModule: Boolean): Command[(String, PathRef)] = Task.Command { os.makeDir.all(bloopDir) val path = bloopConfigPath(jm) - _root_.bloop.config.write(config(), path.toNIO) + _root_.bloop.config.write(outer.bloopConfig(jm, isRootModule)(), path.toNIO) Task.log.info(s"Wrote $path") name(jm) -> PathRef(path) } @deprecated("Use writeConfigFile instead.", "Mill after 0.10.9") def writeConfig: T[(String, PathRef)] = Task { - writeConfigFile()() + writeConfigFile(isRootModule = false)() } } @@ -116,16 +127,23 @@ class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule { JavaModuleUtils.transitiveModules(mod, accept) } - protected def computeModules: Seq[JavaModule] = { - val evals = evs() - evals.flatMap { eval => - if (eval != null) - JavaModuleUtils.transitiveModules(eval.rootModule, accept) + protected def computeModules: Seq[JavaModule] = + computeModules0.map(_._1) + + /** + * All modules that are meant to be imported in Bloop + * + * @return sequence of modules and a boolean indicating whether the module is a root one + */ + protected def computeModules0: Seq[(JavaModule, Boolean)] = + evs() + .filter(_ != null) + .flatMap { eval => + val rootModule = eval.rootModule + JavaModuleUtils.transitiveModules(rootModule, accept) .collect { case jm: JavaModule => jm } - else - Seq.empty - } - } + .map(mod => (mod, mod == rootModule)) + } // class-based pattern matching against path-dependant types doesn't seem to work. private def accept(module: MillModule): Boolean = @@ -156,7 +174,7 @@ class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule { // Computation of the bloop configuration for a specific module // //////////////////////////////////////////////////////////////////////////// - def bloopConfig(module: JavaModule): Task[BloopConfig.File] = { + def bloopConfig(module: JavaModule, isRootModule: Boolean): Task[BloopConfig.File] = { import _root_.bloop.config.Config def out(m: JavaModule) = bloopDir / "out" / name(m) def classes(m: JavaModule) = out(m) / "classes" @@ -395,16 +413,89 @@ class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule { gatherTask.unsafeRun() } - val bloopResolution: Task[BloopConfig.Resolution] = Task.Anon { + val millBuildDependencies: Task[List[BloopConfig.Module]] = Task.Anon { + + val result = module.defaultResolver().getArtifacts( + BuildInfo.millEmbeddedDeps + .split(',') + .filter(_.nonEmpty) + .map { str => + str.split(":", 3) match { + case Array(org, name, ver) => + val module = + coursier.Module(coursier.Organization(org), coursier.ModuleName(name), Map.empty) + coursier.Dependency(module, ver) + case other => + sys.error( + s"Unexpected misshapen entry in BuildInfo.millEmbeddedDeps ('$str', expected 'org:name')" + ) + } + }, + sources = true + ) + + def moduleOf(dep: coursier.Dependency): BloopConfig.Module = + BloopConfig.Module( + dep.module.organization.value, + dep.module.name.value, + dep.version, + Some(dep.configuration.value).filter(_.nonEmpty), + Nil + ) + + val indices = result.fullDetailedArtifacts + .map { + case (dep, _, _, _) => + moduleOf(dep) + } + .zipWithIndex + .reverseIterator + .toMap + + result.fullDetailedArtifacts + .groupBy { + case (dep, _, _, _) => + moduleOf(dep) + } + .toList + .sortBy { + case (mod, _) => + indices(mod) + } + .map { + case (mod, artifacts) => + mod.copy( + artifacts = artifacts.toList.collect { + case (_, pub, art, Some(file)) => + BloopConfig.Artifact( + pub.name, + Some(pub.classifier.value).filter(_.nonEmpty), + None, + file.toPath + ) + } + ) + } + } + + val bloopDependencies: Task[List[BloopConfig.Module]] = Task.Anon { val repos = module.allRepositories() // same as input of resolvedIvyDeps val coursierDeps = Seq( module.coursierDependency.withConfiguration(coursier.core.Configuration.provided), module.coursierDependency ) - BloopConfig.Resolution(artifacts(repos, coursierDeps)) + artifacts(repos, coursierDeps) } + val allBloopDependencies: Task[List[BloopConfig.Module]] = + if (isRootModule && !BloopImpl.isMillRunningFromSources) + Task.Anon { + bloopDependencies() ::: millBuildDependencies() + } + else + bloopDependencies + // ////////////////////////////////////////////////////////////////////////// // Tying up // ////////////////////////////////////////////////////////////////////////// @@ -438,7 +529,7 @@ class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule { sbt = None, test = testConfig(), platform = Some(platform()), - resolution = Some(bloopResolution()), + resolution = Some(BloopConfig.Resolution(allBloopDependencies())), tags = Some(tags), sourceGenerators = None // TODO: are we supposed to hook generated sources here? ) @@ -454,3 +545,17 @@ class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule { lazy val millDiscover: Discover = Discover[this.type] } + +object BloopImpl { + lazy val isMillRunningFromSources = + Option(classOf[BloopImpl].getProtectionDomain.getCodeSource) + .flatMap(s => Option(s.getLocation)) + .flatMap { url => + try Some(Paths.get(url.toURI)) + catch { + case _: FileSystemNotFoundException => None + case _: IllegalArgumentException => None + } + } + .exists(Files.isDirectory(_)) +} diff --git a/contrib/bloop/test/src/mill/contrib/bloop/BloopTests.scala b/contrib/bloop/test/src/mill/contrib/bloop/BloopTests.scala index 1d52da1f68e..27be21b956f 100644 --- a/contrib/bloop/test/src/mill/contrib/bloop/BloopTests.scala +++ b/contrib/bloop/test/src/mill/contrib/bloop/BloopTests.scala @@ -18,7 +18,11 @@ object BloopTests extends TestSuite { val unitTester = UnitTester(build, null) val workdir = unitTester.evaluator.rootModule.millSourcePath - val testBloop = new BloopImpl(() => Seq(unitTester.evaluator), workdir) + val testBloop = new BloopImpl( + () => Seq(unitTester.evaluator), + workdir, + addMillSources = None + ) object build extends TestBaseModule { object scalaModule extends scalalib.ScalaModule with testBloop.Module { diff --git a/integration/ide/bloop/src/BloopTests.scala b/integration/ide/bloop/src/BloopTests.scala index 1a54c3af30b..a5617b7a52d 100644 --- a/integration/ide/bloop/src/BloopTests.scala +++ b/integration/ide/bloop/src/BloopTests.scala @@ -25,6 +25,23 @@ object BloopTests extends UtestIntegrationTestSuite { assert(config("project")("sources").arr.exists(path => os.Path(path.str).last == "build.mill" )) + + if (isPackagedLauncher) { + val modules = config("project")("resolution")("modules").arr + + def sourceJars(org: String, namePrefix: String) = modules + .filter(mod => mod("organization").str == org && mod("name").str.startsWith(namePrefix)) + .flatMap(_("artifacts").arr) + .filter(_("classifier").strOpt.contains("sources")) + .flatMap(_("path").strOpt) + .filter(_.endsWith("-sources.jar")) + .distinct + + val millScalaLibSourceJars = sourceJars("com.lihaoyi", "mill-scalalib_") + assert(millScalaLibSourceJars.nonEmpty) + val coursierCacheSourceJars = sourceJars("io.get-coursier", "coursier-cache_") + assert(coursierCacheSourceJars.nonEmpty) + } } } } diff --git a/main/util/src/mill/util/CoursierSupport.scala b/main/util/src/mill/util/CoursierSupport.scala index f4fb4e3f37c..e200da760ed 100644 --- a/main/util/src/mill/util/CoursierSupport.scala +++ b/main/util/src/mill/util/CoursierSupport.scala @@ -122,33 +122,20 @@ trait CoursierSupport { } /** - * Resolve dependencies using Coursier. - * - * We do not bother breaking this out into the separate ZincWorkerApi classpath, - * because Coursier is already bundled with mill/Ammonite to support the - * `import $ivy` syntax. - * - * Avoid using `deprecatedResolveFilter` if you can. As a substitute, use exclusions - * (or upfront, mark some dependencies as provided aka compile-time when you publish them), - * or as a last resort, manually filter the file sequence returned by this function. + * Resolve dependencies using Coursier, and return very detailed info about their artifacts. */ - def resolveDependencies( + def getArtifacts( repositories: Seq[Repository], deps: IterableOnce[Dependency], - force: IterableOnce[Dependency], + force: IterableOnce[Dependency] = Nil, sources: Boolean = false, mapDependencies: Option[Dependency => Dependency] = None, customizer: Option[Resolution => Resolution] = None, ctx: Option[mill.api.Ctx.Log] = None, coursierCacheCustomizer: Option[FileCache[Task] => FileCache[Task]] = None, - @deprecated( - "This parameter is now ignored, use exclusions instead or mark some dependencies as provided when you publish modules", - "Mill after 0.12.5" - ) - deprecatedResolveFilter: os.Path => Boolean = _ => true, artifactTypes: Option[Set[Type]] = None, resolutionParams: ResolutionParams = ResolutionParams() - ): Result[Agg[PathRef]] = { + ): Result[coursier.Artifacts.Result] = { val resolutionRes = resolveDependenciesMetadataSafe( repositories, deps, @@ -184,18 +171,59 @@ trait CoursierSupport { case Left(error) => Result.Exception(error, new Result.OuterStack((new Exception).getStackTrace)) case Right(res) => - Result.Success( - Agg.from( - res.files - .map(os.Path(_)) - .filter(deprecatedResolveFilter) - .map(PathRef(_, quick = true)) - ) - ) + Result.Success(res) } } } + /** + * Resolve dependencies using Coursier. + * + * We do not bother breaking this out into the separate ZincWorkerApi classpath, + * because Coursier is already bundled with mill/Ammonite to support the + * `import $ivy` syntax. + * + * Avoid using `deprecatedResolveFilter` if you can. As a substitute, use exclusions + * (or upfront, mark some dependencies as provided aka compile-time when you publish them), + * or as a last resort, manually filter the file sequence returned by this function. + */ + def resolveDependencies( + repositories: Seq[Repository], + deps: IterableOnce[Dependency], + force: IterableOnce[Dependency], + sources: Boolean = false, + mapDependencies: Option[Dependency => Dependency] = None, + customizer: Option[Resolution => Resolution] = None, + ctx: Option[mill.api.Ctx.Log] = None, + coursierCacheCustomizer: Option[FileCache[Task] => FileCache[Task]] = None, + @deprecated( + "This parameter is now ignored, use exclusions instead or mark some dependencies as provided when you publish modules", + "Mill after 0.12.5" + ) + deprecatedResolveFilter: os.Path => Boolean = _ => true, + artifactTypes: Option[Set[Type]] = None, + resolutionParams: ResolutionParams = ResolutionParams() + ): Result[Agg[PathRef]] = + getArtifacts( + repositories, + deps, + force, + sources, + mapDependencies, + customizer, + ctx, + coursierCacheCustomizer, + artifactTypes, + resolutionParams + ).map { res => + Agg.from( + res.files + .map(os.Path(_)) + .filter(deprecatedResolveFilter) + .map(PathRef(_, quick = true)) + ) + } + // bin-compat shim def resolveDependencies( repositories: Seq[Repository], diff --git a/scalalib/src/mill/scalalib/CoursierModule.scala b/scalalib/src/mill/scalalib/CoursierModule.scala index d44ede7f8d9..09dad62764d 100644 --- a/scalalib/src/mill/scalalib/CoursierModule.scala +++ b/scalalib/src/mill/scalalib/CoursierModule.scala @@ -11,6 +11,7 @@ import scala.annotation.nowarn import scala.concurrent.Await import scala.concurrent.duration.Duration import mill.Agg +import mill.util.Jvm /** * This module provides the capability to resolve (transitive) dependencies from (remote) repositories. @@ -380,6 +381,28 @@ object CoursierModule { res.orderedDependencies } + + def getArtifacts[T: CoursierModule.Resolvable]( + deps: IterableOnce[T], + sources: Boolean = false, + mapDependencies: Option[Dependency => Dependency] = None, + customizer: Option[Resolution => Resolution] = None, + ctx: Option[mill.api.Ctx.Log] = None, + coursierCacheCustomizer: Option[FileCache[Task] => FileCache[Task]] = None, + artifactTypes: Option[Set[Type]] = None, + resolutionParams: ResolutionParams = ResolutionParams() + ): coursier.Artifacts.Result = { + val deps0 = deps + .iterator + .map(implicitly[CoursierModule.Resolvable[T]].bind(_, bind)) + .toSeq + Jvm.getArtifacts( + repositories, + deps0.map(_.dep), + sources = sources, + ctx = ctx + ).getOrThrow + } } sealed trait Resolvable[T] { From 75666ea968673cdb9c2f1d43faa9cec8db47758d Mon Sep 17 00:00:00 2001 From: Alex Archambault Date: Fri, 21 Feb 2025 17:56:54 +0100 Subject: [PATCH 7/8] Fixes / add doc --- .../bloop/src/mill/contrib/bloop/BloopImpl.scala | 16 +++++++++++++--- integration/ide/bloop/src/BloopTests.scala | 2 ++ integration/package.mill | 1 + .../mill/testkit/UtestIntegrationTestSuite.scala | 2 ++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala b/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala index 9a6328a1bd4..8c32df6b994 100644 --- a/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala +++ b/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala @@ -235,7 +235,7 @@ class BloopImpl( case _ => false } val runtimeClasspathOpt = - if (isTestModule || !runtime) + if (isTestModule) Task.Anon(None) else Task.Anon { @@ -488,8 +488,15 @@ class BloopImpl( artifacts(repos, coursierDeps) } + val addMillSources0 = addMillSources.getOrElse { + // We only try to resolve Mill's dependencies to get their source JARs + // if we're not running from sources. If Mill is running purely from its sources + // it's not is published in ~/.ivy2/local, so we can't get its source JARs. + !BloopImpl.isMillRunningFromSources + } val allBloopDependencies: Task[List[BloopConfig.Module]] = - if (isRootModule && !BloopImpl.isMillRunningFromSources) + // Add Mill source JARs to root modules + if (isRootModule && addMillSources0) Task.Anon { bloopDependencies() ::: millBuildDependencies() } @@ -547,7 +554,10 @@ class BloopImpl( } object BloopImpl { - lazy val isMillRunningFromSources = + // If the class of BloopImpl is loaded from a directory rather than a JAR, + // then we're running from sources (the directory should be something + // like mill-repo/out/contrib/bloop/compile.dest/classes). + private lazy val isMillRunningFromSources = Option(classOf[BloopImpl].getProtectionDomain.getCodeSource) .flatMap(s => Option(s.getLocation)) .flatMap { url => diff --git a/integration/ide/bloop/src/BloopTests.scala b/integration/ide/bloop/src/BloopTests.scala index a5617b7a52d..ca1b150c310 100644 --- a/integration/ide/bloop/src/BloopTests.scala +++ b/integration/ide/bloop/src/BloopTests.scala @@ -37,8 +37,10 @@ object BloopTests extends UtestIntegrationTestSuite { .filter(_.endsWith("-sources.jar")) .distinct + // Look for one of Mill's own source JARs val millScalaLibSourceJars = sourceJars("com.lihaoyi", "mill-scalalib_") assert(millScalaLibSourceJars.nonEmpty) + // Look for a source JAR of a dependency val coursierCacheSourceJars = sourceJars("io.get-coursier", "coursier-cache_") assert(coursierCacheSourceJars.nonEmpty) } diff --git a/integration/package.mill b/integration/package.mill index 4a3c692dd3e..9778749b57b 100644 --- a/integration/package.mill +++ b/integration/package.mill @@ -56,6 +56,7 @@ object `package` extends RootModule { ) def millIntegrationLauncher: T[PathRef] + /** Whether the Mill JARs are published locally alongside this Mill launcher */ def millIntegrationIsPackagedLauncher: Task[Boolean] def forkArgs = Task { super.forkArgs() ++ build.dist.forkArgs() } diff --git a/testkit/src/mill/testkit/UtestIntegrationTestSuite.scala b/testkit/src/mill/testkit/UtestIntegrationTestSuite.scala index 56dea79c899..6ca0b968b70 100644 --- a/testkit/src/mill/testkit/UtestIntegrationTestSuite.scala +++ b/testkit/src/mill/testkit/UtestIntegrationTestSuite.scala @@ -7,6 +7,8 @@ import scala.concurrent.{ExecutionContext, Future} abstract class UtestIntegrationTestSuite extends utest.TestSuite with IntegrationTestSuite { protected def workspaceSourcePath: os.Path = os.Path(sys.env("MILL_TEST_RESOURCE_DIR")) protected def clientServerMode: Boolean = sys.env("MILL_INTEGRATION_SERVER_MODE").toBoolean + + /** Whether the Mill JARs are published locally alongside this Mill launcher */ protected def isPackagedLauncher: Boolean = sys.env("MILL_INTEGRATION_IS_PACKAGED_LAUNCHER").toBoolean protected def millExecutable: os.Path = From 40ce11a5a4ab0ba0525614766cd9dbe90a650cef Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2025 17:05:33 +0000 Subject: [PATCH 8/8] [autofix.ci] apply automated fixes --- integration/package.mill | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/integration/package.mill b/integration/package.mill index 9778749b57b..ccca5cc2a46 100644 --- a/integration/package.mill +++ b/integration/package.mill @@ -56,6 +56,7 @@ object `package` extends RootModule { ) def millIntegrationLauncher: T[PathRef] + /** Whether the Mill JARs are published locally alongside this Mill launcher */ def millIntegrationIsPackagedLauncher: Task[Boolean] @@ -90,11 +91,13 @@ object `package` extends RootModule { def millIntegrationIsPackagedLauncher: Task[Boolean] object fork extends ModeModule { def millIntegrationLauncher = IntegrationLauncherModule.this.millIntegrationLauncher - def millIntegrationIsPackagedLauncher = IntegrationLauncherModule.this.millIntegrationIsPackagedLauncher + def millIntegrationIsPackagedLauncher = + IntegrationLauncherModule.this.millIntegrationIsPackagedLauncher } object server extends ModeModule { def millIntegrationLauncher = IntegrationLauncherModule.this.millIntegrationLauncher - def millIntegrationIsPackagedLauncher = IntegrationLauncherModule.this.millIntegrationIsPackagedLauncher + def millIntegrationIsPackagedLauncher = + IntegrationLauncherModule.this.millIntegrationIsPackagedLauncher } } }