diff --git a/main/Defaults.scala b/main/Defaults.scala index e1c84b169..9cc0d692a 100644 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -233,6 +233,9 @@ object Defaults extends BuildCommon def watchTransitiveSourcesTask: Initialize[Task[Seq[File]]] = inDependencies[Task[Seq[File]]](watchSources.task, const(std.TaskExtra.constant(Nil)), aggregate = true, includeRoot = true) apply { _.join.map(_.flatten) } + def transitiveUpdateTask: Initialize[Task[Seq[UpdateReport]]] = + forDependencies(ref => (update.task in ref).?, aggregate = false, includeRoot = false) apply( _.flatten.join) + def watchSetting: Initialize[Watched] = (pollInterval, thisProjectRef, watchingMessage, triggeredMessage) { (interval, base, msg, trigMsg) => new Watched { val scoped = watchTransitiveSources in base @@ -543,8 +546,11 @@ object Defaults extends BuildCommon } def inDependencies[T](key: SettingKey[T], default: ProjectRef => T, includeRoot: Boolean = true, classpath: Boolean = true, aggregate: Boolean = false): Initialize[Seq[T]] = + forDependencies[T,T](ref => (key in ref) ?? default(ref), includeRoot, classpath, aggregate) + + def forDependencies[T,V](init: ProjectRef => Initialize[V], includeRoot: Boolean = true, classpath: Boolean = true, aggregate: Boolean = false): Initialize[Seq[V]] = Project.bind( (loadedBuild, thisProjectRef).identity ) { case (lb, base) => - transitiveDependencies(base, lb, includeRoot, classpath, aggregate) map ( ref => (key in ref) ?? default(ref) ) join ; + transitiveDependencies(base, lb, includeRoot, classpath, aggregate) map init join ; } def transitiveDependencies(base: ProjectRef, structure: LoadedBuild, includeRoot: Boolean, classpath: Boolean = true, aggregate: Boolean = false): Seq[ProjectRef] = @@ -722,8 +728,10 @@ object Classpaths }, ivySbt <<= ivySbt0, ivyModule <<= (ivySbt, moduleSettings) map { (ivySbt, settings) => new ivySbt.Module(settings) }, - update <<= (ivyModule, thisProjectRef, updateConfiguration, cacheDirectory, scalaInstance, streams) map { (module, ref, config, cacheDirectory, si, s) => - cachedUpdate(cacheDirectory / "update", Project.display(ref), module, config, Some(si), s.log) + transitiveUpdate <<= transitiveUpdateTask, + update <<= (ivyModule, thisProjectRef, updateConfiguration, cacheDirectory, scalaInstance, transitiveUpdate, streams) map { (module, ref, config, cacheDirectory, si, reports, s) => + val depsUpdated = reports.exists(!_.stats.cached) + cachedUpdate(cacheDirectory / "update", Project.display(ref), module, config, Some(si), depsUpdated, s.log) }, update <<= (conflictWarning, update, streams) map { (config, report, s) => ConflictWarning(config, report, s.log); report }, transitiveClassifiers in GlobalScope :== Seq(SourceClassifier, DocClassifier), @@ -798,7 +806,7 @@ object Classpaths }}) } - def cachedUpdate(cacheFile: File, label: String, module: IvySbt#Module, config: UpdateConfiguration, scalaInstance: Option[ScalaInstance], log: Logger): UpdateReport = + def cachedUpdate(cacheFile: File, label: String, module: IvySbt#Module, config: UpdateConfiguration, scalaInstance: Option[ScalaInstance], depsUpdated: Boolean, log: Logger): UpdateReport = { implicit val updateCache = updateIC implicit val updateReport = updateReportF @@ -809,11 +817,16 @@ object Classpaths log.info("Done updating.") scalaInstance match { case Some(si) => substituteScalaFiles(si, r); case None => r } } + def uptodate(inChanged: Boolean, out: UpdateReport): Boolean = + !depsUpdated && + !inChanged && + out.allFiles.forall(_.exists) && + out.cachedDescriptor.exists val f = Tracked.inputChanged(cacheFile / "inputs") { (inChanged: Boolean, in: In) => val outCache = Tracked.lastOutput[In, UpdateReport](cacheFile / "output") { - case (_, Some(out)) if !inChanged && out.allFiles.forall(_.exists) && out.cachedDescriptor.exists => out + case (_, Some(out)) if uptodate(inChanged, out) => out case _ => work(in) } outCache(in) diff --git a/main/Keys.scala b/main/Keys.scala index 40176de6f..ac4e3a074 100644 --- a/main/Keys.scala +++ b/main/Keys.scala @@ -231,6 +231,7 @@ object Keys val ivySbt = TaskKey[IvySbt]("ivy-sbt", "Provides the sbt interface to Ivy.") val ivyModule = TaskKey[IvySbt#Module]("ivy-module", "Provides the sbt interface to a configured Ivy module.") val update = TaskKey[UpdateReport]("update", "Resolves and optionally retrieves dependencies, producing a report.") + val transitiveUpdate = TaskKey[Seq[UpdateReport]]("transitive-update", "UpdateReports for the internal dependencies of this project.") val updateClassifiers = TaskKey[UpdateReport]("update-classifiers", "Resolves and optionally retrieves classified artifacts, such as javadocs and sources, for dependency definitions, transitively.", update) val transitiveClassifiers = SettingKey[Seq[String]]("transitive-classifiers", "List of classifiers used for transitively obtaining extra artifacts for sbt or declared dependencies.") val updateSbtClassifiers = TaskKey[UpdateReport]("update-sbt-classifiers", "Resolves and optionally retrieves classifiers, such as javadocs and sources, for sbt, transitively.", updateClassifiers) diff --git a/sbt/src/sbt-test/dependency-management/invalidate-internal/changes/A.scala b/sbt/src/sbt-test/dependency-management/invalidate-internal/changes/A.scala new file mode 100644 index 000000000..53e0bd0b5 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/invalidate-internal/changes/A.scala @@ -0,0 +1,3 @@ +object A { + def apply(x: org.junit.runners.JUnit4) = () +} \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/invalidate-internal/changes/b.sbt b/sbt/src/sbt-test/dependency-management/invalidate-internal/changes/b.sbt new file mode 100644 index 000000000..6d4e04264 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/invalidate-internal/changes/b.sbt @@ -0,0 +1 @@ +libraryDependencies += "junit" % "junit" % "4.5" diff --git a/sbt/src/sbt-test/dependency-management/invalidate-internal/project/P.scala b/sbt/src/sbt-test/dependency-management/invalidate-internal/project/P.scala new file mode 100644 index 000000000..aacfc450b --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/invalidate-internal/project/P.scala @@ -0,0 +1,9 @@ +import sbt._ +import Keys._ + +object P extends Build +{ + lazy val root = Project("root", file(".")) + lazy val a = Project("a", file("a")) dependsOn(b) + lazy val b = Project("b", file("b")) +} \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-management/invalidate-internal/test b/sbt/src/sbt-test/dependency-management/invalidate-internal/test new file mode 100644 index 000000000..4c8db46c9 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/invalidate-internal/test @@ -0,0 +1,11 @@ +> a/compile +$ copy-file changes/A.scala a/A.scala +-> a/compile + +$ copy-file changes/b.sbt b/build.sbt +> reload +> a/compile + +$ delete b/build.sbt +> reload +-> a/compile \ No newline at end of file