diff --git a/build.sc b/build.sc
index d28672b388b..a067fbb89e7 100644
--- a/build.sc
+++ b/build.sc
@@ -934,7 +934,7 @@ object bsp extends MillPublishScalaModule with BuildInfo {
}
object worker extends MillPublishScalaModule {
- def compileModuleDeps = Seq(bsp, scalalib, testrunner, runner)
+ def compileModuleDeps = Seq(bsp, scalalib, testrunner, runner) ++ scalalib.compileModuleDeps
def ivyDeps = Agg(Deps.bsp4j, Deps.sbtTestInterface)
}
}
diff --git a/example/basic/4-builtin-commands/build.sc b/example/basic/4-builtin-commands/build.sc
index 379727e3e0e..8550d9a5a5e 100644
--- a/example/basic/4-builtin-commands/build.sc
+++ b/example/basic/4-builtin-commands/build.sc
@@ -129,9 +129,9 @@ Inputs:
> ./mill show foo.compileClasspath
[
- ".../foo/compile-resources",
".../org/scala-lang/scala-library/2.13.11/scala-library-2.13.11.jar",
...
+ ".../foo/compile-resources"
]
*/
@@ -150,9 +150,9 @@ Inputs:
".../foo/src"
],
"foo.compileClasspath": [
- ".../foo/compile-resources",
".../org/scala-lang/scala-library/2.13.11/scala-library-2.13.11.jar",
...
+ ".../foo/compile-resources"
]
}
@@ -171,9 +171,9 @@ Inputs:
".../foo/src"
],
"foo.compileClasspath": [
- ".../foo/compile-resources",
".../org/scala-lang/scala-library/2.13.11/scala-library-2.13.11.jar",
...
+ ".../foo/compile-resources"
]
}
diff --git a/example/cross/10-static-blog/build.sc b/example/cross/10-static-blog/build.sc
index 139feb8c9ec..b9038fa0da4 100644
--- a/example/cross/10-static-blog/build.sc
+++ b/example/cross/10-static-blog/build.sc
@@ -3,7 +3,7 @@
// libraries - Commonmark and Scalatags - to deal with Markdown parsing and
// HTML generation respectively:
-import $ivy.`com.lihaoyi::scalatags:0.9.1`, scalatags.Text.all._
+import $ivy.`com.lihaoyi::scalatags:0.12.0`, scalatags.Text.all._
import $ivy.`com.atlassian.commonmark:commonmark:0.13.1`
import org.commonmark.parser.Parser
import org.commonmark.renderer.html.HtmlRenderer
diff --git a/example/misc/3-import-file-ivy/build.sc b/example/misc/3-import-file-ivy/build.sc
index 8212cf806cf..3ae2328d512 100644
--- a/example/misc/3-import-file-ivy/build.sc
+++ b/example/misc/3-import-file-ivy/build.sc
@@ -1,5 +1,5 @@
import mill._, scalalib._
-import $ivy.`com.lihaoyi::scalatags:0.8.2`, scalatags.Text.all._
+import $ivy.`com.lihaoyi::scalatags:0.12.0`, scalatags.Text.all._
import $file.scalaversion, scalaversion.myScalaVersion
object foo extends RootModule with ScalaModule {
diff --git a/example/misc/4-mill-build-folder/build.sc b/example/misc/4-mill-build-folder/build.sc
index a7a1e92b563..5e153dbaa76 100644
--- a/example/misc/4-mill-build-folder/build.sc
+++ b/example/misc/4-mill-build-folder/build.sc
@@ -52,14 +52,14 @@ compiling 1 Scala source...
> ./mill run
Foo.value:
hello
-scalatagsVersion: 0.8.2
+scalatagsVersion: 0.12.0
> ./mill show assembly
".../out/assembly.dest/out.jar"
> ./out/assembly.dest/out.jar # mac/linux
Foo.value: hello
-scalatagsVersion: 0.8.2
+scalatagsVersion: 0.12.0
*/
diff --git a/example/misc/4-mill-build-folder/mill-build/build.sc b/example/misc/4-mill-build-folder/mill-build/build.sc
index 01e68be833d..f7b600970de 100644
--- a/example/misc/4-mill-build-folder/mill-build/build.sc
+++ b/example/misc/4-mill-build-folder/mill-build/build.sc
@@ -1,7 +1,7 @@
import mill._, scalalib._
object millbuild extends MillBuildRootModule{
- val scalatagsVersion = "0.8.2"
+ val scalatagsVersion = "0.12.0"
def ivyDeps = Agg(ivy"com.lihaoyi::scalatags:$scalatagsVersion")
def generatedSources = T {
diff --git a/example/thirdparty/jimfs/build.sc b/example/thirdparty/jimfs/build.sc
index 980a997cbe8..839f3ff4353 100644
--- a/example/thirdparty/jimfs/build.sc
+++ b/example/thirdparty/jimfs/build.sc
@@ -1,6 +1,16 @@
import mill._, scalalib._, publish._
-object jimfs extends PublishModule with MavenModule{
+def sharedCompileIvyDeps = T{
+ Agg(
+ ivy"com.google.auto.service:auto-service:1.0.1",
+ ivy"com.google.code.findbugs:jsr305:3.0.2",
+ ivy"org.checkerframework:checker-compat-qual:2.5.5",
+ ivy"com.ibm.icu:icu4j:73.1",
+ )
+}
+
+
+object jimfs extends PublishModule with MavenModule {
def publishVersion = "1.3.3.7"
def pomSettings = PomSettings(
@@ -12,21 +22,14 @@ object jimfs extends PublishModule with MavenModule{
developers = Nil
)
- def ivyDeps = Agg(
+ def ivyDeps = sharedCompileIvyDeps() ++ Agg(
ivy"com.google.guava:guava:31.1-android",
)
- def compileIvyDeps = Agg(
- ivy"com.google.auto.service:auto-service:1.0.1",
- ivy"com.google.code.findbugs:jsr305:3.0.2",
- ivy"org.checkerframework:checker-compat-qual:2.5.5",
- ivy"com.ibm.icu:icu4j:73.1",
- )
-
def javacOptions = Seq("-processor", "com.google.auto.service.processor.AutoServiceProcessor")
- object test extends MavenModuleTests{
- def ivyDeps = Agg(
+ object test extends MavenModuleTests {
+ def ivyDeps = sharedCompileIvyDeps() ++ Agg(
ivy"junit:junit:4.13.2",
ivy"com.google.guava:guava-testlib:31.1-android",
ivy"com.google.truth:truth:1.1.3",
diff --git a/scalalib/src/mill/scalalib/JavaModule.scala b/scalalib/src/mill/scalalib/JavaModule.scala
index 7f4ac04a40f..b99e62c50ab 100644
--- a/scalalib/src/mill/scalalib/JavaModule.scala
+++ b/scalalib/src/mill/scalalib/JavaModule.scala
@@ -128,12 +128,34 @@ trait JavaModule
/** The compile-only direct dependencies of this module. */
def compileModuleDeps: Seq[JavaModule] = Seq.empty
+ /** The direct and indirect dependencies of this module */
+ def recursiveModuleDeps: Seq[JavaModule] = {
+ moduleDeps.flatMap(_.transitiveModuleDeps).distinct
+ }
+
+ /**
+ * Like `recursiveModuleDeps` but also include the module itself,
+ * basically the modules whose classpath are needed at runtime
+ */
+ def transitiveModuleDeps: Seq[JavaModule] = Seq(this) ++ recursiveModuleDeps
+
+ /**
+ * All direct and indirect module dependencies of this module, including
+ * compile-only dependencies: basically the modules whose classpath are needed
+ * at compile-time.
+ *
+ * Note that `compileModuleDeps` are defined to be non-transitive, so we only
+ * look at the direct `compileModuleDeps` when assembling this list
+ */
+ def transitiveModuleCompileModuleDeps: Seq[JavaModule] = {
+ (moduleDeps ++ compileModuleDeps).flatMap(_.transitiveModuleDeps).distinct
+ }
+
/** The compile-only transitive ivy dependencies of this module and all it's upstream compile-only modules. */
def transitiveCompileIvyDeps: T[Agg[BoundDep]] = T {
// We never include compile-only dependencies transitively, but we must include normal transitive dependencies!
- compileIvyDeps().map(bindDependency()) ++ T
- .traverse(compileModuleDeps)(_.transitiveIvyDeps)()
- .flatten
+ compileIvyDeps().map(bindDependency()) ++
+ T.traverse(compileModuleDeps)(_.transitiveIvyDeps)().flatten
}
/**
@@ -158,16 +180,6 @@ trait JavaModule
T.log.outputStream.println(asString)
}
- /** The direct and indirect dependencies of this module */
- def recursiveModuleDeps: Seq[JavaModule] = {
- moduleDeps.flatMap(_.transitiveModuleDeps).distinct
- }
-
- /** Like `recursiveModuleDeps` but also include the module itself */
- def transitiveModuleDeps: Seq[JavaModule] = {
- Seq(this) ++ recursiveModuleDeps
- }
-
/**
* Additional jars, classfiles or resources to add to the classpath directly
* from disk rather than being downloaded from Maven Central or other package
@@ -180,28 +192,22 @@ trait JavaModule
* This is calculated from [[ivyDeps]], [[mandatoryIvyDeps]] and recursively from [[moduleDeps]].
*/
def transitiveIvyDeps: T[Agg[BoundDep]] = T {
- (ivyDeps() ++ mandatoryIvyDeps()).map(bindDependency()) ++ T.traverse(moduleDeps)(
- _.transitiveIvyDeps
- )().flatten
+ (ivyDeps() ++ mandatoryIvyDeps()).map(bindDependency()) ++
+ T.traverse(moduleDeps)(_.transitiveIvyDeps)().flatten
}
/**
* The upstream compilation output of all this module's upstream modules
*/
def upstreamCompileOutput: T[Seq[CompilationResult]] = T {
- T.traverse((recursiveModuleDeps ++ compileModuleDeps.flatMap(
- _.transitiveModuleDeps
- )).distinct)(_.compile)
+ T.traverse(transitiveModuleCompileModuleDeps)(_.compile)
}
/**
* The transitive version of `localClasspath`
*/
def transitiveLocalClasspath: T[Agg[PathRef]] = T {
- T.traverse(
- (moduleDeps ++ compileModuleDeps).flatMap(_.transitiveModuleDeps).distinct
- )(m => m.localClasspath)()
- .flatten
+ T.traverse(transitiveModuleCompileModuleDeps)(_.localClasspath)().flatten
}
/**
@@ -210,20 +216,16 @@ trait JavaModule
// Keep in sync with [[transitiveLocalClasspath]]
@internal
def bspTransitiveLocalClasspath: T[Agg[UnresolvedPath]] = T {
- T.traverse(
- (moduleDeps ++ compileModuleDeps).flatMap(_.transitiveModuleDeps).distinct
- )(m => m.bspLocalClasspath)()
- .flatten
+ T.traverse(transitiveModuleCompileModuleDeps)(_.bspLocalClasspath)().flatten
}
/**
* The transitive version of `compileClasspath`
*/
def transitiveCompileClasspath: T[Agg[PathRef]] = T {
- T.traverse(
- (moduleDeps ++ compileModuleDeps).flatMap(_.transitiveModuleDeps).distinct
- )(m => T.task { m.compileClasspath() ++ Agg(m.compile().classes) })()
- .flatten
+ T.traverse(transitiveModuleCompileModuleDeps)(m =>
+ T.task { m.localCompileClasspath() ++ Agg(m.compile().classes) }
+ )().flatten
}
/**
@@ -232,9 +234,7 @@ trait JavaModule
// Keep in sync with [[transitiveCompileClasspath]]
@internal
def bspTransitiveCompileClasspath: T[Agg[UnresolvedPath]] = T {
- T.traverse(
- (moduleDeps ++ compileModuleDeps).flatMap(_.transitiveModuleDeps).distinct
- )(m =>
+ T.traverse(transitiveModuleCompileModuleDeps)(m =>
T.task {
m.bspCompileClasspath() ++ Agg(m.bspCompileClassesPath())
}
@@ -355,11 +355,11 @@ trait JavaModule
}
/**
- * The output classfiles/resources from this module, excluding upstream
- * modules and third-party dependencies
+ * The *output* classfiles/resources from this module, used for execution,
+ * excluding upstream modules and third-party dependencies
*/
def localClasspath: T[Seq[PathRef]] = T {
- compileResources() ++ resources() ++ Agg(compile().classes)
+ localCompileClasspath().toSeq ++ resources() ++ Agg(compile().classes)
}
/**
@@ -368,9 +368,8 @@ trait JavaModule
*/
@internal
def bspLocalClasspath: T[Agg[UnresolvedPath]] = T {
- (compileResources() ++ resources()).map(p => UnresolvedPath.ResolvedPath(p.path)) ++ Agg(
- bspCompileClassesPath()
- )
+ (compileResources() ++ resources()).map(p => UnresolvedPath.ResolvedPath(p.path)) ++
+ Agg(bspCompileClassesPath())
}
/**
@@ -379,10 +378,15 @@ trait JavaModule
*/
// Keep in sync with [[bspCompileClasspath]]
def compileClasspath: T[Agg[PathRef]] = T {
- transitiveCompileClasspath() ++
- compileResources() ++
- unmanagedClasspath() ++
- resolvedIvyDeps()
+ resolvedIvyDeps() ++ transitiveCompileClasspath() ++ localCompileClasspath()
+ }
+
+ /**
+ * The *input* classfiles/resources from this module, used during compilation,
+ * excluding upstream modules and third-party dependencies
+ */
+ def localCompileClasspath: T[Agg[PathRef]] = T {
+ compileResources() ++ unmanagedClasspath()
}
/** Same as [[compileClasspath]], but does not trigger compilation targets, if possible. */
@@ -390,7 +394,7 @@ trait JavaModule
@internal
def bspCompileClasspath: T[Agg[UnresolvedPath]] = T {
bspTransitiveCompileClasspath() ++
- (compileResources() ++ unmanagedClasspath() ++ resolvedIvyDeps())
+ (localCompileClasspath() ++ resolvedIvyDeps())
.map(p => UnresolvedPath.ResolvedPath(p.path))
}
@@ -398,9 +402,7 @@ trait JavaModule
* Resolved dependencies based on [[transitiveIvyDeps]] and [[transitiveCompileIvyDeps]].
*/
def resolvedIvyDeps: T[Agg[PathRef]] = T {
- resolveDeps(T.task {
- transitiveCompileIvyDeps() ++ transitiveIvyDeps()
- })()
+ resolveDeps(T.task { transitiveCompileIvyDeps() ++ transitiveIvyDeps() })()
}
/**
@@ -408,15 +410,11 @@ trait JavaModule
* assembly, but without this module's contribution
*/
def upstreamAssemblyClasspath: T[Agg[PathRef]] = T {
- transitiveLocalClasspath() ++
- unmanagedClasspath() ++
- resolvedRunIvyDeps()
+ resolvedRunIvyDeps() ++ transitiveLocalClasspath()
}
def resolvedRunIvyDeps: T[Agg[PathRef]] = T {
- resolveDeps(T.task {
- runIvyDeps().map(bindDependency()) ++ transitiveIvyDeps()
- })()
+ resolveDeps(T.task { runIvyDeps().map(bindDependency()) ++ transitiveIvyDeps() })()
}
/**
@@ -424,8 +422,7 @@ trait JavaModule
* necessary to run this module's code after compilation
*/
def runClasspath: T[Seq[PathRef]] = T {
- localClasspath() ++
- upstreamAssemblyClasspath()
+ resolvedRunIvyDeps().toSeq ++ transitiveLocalClasspath() ++ localClasspath()
}
/**
@@ -470,10 +467,7 @@ trait JavaModule
* without those from upstream modules and dependencies
*/
def jar: T[PathRef] = T {
- Jvm.createJar(
- localClasspath().map(_.path).filter(os.exists),
- manifest()
- )
+ Jvm.createJar(localClasspath().map(_.path).filter(os.exists), manifest())
}
/**
diff --git a/scalalib/test/src/mill/scalalib/HelloWorldTests.scala b/scalalib/test/src/mill/scalalib/HelloWorldTests.scala
index 8b4a1beed1a..7498a8ced4e 100644
--- a/scalalib/test/src/mill/scalalib/HelloWorldTests.scala
+++ b/scalalib/test/src/mill/scalalib/HelloWorldTests.scala
@@ -329,6 +329,60 @@ object HelloWorldTests extends TestSuite {
def checkedTuplePathRef: T[Tuple1[PathRef]] = T { Tuple1(mkDirWithFile().withRevalidateOnce) }
}
+ object MultiModuleClasspaths extends HelloBase {
+ trait FooModule extends ScalaModule {
+ def scalaVersion = "2.13.12"
+
+ def ivyDeps = Agg(ivy"com.lihaoyi::sourcecode:0.2.2")
+ def compileIvyDeps = Agg(ivy"com.lihaoyi::geny:0.4.2")
+ def runIvyDeps = Agg(ivy"com.lihaoyi::utest:0.7.2")
+ def unmanagedClasspath = T { Agg(PathRef(millSourcePath / "unmanaged")) }
+ }
+ trait BarModule extends ScalaModule {
+ def scalaVersion = "2.13.12"
+
+ def ivyDeps = Agg(ivy"com.lihaoyi::sourcecode:0.2.1")
+ def compileIvyDeps = Agg(ivy"com.lihaoyi::geny:0.4.1")
+ def runIvyDeps = Agg(ivy"com.lihaoyi::utest:0.7.1")
+ def unmanagedClasspath = T { Agg(PathRef(millSourcePath / "unmanaged")) }
+ }
+ trait QuxModule extends ScalaModule {
+ def scalaVersion = "2.13.12"
+
+ def ivyDeps = Agg(ivy"com.lihaoyi::sourcecode:0.2.0")
+ def compileIvyDeps = Agg(ivy"com.lihaoyi::geny:0.4.0")
+ def runIvyDeps = Agg(ivy"com.lihaoyi::utest:0.7.0")
+ def unmanagedClasspath = T { Agg(PathRef(millSourcePath / "unmanaged")) }
+ }
+ object ModMod extends Module {
+ object foo extends FooModule
+ object bar extends BarModule {
+ def moduleDeps = Seq(foo)
+ }
+ object qux extends QuxModule {
+ def moduleDeps = Seq(bar)
+ }
+ }
+ object ModCompile extends Module {
+ object foo extends FooModule
+ object bar extends BarModule {
+ def moduleDeps = Seq(foo)
+ }
+ object qux extends QuxModule {
+ def compileModuleDeps = Seq(bar)
+ }
+ }
+ object CompileMod extends Module {
+ object foo extends FooModule
+ object bar extends BarModule {
+ def compileModuleDeps = Seq(foo)
+ }
+ object qux extends QuxModule {
+ def moduleDeps = Seq(bar)
+ }
+ }
+ }
+
val resourcePath = os.pwd / "scalalib" / "test" / "resources" / "hello-world"
def jarMainClass(jar: JarFile): Option[String] = {
@@ -1341,5 +1395,223 @@ object HelloWorldTests extends TestSuite {
}
}
+
+ "multiModuleClasspaths" - {
+ // Make sure that a bunch of modules dependent on each other has their various
+ // {classpaths,moduleDeps,ivyDeps}x{run,compile,normal} properly aggregated
+ def check(
+ eval: TestEvaluator,
+ mod: ScalaModule,
+ expectedRunClasspath: Seq[String],
+ expectedCompileClasspath: Seq[String],
+ expectedLocalClasspath: Seq[String]
+ ) = {
+ val Right((runClasspath, _)) = eval.apply(mod.runClasspath)
+ val Right((compileClasspath, _)) = eval.apply(mod.compileClasspath)
+ val Right((upstreamAssemblyClasspath, _)) = eval.apply(mod.upstreamAssemblyClasspath)
+ val Right((localClasspath, _)) = eval.apply(mod.localClasspath)
+
+ val start = Set("org", "com", "MultiModuleClasspaths", "multiModuleClasspaths")
+ def simplify(cp: Seq[PathRef]) = {
+ cp.map(_.path.segments.dropWhile(!start.contains(_)).mkString("/"))
+ }
+
+ val simplerRunClasspath = simplify(runClasspath)
+ val simplerCompileClasspath = simplify(compileClasspath.toSeq)
+ val simplerLocalClasspath = simplify(localClasspath)
+
+ assert(expectedRunClasspath == simplerRunClasspath)
+ assert(expectedCompileClasspath == simplerCompileClasspath)
+ assert(expectedLocalClasspath == simplerLocalClasspath)
+ // invariant: the `upstreamAssemblyClasspath` used to make the `upstreamAssembly`
+ // and the `localClasspath` used to complete it to make the final `assembly` must
+ // have the same entries as the `runClasspath` used to execute things
+ assert(runClasspath == upstreamAssemblyClasspath.toSeq ++ localClasspath)
+ }
+
+ "modMod" - workspaceTest(MultiModuleClasspaths) { eval =>
+ // Make sure that `compileClasspath` has all the same things as `runClasspath`,
+ // but without the `/resources`
+ check(
+ eval,
+ MultiModuleClasspaths.ModMod.qux,
+ expectedRunClasspath = List(
+ // We pick up the oldest version of utest 0.7.0 from the current module, because
+ // utest is a `runIvyDeps` and not picked up transitively
+ "com/lihaoyi/utest_2.13/0.7.0/utest_2.13-0.7.0.jar",
+ // We pick up the newest version of sourcecode 0.2.4 from the upstream module, because
+ // sourcecode is a `ivyDeps` and `runIvyDeps` and those are picked up transitively
+ "com/lihaoyi/sourcecode_2.13/0.2.2/sourcecode_2.13-0.2.2.jar",
+ //
+ "org/scala-lang/scala-library/2.13.12/scala-library-2.13.12.jar",
+ "org/scala-sbt/test-interface/1.0/test-interface-1.0.jar",
+ "org/portable-scala/portable-scala-reflect_2.13/0.1.0/portable-scala-reflect_2.13-0.1.0.jar",
+ "org/scala-lang/scala-reflect/2.13.12/scala-reflect-2.13.12.jar",
+ //
+ "MultiModuleClasspaths/ModMod/bar/compile-resources",
+ "MultiModuleClasspaths/ModMod/bar/unmanaged",
+ "MultiModuleClasspaths/ModMod/bar/resources",
+ "multiModuleClasspaths/modMod/ModMod/bar/compile.dest/classes",
+ //
+ "MultiModuleClasspaths/ModMod/foo/compile-resources",
+ "MultiModuleClasspaths/ModMod/foo/unmanaged",
+ "MultiModuleClasspaths/ModMod/foo/resources",
+ "multiModuleClasspaths/modMod/ModMod/foo/compile.dest/classes",
+ //
+ "MultiModuleClasspaths/ModMod/qux/compile-resources",
+ "MultiModuleClasspaths/ModMod/qux/unmanaged",
+ "MultiModuleClasspaths/ModMod/qux/resources",
+ "multiModuleClasspaths/modMod/ModMod/qux/compile.dest/classes"
+ ),
+ expectedCompileClasspath = List(
+ // Make sure we only have geny 0.6.4 from the current module, and not newer
+ // versions pulled in by the upstream modules, because as `compileIvyDeps` it
+ // is not picked up transitively
+ "com/lihaoyi/geny_2.13/0.4.0/geny_2.13-0.4.0.jar",
+ "com/lihaoyi/sourcecode_2.13/0.2.2/sourcecode_2.13-0.2.2.jar",
+ //
+ "org/scala-lang/scala-library/2.13.12/scala-library-2.13.12.jar",
+ //
+ "MultiModuleClasspaths/ModMod/bar/compile-resources",
+ "MultiModuleClasspaths/ModMod/bar/unmanaged",
+ "multiModuleClasspaths/modMod/ModMod/bar/compile.dest/classes",
+ //
+ "MultiModuleClasspaths/ModMod/foo/compile-resources",
+ "MultiModuleClasspaths/ModMod/foo/unmanaged",
+ "multiModuleClasspaths/modMod/ModMod/foo/compile.dest/classes",
+ //
+ "MultiModuleClasspaths/ModMod/qux/compile-resources",
+ "MultiModuleClasspaths/ModMod/qux/unmanaged"
+ // We do not include `qux/compile.dest/classes` here, because this is the input
+ // that is required to compile `qux` in the first place
+ ),
+ expectedLocalClasspath = List(
+ "MultiModuleClasspaths/ModMod/qux/compile-resources",
+ "MultiModuleClasspaths/ModMod/qux/unmanaged",
+ "MultiModuleClasspaths/ModMod/qux/resources",
+ "multiModuleClasspaths/modMod/ModMod/qux/compile.dest/classes"
+ )
+ )
+ }
+
+ "modCompile" - workspaceTest(MultiModuleClasspaths) { eval =>
+ // Mostly the same as `modMod` above, but with the dependency
+ // from `qux` to `bar` being a `compileModuleDeps`
+ check(
+ eval,
+ MultiModuleClasspaths.ModCompile.qux,
+ expectedRunClasspath = List(
+ // `utest` is a `runIvyDeps` and not picked up transitively
+ "com/lihaoyi/utest_2.13/0.7.0/utest_2.13-0.7.0.jar",
+ // Because `sourcecode` comes from `ivyDeps`, and the dependency from
+ // `qux` to `bar` is a `compileModuleDeps`, we do not include its
+ // dependencies for `qux`'s `runClasspath`
+ "com/lihaoyi/sourcecode_2.13/0.2.0/sourcecode_2.13-0.2.0.jar",
+ //
+ "org/scala-lang/scala-library/2.13.12/scala-library-2.13.12.jar",
+ "org/scala-sbt/test-interface/1.0/test-interface-1.0.jar",
+ "org/portable-scala/portable-scala-reflect_2.13/0.1.0/portable-scala-reflect_2.13-0.1.0.jar",
+ "org/scala-lang/scala-reflect/2.13.12/scala-reflect-2.13.12.jar",
+ //
+ "MultiModuleClasspaths/ModCompile/bar/compile-resources",
+ "MultiModuleClasspaths/ModCompile/bar/unmanaged",
+ "MultiModuleClasspaths/ModCompile/bar/resources",
+ "multiModuleClasspaths/modCompile/ModCompile/bar/compile.dest/classes",
+ //
+ "MultiModuleClasspaths/ModCompile/foo/compile-resources",
+ "MultiModuleClasspaths/ModCompile/foo/unmanaged",
+ "MultiModuleClasspaths/ModCompile/foo/resources",
+ "multiModuleClasspaths/modCompile/ModCompile/foo/compile.dest/classes",
+ //
+ "MultiModuleClasspaths/ModCompile/qux/compile-resources",
+ "MultiModuleClasspaths/ModCompile/qux/unmanaged",
+ "MultiModuleClasspaths/ModCompile/qux/resources",
+ "multiModuleClasspaths/modCompile/ModCompile/qux/compile.dest/classes"
+ ),
+ expectedCompileClasspath = List(
+ "com/lihaoyi/geny_2.13/0.4.0/geny_2.13-0.4.0.jar",
+ // `sourcecode` is a `ivyDeps` from a `compileModuleDeps, which still
+ // gets picked up transitively, but only for compilation. This is necessary
+ // in order to make sure that we can correctly compile against the upstream
+ // module's classes.
+ "com/lihaoyi/sourcecode_2.13/0.2.2/sourcecode_2.13-0.2.2.jar",
+ //
+ "org/scala-lang/scala-library/2.13.12/scala-library-2.13.12.jar",
+ //
+ "MultiModuleClasspaths/ModCompile/bar/compile-resources",
+ "MultiModuleClasspaths/ModCompile/bar/unmanaged",
+ "multiModuleClasspaths/modCompile/ModCompile/bar/compile.dest/classes",
+ //
+ "MultiModuleClasspaths/ModCompile/foo/compile-resources",
+ "MultiModuleClasspaths/ModCompile/foo/unmanaged",
+ "multiModuleClasspaths/modCompile/ModCompile/foo/compile.dest/classes",
+ //
+ "MultiModuleClasspaths/ModCompile/qux/compile-resources",
+ "MultiModuleClasspaths/ModCompile/qux/unmanaged"
+ ),
+ expectedLocalClasspath = List(
+ "MultiModuleClasspaths/ModCompile/qux/compile-resources",
+ "MultiModuleClasspaths/ModCompile/qux/unmanaged",
+ "MultiModuleClasspaths/ModCompile/qux/resources",
+ "multiModuleClasspaths/modCompile/ModCompile/qux/compile.dest/classes"
+ )
+ )
+ }
+
+ "compileMod" - workspaceTest(MultiModuleClasspaths) { eval =>
+ // Both the `runClasspath` and `compileClasspath` should not have `foo` on the
+ // classpath, nor should it have the versions of libraries pulled in by `foo`
+ // (e.g. `sourcecode-0.2.4`), because it is a `compileModuleDep` of an upstream
+ // module and thus it is not transitive
+ check(
+ eval,
+ MultiModuleClasspaths.CompileMod.qux,
+ expectedRunClasspath = List(
+ "com/lihaoyi/utest_2.13/0.7.0/utest_2.13-0.7.0.jar",
+ // We pick up the version of `sourcecode` from `ivyDeps` from `bar` because
+ // we have a normal `moduleDeps` from `qux` to `bar`, but do not pick it up
+ // from `foo` because it's a `compileIvyDeps` from `bar` to `foo` and
+ // `compileIvyDeps` are not transitive
+ "com/lihaoyi/sourcecode_2.13/0.2.1/sourcecode_2.13-0.2.1.jar",
+ //
+ "org/scala-lang/scala-library/2.13.12/scala-library-2.13.12.jar",
+ "org/scala-sbt/test-interface/1.0/test-interface-1.0.jar",
+ "org/portable-scala/portable-scala-reflect_2.13/0.1.0/portable-scala-reflect_2.13-0.1.0.jar",
+ "org/scala-lang/scala-reflect/2.13.12/scala-reflect-2.13.12.jar",
+ //
+ "MultiModuleClasspaths/CompileMod/bar/compile-resources",
+ "MultiModuleClasspaths/CompileMod/bar/unmanaged",
+ "MultiModuleClasspaths/CompileMod/bar/resources",
+ "multiModuleClasspaths/compileMod/CompileMod/bar/compile.dest/classes",
+ //
+ "MultiModuleClasspaths/CompileMod/qux/compile-resources",
+ "MultiModuleClasspaths/CompileMod/qux/unmanaged",
+ "MultiModuleClasspaths/CompileMod/qux/resources",
+ "multiModuleClasspaths/compileMod/CompileMod/qux/compile.dest/classes"
+ ),
+ expectedCompileClasspath = List(
+ "com/lihaoyi/geny_2.13/0.4.0/geny_2.13-0.4.0.jar",
+ "com/lihaoyi/sourcecode_2.13/0.2.1/sourcecode_2.13-0.2.1.jar",
+ //
+ "org/scala-lang/scala-library/2.13.12/scala-library-2.13.12.jar",
+ // We do not include `foo`s compile output here, because `foo` is a
+ // `compileModuleDep` of `bar`, and `compileModuleDep`s are non-transitive
+ //
+ "MultiModuleClasspaths/CompileMod/bar/compile-resources",
+ "MultiModuleClasspaths/CompileMod/bar/unmanaged",
+ "multiModuleClasspaths/compileMod/CompileMod/bar/compile.dest/classes",
+ //
+ "MultiModuleClasspaths/CompileMod/qux/compile-resources",
+ "MultiModuleClasspaths/CompileMod/qux/unmanaged"
+ ),
+ expectedLocalClasspath = List(
+ "MultiModuleClasspaths/CompileMod/qux/compile-resources",
+ "MultiModuleClasspaths/CompileMod/qux/unmanaged",
+ "MultiModuleClasspaths/CompileMod/qux/resources",
+ "multiModuleClasspaths/compileMod/CompileMod/qux/compile.dest/classes"
+ )
+ )
+ }
+ }
}
}