* new [ivy] section with 'cache-directory' label in launcher configuration to specify the cache directory used by the launcher for Scala and sbt

* new label 'classifiers' accepted under [app] section to retrieve other artifacts for the application
This commit is contained in:
Mark Harrah 2010-05-13 18:38:55 -04:00
parent 10352bc148
commit f70442c5c7
8 changed files with 85 additions and 44 deletions

View File

@ -52,10 +52,18 @@ private object BootConfiguration
/** The Ivy pattern to use for retrieving the scala compiler and library. It is relative to the directory
* containing all jars for the requested version of scala. */
val scalaRetrievePattern = ScalaDirectoryName + "/[artifact](-[classifier]).[ext]"
def artifactType(classifier: String) =
classifier match
{
case "sources" => "src"
case "javadoc" => "doc"
case _ => "jar"
}
/** The Ivy pattern to use for retrieving the application and its dependencies. It is relative to the directory
* containing all jars for the requested version of scala. */
def appRetrievePattern(appID: xsbti.ApplicationID) = appDirectoryName(appID, "/") + "(/[component])/[artifact]-[revision].[ext]"
def appRetrievePattern(appID: xsbti.ApplicationID) = appDirectoryName(appID, "/") + "(/[component])/[artifact]-[revision](-[classifier]).[ext]"
/** The name of the directory to retrieve the application and its dependencies to.*/
def appDirectoryName(appID: xsbti.ApplicationID, sep: String) = appID.groupID + sep + appID.name + sep + appID.version

View File

@ -28,20 +28,22 @@ class ConfigurationParser extends NotNull
def processSections(sections: SectionMap): LaunchConfiguration =
{
val ((scalaVersion, scalaClassifiers), m1) = processSection(sections, "scala", getScala)
val (app, m2) = processSection(m1, "app", getApplication)
val ((app, appClassifiers), m2) = processSection(m1, "app", getApplication)
val (repositories, m3) = processSection(m2, "repositories", getRepositories)
val (boot, m4) = processSection(m3, "boot", getBoot)
val (logging, m5) = processSection(m4, "log", getLogging)
val (properties, m6) = processSection(m5, "app-properties", getAppProperties)
check(m6, "section")
new LaunchConfiguration(scalaVersion, scalaClassifiers, app, repositories, boot, logging, properties)
val (cacheDir, m7) = processSection(m6, "ivy", getIvy)
check(m7, "section")
val classifiers = Classifiers("" :: scalaClassifiers, "" :: appClassifiers)
new LaunchConfiguration(scalaVersion, IvyOptions(cacheDir, classifiers, repositories), app, boot, logging, properties)
}
def getScala(m: LabelMap) =
{
val (scalaVersion, m1) = getVersion(m, "Scala version", "scala.version")
val (scalaClassifiers, m2) = ids(m1, "classifiers", Nil)
check(m2, "label")
(scalaVersion, "" :: scalaClassifiers) // the added "" ensures that the main jars are retrieved
(scalaVersion, scalaClassifiers) // the added "" ensures that the main jars are retrieved
}
def getVersion(m: LabelMap, label: String, defaultName: String): (Version, LabelMap) = process(m, "version", processVersion(label, defaultName))
def processVersion(label: String, defaultName: String)(value: Option[String]): Version =
@ -75,6 +77,12 @@ class ConfigurationParser extends NotNull
def file(map: LabelMap, name: String, default: File): (File, LabelMap) =
(orElse(getOrNone(map, name).map(toFile), default), map - name)
def getIvy(m: LabelMap): Option[File] =
{
val (cacheDir, m1) = file(m, "cache-directory", null) // fix this later
check(m1, "label")
if(cacheDir eq null) None else Some(cacheDir)
}
def getBoot(m: LabelMap): BootSetup =
{
val (dir, m1) = file(m, "directory", toFile("project/boot"))
@ -96,7 +104,7 @@ class ConfigurationParser extends NotNull
case (tpe :: paths, newM) => (Search(tpe, toFiles(paths)), newM)
}
def getApplication(m: LabelMap): Application =
def getApplication(m: LabelMap): (Application, List[String]) =
{
val (org, m1) = id(m, "org", "org.scala-tools.sbt")
val (name, m2) = id(m1, "name", "sbt")
@ -105,9 +113,11 @@ class ConfigurationParser extends NotNull
val (components, m5) = ids(m4, "components", List("default"))
val (crossVersioned, m6) = id(m5, "cross-versioned", "true")
val (resources, m7) = ids(m6, "resources", Nil)
check(m7, "label")
val (classifiers, m8) = ids(m7, "classifiers", Nil)
check(m8, "label")
val classpathExtra = toArray(toFiles(resources))
new Application(org, name, rev, main, components, toBoolean(crossVersioned), classpathExtra)
val app = new Application(org, name, rev, main, components, toBoolean(crossVersioned), classpathExtra)
(app, classifiers)
}
def getRepositories(m: LabelMap): List[Repository] =
{

View File

@ -22,8 +22,9 @@ class Enumeration extends NotNull
Nil
}
}
def value(s: String) = new Value(s)
class Value(override val toString: String) extends NotNull
def value(s: String) = new Value(s, 0)
def value(s: String, i: Int) = new Value(s, i)
class Value(override val toString: String, val id: Int) extends NotNull
def toValue(s: String): Value = elements.find(_.toString == s).getOrElse(error("Expected one of " + elements.mkString(",") + " (got: " + s + ")"))
}

