mirror of https://github.com/sbt/sbt.git
Initial xsbt commit
This commit is contained in:
commit
43a299bc3f
|
|
@ -0,0 +1,100 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009 Mark Harrah
|
||||
*/
|
||||
package xsbt
|
||||
|
||||
import org.apache.ivy.{core,plugins}
|
||||
import core.module.id.ModuleRevisionId
|
||||
import plugins.resolver.{ChainResolver, DependencyResolver, IBiblioResolver}
|
||||
import plugins.resolver.{AbstractPatternsBasedResolver, AbstractSshBasedResolver, FileSystemResolver, SFTPResolver, SshResolver, URLResolver}
|
||||
|
||||
private object ConvertResolver
|
||||
{
|
||||
/** Converts the given sbt resolver into an Ivy resolver..*/
|
||||
def apply(r: Resolver) =
|
||||
{
|
||||
r match
|
||||
{
|
||||
case repo: MavenRepository =>
|
||||
{
|
||||
val resolver = new IBiblioResolver
|
||||
initializeMavenStyle(resolver, repo.name, repo.root)
|
||||
resolver
|
||||
}
|
||||
case JavaNet1Repository =>
|
||||
{
|
||||
// Thanks to Matthias Pfau for posting how to use the Maven 1 repository on java.net with Ivy:
|
||||
// http://www.nabble.com/Using-gradle-Ivy-with-special-maven-repositories-td23775489.html
|
||||
val resolver = new IBiblioResolver { override def convertM2IdForResourceSearch(mrid: ModuleRevisionId) = mrid }
|
||||
initializeMavenStyle(resolver, JavaNet1Repository.name, "http://download.java.net/maven/1/")
|
||||
resolver.setPattern("[organisation]/[ext]s/[module]-[revision](-[classifier]).[ext]")
|
||||
resolver
|
||||
}
|
||||
case repo: SshRepository =>
|
||||
{
|
||||
val resolver = new SshResolver
|
||||
initializeSSHResolver(resolver, repo)
|
||||
repo.publishPermissions.foreach(perm => resolver.setPublishPermissions(perm))
|
||||
resolver
|
||||
}
|
||||
case repo: SftpRepository =>
|
||||
{
|
||||
val resolver = new SFTPResolver
|
||||
initializeSSHResolver(resolver, repo)
|
||||
resolver
|
||||
}
|
||||
case repo: FileRepository =>
|
||||
{
|
||||
val resolver = new FileSystemResolver
|
||||
resolver.setName(repo.name)
|
||||
initializePatterns(resolver, repo.patterns)
|
||||
import repo.configuration.{isLocal, isTransactional}
|
||||
resolver.setLocal(isLocal)
|
||||
isTransactional.foreach(value => resolver.setTransactional(value.toString))
|
||||
resolver
|
||||
}
|
||||
case repo: URLRepository =>
|
||||
{
|
||||
val resolver = new URLResolver
|
||||
resolver.setName(repo.name)
|
||||
initializePatterns(resolver, repo.patterns)
|
||||
resolver
|
||||
}
|
||||
}
|
||||
}
|
||||
private def initializeMavenStyle(resolver: IBiblioResolver, name: String, root: String)
|
||||
{
|
||||
resolver.setName(name)
|
||||
resolver.setM2compatible(true)
|
||||
resolver.setRoot(root)
|
||||
}
|
||||
private def initializeSSHResolver(resolver: AbstractSshBasedResolver, repo: SshBasedRepository)
|
||||
{
|
||||
resolver.setName(repo.name)
|
||||
resolver.setPassfile(null)
|
||||
initializePatterns(resolver, repo.patterns)
|
||||
initializeConnection(resolver, repo.connection)
|
||||
}
|
||||
private def initializeConnection(resolver: AbstractSshBasedResolver, connection: RepositoryHelpers.SshConnection)
|
||||
{
|
||||
import resolver._
|
||||
import connection._
|
||||
hostname.foreach(setHost)
|
||||
port.foreach(setPort)
|
||||
authentication foreach
|
||||
{
|
||||
case RepositoryHelpers.PasswordAuthentication(user, password) =>
|
||||
setUser(user)
|
||||
setUserPassword(password)
|
||||
case RepositoryHelpers.KeyFileAuthentication(file, password) =>
|
||||
setKeyFile(file)
|
||||
setKeyFilePassword(password)
|
||||
}
|
||||
}
|
||||
private def initializePatterns(resolver: AbstractPatternsBasedResolver, patterns: RepositoryHelpers.Patterns)
|
||||
{
|
||||
resolver.setM2compatible(patterns.isMavenCompatible)
|
||||
patterns.ivyPatterns.foreach(resolver.addIvyPattern)
|
||||
patterns.artifactPatterns.foreach(resolver.addArtifactPattern)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009 Mark Harrah
|
||||
*/
|
||||
package xsbt
|
||||
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.net.URL
|
||||
|
||||
import org.apache.ivy.{core, plugins}
|
||||
import core.module.descriptor.{DefaultDependencyDescriptor, DefaultModuleDescriptor}
|
||||
import core.settings.IvySettings
|
||||
import plugins.parser.xml.XmlModuleDescriptorParser
|
||||
import plugins.repository.Resource
|
||||
import plugins.repository.url.URLResource
|
||||
|
||||
/** Subclasses the default Ivy file parser in order to provide access to protected methods.*/
|
||||
private object CustomXmlParser extends XmlModuleDescriptorParser with NotNull
|
||||
{
|
||||
import XmlModuleDescriptorParser.Parser
|
||||
class CustomParser(settings: IvySettings) extends Parser(CustomXmlParser, settings) with NotNull
|
||||
{
|
||||
def setSource(url: URL) =
|
||||
{
|
||||
super.setResource(new URLResource(url))
|
||||
super.setInput(url)
|
||||
}
|
||||
def setInput(bytes: Array[Byte]) { setInput(new ByteArrayInputStream(bytes)) }
|
||||
/** Overridden because the super implementation overwrites the module descriptor.*/
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009 Mark Harrah
|
||||
*/
|
||||
package xsbt
|
||||
|
||||
import Artifact.{defaultExtension, defaultType}
|
||||
|
||||
import java.io.File
|
||||
|
||||
import org.apache.ivy.{core, plugins, util, Ivy}
|
||||
import core.cache.DefaultRepositoryCacheManager
|
||||
import core.module.descriptor.{DefaultArtifact, DefaultDependencyArtifactDescriptor, MDArtifact}
|
||||
import core.module.descriptor.{DefaultDependencyDescriptor, DefaultModuleDescriptor, ModuleDescriptor}
|
||||
import core.module.id.{ArtifactId,ModuleId, ModuleRevisionId}
|
||||
import core.settings.IvySettings
|
||||
import plugins.matcher.PatternMatcher
|
||||
import plugins.parser.m2.PomModuleDescriptorParser
|
||||
import plugins.resolver.ChainResolver
|
||||
import util.Message
|
||||
|
||||
final class IvySbt(configuration: IvyConfiguration)
|
||||
{
|
||||
import configuration._
|
||||
/** ========== Configuration/Setup ============
|
||||
* This part configures the Ivy instance by first creating the logger interface to ivy, then IvySettings, and then the Ivy instance.
|
||||
* These are lazy so that they are loaded within the right context. This is important so that no Ivy XML configuration needs to be loaded,
|
||||
* saving some time. This is necessary because Ivy has global state (IvyContext, Message, DocumentBuilder, ...).
|
||||
*/
|
||||
private lazy val logger = new IvyLoggerInterface(log)
|
||||
private def withDefaultLogger[T](f: => T): T =
|
||||
IvySbt.synchronized // Ivy is not thread-safe. In particular, it uses a static DocumentBuilder, which is not thread-safe
|
||||
{
|
||||
val originalLogger = Message.getDefaultLogger
|
||||
Message.setDefaultLogger(logger)
|
||||
try { f }
|
||||
finally { Message.setDefaultLogger(originalLogger) }
|
||||
}
|
||||
private lazy val settings =
|
||||
{
|
||||
val is = new IvySettings
|
||||
is.setBaseDir(paths.baseDirectory)
|
||||
IvySbt.configureCache(is, paths.cacheDirectory)
|
||||
if(resolvers.isEmpty)
|
||||
autodetectConfiguration(is)
|
||||
else
|
||||
IvySbt.setResolvers(is, resolvers, log)
|
||||
is
|
||||
}
|
||||
private lazy val ivy =
|
||||
{
|
||||
val i = Ivy.newInstance(settings)
|
||||
i.getLoggerEngine.pushLogger(logger)
|
||||
i
|
||||
}
|
||||
/** Called to configure Ivy when inline resolvers are not specified.
|
||||
* This will configure Ivy with an 'ivy-settings.xml' file if there is one or else use default resolvers.*/
|
||||
private def autodetectConfiguration(settings: IvySettings)
|
||||
{
|
||||
log.debug("Autodetecting configuration.")
|
||||
val defaultIvyConfigFile = IvySbt.defaultIvyConfiguration(paths.baseDirectory)
|
||||
if(defaultIvyConfigFile.canRead)
|
||||
settings.load(defaultIvyConfigFile)
|
||||
else
|
||||
IvySbt.setResolvers(settings, Resolver.withDefaultResolvers(Nil), log)
|
||||
}
|
||||
/** ========== End Configuration/Setup ============*/
|
||||
|
||||
/** Uses the configured Ivy instance within a safe context.*/
|
||||
def withIvy[T](f: Ivy => T): T =
|
||||
withDefaultLogger
|
||||
{
|
||||
ivy.pushContext()
|
||||
try { f(ivy) }
|
||||
finally { ivy.popContext() }
|
||||
}
|
||||
|
||||
final class Module(val moduleConfiguration: ModuleConfiguration) extends NotNull
|
||||
{
|
||||
def logger = configuration.log
|
||||
def withModule[T](f: (Ivy,DefaultModuleDescriptor,String) => T): T =
|
||||
withIvy[T] { ivy => f(ivy, moduleDescriptor, defaultConfig) }
|
||||
|
||||
import moduleConfiguration._
|
||||
private lazy val (moduleDescriptor: DefaultModuleDescriptor, defaultConfig: String) =
|
||||
{
|
||||
val (baseModule, baseConfiguration) =
|
||||
if(isUnconfigured)
|
||||
autodetectDependencies(IvySbt.toID(module))
|
||||
else
|
||||
configureModule
|
||||
ivyScala.foreach(IvyScala.checkModule(baseModule, baseConfiguration))
|
||||
baseModule.getExtraAttributesNamespaces.asInstanceOf[java.util.Map[String,String]].put("m", "m")
|
||||
(baseModule, baseConfiguration)
|
||||
}
|
||||
private def configureModule =
|
||||
{
|
||||
val moduleID = newConfiguredModuleID
|
||||
val defaultConf = defaultConfiguration getOrElse Configurations.config(ModuleDescriptor.DEFAULT_CONFIGURATION)
|
||||
log.debug("Using inline dependencies specified in Scala" + (if(ivyXML.isEmpty) "." else " and XML."))
|
||||
|
||||
val parser = IvySbt.parseIvyXML(ivy.getSettings, IvySbt.wrapped(module, ivyXML), moduleID, defaultConf.name, validate)
|
||||
|
||||
IvySbt.addArtifacts(moduleID, artifacts)
|
||||
IvySbt.addDependencies(moduleID, dependencies, parser)
|
||||
IvySbt.addMainArtifact(moduleID)
|
||||
(moduleID, parser.getDefaultConf)
|
||||
}
|
||||
private def newConfiguredModuleID =
|
||||
{
|
||||
val mod = new DefaultModuleDescriptor(IvySbt.toID(module), "release", null, false)
|
||||
mod.setLastModified(System.currentTimeMillis)
|
||||
configurations.foreach(config => mod.addConfiguration(IvySbt.toIvyConfiguration(config)))
|
||||
mod
|
||||
}
|
||||
|
||||
/** Parses the given Maven pom 'pomFile'.*/
|
||||
private def readPom(pomFile: File) =
|
||||
{
|
||||
val md = PomModuleDescriptorParser.getInstance.parseDescriptor(settings, toURL(pomFile), validate)
|
||||
(IvySbt.toDefaultModuleDescriptor(md), "compile")
|
||||
}
|
||||
/** Parses the given Ivy file 'ivyFile'.*/
|
||||
private def readIvyFile(ivyFile: File) =
|
||||
{
|
||||
val url = toURL(ivyFile)
|
||||
val parser = new CustomXmlParser.CustomParser(settings)
|
||||
parser.setValidate(validate)
|
||||
parser.setSource(url)
|
||||
parser.parse()
|
||||
val md = parser.getModuleDescriptor()
|
||||
(IvySbt.toDefaultModuleDescriptor(md), parser.getDefaultConf)
|
||||
}
|
||||
private def toURL(file: File) = file.toURI.toURL
|
||||
/** Called to determine dependencies when the dependency manager is SbtManager and no inline dependencies (Scala or XML)
|
||||
* are defined. It will try to read from pom.xml first and then ivy.xml if pom.xml is not found. If neither is found,
|
||||
* Ivy is configured with defaults.*/
|
||||
private def autodetectDependencies(module: ModuleRevisionId) =
|
||||
{
|
||||
log.debug("Autodetecting dependencies.")
|
||||
val defaultPOMFile = IvySbt.defaultPOM(paths.baseDirectory)
|
||||
if(defaultPOMFile.canRead)
|
||||
readPom(defaultPOMFile)
|
||||
else
|
||||
{
|
||||
val defaultIvy = IvySbt.defaultIvyFile(paths.baseDirectory)
|
||||
if(defaultIvy.canRead)
|
||||
readIvyFile(defaultIvy)
|
||||
else
|
||||
{
|
||||
val defaultConf = ModuleDescriptor.DEFAULT_CONFIGURATION
|
||||
log.warn("No dependency configuration found, using defaults.")
|
||||
val moduleID = DefaultModuleDescriptor.newDefaultInstance(module)
|
||||
IvySbt.addMainArtifact(moduleID)
|
||||
IvySbt.addDefaultArtifact(defaultConf, moduleID)
|
||||
(moduleID, defaultConf)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object IvySbt
|
||||
{
|
||||
val DefaultIvyConfigFilename = "ivysettings.xml"
|
||||
val DefaultIvyFilename = "ivy.xml"
|
||||
val DefaultMavenFilename = "pom.xml"
|
||||
|
||||
private def defaultIvyFile(project: File) = new File(project, DefaultIvyFilename)
|
||||
private def defaultIvyConfiguration(project: File) = new File(project, DefaultIvyConfigFilename)
|
||||
private def defaultPOM(project: File) = new File(project, DefaultMavenFilename)
|
||||
|
||||
/** Sets the resolvers for 'settings' to 'resolvers'. This is done by creating a new chain and making it the default. */
|
||||
private def setResolvers(settings: IvySettings, resolvers: Seq[Resolver], log: IvyLogger)
|
||||
{
|
||||
val newDefault = new ChainResolver
|
||||
newDefault.setName("sbt-chain")
|
||||
newDefault.setReturnFirst(true)
|
||||
newDefault.setCheckmodified(true)
|
||||
resolvers.foreach(r => newDefault.add(ConvertResolver(r)))
|
||||
settings.addResolver(newDefault)
|
||||
settings.setDefaultResolver(newDefault.getName)
|
||||
log.debug("Using repositories:\n" + resolvers.mkString("\n\t"))
|
||||
}
|
||||
private def configureCache(settings: IvySettings, dir: Option[File])
|
||||
{
|
||||
val cacheDir = dir.getOrElse(settings.getDefaultRepositoryCacheBasedir())
|
||||
val manager = new DefaultRepositoryCacheManager("default-cache", settings, cacheDir)
|
||||
manager.setUseOrigin(true)
|
||||
manager.setChangingMatcher(PatternMatcher.REGEXP);
|
||||
manager.setChangingPattern(".*-SNAPSHOT");
|
||||
settings.setDefaultRepositoryCacheManager(manager)
|
||||
}
|
||||
private def toIvyConfiguration(configuration: Configuration) =
|
||||
{
|
||||
import org.apache.ivy.core.module.descriptor.{Configuration => IvyConfig}
|
||||
import IvyConfig.Visibility._
|
||||
import configuration._
|
||||
new IvyConfig(name, if(isPublic) PUBLIC else PRIVATE, description, extendsConfigs.map(_.name).toArray, transitive, null)
|
||||
}
|
||||
private def addDefaultArtifact(defaultConf: String, moduleID: DefaultModuleDescriptor) =
|
||||
moduleID.addArtifact(defaultConf, new MDArtifact(moduleID, moduleID.getModuleRevisionId.getName, defaultType, defaultExtension))
|
||||
/** Adds the ivy.xml main artifact. */
|
||||
private def addMainArtifact(moduleID: DefaultModuleDescriptor)
|
||||
{
|
||||
val artifact = DefaultArtifact.newIvyArtifact(moduleID.getResolvedModuleRevisionId, moduleID.getPublicationDate)
|
||||
moduleID.setModuleArtifact(artifact)
|
||||
moduleID.check()
|
||||
}
|
||||
/** Converts the given sbt module id into an Ivy ModuleRevisionId.*/
|
||||
private def toID(m: ModuleID) =
|
||||
{
|
||||
import m._
|
||||
ModuleRevisionId.newInstance(organization, name, revision)
|
||||
}
|
||||
private def toIvyArtifact(moduleID: ModuleDescriptor, a: Artifact, configurations: Iterable[String]): MDArtifact =
|
||||
{
|
||||
val artifact = new MDArtifact(moduleID, a.name, a.`type`, a.extension, null, extra(a))
|
||||
configurations.foreach(artifact.addConfiguration)
|
||||
artifact
|
||||
}
|
||||
private def extra(artifact: Artifact) = artifact.classifier.map(c => javaMap("m:classifier" -> c)).getOrElse(null)
|
||||
|
||||
private object javaMap
|
||||
{
|
||||
import java.util.{HashMap, Map}
|
||||
def apply[K,V](pairs: (K,V)*): Map[K,V] =
|
||||
{
|
||||
val map = new HashMap[K,V]
|
||||
pairs.foreach { case (key, value) => map.put(key, value) }
|
||||
map
|
||||
}
|
||||
}
|
||||
/** Creates a full ivy file for 'module' using the 'content' XML as the part after the <info>...</info> section. */
|
||||
private def wrapped(module: ModuleID, content: scala.xml.NodeSeq) =
|
||||
{
|
||||
import module._
|
||||
<ivy-module version="2.0">
|
||||
<info organisation={organization} module={name} revision={revision}/>
|
||||
{content}
|
||||
</ivy-module>
|
||||
}
|
||||
/** Parses the given in-memory Ivy file 'xml', using the existing 'moduleID' and specifying the given 'defaultConfiguration'. */
|
||||
private def parseIvyXML(settings: IvySettings, xml: scala.xml.NodeSeq, moduleID: DefaultModuleDescriptor, defaultConfiguration: String, validate: Boolean): CustomXmlParser.CustomParser =
|
||||
parseIvyXML(settings, xml.toString, moduleID, defaultConfiguration, validate)
|
||||
/** 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)
|
||||
parser.setMd(moduleID)
|
||||
parser.setDefaultConf(defaultConfiguration)
|
||||
parser.setValidate(validate)
|
||||
parser.setInput(xml.getBytes)
|
||||
parser.parse()
|
||||
parser
|
||||
}
|
||||
|
||||
/** This method is used to add inline dependencies to the provided module. */
|
||||
def addDependencies(moduleID: DefaultModuleDescriptor, dependencies: Iterable[ModuleID], parser: CustomXmlParser.CustomParser)
|
||||
{
|
||||
for(dependency <- dependencies)
|
||||
{
|
||||
val dependencyDescriptor = new DefaultDependencyDescriptor(moduleID, toID(dependency), false, dependency.isChanging, dependency.isTransitive)
|
||||
dependency.configurations match
|
||||
{
|
||||
case None => // The configuration for this dependency was not explicitly specified, so use the default
|
||||
parser.parseDepsConfs(parser.getDefaultConf, dependencyDescriptor)
|
||||
case Some(confs) => // The configuration mapping (looks like: test->default) was specified for this dependency
|
||||
parser.parseDepsConfs(confs, dependencyDescriptor)
|
||||
}
|
||||
for(artifact <- dependency.explicitArtifacts)
|
||||
{
|
||||
import artifact.{name, classifier, `type`, extension, url}
|
||||
val extraMap = extra(artifact)
|
||||
val ivyArtifact = new DefaultDependencyArtifactDescriptor(dependencyDescriptor, name, `type`, extension, url.getOrElse(null), extraMap)
|
||||
for(conf <- dependencyDescriptor.getModuleConfigurations)
|
||||
dependencyDescriptor.addDependencyArtifact(conf, ivyArtifact)
|
||||
}
|
||||
moduleID.addDependency(dependencyDescriptor)
|
||||
}
|
||||
}
|
||||
/** This method is used to add inline artifacts to the provided module. */
|
||||
def addArtifacts(moduleID: DefaultModuleDescriptor, artifacts: Iterable[Artifact])
|
||||
{
|
||||
val allConfigurations = moduleID.getPublicConfigurationsNames
|
||||
for(artifact <- artifacts)
|
||||
{
|
||||
val configurationStrings =
|
||||
{
|
||||
val artifactConfigurations = artifact.configurations
|
||||
if(artifactConfigurations.isEmpty)
|
||||
allConfigurations
|
||||
else
|
||||
artifactConfigurations.map(_.name)
|
||||
}
|
||||
val ivyArtifact = toIvyArtifact(moduleID, artifact, configurationStrings)
|
||||
configurationStrings.foreach(configuration => moduleID.addArtifact(configuration, ivyArtifact))
|
||||
}
|
||||
}
|
||||
/** This code converts the given ModuleDescriptor to a DefaultModuleDescriptor by casting or generating an error.
|
||||
* Ivy 2.0.0 always produces a DefaultModuleDescriptor. */
|
||||
private def toDefaultModuleDescriptor(md: ModuleDescriptor) =
|
||||
md match
|
||||
{
|
||||
case dmd: DefaultModuleDescriptor => dmd
|
||||
case _ => error("Unknown ModuleDescriptor type.")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
package xsbt
|
||||
|
||||
import java.io.File
|
||||
|
||||
import org.apache.ivy.{core, plugins, util, Ivy}
|
||||
import core.cache.DefaultRepositoryCacheManager
|
||||
import core.LogOptions
|
||||
import core.deliver.DeliverOptions
|
||||
import core.module.descriptor.{DefaultArtifact, DefaultDependencyArtifactDescriptor, MDArtifact}
|
||||
import core.module.descriptor.{DefaultDependencyDescriptor, DefaultModuleDescriptor, DependencyDescriptor, ModuleDescriptor}
|
||||
import core.module.id.{ArtifactId,ModuleId, ModuleRevisionId}
|
||||
import core.publish.PublishOptions
|
||||
import core.resolve.ResolveOptions
|
||||
import core.retrieve.RetrieveOptions
|
||||
import plugins.parser.m2.{PomModuleDescriptorParser,PomModuleDescriptorWriter}
|
||||
|
||||
final class UpdateConfiguration(val retrieveDirectory: File, val outputPattern: String, val synchronize: Boolean, val quiet: Boolean) extends NotNull
|
||||
|
||||
object IvyActions
|
||||
{
|
||||
/** Clears the Ivy cache, as configured by 'config'. */
|
||||
def cleanCache(ivy: IvySbt) = ivy.withIvy { _.getSettings.getRepositoryCacheManagers.foreach(_.clean()) }
|
||||
|
||||
/** Creates a Maven pom from the given Ivy configuration*/
|
||||
def makePom(module: IvySbt#Module, extraDependencies: Iterable[ModuleID], configurations: Option[Iterable[Configuration]], output: File)
|
||||
{
|
||||
module.withModule { (ivy, md, default) =>
|
||||
addLateDependencies(ivy, md, default, extraDependencies)
|
||||
val pomModule = keepConfigurations(md, configurations)
|
||||
PomModuleDescriptorWriter.write(pomModule, DefaultConfigurationMapping, output)
|
||||
module.logger.info("Wrote " + output.getAbsolutePath)
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
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]]) =
|
||||
configurations match
|
||||
{
|
||||
case Some(confs) => confs.map(_.name).toList.toArray
|
||||
case None => module.getPublicConfigurationsNames
|
||||
}
|
||||
/** Retain dependencies only with the configurations given, or all public configurations of `module` if `configurations` is None.
|
||||
* This currently only preserves the information required by makePom*/
|
||||
private def keepConfigurations(module: ModuleDescriptor, configurations: Option[Iterable[Configuration]]): ModuleDescriptor =
|
||||
{
|
||||
val keepConfigurations = getConfigurations(module, configurations)
|
||||
val keepSet = Set(keepConfigurations.toSeq : _*)
|
||||
def translate(dependency: DependencyDescriptor) =
|
||||
{
|
||||
val keep = dependency.getModuleConfigurations.filter(keepSet.contains)
|
||||
if(keep.isEmpty)
|
||||
None
|
||||
else // TODO: translate the dependency to contain only configurations to keep
|
||||
Some(dependency)
|
||||
}
|
||||
val newModule = new DefaultModuleDescriptor(module.getModuleRevisionId, "", null)
|
||||
newModule.setHomePage(module.getHomePage)
|
||||
for(dependency <- module.getDependencies; translated <- translate(dependency))
|
||||
newModule.addDependency(translated)
|
||||
newModule
|
||||
}
|
||||
|
||||
def deliver(module: IvySbt#Module, status: String, deliverIvyPattern: String, extraDependencies: Iterable[ModuleID], configurations: Option[Iterable[Configuration]], quiet: Boolean)
|
||||
{
|
||||
module.withModule { case (ivy, md, default) =>
|
||||
addLateDependencies(ivy, md, default, extraDependencies)
|
||||
resolve(quiet)(ivy, md, default) // todo: set download = false for resolve
|
||||
val revID = md.getModuleRevisionId
|
||||
val options = DeliverOptions.newInstance(ivy.getSettings).setStatus(status)
|
||||
options.setConfs(getConfigurations(md, configurations))
|
||||
ivy.deliver(revID, revID.getRevision, deliverIvyPattern, options)
|
||||
}
|
||||
}
|
||||
// todo: map configurations, extra dependencies
|
||||
def publish(module: IvySbt#Module, resolverName: String, srcArtifactPatterns: Iterable[String], deliveredIvyPattern: Option[String], configurations: Option[Iterable[Configuration]])
|
||||
{
|
||||
module.withModule { case (ivy, md, default) =>
|
||||
val revID = md.getModuleRevisionId
|
||||
val patterns = new java.util.ArrayList[String]
|
||||
srcArtifactPatterns.foreach(pattern => patterns.add(pattern))
|
||||
val options = (new PublishOptions).setOverwrite(true)
|
||||
deliveredIvyPattern.foreach(options.setSrcIvyPattern)
|
||||
options.setConfs(getConfigurations(md, configurations))
|
||||
ivy.publish(revID, patterns, resolverName, options)
|
||||
}
|
||||
}
|
||||
/** Resolves and retrieves dependencies. 'ivyConfig' is used to produce an Ivy file and configuration.
|
||||
* 'updateConfig' configures the actual resolution and retrieval process. */
|
||||
def update(module: IvySbt#Module, configuration: UpdateConfiguration)
|
||||
{
|
||||
module.withModule { case (ivy, md, default) =>
|
||||
import configuration._
|
||||
resolve(quiet)(ivy, md, default)
|
||||
val retrieveOptions = new RetrieveOptions
|
||||
retrieveOptions.setSync(synchronize)
|
||||
val patternBase = retrieveDirectory.getAbsolutePath
|
||||
val pattern =
|
||||
if(patternBase.endsWith(File.separator))
|
||||
patternBase + outputPattern
|
||||
else
|
||||
patternBase + File.separatorChar + outputPattern
|
||||
ivy.retrieve(md.getModuleRevisionId, pattern, retrieveOptions)
|
||||
}
|
||||
}
|
||||
private def resolve(quiet: Boolean)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String) =
|
||||
{
|
||||
val resolveOptions = new ResolveOptions
|
||||
if(quiet)
|
||||
resolveOptions.setLog(LogOptions.LOG_DOWNLOAD_ONLY)
|
||||
val resolveReport = ivy.resolve(module, resolveOptions)
|
||||
if(resolveReport.hasError)
|
||||
error(Set(resolveReport.getAllProblemMessages.toArray: _*).mkString("\n"))
|
||||
}
|
||||
}
|
||||
|
||||
private object DefaultConfigurationMapping extends PomModuleDescriptorWriter.ConfigurationScopeMapping(new java.util.HashMap)
|
||||
{
|
||||
override def getScope(confs: Array[String]) =
|
||||
{
|
||||
Configurations.defaultMavenConfigurations.find(conf => confs.contains(conf.name)) match
|
||||
{
|
||||
case Some(conf) => conf.name
|
||||
case None =>
|
||||
if(confs.isEmpty || confs(0) == Configurations.Default.name)
|
||||
null
|
||||
else
|
||||
confs(0)
|
||||
}
|
||||
}
|
||||
override def isOptional(confs: Array[String]) = confs.isEmpty || (confs.length == 1 && confs(0) == Configurations.Optional.name)
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009 Mark Harrah
|
||||
*/
|
||||
package xsbt
|
||||
|
||||
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 ModuleConfiguration(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 NotNull
|
||||
{
|
||||
def isUnconfigured = dependencies.isEmpty && ivyXML.isEmpty && configurations.isEmpty &&
|
||||
defaultConfiguration.isEmpty && artifacts.isEmpty
|
||||
}
|
||||
object ModuleConfiguration
|
||||
{
|
||||
def configurations(explicitConfigurations: Iterable[Configuration], defaultConfiguration: Option[Configuration]) =
|
||||
if(explicitConfigurations.isEmpty)
|
||||
{
|
||||
defaultConfiguration match
|
||||
{
|
||||
case Some(Configurations.DefaultIvyConfiguration) => Configurations.Default :: Nil
|
||||
case Some(Configurations.DefaultMavenConfiguration) => Configurations.defaultMavenConfigurations
|
||||
case _ => Nil
|
||||
}
|
||||
}
|
||||
else
|
||||
explicitConfigurations
|
||||
}
|
||||
|
|
@ -0,0 +1,360 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009 Mark Harrah
|
||||
*/
|
||||
package xsbt
|
||||
|
||||
import java.io.File
|
||||
import java.net.{URI, URL}
|
||||
import scala.xml.NodeSeq
|
||||
import org.apache.ivy.plugins.resolver.IBiblioResolver
|
||||
import org.apache.ivy.util.url.CredentialsStore
|
||||
|
||||
final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean, explicitArtifacts: Seq[Artifact]) extends NotNull
|
||||
{
|
||||
override def toString = organization + ":" + name + ":" + revision
|
||||
// () required for chaining
|
||||
def notTransitive() = intransitive()
|
||||
def intransitive() = ModuleID(organization, name, revision, configurations, isChanging, false, explicitArtifacts)
|
||||
def changing() = ModuleID(organization, name, revision, configurations, true, isTransitive, explicitArtifacts)
|
||||
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)
|
||||
}
|
||||
object ModuleID
|
||||
{
|
||||
def apply(organization: String, name: String, revision: String): ModuleID = ModuleID(organization, name, revision, None)
|
||||
def apply(organization: String, name: String, revision: String, configurations: Option[String]): ModuleID =
|
||||
ModuleID(organization, name, revision, configurations, false, true)
|
||||
def apply(organization: String, name: String, revision: String, configurations: Option[String], isChanging: Boolean, isTransitive: Boolean): ModuleID =
|
||||
ModuleID(organization, name, revision, configurations, isChanging, isTransitive, Nil)
|
||||
}
|
||||
sealed trait Resolver extends NotNull
|
||||
{
|
||||
def name: String
|
||||
}
|
||||
sealed case class MavenRepository(name: String, root: String) extends Resolver
|
||||
{
|
||||
override def toString = name + ": " + root
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
/** Configuration specific to an Ivy filesystem resolver. */
|
||||
final case class FileConfiguration(isLocal: Boolean, isTransactional: Option[Boolean]) extends NotNull
|
||||
{
|
||||
def transactional() = FileConfiguration(isLocal, Some(true))
|
||||
def nontransactional() = FileConfiguration(isLocal, Some(false))
|
||||
def nonlocal() = FileConfiguration(false, isTransactional)
|
||||
}
|
||||
sealed trait SshAuthentication extends NotNull
|
||||
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.{KeyFileAuthentication, PasswordAuthentication, SshAuthentication}
|
||||
|
||||
/** sbt interface to an Ivy repository based on patterns, which is most Ivy repositories.*/
|
||||
sealed abstract class PatternsBasedRepository extends Resolver
|
||||
{
|
||||
type RepositoryType <: PatternsBasedRepository
|
||||
/** Should be implemented to create a new copy of this repository but with `patterns` as given.*/
|
||||
protected def copy(patterns: Patterns): RepositoryType
|
||||
|
||||
/** The object representing the configured patterns for this repository. */
|
||||
def patterns: Patterns
|
||||
|
||||
/** Enables maven 2 compatibility for this repository. */
|
||||
def mavenStyle() = copy(patterns.mavenStyle())
|
||||
/** Adds the given patterns for resolving/publishing Ivy files.*/
|
||||
def ivys(ivyPatterns: String*): RepositoryType = copy(patterns.withIvys(ivyPatterns))
|
||||
/** Adds the given patterns for resolving/publishing artifacts.*/
|
||||
def artifacts(artifactPatterns: String*): RepositoryType = copy(patterns.withArtifacts(artifactPatterns))
|
||||
}
|
||||
/** sbt interface for an Ivy filesystem repository. More convenient construction is done using Resolver.file. */
|
||||
final case class FileRepository(name: String, configuration: FileConfiguration, patterns: Patterns) extends PatternsBasedRepository
|
||||
{
|
||||
type RepositoryType = FileRepository
|
||||
protected def copy(patterns: Patterns): FileRepository = FileRepository(name, configuration, patterns)
|
||||
private def copy(configuration: FileConfiguration) = FileRepository(name, configuration, patterns)
|
||||
def transactional() = copy(configuration.transactional())
|
||||
def nonlocal() = copy(configuration.nonlocal())
|
||||
}
|
||||
final case class URLRepository(name: String, patterns: Patterns) extends PatternsBasedRepository
|
||||
{
|
||||
type RepositoryType = URLRepository
|
||||
protected def copy(patterns: Patterns): URLRepository = URLRepository(name, patterns)
|
||||
}
|
||||
/** sbt interface for an Ivy ssh-based repository (ssh and sftp). Requires the Jsch library.. */
|
||||
sealed abstract class SshBasedRepository extends PatternsBasedRepository
|
||||
{
|
||||
type RepositoryType <: SshBasedRepository
|
||||
protected def copy(connection: SshConnection): RepositoryType
|
||||
private def copy(authentication: SshAuthentication): RepositoryType = copy(connection.copy(Some(authentication)))
|
||||
|
||||
/** The object representing the configured ssh connection for this repository. */
|
||||
def connection: SshConnection
|
||||
|
||||
/** Configures this to use the specified user name and password when connecting to the remote repository. */
|
||||
def as(user: String, password: String): RepositoryType = copy(new PasswordAuthentication(user, password))
|
||||
/** Configures this to use the specified keyfile and password for the keyfile when connecting to the remote repository. */
|
||||
def as(keyfile: File, password: String): RepositoryType = copy(new KeyFileAuthentication(keyfile, password))
|
||||
}
|
||||
/** sbt interface for an Ivy repository over ssh. More convenient construction is done using Resolver.ssh. */
|
||||
final case class SshRepository(name: String, connection: SshConnection, patterns: Patterns, publishPermissions: Option[String]) extends SshBasedRepository
|
||||
{
|
||||
type RepositoryType = SshRepository
|
||||
protected def copy(patterns: Patterns): SshRepository = SshRepository(name, connection, patterns, publishPermissions)
|
||||
protected def copy(connection: SshConnection): SshRepository = SshRepository(name, connection, patterns, publishPermissions)
|
||||
/** Defines the permissions to set when publishing to this repository. */
|
||||
def withPermissions(publishPermissions: String): SshRepository = withPermissions(Some(publishPermissions))
|
||||
def withPermissions(publishPermissions: Option[String]): SshRepository = SshRepository(name, connection, patterns, publishPermissions)
|
||||
}
|
||||
/** sbt interface for an Ivy repository over sftp. More convenient construction is done using Resolver.sftp. */
|
||||
final case class SftpRepository(name: String, connection: SshConnection, patterns: Patterns) extends SshBasedRepository
|
||||
{
|
||||
type RepositoryType = SftpRepository
|
||||
protected def copy(patterns: Patterns): SftpRepository = SftpRepository(name, connection, patterns)
|
||||
protected def copy(connection: SshConnection): SftpRepository = SftpRepository(name, connection, patterns)
|
||||
}
|
||||
|
||||
import Resolver._
|
||||
object ScalaToolsReleases extends MavenRepository(ScalaToolsReleasesName, ScalaToolsReleasesRoot)
|
||||
object ScalaToolsSnapshots extends MavenRepository(ScalaToolsSnapshotsName, ScalaToolsSnapshotsRoot)
|
||||
object DefaultMavenRepository extends MavenRepository("public", IBiblioResolver.DEFAULT_M2_ROOT)
|
||||
object JavaNet1Repository extends Resolver
|
||||
{
|
||||
def name = "java.net Maven1 Repository"
|
||||
}
|
||||
|
||||
object Resolver
|
||||
{
|
||||
val ScalaToolsReleasesName = "Scala-Tools Maven2 Repository"
|
||||
val ScalaToolsSnapshotsName = "Scala-Tools Maven2 Snapshots Repository"
|
||||
val ScalaToolsReleasesRoot = "http://scala-tools.org/repo-releases"
|
||||
val ScalaToolsSnapshotsRoot = "http://scala-tools.org/repo-snapshots"
|
||||
|
||||
def withDefaultResolvers(userResolvers: Seq[Resolver]): Seq[Resolver] =
|
||||
withDefaultResolvers(userResolvers, true)
|
||||
def withDefaultResolvers(userResolvers: Seq[Resolver], scalaTools: Boolean): Seq[Resolver] =
|
||||
withDefaultResolvers(userResolvers, true, scalaTools)
|
||||
def withDefaultResolvers(userResolvers: Seq[Resolver], mavenCentral: Boolean, scalaTools: Boolean): Seq[Resolver] =
|
||||
Seq(Resolver.defaultLocal) ++
|
||||
userResolvers ++
|
||||
single(DefaultMavenRepository, mavenCentral)++
|
||||
single(ScalaToolsReleases, scalaTools)
|
||||
private def single[T](value: T, nonEmpty: Boolean): Seq[T] = if(nonEmpty) Seq(value) else Nil
|
||||
|
||||
/** A base class for defining factories for interfaces to Ivy repositories that require a hostname , port, and patterns. */
|
||||
sealed abstract class Define[RepositoryType <: SshBasedRepository] extends NotNull
|
||||
{
|
||||
/** Subclasses should implement this method to */
|
||||
protected def construct(name: String, connection: SshConnection, patterns: Patterns): RepositoryType
|
||||
/** Constructs this repository type with the given `name`. `basePatterns` are the initial patterns to use. A ManagedProject
|
||||
* has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns.*/
|
||||
def apply(name: String)(implicit basePatterns: Patterns): RepositoryType =
|
||||
apply(name, None, None, None)
|
||||
/** Constructs this repository type with the given `name` and `hostname`. `basePatterns` are the initial patterns to use.
|
||||
* A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns.*/
|
||||
def apply(name: String, hostname: String)(implicit basePatterns: Patterns): RepositoryType =
|
||||
apply(name, Some(hostname), None, None)
|
||||
/** Constructs this repository type with the given `name`, `hostname`, and the `basePath` against which the initial
|
||||
* patterns will be resolved. `basePatterns` are the initial patterns to use.
|
||||
* A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns.*/
|
||||
def apply(name: String, hostname: String, basePath: String)(implicit basePatterns: Patterns): RepositoryType =
|
||||
apply(name, Some(hostname), None, Some(basePath))
|
||||
/** Constructs this repository type with the given `name`, `hostname`, and `port`. `basePatterns` are the initial patterns to use.
|
||||
* A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns.*/
|
||||
def apply(name: String, hostname: String, port: Int)(implicit basePatterns: Patterns): RepositoryType =
|
||||
apply(name, Some(hostname), Some(port), None)
|
||||
/** Constructs this repository type with the given `name`, `hostname`, `port`, and the `basePath` against which the initial
|
||||
* patterns will be resolved. `basePatterns` are the initial patterns to use.
|
||||
* A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns.*/
|
||||
def apply(name: String, hostname: String, port: Int, basePath: String)(implicit basePatterns: Patterns): RepositoryType =
|
||||
apply(name, Some(hostname), Some(port), Some(basePath))
|
||||
/** Constructs this repository type with the given `name`, `hostname`, `port`, and the `basePath` against which the initial
|
||||
* patterns will be resolved. `basePatterns` are the initial patterns to use. All but the `name` are optional (use None).
|
||||
* A ManagedProject has an implicit defining these initial patterns based on a setting for either Maven or Ivy style patterns.*/
|
||||
def apply(name: String, hostname: Option[String], port: Option[Int], basePath: Option[String])(implicit basePatterns: Patterns): RepositoryType =
|
||||
construct(name, SshConnection(None, hostname, port), resolvePatterns(basePath, basePatterns))
|
||||
}
|
||||
/** A factory to construct an interface to an Ivy SSH resolver.*/
|
||||
object ssh extends Define[SshRepository]
|
||||
{
|
||||
protected def construct(name: String, connection: SshConnection, patterns: Patterns) = SshRepository(name, connection, patterns, None)
|
||||
}
|
||||
/** A factory to construct an interface to an Ivy SFTP resolver.*/
|
||||
object sftp extends Define[SftpRepository]
|
||||
{
|
||||
protected def construct(name: String, connection: SshConnection, patterns: Patterns) = SftpRepository(name, connection, patterns)
|
||||
}
|
||||
/** A factory to construct an interface to an Ivy filesytem resolver. */
|
||||
object file
|
||||
{
|
||||
/** Constructs a file resolver with the given name. The patterns to use must be explicitly specified
|
||||
* using the `ivys` or `artifacts` methods on the constructed resolver object.*/
|
||||
def apply(name: String): FileRepository = FileRepository(name, defaultFileConfiguration, ivyStylePatterns)
|
||||
/** Constructs a file resolver with the given name and base directory. */
|
||||
def apply(name: String, baseDirectory: File)(implicit basePatterns: Patterns): FileRepository =
|
||||
baseRepository(baseDirectory.toURI)(FileRepository(name, defaultFileConfiguration, _))
|
||||
}
|
||||
object url
|
||||
{
|
||||
/** Constructs a URL resolver with the given name. The patterns to use must be explicitly specified
|
||||
* using the `ivys` or `artifacts` methods on the constructed resolver object.*/
|
||||
def apply(name: String): URLRepository = URLRepository(name, ivyStylePatterns)
|
||||
/** Constructs a file resolver with the given name and base directory. */
|
||||
def apply(name: String, baseURL: URL)(implicit basePatterns: Patterns): URLRepository =
|
||||
baseRepository(baseURL.toURI)(URLRepository(name, _))
|
||||
}
|
||||
private def baseRepository[T](baseURI: java.net.URI)(construct: Patterns => T)(implicit basePatterns: Patterns): T =
|
||||
construct(resolvePatterns(baseURI.normalize, basePatterns))
|
||||
|
||||
/** If `base` is None, `patterns` is returned unchanged.
|
||||
* Otherwise, the ivy file and artifact patterns in `patterns` are resolved against the given base. */
|
||||
private def resolvePatterns(base: Option[String], patterns: Patterns): Patterns =
|
||||
base match
|
||||
{
|
||||
case Some(path) => resolvePatterns(pathURI(path), patterns)
|
||||
case None => patterns
|
||||
}
|
||||
/** Resolves the ivy file and artifact patterns in `patterns` against the given base. */
|
||||
private def resolvePatterns(base: URI, basePatterns: Patterns): Patterns =
|
||||
{
|
||||
def resolve(pattern: String) = base.resolve(pathURI(pattern)).getPath
|
||||
def resolveAll(patterns: Seq[String]) = patterns.map(resolve)
|
||||
Patterns(resolveAll(basePatterns.ivyPatterns), resolveAll(basePatterns.artifactPatterns), basePatterns.isMavenCompatible)
|
||||
}
|
||||
/** Constructs a `URI` with the path component set to `path` and the other components set to null.*/
|
||||
private def pathURI(path: String) = new URI(null, null, path, null)
|
||||
|
||||
def defaultFileConfiguration = FileConfiguration(true, None)
|
||||
def mavenStylePatterns = Patterns(Nil, mavenStyleBasePattern :: Nil, true)
|
||||
def ivyStylePatterns = Patterns(Nil, Nil, false)
|
||||
|
||||
def defaultPatterns = mavenStylePatterns
|
||||
def mavenStyleBasePattern = "[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]"
|
||||
def localBasePattern = "[organisation]/[module]/[revision]/[type]s/[artifact].[ext]"
|
||||
|
||||
def userRoot = System.getProperty("user.home")
|
||||
def userMavenRoot = userRoot + "/.m2/repository/"
|
||||
def userIvyRoot = userRoot + "/.ivy2/"
|
||||
|
||||
def defaultLocal = defaultUserFileRepository("local")
|
||||
def defaultShared = defaultUserFileRepository("shared")
|
||||
def defaultUserFileRepository(id: String) = file(id, new File(userIvyRoot, id))(defaultIvyPatterns)
|
||||
def defaultIvyPatterns =
|
||||
{
|
||||
val pList = List(localBasePattern)
|
||||
Patterns(pList, pList, false)
|
||||
}
|
||||
}
|
||||
|
||||
object Configurations
|
||||
{
|
||||
def config(name: String) = new Configuration(name)
|
||||
def defaultMavenConfigurations = Compile :: Runtime :: Test :: Provided :: System :: Optional :: Sources :: Javadoc :: Nil
|
||||
|
||||
lazy val Default = config("default")
|
||||
lazy val Compile = config("compile")
|
||||
lazy val IntegrationTest = config("it") hide
|
||||
lazy val Provided = config("provided")
|
||||
lazy val Javadoc = config("javadoc")
|
||||
lazy val Runtime = config("runtime")
|
||||
lazy val Test = config("test") hide
|
||||
lazy val Sources = config("sources")
|
||||
lazy val System = config("system")
|
||||
lazy val Optional = config("optional")
|
||||
|
||||
lazy val CompilerPlugin = config("plugin") hide
|
||||
|
||||
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 removeDuplicates(configs: Iterable[Configuration]) = Set(scala.collection.mutable.Map(configs.map(config => (config.name, config)).toSeq: _*).values.toList: _*)
|
||||
}
|
||||
/** Represents an Ivy configuration. */
|
||||
final case class Configuration(name: String, description: String, isPublic: Boolean, extendsConfigs: List[Configuration], transitive: Boolean) extends NotNull
|
||||
{
|
||||
require(name != null && !name.isEmpty)
|
||||
require(description != null)
|
||||
def this(name: String) = this(name, "", true, Nil, true)
|
||||
def describedAs(newDescription: String) = Configuration(name, newDescription, isPublic, extendsConfigs, transitive)
|
||||
def extend(configs: Configuration*) = Configuration(name, description, isPublic, configs.toList ::: extendsConfigs, transitive)
|
||||
def notTransitive = intransitive
|
||||
def intransitive = Configuration(name, description, isPublic, extendsConfigs, false)
|
||||
def hide = Configuration(name, description, false, extendsConfigs, transitive)
|
||||
override def toString = name
|
||||
}
|
||||
|
||||
final case class Artifact(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL]) extends NotNull
|
||||
object Artifact
|
||||
{
|
||||
def apply(name: String): Artifact = Artifact(name, defaultType, defaultExtension, None, Nil, None)
|
||||
def apply(name: String, classifier: String): Artifact = Artifact(name, defaultType, defaultExtension, Some(classifier), Nil, None)
|
||||
def apply(name: String, `type`: String, extension: String): Artifact = Artifact(name, `type`, extension, None, Nil, None)
|
||||
def apply(name: String, url: URL): Artifact =Artifact(name, extract(url, defaultType), extract(url, defaultExtension), None, Nil, Some(url))
|
||||
val defaultExtension = "jar"
|
||||
val defaultType = "jar"
|
||||
private[this] def extract(url: URL, default: String) =
|
||||
{
|
||||
val s = url.toString
|
||||
val i = s.lastIndexOf('.')
|
||||
if(i >= 0)
|
||||
s.substring(i+1)
|
||||
else
|
||||
default
|
||||
}
|
||||
}
|
||||
/*
|
||||
object Credentials
|
||||
{
|
||||
/** Add the provided credentials to Ivy's credentials cache.*/
|
||||
def add(realm: String, host: String, userName: String, passwd: String): Unit =
|
||||
CredentialsStore.INSTANCE.addCredentials(realm, host, userName, passwd)
|
||||
/** Load credentials from the given file into Ivy's credentials cache.*/
|
||||
def apply(file: String, log: Logger): Unit = apply(Path.fromFile(file), log)
|
||||
/** Load credentials from the given file into Ivy's credentials cache.*/
|
||||
def apply(file: File, log: Logger): Unit = apply(Path.fromFile(file), log)
|
||||
/** Load credentials from the given file into Ivy's credentials cache.*/
|
||||
def apply(path: Path, log: Logger)
|
||||
{
|
||||
val msg =
|
||||
if(path.exists)
|
||||
{
|
||||
val properties = new scala.collection.mutable.HashMap[String, String]
|
||||
def get(keys: List[String]) = keys.flatMap(properties.get).firstOption.toRight(keys.head + " not specified in credentials file: " + path)
|
||||
|
||||
impl.MapUtilities.read(properties, path, log) orElse
|
||||
{
|
||||
List.separate( List(RealmKeys, HostKeys, UserKeys, PasswordKeys).map(get) ) match
|
||||
{
|
||||
case (Nil, List(realm, host, user, pass)) => add(realm, host, user, pass); None
|
||||
case (errors, _) => Some(errors.mkString("\n"))
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
Some("Credentials file " + path + " does not exist")
|
||||
msg.foreach(x => log.warn(x))
|
||||
}
|
||||
private[this] val RealmKeys = List("realm")
|
||||
private[this] val HostKeys = List("host", "hostname")
|
||||
private[this] val UserKeys = List("user", "user.name", "username")
|
||||
private[this] val PasswordKeys = List("password", "pwd", "pass", "passwd")
|
||||
}*/
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009 Mark Harrah
|
||||
*/
|
||||
package xsbt
|
||||
|
||||
import org.apache.ivy.util.{Message, MessageLogger}
|
||||
|
||||
trait IvyLogger
|
||||
{
|
||||
def info(msg: => String)
|
||||
def debug(msg: => String)
|
||||
def warn(msg: => String)
|
||||
def error(msg: => String)
|
||||
def verbose(msg: => String)
|
||||
}
|
||||
|
||||
/** Interface to Ivy logging. */
|
||||
private final class IvyLoggerInterface(logger: IvyLogger) extends MessageLogger
|
||||
{
|
||||
def rawlog(msg: String, level: Int) = log(msg, level)
|
||||
def log(msg: String, level: Int)
|
||||
{
|
||||
import Message.{MSG_DEBUG, MSG_VERBOSE, MSG_INFO, MSG_WARN, MSG_ERR}
|
||||
level match
|
||||
{
|
||||
case MSG_DEBUG => debug(msg)
|
||||
case MSG_VERBOSE => verbose(msg)
|
||||
case MSG_INFO => info(msg)
|
||||
case MSG_WARN => warn(msg)
|
||||
case MSG_ERR => error(msg)
|
||||
}
|
||||
}
|
||||
def debug(msg: String) = logger.debug(msg)
|
||||
def verbose(msg: String) = logger.verbose(msg)
|
||||
def deprecated(msg: String) = warn(msg)
|
||||
def info(msg: String) = logger.info(msg)
|
||||
def rawinfo(msg: String) = info(msg)
|
||||
def warn(msg: String) = logger.warn(msg)
|
||||
def error(msg: String) = logger.error(msg)
|
||||
|
||||
private def emptyList = java.util.Collections.emptyList[T forSome { type T}]
|
||||
def getProblems = emptyList
|
||||
def getWarns = emptyList
|
||||
def getErrors = emptyList
|
||||
|
||||
def clearProblems = ()
|
||||
def sumupProblems = ()
|
||||
def progress = ()
|
||||
def endProgress = ()
|
||||
|
||||
def endProgress(msg: String) = info(msg)
|
||||
def isShowProgress = false
|
||||
def setShowProgress(progress: Boolean) {}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/* sbt -- Simple Build Tool
|
||||
* Copyright 2008, 2009 Mark Harrah
|
||||
*/
|
||||
package xsbt
|
||||
|
||||
import java.util.Collections
|
||||
import scala.collection.mutable.HashSet
|
||||
|
||||
import org.apache.ivy.{core, plugins}
|
||||
import core.module.descriptor.{DefaultExcludeRule, ExcludeRule}
|
||||
import core.module.descriptor.{DefaultModuleDescriptor, ModuleDescriptor}
|
||||
import core.module.id.{ArtifactId,ModuleId, ModuleRevisionId}
|
||||
import plugins.matcher.ExactPatternMatcher
|
||||
|
||||
final class IvyScala(val scalaVersion: String, val configurations: Iterable[Configuration], val checkExplicit: Boolean, val filterImplicit: Boolean) extends NotNull
|
||||
private object IvyScala
|
||||
{
|
||||
val ScalaOrganization = "org.scala-lang"
|
||||
val ScalaLibraryID = "scala-library"
|
||||
val ScalaCompilerID = "scala-compiler"
|
||||
|
||||
/** Performs checks/adds filters on Scala dependencies (if enabled in IvyScala). */
|
||||
def checkModule(module: DefaultModuleDescriptor, conf: String)(check: IvyScala)
|
||||
{
|
||||
if(check.checkExplicit)
|
||||
checkDependencies(module, check.scalaVersion, check.configurations)
|
||||
if(check.filterImplicit)
|
||||
excludeScalaJars(module, check.configurations)
|
||||
}
|
||||
/** Checks the immediate dependencies of module for dependencies on scala jars and verifies that the version on the
|
||||
* dependencies matches scalaVersion. */
|
||||
private def checkDependencies(module: ModuleDescriptor, scalaVersion: String, configurations: Iterable[Configuration])
|
||||
{
|
||||
val configSet = configurationSet(configurations)
|
||||
for(dep <- module.getDependencies.toList)
|
||||
{
|
||||
val id = dep.getDependencyRevisionId
|
||||
if(id.getOrganisation == ScalaOrganization && id.getRevision != scalaVersion && dep.getModuleConfigurations.exists(configSet.contains))
|
||||
error("Different Scala version specified in dependency ("+ id.getRevision + ") than in project (" + scalaVersion + ").")
|
||||
}
|
||||
}
|
||||
private def configurationSet(configurations: Iterable[Configuration]) = HashSet(configurations.map(_.toString).toSeq : _*)
|
||||
/** Adds exclusions for the scala library and compiler jars so that they are not downloaded. This is
|
||||
* done because normally these jars are already on the classpath and cannot/should not be overridden. The version
|
||||
* of Scala to use is done by setting scala.version in the project definition. */
|
||||
private def excludeScalaJars(module: DefaultModuleDescriptor, configurations: Iterable[Configuration])
|
||||
{
|
||||
val configurationNames =
|
||||
{
|
||||
val names = module.getConfigurationsNames
|
||||
if(configurations.isEmpty)
|
||||
names
|
||||
else
|
||||
{
|
||||
val configSet = configurationSet(configurations)
|
||||
configSet.intersect(HashSet(names : _*))
|
||||
configSet.toArray
|
||||
}
|
||||
}
|
||||
def excludeScalaJar(name: String): Unit =
|
||||
module.addExcludeRule(excludeRule(ScalaOrganization, name, configurationNames))
|
||||
excludeScalaJar(ScalaLibraryID)
|
||||
excludeScalaJar(ScalaCompilerID)
|
||||
}
|
||||
/** Creates an ExcludeRule that excludes artifacts with the given module organization and name for
|
||||
* the given configurations. */
|
||||
private def excludeRule(organization: String, name: String, configurationNames: Iterable[String]): ExcludeRule =
|
||||
{
|
||||
val artifact = new ArtifactId(ModuleId.newInstance(organization, name), "*", "*", "*")
|
||||
val rule = new DefaultExcludeRule(artifact, ExactPatternMatcher.INSTANCE, Collections.emptyMap[AnyRef,AnyRef])
|
||||
configurationNames.foreach(rule.addConfiguration)
|
||||
rule
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue