mirror of https://github.com/sbt/sbt.git
Turned sbt launcher into a general Scala application launcher as described in launch.specification
This commit is contained in:
parent
b6b7fe2f9b
commit
abd06a17c5
|
|
@ -1,7 +1,6 @@
|
|||
package xsbt
|
||||
|
||||
import java.io.File
|
||||
import xsbti.Versions
|
||||
|
||||
/** A component manager provides access to the pieces of xsbt that are distributed as components.
|
||||
* There are two types of components. The first type is compiled subproject jars with their dependencies.
|
||||
|
|
@ -12,30 +11,13 @@ import xsbti.Versions
|
|||
* This is used for compiled source jars so that the compilation need not be repeated for other projects on the same
|
||||
* machine.
|
||||
*/
|
||||
class ComponentManager(baseDirectory: File, log: IvyLogger) extends NotNull
|
||||
class ComponentManager(provider: xsbti.ComponentProvider, log: IvyLogger) extends NotNull
|
||||
{
|
||||
/** Get the location where files for component 'id' are stored. This method does not ensure that the component is retrieved from the
|
||||
* local repository. By default, the location returned is is baseDirectory / id.*/
|
||||
def location(id: String): File = new File(baseDirectory, id)
|
||||
/** Get the location where files for component 'id' are stored. If the component has not yet been retrieved from the local repository,
|
||||
* it is retrieved first. */
|
||||
def directory(id: String): File =
|
||||
{
|
||||
val dir = location(id)
|
||||
if(!dir.exists)
|
||||
update(id)
|
||||
dir
|
||||
}
|
||||
// get the contents of the given directory, wrapping a null result in an empty list.
|
||||
private def contents(dir: File): Seq[File] =
|
||||
{
|
||||
val fs = dir.listFiles
|
||||
if(fs == null) Nil else fs
|
||||
}
|
||||
/** Get all of the files for component 'id', throwing an exception if no files exist for the component. */
|
||||
def files(id: String): Iterable[File] =
|
||||
{
|
||||
val fs = contents(directory(id))
|
||||
val existing = provider.component(id)
|
||||
val fs = if(existing.isEmpty) { update(id); provider.component(id) } else existing
|
||||
if(!fs.isEmpty) fs else invalid("Could not find required component '" + id + "'")
|
||||
}
|
||||
/** Get the file for component 'id', throwing an exception if no files or multiple files exist for the component. */
|
||||
|
|
@ -47,12 +29,13 @@ class ComponentManager(baseDirectory: File, log: IvyLogger) extends NotNull
|
|||
private def invalid(msg: String) = throw new InvalidComponent(msg)
|
||||
private def invalid(e: NotInCache) = throw new InvalidComponent(e.getMessage, e)
|
||||
|
||||
def define(id: String, files: Iterable[File]) = provider.defineComponent(id, files.toSeq.toArray)
|
||||
/** Retrieve the file for component 'id' from the local repository. */
|
||||
def update(id: String): Unit =
|
||||
try { IvyCache.retrieveCachedJar(sbtModuleID(id), location(id), log) }
|
||||
try { IvyCache.withCachedJar(sbtModuleID(id), log)(jar => define(id, Seq(jar)) ) }
|
||||
catch { case e: NotInCache => invalid(e) }
|
||||
|
||||
def sbtModuleID(id: String) = ModuleID("org.scala-tools.sbt", id, Versions.Sbt)
|
||||
def sbtModuleID(id: String) = ModuleID("org.scala-tools.sbt", id, xsbti.Versions.Sbt)
|
||||
/** Install the files for component 'id' to the local repository. This is usually used after writing files to the directory returned by 'location'. */
|
||||
def cache(id: String): Unit = IvyCache.cacheJar(sbtModuleID(id), file(id), log)
|
||||
def clearCache(id: String): Unit = IvyCache.clearCachedJar(sbtModuleID(id), log)
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ private object ConvertResolver
|
|||
setKeyFilePassword(password)
|
||||
}
|
||||
}
|
||||
private def initializePatterns(resolver: AbstractPatternsBasedResolver, patterns: RepositoryHelpers.Patterns)
|
||||
private def initializePatterns(resolver: AbstractPatternsBasedResolver, patterns: Patterns)
|
||||
{
|
||||
resolver.setM2compatible(patterns.isMavenCompatible)
|
||||
patterns.ivyPatterns.foreach(resolver.addIvyPattern)
|
||||
|
|
|
|||
|
|
@ -17,8 +17,10 @@ import plugins.repository.url.URLResource
|
|||
private[xsbt] object CustomXmlParser extends XmlModuleDescriptorParser with NotNull
|
||||
{
|
||||
import XmlModuleDescriptorParser.Parser
|
||||
class CustomParser(settings: IvySettings) extends Parser(CustomXmlParser, settings) with NotNull
|
||||
class CustomParser(settings: IvySettings, defaultConfig: Option[String]) extends Parser(CustomXmlParser, settings) with NotNull
|
||||
{
|
||||
defaultConfig.foreach(x => setDefaultConfMapping("*->default(compile)"))
|
||||
|
||||
def setSource(url: URL) =
|
||||
{
|
||||
super.setResource(new URLResource(url))
|
||||
|
|
@ -29,7 +31,6 @@ private[xsbt] object CustomXmlParser extends XmlModuleDescriptorParser with NotN
|
|||
override def setResource(res: Resource) {}
|
||||
override def setMd(md: DefaultModuleDescriptor) = super.setMd(md)
|
||||
override def parseDepsConfs(confs: String, dd: DefaultDependencyDescriptor) = super.parseDepsConfs(confs, dd)
|
||||
override def getDefaultConf = super.getDefaultConf
|
||||
override def setDefaultConf(conf: String) = super.setDefaultConf(conf)
|
||||
override def getDefaultConf = defaultConfig.getOrElse(super.getDefaultConf)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import Artifact.{defaultExtension, defaultType}
|
|||
import java.io.File
|
||||
|
||||
import org.apache.ivy.{core, plugins, util, Ivy}
|
||||
import core.IvyPatternHelper
|
||||
import core.cache.DefaultRepositoryCacheManager
|
||||
import core.module.descriptor.{DefaultArtifact, DefaultDependencyArtifactDescriptor, MDArtifact}
|
||||
import core.module.descriptor.{DefaultDependencyDescriptor, DefaultModuleDescriptor, ModuleDescriptor}
|
||||
|
|
@ -74,7 +75,7 @@ final class IvySbt(configuration: IvyConfiguration)
|
|||
finally { ivy.popContext() }
|
||||
}
|
||||
|
||||
final class Module(val moduleConfiguration: ModuleConfiguration) extends NotNull
|
||||
final class Module(val moduleSettings: ModuleSettings) extends NotNull
|
||||
{
|
||||
def logger = configuration.log
|
||||
def withModule[T](f: (Ivy,DefaultModuleDescriptor,String) => T): T =
|
||||
|
|
@ -83,14 +84,14 @@ final class IvySbt(configuration: IvyConfiguration)
|
|||
private lazy val (moduleDescriptor: DefaultModuleDescriptor, defaultConfig: String) =
|
||||
{
|
||||
val (baseModule, baseConfiguration) =
|
||||
moduleConfiguration match
|
||||
moduleSettings match
|
||||
{
|
||||
case ic: InlineConfiguration => configureInline(ic)
|
||||
case ec: EmptyConfiguration => configureEmpty(ec.module)
|
||||
case pc: PomConfiguration => readPom(pc.file, pc.validate)
|
||||
case ifc: IvyFileConfiguration => readIvyFile(ifc.file, ifc.validate)
|
||||
}
|
||||
moduleConfiguration.ivyScala.foreach(IvyScala.checkModule(baseModule, baseConfiguration))
|
||||
moduleSettings.ivyScala.foreach(IvyScala.checkModule(baseModule, baseConfiguration))
|
||||
baseModule.getExtraAttributesNamespaces.asInstanceOf[java.util.Map[String,String]].put("e", "http://ant.apache.org/ivy/extra")
|
||||
(baseModule, baseConfiguration)
|
||||
}
|
||||
|
|
@ -105,6 +106,7 @@ final class IvySbt(configuration: IvyConfiguration)
|
|||
|
||||
IvySbt.addArtifacts(moduleID, artifacts)
|
||||
IvySbt.addDependencies(moduleID, dependencies, parser)
|
||||
IvySbt.setModuleConfigurations(settings, moduleConfigurations)
|
||||
IvySbt.addMainArtifact(moduleID)
|
||||
(moduleID, parser.getDefaultConf)
|
||||
}
|
||||
|
|
@ -126,7 +128,7 @@ final class IvySbt(configuration: IvyConfiguration)
|
|||
private def readIvyFile(ivyFile: File, validate: Boolean) =
|
||||
{
|
||||
val url = toURL(ivyFile)
|
||||
val parser = new CustomXmlParser.CustomParser(settings)
|
||||
val parser = new CustomXmlParser.CustomParser(settings, None)
|
||||
parser.setValidate(validate)
|
||||
parser.setSource(url)
|
||||
parser.parse()
|
||||
|
|
@ -168,6 +170,20 @@ private object IvySbt
|
|||
settings.setDefaultResolver(newDefault.getName)
|
||||
log.debug("Using repositories:\n" + resolvers.mkString("\n\t"))
|
||||
}
|
||||
private def setModuleConfigurations(settings: IvySettings, moduleConfigurations: Seq[ModuleConfiguration])
|
||||
{
|
||||
val existing = settings.getResolverNames
|
||||
for(moduleConf <- moduleConfigurations)
|
||||
{
|
||||
import moduleConf._
|
||||
import IvyPatternHelper._
|
||||
import PatternMatcher._
|
||||
if(!existing.contains(resolver.name))
|
||||
settings.addResolver(ConvertResolver(resolver))
|
||||
val attributes = javaMap(Map(MODULE_KEY -> name, ORGANISATION_KEY -> organization, REVISION_KEY -> revision))
|
||||
settings.addModuleConfiguration(attributes, settings.getMatcher(EXACT_OR_REGEXP), resolver.name, null, null, null)
|
||||
}
|
||||
}
|
||||
private def configureCache(settings: IvySettings, dir: Option[File])
|
||||
{
|
||||
val cacheDir = dir.getOrElse(settings.getDefaultRepositoryCacheBasedir())
|
||||
|
|
@ -244,9 +260,8 @@ private object IvySbt
|
|||
/** Parses the given in-memory Ivy file 'xml', using the existing 'moduleID' and specifying the given 'defaultConfiguration'. */
|
||||
private def parseIvyXML(settings: IvySettings, xml: String, moduleID: DefaultModuleDescriptor, defaultConfiguration: String, validate: Boolean): CustomXmlParser.CustomParser =
|
||||
{
|
||||
val parser = new CustomXmlParser.CustomParser(settings)
|
||||
val parser = new CustomXmlParser.CustomParser(settings, Some(defaultConfiguration))
|
||||
parser.setMd(moduleID)
|
||||
parser.setDefaultConf(defaultConfiguration)
|
||||
parser.setValidate(validate)
|
||||
parser.setInput(xml.getBytes)
|
||||
parser.parse()
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ object IvyActions
|
|||
{
|
||||
module.logger.info("Installing " + dependency)
|
||||
val options = new InstallOptions
|
||||
options.setValidate(module.moduleConfiguration.validate)
|
||||
options.setValidate(module.moduleSettings.validate)
|
||||
options.setTransitive(dependency.isTransitive)
|
||||
ivy.install(dependency.getDependencyRevisionId, from, to, options)
|
||||
}
|
||||
|
|
@ -50,10 +50,8 @@ object IvyActions
|
|||
// todo: correct default configuration for extra dependencies
|
||||
private def addLateDependencies(ivy: Ivy, module: DefaultModuleDescriptor, defaultConfiguration: String, extraDependencies: Iterable[ModuleID])
|
||||
{
|
||||
val parser = new CustomXmlParser.CustomParser(ivy.getSettings)
|
||||
val parser = new CustomXmlParser.CustomParser(ivy.getSettings, Some(defaultConfiguration))
|
||||
parser.setMd(module)
|
||||
val defaultConf = if(defaultConfiguration.contains("->")) defaultConfiguration else (defaultConfiguration + "->default(compile)")
|
||||
parser.setDefaultConf(defaultConf)
|
||||
IvySbt.addDependencies(module, extraDependencies, parser)
|
||||
}
|
||||
private def getConfigurations(module: ModuleDescriptor, configurations: Option[Iterable[Configuration]]) =
|
||||
|
|
|
|||
|
|
@ -40,19 +40,20 @@ object IvyCache
|
|||
/** Clears the cache of the jar for the given ID.*/
|
||||
def clearCachedJar(id: ModuleID, log: IvyLogger)
|
||||
{
|
||||
try { getCachedFile(id, log).delete }
|
||||
try { withCachedJar(id, log)(_.delete) }
|
||||
catch { case e: Exception => log.debug("Error cleaning cached jar: " + e.toString) }
|
||||
}
|
||||
/** Copies the cached jar for the given ID to the directory 'toDirectory'. If the jar is not in the cache, NotInCache is thrown.*/
|
||||
def retrieveCachedJar(id: ModuleID, toDirectory: File, log: IvyLogger) =
|
||||
{
|
||||
val cachedFile = getCachedFile(id, log)
|
||||
val copyTo = new File(toDirectory, cachedFile.getName)
|
||||
FileUtil.copy(cachedFile, copyTo, null)
|
||||
copyTo
|
||||
}
|
||||
/** Get the location of the cached jar for the given ID in the Ivy cache. If the jar is not in the cache, NotInCache is thrown.*/
|
||||
def getCachedFile(id: ModuleID, log: IvyLogger): File =
|
||||
withCachedJar(id, log) { cachedFile =>
|
||||
val copyTo = new File(toDirectory, cachedFile.getName)
|
||||
FileUtil.copy(cachedFile, copyTo, null)
|
||||
copyTo
|
||||
}
|
||||
|
||||
/** Get the location of the cached jar for the given ID in the Ivy cache. If the jar is not in the cache, NotInCache is thrown
|
||||
* TODO: locking.*/
|
||||
def withCachedJar[T](id: ModuleID, log: IvyLogger)(f: File => T): T =
|
||||
{
|
||||
val cachedFile =
|
||||
try
|
||||
|
|
@ -64,7 +65,7 @@ object IvyCache
|
|||
}
|
||||
catch { case e: Exception => throw new NotInCache(id, e) }
|
||||
|
||||
if(cachedFile.exists) cachedFile else throw new NotInCache(id)
|
||||
if(cachedFile.exists) f(cachedFile) else throw new NotInCache(id)
|
||||
}
|
||||
/** Calls the given function with the default Ivy cache.*/
|
||||
def withDefaultCache[T](log: IvyLogger)(f: DefaultRepositoryCacheManager => T): T =
|
||||
|
|
@ -82,7 +83,7 @@ object IvyCache
|
|||
{
|
||||
val local = Resolver.defaultLocal
|
||||
val paths = new IvyPaths(new File("."), None)
|
||||
val conf = new IvyConfiguration(paths, Seq(local), log)
|
||||
val conf = new IvyConfiguration(paths, Seq(local), Nil, log)
|
||||
(new IvySbt(conf), local)
|
||||
}
|
||||
/** Creates a default jar artifact based on the given ID.*/
|
||||
|
|
|
|||
|
|
@ -7,19 +7,20 @@ import java.io.File
|
|||
import scala.xml.NodeSeq
|
||||
|
||||
final class IvyPaths(val baseDirectory: File, val cacheDirectory: Option[File]) extends NotNull
|
||||
final class IvyConfiguration(val paths: IvyPaths, val resolvers: Seq[Resolver], val log: IvyLogger) extends NotNull
|
||||
final class IvyConfiguration(val paths: IvyPaths, val resolvers: Seq[Resolver],
|
||||
val moduleConfigurations: Seq[ModuleConfiguration], val log: IvyLogger) extends NotNull
|
||||
|
||||
sealed trait ModuleConfiguration extends NotNull
|
||||
sealed trait ModuleSettings extends NotNull
|
||||
{
|
||||
def validate: Boolean
|
||||
def ivyScala: Option[IvyScala]
|
||||
}
|
||||
final class IvyFileConfiguration(val file: File, val ivyScala: Option[IvyScala], val validate: Boolean) extends ModuleConfiguration
|
||||
final class PomConfiguration(val file: File, val ivyScala: Option[IvyScala], val validate: Boolean) extends ModuleConfiguration
|
||||
final class IvyFileConfiguration(val file: File, val ivyScala: Option[IvyScala], val validate: Boolean) extends ModuleSettings
|
||||
final class PomConfiguration(val file: File, val ivyScala: Option[IvyScala], val validate: Boolean) extends ModuleSettings
|
||||
final class InlineConfiguration(val module: ModuleID, val dependencies: Iterable[ModuleID], val ivyXML: NodeSeq,
|
||||
val configurations: Iterable[Configuration], val defaultConfiguration: Option[Configuration], val ivyScala: Option[IvyScala],
|
||||
val artifacts: Iterable[Artifact], val validate: Boolean) extends ModuleConfiguration
|
||||
final class EmptyConfiguration(val module: ModuleID, val ivyScala: Option[IvyScala], val validate: Boolean) extends ModuleConfiguration
|
||||
val artifacts: Iterable[Artifact], val validate: Boolean) extends ModuleSettings
|
||||
final class EmptyConfiguration(val module: ModuleID, val ivyScala: Option[IvyScala], val validate: Boolean) extends ModuleSettings
|
||||
object InlineConfiguration
|
||||
{
|
||||
def apply(module: ModuleID, dependencies: Iterable[ModuleID], artifacts: Iterable[Artifact]) =
|
||||
|
|
@ -37,7 +38,7 @@ object InlineConfiguration
|
|||
else
|
||||
explicitConfigurations
|
||||
}
|
||||
object ModuleConfiguration
|
||||
object ModuleSettings
|
||||
{
|
||||
def apply(ivyScala: Option[IvyScala], validate: Boolean, module: => ModuleID)(baseDirectory: File, log: IvyLogger) =
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ final case class ModuleID(organization: String, name: String, revision: String,
|
|||
def from(url: String) = artifacts(Artifact(name, new URL(url)))
|
||||
def classifier(c: String) = artifacts(Artifact(name, c))
|
||||
def artifacts(newArtifacts: Artifact*) = ModuleID(organization, name, revision, configurations, isChanging, isTransitive, newArtifacts ++ explicitArtifacts, extraAttributes)
|
||||
def extra(attributes: (String,String)*) = ModuleID(organization, name, revision, configurations, isChanging, isTransitive, explicitArtifacts, extraAttributes ++ attributes)
|
||||
def extra(attributes: (String,String)*) = ModuleID(organization, name, revision, configurations, isChanging, isTransitive, explicitArtifacts, extraAttributes ++ ModuleID.checkE(attributes))
|
||||
}
|
||||
object ModuleID
|
||||
{
|
||||
|
|
@ -30,6 +30,10 @@ object ModuleID
|
|||
ModuleID(organization, name, revision, configurations, isChanging, isTransitive, Nil)
|
||||
def apply(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean, explicitArtifacts: Seq[Artifact]): ModuleID =
|
||||
ModuleID(organization, name, revision, configurations, isChanging, isTransitive, explicitArtifacts, Map.empty)
|
||||
|
||||
def checkE(attributes: Seq[(String, String)]) =
|
||||
for ( (key, value) <- attributes) yield
|
||||
if(key.startsWith("e:")) (key, value) else ("e:" + key, value)
|
||||
}
|
||||
sealed trait Resolver extends NotNull
|
||||
{
|
||||
|
|
@ -40,14 +44,20 @@ sealed case class MavenRepository(name: String, root: String) extends Resolver
|
|||
override def toString = name + ": " + root
|
||||
}
|
||||
|
||||
final class Patterns(val ivyPatterns: Seq[String], val artifactPatterns: Seq[String], val isMavenCompatible: Boolean) extends NotNull
|
||||
{
|
||||
private[xsbt] def mavenStyle(): Patterns = Patterns(ivyPatterns, artifactPatterns, true)
|
||||
private[xsbt] def withIvys(patterns: Seq[String]): Patterns = Patterns(patterns ++ ivyPatterns, artifactPatterns, isMavenCompatible)
|
||||
private[xsbt] def withArtifacts(patterns: Seq[String]): Patterns = Patterns(ivyPatterns, patterns ++ artifactPatterns, isMavenCompatible)
|
||||
}
|
||||
object Patterns
|
||||
{
|
||||
def apply(artifactPatterns: String*): Patterns = Patterns(true, artifactPatterns : _*)
|
||||
def apply(isMavenCompatible: Boolean, artifactPatterns: String*): Patterns = Patterns(Nil, artifactPatterns, isMavenCompatible)
|
||||
def apply(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean): Patterns = new Patterns(ivyPatterns, artifactPatterns, isMavenCompatible)
|
||||
}
|
||||
object RepositoryHelpers
|
||||
{
|
||||
final case class Patterns(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean) extends NotNull
|
||||
{
|
||||
private[xsbt] def mavenStyle(): Patterns = Patterns(ivyPatterns, artifactPatterns, true)
|
||||
private[xsbt] def withIvys(patterns: Seq[String]): Patterns = Patterns(patterns ++ ivyPatterns, artifactPatterns, isMavenCompatible)
|
||||
private[xsbt] def withArtifacts(patterns: Seq[String]): Patterns = Patterns(ivyPatterns, patterns ++ artifactPatterns, isMavenCompatible)
|
||||
}
|
||||
final case class SshConnection(authentication: Option[SshAuthentication], hostname: Option[String], port: Option[Int]) extends NotNull
|
||||
{
|
||||
def copy(authentication: Option[SshAuthentication]) = SshConnection(authentication, hostname, port)
|
||||
|
|
@ -63,7 +73,7 @@ object RepositoryHelpers
|
|||
final case class PasswordAuthentication(user: String, password: String) extends SshAuthentication
|
||||
final case class KeyFileAuthentication(keyfile: File, password: String) extends SshAuthentication
|
||||
}
|
||||
import RepositoryHelpers.{Patterns, SshConnection, FileConfiguration}
|
||||
import RepositoryHelpers.{SshConnection, FileConfiguration}
|
||||
import RepositoryHelpers.{KeyFileAuthentication, PasswordAuthentication, SshAuthentication}
|
||||
|
||||
/** sbt interface to an Ivy repository based on patterns, which is most Ivy repositories.*/
|
||||
|
|
@ -283,12 +293,7 @@ object Configurations
|
|||
private[xsbt] val DefaultMavenConfiguration = defaultConfiguration(true)
|
||||
private[xsbt] val DefaultIvyConfiguration = defaultConfiguration(false)
|
||||
private[xsbt] def DefaultConfiguration(mavenStyle: Boolean) = if(mavenStyle) DefaultMavenConfiguration else DefaultIvyConfiguration
|
||||
private[xsbt] def defaultConfiguration(mavenStyle: Boolean) =
|
||||
{
|
||||
val base = if(mavenStyle) Configurations.Compile else Configurations.Default
|
||||
config(base.name + "->default(compile)")
|
||||
}
|
||||
|
||||
private[xsbt] def defaultConfiguration(mavenStyle: Boolean) = if(mavenStyle) Configurations.Compile else Configurations.Default
|
||||
private[xsbt] def removeDuplicates(configs: Iterable[Configuration]) = Set(scala.collection.mutable.Map(configs.map(config => (config.name, config)).toSeq: _*).values.toList: _*)
|
||||
}
|
||||
/** Represents an Ivy configuration. */
|
||||
|
|
@ -337,6 +342,12 @@ object Artifact
|
|||
Artifact(name, extract(name, defaultType), extract(name, defaultExtension), None, Nil, Some(file.toURI.toURL))
|
||||
}
|
||||
}
|
||||
final case class ModuleConfiguration(organization: String, name: String, revision: String, resolver: Resolver) extends NotNull
|
||||
object ModuleConfiguration
|
||||
{
|
||||
def apply(org: String, resolver: Resolver): ModuleConfiguration = apply(org, "*", "*", resolver)
|
||||
def apply(org: String, name: String, resolver: Resolver): ModuleConfiguration = ModuleConfiguration(org, name, "*", resolver)
|
||||
}
|
||||
/*
|
||||
object Credentials
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,34 +14,33 @@ object ComponentManagerTest extends Specification
|
|||
}
|
||||
"throw an exception if 'file' is called for an empty component" in {
|
||||
withManager { manager =>
|
||||
createDirectory(manager.location(TestID))
|
||||
manager.define(TestID, Nil)
|
||||
( manager.file(TestID) ) must throwA[InvalidComponent]
|
||||
}
|
||||
}
|
||||
"return the file for a single-file component" in {
|
||||
withManager { manager =>
|
||||
createFiles(manager, TestID, "a") match { case Seq(x) =>
|
||||
manager.file(TestID).getAbsoluteFile must beEqualTo(x.getAbsoluteFile)
|
||||
}
|
||||
val hash = defineFile(manager, TestID, "a")
|
||||
checksum(manager.file(TestID)) must beEqualTo(hash)
|
||||
}
|
||||
}
|
||||
|
||||
"throw an exception if 'file' is called for multi-file component" in {
|
||||
withManager { manager =>
|
||||
createFiles(manager, TestID, "a", "b")
|
||||
defineFiles(manager, TestID, "a", "b")
|
||||
( manager.file(TestID) ) must throwA[InvalidComponent]
|
||||
}
|
||||
}
|
||||
"return the files for a multi-file component" in {
|
||||
withManager { manager =>
|
||||
val files = createFiles(manager, TestID, "a", "b")
|
||||
manager.files(TestID) must haveTheSameElementsAs(files)
|
||||
val hashes = defineFiles(manager, TestID, "a", "b")
|
||||
checksum(manager.files(TestID)) must haveTheSameElementsAs(hashes)
|
||||
}
|
||||
}
|
||||
"return the files for a single-file component" in {
|
||||
withManager { manager =>
|
||||
val files = createFiles(manager, TestID, "a")
|
||||
manager.files(TestID) must haveTheSameElementsAs(files)
|
||||
val hashes = defineFiles(manager, TestID, "a")
|
||||
checksum(manager.files(TestID)) must haveTheSameElementsAs(hashes)
|
||||
}
|
||||
}
|
||||
"throw an exception if 'files' is called for a non-existing component" in {
|
||||
|
|
@ -49,47 +48,33 @@ object ComponentManagerTest extends Specification
|
|||
}
|
||||
|
||||
"properly cache a file and then retrieve it to an unresolved component" in {
|
||||
withManager { manager =>
|
||||
val file = createFile(manager, TestID, "a")
|
||||
val hash = checksum(file)
|
||||
withManager { definingManager =>
|
||||
val hash = defineFile(definingManager, TestID, "a")
|
||||
try
|
||||
{
|
||||
manager.cache(TestID)
|
||||
delete(manager.location(TestID))
|
||||
FileUtilities.listFiles(manager.location(TestID)).toList must haveSize(0)
|
||||
checksum(manager.file(TestID)) must beEqualTo(hash)
|
||||
definingManager.cache(TestID)
|
||||
withManager { usingManager =>
|
||||
checksum(usingManager.file(TestID)) must beEqualTo(hash)
|
||||
}
|
||||
}
|
||||
finally { manager.clearCache(TestID) }
|
||||
}
|
||||
}
|
||||
|
||||
"not retrieve to a component already resolved" in {
|
||||
withManager { manager =>
|
||||
val file = createFile(manager, TestID, "a")
|
||||
try
|
||||
{
|
||||
manager.cache(TestID)
|
||||
val idDirectory = manager.location(TestID)
|
||||
delete(idDirectory)
|
||||
createDirectory(idDirectory)
|
||||
manager.file(TestID) must throwA[InvalidComponent]
|
||||
}
|
||||
finally { manager.clearCache(TestID) }
|
||||
finally { definingManager.clearCache(TestID) }
|
||||
}
|
||||
}
|
||||
}
|
||||
private def checksum(file: File) = ChecksumHelper.computeAsString(file, "sha1")
|
||||
private def createFile(manager: ComponentManager, id: String, name: String): File = createFiles(manager, id, name).toList.head
|
||||
private def createFiles(manager: ComponentManager, id: String, names: String*): Seq[File] =
|
||||
{
|
||||
val dir = manager.location(id)
|
||||
createDirectory(dir)
|
||||
names.map { name =>
|
||||
val testFile = new File(dir, name)
|
||||
touch(testFile)
|
||||
testFile
|
||||
private def checksum(files: Iterable[File]): Seq[String] = files.map(checksum).toSeq
|
||||
private def checksum(file: File): String = if(file.exists) ChecksumHelper.computeAsString(file, "sha1") else ""
|
||||
private def defineFile(manager: ComponentManager, id: String, name: String): String = createFile(manager, id, name)(checksum)
|
||||
private def defineFiles(manager: ComponentManager, id: String, names: String*): Seq[String] = createFiles(manager, id, names : _*)(checksum)
|
||||
private def createFile[T](manager: ComponentManager, id: String, name: String)(f: File => T): T = createFiles(manager, id, name)(files => f(files.toList.head))
|
||||
private def createFiles[T](manager: ComponentManager, id: String, names: String*)(f: Seq[File] => T): T =
|
||||
withTemporaryDirectory { dir =>
|
||||
val files = names.map(name => new File(dir, name) )
|
||||
files.foreach(writeRandomContent)
|
||||
manager.define(id, files)
|
||||
f(files)
|
||||
}
|
||||
}
|
||||
private def writeRandomContent(file: File) = FileUtilities.write(file, randomString)
|
||||
private def randomString = "asdf"
|
||||
private def withManager[T](f: ComponentManager => T): T =
|
||||
TestIvyLogger( logger => withTemporaryDirectory { temp => f(new ComponentManager(temp, logger)) } )
|
||||
TestIvyLogger( logger => withTemporaryDirectory { temp => f(new ComponentManager(new xsbt.boot.ComponentProvider(temp), logger)) } )
|
||||
}
|
||||
Loading…
Reference in New Issue