diff --git a/launch/BootConfiguration.scala b/launch/BootConfiguration.scala index 3409d55d9..247475cca 100644 --- a/launch/BootConfiguration.scala +++ b/launch/BootConfiguration.scala @@ -53,11 +53,22 @@ private object BootConfiguration val DefaultIvyConfiguration = "default" - /** The name of the directory within the boot directory to retrieve scala to. */ - val ScalaDirectoryName = "lib" + private val ScalaDirectoryName = "lib" + + /** The name of the directory within the boot directory to retrieve scala to. + * scalaOrg is appended if non-standard scala is used. + * + * The reason for this inconsistency is backward compatiblity and + * relatively infrequent use of non-standard scalaOrg */ + def scalaDirectoryName(scalaOrg: String) = scalaOrg match { + case ScalaOrg => ScalaDirectoryName + case _ => ScalaDirectoryName + "-" + scalaOrg + } + /** 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]" + * containing all jars for the requested version of scala. + */ + def scalaRetrievePattern(scalaOrg: String) = scalaDirectoryName(scalaOrg) + "/[artifact](-[classifier]).[ext]" def artifactType(classifier: String) = classifier match @@ -80,6 +91,7 @@ private object BootConfiguration case None => "other" case Some(sv) => ScalaDirPrefix + sv } + def extractScalaVersion(dir: File): Option[String] = { val name = dir.getName diff --git a/launch/Launch.scala b/launch/Launch.scala index c7e6d64ba..b1385586f 100644 --- a/launch/Launch.scala +++ b/launch/Launch.scala @@ -77,18 +77,17 @@ object Launch } final class RunConfiguration(val scalaVersion: Option[String], val app: xsbti.ApplicationID, val workingDirectory: File, val arguments: List[String]) -import BootConfiguration.{appDirectoryName, baseDirectoryName, extractScalaVersion, ScalaDirectoryName, TestLoadScalaClasses} +import BootConfiguration.{appDirectoryName, baseDirectoryName, extractScalaVersion, scalaDirectoryName, TestLoadScalaClasses} class Launch private[xsbt](val bootDirectory: File, val lockBoot: Boolean, val ivyOptions: IvyOptions) extends xsbti.Launcher { import ivyOptions.{checksums => checksumsList, classifiers, repositories} bootDirectory.mkdirs - private val scalaProviders = new Cache[String, String, xsbti.ScalaProvider](getScalaProvider(_,_)) + private val scalaProviders = new Cache[(String, String), String, xsbti.ScalaProvider]((x, y) => getScalaProvider(x._1, x._2, y)) def getScala(version: String): xsbti.ScalaProvider = getScala(version, "") - def getScala(version: String, reason: String): xsbti.ScalaProvider = scalaProviders(version, reason) + def getScala(version: String, reason: String): xsbti.ScalaProvider = getScala(BootConfiguration.ScalaOrg, version, reason) + def getScala(scalaOrg: String, version: String, reason: String) = scalaProviders((scalaOrg, version), reason) def app(id: xsbti.ApplicationID, version: String): xsbti.AppProvider = app(id, Option(version)) - def app(id: xsbti.ApplicationID, scalaVersion: Option[String]): xsbti.AppProvider = - getAppProvider(id, scalaVersion, false) - + def app(id: xsbti.ApplicationID, scalaVersion: Option[String]): xsbti.AppProvider = getAppProvider(id, scalaVersion, false) val bootLoader = new BootFilteredLoader(getClass.getClassLoader) val topLoader = jnaLoader(bootLoader) @@ -102,7 +101,7 @@ class Launch private[xsbt](val bootDirectory: File, val lockBoot: Boolean, val i def jnaLoader(parent: ClassLoader): ClassLoader = { val id = AppID("net.java.dev.jna", "jna", "3.2.3", "", toArray(Nil), false, array()) - val configuration = makeConfiguration(None) + val configuration = makeConfiguration(None, None) val jnaHome = appDirectory(new File(bootDirectory, baseDirectoryName(None)), id) val module = appModule(id, None, false, "jna") def makeLoader(): ClassLoader = { @@ -129,8 +128,8 @@ class Launch private[xsbt](val bootDirectory: File, val lockBoot: Boolean, val i module.retrieveCorrupt(missing) } - private[this] def makeConfiguration(version: Option[String]): UpdateConfiguration = - new UpdateConfiguration(bootDirectory, ivyOptions.ivyHome, version, repositories, checksumsList) + private[this] def makeConfiguration(scalaOrg: Option[String], version: Option[String]): UpdateConfiguration = + new UpdateConfiguration(bootDirectory, ivyOptions.ivyHome, scalaOrg, version, repositories, checksumsList) final def getAppProvider(id: xsbti.ApplicationID, explicitScalaVersion: Option[String], forceAppUpdate: Boolean): xsbti.AppProvider = locked(new Callable[xsbti.AppProvider] { def call = getAppProvider0(id, explicitScalaVersion, forceAppUpdate) }) @@ -149,7 +148,7 @@ class Launch private[xsbt](val bootDirectory: File, val lockBoot: Boolean, val i retrieve() else existing(app, explicitScalaVersion, baseDirs) getOrElse retrieve() - + val scalaVersion = getOrError(strictOr(explicitScalaVersion, retrievedApp.detectedScalaVersion), "No Scala version specified or detected") val scalaProvider = getScala(scalaVersion, "(for " + id.name + ")") @@ -170,13 +169,13 @@ class Launch private[xsbt](val bootDirectory: File, val lockBoot: Boolean, val i (missing, p) } private[this] def locked[T](c: Callable[T]): T = Locks(orNull(updateLockFile), c) - def getScalaProvider(scalaVersion: String, reason: String): xsbti.ScalaProvider = - locked(new Callable[xsbti.ScalaProvider] { def call = getScalaProvider0(scalaVersion, reason) }) + def getScalaProvider(scalaOrg: String, scalaVersion: String, reason: String): xsbti.ScalaProvider = + locked(new Callable[xsbti.ScalaProvider] { def call = getScalaProvider0(scalaOrg, scalaVersion, reason) }) - private[this] final def getScalaProvider0(scalaVersion: String, reason: String) = + private[this] final def getScalaProvider0(scalaOrg: String, scalaVersion: String, reason: String) = { - val scalaM = scalaModule(scalaVersion) - val (scalaHome, lib) = scalaDirs(scalaM, scalaVersion) + val scalaM = scalaModule(scalaOrg, scalaVersion) + val (scalaHome, lib) = scalaDirs(scalaM, scalaOrg, scalaVersion) val baseDirs = lib :: Nil def provider(retrieved: RetrievedModule): xsbti.ScalaProvider = { val p = scalaProvider(scalaVersion, retrieved, topLoader, lib) @@ -219,10 +218,10 @@ class Launch private[xsbt](val bootDirectory: File, val lockBoot: Boolean, val i def appDirectory(base: File, id: xsbti.ApplicationID): File = new File(base, appDirectoryName(id, File.separator)) - def scalaDirs(module: ModuleDefinition, scalaVersion: String): (File, File) = + def scalaDirs(module: ModuleDefinition, scalaOrg: String, scalaVersion: String): (File, File) = { val scalaHome = new File(bootDirectory, baseDirectoryName(Some(scalaVersion))) - val libDirectory = new File(scalaHome, ScalaDirectoryName) + val libDirectory = new File(scalaHome, scalaDirectoryName(scalaOrg)) (scalaHome, libDirectory) } @@ -257,13 +256,13 @@ class Launch private[xsbt](val bootDirectory: File, val lockBoot: Boolean, val i } def appModule(id: xsbti.ApplicationID, scalaVersion: Option[String], getClassifiers: Boolean, tpe: String): ModuleDefinition = new ModuleDefinition( - configuration = makeConfiguration(scalaVersion), + configuration = makeConfiguration(None, scalaVersion), target = new UpdateApp(Application(id), if(getClassifiers) Value.get(classifiers.app) else Nil, tpe), failLabel = id.name + " " + id.version, extraClasspath = id.classpathExtra ) - def scalaModule(version: String): ModuleDefinition = new ModuleDefinition( - configuration = makeConfiguration(Some(version)), + def scalaModule(org: String, version: String): ModuleDefinition = new ModuleDefinition( + configuration = makeConfiguration(Some(org), Some(version)), target = new UpdateScala(Value.get(classifiers.forScala)), failLabel = "Scala " + version, extraClasspath = array() diff --git a/launch/LaunchConfiguration.scala b/launch/LaunchConfiguration.scala index d1e150d1a..625ad630d 100644 --- a/launch/LaunchConfiguration.scala +++ b/launch/LaunchConfiguration.scala @@ -15,12 +15,14 @@ final case class LaunchConfiguration(scalaVersion: Value[String], ivyConfigurati val sv = Value.get(scalaVersion) if(sv == "auto") None else Some(sv) } + def withScalaVersion(newScalaVersion: String) = LaunchConfiguration(new 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 Explicit(newAppVersion)), boot, logging, appProperties) // TODO: withExplicit def withVersions(newScalaVersion: String, newAppVersion: String, classifiers0: Classifiers) = LaunchConfiguration(new Explicit(newScalaVersion), ivyConfiguration.copy(classifiers = classifiers0), app.withVersion(new 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(ivyHome: Option[File], classifiers: Classifiers, repositories: List[xsbti.Repository], checksums: List[String]) diff --git a/launch/Update.scala b/launch/Update.scala index df20f6d36..8844e86e9 100644 --- a/launch/Update.scala +++ b/launch/Update.scala @@ -33,8 +33,13 @@ sealed trait UpdateTarget { 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, val classifiers: List[String], val tpe: String) extends UpdateTarget -final class UpdateConfiguration(val bootDirectory: File, val ivyHome: Option[File], val scalaVersion: Option[String], val repositories: List[xsbti.Repository], val checksums: List[String]) { +final class UpdateConfiguration(val bootDirectory: File, val ivyHome: Option[File], val scalaOrg: Option[String], + val scalaVersion: Option[String], val repositories: List[xsbti.Repository], val checksums: List[String]) { + def getScalaVersion = scalaVersion match { case Some(sv) => sv; case None => "" } + + def getScalaOrg = scalaOrg match { case Some(so) => so; case None => ScalaOrg } + } final class UpdateResult(val success: Boolean, val scalaVersion: Option[String]) @@ -42,7 +47,7 @@ final class UpdateResult(val success: Boolean, val scalaVersion: Option[String]) /** Ensures that the Scala and application jars exist for the given versions or else downloads them.*/ final class Update(config: UpdateConfiguration) { - import config.{bootDirectory, checksums, getScalaVersion, ivyHome, repositories, scalaVersion} + import config.{bootDirectory, checksums, getScalaVersion, ivyHome, repositories, scalaVersion, getScalaOrg} bootDirectory.mkdirs private def logFile = new File(bootDirectory, UpdateLogName) @@ -128,8 +133,9 @@ final class Update(config: UpdateConfiguration) { case u: UpdateScala => val scalaVersion = getScalaVersion - addDependency(moduleID, ScalaOrg, CompilerModuleName, scalaVersion, "default;optional(default)", u.classifiers) - addDependency(moduleID, ScalaOrg, LibraryModuleName, scalaVersion, "default", u.classifiers) + val scalaOrg = getScalaOrg + addDependency(moduleID, scalaOrg, CompilerModuleName, scalaVersion, "default;optional(default)", u.classifiers) + addDependency(moduleID, scalaOrg, LibraryModuleName, scalaVersion, "default", u.classifiers) excludeJUnit(moduleID) System.out.println("Getting Scala " + scalaVersion + " " + reason + "...") case u: UpdateApp => @@ -233,7 +239,7 @@ final class Update(config: UpdateConfiguration) val (pattern, extraFilter) = target match { - case _: UpdateScala => (scalaRetrievePattern, const(true)) + case _: UpdateScala => (scalaRetrievePattern(getScalaOrg), const(true)) case u: UpdateApp => (appRetrievePattern(u.id.toID), notCoreScala _) } val filter = (a: IArtifact) => retrieveType(a.getType) && a.getExtraAttribute("classifier") == null && extraFilter(a) diff --git a/launch/interface/src/main/java/xsbti/Launcher.java b/launch/interface/src/main/java/xsbti/Launcher.java index 0593db35d..b21859135 100644 --- a/launch/interface/src/main/java/xsbti/Launcher.java +++ b/launch/interface/src/main/java/xsbti/Launcher.java @@ -7,6 +7,7 @@ public interface Launcher public static final int InterfaceVersion = 1; public ScalaProvider getScala(String version); public ScalaProvider getScala(String version, String reason); + public ScalaProvider getScala(String scalaOrg, String version, String reason); public AppProvider app(ApplicationID id, String version); public ClassLoader topLoader(); public GlobalLock globalLock(); diff --git a/main/Defaults.scala b/main/Defaults.scala index 7d835ddd2..5216c63d6 100755 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -52,6 +52,7 @@ object Defaults extends BuildCommon )) def globalCore: Seq[Setting[_]] = inScope(GlobalScope)(defaultTestTasks(test) ++ defaultTestTasks(testOnly) ++ defaultTestTasks(testQuick) ++ Seq( crossVersion :== CrossVersion.Disabled, + scalaOrg :== "org.scala-lang", buildDependencies <<= buildDependencies or Classpaths.constructBuildDependencies, taskTemporaryDirectory := IO.createTemporaryDirectory, onComplete <<= taskTemporaryDirectory { dir => () => IO.delete(dir); IO.createDirectory(dir) }, @@ -264,10 +265,10 @@ object Defaults extends BuildCommon } } } - def scalaInstanceSetting = (appConfiguration, scalaVersion, scalaHome) map { (app, version, home) => + def scalaInstanceSetting = (appConfiguration, scalaOrg, scalaVersion, scalaHome) map { (app, scalaOrg, version, home) => val launcher = app.provider.scalaProvider.launcher home match { - case None => ScalaInstance(version, launcher) + case None => ScalaInstance(scalaOrg, version, launcher) case Some(h) => ScalaInstance(h, launcher) } } diff --git a/main/Keys.scala b/main/Keys.scala index 52a79757c..007f96655 100644 --- a/main/Keys.scala +++ b/main/Keys.scala @@ -135,6 +135,7 @@ object Keys val compileInputs = TaskKey[Compiler.Inputs]("compile-inputs", "Collects all inputs needed for compilation.", DTask) val scalaHome = SettingKey[Option[File]]("scala-home", "If Some, defines the local Scala installation to use for compilation, running, and testing.", ASetting) val scalaInstance = TaskKey[ScalaInstance]("scala-instance", "Defines the Scala instance to use for compilation, running, and testing.", DTask) + val scalaOrg = SettingKey[String]("scala-org", "Artifact id of Scala scala used in the project.", CSetting) val scalaVersion = SettingKey[String]("scala-version", "The version of Scala used for building.", APlusSetting) val scalaBinaryVersion = SettingKey[String]("scala-binary-version", "The Scala version substring describing binary compatibility.", BPlusSetting) val crossScalaVersions = SettingKey[Seq[String]]("cross-scala-versions", "The versions of Scala used when cross-building.", BPlusSetting) diff --git a/util/classpath/ScalaInstance.scala b/util/classpath/ScalaInstance.scala index de6cabc24..b7594232d 100644 --- a/util/classpath/ScalaInstance.scala +++ b/util/classpath/ScalaInstance.scala @@ -22,6 +22,9 @@ final class ScalaInstance(val version: String, val loader: ClassLoader, val libr object ScalaInstance { val VersionPrefix = "version " + + def apply(org: String, version: String, launcher: xsbti.Launcher): ScalaInstance = + apply(version, launcher.getScala(org, version, "")) /** Creates a ScalaInstance using the given provider to obtain the jars and loader.*/ def apply(version: String, launcher: xsbti.Launcher): ScalaInstance = apply(version, launcher.getScala(version))