diff --git a/launch/BootConfiguration.scala b/launch/BootConfiguration.scala index 3409d55d9..aed6c77dc 100644 --- a/launch/BootConfiguration.scala +++ b/launch/BootConfiguration.scala @@ -53,10 +53,11 @@ private object BootConfiguration val DefaultIvyConfiguration = "default" - /** The name of the directory within the boot directory to retrieve scala to. */ 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. */ + * containing all jars for the requested version of scala. + */ val scalaRetrievePattern = ScalaDirectoryName + "/[artifact](-[classifier]).[ext]" def artifactType(classifier: String) = @@ -71,19 +72,23 @@ private object BootConfiguration * containing all jars for the requested version of scala. */ def appRetrievePattern(appID: xsbti.ApplicationID) = appDirectoryName(appID, "/") + "(/[component])/[artifact]-[revision](-[classifier]).[ext]" - val ScalaDirPrefix = "scala-" + val ScalaVersionPrefix = "scala-" /** 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 /** The name of the directory in the boot directory to put all jars for the given version of scala in.*/ - def baseDirectoryName(scalaVersion: Option[String]) = scalaVersion match { + def baseDirectoryName(scalaOrg: String, scalaVersion: Option[String]) = scalaVersion match { case None => "other" - case Some(sv) => ScalaDirPrefix + sv + case Some(sv) => (if (scalaOrg == ScalaOrg) "" else scalaOrg + ".") + ScalaVersionPrefix + sv } + def extractScalaVersion(dir: File): Option[String] = { val name = dir.getName - if(name.startsWith(ScalaDirPrefix)) Some(name.substring(ScalaDirPrefix.length)) else None + if(name.contains(ScalaVersionPrefix)) + Some(name.substring(name.lastIndexOf(ScalaVersionPrefix) + ScalaVersionPrefix.length)) + else + None } } private object ProxyProperties diff --git a/launch/Launch.scala b/launch/Launch.scala index c7e6d64ba..3bcc59ccd 100644 --- a/launch/Launch.scala +++ b/launch/Launch.scala @@ -77,17 +77,18 @@ 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, ScalaOrg} 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(version, reason, ScalaOrg) + def getScala(version: String, reason: String, scalaOrg: 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,8 +103,8 @@ 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 jnaHome = appDirectory(new File(bootDirectory, baseDirectoryName(None)), id) + val configuration = makeConfiguration(ScalaOrg, None) + val jnaHome = appDirectory(new File(bootDirectory, baseDirectoryName(ScalaOrg, None)), id) val module = appModule(id, None, false, "jna") def makeLoader(): ClassLoader = { val urls = toURLs(wrapNull(jnaHome.listFiles(JarFilter))) @@ -129,8 +130,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: 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) }) @@ -142,14 +143,14 @@ class Launch private[xsbt](val bootDirectory: File, val lockBoot: Boolean, val i def retrieve() = { val sv = update(app, "") val scalaVersion = strictOr(explicitScalaVersion, sv) - new RetrievedModule(true, app, sv, baseDirs(scalaHome(scalaVersion))) + new RetrievedModule(true, app, sv, baseDirs(scalaHome(ScalaOrg, scalaVersion))) } val retrievedApp = if(forceAppUpdate) retrieve() else - existing(app, explicitScalaVersion, baseDirs) getOrElse retrieve() - + existing(app, ScalaOrg, explicitScalaVersion, baseDirs) getOrElse retrieve() + val scalaVersion = getOrError(strictOr(explicitScalaVersion, retrievedApp.detectedScalaVersion), "No Scala version specified or detected") val scalaProvider = getScala(scalaVersion, "(for " + id.name + ")") @@ -161,8 +162,8 @@ class Launch private[xsbt](val bootDirectory: File, val lockBoot: Boolean, val i else getAppProvider0(id, explicitScalaVersion, true) } - def scalaHome(scalaVersion: Option[String]): File = new File(bootDirectory, baseDirectoryName(scalaVersion)) - def appHome(id: xsbti.ApplicationID, scalaVersion: Option[String]): File = appDirectory(scalaHome(scalaVersion), id) + def scalaHome(scalaOrg: String, scalaVersion: Option[String]): File = new File(bootDirectory, baseDirectoryName(scalaOrg, scalaVersion)) + def appHome(id: xsbti.ApplicationID, scalaVersion: Option[String]): File = appDirectory(scalaHome(ScalaOrg, scalaVersion), id) def checkedAppProvider(id: xsbti.ApplicationID, module: RetrievedModule, scalaProvider: xsbti.ScalaProvider): (Iterable[String], xsbti.AppProvider) = { val p = appProvider(id, module, scalaProvider, appHome(id, Some(scalaProvider.version))) @@ -170,19 +171,19 @@ 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) checkLoader(p.loader, retrieved.definition, TestLoadScalaClasses, p) } - existing(scalaM, Some(scalaVersion), _ => baseDirs) flatMap { mod => + existing(scalaM, scalaOrg, Some(scalaVersion), _ => baseDirs) flatMap { mod => try Some(provider(mod)) catch { case e: Exception => None } } getOrElse { @@ -191,10 +192,10 @@ class Launch private[xsbt](val bootDirectory: File, val lockBoot: Boolean, val i } } - def existing(module: ModuleDefinition, explicitScalaVersion: Option[String], baseDirs: File => List[File]): Option[RetrievedModule] = + def existing(module: ModuleDefinition, scalaOrg: String, explicitScalaVersion: Option[String], baseDirs: File => List[File]): Option[RetrievedModule] = { val filter = new java.io.FileFilter { - val explicitName = explicitScalaVersion.map(sv => baseDirectoryName(Some(sv))) + val explicitName = explicitScalaVersion.map(sv => baseDirectoryName(scalaOrg, Some(sv))) def accept(file: File) = file.isDirectory && explicitName.forall(_ == file.getName) } val retrieved = wrapNull(bootDirectory.listFiles(filter)) flatMap { scalaDir => @@ -219,9 +220,9 @@ 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 scalaHome = new File(bootDirectory, baseDirectoryName(scalaOrg, Some(scalaVersion))) val libDirectory = new File(scalaHome, ScalaDirectoryName) (scalaHome, libDirectory) } @@ -257,13 +258,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(ScalaOrg, 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(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..23816e467 100644 --- a/launch/Update.scala +++ b/launch/Update.scala @@ -33,8 +33,11 @@ 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]) { - def getScalaVersion = scalaVersion match { case Some(sv) => sv; case None => "" } +final class UpdateConfiguration(val bootDirectory: File, val ivyHome: Option[File], val scalaOrg: String, + val scalaVersion: Option[String], val repositories: List[xsbti.Repository], val checksums: List[String]) { + + def getScalaVersion = scalaVersion match { case Some(sv) => sv; case None => "" } + } final class UpdateResult(val success: Boolean, val scalaVersion: Option[String]) @@ -42,7 +45,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, scalaOrg} bootDirectory.mkdirs private def logFile = new File(bootDirectory, UpdateLogName) @@ -127,11 +130,12 @@ final class Update(config: UpdateConfiguration) target match { 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 scalaVersion = getScalaVersion + 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 + "...") + val scalaOrgString = if (scalaOrg != ScalaOrg) " " + scalaOrg else "" + System.out.println("Getting" + scalaOrgString + " Scala " + scalaVersion + " " + reason + "...") case u: UpdateApp => val app = u.id val resolvedName = (app.crossVersioned, scalaVersion) match { @@ -239,7 +243,7 @@ final class Update(config: UpdateConfiguration) val filter = (a: IArtifact) => retrieveType(a.getType) && a.getExtraAttribute("classifier") == null && extraFilter(a) retrieveOptions.setArtifactFilter(new ArtifactFilter(filter)) val scalaV = strictOr(scalaVersion, autoScalaVersion) - retrieveEngine.retrieve(module.getModuleRevisionId, baseDirectoryName(scalaV) + "/" + pattern, retrieveOptions) + retrieveEngine.retrieve(module.getModuleRevisionId, baseDirectoryName(scalaOrg, scalaV) + "/" + pattern, retrieveOptions) } private[this] def notCoreScala(a: IArtifact) = a.getName match { case LibraryModuleName | CompilerModuleName => false diff --git a/launch/interface/src/main/java/xsbti/Launcher.java b/launch/interface/src/main/java/xsbti/Launcher.java index 0593db35d..f3b16214f 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 version, String reason, String scalaOrg); public AppProvider app(ApplicationID id, String version); public ClassLoader topLoader(); public GlobalLock globalLock(); diff --git a/main/Defaults.scala b/main/Defaults.scala index b372fdfd4..1a5fa4e81 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, + scalaOrganization :== ScalaArtifacts.Organization, 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, scalaOrganization, scalaVersion, scalaHome) map { (app, org, version, home) => val launcher = app.provider.scalaProvider.launcher home match { - case None => ScalaInstance(version, launcher) + case None => ScalaInstance(org, version, launcher) case Some(h) => ScalaInstance(h, launcher) } } diff --git a/main/Keys.scala b/main/Keys.scala index d752cd8ff..7e66a1d34 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 scalaOrganization = SettingKey[String]("scala-organization", "Organization/group ID of the Scala used in the project. Default value is 'org.scala-lang'. This is an advanced setting used for clones of the Scala Language. It should be disregarded in standard use cases.", 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..9b687c9b5 100644 --- a/util/classpath/ScalaInstance.scala +++ b/util/classpath/ScalaInstance.scala @@ -21,7 +21,19 @@ final class ScalaInstance(val version: String, val loader: ClassLoader, val libr } object ScalaInstance { + val ScalaOrg = "org.scala-lang" val VersionPrefix = "version " + + def apply(org: String, version: String, launcher: xsbti.Launcher): ScalaInstance = + // Due to incompatibility with previous launchers if scalaOrg has default value revert to an existing method + if (org == ScalaOrg) + apply(version, launcher) + else try { + apply(version, launcher.getScala(version, "", org)) + } catch { + case x: NoSuchMethodError => error("Incompatible version of the xsbti.Launcher interface. Use sbt-0.12.x launcher instead.") + } + /** 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))