mirror of https://github.com/sbt/sbt.git
Adding app-repositories feature to Launcher.
* Added appRepositories method to Launcher interface * Added 'bootOnly' configuration, such that repositories can be used only for boot and not applications. * Added tests to ensure 'bootOnly' and 'mavenCompatible' behave well * Updated documentation on launcher to reflect new options.
This commit is contained in:
parent
e07dc32b7e
commit
4210936163
|
|
@ -58,13 +58,15 @@ class ConfigurationParser
|
|||
case line => readLine(in, ParseLine(line,index) ::: accum, index+1)
|
||||
}
|
||||
private def newReader(file: File) = new InputStreamReader(new FileInputStream(file), "UTF-8")
|
||||
def readRepositoriesConfig(file: File): List[xsbti.Repository] =
|
||||
def readRepositoriesConfig(file: File): List[Repository.Repository] =
|
||||
Using(newReader(file))(readRepositoriesConfig)
|
||||
def readRepositoriesConfig(reader: Reader): List[xsbti.Repository] =
|
||||
def readRepositoriesConfig(reader: Reader): List[Repository.Repository] =
|
||||
Using(new BufferedReader(reader))(readRepositoriesConfig)
|
||||
private def readRepositoriesConfig(in: BufferedReader): List[xsbti.Repository] =
|
||||
def readRepositoriesConfig(s: String): List[Repository.Repository] =
|
||||
Using(new StringReader(s))(readRepositoriesConfig)
|
||||
private def readRepositoriesConfig(in: BufferedReader): List[Repository.Repository] =
|
||||
processRepositoriesConfig(processLines(readLine(in, Nil, 0)))
|
||||
def processRepositoriesConfig(sections: SectionMap): List[xsbti.Repository] =
|
||||
def processRepositoriesConfig(sections: SectionMap): List[Repository.Repository] =
|
||||
processSection(sections, "repositories", getRepositories)._1
|
||||
// section -> configuration instance processing
|
||||
def processSections(sections: SectionMap): LaunchConfiguration =
|
||||
|
|
@ -176,21 +178,32 @@ class ConfigurationParser
|
|||
val app = new Application(org, name, rev, main, components, toBoolean(crossVersioned), classpathExtra)
|
||||
(app, classifiers)
|
||||
}
|
||||
def getRepositories(m: LabelMap): List[xsbti.Repository] =
|
||||
def getRepositories(m: LabelMap): List[Repository.Repository] =
|
||||
{
|
||||
import Repository.{Ivy, Maven, Predefined}
|
||||
val BootOnly = "bootOnly"
|
||||
val MvnComp = "mavenCompatible"
|
||||
m.toList.map {
|
||||
case (key, None) => Predefined(key)
|
||||
case (key, Some(BootOnly)) => Predefined(key, true)
|
||||
case (key, Some(value)) =>
|
||||
val r = trim(substituteVariables(value).split(",",4))
|
||||
val r = trim(substituteVariables(value).split(",",5))
|
||||
val url = try { new URL(r(0)) } catch { case e: MalformedURLException => error("Invalid URL specified for '" + key + "': " + e.getMessage) }
|
||||
// TODO - Clean this up a lot.
|
||||
r.tail match {
|
||||
case both :: "mavenCompatible" :: Nil => Ivy(key, url, both, both, mavenCompatible=true)
|
||||
case ivy :: art :: "mavenCompatible" :: Nil => Ivy(key, url, ivy, art, mavenCompatible=true)
|
||||
case ivy :: art :: Nil => Ivy(key, url, ivy, art, mavenCompatible=false)
|
||||
case both :: Nil => Ivy(key, url, both, both, mavenCompatible=false)
|
||||
case Nil => Maven(key, url)
|
||||
case _ => error("Could not parse %s: %s".format(key, value))
|
||||
case both :: MvnComp :: BootOnly :: Nil => Ivy(key, url, both, both, mavenCompatible=true, bootOnly=true)
|
||||
case both :: BootOnly :: MvnComp :: Nil => Ivy(key, url, both, both, mavenCompatible=true, bootOnly=true)
|
||||
case both :: MvnComp :: Nil => Ivy(key, url, both, both, mavenCompatible=true, bootOnly=false)
|
||||
case both :: BootOnly :: Nil => Ivy(key, url, both, both, mavenCompatible=false, bootOnly=true)
|
||||
case ivy :: art :: MvnComp :: BootOnly :: Nil => Ivy(key, url, ivy, art, mavenCompatible=true, bootOnly=true)
|
||||
case ivy :: art :: BootOnly :: MvnComp :: Nil => Ivy(key, url, ivy, art, mavenCompatible=true, bootOnly=true)
|
||||
case ivy :: art :: MvnComp :: Nil => Ivy(key, url, ivy, art, mavenCompatible=true, bootOnly=false)
|
||||
case ivy :: art :: BootOnly :: Nil => Ivy(key, url, ivy, art, mavenCompatible=false, bootOnly=true)
|
||||
case ivy :: art :: Nil => Ivy(key, url, ivy, art, mavenCompatible=false, bootOnly=false)
|
||||
case BootOnly :: Nil => Maven(key, url, bootOnly=true)
|
||||
case both :: Nil => Ivy(key, url, both, both, mavenCompatible=false, bootOnly=false)
|
||||
case Nil => Maven(key, url)
|
||||
case _ => error("Could not parse %s: %s".format(key, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,8 @@ class Launch private[xsbt](val bootDirectory: File, val lockBoot: Boolean, val i
|
|||
|
||||
def globalLock: xsbti.GlobalLock = Locks
|
||||
def ivyHome = orNull(ivyOptions.ivyHome)
|
||||
def ivyRepositories = repositories.toArray
|
||||
def ivyRepositories = (repositories: List[xsbti.Repository]).toArray
|
||||
def appRepositories = ((repositories filterNot (_.bootOnly)): List[xsbti.Repository]).toArray
|
||||
def isOverrideRepositories: Boolean = ivyOptions.isOverrideRepositories
|
||||
def checksums = checksumsList.toArray[String]
|
||||
|
||||
|
|
@ -278,7 +279,7 @@ class Launch private[xsbt](val bootDirectory: File, val lockBoot: Boolean, val i
|
|||
}
|
||||
object Launcher
|
||||
{
|
||||
def apply(bootDirectory: File, repositories: List[xsbti.Repository]): xsbti.Launcher =
|
||||
def apply(bootDirectory: File, repositories: List[Repository.Repository]): xsbti.Launcher =
|
||||
apply(bootDirectory, IvyOptions(None, Classifiers(Nil, Nil), repositories, BootConfiguration.DefaultChecksums, false))
|
||||
def apply(bootDirectory: File, ivyOptions: IvyOptions): xsbti.Launcher =
|
||||
apply(bootDirectory, ivyOptions, GetLocks.find)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ final case class LaunchConfiguration(scalaVersion: Value[String], ivyConfigurati
|
|||
|
||||
def map(f: File => File) = LaunchConfiguration(scalaVersion, ivyConfiguration.map(f), app.map(f), boot.map(f), logging, appProperties)
|
||||
}
|
||||
final case class IvyOptions(ivyHome: Option[File], classifiers: Classifiers, repositories: List[xsbti.Repository], checksums: List[String], isOverrideRepositories: Boolean)
|
||||
final case class IvyOptions(ivyHome: Option[File], classifiers: Classifiers, repositories: List[Repository.Repository], checksums: List[String], isOverrideRepositories: Boolean)
|
||||
{
|
||||
def map(f: File => File) = IvyOptions(ivyHome.map(f), classifiers, repositories, checksums, isOverrideRepositories)
|
||||
}
|
||||
|
|
@ -70,15 +70,19 @@ object Application
|
|||
|
||||
object Repository
|
||||
{
|
||||
final case class Maven(id: String, url: URL) extends xsbti.MavenRepository
|
||||
final case class Ivy(id: String, url: URL, ivyPattern: String, artifactPattern: String, mavenCompatible: Boolean) extends xsbti.IvyRepository
|
||||
final case class Predefined(id: xsbti.Predefined) extends xsbti.PredefinedRepository
|
||||
trait Repository extends xsbti.Repository {
|
||||
def bootOnly: Boolean
|
||||
}
|
||||
final case class Maven(id: String, url: URL, bootOnly: Boolean = false) extends xsbti.MavenRepository with Repository
|
||||
final case class Ivy(id: String, url: URL, ivyPattern: String, artifactPattern: String, mavenCompatible: Boolean, bootOnly: Boolean = false) extends xsbti.IvyRepository with Repository
|
||||
final case class Predefined(id: xsbti.Predefined, bootOnly: Boolean = false) extends xsbti.PredefinedRepository with Repository
|
||||
object Predefined {
|
||||
def apply(s: String): Predefined = Predefined(xsbti.Predefined.toValue(s))
|
||||
def apply(s: String): Predefined = new Predefined(xsbti.Predefined.toValue(s), false)
|
||||
def apply(s: String, bootOnly: Boolean): Predefined = new Predefined(xsbti.Predefined.toValue(s), bootOnly)
|
||||
}
|
||||
|
||||
def isMavenLocal(repo: xsbti.Repository) = repo match { case p: xsbti.PredefinedRepository => p.id == xsbti.Predefined.MavenLocal; case _ => false }
|
||||
def defaults: List[xsbti.Repository] = xsbti.Predefined.values.map(Predefined.apply).toList
|
||||
def defaults: List[xsbti.Repository] = xsbti.Predefined.values.map(x => Predefined(x, false)).toList
|
||||
}
|
||||
|
||||
final case class Search(tpe: Search.Value, paths: List[File])
|
||||
|
|
|
|||
|
|
@ -38,6 +38,11 @@ public interface Launcher
|
|||
* are the same ones used to load the launcher.
|
||||
*/
|
||||
public xsbti.Repository[] ivyRepositories();
|
||||
/** These are the repositories configured by this launcher
|
||||
* which should be used by the application when resolving
|
||||
* further artifacts.
|
||||
*/
|
||||
public xsbti.Repository[] appRepositories();
|
||||
/** The user has configured the launcher with the only repositories
|
||||
* it wants to use for this applciation.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
package xsbt.boot
|
||||
|
||||
import java.io.{File,InputStream}
|
||||
import java.net.URL
|
||||
import java.util.Properties
|
||||
import xsbti._
|
||||
import org.specs2._
|
||||
import mutable.Specification
|
||||
import sbt.IO.{createDirectory, touch,withTemporaryDirectory}
|
||||
|
||||
object ConfigurationParserTest extends Specification
|
||||
{
|
||||
"Configuration Parser" should {
|
||||
"Correctly parse bootOnly" in {
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| local: bootOnly""".stripMargin,
|
||||
Repository.Predefined("local", true))
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| local""".stripMargin,
|
||||
Repository.Predefined("local", false))
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| id: http://repo1.maven.org""".stripMargin,
|
||||
Repository.Maven("id", new URL("http://repo1.maven.org"), false))
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| id: http://repo1.maven.org, bootOnly""".stripMargin,
|
||||
Repository.Maven("id", new URL("http://repo1.maven.org"), true))
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| id: http://repo1.maven.org, [orgPath]""".stripMargin,
|
||||
Repository.Ivy("id", new URL("http://repo1.maven.org"), "[orgPath]", "[orgPath]", false, false))
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| id: http://repo1.maven.org, [orgPath], mavenCompatible""".stripMargin,
|
||||
Repository.Ivy("id", new URL("http://repo1.maven.org"), "[orgPath]", "[orgPath]", true, false))
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| id: http://repo1.maven.org, [orgPath], mavenCompatible, bootOnly""".stripMargin,
|
||||
Repository.Ivy("id", new URL("http://repo1.maven.org"), "[orgPath]", "[orgPath]", true, true))
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| id: http://repo1.maven.org, [orgPath], bootOnly, mavenCompatible""".stripMargin,
|
||||
Repository.Ivy("id", new URL("http://repo1.maven.org"), "[orgPath]", "[orgPath]", true, true))
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| id: http://repo1.maven.org, [orgPath], bootOnly""".stripMargin,
|
||||
Repository.Ivy("id", new URL("http://repo1.maven.org"), "[orgPath]", "[orgPath]", false, true))
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| id: http://repo1.maven.org, [orgPath], [artPath]""".stripMargin,
|
||||
Repository.Ivy("id", new URL("http://repo1.maven.org"), "[orgPath]", "[artPath]", false, false))
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| id: http://repo1.maven.org, [orgPath], [artPath], bootOnly""".stripMargin,
|
||||
Repository.Ivy("id", new URL("http://repo1.maven.org"), "[orgPath]", "[artPath]", false, true))
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| id: http://repo1.maven.org, [orgPath], [artPath], bootOnly, mavenCompatible""".stripMargin,
|
||||
Repository.Ivy("id", new URL("http://repo1.maven.org"), "[orgPath]", "[artPath]", true, true))
|
||||
|
||||
repoFileContains("""|[repositories]
|
||||
| id: http://repo1.maven.org, [orgPath], [artPath], mavenCompatible, bootOnly""".stripMargin,
|
||||
Repository.Ivy("id", new URL("http://repo1.maven.org"), "[orgPath]", "[artPath]", true, true))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
def repoFileContains(file: String, repo: Repository.Repository) =
|
||||
loadRepoFile(file) must contain(repo)
|
||||
|
||||
def loadRepoFile(file: String) =
|
||||
(new ConfigurationParser) readRepositoriesConfig file
|
||||
}
|
||||
|
|
@ -106,7 +106,7 @@ by the following grammar. ``'nl'`` is a newline or end of file and
|
|||
resources: "resources" ":" `path` ("," `path`)*
|
||||
repository: ( `predefinedRepository` | `customRepository` ) `nl`
|
||||
predefinedRepository: "local" | "maven-local" | "maven-central"
|
||||
customRepository: `label` ":" `url` [ ["," `ivyPattern`] "," `artifactPattern` [", mavenCompatible"]]
|
||||
customRepository: `label` ":" `url` [ ["," `ivyPattern`] ["," `artifactPattern`] [", mavenCompatible"] [", bootOnly"]]
|
||||
property: `label` ":" `propertyDefinition` ("," `propertyDefinition`)*
|
||||
propertyDefinition: `mode` "=" (`set` | `prompt`)
|
||||
mode: "quick" | "new" | "fill"
|
||||
|
|
@ -157,7 +157,7 @@ The default configuration file for sbt looks like:
|
|||
|
||||
[repositories]
|
||||
local
|
||||
typesafe-ivy-releases: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]
|
||||
typesafe-ivy-releases: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext], bootOnly
|
||||
maven-central
|
||||
sonatype-snapshots: https://oss.sonatype.org/content/repositories/snapshots
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue