From 439174cf70db5ebe14ebe06545e6ef1ec8a84d64 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Wed, 2 Sep 2020 14:05:18 +0200 Subject: [PATCH] Give more control over module dependencies. Support compile-only module dependencies with added target `compileModuleDeps`. Added target `showModuleDeps` to let the user inspect module dependencies on the cmdline. Fixes https://github.com/lihaoyi/mill/issues/877 Fixes https://github.com/lihaoyi/mill/issues/828 --- .../src/mill/contrib/bloop/BloopImpl.scala | 14 ++++---- .../mill/contrib/bsp/MillBuildServer.scala | 2 +- contrib/scalapblib/src/ScalaPBModule.scala | 2 +- contrib/scoverage/src/ScoverageModule.scala | 1 + contrib/tut/src/TutModule.scala | 2 +- scalalib/src/GenIdeaImpl.scala | 2 +- scalalib/src/JavaModule.scala | 36 ++++++++++++++++--- scalalib/src/PublishModule.scala | 7 +++- scalalib/src/ScalaModule.scala | 2 +- 9 files changed, 50 insertions(+), 18 deletions(-) diff --git a/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala b/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala index 5fbce60f912..76c71c6da64 100644 --- a/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala +++ b/contrib/bloop/src/mill/contrib/bloop/BloopImpl.scala @@ -356,7 +356,7 @@ class BloopImpl(ev: () => Evaluator, wd: Path) extends ExternalModule { outer => val bloopResolution: Task[BloopConfig.Resolution] = T.task { val repos = module.repositories val allIvyDeps = module - .transitiveIvyDeps() ++ scalaLibraryIvyDeps() ++ module.compileIvyDeps() + .transitiveIvyDeps() ++ scalaLibraryIvyDeps() ++ module.transitiveCompileIvyDeps() val coursierDeps = allIvyDeps.map(module.resolveCoursierDependency()).toList BloopConfig.Resolution(artifacts(repos, coursierDeps)) @@ -371,13 +371,13 @@ class BloopImpl(ev: () => Evaluator, wd: Path) extends ExternalModule { outer => case _ => T.task(Loose.Agg.empty[Dep]) } - val ivyDepsClasspath = - module - .resolveDeps(T.task { - module.compileIvyDeps() ++ module - .transitiveIvyDeps() ++ scalaLibIvyDeps() + val ivyDepsClasspath = module + .resolveDeps(T.task { + module.transitiveCompileIvyDeps() ++ + module.transitiveIvyDeps() ++ + scalaLibIvyDeps() }) - .map(_.map(_.path).toSeq) + .map(_.map(_.path).toSeq) def transitiveClasspath(m: JavaModule): Task[Seq[Path]] = T.task { m.moduleDeps.map(classes) ++ diff --git a/contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala b/contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala index 0f86423e888..7e91c832818 100644 --- a/contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala +++ b/contrib/bsp/src/mill/contrib/bsp/MillBuildServer.scala @@ -142,7 +142,7 @@ class MillBuildServer(evaluator: Evaluator, bspVersion: String, serverVersion: S val module = getModule(targetId, modules) val sources = evaluateInformativeTask( evaluator, - module.resolveDeps(T.task(module.compileIvyDeps() ++ module.transitiveIvyDeps()), sources = true), + module.resolveDeps(T.task(module.transitiveCompileIvyDeps() ++ module.transitiveIvyDeps()), sources = true), Agg.empty[PathRef] ) val unmanaged = evaluateInformativeTask( diff --git a/contrib/scalapblib/src/ScalaPBModule.scala b/contrib/scalapblib/src/ScalaPBModule.scala index e0fcce60d84..088aecdbaf0 100644 --- a/contrib/scalapblib/src/ScalaPBModule.scala +++ b/contrib/scalapblib/src/ScalaPBModule.scala @@ -72,7 +72,7 @@ trait ScalaPBModule extends ScalaModule { def scalaPBIncludePath: T[Seq[PathRef]] = T.sources { Seq.empty[PathRef] } def scalaPBProtoClasspath: T[Agg[PathRef]] = T { - resolveDeps(T.task { compileIvyDeps() ++ transitiveIvyDeps() })() + resolveDeps(T.task { transitiveCompileIvyDeps() ++ transitiveIvyDeps() })() } def scalaPBUnpackProto: T[PathRef] = T { diff --git a/contrib/scoverage/src/ScoverageModule.scala b/contrib/scoverage/src/ScoverageModule.scala index af25a8c0cd8..c5eeb73bf79 100644 --- a/contrib/scoverage/src/ScoverageModule.scala +++ b/contrib/scoverage/src/ScoverageModule.scala @@ -109,6 +109,7 @@ trait ScoverageModule extends ScalaModule { outer: ScalaModule => override def generatedSources: Target[Seq[PathRef]] = T{ outer.generatedSources() } override def allSources: Target[Seq[PathRef]] = T{ outer.allSources() } override def moduleDeps: Seq[JavaModule] = outer.moduleDeps + override def compileModuleDeps: Seq[JavaModule] = outer.compileModuleDeps override def sources: Sources = T.sources { outer.sources() } override def resources: Sources = T.sources { outer.resources() } override def scalaVersion = T{ outer.scalaVersion() } diff --git a/contrib/tut/src/TutModule.scala b/contrib/tut/src/TutModule.scala index ce40f003b49..8b1d9627fc6 100644 --- a/contrib/tut/src/TutModule.scala +++ b/contrib/tut/src/TutModule.scala @@ -100,7 +100,7 @@ trait TutModule extends ScalaModule { Lib.resolveDependencies( repositories :+ MavenRepository(s"https://dl.bintray.com/tpolecat/maven"), Lib.depToDependency(_, scalaVersion()), - compileIvyDeps() ++ transitiveIvyDeps() ++ Seq( + transitiveCompileIvyDeps() ++ transitiveIvyDeps() ++ Seq( ivy"org.tpolecat::tut-core:${tutVersion()}" ) ) diff --git a/scalalib/src/GenIdeaImpl.scala b/scalalib/src/GenIdeaImpl.scala index 791ba3ab7d7..63937e36681 100755 --- a/scalalib/src/GenIdeaImpl.scala +++ b/scalalib/src/GenIdeaImpl.scala @@ -134,7 +134,7 @@ case class GenIdeaImpl(evaluator: Evaluator, case x: ScalaModule => x.scalaLibraryIvyDeps case _ => T.task{Loose.Agg.empty[Dep]} } - val allIvyDeps = T.task{mod.transitiveIvyDeps() ++ scalaLibraryIvyDeps() ++ mod.compileIvyDeps()} + val allIvyDeps = T.task{mod.transitiveIvyDeps() ++ scalaLibraryIvyDeps() ++ mod.transitiveCompileIvyDeps()} val scalaCompilerClasspath = mod match{ case x: ScalaModule => x.scalaCompilerClasspath diff --git a/scalalib/src/JavaModule.scala b/scalalib/src/JavaModule.scala index 28cb0415820..258d592ca92 100644 --- a/scalalib/src/JavaModule.scala +++ b/scalalib/src/JavaModule.scala @@ -94,6 +94,32 @@ trait JavaModule extends mill.Module /** The direct dependencies of this module */ def moduleDeps = Seq.empty[JavaModule] + /** The compile-only direct dependencies of this module. */ + def compileModuleDeps = Seq.empty[JavaModule] + + /** The compile-only transitive ivy dependencies of this module and all it's upstream compile-only modules. */ + def transitiveCompileIvyDeps: T[Agg[Dep]] = T{ + // We never include compile-only dependencies transitively, but we must include normal transitive dependencies! + compileIvyDeps() ++ T.traverse(compileModuleDeps)(_.transitiveIvyDeps)().flatten + } + + /** + * Show the module dependencies. + * @param recursive If `true` include all recursive module dependencies, else only show direct dependencies. + */ + def showModuleDeps(recursive: Boolean = false) = T.command { + val normalDeps = if (recursive) recursiveModuleDeps else moduleDeps + val compileDeps = if(recursive) compileModuleDeps.flatMap(_.transitiveModuleDeps).distinct else compileModuleDeps + val deps = (normalDeps ++ compileDeps).distinct + val asString = s"${if(recursive) "Recursive module" else "Module"} dependencies of ${millModuleSegments.render}:\n\t${ + deps.map { dep => + dep.millModuleSegments.render ++ + (if (compileModuleDeps.contains(dep) || !normalDeps.contains(dep)) " (compile)" else "") + }.mkString("\n\t") + }" + T.log.outputStream.println(asString) + } + /** The direct and indirect dependencies of this module */ def recursiveModuleDeps: Seq[JavaModule] = { moduleDeps.flatMap(_.transitiveModuleDeps).distinct @@ -122,14 +148,14 @@ trait JavaModule extends mill.Module * The upstream compilation output of all this module's upstream modules */ def upstreamCompileOutput = T{ - T.traverse(recursiveModuleDeps)(_.compile) + T.traverse((recursiveModuleDeps ++ compileModuleDeps.flatMap(_.transitiveModuleDeps)).distinct)(_.compile) } /** * The transitive version of `localClasspath` */ def transitiveLocalClasspath: T[Agg[PathRef]] = T{ - T.traverse(moduleDeps)(m => + T.traverse(moduleDeps ++ compileModuleDeps)(m => T.task{m.localClasspath() ++ m.transitiveLocalClasspath()} )().flatten } @@ -224,7 +250,7 @@ trait JavaModule extends mill.Module transitiveLocalClasspath() ++ resources() ++ unmanagedClasspath() ++ - resolveDeps(T.task{compileIvyDeps() ++ transitiveIvyDeps()})() + resolveDeps(T.task{transitiveCompileIvyDeps() ++ transitiveIvyDeps()})() } /** @@ -416,10 +442,10 @@ trait JavaModule extends mill.Module def ivyDepsTree(inverse: Boolean = false, withCompile: Boolean = false, withRuntime: Boolean = false): Command[Unit] = (withCompile, withRuntime) match { case (true, true) => T.command { - printDepsTree(inverse, T.task{ compileIvyDeps() ++ runIvyDeps() }) + printDepsTree(inverse, T.task{ transitiveCompileIvyDeps() ++ runIvyDeps() }) } case (true, false) => T.command { - printDepsTree(inverse, compileIvyDeps) + printDepsTree(inverse, transitiveCompileIvyDeps) } case (false, true) => T.command { printDepsTree(inverse, runIvyDeps) diff --git a/scalalib/src/PublishModule.scala b/scalalib/src/PublishModule.scala index 3110019548c..8d36d6743cf 100644 --- a/scalalib/src/PublishModule.scala +++ b/scalalib/src/PublishModule.scala @@ -30,8 +30,13 @@ trait PublishModule extends JavaModule { outer => .map(_.copy(scope = Scope.Provided)) val modulePomDeps = T.sequence(moduleDeps.map(_.publishSelfDependency))() + val compileModulePomDeps = T.sequence(compileModuleDeps.collect { + case m: PublishModule => m.publishSelfDependency + })() - ivyPomDeps ++ compileIvyPomDeps ++ modulePomDeps.map(Dependency(_, Scope.Compile)) + ivyPomDeps ++ compileIvyPomDeps ++ + modulePomDeps.map(Dependency(_, Scope.Compile)) ++ + compileModulePomDeps.map(Dependency(_, Scope.Provided)) } def pom: Target[PathRef] = T { diff --git a/scalalib/src/ScalaModule.scala b/scalalib/src/ScalaModule.scala index 2e07c64b2bb..c064565e706 100644 --- a/scalalib/src/ScalaModule.scala +++ b/scalalib/src/ScalaModule.scala @@ -140,7 +140,7 @@ trait ScalaModule extends JavaModule { outer => transitiveLocalClasspath() ++ resources() ++ unmanagedClasspath() ++ - resolveDeps(T.task{compileIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps()})() + resolveDeps(T.task{transitiveCompileIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps()})() } override def upstreamAssemblyClasspath = T{