Force update on change to last modified time of artifacts or cached descriptor.

This is part 2 of the fix for #532.  It may also fix issues when working with
multiple local projects via 'publish-local' and binary dependencies.
This commit is contained in:
Mark Harrah 2012-08-29 11:13:48 -04:00
parent 14952e00b6
commit 3dd3a18996
6 changed files with 22 additions and 9 deletions

View File

@ -48,7 +48,7 @@ object IvyRetrieve
}
def updateReport(report: ResolveReport, cachedDescriptor: File): UpdateReport =
new UpdateReport(cachedDescriptor, reports(report) map configurationReport, updateStats(report))
new UpdateReport(cachedDescriptor, reports(report) map configurationReport, updateStats(report), Map.empty) recomputeStamps()
def updateStats(report: ResolveReport): UpdateStats =
new UpdateStats(report.getResolveTime, report.getDownloadTime, report.getDownloadSize, false)
def configurationReport(confReport: ConfigurationResolveReport): ConfigurationReport =

View File

@ -54,7 +54,7 @@ private[sbt] object ResolutionCache
private val ReportFileName = "report.xml"
// base name (name except for extension) of resolution report file
private val ResolvedName = "resolved"
private val ResolvedName = "resolved.xml"
// Cache name
private val Name = "sbt-resolution-cache"

View File

@ -13,15 +13,19 @@ package sbt
* @param stats information about the update that produced this report
* @see sbt.RichUpdateReport
*/
final class UpdateReport(val cachedDescriptor: File, val configurations: Seq[ConfigurationReport], val stats: UpdateStats)
final class UpdateReport(val cachedDescriptor: File, val configurations: Seq[ConfigurationReport], val stats: UpdateStats, private[sbt] val stamps: Map[File,Long])
{
@deprecated("Use the variant that provides timestamps of files.", "0.13.0")
def this(cachedDescriptor: File, configurations: Seq[ConfigurationReport], stats: UpdateStats) =
this(cachedDescriptor, configurations, stats, Map.empty)
override def toString = "Update report:\n\t" + stats + "\n" + configurations.mkString
/** All resolved modules in all configurations. */
def allModules: Seq[ModuleID] = configurations.flatMap(_.allModules).distinct
def retrieve(f: (String, ModuleID, Artifact, File) => File): UpdateReport =
new UpdateReport(cachedDescriptor, configurations map { _ retrieve f}, stats )
new UpdateReport(cachedDescriptor, configurations map { _ retrieve f}, stats, stamps )
/** Gets the report for the given configuration, or `None` if the configuration was not resolved.*/
def configuration(s: String) = configurations.find(_.configuration == s)
@ -71,6 +75,13 @@ object UpdateReport
/** Provides extra methods for filtering the contents of an `UpdateReport` and for obtaining references to a selected subset of the underlying files. */
final class RichUpdateReport(report: UpdateReport)
{
def recomputeStamps(): UpdateReport =
{
val files = report.cachedDescriptor +: allFiles
val stamps = files.map(f => (f, f.lastModified)).toMap
new UpdateReport(report.cachedDescriptor, report.configurations, report.stats, stamps)
}
import DependencyFilter._
/** Obtains all successfully retrieved files in all configurations and modules. */
def allFiles: Seq[File] = matching(DependencyFilter.allPass)
@ -123,7 +134,7 @@ object UpdateReport
val newModules = modules map { modReport => f(configuration, modReport) }
new ConfigurationReport(configuration, newModules, evicted)
}
new UpdateReport(report.cachedDescriptor, newConfigurations, report.stats)
new UpdateReport(report.cachedDescriptor, newConfigurations, report.stats, report.stamps)
}
}
}

View File

@ -956,8 +956,8 @@ object Classpaths
!force &&
!depsUpdated &&
!inChanged &&
out.allFiles.forall(_.exists) &&
out.cachedDescriptor.exists
out.allFiles.forall(f => fileUptodate(f,out.stamps)) &&
fileUptodate(out.cachedDescriptor, out.stamps)
val outCacheFile = cacheFile / "output"
def skipWork: In => UpdateReport =
@ -976,6 +976,8 @@ object Classpaths
val f = if(skip && !force) skipWork else doWork
f(module.owner.configuration :+: module.moduleSettings :+: config :+: HNil)
}
private[this] def fileUptodate(file: File, stamps: Map[File, Long]): Boolean =
stamps.get(file).forall(_ == file.lastModified)
/*
// can't cache deliver/publish easily since files involved are hidden behind patterns. publish will be difficult to verify target-side anyway
def cachedPublish(cacheFile: File)(g: (IvySbt#Module, PublishConfiguration) => Unit, module: IvySbt#Module, config: PublishConfiguration) => Unit =

View File

@ -59,7 +59,7 @@ object CacheIvy
implicit lazy val updateReportFormat: Format[UpdateReport] =
{
import DefaultProtocol.{StringFormat, FileFormat}
wrap[UpdateReport, (File, Seq[ConfigurationReport], UpdateStats)](rep => (rep.cachedDescriptor, rep.configurations, rep.stats), { case (cd, cs, stats) => new UpdateReport(cd, cs, stats) })
wrap[UpdateReport, (File, Seq[ConfigurationReport], UpdateStats, Map[File,Long])](rep => (rep.cachedDescriptor, rep.configurations, rep.stats, rep.stamps), { case (cd, cs, stats, stamps) => new UpdateReport(cd, cs, stats, stamps) })
}
implicit def updateStatsFormat: Format[UpdateStats] =
wrap[UpdateStats, (Long,Long,Long)]( us => (us.resolveTime, us.downloadTime, us.downloadSize), { case (rt, dt, ds) => new UpdateStats(rt, dt, ds, true) })

View File

@ -22,7 +22,7 @@ object PomTest extends Build
def checkPom = makePom map { pom =>
val expected = Seq(
("a", Some("compile"), false, None),
("a", None, false, None),
("b", Some("runtime"), true, None),
("c", None, true, None),
("d", Some("test"), false, None),