package sbt
import java.io.File
import java.net.URL
import org.apache.ivy.{core, plugins, util}
import core.cache.{ArtifactOrigin, CacheDownloadOptions, DefaultRepositoryCacheManager}
import core.module.descriptor.{Artifact => IvyArtifact, DefaultArtifact}
import plugins.repository.file.{FileRepository=>IvyFileRepository, FileResource}
import plugins.repository.{ArtifactResourceResolver, Resource, ResourceDownloader}
import plugins.resolver.util.ResolvedResource
import util.FileUtil
class NotInCache(val id: ModuleID, cause: Throwable)
extends RuntimeException(NotInCache(id, cause), cause)
{
def this(id: ModuleID) = this(id, null)
}
private object NotInCache
{
def apply(id: ModuleID, cause: Throwable) =
{
val postfix = if(cause == null) "" else (": " +cause.toString)
"File for " + id + " not in cache" + postfix
}
}
class IvyCache(val ivyHome: Option[File])
{
def lockFile = new File(ivyHome getOrElse Path.userHome, ".sbt.cache.lock")
def cacheJar(moduleID: ModuleID, file: File, lock: Option[xsbti.GlobalLock], log: Logger)
{
val artifact = defaultArtifact(moduleID)
val resolved = new ResolvedResource(new FileResource(new IvyFileRepository, file), moduleID.revision)
withDefaultCache(lock, log) { cache =>
val resolver = new ArtifactResourceResolver { def resolve(artifact: IvyArtifact) = resolved }
cache.download(artifact, resolver, new FileDownloader, new CacheDownloadOptions)
}
}
def clearCachedJar(id: ModuleID, lock: Option[xsbti.GlobalLock], log: Logger)
{
try { withCachedJar(id, lock, log)(_.delete) }
catch { case e: Exception => log.debug("Error cleaning cached jar: " + e.toString) }
}
def retrieveCachedJar(id: ModuleID, toDirectory: File, lock: Option[xsbti.GlobalLock], log: Logger) =
withCachedJar(id, lock, log) { cachedFile =>
val copyTo = new File(toDirectory, cachedFile.getName)
FileUtil.copy(cachedFile, copyTo, null)
copyTo
}
def withCachedJar[T](id: ModuleID, lock: Option[xsbti.GlobalLock], log: Logger)(f: File => T): T =
{
val cachedFile =
try
{
withDefaultCache(lock, log) { cache =>
val artifact = defaultArtifact(id)
cache.getArchiveFileInCache(artifact, unknownOrigin(artifact))
}
}
catch { case e: Exception => throw new NotInCache(id, e) }
if(cachedFile.exists) f(cachedFile) else throw new NotInCache(id)
}
def withDefaultCache[T](lock: Option[xsbti.GlobalLock], log: Logger)(f: DefaultRepositoryCacheManager => T): T =
{
val (ivy, local) = basicLocalIvy(lock, log)
ivy.withIvy(log) { ivy =>
val cache = ivy.getSettings.getDefaultRepositoryCacheManager.asInstanceOf[DefaultRepositoryCacheManager]
cache.setUseOrigin(false)
f(cache)
}
}
private def unknownOrigin(artifact: IvyArtifact) = ArtifactOrigin.unkwnown(artifact)
private def basicLocalIvy(lock: Option[xsbti.GlobalLock], log: Logger) =
{
val local = Resolver.defaultLocal
val paths = new IvyPaths(new File("."), ivyHome)
val conf = new InlineIvyConfiguration(paths, Seq(local), Nil, Nil, false, lock, IvySbt.DefaultChecksums, log)
(new IvySbt(conf), local)
}
private def defaultArtifact(moduleID: ModuleID): IvyArtifact =
new DefaultArtifact(IvySbt.toID(moduleID), null, moduleID.name, "jar", "jar")
}
private class FileDownloader extends ResourceDownloader with NotNull
{
def download(artifact: IvyArtifact, resource: Resource, dest: File)
{
if(dest.exists()) dest.delete()
val part = new File(dest.getAbsolutePath + ".part")
FileUtil.copy(resource.openStream, part, null)
if(!part.renameTo(dest))
error("Could not move temporary file " + part + " to final location " + dest)
}
}