From e910a13d7f80388018957e40a4dba8d4e82c59ea Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Wed, 9 Jan 2019 17:27:50 -0800 Subject: [PATCH] Add internalDependencyConfigurations setting In order to walk the full dependency graph of a task, we need to know the internal class path dependency configurations. Suppose that we have projects a and b where b depends on *->compile in a. If we want to find all of the inputs for b, then if we find that there is a dependency on b/Compile/internalDependencyClasspath, then we must add a / Compile / internalDependencyClasspath to the list of dependencies for the task. I copied the setup of one of the other scripted tests that was introduced to test the track-internal-dependencies feature to write a basic scripted test for this new key and implementation. --- main/src/main/scala/sbt/Defaults.scala | 1 + main/src/main/scala/sbt/Keys.scala | 1 + .../sbt/internal/InternalDependencies.scala | 32 +++++++++++ .../a/A.scala | 3 ++ .../b/B.scala | 5 ++ .../build.sbt | 53 +++++++++++++++++++ .../c/C.scala | 3 ++ .../d/D.scala | 3 ++ .../internal-dependency-configurations/test | 7 +++ 9 files changed, 108 insertions(+) create mode 100644 main/src/main/scala/sbt/internal/InternalDependencies.scala create mode 100644 sbt/src/sbt-test/project/internal-dependency-configurations/a/A.scala create mode 100644 sbt/src/sbt-test/project/internal-dependency-configurations/b/B.scala create mode 100644 sbt/src/sbt-test/project/internal-dependency-configurations/build.sbt create mode 100644 sbt/src/sbt-test/project/internal-dependency-configurations/c/C.scala create mode 100644 sbt/src/sbt-test/project/internal-dependency-configurations/d/D.scala create mode 100644 sbt/src/sbt-test/project/internal-dependency-configurations/test diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 24659d662..d7044ecfd 100755 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -583,6 +583,7 @@ object Defaults extends BuildCommon { ) ++ (sourceGenerators / fileOutputs).value, compile := compileTask.value, clean := Clean.taskIn(ThisScope).value, + internalDependencyConfigurations := InternalDependencies.configurations.value, manipulateBytecode := compileIncremental.value, compileIncremental := (compileIncrementalTask tag (Tags.Compile, Tags.CPU)).value, printWarnings := printWarningsTask.value, diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index f8de41394..1b276dea8 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -334,6 +334,7 @@ object Keys { val internalDependencyAsJars = taskKey[Classpath]("The internal (inter-project) classpath as JARs.") val dependencyClasspathAsJars = taskKey[Classpath]("The classpath consisting of internal and external, managed and unmanaged dependencies, all as JARs.") val fullClasspathAsJars = taskKey[Classpath]("The exported classpath, consisting of build products and unmanaged and managed, internal and external dependencies, all as JARs.") + val internalDependencyConfigurations = settingKey[Seq[(ProjectRef, Set[String])]]("The project configurations that this configuration depends on") val internalConfigurationMap = settingKey[Configuration => Configuration]("Maps configurations to the actual configuration used to define the classpath.").withRank(CSetting) val classpathConfiguration = taskKey[Configuration]("The configuration used to define the classpath.").withRank(CTask) diff --git a/main/src/main/scala/sbt/internal/InternalDependencies.scala b/main/src/main/scala/sbt/internal/InternalDependencies.scala new file mode 100644 index 000000000..9dc447831 --- /dev/null +++ b/main/src/main/scala/sbt/internal/InternalDependencies.scala @@ -0,0 +1,32 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt +package internal + +import sbt.Keys._ + +private[sbt] object InternalDependencies { + def configurations: Def.Initialize[Seq[(ProjectRef, Set[String])]] = Def.setting { + val allConfigs = Classpaths.allConfigs(configuration.value).map(_.name).toSet + val ref = thisProjectRef.value + val applicableConfigs = allConfigs + "*" + ((ref -> allConfigs) +: buildDependencies.value.classpath + .get(ref) + .toSeq + .flatMap(_.flatMap { + case ResolvedClasspathDependency(p, rawConfigs) => + val configs = rawConfigs.getOrElse("*->compile").split(";").flatMap { config => + config.split("->") match { + case Array(n, c) if applicableConfigs.contains(n) => Some(c) + case _ => None + } + } + if (configs.isEmpty) None else Some(p -> configs.toSet) + })).distinct + } +} diff --git a/sbt/src/sbt-test/project/internal-dependency-configurations/a/A.scala b/sbt/src/sbt-test/project/internal-dependency-configurations/a/A.scala new file mode 100644 index 000000000..3f2aea979 --- /dev/null +++ b/sbt/src/sbt-test/project/internal-dependency-configurations/a/A.scala @@ -0,0 +1,3 @@ +package a + +object A {} diff --git a/sbt/src/sbt-test/project/internal-dependency-configurations/b/B.scala b/sbt/src/sbt-test/project/internal-dependency-configurations/b/B.scala new file mode 100644 index 000000000..184707bb1 --- /dev/null +++ b/sbt/src/sbt-test/project/internal-dependency-configurations/b/B.scala @@ -0,0 +1,5 @@ +package b + +object B { + println(a.A.toString) +} diff --git a/sbt/src/sbt-test/project/internal-dependency-configurations/build.sbt b/sbt/src/sbt-test/project/internal-dependency-configurations/build.sbt new file mode 100644 index 000000000..06a8556dd --- /dev/null +++ b/sbt/src/sbt-test/project/internal-dependency-configurations/build.sbt @@ -0,0 +1,53 @@ +lazy val root = (project in file(".")). + aggregate(a, b, c, d). + settings( + inThisBuild(Seq( + scalaVersion := "2.11.7", + trackInternalDependencies := TrackLevel.NoTracking + )) + ) + +lazy val a = project in file("a") + +lazy val b = (project in file("b")).dependsOn(a % "*->compile") + +lazy val c = (project in file("c")).settings(exportToInternal := TrackLevel.NoTracking) + +lazy val d = (project in file("d")) + .dependsOn(c % "test->test;compile->compile") + .settings(trackInternalDependencies := TrackLevel.TrackIfMissing) + +def getConfigs(key: SettingKey[Seq[(ProjectRef, Set[String])]]): + Def.Initialize[Map[String, Set[String]]] = + Def.setting(key.value.map { case (p, c) => p.project -> c }.toMap) +val checkA = taskKey[Unit]("Verify that project a's internal dependencies are as expected") +checkA := { + val compileDeps = getConfigs(a / Compile / internalDependencyConfigurations).value + assert(compileDeps == Map("a" -> Set("compile"))) + val testDeps = getConfigs(a / Test / internalDependencyConfigurations).value + assert(testDeps == Map("a" -> Set("compile", "runtime", "test"))) +} + +val checkB = taskKey[Unit]("Verify that project b's internal dependencies are as expected") +checkB := { + val compileDeps = getConfigs(b / Compile / internalDependencyConfigurations).value + assert(compileDeps == Map("b" -> Set("compile"), "a" -> Set("compile"))) + val testDeps = getConfigs(b / Test / internalDependencyConfigurations).value + assert(testDeps == Map("b" -> Set("compile", "runtime", "test"), "a" -> Set("compile"))) +} + +val checkC = taskKey[Unit]("Verify that project c's internal dependencies are as expected") +checkC := { + val compileDeps = getConfigs(c / Compile / internalDependencyConfigurations).value + assert(compileDeps == Map("c" -> Set("compile"))) + val testDeps = getConfigs(c / Test / internalDependencyConfigurations).value + assert(testDeps == Map("c" -> Set("compile", "runtime", "test"))) +} + +val checkD = taskKey[Unit]("Verify that project d's internal dependencies are as expected") +checkD := { + val compileDeps = getConfigs(d / Compile / internalDependencyConfigurations).value + assert(compileDeps == Map("d" -> Set("compile"), "c" -> Set("compile"))) + val testDeps = getConfigs(d / Test / internalDependencyConfigurations).value + assert(testDeps == Map("d" -> Set("compile", "runtime", "test"), "c" -> Set("compile", "test"))) +} diff --git a/sbt/src/sbt-test/project/internal-dependency-configurations/c/C.scala b/sbt/src/sbt-test/project/internal-dependency-configurations/c/C.scala new file mode 100644 index 000000000..abadf1e84 --- /dev/null +++ b/sbt/src/sbt-test/project/internal-dependency-configurations/c/C.scala @@ -0,0 +1,3 @@ +package c + +object C {} diff --git a/sbt/src/sbt-test/project/internal-dependency-configurations/d/D.scala b/sbt/src/sbt-test/project/internal-dependency-configurations/d/D.scala new file mode 100644 index 000000000..9a2cd3377 --- /dev/null +++ b/sbt/src/sbt-test/project/internal-dependency-configurations/d/D.scala @@ -0,0 +1,3 @@ +package d + +object D { println(c.C.toString) } diff --git a/sbt/src/sbt-test/project/internal-dependency-configurations/test b/sbt/src/sbt-test/project/internal-dependency-configurations/test new file mode 100644 index 000000000..618b58159 --- /dev/null +++ b/sbt/src/sbt-test/project/internal-dependency-configurations/test @@ -0,0 +1,7 @@ +> checkA + +> checkB + +> checkC + +> checkD