mirror of https://github.com/sbt/sbt.git
Use lock file to control access to boot directory during update
This commit is contained in:
parent
0a79f1ebbd
commit
92fc01f185
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue