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
56e96c3f49
commit
b2fdc07505
|
|
@ -35,9 +35,9 @@ class AnalyzingCompiler(scalaInstance: ScalaInstance, manager: ComponentManager)
|
|||
new DualLoader(scalaLoader, notXsbtiFilter, x => true, sbtLoader, xsbtiFilter, x => false)
|
||||
}
|
||||
override def toString = "Analyzing compiler (Scala " + scalaInstance.actualVersion + ")"
|
||||
}
|
||||
}/*
|
||||
object AnalyzingCompiler
|
||||
{
|
||||
def apply(scalaVersion: String, provider: xsbti.ScalaProvider, manager: ComponentManager): AnalyzingCompiler =
|
||||
new AnalyzingCompiler(ScalaInstance(scalaVersion, provider), manager)
|
||||
}
|
||||
}*/
|
||||
|
|
@ -27,12 +27,13 @@ class ComponentCompiler(compiler: RawCompiler, manager: ComponentManager)
|
|||
protected def compileAndInstall(id: String, binID: String): File =
|
||||
{
|
||||
val srcID = id + srcExtension
|
||||
val binaryDirectory = manager.location(binID)
|
||||
createDirectory(binaryDirectory)
|
||||
val targetJar = new File(binaryDirectory, id + ".jar")
|
||||
compileSources(manager.files(srcID), targetJar, id)
|
||||
manager.cache(binID)
|
||||
targetJar
|
||||
withTemporaryDirectory { binaryDirectory =>
|
||||
val targetJar = new File(binaryDirectory, id + ".jar")
|
||||
compileSources(manager.files(srcID), targetJar, id)
|
||||
manager.define(binID, Seq(targetJar))
|
||||
manager.cache(binID)
|
||||
}
|
||||
manager.file(binID)
|
||||
}
|
||||
/** Extract sources from source jars, compile them with the xsbti interfaces on the classpath, and package the compiled classes and
|
||||
* any resources from the source jars into a final jar.*/
|
||||
|
|
|
|||
|
|
@ -21,12 +21,8 @@ object ScalaInstance
|
|||
{
|
||||
val VersionPrefix = "version "
|
||||
/** Creates a ScalaInstance using the given provider to obtain the jars and loader.*/
|
||||
def apply(version: String, provider: xsbti.ScalaProvider) =
|
||||
{
|
||||
val scalaLibDirectory = provider.getScalaHome(version)
|
||||
// these get the locations of the scala jars given the location of the lib/ directory
|
||||
val libraryJar = new File(scalaLibDirectory, "scala-library.jar")
|
||||
val compilerJar = new File(scalaLibDirectory, "scala-compiler.jar")
|
||||
new ScalaInstance(version, provider.getScalaLoader(version), libraryJar, compilerJar)
|
||||
}
|
||||
def apply(version: String, launcher: xsbti.Launcher): ScalaInstance =
|
||||
apply(version, launcher.getScala(version))
|
||||
def apply(version: String, provider: xsbti.ScalaProvider): ScalaInstance =
|
||||
new ScalaInstance(version, provider.loader, provider.libraryJar, provider.compilerJar)
|
||||
}
|
||||
|
|
@ -34,34 +34,23 @@ object WithCompiler
|
|||
val log = new TestIvyLogger with CompileLogger
|
||||
log.setLevel(Level.Debug)
|
||||
log.bufferQuietly {
|
||||
FileUtilities.withTemporaryDirectory { temp =>
|
||||
val launch = new xsbt.boot.Launch(temp)
|
||||
val sbtVersion = xsbti.Versions.Sbt
|
||||
val manager = new ComponentManager(launch.getSbtHome(sbtVersion, scalaVersion), log)
|
||||
prepare(manager, ComponentCompiler.compilerInterfaceSrcID, "CompilerInterface.scala")
|
||||
prepare(manager, ComponentCompiler.xsbtiID, classOf[xsbti.AnalysisCallback])
|
||||
val result = f(AnalyzingCompiler(scalaVersion, launch, manager), log)
|
||||
launch.clearScalaLoaderCache
|
||||
System.gc()
|
||||
System.gc()
|
||||
System.gc()
|
||||
result
|
||||
boot.LaunchTest.withLauncher { launch =>
|
||||
FileUtilities.withTemporaryDirectory { componentDirectory =>
|
||||
val manager = new ComponentManager(new boot.ComponentProvider(componentDirectory), log)
|
||||
prepare(manager, ComponentCompiler.compilerInterfaceSrcID, "CompilerInterface.scala")
|
||||
prepare(manager, ComponentCompiler.xsbtiID, classOf[xsbti.AnalysisCallback])
|
||||
f(new AnalyzingCompiler(ScalaInstance(scalaVersion, launch), manager), log)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private def prepare(manager: ComponentManager, id: String, resource: Class[_]): Unit =
|
||||
{
|
||||
val src = FileUtilities.classLocationFile(resource)
|
||||
prepare(manager, id, src)
|
||||
}
|
||||
manager.define(id, FileUtilities.classLocationFile(resource) :: Nil)
|
||||
private def prepare(manager: ComponentManager, id: String, resource: String): Unit =
|
||||
{
|
||||
val src = getClass.getClassLoader.getResource(resource)
|
||||
if(src eq null)
|
||||
error("Resource not found: " + resource)
|
||||
prepare(manager, id, FileUtilities.asFile(src))
|
||||
manager.define(id, FileUtilities.asFile(src) :: Nil)
|
||||
}
|
||||
import Paths._
|
||||
private def prepare(manager: ComponentManager, id: String, file: File): Unit =
|
||||
FileUtilities.copy(file x FileMapper.flat(manager.location(id)))
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ package xsbti;
|
|||
|
||||
public interface Versions
|
||||
{
|
||||
public static final String Sbt = "0.7";
|
||||
public static final String Sbt = "0.7.0_13"; // keep in sync with LauncherProject in the XSbt project definition;
|
||||
public static final int Interface = 1;
|
||||
public static final int BootInterface = 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)) } )
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ The sbt launcher component is a self-contained jar that boots a Scala applicatio
|
|||
The launcher may be configured in the following ways in increasing order of precedence:
|
||||
* Replace the /sbt/sbt.launch.config file in the jar
|
||||
* Put a configuration file named sbt.launch.config file on the classpath. Put it in the classpath root without the /sbt prefix.
|
||||
* Specify the location of an alternate configuration on the command line. The alternate configuration option is specified as the first argument to the launcher. This option is the path to the configuration file preceeded by '@'. Resolution of a relative path is first attempted against the current working directory, then against the user's home directory, and then against the directory containing the launcher jar. An error is generated if none of these attempts succeed.
|
||||
* Specify the location of an alternate configuration on the command line. This can be done by either specifying the location as the system property 'sbt.boot.properties' or as the first argument to the launcher prefixed by '@'. The system property has lower precedence. Resolution of a relative path is first attempted against the current working directory, then against the user's home directory, and then against the directory containing the launcher jar. An error is generated if none of these attempts succeed.
|
||||
|
||||
The configuration file is read as UTF-8 encoded and is defined by the following grammer (nl is a newline or end of file):
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ private object BootConfiguration
|
|||
val JLinePackagePath = "jline/"
|
||||
/** The loader will check that these classes can be loaded and will assume that their presence indicates
|
||||
* the Scala compiler and library have been downloaded.*/
|
||||
val TestLoadScalaClasses = "scala.List" :: "scala.tools.nsc.GenericRunnerCommand" :: Nil
|
||||
val TestLoadScalaClasses = "scala.Option" :: "scala.tools.nsc.Global" :: Nil
|
||||
|
||||
val ScalaHomeProperty = "scala.home"
|
||||
val UpdateLogName = "update.log"
|
||||
|
|
|
|||
|
|
@ -10,12 +10,15 @@ object Configuration
|
|||
args match
|
||||
{
|
||||
case Seq(head, tail @ _*) if head.startsWith("@")=> (configurationFromFile(head.substring(1), baseDirectory), tail)
|
||||
case _ => (configurationOnClasspath, args)
|
||||
case _ =>
|
||||
val propertyConfigured = System.getProperty("sbt.boot.properties")
|
||||
val url = if(propertyConfigured == null) configurationOnClasspath else configurationFromFile(propertyConfigured, baseDirectory)
|
||||
(url , args)
|
||||
}
|
||||
def configurationOnClasspath: URL =
|
||||
{
|
||||
resourcePaths.toStream.map(getClass.getResource).find(_ ne null) getOrElse
|
||||
( throw new BootException(resourcePaths.mkString("Could not finder sbt launch configuration. (Searched classpath for ", ",", ")")) )
|
||||
( multiPartError("Could not finder sbt launch configuration. Searched classpath for:", resourcePaths))
|
||||
}
|
||||
def configurationFromFile(path: String, baseDirectory: File): URL =
|
||||
{
|
||||
|
|
@ -25,13 +28,15 @@ object Configuration
|
|||
val exists = try { (new File(resolved)).exists } catch { case _: IllegalArgumentException => false }
|
||||
if(exists) Some(resolved.toURL) else None
|
||||
}
|
||||
resolveAgainst(baseDirectory).toStream.flatMap(resolve).firstOption.getOrElse(throw new BootException("Could not find configuration file '" + path + "'."))
|
||||
val against = resolveAgainst(baseDirectory)
|
||||
against.toStream.flatMap(resolve).firstOption.getOrElse(multiPartError("Could not find configuration file '" + path + "'. Searched:", against))
|
||||
}
|
||||
def multiPartError[T](firstLine: String, lines: Seq[T]) = throw new BootException( (Seq(firstLine) ++ lines).mkString("\n\t") )
|
||||
|
||||
val ConfigurationFilename = "sbt.boot.properties"
|
||||
val ConfigurationName = "sbt.boot.properties"
|
||||
val JarBasePath = "/sbt/"
|
||||
def userConfigurationPath = "/" + ConfigurationFilename
|
||||
def defaultConfigurationPath = JarBasePath + ConfigurationFilename
|
||||
def userConfigurationPath = "/" + ConfigurationName
|
||||
def defaultConfigurationPath = JarBasePath + ConfigurationName
|
||||
def resourcePaths = Seq(userConfigurationPath, defaultConfigurationPath)
|
||||
def resolveAgainst(baseDirectory: File) = Seq(baseDirectory toURI, new File(System.getProperty("user.home")) toURI, classLocation(getClass).toURI)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,37 +1,50 @@
|
|||
package xsbt.boot
|
||||
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
object Launch
|
||||
{
|
||||
def apply(arguments: Seq[String]): Unit = apply( (new File("")).getAbsoluteFile, arguments )
|
||||
def apply(currentDirectory: File, arguments: Seq[String])
|
||||
{
|
||||
val (configFile, newArguments) = Configuration.find(arguments, currentDirectory)
|
||||
val parsed = Configuration.parse(configFile, currentDirectory)
|
||||
val (explicit, finish) = ResolveVersions(parsed)
|
||||
val launcher = new Launch(explicit)
|
||||
launch(launcher, explicit.getScalaVersion, explicit.app.toID, currentDirectory, newArguments, finish)
|
||||
}
|
||||
final def launch(launcher: xsbti.Launcher, scalaVersion: String, app: xsbti.ApplicationID, workingDirectory: File, arguments: Seq[String], finish: () => Unit)
|
||||
def apply(arguments: Seq[String]): Unit = apply( (new File("")).getAbsoluteFile , arguments )
|
||||
|
||||
def apply(currentDirectory: File, arguments: Seq[String]): Unit =
|
||||
Configuration.find(arguments, currentDirectory) match { case (configLocation, newArguments) => configured(currentDirectory, configLocation, newArguments) }
|
||||
|
||||
def configured(currentDirectory: File, configLocation: URL, arguments: Seq[String]): Unit =
|
||||
parsed(currentDirectory, Configuration.parse(configLocation, currentDirectory) , arguments)
|
||||
|
||||
def parsed(currentDirectory: File, parsed: LaunchConfiguration, arguments: Seq[String]): Unit =
|
||||
ResolveVersions(parsed) match { case (resolved, finish) => explicit(currentDirectory, resolved, arguments, finish) }
|
||||
|
||||
def explicit(currentDirectory: File, explicit: LaunchConfiguration, arguments: Seq[String], setupComplete: () => Unit): Unit =
|
||||
launch( run(new Launch(explicit.boot.directory, explicit.repositories)) ) (
|
||||
RunConfiguration(explicit.getScalaVersion, explicit.app.toID, currentDirectory, arguments, setupComplete) )
|
||||
|
||||
final def run(launcher: xsbti.Launcher)(config: RunConfiguration): xsbti.MainResult =
|
||||
{
|
||||
import config._
|
||||
val scalaProvider: xsbti.ScalaProvider = launcher.getScala(scalaVersion)
|
||||
val appProvider: xsbti.AppProvider = scalaProvider.app(app)
|
||||
val appConfig: xsbti.AppConfiguration = new AppConfiguration(arguments.toArray, workingDirectory, appProvider)
|
||||
|
||||
|
||||
val main = appProvider.newMain()
|
||||
finish()
|
||||
main.run(appConfig) match
|
||||
setupComplete()
|
||||
main.run(appConfig)
|
||||
}
|
||||
final def launch(run: RunConfiguration => xsbti.MainResult)(config: RunConfiguration)
|
||||
{
|
||||
run(config) match
|
||||
{
|
||||
case e: xsbti.Exit => System.exit(e.code)
|
||||
case r: xsbti.Reboot => launch(launcher, r.scalaVersion, r.app, r.baseDirectory, r.arguments, () => ())
|
||||
case r: xsbti.Reboot => launch(run)(RunConfiguration(r.scalaVersion, r.app, r.baseDirectory, r.arguments, () => ()))
|
||||
case x => throw new BootException("Invalid main result: " + x + (if(x eq null) "" else " (class: " + x.getClass + ")"))
|
||||
}
|
||||
}
|
||||
}
|
||||
case class RunConfiguration(scalaVersion: String, app: xsbti.ApplicationID, workingDirectory: File, arguments: Seq[String], setupComplete: () => Unit) extends NotNull
|
||||
|
||||
import BootConfiguration.{appDirectoryName, baseDirectoryName, ScalaDirectoryName, TestLoadScalaClasses}
|
||||
class Launch(val configuration: LaunchConfiguration) extends xsbti.Launcher
|
||||
class Launch(val bootDirectory: File, repositories: Seq[Repository]) extends xsbti.Launcher
|
||||
{
|
||||
import scala.collection.mutable.HashMap
|
||||
private val scalaProviders = new HashMap[String, ScalaProvider]
|
||||
|
|
@ -42,12 +55,15 @@ class Launch(val configuration: LaunchConfiguration) extends xsbti.Launcher
|
|||
def launcher: xsbti.Launcher = Launch.this
|
||||
|
||||
lazy val parentLoader = new BootFilteredLoader(getClass.getClassLoader)
|
||||
lazy val configuration = Launch.this.configuration.withScalaVersion(version)
|
||||
lazy val libDirectory = new File(configuration.boot.directory, baseDirectoryName(version))
|
||||
|
||||
lazy val configuration = new UpdateConfiguration(bootDirectory, version, repositories)
|
||||
lazy val libDirectory = new File(configuration.bootDirectory, baseDirectoryName(version))
|
||||
lazy val scalaHome = new File(libDirectory, ScalaDirectoryName)
|
||||
def compilerJar = new File(scalaHome, "scala-compiler.jar")
|
||||
def libraryJar = new File(scalaHome, "scala-library.jar")
|
||||
def baseDirectories = Seq(scalaHome)
|
||||
def testLoadClasses = TestLoadScalaClasses
|
||||
def target = UpdateTarget.UpdateScala
|
||||
def target = UpdateScala
|
||||
def failLabel = "Scala " + version
|
||||
|
||||
def app(id: xsbti.ApplicationID): xsbti.AppProvider = new AppProvider(id)
|
||||
|
|
@ -55,12 +71,12 @@ class Launch(val configuration: LaunchConfiguration) extends xsbti.Launcher
|
|||
class AppProvider(val id: xsbti.ApplicationID) extends xsbti.AppProvider with Provider
|
||||
{
|
||||
def scalaProvider: xsbti.ScalaProvider = ScalaProvider.this
|
||||
lazy val configuration = ScalaProvider.this.configuration.withApp(Application(id))
|
||||
def configuration = ScalaProvider.this.configuration
|
||||
lazy val appHome = new File(libDirectory, appDirectoryName(id, File.separator))
|
||||
def parentLoader = ScalaProvider.this.loader
|
||||
def baseDirectories = id.mainComponents.map(componentLocation) ++ Seq(appHome)
|
||||
def baseDirectories = id.mainComponents.map(components.componentLocation) ++ Seq(appHome)
|
||||
def testLoadClasses = Seq(id.mainClass)
|
||||
def target = UpdateTarget.UpdateApp
|
||||
def target = new UpdateApp(Application(id))
|
||||
def failLabel = id.name + " " + id.version
|
||||
|
||||
lazy val mainClass: Class[T] forSome { type T <: xsbti.AppMain } =
|
||||
|
|
@ -70,16 +86,20 @@ class Launch(val configuration: LaunchConfiguration) extends xsbti.Launcher
|
|||
}
|
||||
def newMain(): xsbti.AppMain = mainClass.newInstance
|
||||
|
||||
def componentLocation(id: String): File = new File(appHome, id)
|
||||
def component(id: String) = GetJars(componentLocation(id) :: Nil)
|
||||
def defineComponent(id: String, files: Array[File]) =
|
||||
{
|
||||
val location = componentLocation(id)
|
||||
if(location.exists)
|
||||
throw new BootException("Cannot redefine component. (id: " + id + ", files: " + files.mkString(","))
|
||||
else
|
||||
files.foreach(file => Copy(file, location))
|
||||
}
|
||||
lazy val components = new ComponentProvider(appHome)
|
||||
}
|
||||
}
|
||||
}
|
||||
class ComponentProvider(baseDirectory: File) extends xsbti.ComponentProvider
|
||||
{
|
||||
def componentLocation(id: String): File = new File(baseDirectory, id)
|
||||
def component(id: String) = GetJars.wrapNull(componentLocation(id).listFiles).filter(_.isFile)
|
||||
def defineComponent(id: String, files: Array[File]) =
|
||||
{
|
||||
val location = componentLocation(id)
|
||||
if(location.exists)
|
||||
throw new BootException("Cannot redefine component. ID: " + id + ", files: " + files.mkString(","))
|
||||
else
|
||||
Copy(files, location)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,10 +5,10 @@ import java.net.{URL, URLClassLoader}
|
|||
|
||||
trait Provider extends NotNull
|
||||
{
|
||||
def configuration: LaunchConfiguration
|
||||
def configuration: UpdateConfiguration
|
||||
def baseDirectories: Seq[File]
|
||||
def testLoadClasses: Seq[String]
|
||||
def target: UpdateTarget.Value
|
||||
def target: UpdateTarget
|
||||
def failLabel: String
|
||||
def parentLoader: ClassLoader
|
||||
|
||||
|
|
|
|||
|
|
@ -21,19 +21,17 @@ import util.{DefaultMessageLogger, Message}
|
|||
|
||||
import BootConfiguration._
|
||||
|
||||
object UpdateTarget extends Enumeration
|
||||
{
|
||||
val UpdateScala = Value("scala")
|
||||
val UpdateApp = Value("app")
|
||||
}
|
||||
import UpdateTarget.{UpdateApp, UpdateScala}
|
||||
sealed trait UpdateTarget extends NotNull { def tpe: String }
|
||||
final object UpdateScala extends UpdateTarget { def tpe = "scala" }
|
||||
final case class UpdateApp(id: Application) extends UpdateTarget { def tpe = "app" }
|
||||
|
||||
final class UpdateConfiguration(val bootDirectory: File, val scalaVersion: String, val repositories: Seq[Repository]) extends NotNull
|
||||
|
||||
/** Ensures that the Scala and application jars exist for the given versions or else downloads them.*/
|
||||
final class Update(config: LaunchConfiguration)
|
||||
final class Update(config: UpdateConfiguration)
|
||||
{
|
||||
private val bootDirectory = config.boot.directory
|
||||
import config.{bootDirectory, repositories, scalaVersion}
|
||||
bootDirectory.mkdirs
|
||||
private val scalaVersion = config.getScalaVersion
|
||||
|
||||
private def logFile = new File(bootDirectory, UpdateLogName)
|
||||
private val logWriter = new PrintWriter(new FileWriter(logFile))
|
||||
|
|
@ -49,7 +47,7 @@ final class Update(config: LaunchConfiguration)
|
|||
private lazy val ivy = Ivy.newInstance(settings)
|
||||
|
||||
/** The main entry point of this class for use by the Update module. It runs Ivy */
|
||||
def apply(target: UpdateTarget.Value)
|
||||
def apply(target: UpdateTarget)
|
||||
{
|
||||
Message.setDefaultLogger(new SbtIvyLogger(logWriter))
|
||||
ivy.pushContext()
|
||||
|
|
@ -68,11 +66,11 @@ final class Update(config: LaunchConfiguration)
|
|||
}
|
||||
}
|
||||
/** Runs update for the specified target (updates either the scala or appliciation jars for building the project) */
|
||||
private def update(target: UpdateTarget.Value)
|
||||
private def update(target: UpdateTarget)
|
||||
{
|
||||
import IvyConfiguration.Visibility.PUBLIC
|
||||
// the actual module id here is not that important
|
||||
val moduleID = new DefaultModuleDescriptor(createID(SbtOrg, "boot-" + target, "1.0"), "release", null, false)
|
||||
val moduleID = new DefaultModuleDescriptor(createID(SbtOrg, "boot-" + target.tpe, "1.0"), "release", null, false)
|
||||
moduleID.setLastModified(System.currentTimeMillis)
|
||||
moduleID.addConfiguration(new IvyConfiguration(DefaultIvyConfiguration, PUBLIC, "", Array(), true, null))
|
||||
// add dependencies based on which target needs updating
|
||||
|
|
@ -81,14 +79,14 @@ final class Update(config: LaunchConfiguration)
|
|||
case UpdateScala =>
|
||||
addDependency(moduleID, ScalaOrg, CompilerModuleName, scalaVersion, "default")
|
||||
addDependency(moduleID, ScalaOrg, LibraryModuleName, scalaVersion, "default")
|
||||
case UpdateApp =>
|
||||
val resolvedName = if(config.app.crossVersioned) config.app.name + "_" + scalaVersion else config.app.name
|
||||
addDependency(moduleID, config.app.groupID, resolvedName, config.app.getVersion, "runtime(default)")
|
||||
case UpdateApp(app) =>
|
||||
val resolvedName = if(app.crossVersioned) app.name + "_" + scalaVersion else app.name
|
||||
addDependency(moduleID, app.groupID, resolvedName, app.getVersion, "runtime(default)")
|
||||
}
|
||||
update(moduleID, target)
|
||||
}
|
||||
/** Runs the resolve and retrieve for the given moduleID, which has had its dependencies added already. */
|
||||
private def update(moduleID: DefaultModuleDescriptor, target: UpdateTarget.Value)
|
||||
private def update(moduleID: DefaultModuleDescriptor, target: UpdateTarget)
|
||||
{
|
||||
val eventManager = new EventManager
|
||||
resolve(eventManager, moduleID)
|
||||
|
|
@ -128,16 +126,15 @@ final class Update(config: LaunchConfiguration)
|
|||
}
|
||||
}
|
||||
/** Retrieves resolved dependencies using the given target to determine the location to retrieve to. */
|
||||
private def retrieve(eventManager: EventManager, module: ModuleDescriptor, target: UpdateTarget.Value)
|
||||
private def retrieve(eventManager: EventManager, module: ModuleDescriptor, target: UpdateTarget)
|
||||
{
|
||||
val retrieveOptions = new RetrieveOptions
|
||||
val retrieveEngine = new RetrieveEngine(settings, eventManager)
|
||||
val pattern =
|
||||
target match
|
||||
{
|
||||
// see BootConfiguration
|
||||
case UpdateApp => appRetrievePattern(config.app.toID)
|
||||
case UpdateScala => scalaRetrievePattern
|
||||
case UpdateApp(app) => appRetrievePattern(app.toID)
|
||||
}
|
||||
retrieveEngine.retrieve(module.getModuleRevisionId, baseDirectoryName(scalaVersion) + "/" + pattern, retrieveOptions)
|
||||
}
|
||||
|
|
@ -146,8 +143,8 @@ final class Update(config: LaunchConfiguration)
|
|||
{
|
||||
val newDefault = new ChainResolver
|
||||
newDefault.setName("redefined-public")
|
||||
if(config.repositories.isEmpty) throw new BootException("No repositories defined.")
|
||||
config.repositories.foreach(repo => newDefault.add(toIvyRepository(settings, repo)))
|
||||
if(repositories.isEmpty) throw new BootException("No repositories defined.")
|
||||
repositories.foreach(repo => newDefault.add(toIvyRepository(settings, repo)))
|
||||
onDefaultRepositoryCacheManager(settings)(_.setUseOrigin(true))
|
||||
settings.addResolver(newDefault)
|
||||
settings.setDefaultResolver(newDefault.getName)
|
||||
|
|
|
|||
|
|
@ -10,15 +10,12 @@ object Using extends NotNull
|
|||
|
||||
object Copy
|
||||
{
|
||||
def apply(files: Array[File], to: File)
|
||||
{
|
||||
to.mkdirs()
|
||||
files.foreach(file => apply(file, to))
|
||||
}
|
||||
def apply(file: File, to: File)
|
||||
def apply(files: Seq[File], toDirectory: File): Unit = files.foreach(file => apply(file, toDirectory))
|
||||
def apply(file: File, toDirectory: File)
|
||||
{
|
||||
toDirectory.mkdirs()
|
||||
Using(new FileInputStream(file)) { in =>
|
||||
Using(new FileOutputStream(new File(to, file.getName))) { out =>
|
||||
Using(new FileOutputStream(new File(toDirectory, file.getName))) { out =>
|
||||
transfer(in, out)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package xsbti;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface AppProvider
|
||||
{
|
||||
public ScalaProvider scalaProvider();
|
||||
|
|
@ -10,6 +8,5 @@ public interface AppProvider
|
|||
public Class<? extends AppMain> mainClass();
|
||||
public AppMain newMain();
|
||||
|
||||
public File[] component(String componentID);
|
||||
public void defineComponent(String componentID, File[] components);
|
||||
}
|
||||
public ComponentProvider components();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package xsbti;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface ComponentProvider
|
||||
{
|
||||
public File[] component(String componentID);
|
||||
public void defineComponent(String componentID, File[] components);
|
||||
}
|
||||
|
|
@ -9,5 +9,7 @@ public interface ScalaProvider
|
|||
|
||||
public ClassLoader loader();
|
||||
public File[] jars();
|
||||
public File libraryJar();
|
||||
public File compilerJar();
|
||||
public AppProvider app(ApplicationID id);
|
||||
}
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
package xsbt
|
||||
package xsbt.boot
|
||||
|
||||
import java.io.File
|
||||
import java.util.Properties
|
||||
import xsbti._
|
||||
import org.specs._
|
||||
import LoadHelpers._
|
||||
import LaunchTest._
|
||||
|
||||
final class Main // needed so that when we test Launch, it doesn't think sbt was improperly downloaded (it looks for xsbt.Main to verify the right jar was downloaded)
|
||||
|
||||
|
|
@ -18,32 +19,44 @@ object ScalaProviderTest extends Specification
|
|||
}
|
||||
|
||||
"Launch" should {
|
||||
"Successfully load (stub) main sbt from local repository and run it with correct arguments" in {
|
||||
checkLoad(Array("test"), "xsbt.test.ArgumentTest").asInstanceOf[Exit].code must be(0)
|
||||
checkLoad(Array(), "xsbt.test.ArgumentTest") must throwA[RuntimeException]
|
||||
"Successfully load an application from local repository and run it with correct arguments" in {
|
||||
checkLoad(Array("test"), "xsbt.boot.test.ArgumentTest").asInstanceOf[Exit].code must be(0)
|
||||
checkLoad(Array(), "xsbt.boot.test.ArgumentTest") must throwA[RuntimeException]
|
||||
}
|
||||
"Successfully load (stub) main sbt from local repository and run it with correct sbt version" in {
|
||||
checkLoad(Array(), "xsbt.test.SbtVersionTest").asInstanceOf[Exit].code must be(0)
|
||||
"Successfully load an application from local repository and run it with correct sbt version" in {
|
||||
checkLoad(Array(), "xsbt.boot.test.AppVersionTest").asInstanceOf[Exit].code must be(0)
|
||||
}
|
||||
}
|
||||
|
||||
private def checkLoad(args: Array[String], mainClassName: String): MainResult =
|
||||
withLaunch { _.load(args, test.MainTest.SbtTestVersion, mainClassName, mapScalaVersion(getScalaVersion)) }
|
||||
|
||||
private def checkScalaLoader(version: String): Unit = withLaunch(checkLauncher(version, scalaVersionMap(version)))
|
||||
private def checkLauncher(version: String, versionValue: String)(launcher: ScalaProvider): Unit =
|
||||
private def checkLoad(arguments: Array[String], mainClassName: String): MainResult =
|
||||
FileUtilities.withTemporaryDirectory { currentDirectory =>
|
||||
withLauncher { launcher =>
|
||||
Launch.run(launcher)(
|
||||
RunConfiguration(mapScalaVersion(LaunchTest.getScalaVersion), LaunchTest.testApp(mainClassName).toID, currentDirectory, arguments, () => ())
|
||||
)
|
||||
}
|
||||
}
|
||||
private def checkScalaLoader(version: String): Unit = withLauncher( checkLauncher(version, scalaVersionMap(version)) )
|
||||
private def checkLauncher(version: String, versionValue: String)(launcher: Launcher): Unit =
|
||||
{
|
||||
val loader = launcher.getScalaLoader(version)
|
||||
val provider = launcher.getScala(version)
|
||||
val loader = provider.loader
|
||||
// ensure that this loader can load Scala classes by trying scala.ScalaObject.
|
||||
tryScala(loader)
|
||||
getScalaVersion(loader) must beEqualTo(versionValue)
|
||||
}
|
||||
private def tryScala(loader: ClassLoader): Unit = Class.forName("scala.ScalaObject", false, loader).getClassLoader must be(loader)
|
||||
}
|
||||
object LoadHelpers
|
||||
object LaunchTest
|
||||
{
|
||||
def withLaunch[T](f: Launcher => T): T =
|
||||
FileUtilities.withTemporaryDirectory { temp => f(new xsbt.boot.Launch(temp)) }
|
||||
def testApp(main: String) = Application("org.scala-tools.sbt", "launch-test", Version.Explicit(test.MainTest.Version), main, Nil, false)
|
||||
import Repository.Predefined._
|
||||
def testRepositories = Seq(Local, ScalaToolsReleases, ScalaToolsSnapshots).map(Repository.Predefined.apply)
|
||||
def withLauncher[T](f: xsbti.Launcher => T): T =
|
||||
FileUtilities.withTemporaryDirectory { bootDirectory =>
|
||||
f(new Launch(bootDirectory, testRepositories))
|
||||
}
|
||||
|
||||
def mapScalaVersion(versionNumber: String) = scalaVersionMap.find(_._2 == versionNumber).getOrElse {
|
||||
error("Scala version number " + versionNumber + " from library.properties has no mapping")}._1
|
||||
val scalaVersionMap = Map("2.7.2" -> "2.7.2") ++ Seq("2.7.3", "2.7.4", "2.7.5").map(v => (v, v + ".final"))
|
||||
|
|
@ -56,29 +69,28 @@ object LoadHelpers
|
|||
properties.getProperty("version.number")
|
||||
}
|
||||
}
|
||||
|
||||
package test
|
||||
{
|
||||
object MainTest
|
||||
{
|
||||
val SbtTestVersion = "test-0.7" // keep in sync with LauncherProject in the XSbt project definition
|
||||
val Version = "test-" + xsbti.Versions.Sbt
|
||||
}
|
||||
import MainTest.SbtTestVersion
|
||||
class Exit(val code: Int) extends xsbti.Exit
|
||||
final class MainException(message: String) extends RuntimeException(message)
|
||||
final class ArgumentTest extends SbtMain
|
||||
final class ArgumentTest extends AppMain
|
||||
{
|
||||
def run(configuration: SbtConfiguration) =
|
||||
def run(configuration: xsbti.AppConfiguration) =
|
||||
if(configuration.arguments.length == 0)
|
||||
throw new MainException("Arguments were empty")
|
||||
else
|
||||
new xsbt.boot.Exit(0)
|
||||
new Exit(0)
|
||||
}
|
||||
class SbtVersionTest extends SbtMain
|
||||
class AppVersionTest extends AppMain
|
||||
{
|
||||
def run(configuration: SbtConfiguration) =
|
||||
if(configuration.sbtVersion == SbtTestVersion)
|
||||
new xsbt.boot.Exit(0)
|
||||
def run(configuration: xsbti.AppConfiguration) =
|
||||
if(configuration.provider.id.version == MainTest.Version)
|
||||
new Exit(0)
|
||||
else
|
||||
throw new MainException("sbt version was " + configuration.sbtVersion + ", expected: " + SbtTestVersion)
|
||||
throw new MainException("app version was " + configuration.provider.id.version + ", expected: " + MainTest.Version)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
package xsbt
|
||||
|
||||
import xsbti.{Exit => IExit, MainResult, SbtConfiguration, SbtMain}
|
||||
|
||||
class Main extends xsbti.SbtMain
|
||||
class Main extends xsbti.AppMain
|
||||
{
|
||||
def run(configuration: SbtConfiguration): MainResult =
|
||||
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
|
||||
{
|
||||
println(configuration.arguments.mkString("\n"))
|
||||
Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
final case class Exit(code: Int) extends IExit
|
||||
final case class Exit(code: Int) extends xsbti.Exit
|
||||
16
notes
16
notes
|
|
@ -11,8 +11,6 @@ Task engine
|
|||
- unnamed tasks log to parent task
|
||||
- in parallel, optionally one task always logging
|
||||
|
||||
- boot interface contains static final int version = N that main xsbt can use to check if it can be loaded by that version (a lower bound check)
|
||||
- main xsbt has static final int version = N that boot can use to check if it can load that version (a lower bound check)
|
||||
- Have Interfaces subproject that depends on no other project and defines interfaces in package xsbti. They are written in Java and cannot refer to Scala classes (compileOrder = JavaThenScala). These interfaces are loaded by the root loader and can be used to pass objects across ClassLoader boundaries.
|
||||
- launcher/main interface is not static (no system properties!)
|
||||
- simple, well-defined ClassLoaders
|
||||
|
|
@ -26,18 +24,10 @@ Task engine
|
|||
- minimal dependence on main xsbt logger from subcomponents: use thin interface for subcomponents and implement interface in separate files in main xsbt
|
||||
|
||||
Dependency Management
|
||||
- drop explicit managers
|
||||
- resolvers are completely defined in project definition (use Resolver.withDefaultResolvers)
|
||||
- configurations completely defined within project (use ModuleConfiguration.configurations)
|
||||
|
||||
Launcher
|
||||
- generalize to be able to launch any conforming application
|
||||
- default configuration file in jar- can be replaced in jar or overridden on command line
|
||||
- format:
|
||||
scala.version=versionSpecification
|
||||
main.org=ID
|
||||
main.name=ID
|
||||
main.version=versionSpecification
|
||||
main.components=ID (',' ID)*
|
||||
repo=id ',' url [',' pattern]
|
||||
versionSpecification := ( ('read'|'prompt'|'readOrPrompt') [default] ) |version
|
||||
- see launch.specification
|
||||
- boot interface contains static final int version = N that main xsbt can use to check if it can be loaded by that version (a lower bound check)
|
||||
- main xsbt has static final int version = N that boot can use to check if it can load that version (a lower bound check)
|
||||
|
|
@ -14,7 +14,7 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
|||
val ioSub = project(utilPath / "io", "IO", new IOProject(_), controlSub)
|
||||
val classpathSub = project(utilPath / "classpath", "Classpath", new Base(_))
|
||||
|
||||
val ivySub = project("ivy", "Ivy", new IvyProject(_), interfaceSub)
|
||||
val ivySub = project("ivy", "Ivy", new IvyProject(_), interfaceSub, launchInterfaceSub)
|
||||
val logSub = project(utilPath / "log", "Logging", new Base(_), interfaceSub)
|
||||
|
||||
val compileInterfaceSub = project(compilePath / "interface", "Compiler Interface", new CompilerInterfaceProject(_), interfaceSub)
|
||||
|
|
@ -64,21 +64,22 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
|||
val jline = "jline" % "jline" % "0.9.94"
|
||||
val ivy = "org.apache.ivy" % "ivy" % "2.0.0"
|
||||
def rawJarPath = jarPath
|
||||
override final def crossScalaVersions = Set.empty // don't need to cross-build, since the distributed jar is standalone (proguard)
|
||||
lazy val rawPackage = packageTask(packagePaths +++ launchInterfaceSub.packagePaths, rawJarPath, packageOptions).dependsOn(compile)
|
||||
// to test the retrieving and loading of the main sbt, we package and publish the test classes to the local repository
|
||||
override def defaultMainArtifact = Artifact(idWithVersion)
|
||||
override def projectID = ModuleID(organization, idWithVersion, "test-" + version)
|
||||
override def packageAction = packageTask(packageTestPaths, outputPath / (idWithVersion + "-" + projectID.revision +".jar"), packageOptions).dependsOn(rawTestCompile)
|
||||
override def defaultMainArtifact = Artifact(testID)
|
||||
override def projectID = ModuleID(organization, testID, "test-" + version)
|
||||
override def packageAction = packageTask(packageTestPaths, outputPath / (testID + "-" + projectID.revision +".jar"), packageOptions).dependsOn(rawTestCompile)
|
||||
override def deliverProjectDependencies = Nil
|
||||
def idWithVersion = "xsbt_" + ScalaVersion.currentString
|
||||
lazy val rawTestCompile = super.testCompileAction
|
||||
def testID = "launch-test"
|
||||
override def testClasspath = super.testClasspath +++ interfaceSub.compileClasspath
|
||||
lazy val rawTestCompile = super.testCompileAction dependsOn(interfaceSub.compile)
|
||||
override def testCompileAction = publishLocal dependsOn(rawTestCompile)
|
||||
}
|
||||
trait TestDependencies extends Project
|
||||
{
|
||||
val sc = "org.scala-tools.testing" % "scalacheck" % "1.5" % "test->default"
|
||||
val sp = "org.scala-tools.testing" % "specs" % "1.5.0" % "test->default"
|
||||
val ju = "junit" % "junit" % "4.5" % "test->default" // required by specs to compile properly
|
||||
val sp = "org.scala-tools.testing" % "specs" % "1.6.0" % "test->default"
|
||||
}
|
||||
class StandardTaskProject(info: ProjectInfo) extends Base(info)
|
||||
{
|
||||
|
|
@ -97,15 +98,15 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
|||
override def scratch = true
|
||||
override def consoleClasspath = testClasspath
|
||||
}
|
||||
class CompileProject(info: ProjectInfo) extends Base(info) with TestWithLog
|
||||
class CompileProject(info: ProjectInfo) extends Base(info) with TestWithLog with TestWithLaunch
|
||||
{
|
||||
override def testCompileAction = super.testCompileAction dependsOn(launchSub.testCompile, compileInterfaceSub.`package`, interfaceSub.`package`)
|
||||
override def testCompileAction = super.testCompileAction dependsOn(compileInterfaceSub.`package`, interfaceSub.`package`)
|
||||
// don't include launch interface in published dependencies because it will be provided by launcher
|
||||
override def deliverProjectDependencies = Set(super.deliverProjectDependencies.toSeq : _*) - launchInterfaceSub.projectID
|
||||
override def testClasspath = super.testClasspath +++ launchSub.testClasspath +++ compileInterfaceSub.jarPath +++ interfaceSub.jarPath --- compilerInterfaceClasspath
|
||||
override def testClasspath = super.testClasspath +++ compileInterfaceSub.jarPath +++ interfaceSub.jarPath --- compilerInterfaceClasspath
|
||||
override def compileOptions = super.compileOptions ++ Seq(CompileOption("-Xno-varargs-conversion")) //needed for invoking nsc.scala.tools.Main.process(Array[String])
|
||||
}
|
||||
class IvyProject(info: ProjectInfo) extends Base(info) with TestWithIO with TestWithLog
|
||||
class IvyProject(info: ProjectInfo) extends Base(info) with TestWithIO with TestWithLog with TestWithLaunch
|
||||
{
|
||||
val ivy = "org.apache.ivy" % "ivy" % "2.0.0"
|
||||
}
|
||||
|
|
@ -122,16 +123,25 @@ class XSbt(info: ProjectInfo) extends ParentProject(info)
|
|||
def xTestClasspath = projectClasspath(Configurations.Test)
|
||||
override def componentID = Some("compiler-interface-src")
|
||||
}
|
||||
trait TestWithIO extends BasicScalaProject
|
||||
{
|
||||
// use IO from tests
|
||||
override def testCompileAction = super.testCompileAction dependsOn(ioSub.testCompile)
|
||||
override def testClasspath = super.testClasspath +++ ioSub.testClasspath
|
||||
trait TestWithIO extends TestWith {
|
||||
override def testWithTestClasspath = super.testWithTestClasspath ++ Seq(ioSub)
|
||||
}
|
||||
trait TestWithLog extends BasicScalaProject
|
||||
trait TestWithLaunch extends TestWith {
|
||||
override def testWithTestClasspath = super.testWithTestClasspath ++ Seq(launchSub)
|
||||
}
|
||||
trait TestWithLog extends TestWith {
|
||||
override def testWithCompileClasspath = super.testWithCompileClasspath ++ Seq(logSub)
|
||||
}
|
||||
trait TestWith extends BasicScalaProject
|
||||
{
|
||||
override def testCompileAction = super.testCompileAction dependsOn(logSub.compile)
|
||||
override def testClasspath = super.testClasspath +++ logSub.compileClasspath
|
||||
def testWithCompileClasspath: Seq[BasicScalaProject] = Nil
|
||||
def testWithTestClasspath: Seq[BasicScalaProject] = Nil
|
||||
override def testCompileAction = super.testCompileAction dependsOn((testWithTestClasspath.map(_.testCompile) ++ testWithCompileClasspath.map(_.compile)) : _*)
|
||||
override def testClasspath = (super.testClasspath /: (testWithTestClasspath.map(_.testClasspath) ++ testWithCompileClasspath.map(_.compileClasspath) ))(_ +++ _)
|
||||
}
|
||||
trait WithLauncherInterface extends BasicScalaProject
|
||||
{
|
||||
override def deliverProjectDependencies = super.deliverProjectDependencies.toList - launchInterfaceSub.projectID
|
||||
}
|
||||
}
|
||||
trait JavaProject extends BasicScalaProject
|
||||
|
|
@ -148,7 +158,7 @@ trait SourceProject extends BasicScalaProject
|
|||
}
|
||||
trait ManagedBase extends BasicScalaProject
|
||||
{
|
||||
override def deliverScalaDependencies = Nil //
|
||||
override def deliverScalaDependencies = Nil
|
||||
override def crossScalaVersions = Set("2.7.5")
|
||||
override def managedStyle = ManagedStyle.Ivy
|
||||
override def useDefaultConfigurations = false
|
||||
|
|
|
|||
Loading…
Reference in New Issue