From 3690ff193cfbc6c9391bf0176aab3d930ff88010 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 29 May 2017 17:14:52 -0400 Subject: [PATCH] Fix cached update task Fixes sbt/sbt#3226 One of the checks that the cached update task performs is called `depsUpdated`, which checks if the subproject dependencies have been thawed out of cache of now. For this to function correctly, when we thaw the `UpdateReport` from JSON, we need to mark the report as cached. This was done subtley in sbt 0.13 for sbinary (https://github.com/sbt/sbt-zero-thirteen/blob/v0.13.15/main/actions/src/main/scala/sbt/CacheIvy.scala#L66-L67). --- .../sbt/internal/LibraryManagement.scala | 9 ++- .../cache-update/build.sbt | 73 ++++++++++++------- .../dependency-management/cache-update/test | 1 + 3 files changed, 55 insertions(+), 28 deletions(-) diff --git a/main/src/main/scala/sbt/internal/LibraryManagement.scala b/main/src/main/scala/sbt/internal/LibraryManagement.scala index fa78eff39..f21919383 100644 --- a/main/src/main/scala/sbt/internal/LibraryManagement.scala +++ b/main/src/main/scala/sbt/internal/LibraryManagement.scala @@ -71,17 +71,22 @@ object LibraryManagement { def skipResolve(cache: CacheStore): UpdateInputs => UpdateReport = { import sbt.librarymanagement.LibraryManagementCodec._ Tracked.lastOutput[UpdateInputs, UpdateReport](cache) { - case (_, Some(out)) => out + case (_, Some(out)) => markAsCached(out) case _ => sys.error("Skipping update requested, but update has not previously run successfully.") } } + // Mark UpdateReport#stats as "cached." This is used by the dependers later + // to determine whether they now need to run update in the above `upToDate`. + def markAsCached(ur: UpdateReport): UpdateReport = + ur.withStats(ur.stats.withCached(true)) + def doResolve(cache: CacheStore): UpdateInputs => UpdateReport = { val doCachedResolve = { (inChanged: Boolean, updateInputs: UpdateInputs) => import sbt.librarymanagement.LibraryManagementCodec._ val cachedResolve = Tracked.lastOutput[UpdateInputs, UpdateReport](cache) { - case (_, Some(out)) if upToDate(inChanged, out) => out + case (_, Some(out)) if upToDate(inChanged, out) => markAsCached(out) case _ => resolve(updateInputs) } import scala.util.control.Exception.catching diff --git a/sbt/src/sbt-test/dependency-management/cache-update/build.sbt b/sbt/src/sbt-test/dependency-management/cache-update/build.sbt index 2043ff2f4..38eb67043 100644 --- a/sbt/src/sbt-test/dependency-management/cache-update/build.sbt +++ b/sbt/src/sbt-test/dependency-management/cache-update/build.sbt @@ -1,33 +1,54 @@ -// #1620 - -ivyPaths := IvyPaths( - (baseDirectory in ThisBuild).value, - Some((baseDirectory in LocalRootProject).value / "ivy-cache") -) - -scalaVersion := "2.10.4" - +scalaVersion in ThisBuild := "2.10.4" dependencyOverrides in ThisBuild += "com.github.nscala-time" %% "nscala-time" % "1.0.0" -libraryDependencies += "com.github.nscala-time" %% "nscala-time" % "1.0.0" -TaskKey[Unit]("check") := { - val s = (streams in update).value - val cacheStoreFactory = s.cacheStoreFactory sub updateCacheName.value - val module = ivyModule.value - val config = updateConfiguration.value +lazy val root = (project in file(".")) + .dependsOn(p1 % Compile) + .settings( + ivyPaths := IvyPaths( + (baseDirectory in ThisBuild).value, + Some((baseDirectory in LocalRootProject).value / "ivy-cache") + ), + libraryDependencies += "com.github.nscala-time" %% "nscala-time" % "1.0.0", - import sbt.internal.librarymanagement.IvyConfiguration - import sbt.librarymanagement.{ ModuleSettings, UpdateConfiguration } + // https://github.com/sbt/sbt/pull/1620 + // sbt resolves dependencies every compile when using %% with dependencyOverrides + TaskKey[Unit]("check") := { + val s = (streams in update).value + val cacheStoreFactory = s.cacheStoreFactory sub updateCacheName.value + val module = ivyModule.value + val config = updateConfiguration.value - type In = IvyConfiguration :+: ModuleSettings :+: UpdateConfiguration :+: HNil + import sbt.internal.librarymanagement.IvyConfiguration + import sbt.librarymanagement.{ ModuleSettings, UpdateConfiguration } - import sbt.util.CacheImplicits._ - import sbt.internal.AltLibraryManagementCodec._ + type In = IvyConfiguration :+: ModuleSettings :+: UpdateConfiguration :+: HNil - val f: In => Unit = - Tracked.inputChanged(cacheStoreFactory make "inputs") { (inChanged: Boolean, in: In) => - if (inChanged) - sys.error(s"Update cache is invalidated: ${module.owner.configuration}, ${module.moduleSettings}, $config") + import sbt.util.CacheImplicits._ + import sbt.internal.AltLibraryManagementCodec._ + + val f: In => Unit = + Tracked.inputChanged(cacheStoreFactory make "inputs") { (inChanged: Boolean, in: In) => + if (inChanged) + sys.error(s"Update cache is invalidated: ${module.owner.configuration}, ${module.moduleSettings}, $config") + } + f(module.owner.configuration :+: module.moduleSettings :+: config :+: HNil) + }, + + // https://github.com/sbt/sbt/issues/3226 + // update caching is not working on sbt 1.0.x + TaskKey[Unit]("check2") := { + val ur = update.value + if (!ur.stats.cached) { + sys.error(s"update.value is not cached! $ur") + } + val tu = transitiveUpdate.value + if (tu.exists(!_.stats.cached)) { + sys.error(s"uncached transitiveUpdate exists! $tu") + } } - f(module.owner.configuration :+: module.moduleSettings :+: config :+: HNil) -} + ) + +lazy val p1 = project + .settings( + libraryDependencies += "com.novocode" % "junit-interface" % "0.11" + ) diff --git a/sbt/src/sbt-test/dependency-management/cache-update/test b/sbt/src/sbt-test/dependency-management/cache-update/test index e3bd83da1..468a2b8d7 100644 --- a/sbt/src/sbt-test/dependency-management/cache-update/test +++ b/sbt/src/sbt-test/dependency-management/cache-update/test @@ -1,2 +1,3 @@ > compile > check +> check2