Use lock file to control access to boot directory during update

This commit is contained in:
Mark Harrah 2009-10-24 13:07:42 -04:00
parent 0a79f1ebbd
commit 92fc01f185
3 changed files with 28 additions and 21 deletions

View File

@ -72,10 +72,12 @@ final class RunConfiguration(val scalaVersion: String, val app: xsbti.Applicatio
import BootConfiguration.{appDirectoryName, baseDirectoryName, ScalaDirectoryName, TestLoadScalaClasses}
class Launch(val bootDirectory: File, repositories: List[Repository]) extends xsbti.Launcher
{
bootDirectory.mkdirs
private val scalaProviders = new Cache[String, ScalaProvider](new ScalaProvider(_))
def getScala(version: String): xsbti.ScalaProvider = scalaProviders(version)
lazy val topLoader = new BootFilteredLoader(getClass.getClassLoader)
val updateLockFile = new File(bootDirectory, "sbt.boot.lock")
def globalLock: xsbti.GlobalLock = Locks
@ -93,6 +95,7 @@ class Launch(val bootDirectory: File, repositories: List[Repository]) extends xs
def testLoadClasses = TestLoadScalaClasses
def target = UpdateScala
def failLabel = "Scala " + version
def lockFile = updateLockFile
def app(id: xsbti.ApplicationID): xsbti.AppProvider = new AppProvider(id)
@ -106,6 +109,7 @@ class Launch(val bootDirectory: File, repositories: List[Repository]) extends xs
def testLoadClasses = List(id.mainClass)
def target = new UpdateApp(Application(id))
def failLabel = id.name + " " + id.version
def lockFile = updateLockFile
lazy val mainClass: Class[T] forSome { type T <: xsbti.AppMain } =
{
@ -121,7 +125,7 @@ class Launch(val bootDirectory: File, repositories: List[Repository]) extends xs
class ComponentProvider(baseDirectory: File) extends xsbti.ComponentProvider
{
def componentLocation(id: String): File = new File(baseDirectory, id)
def component(id: String) = GetJars.wrapNull(componentLocation(id).listFiles).filter(_.isFile)
def component(id: String) = Provider.wrapNull(componentLocation(id).listFiles).filter(_.isFile)
def defineComponent(id: String, files: Array[File]) =
{
val location = componentLocation(id)

View File

@ -8,7 +8,7 @@ import java.util.concurrent.Callable
object Locks extends xsbti.GlobalLock
{
private[this] val locks = new Cache[File, GlobalLock](new GlobalLock(_))
def apply[T](file: File, action: Callable[T]) =
def apply[T](file: File, action: Callable[T]): T =
synchronized { locks(file.getCanonicalFile).withLock(action) }
private[this] class GlobalLock(file: File)

View File

@ -3,6 +3,7 @@ package xsbt.boot
import Pre._
import java.io.{File, FileFilter}
import java.net.{URL, URLClassLoader}
import java.util.concurrent.Callable
trait Provider extends NotNull
{
@ -12,39 +13,41 @@ trait Provider extends NotNull
def target: UpdateTarget
def failLabel: String
def parentLoader: ClassLoader
def lockFile: File
val (jars, loader) =
val (jars, loader) = Locks(lockFile, new initialize)
private final class initialize extends Callable[(Array[File], ClassLoader)]
{
val (existingJars, existingLoader) = createLoader
if(Check.needsUpdate(existingLoader, testLoadClasses))
def call =
{
( new Update(configuration) )(target)
val (newJars, newLoader) = createLoader
Check.failIfMissing(newLoader, testLoadClasses, failLabel)
(newJars, newLoader)
val (existingJars, existingLoader) = createLoader
if(Provider.needsUpdate(existingLoader, testLoadClasses))
{
( new Update(configuration) )(target)
val (newJars, newLoader) = createLoader
Provider.failIfMissing(newLoader, testLoadClasses, failLabel)
(newJars, newLoader)
}
else
(existingJars, existingLoader)
}
def createLoader =
{
val jars = Provider.getJars(baseDirectories)
(jars, new URLClassLoader(jars.map(_.toURI.toURL), parentLoader) )
}
else
(existingJars, existingLoader)
}
def createLoader =
{
val jars = GetJars(baseDirectories)
(jars, new URLClassLoader(jars.map(_.toURI.toURL), parentLoader) )
}
}
object GetJars
object Provider
{
def apply(directories: List[File]): Array[File] = toArray(directories.flatMap(directory => wrapNull(directory.listFiles(JarFilter))))
def getJars(directories: List[File]): Array[File] = toArray(directories.flatMap(directory => wrapNull(directory.listFiles(JarFilter))))
def wrapNull(a: Array[File]): Array[File] = if(a == null) Array() else a
object JarFilter extends FileFilter
{
def accept(file: File) = !file.isDirectory && file.getName.endsWith(".jar")
}
}
object Check
{
def failIfMissing(loader: ClassLoader, classes: Iterable[String], label: String) =
checkTarget(loader, classes, (), missing => error("Could not retrieve " + label + ": missing " + missing.mkString(", ")))
def needsUpdate(loader: ClassLoader, classes: Iterable[String]) = checkTarget(loader, classes, false, x => true)