Add scala.classifiers property to specify classifiers for additional scala artifacts to retrieve.

This commit is contained in:
Mark Harrah 2010-01-10 16:46:15 -05:00
parent 1673a2a3e2
commit 2d9a7b12cc
8 changed files with 48 additions and 28 deletions

View File

@ -35,7 +35,7 @@ The launcher may be configured in one of the following ways in increasing order
The configuration file is line-based, read as UTF-8 encoded, and defined by the following grammer. `'nl'` is a newline or end of file and `'text'` is plain text without newlines or the surrounding delimiters (such as parentheses or square brackets):
{{{
configuration ::= scala app repositories boot log app-properties
scala ::= '[' 'scala' ']' nl version nl
scala ::= '[' 'scala' ']' nl version nl classifiers nl
app ::= '[' 'app' ']' nl org nl name nl version nl components nl class nl cross-versioned nl resources nl
repositories ::= '[' 'repositories' ']' nl (repository nl)*
boot ::= '[' 'boot' ']' nl directory nl bootProperties nl search nl promptCreate nl promptFill nl quickOption nl
@ -55,6 +55,8 @@ configuration ::= scala app repositories boot log app-properties
readProperty ::= 'read' '(' propertyName ')' '[' default ']'
fixedVersion ::= text
classifiers ::= 'classifiers' ':' text (',' text)*
org ::= 'org' ':' text
name ::= 'name' ':' text
class ::= 'class' ':' text
@ -117,7 +119,7 @@ The default configuration file for sbt looks like:
project.initialize: quick=set(true), new=set(true)
}}}
The `scala.version` property specifies the version of Scala used to run the application. The `app.org`, `app.name`, and `app.version` properties specify the organization, module ID, and version of the application, respectively. These are used to resolve and retrieve the application from the repositories listed in `[repositories]`. If `app.cross-versioned` is true, the resolved module ID is `{app.name+'_'+scala.version}`. The paths given in `app.resources` are added to the application's classpath. If the path is relative, it is resolved against the application's working directory.
The `scala.version` property specifies the version of Scala used to run the application. If specified, the `scala.classifiers`property defines classifers such as 'sources' of extra Scala artifacts to retrieve. The `app.org`, `app.name`, and `app.version` properties specify the organization, module ID, and version of the application, respectively. These are used to resolve and retrieve the application from the repositories listed in `[repositories]`. If `app.cross-versioned` is true, the resolved module ID is `{app.name+'_'+scala.version}`. The paths given in `app.resources` are added to the application's classpath. If the path is relative, it is resolved against the application's working directory.
Jars are retrieved to the directory given by `boot.directory`. You can make this an absolute path to be shared by all sbt instances on the machine. You might see messages like:
{{{

View File

@ -23,7 +23,7 @@ private object BootConfiguration
/** The name of the local Ivy repository, which is used when compiling sbt from source.*/
val LocalIvyName = "local"
/** The pattern used for the local Ivy repository, which is used when compiling sbt from source.*/
val LocalPattern = "[organisation]/[module]/[revision]/[type]s/[artifact].[ext]"
val LocalPattern = "[organisation]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]"
/** The artifact pattern used for the local Ivy repository.*/
def LocalArtifactPattern = LocalPattern
/** The Ivy pattern used for the local Ivy repository.*/
@ -51,7 +51,7 @@ private object BootConfiguration
val ScalaDirectoryName = "lib"
/** 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].[ext]"
val scalaRetrievePattern = ScalaDirectoryName + "/[artifact](-[classifier]).[ext]"
/** 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. */

View File

@ -23,16 +23,22 @@ class ConfigurationParser extends NotNull
// section -> configuration instance processing
def processSections(sections: SectionMap): LaunchConfiguration =
{
val (scalaVersion, m1) = processSection(sections, "scala", getScalaVersion)
val ((scalaVersion, scalaClassifiers), m1) = processSection(sections, "scala", getScala)
val (app, 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, app, repositories, boot, logging, properties)
new LaunchConfiguration(scalaVersion, scalaClassifiers, app, repositories, 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
}
def getScalaVersion(m: LabelMap) = check("label", getVersion(m, "Scala version", "scala.version"))
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 =
value.map(version(label)).getOrElse(new Version.Implicit(defaultName, None))

View File

@ -40,7 +40,7 @@ object Launch
}
def explicit(currentDirectory: File, explicit: LaunchConfiguration, arguments: List[String]): Unit =
launch( run(new Launch(explicit.boot.directory, explicit.repositories)) ) (
launch( run(new Launch(explicit.boot.directory, explicit.repositories, explicit.scalaClassifiers)) ) (
new RunConfiguration(explicit.getScalaVersion, explicit.app.toID, currentDirectory, arguments) )
def run(launcher: xsbti.Launcher)(config: RunConfiguration): xsbti.MainResult =
@ -70,7 +70,7 @@ 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]) extends xsbti.Launcher
class Launch(val bootDirectory: File, repositories: List[Repository], scalaClassifiers: List[String]) extends xsbti.Launcher
{
bootDirectory.mkdirs
private val scalaProviders = new Cache[String, ScalaProvider](new ScalaProvider(_))
@ -91,9 +91,10 @@ class Launch(val bootDirectory: File, repositories: List[Repository]) extends xs
lazy val scalaHome = new File(libDirectory, ScalaDirectoryName)
def compilerJar = new File(scalaHome, "scala-compiler.jar")
def libraryJar = new File(scalaHome, "scala-library.jar")
override def classpath = Array(compilerJar, libraryJar)
def baseDirectories = List(scalaHome)
def testLoadClasses = TestLoadScalaClasses
def target = UpdateScala
def target = new UpdateScala(scalaClassifiers)
def failLabel = "Scala " + version
def lockFile = updateLockFile
def extraClasspath = Array[File]()

View File

@ -4,14 +4,14 @@ import Pre._
import java.io.File
import java.net.URL
final case class LaunchConfiguration(scalaVersion: Version, app: Application, repositories: List[Repository], boot: BootSetup, logging: Logging, appProperties: List[AppProperty]) extends NotNull
final case class LaunchConfiguration(scalaVersion: Version, scalaClassifiers: List[String], app: Application, repositories: List[Repository], boot: BootSetup, logging: Logging, appProperties: List[AppProperty]) extends NotNull
{
def getScalaVersion = Version.get(scalaVersion)
def withScalaVersion(newScalaVersion: String) = LaunchConfiguration(new Version.Explicit(newScalaVersion), app, repositories, boot, logging, appProperties)
def withApp(app: Application) = LaunchConfiguration(scalaVersion, app, repositories, boot, logging, appProperties)
def withAppVersion(newAppVersion: String) = LaunchConfiguration(scalaVersion, app.withVersion(new Version.Explicit(newAppVersion)), repositories, boot, logging, appProperties)
def withVersions(newScalaVersion: String, newAppVersion: String) = LaunchConfiguration(new Version.Explicit(newScalaVersion), app.withVersion(new Version.Explicit(newAppVersion)), repositories, boot, logging, appProperties)
def map(f: File => File) = LaunchConfiguration(scalaVersion, app.map(f), repositories, boot.map(f), logging, appProperties)
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)
}
sealed trait Version extends NotNull

View File

@ -22,7 +22,7 @@ trait Provider extends NotNull
def retrieveCorrupt(missing: Iterable[String]): Nothing = fail(": missing " + missing.mkString(", "))
private def fail(extra: String) =
throw new xsbti.RetrieveException(versionString, "Could not retrieve " + failLabel + extra)
private def versionString: String = target match { case UpdateScala => configuration.scalaVersion; case a: UpdateApp => Version.get(a.id.version) }
private def versionString: String = target match { case _: UpdateScala => configuration.scalaVersion; case a: UpdateApp => Version.get(a.id.version) }
val (jars, loader) = Locks(lockFile, new initialize)
private final class initialize extends Callable[(Array[File], ClassLoader)]

View File

@ -12,7 +12,7 @@ import core.LogOptions
import core.cache.DefaultRepositoryCacheManager
import core.event.EventManager
import core.module.id.ModuleRevisionId
import core.module.descriptor.{Configuration => IvyConfiguration, DefaultDependencyDescriptor, DefaultModuleDescriptor, ModuleDescriptor}
import core.module.descriptor.{Configuration => IvyConfiguration, DefaultDependencyArtifactDescriptor, DefaultDependencyDescriptor, DefaultModuleDescriptor, ModuleDescriptor}
import core.report.ResolveReport
import core.resolve.{ResolveEngine, ResolveOptions}
import core.retrieve.{RetrieveEngine, RetrieveOptions}
@ -25,7 +25,7 @@ import util.{DefaultMessageLogger, Message}
import BootConfiguration._
sealed trait UpdateTarget extends NotNull { def tpe: String }
final object UpdateScala extends UpdateTarget { def tpe = "scala" }
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 UpdateConfiguration(val bootDirectory: File, val scalaVersion: String, val repositories: List[Repository]) extends NotNull
@ -81,14 +81,14 @@ final class Update(config: UpdateConfiguration)
// add dependencies based on which target needs updating
target match
{
case UpdateScala =>
addDependency(moduleID, ScalaOrg, CompilerModuleName, scalaVersion, "default")
addDependency(moduleID, ScalaOrg, LibraryModuleName, scalaVersion, "default")
case u: UpdateScala =>
addDependency(moduleID, ScalaOrg, CompilerModuleName, scalaVersion, "default", u.classifiers)
addDependency(moduleID, ScalaOrg, LibraryModuleName, scalaVersion, "default", u.classifiers)
System.out.println("Getting Scala " + scalaVersion + " ...")
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)")
addDependency(moduleID, app.groupID, resolvedName, app.getVersion, "default(compile)", Nil)
System.out.println("Getting " + app.groupID + " " + resolvedName + " " + app.getVersion + " ...")
}
update(moduleID, target)
@ -103,12 +103,23 @@ final class Update(config: UpdateConfiguration)
private def createID(organization: String, name: String, revision: String) =
ModuleRevisionId.newInstance(organization, name, revision)
/** Adds the given dependency to the default configuration of 'moduleID'. */
private def addDependency(moduleID: DefaultModuleDescriptor, organization: String, name: String, revision: String, conf: String)
private def addDependency(moduleID: DefaultModuleDescriptor, organization: String, name: String, revision: String, conf: String, classifiers: List[String])
{
val dep = new DefaultDependencyDescriptor(moduleID, createID(organization, name, revision), false, false, true)
dep.addDependencyConfiguration(DefaultIvyConfiguration, conf)
for(classifier <- classifiers)
addClassifier(dep, name, classifier)
moduleID.addDependency(dep)
}
private def addClassifier(dep: DefaultDependencyDescriptor, name: String, classifier: String)
{
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)
for(conf <- dep.getModuleConfigurations)
dep.addDependencyArtifact(conf, ivyArtifact)
}
private def resolve(eventManager: EventManager, module: ModuleDescriptor)
{
val resolveOptions = new ResolveOptions
@ -143,7 +154,7 @@ final class Update(config: UpdateConfiguration)
val pattern =
target match
{
case UpdateScala => scalaRetrievePattern
case _: UpdateScala => scalaRetrievePattern
case u: UpdateApp => appRetrievePattern(u.id.toID)
}
retrieveEngine.retrieve(module.getModuleRevisionId, baseDirectoryName(scalaVersion) + "/" + pattern, retrieveOptions)

View File

@ -1,6 +1,6 @@
[scala]
# version: read(def.scala.version)
version: 2.7.7
version: read(def.scala.version)
# classifiers: sources
[app]
org: org.scala-tools.sbt
@ -32,7 +32,7 @@
project.name: quick=set(test), new=prompt(Name), fill=prompt(Name)
project.organization: new=prompt(Organization)
project.version: quick=set(1.0), new=prompt(Version)[1.0], fill=prompt(Version)[1.0]
# def.scala.version: quick=set(2.7.7), new=set(2.7.7), fill=set(2.7.7)
def.scala.version: quick=set(2.7.7), new=set(2.7.7), fill=set(2.7.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.6.9), new=prompt(sbt version)[0.6.9], fill=prompt(sbt version)[0.6.9]
project.scratch: quick=set(true)