View File

@ -32,7 +32,9 @@ object Launch
}
def initialized(currentDirectory: File, parsed: LaunchConfiguration, arguments: List[String]): Unit =
{
parsed.logging.debug("Parsed configuration: " + parsed)
val resolved = ResolveVersions(parsed)
resolved.logging.debug("Resolved configuration: " + resolved)
explicit(currentDirectory, resolved, arguments)
}
@ -63,8 +65,9 @@ object Launch
final class RunConfiguration(val scalaVersion: String, val app: xsbti.ApplicationID, val workingDirectory: File, val arguments: List[String]) extends NotNull
import BootConfiguration.{appDirectoryName, baseDirectoryName, ScalaDirectoryName, TestLoadScalaClasses}
class Launch(val bootDirectory: File, repositories: List[Repository], scalaClassifiers: List[String]) extends xsbti.Launcher
class Launch private[xsbt](val bootDirectory: File, val ivyOptions: IvyOptions) extends xsbti.Launcher
{
import ivyOptions.{cacheDirectory, classifiers, repositories}
bootDirectory.mkdirs
private val scalaProviders = new Cache[String, ScalaProvider](new ScalaProvider(_))
def getScala(version: String): xsbti.ScalaProvider = scalaProviders(version)
@ -79,7 +82,7 @@ class Launch(val bootDirectory: File, repositories: List[Repository], scalaClass
def launcher: xsbti.Launcher = Launch.this
def parentLoader = topLoader
lazy val configuration = new UpdateConfiguration(bootDirectory, version, repositories)
lazy val configuration = new UpdateConfiguration(bootDirectory, cacheDirectory, version, repositories)
lazy val libDirectory = new File(configuration.bootDirectory, baseDirectoryName(version))
lazy val scalaHome = new File(libDirectory, ScalaDirectoryName)
def compilerJar = new File(scalaHome,CompilerModuleName + ".jar")
@ -87,7 +90,7 @@ class Launch(val bootDirectory: File, repositories: List[Repository], scalaClass
override def classpath = array(compilerJar, libraryJar)
def baseDirectories = List(scalaHome)
def testLoadClasses = TestLoadScalaClasses
def target = new UpdateScala(scalaClassifiers)
def target = new UpdateScala(classifiers.forScala)
def failLabel = "Scala " + version
def lockFile = updateLockFile
def extraClasspath = array()
@ -102,7 +105,7 @@ class Launch(val bootDirectory: File, repositories: List[Repository], scalaClass
def parentLoader = ScalaProvider.this.loader
def baseDirectories = appHome :: id.mainComponents.map(components.componentLocation).toList
def testLoadClasses = List(id.mainClass)
def target = new UpdateApp(Application(id))
def target = new UpdateApp(Application(id), classifiers.app)
def failLabel = id.name + " " + id.version
def lockFile = updateLockFile
def mainClasspath = fullClasspath
@ -121,14 +124,16 @@ class Launch(val bootDirectory: File, repositories: List[Repository], scalaClass
}
object Launcher
{
def apply(bootDirectory: File, repositories: List[Repository], scalaClassifiers: List[String]): xsbti.Launcher =
apply(bootDirectory, repositories, scalaClassifiers, GetLocks.find)
def apply(bootDirectory: File, repositories: List[Repository], scalaClassifiers: List[String], locks: xsbti.GlobalLock): xsbti.Launcher =
new Launch(bootDirectory, repositories, scalaClassifiers) {
def apply(bootDirectory: File, repositories: List[Repository]): xsbti.Launcher =
apply(bootDirectory, IvyOptions(None, Classifiers(Nil, Nil), repositories))
def apply(bootDirectory: File, ivyOptions: IvyOptions): xsbti.Launcher =
apply(bootDirectory, ivyOptions, GetLocks.find)
def apply(bootDirectory: File, ivyOptions: IvyOptions, locks: xsbti.GlobalLock): xsbti.Launcher =
new Launch(bootDirectory, ivyOptions) {
override def globalLock = locks
}
def apply(explicit: LaunchConfiguration): xsbti.Launcher =
new Launch(explicit.boot.directory, explicit.repositories, explicit.scalaClassifiers)
new Launch(explicit.boot.directory, explicit.ivyConfiguration)
def defaultAppProvider(baseDirectory: File): xsbti.AppProvider = getAppProvider(baseDirectory, Configuration.configurationOnClasspath)
def getAppProvider(baseDirectory: File, configLocation: URL): xsbti.AppProvider =
{

View File

@ -7,24 +7,26 @@ import Pre._
import java.io.File
import java.net.URL
final case class LaunchConfiguration(scalaVersion: Version, scalaClassifiers: List[String], app: Application, repositories: List[Repository], boot: BootSetup, logging: Logging, appProperties: List[AppProperty]) extends NotNull
final case class LaunchConfiguration(scalaVersion: Version, ivyConfiguration: IvyOptions, app: Application, boot: BootSetup, logging: Logging, appProperties: List[AppProperty]) extends NotNull
{
def getScalaVersion = Version.get(scalaVersion)
def withScalaVersion(newScalaVersion: String) = LaunchConfiguration(new Version.Explicit(newScalaVersion), scalaClassifiers, app, repositories, boot, logging, appProperties)
def withApp(app: Application) = LaunchConfiguration(scalaVersion, scalaClassifiers, app, repositories, boot, logging, appProperties)
def withAppVersion(newAppVersion: String) = LaunchConfiguration(scalaVersion, scalaClassifiers, app.withVersion(new Version.Explicit(newAppVersion)), repositories, boot, logging, appProperties)
def withVersions(newScalaVersion: String, newAppVersion: String) = LaunchConfiguration(new Version.Explicit(newScalaVersion), scalaClassifiers, app.withVersion(new Version.Explicit(newAppVersion)), repositories, boot, logging, appProperties)
def map(f: File => File) = LaunchConfiguration(scalaVersion, scalaClassifiers, app.map(f), repositories, boot.map(f), logging, appProperties)
def withScalaVersion(newScalaVersion: String) = LaunchConfiguration(new Version.Explicit(newScalaVersion), ivyConfiguration, app, boot, logging, appProperties)
def withApp(app: Application) = LaunchConfiguration(scalaVersion, ivyConfiguration, app, boot, logging, appProperties)
def withAppVersion(newAppVersion: String) = LaunchConfiguration(scalaVersion, ivyConfiguration, app.withVersion(new Version.Explicit(newAppVersion)), boot, logging, appProperties)
def withVersions(newScalaVersion: String, newAppVersion: String) = LaunchConfiguration(new Version.Explicit(newScalaVersion), ivyConfiguration, app.withVersion(new Version.Explicit(newAppVersion)), boot, logging, appProperties)
def map(f: File => File) = LaunchConfiguration(scalaVersion, ivyConfiguration, app.map(f), boot.map(f), logging, appProperties)
}
final case class IvyOptions(cacheDirectory: Option[File], classifiers: Classifiers, repositories: List[Repository]) extends NotNull
final case class Classifiers(forScala: List[String], app: List[String]) extends NotNull
sealed trait Version extends NotNull
object Version
{
final class Explicit(val value: String) extends Version
final class Explicit(val value: String) extends Version { override def toString = value }
final class Implicit(val name: String, val default: Option[String]) extends Version
{
require(isNonEmpty(name), "Name cannot be empty")
require(default.isEmpty || isNonEmpty(default.get), "Default cannot be the empty string")
override def toString = name + (default match { case Some(d) => "[" + d + "]"; case None => "" })
}
object Implicit
@ -96,12 +98,18 @@ final class SetProperty(val value: String) extends PropertyInit
final class PromptProperty(val label: String, val default: Option[String]) extends PropertyInit
final class Logging(level: LogLevel.Value) extends NotNull
{
import LogLevel._
def log(s: => String, at: Value) = if(level.id <= at.id) stream(at).println("[" + at + "] " + s)
def debug(s: => String) = log(s, Debug)
private def stream(at: Value) = if(at == Error) System.err else System.out
}
object LogLevel extends Enumeration
{
val Debug = value("debug")
val Info = value("info")
val Warn = value("warn")
val Error = value("error")
val Debug = value("debug", 0)
val Info = value("info", 1)
val Warn = value("warn", 2)
val Error = value("error", 3)
def apply(s: String): Logging = new Logging(toValue(s))
}

View File

@ -26,16 +26,16 @@ import util.{DefaultMessageLogger, Message, MessageLoggerEngine}
import BootConfiguration._
sealed trait UpdateTarget extends NotNull { def tpe: String }
sealed trait UpdateTarget extends NotNull { def tpe: String; def classifiers: List[String] }
final class UpdateScala(val classifiers: List[String]) extends UpdateTarget { def tpe = "scala" }
final class UpdateApp(val id: Application) extends UpdateTarget { def tpe = "app" }
final class UpdateApp(val id: Application, val classifiers: List[String]) extends UpdateTarget { def tpe = "app" }
final class UpdateConfiguration(val bootDirectory: File, val scalaVersion: String, val repositories: List[Repository]) extends NotNull
final class UpdateConfiguration(val bootDirectory: File, val ivyCacheDirectory: Option[File], val scalaVersion: String, val repositories: List[Repository]) extends NotNull
/** Ensures that the Scala and application jars exist for the given versions or else downloads them.*/
final class Update(config: UpdateConfiguration)
{
import config.{bootDirectory, repositories, scalaVersion}
import config.{bootDirectory, ivyCacheDirectory, repositories, scalaVersion}
bootDirectory.mkdirs
private def logFile = new File(bootDirectory, UpdateLogName)
@ -103,7 +103,7 @@ final class Update(config: UpdateConfiguration)
case u: UpdateApp =>
val app = u.id
val resolvedName = if(app.crossVersioned) app.name + "_" + scalaVersion else app.name
addDependency(moduleID, app.groupID, resolvedName, app.getVersion, "default(compile)", Nil)
addDependency(moduleID, app.groupID, resolvedName, app.getVersion, "default(compile)", u.classifiers)
excludeScala(moduleID)
System.out.println("Getting " + app.groupID + " " + resolvedName + " " + app.getVersion + " ...")
}
@ -132,7 +132,7 @@ final class Update(config: UpdateConfiguration)
val extraMap = new java.util.HashMap[String,String]
if(!classifier.isEmpty)
extraMap.put("e:classifier", classifier)
val ivyArtifact = new DefaultDependencyArtifactDescriptor(dep, name, "jar", "jar", null, extraMap)
val ivyArtifact = new DefaultDependencyArtifactDescriptor(dep, name, artifactType(classifier), "jar", null, extraMap)
for(conf <- dep.getModuleConfigurations)
dep.addDependencyArtifact(conf, ivyArtifact)
}
@ -197,7 +197,7 @@ final class Update(config: UpdateConfiguration)
if(repositories.isEmpty) error("No repositories defined.")
for(repo <- repositories if includeRepo(repo))
newDefault.add(toIvyRepository(settings, repo))
onDefaultRepositoryCacheManager(settings)(configureCache)
configureCache(settings, ivyCacheDirectory)
settings.addResolver(newDefault)
settings.setDefaultResolver(newDefault.getName)
}
@ -207,11 +207,16 @@ final class Update(config: UpdateConfiguration)
private[this] val Snapshot = "-SNAPSHOT"
private[this] val ChangingPattern = ".*" + Snapshot
private[this] val ChangingMatcher = PatternMatcher.REGEXP
private def configureCache(manager: DefaultRepositoryCacheManager)
private def configureCache(settings: IvySettings, dir: Option[File])
{
val cacheDir = dir.getOrElse(settings.getDefaultRepositoryCacheBasedir())
val manager = new DefaultRepositoryCacheManager("default-cache", settings, cacheDir)
manager.setUseOrigin(true)
manager.setChangingMatcher(ChangingMatcher)
manager.setChangingPattern(ChangingPattern)
settings.addRepositoryCacheManager(manager)
settings.setDefaultRepositoryCacheManager(manager)
dir.foreach(dir => settings.setDefaultResolutionCacheBasedir(dir.getAbsolutePath))
}
private def toIvyRepository(settings: IvySettings, repo: Repository) =
{
@ -280,7 +285,7 @@ final class Update(config: UpdateConfiguration)
if(m.matches)
{
val base = List(1,2,3).map(m.group).mkString(".")
val pattern = "http://scala-tools.org/repo-snapshots/[organization]/[module]/" + base + "-SNAPSHOT/[artifact]-[revision].[ext]"
val pattern = "http://scala-tools.org/repo-snapshots/[organization]/[module]/" + base + "-SNAPSHOT/[artifact]-[revision](-[classifier]).[ext]"
val resolver = new URLResolver
resolver.setName("Scala Tools Snapshots")

View File

@ -1,6 +1,6 @@
[scala]
version: 2.7.7
# classifiers: sources
#classifiers: sources, javadoc
[app]
org: org.scala-tools.sbt
@ -9,6 +9,7 @@
class: sbt.xMain
components: xsbti
cross-versioned: true
#classifiers: sources, javadoc
[repositories]
local
@ -35,4 +36,7 @@
build.scala.versions: quick=set(2.7.7), new=prompt(Scala version)[2.7.7], fill=prompt(Scala version)[2.7.7]
sbt.version: quick=set(0.7.3), new=prompt(sbt version)[0.7.3], fill=prompt(sbt version)[0.7.3]
project.scratch: quick=set(true)
project.initialize: quick=set(true), new=set(true)
project.initialize: quick=set(true), new=set(true)
#[ivy]
# cache-directory: /home/user/.ivy2/cache2

View File

@ -68,7 +68,7 @@ object LaunchTest
def testRepositories = List(Local, ScalaToolsReleases, ScalaToolsSnapshots).map(Repository.Predefined.apply)
def withLauncher[T](f: xsbti.Launcher => T): T =
FileUtilities.withTemporaryDirectory { bootDirectory =>
f(Launcher(bootDirectory, testRepositories, Nil))
f(Launcher(bootDirectory, testRepositories))
}
def mapScalaVersion(versionNumber: String) = scalaVersionMap.find(_._2 == versionNumber).getOrElse {