mirror of https://github.com/sbt/sbt.git
added scalariform
This commit is contained in:
parent
60d038170f
commit
e64165ce9e
|
|
@ -6,71 +6,69 @@ package sbt
|
|||
import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
final case class Artifact(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL], extraAttributes: Map[String,String])
|
||||
{
|
||||
def extra(attributes: (String,String)*) = Artifact(name, `type`, extension, classifier, configurations, url, extraAttributes ++ ModuleID.checkE(attributes))
|
||||
final case class Artifact(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL], extraAttributes: Map[String, String]) {
|
||||
def extra(attributes: (String, String)*) = Artifact(name, `type`, extension, classifier, configurations, url, extraAttributes ++ ModuleID.checkE(attributes))
|
||||
}
|
||||
|
||||
import Configurations.{config, Docs, Optional, Pom, Sources, Test}
|
||||
import Configurations.{ config, Docs, Optional, Pom, Sources, Test }
|
||||
|
||||
object Artifact
|
||||
{
|
||||
def apply(name: String): Artifact = Artifact(name, DefaultType, DefaultExtension, None, Nil, None)
|
||||
def apply(name: String, extra: Map[String,String]): Artifact = Artifact(name, DefaultType, DefaultExtension, None, Nil, None, extra)
|
||||
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, `type`: String, extension: String, classifier: String): Artifact = Artifact(name, `type`, extension, Some(classifier), Nil, None)
|
||||
def apply(name: String, url: URL): Artifact =Artifact(name, extract(url, DefaultType), extract(url, DefaultExtension), None, Nil, Some(url))
|
||||
def apply(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL]): Artifact =
|
||||
Artifact(name, `type`, extension, classifier, configurations, url, Map.empty)
|
||||
object Artifact {
|
||||
def apply(name: String): Artifact = Artifact(name, DefaultType, DefaultExtension, None, Nil, None)
|
||||
def apply(name: String, extra: Map[String, String]): Artifact = Artifact(name, DefaultType, DefaultExtension, None, Nil, None, extra)
|
||||
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, `type`: String, extension: String, classifier: String): Artifact = Artifact(name, `type`, extension, Some(classifier), Nil, None)
|
||||
def apply(name: String, url: URL): Artifact = Artifact(name, extract(url, DefaultType), extract(url, DefaultExtension), None, Nil, Some(url))
|
||||
def apply(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Iterable[Configuration], url: Option[URL]): Artifact =
|
||||
Artifact(name, `type`, extension, classifier, configurations, url, Map.empty)
|
||||
|
||||
val DefaultExtension = "jar"
|
||||
val DefaultType = "jar"
|
||||
val DefaultExtension = "jar"
|
||||
val DefaultType = "jar"
|
||||
|
||||
def sources(name: String) = classified(name, SourceClassifier)
|
||||
def javadoc(name: String) = classified(name, DocClassifier)
|
||||
def pom(name: String) = Artifact(name, PomType, PomType, None, Pom :: Nil, None)
|
||||
def sources(name: String) = classified(name, SourceClassifier)
|
||||
def javadoc(name: String) = classified(name, DocClassifier)
|
||||
def pom(name: String) = Artifact(name, PomType, PomType, None, Pom :: Nil, None)
|
||||
|
||||
val DocClassifier = "javadoc"
|
||||
val SourceClassifier = "sources"
|
||||
val DocType = "doc"
|
||||
val SourceType = "src"
|
||||
val PomType = "pom"
|
||||
val TestsClassifier = "tests"
|
||||
val DocClassifier = "javadoc"
|
||||
val SourceClassifier = "sources"
|
||||
val DocType = "doc"
|
||||
val SourceType = "src"
|
||||
val PomType = "pom"
|
||||
val TestsClassifier = "tests"
|
||||
|
||||
def extract(url: URL, default: String): String = extract(url.toString, default)
|
||||
def extract(name: String, default: String): String =
|
||||
{
|
||||
val i = name.lastIndexOf('.')
|
||||
if(i >= 0)
|
||||
name.substring(i+1)
|
||||
else
|
||||
default
|
||||
}
|
||||
def defaultArtifact(file: File) =
|
||||
{
|
||||
val name = file.getName
|
||||
val i = name.lastIndexOf('.')
|
||||
val base = if(i >= 0) name.substring(0, i) else name
|
||||
Artifact(base, extract(name, DefaultType), extract(name, DefaultExtension), None, Nil, Some(file.toURI.toURL))
|
||||
}
|
||||
def artifactName(scalaVersion: ScalaVersion, module: ModuleID, artifact: Artifact): String =
|
||||
{
|
||||
import artifact._
|
||||
val classifierStr = classifier match { case None => ""; case Some(c) => "-" + c }
|
||||
val cross = CrossVersion(module.crossVersion, scalaVersion.full, scalaVersion.binary)
|
||||
val base = CrossVersion.applyCross(artifact.name, cross)
|
||||
base + "-" + module.revision + classifierStr + "." + artifact.extension
|
||||
}
|
||||
def extract(url: URL, default: String): String = extract(url.toString, default)
|
||||
def extract(name: String, default: String): String =
|
||||
{
|
||||
val i = name.lastIndexOf('.')
|
||||
if (i >= 0)
|
||||
name.substring(i + 1)
|
||||
else
|
||||
default
|
||||
}
|
||||
def defaultArtifact(file: File) =
|
||||
{
|
||||
val name = file.getName
|
||||
val i = name.lastIndexOf('.')
|
||||
val base = if (i >= 0) name.substring(0, i) else name
|
||||
Artifact(base, extract(name, DefaultType), extract(name, DefaultExtension), None, Nil, Some(file.toURI.toURL))
|
||||
}
|
||||
def artifactName(scalaVersion: ScalaVersion, module: ModuleID, artifact: Artifact): String =
|
||||
{
|
||||
import artifact._
|
||||
val classifierStr = classifier match { case None => ""; case Some(c) => "-" + c }
|
||||
val cross = CrossVersion(module.crossVersion, scalaVersion.full, scalaVersion.binary)
|
||||
val base = CrossVersion.applyCross(artifact.name, cross)
|
||||
base + "-" + module.revision + classifierStr + "." + artifact.extension
|
||||
}
|
||||
|
||||
val classifierConfMap = Map(SourceClassifier -> Sources, DocClassifier -> Docs)
|
||||
val classifierTypeMap = Map(SourceClassifier -> SourceType, DocClassifier -> DocType)
|
||||
def classifierConf(classifier: String): Configuration =
|
||||
if(classifier.startsWith(TestsClassifier))
|
||||
Test
|
||||
else
|
||||
classifierConfMap.getOrElse(classifier, Optional)
|
||||
def classifierType(classifier: String): String = classifierTypeMap.getOrElse(classifier.stripPrefix(TestsClassifier + "-"), DefaultType)
|
||||
def classified(name: String, classifier: String): Artifact =
|
||||
Artifact(name, classifierType(classifier), DefaultExtension, Some(classifier), classifierConf(classifier) :: Nil, None)
|
||||
val classifierConfMap = Map(SourceClassifier -> Sources, DocClassifier -> Docs)
|
||||
val classifierTypeMap = Map(SourceClassifier -> SourceType, DocClassifier -> DocType)
|
||||
def classifierConf(classifier: String): Configuration =
|
||||
if (classifier.startsWith(TestsClassifier))
|
||||
Test
|
||||
else
|
||||
classifierConfMap.getOrElse(classifier, Optional)
|
||||
def classifierType(classifier: String): String = classifierTypeMap.getOrElse(classifier.stripPrefix(TestsClassifier + "-"), DefaultType)
|
||||
def classified(name: String, classifier: String): Artifact =
|
||||
Artifact(name, classifierType(classifier), DefaultExtension, Some(classifier), classifierConf(classifier) :: Nil, None)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,90 +3,87 @@
|
|||
*/
|
||||
package sbt
|
||||
|
||||
import java.io.{File,FileOutputStream}
|
||||
import java.io.{ File, FileOutputStream }
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
/** 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.
|
||||
* The second type is a subproject distributed as a source jar so that it can be compiled against a specific
|
||||
* version of Scala.
|
||||
*
|
||||
* The component manager provides services to install and retrieve components to the local repository.
|
||||
* This is used for compiled source jars so that the compilation need not be repeated for other projects on the same
|
||||
* machine.
|
||||
*/
|
||||
class ComponentManager(globalLock: xsbti.GlobalLock, provider: xsbti.ComponentProvider, ivyHome: Option[File], val log: Logger)
|
||||
{
|
||||
private[this] val ivyCache = new IvyCache(ivyHome)
|
||||
/** Get all of the files for component 'id', throwing an exception if no files exist for the component. */
|
||||
def files(id: String)(ifMissing: IfMissing): Iterable[File] =
|
||||
{
|
||||
def fromGlobal =
|
||||
lockGlobalCache {
|
||||
try { update(id); getOrElse(createAndCache) }
|
||||
catch { case e: NotInCache => createAndCache }
|
||||
}
|
||||
def getOrElse(orElse: => Iterable[File]): Iterable[File] =
|
||||
{
|
||||
val existing = provider.component(id)
|
||||
if(existing.isEmpty) orElse else existing
|
||||
}
|
||||
def notFound = invalid("Could not find required component '" + id + "'")
|
||||
def createAndCache =
|
||||
ifMissing match {
|
||||
case IfMissing.Fail => notFound
|
||||
case d: IfMissing.Define =>
|
||||
d()
|
||||
if(d.cache) cache(id)
|
||||
getOrElse(notFound)
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
* The second type is a subproject distributed as a source jar so that it can be compiled against a specific
|
||||
* version of Scala.
|
||||
*
|
||||
* The component manager provides services to install and retrieve components to the local repository.
|
||||
* This is used for compiled source jars so that the compilation need not be repeated for other projects on the same
|
||||
* machine.
|
||||
*/
|
||||
class ComponentManager(globalLock: xsbti.GlobalLock, provider: xsbti.ComponentProvider, ivyHome: Option[File], val log: Logger) {
|
||||
private[this] val ivyCache = new IvyCache(ivyHome)
|
||||
/** Get all of the files for component 'id', throwing an exception if no files exist for the component. */
|
||||
def files(id: String)(ifMissing: IfMissing): Iterable[File] =
|
||||
{
|
||||
def fromGlobal =
|
||||
lockGlobalCache {
|
||||
try { update(id); getOrElse(createAndCache) }
|
||||
catch { case e: NotInCache => createAndCache }
|
||||
}
|
||||
def getOrElse(orElse: => Iterable[File]): Iterable[File] =
|
||||
{
|
||||
val existing = provider.component(id)
|
||||
if (existing.isEmpty) orElse else existing
|
||||
}
|
||||
def notFound = invalid("Could not find required component '" + id + "'")
|
||||
def createAndCache =
|
||||
ifMissing match {
|
||||
case IfMissing.Fail => notFound
|
||||
case d: IfMissing.Define =>
|
||||
d()
|
||||
if (d.cache) cache(id)
|
||||
getOrElse(notFound)
|
||||
}
|
||||
|
||||
lockLocalCache { getOrElse(fromGlobal) }
|
||||
}
|
||||
/** This is used to lock the local cache in project/boot/. By checking the local cache first, we can avoid grabbing a global lock. */
|
||||
private def lockLocalCache[T](action: => T): T = lock(provider.lockFile)( action )
|
||||
/** This is used to ensure atomic access to components in the global Ivy cache.*/
|
||||
private def lockGlobalCache[T](action: => T): T = lock(ivyCache.lockFile)( action )
|
||||
private def lock[T](file: File)(action: => T): T = globalLock(file, new Callable[T] { def call = action })
|
||||
/** Get the file for component 'id', throwing an exception if no files or multiple files exist for the component. */
|
||||
def file(id: String)(ifMissing: IfMissing): File =
|
||||
files(id)(ifMissing).toList match {
|
||||
case x :: Nil => x
|
||||
case xs => invalid("Expected single file for component '" + id + "', found: " + xs.mkString(", "))
|
||||
}
|
||||
private def invalid(msg: String) = throw new InvalidComponent(msg)
|
||||
private def invalid(e: NotInCache) = throw new InvalidComponent(e.getMessage, e)
|
||||
lockLocalCache { getOrElse(fromGlobal) }
|
||||
}
|
||||
/** This is used to lock the local cache in project/boot/. By checking the local cache first, we can avoid grabbing a global lock. */
|
||||
private def lockLocalCache[T](action: => T): T = lock(provider.lockFile)(action)
|
||||
/** This is used to ensure atomic access to components in the global Ivy cache.*/
|
||||
private def lockGlobalCache[T](action: => T): T = lock(ivyCache.lockFile)(action)
|
||||
private def lock[T](file: File)(action: => T): T = globalLock(file, new Callable[T] { def call = action })
|
||||
/** Get the file for component 'id', throwing an exception if no files or multiple files exist for the component. */
|
||||
def file(id: String)(ifMissing: IfMissing): File =
|
||||
files(id)(ifMissing).toList match {
|
||||
case x :: Nil => x
|
||||
case xs => invalid("Expected single file for component '" + id + "', found: " + xs.mkString(", "))
|
||||
}
|
||||
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]) = lockLocalCache { provider.defineComponent(id, files.toSeq.toArray) }
|
||||
/** Retrieve the file for component 'id' from the local repository. */
|
||||
private def update(id: String): Unit = ivyCache.withCachedJar(sbtModuleID(id), Some(globalLock), log)(jar => define(id, Seq(jar)) )
|
||||
def define(id: String, files: Iterable[File]) = lockLocalCache { provider.defineComponent(id, files.toSeq.toArray) }
|
||||
/** Retrieve the file for component 'id' from the local repository. */
|
||||
private def update(id: String): Unit = ivyCache.withCachedJar(sbtModuleID(id), Some(globalLock), log)(jar => define(id, Seq(jar)))
|
||||
|
||||
private def sbtModuleID(id: String) = ModuleID(SbtArtifacts.Organization, id, ComponentManager.stampedVersion)
|
||||
/** 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)(IfMissing.Fail), Some(globalLock), log)
|
||||
def clearCache(id: String): Unit = lockGlobalCache { ivyCache.clearCachedJar(sbtModuleID(id), Some(globalLock), log) }
|
||||
private def sbtModuleID(id: String) = ModuleID(SbtArtifacts.Organization, id, ComponentManager.stampedVersion)
|
||||
/** 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)(IfMissing.Fail), Some(globalLock), log)
|
||||
def clearCache(id: String): Unit = lockGlobalCache { ivyCache.clearCachedJar(sbtModuleID(id), Some(globalLock), log) }
|
||||
}
|
||||
class InvalidComponent(msg: String, cause: Throwable) extends RuntimeException(msg, cause)
|
||||
{
|
||||
def this(msg: String) = this(msg, null)
|
||||
class InvalidComponent(msg: String, cause: Throwable) extends RuntimeException(msg, cause) {
|
||||
def this(msg: String) = this(msg, null)
|
||||
}
|
||||
sealed trait IfMissing extends NotNull
|
||||
object IfMissing
|
||||
{
|
||||
object Fail extends IfMissing
|
||||
final class Define(val cache: Boolean, define: => Unit) extends IfMissing { def apply() = define }
|
||||
object IfMissing {
|
||||
object Fail extends IfMissing
|
||||
final class Define(val cache: Boolean, define: => Unit) extends IfMissing { def apply() = define }
|
||||
}
|
||||
object ComponentManager
|
||||
{
|
||||
lazy val (version, timestamp) =
|
||||
{
|
||||
val properties = new java.util.Properties
|
||||
val propertiesStream = versionResource.openStream
|
||||
try { properties.load(propertiesStream) } finally { propertiesStream.close() }
|
||||
(properties.getProperty("version"), properties.getProperty("timestamp"))
|
||||
}
|
||||
lazy val stampedVersion = version + "_" + timestamp
|
||||
object ComponentManager {
|
||||
lazy val (version, timestamp) =
|
||||
{
|
||||
val properties = new java.util.Properties
|
||||
val propertiesStream = versionResource.openStream
|
||||
try { properties.load(propertiesStream) } finally { propertiesStream.close() }
|
||||
(properties.getProperty("version"), properties.getProperty("timestamp"))
|
||||
}
|
||||
lazy val stampedVersion = version + "_" + timestamp
|
||||
|
||||
import java.net.URL
|
||||
private def versionResource: URL = getClass.getResource("/xsbt.version.properties")
|
||||
import java.net.URL
|
||||
private def versionResource: URL = getClass.getResource("/xsbt.version.properties")
|
||||
}
|
||||
|
|
@ -3,63 +3,61 @@
|
|||
*/
|
||||
package sbt
|
||||
|
||||
object Configurations
|
||||
{
|
||||
def config(name: String) = new Configuration(name)
|
||||
def default: Seq[Configuration] = defaultMavenConfigurations
|
||||
def defaultMavenConfigurations: Seq[Configuration] = Seq(Compile, Runtime, Test, Provided, Optional)
|
||||
def defaultInternal: Seq[Configuration] = Seq(CompileInternal, RuntimeInternal, TestInternal)
|
||||
def auxiliary: Seq[Configuration] = Seq(Sources, Docs, Pom)
|
||||
def names(cs: Seq[Configuration]) = cs.map(_.name)
|
||||
object Configurations {
|
||||
def config(name: String) = new Configuration(name)
|
||||
def default: Seq[Configuration] = defaultMavenConfigurations
|
||||
def defaultMavenConfigurations: Seq[Configuration] = Seq(Compile, Runtime, Test, Provided, Optional)
|
||||
def defaultInternal: Seq[Configuration] = Seq(CompileInternal, RuntimeInternal, TestInternal)
|
||||
def auxiliary: Seq[Configuration] = Seq(Sources, Docs, Pom)
|
||||
def names(cs: Seq[Configuration]) = cs.map(_.name)
|
||||
|
||||
lazy val RuntimeInternal = optionalInternal(Runtime)
|
||||
lazy val TestInternal = fullInternal(Test)
|
||||
lazy val IntegrationTestInternal = fullInternal(IntegrationTest)
|
||||
lazy val CompileInternal = fullInternal(Compile)
|
||||
lazy val RuntimeInternal = optionalInternal(Runtime)
|
||||
lazy val TestInternal = fullInternal(Test)
|
||||
lazy val IntegrationTestInternal = fullInternal(IntegrationTest)
|
||||
lazy val CompileInternal = fullInternal(Compile)
|
||||
|
||||
def internalMap(c: Configuration) = c match {
|
||||
case Compile => CompileInternal
|
||||
case Test => TestInternal
|
||||
case Runtime => RuntimeInternal
|
||||
case IntegrationTest => IntegrationTestInternal
|
||||
case _ => c
|
||||
}
|
||||
def internalMap(c: Configuration) = c match {
|
||||
case Compile => CompileInternal
|
||||
case Test => TestInternal
|
||||
case Runtime => RuntimeInternal
|
||||
case IntegrationTest => IntegrationTestInternal
|
||||
case _ => c
|
||||
}
|
||||
|
||||
def internal(base: Configuration, ext: Configuration*) = config(base.name + "-internal") extend(ext : _*) hide;
|
||||
def fullInternal(base: Configuration): Configuration = internal(base, base, Optional, Provided)
|
||||
def optionalInternal(base: Configuration): Configuration = internal(base, base, Optional)
|
||||
def internal(base: Configuration, ext: Configuration*) = config(base.name + "-internal") extend (ext: _*) hide;
|
||||
def fullInternal(base: Configuration): Configuration = internal(base, base, Optional, Provided)
|
||||
def optionalInternal(base: Configuration): Configuration = internal(base, base, Optional)
|
||||
|
||||
lazy val Default = config("default")
|
||||
lazy val Compile = config("compile")
|
||||
lazy val IntegrationTest = config("it") extend(Runtime)
|
||||
lazy val Provided = config("provided") ;
|
||||
lazy val Docs = config("docs")
|
||||
lazy val Runtime = config("runtime") extend(Compile)
|
||||
lazy val Test = config("test") extend(Runtime)
|
||||
lazy val Sources = config("sources")
|
||||
lazy val System = config("system")
|
||||
lazy val Optional = config("optional")
|
||||
lazy val Pom = config("pom")
|
||||
lazy val Default = config("default")
|
||||
lazy val Compile = config("compile")
|
||||
lazy val IntegrationTest = config("it") extend (Runtime)
|
||||
lazy val Provided = config("provided");
|
||||
lazy val Docs = config("docs")
|
||||
lazy val Runtime = config("runtime") extend (Compile)
|
||||
lazy val Test = config("test") extend (Runtime)
|
||||
lazy val Sources = config("sources")
|
||||
lazy val System = config("system")
|
||||
lazy val Optional = config("optional")
|
||||
lazy val Pom = config("pom")
|
||||
|
||||
lazy val ScalaTool = config("scala-tool") hide
|
||||
lazy val CompilerPlugin = config("plugin") hide
|
||||
lazy val ScalaTool = config("scala-tool") hide
|
||||
lazy val CompilerPlugin = config("plugin") hide
|
||||
|
||||
private[sbt] val DefaultMavenConfiguration = defaultConfiguration(true)
|
||||
private[sbt] val DefaultIvyConfiguration = defaultConfiguration(false)
|
||||
private[sbt] def DefaultConfiguration(mavenStyle: Boolean) = if(mavenStyle) DefaultMavenConfiguration else DefaultIvyConfiguration
|
||||
private[sbt] def defaultConfiguration(mavenStyle: Boolean) = if(mavenStyle) Configurations.Compile else Configurations.Default
|
||||
private[sbt] def removeDuplicates(configs: Iterable[Configuration]) = Set(scala.collection.mutable.Map(configs.map(config => (config.name, config)).toSeq: _*).values.toList: _*)
|
||||
private[sbt] val DefaultMavenConfiguration = defaultConfiguration(true)
|
||||
private[sbt] val DefaultIvyConfiguration = defaultConfiguration(false)
|
||||
private[sbt] def DefaultConfiguration(mavenStyle: Boolean) = if (mavenStyle) DefaultMavenConfiguration else DefaultIvyConfiguration
|
||||
private[sbt] def defaultConfiguration(mavenStyle: Boolean) = if (mavenStyle) Configurations.Compile else Configurations.Default
|
||||
private[sbt] 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)
|
||||
{
|
||||
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 Configuration(name: String, description: String, isPublic: Boolean, extendsConfigs: List[Configuration], transitive: Boolean) {
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,80 +1,74 @@
|
|||
package sbt
|
||||
|
||||
import DependencyFilter._
|
||||
import DependencyFilter._
|
||||
|
||||
final case class ConflictWarning(label: String, level: Level.Value, failOnConflict: Boolean)
|
||||
{
|
||||
@deprecated("`filter` is no longer used", "0.13.0")
|
||||
val filter: ModuleFilter = (_: ModuleID) => false
|
||||
@deprecated("`group` is no longer used", "0.13.0")
|
||||
val group: ModuleID => String = ConflictWarning.org
|
||||
final case class ConflictWarning(label: String, level: Level.Value, failOnConflict: Boolean) {
|
||||
@deprecated("`filter` is no longer used", "0.13.0")
|
||||
val filter: ModuleFilter = (_: ModuleID) => false
|
||||
@deprecated("`group` is no longer used", "0.13.0")
|
||||
val group: ModuleID => String = ConflictWarning.org
|
||||
}
|
||||
object ConflictWarning
|
||||
{
|
||||
@deprecated("`group` and `filter` are no longer used. Use a standard Ivy conflict manager.", "0.13.0")
|
||||
def apply(label: String, filter: ModuleFilter, group: ModuleID => String, level: Level.Value, failOnConflict: Boolean): ConflictWarning =
|
||||
ConflictWarning(label, level, failOnConflict)
|
||||
object ConflictWarning {
|
||||
@deprecated("`group` and `filter` are no longer used. Use a standard Ivy conflict manager.", "0.13.0")
|
||||
def apply(label: String, filter: ModuleFilter, group: ModuleID => String, level: Level.Value, failOnConflict: Boolean): ConflictWarning =
|
||||
ConflictWarning(label, level, failOnConflict)
|
||||
|
||||
def disable: ConflictWarning = ConflictWarning("", Level.Debug, false)
|
||||
def disable: ConflictWarning = ConflictWarning("", Level.Debug, false)
|
||||
|
||||
private def org = (_: ModuleID).organization
|
||||
private[this] def idString(org: String, name: String) = s"$org:$name"
|
||||
private def org = (_: ModuleID).organization
|
||||
private[this] def idString(org: String, name: String) = s"$org:$name"
|
||||
|
||||
def default(label: String): ConflictWarning = ConflictWarning(label, Level.Error, true)
|
||||
def default(label: String): ConflictWarning = ConflictWarning(label, Level.Error, true)
|
||||
|
||||
@deprecated("Warning on evicted modules is no longer done, so this is the same as `default`. Use a standard Ivy conflict manager.", "0.13.0")
|
||||
def strict(label: String): ConflictWarning = ConflictWarning(label, Level.Error, true)
|
||||
@deprecated("Warning on evicted modules is no longer done, so this is the same as `default`. Use a standard Ivy conflict manager.", "0.13.0")
|
||||
def strict(label: String): ConflictWarning = ConflictWarning(label, Level.Error, true)
|
||||
|
||||
def apply(config: ConflictWarning, report: UpdateReport, log: Logger)
|
||||
{
|
||||
processCrossVersioned(config, report, log)
|
||||
}
|
||||
private[this] def processCrossVersioned(config: ConflictWarning, report: UpdateReport, log: Logger)
|
||||
{
|
||||
val crossMismatches = crossVersionMismatches(report)
|
||||
if(!crossMismatches.isEmpty)
|
||||
{
|
||||
val pre = s"Modules were resolved with conflicting cross-version suffixes in ${config.label}:\n "
|
||||
val conflictMsgs =
|
||||
for( ((org,rawName), fullNames) <- crossMismatches ) yield
|
||||
{
|
||||
val suffixes = fullNames.map(getCrossSuffix).mkString(", ")
|
||||
s"${idString(org,rawName)} $suffixes"
|
||||
}
|
||||
log.log(config.level, conflictMsgs.mkString(pre, "\n ", ""))
|
||||
if(config.failOnConflict) {
|
||||
val summary = crossMismatches.map{ case ((org,raw),_) => idString(org,raw)}.mkString(", ")
|
||||
sys.error("Conflicting cross-version suffixes in: " + summary)
|
||||
}
|
||||
}
|
||||
}
|
||||
def apply(config: ConflictWarning, report: UpdateReport, log: Logger) {
|
||||
processCrossVersioned(config, report, log)
|
||||
}
|
||||
private[this] def processCrossVersioned(config: ConflictWarning, report: UpdateReport, log: Logger) {
|
||||
val crossMismatches = crossVersionMismatches(report)
|
||||
if (!crossMismatches.isEmpty) {
|
||||
val pre = s"Modules were resolved with conflicting cross-version suffixes in ${config.label}:\n "
|
||||
val conflictMsgs =
|
||||
for (((org, rawName), fullNames) <- crossMismatches) yield {
|
||||
val suffixes = fullNames.map(getCrossSuffix).mkString(", ")
|
||||
s"${idString(org, rawName)} $suffixes"
|
||||
}
|
||||
log.log(config.level, conflictMsgs.mkString(pre, "\n ", ""))
|
||||
if (config.failOnConflict) {
|
||||
val summary = crossMismatches.map { case ((org, raw), _) => idString(org, raw) }.mkString(", ")
|
||||
sys.error("Conflicting cross-version suffixes in: " + summary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Map from (organization, rawName) to set of multiple full names. */
|
||||
def crossVersionMismatches(report: UpdateReport): Map[(String,String), Set[String]] =
|
||||
{
|
||||
val mismatches = report.configurations.flatMap { confReport =>
|
||||
groupByRawName(confReport.allModules).mapValues { modules =>
|
||||
val differentFullNames = modules.map(_.name).toSet
|
||||
if(differentFullNames.size > 1) differentFullNames else Set.empty[String]
|
||||
}
|
||||
}
|
||||
(Map.empty[(String,String),Set[String]] /: mismatches)(merge)
|
||||
}
|
||||
private[this] def merge[A,B](m: Map[A, Set[B]], b: (A, Set[B])): Map[A, Set[B]] =
|
||||
if(b._2.isEmpty) m else
|
||||
m.updated(b._1, m.getOrElse(b._1, Set.empty) ++ b._2)
|
||||
/** Map from (organization, rawName) to set of multiple full names. */
|
||||
def crossVersionMismatches(report: UpdateReport): Map[(String, String), Set[String]] =
|
||||
{
|
||||
val mismatches = report.configurations.flatMap { confReport =>
|
||||
groupByRawName(confReport.allModules).mapValues { modules =>
|
||||
val differentFullNames = modules.map(_.name).toSet
|
||||
if (differentFullNames.size > 1) differentFullNames else Set.empty[String]
|
||||
}
|
||||
}
|
||||
(Map.empty[(String, String), Set[String]] /: mismatches)(merge)
|
||||
}
|
||||
private[this] def merge[A, B](m: Map[A, Set[B]], b: (A, Set[B])): Map[A, Set[B]] =
|
||||
if (b._2.isEmpty) m else
|
||||
m.updated(b._1, m.getOrElse(b._1, Set.empty) ++ b._2)
|
||||
|
||||
private[this] def groupByRawName(ms: Seq[ModuleID]): Map[(String,String), Seq[ModuleID]] =
|
||||
ms.groupBy(m => (m.organization, dropCrossSuffix(m.name)))
|
||||
private[this] def groupByRawName(ms: Seq[ModuleID]): Map[(String, String), Seq[ModuleID]] =
|
||||
ms.groupBy(m => (m.organization, dropCrossSuffix(m.name)))
|
||||
|
||||
private[this] val CrossSuffixPattern = """(.+)_(\d+\.\d+(?:\.\d+)?(?:-.+)?)""".r
|
||||
private[this] def dropCrossSuffix(s: String): String = s match {
|
||||
case CrossSuffixPattern(raw, _) => raw
|
||||
case _ => s
|
||||
}
|
||||
private[this] def getCrossSuffix(s: String): String = s match {
|
||||
case CrossSuffixPattern(_, v) => "_" + v
|
||||
case _ => "<none>"
|
||||
}
|
||||
private[this] val CrossSuffixPattern = """(.+)_(\d+\.\d+(?:\.\d+)?(?:-.+)?)""".r
|
||||
private[this] def dropCrossSuffix(s: String): String = s match {
|
||||
case CrossSuffixPattern(raw, _) => raw
|
||||
case _ => s
|
||||
}
|
||||
private[this] def getCrossSuffix(s: String): String = s match {
|
||||
case CrossSuffixPattern(_, v) => "_" + v
|
||||
case _ => "<none>"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,239 +5,234 @@ package sbt
|
|||
|
||||
import java.net.URL
|
||||
import java.util.Collections
|
||||
import org.apache.ivy.{core,plugins}
|
||||
import org.apache.ivy.{ core, plugins }
|
||||
import core.module.id.ModuleRevisionId
|
||||
import core.module.descriptor.DependencyDescriptor
|
||||
import core.resolve.ResolveData
|
||||
import core.settings.IvySettings
|
||||
import plugins.resolver.{BasicResolver, DependencyResolver, IBiblioResolver, RepositoryResolver}
|
||||
import plugins.resolver.{AbstractPatternsBasedResolver, AbstractSshBasedResolver, FileSystemResolver, SFTPResolver, SshResolver, URLResolver}
|
||||
import plugins.repository.url.{URLRepository => URLRepo}
|
||||
import plugins.repository.file.{FileRepository => FileRepo, FileResource}
|
||||
import plugins.resolver.{ BasicResolver, DependencyResolver, IBiblioResolver, RepositoryResolver }
|
||||
import plugins.resolver.{ AbstractPatternsBasedResolver, AbstractSshBasedResolver, FileSystemResolver, SFTPResolver, SshResolver, URLResolver }
|
||||
import plugins.repository.url.{ URLRepository => URLRepo }
|
||||
import plugins.repository.file.{ FileRepository => FileRepo, FileResource }
|
||||
import java.io.File
|
||||
import org.apache.ivy.util.ChecksumHelper
|
||||
import org.apache.ivy.core.module.descriptor.{Artifact=>IArtifact}
|
||||
import org.apache.ivy.core.module.descriptor.{ Artifact => IArtifact }
|
||||
|
||||
|
||||
private object ConvertResolver
|
||||
{
|
||||
/** This class contains all the reflective lookups used in the
|
||||
* checksum-friendly URL publishing shim.
|
||||
*/
|
||||
private object ChecksumFriendlyURLResolver {
|
||||
// TODO - When we dump JDK6 support we can remove this hackery
|
||||
// import java.lang.reflect.AccessibleObject
|
||||
type AccessibleObject = {
|
||||
def setAccessible(value: Boolean): Unit
|
||||
}
|
||||
private def reflectiveLookup[A <: AccessibleObject](f: Class[_] => A): Option[A] =
|
||||
try {
|
||||
val cls = classOf[RepositoryResolver]
|
||||
val thing = f(cls)
|
||||
import scala.language.reflectiveCalls
|
||||
thing.setAccessible(true)
|
||||
Some(thing)
|
||||
} catch {
|
||||
case (_: java.lang.NoSuchFieldException) |
|
||||
(_: java.lang.SecurityException) |
|
||||
(_: java.lang.NoSuchMethodException) => None
|
||||
}
|
||||
private val signerNameField: Option[java.lang.reflect.Field] =
|
||||
reflectiveLookup(_.getDeclaredField("signerName"))
|
||||
private val putChecksumMethod: Option[java.lang.reflect.Method] =
|
||||
reflectiveLookup(_.getDeclaredMethod("putChecksum",
|
||||
classOf[IArtifact], classOf[File], classOf[String],
|
||||
classOf[Boolean], classOf[String]))
|
||||
private val putSignatureMethod: Option[java.lang.reflect.Method] =
|
||||
reflectiveLookup(_.getDeclaredMethod("putSignature",
|
||||
classOf[IArtifact], classOf[File], classOf[String],
|
||||
classOf[Boolean]))
|
||||
}
|
||||
/**
|
||||
* The default behavior of ivy's overwrite flags ignores the fact that a lot of repositories
|
||||
* will autogenerate checksums *for* an artifact if it doesn't already exist. Therefore
|
||||
* if we succeed in publishing an artifact, we need to just blast the checksums in place.
|
||||
* This acts as a "shim" on RepositoryResolvers so that we can hook our methods into
|
||||
* both the IBiblioResolver + URLResolver without having to duplicate the code in two
|
||||
* places. However, this does mean our use of reflection is awesome.
|
||||
*
|
||||
* TODO - See about contributing back to ivy.
|
||||
*/
|
||||
private trait ChecksumFriendlyURLResolver extends RepositoryResolver {
|
||||
import ChecksumFriendlyURLResolver._
|
||||
private def signerName: String = signerNameField match {
|
||||
case Some(field) => field.get(this).asInstanceOf[String]
|
||||
case None => null
|
||||
}
|
||||
override protected def put(artifact: IArtifact, src: File, dest: String, overwrite: Boolean): Unit = {
|
||||
// verify the checksum algorithms before uploading artifacts!
|
||||
val checksums = getChecksumAlgorithms()
|
||||
val repository = getRepository()
|
||||
for {
|
||||
checksum <- checksums
|
||||
if !ChecksumHelper.isKnownAlgorithm(checksum)
|
||||
} throw new IllegalArgumentException("Unknown checksum algorithm: " + checksum)
|
||||
repository.put(artifact, src, dest, overwrite);
|
||||
// Fix for sbt#1156 - Artifactory will auto-generate MD5/sha1 files, so
|
||||
// we need to overwrite what it has.
|
||||
for (checksum <- checksums) {
|
||||
putChecksumMethod match {
|
||||
case Some(method) => method.invoke(this, artifact, src, dest, true: java.lang.Boolean, checksum)
|
||||
case None => // TODO - issue warning?
|
||||
}
|
||||
}
|
||||
if (signerName != null) {
|
||||
putSignatureMethod match {
|
||||
case None => ()
|
||||
case Some(method) => method.invoke(artifact, src, dest, true: java.lang.Boolean)
|
||||
}
|
||||
}
|
||||
private object ConvertResolver {
|
||||
/**
|
||||
* This class contains all the reflective lookups used in the
|
||||
* checksum-friendly URL publishing shim.
|
||||
*/
|
||||
private object ChecksumFriendlyURLResolver {
|
||||
// TODO - When we dump JDK6 support we can remove this hackery
|
||||
// import java.lang.reflect.AccessibleObject
|
||||
type AccessibleObject = {
|
||||
def setAccessible(value: Boolean): Unit
|
||||
}
|
||||
}
|
||||
private def reflectiveLookup[A <: AccessibleObject](f: Class[_] => A): Option[A] =
|
||||
try {
|
||||
val cls = classOf[RepositoryResolver]
|
||||
val thing = f(cls)
|
||||
import scala.language.reflectiveCalls
|
||||
thing.setAccessible(true)
|
||||
Some(thing)
|
||||
} catch {
|
||||
case (_: java.lang.NoSuchFieldException) |
|
||||
(_: java.lang.SecurityException) |
|
||||
(_: java.lang.NoSuchMethodException) => None
|
||||
}
|
||||
private val signerNameField: Option[java.lang.reflect.Field] =
|
||||
reflectiveLookup(_.getDeclaredField("signerName"))
|
||||
private val putChecksumMethod: Option[java.lang.reflect.Method] =
|
||||
reflectiveLookup(_.getDeclaredMethod("putChecksum",
|
||||
classOf[IArtifact], classOf[File], classOf[String],
|
||||
classOf[Boolean], classOf[String]))
|
||||
private val putSignatureMethod: Option[java.lang.reflect.Method] =
|
||||
reflectiveLookup(_.getDeclaredMethod("putSignature",
|
||||
classOf[IArtifact], classOf[File], classOf[String],
|
||||
classOf[Boolean]))
|
||||
}
|
||||
/**
|
||||
* The default behavior of ivy's overwrite flags ignores the fact that a lot of repositories
|
||||
* will autogenerate checksums *for* an artifact if it doesn't already exist. Therefore
|
||||
* if we succeed in publishing an artifact, we need to just blast the checksums in place.
|
||||
* This acts as a "shim" on RepositoryResolvers so that we can hook our methods into
|
||||
* both the IBiblioResolver + URLResolver without having to duplicate the code in two
|
||||
* places. However, this does mean our use of reflection is awesome.
|
||||
*
|
||||
* TODO - See about contributing back to ivy.
|
||||
*/
|
||||
private trait ChecksumFriendlyURLResolver extends RepositoryResolver {
|
||||
import ChecksumFriendlyURLResolver._
|
||||
private def signerName: String = signerNameField match {
|
||||
case Some(field) => field.get(this).asInstanceOf[String]
|
||||
case None => null
|
||||
}
|
||||
override protected def put(artifact: IArtifact, src: File, dest: String, overwrite: Boolean): Unit = {
|
||||
// verify the checksum algorithms before uploading artifacts!
|
||||
val checksums = getChecksumAlgorithms()
|
||||
val repository = getRepository()
|
||||
for {
|
||||
checksum <- checksums
|
||||
if !ChecksumHelper.isKnownAlgorithm(checksum)
|
||||
} throw new IllegalArgumentException("Unknown checksum algorithm: " + checksum)
|
||||
repository.put(artifact, src, dest, overwrite);
|
||||
// Fix for sbt#1156 - Artifactory will auto-generate MD5/sha1 files, so
|
||||
// we need to overwrite what it has.
|
||||
for (checksum <- checksums) {
|
||||
putChecksumMethod match {
|
||||
case Some(method) => method.invoke(this, artifact, src, dest, true: java.lang.Boolean, checksum)
|
||||
case None => // TODO - issue warning?
|
||||
}
|
||||
}
|
||||
if (signerName != null) {
|
||||
putSignatureMethod match {
|
||||
case None => ()
|
||||
case Some(method) => method.invoke(artifact, src, dest, true: java.lang.Boolean)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Converts the given sbt resolver into an Ivy resolver..*/
|
||||
def apply(r: Resolver, settings: IvySettings, log: Logger) =
|
||||
{
|
||||
r match
|
||||
{
|
||||
case repo: MavenRepository =>
|
||||
{
|
||||
val pattern = Collections.singletonList(Resolver.resolvePattern(repo.root, Resolver.mavenStyleBasePattern))
|
||||
final class PluginCapableResolver extends IBiblioResolver with ChecksumFriendlyURLResolver with DescriptorRequired {
|
||||
def setPatterns() { // done this way for access to protected methods.
|
||||
setArtifactPatterns(pattern)
|
||||
setIvyPatterns(pattern)
|
||||
}
|
||||
}
|
||||
val resolver = new PluginCapableResolver
|
||||
resolver.setRepository(new LocalIfFileRepo)
|
||||
initializeMavenStyle(resolver, repo.name, repo.root)
|
||||
resolver.setPatterns() // has to be done after initializeMavenStyle, which calls methods that overwrite the patterns
|
||||
resolver
|
||||
}
|
||||
case r: 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 with DescriptorRequired { 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 with DescriptorRequired
|
||||
initializeSSHResolver(resolver, repo, settings)
|
||||
repo.publishPermissions.foreach(perm => resolver.setPublishPermissions(perm))
|
||||
resolver
|
||||
}
|
||||
case repo: SftpRepository =>
|
||||
{
|
||||
val resolver = new SFTPResolver
|
||||
initializeSSHResolver(resolver, repo, settings)
|
||||
resolver
|
||||
}
|
||||
case repo: FileRepository =>
|
||||
{
|
||||
val resolver = new FileSystemResolver with DescriptorRequired {
|
||||
// Workaround for #1156
|
||||
// Temporarily in sbt 0.13.x we deprecate overwriting
|
||||
// in local files for non-changing revisions.
|
||||
// This will be fully enforced in sbt 1.0.
|
||||
setRepository(new WarnOnOverwriteFileRepo())
|
||||
}
|
||||
resolver.setName(repo.name)
|
||||
initializePatterns(resolver, repo.patterns, settings)
|
||||
import repo.configuration.{isLocal, isTransactional}
|
||||
resolver.setLocal(isLocal)
|
||||
isTransactional.foreach(value => resolver.setTransactional(value.toString))
|
||||
resolver
|
||||
}
|
||||
case repo: URLRepository =>
|
||||
{
|
||||
val resolver = new URLResolver with ChecksumFriendlyURLResolver with DescriptorRequired
|
||||
resolver.setName(repo.name)
|
||||
initializePatterns(resolver, repo.patterns, settings)
|
||||
resolver
|
||||
}
|
||||
case repo: ChainedResolver => IvySbt.resolverChain(repo.name, repo.resolvers, false, settings, log)
|
||||
case repo: RawRepository => repo.resolver
|
||||
}
|
||||
}
|
||||
|
||||
private sealed trait DescriptorRequired extends BasicResolver
|
||||
{
|
||||
override def getDependency(dd: DependencyDescriptor, data: ResolveData) =
|
||||
{
|
||||
val prev = descriptorString(isAllownomd)
|
||||
setDescriptor(descriptorString(hasExplicitURL(dd)))
|
||||
try super.getDependency(dd, data) finally setDescriptor(prev)
|
||||
}
|
||||
def descriptorString(optional: Boolean) =
|
||||
if(optional) BasicResolver.DESCRIPTOR_OPTIONAL else BasicResolver.DESCRIPTOR_REQUIRED
|
||||
def hasExplicitURL(dd: DependencyDescriptor): Boolean =
|
||||
dd.getAllDependencyArtifacts.exists(_.getUrl != null)
|
||||
}
|
||||
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, settings: IvySettings)
|
||||
{
|
||||
resolver.setName(repo.name)
|
||||
resolver.setPassfile(null)
|
||||
initializePatterns(resolver, repo.patterns, settings)
|
||||
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)
|
||||
password.foreach(setUserPassword)
|
||||
case RepositoryHelpers.KeyFileAuthentication(user, file, password) =>
|
||||
setKeyFile(file)
|
||||
password.foreach(setKeyFilePassword)
|
||||
setUser(user)
|
||||
}
|
||||
}
|
||||
private def initializePatterns(resolver: AbstractPatternsBasedResolver, patterns: Patterns, settings: IvySettings)
|
||||
{
|
||||
resolver.setM2compatible(patterns.isMavenCompatible)
|
||||
resolver.setDescriptor(if (patterns.descriptorOptional) BasicResolver.DESCRIPTOR_OPTIONAL else BasicResolver.DESCRIPTOR_REQUIRED)
|
||||
resolver.setCheckconsistency(!patterns.skipConsistencyCheck)
|
||||
patterns.ivyPatterns.foreach(p => resolver.addIvyPattern(settings substitute p))
|
||||
patterns.artifactPatterns.foreach(p => resolver.addArtifactPattern(settings substitute p))
|
||||
}
|
||||
/** A custom Ivy URLRepository that returns FileResources for file URLs.
|
||||
* This allows using the artifacts from the Maven local repository instead of copying them to the Ivy cache. */
|
||||
private[this] final class LocalIfFileRepo extends URLRepo {
|
||||
private[this] val repo = new WarnOnOverwriteFileRepo()
|
||||
override def getResource(source: String) = {
|
||||
val url = new URL(source)
|
||||
if(url.getProtocol == IO.FileScheme)
|
||||
new FileResource(repo, IO.toFile(url))
|
||||
else
|
||||
super.getResource(source)
|
||||
}
|
||||
}
|
||||
/** Converts the given sbt resolver into an Ivy resolver..*/
|
||||
def apply(r: Resolver, settings: IvySettings, log: Logger) =
|
||||
{
|
||||
r match {
|
||||
case repo: MavenRepository =>
|
||||
{
|
||||
val pattern = Collections.singletonList(Resolver.resolvePattern(repo.root, Resolver.mavenStyleBasePattern))
|
||||
final class PluginCapableResolver extends IBiblioResolver with ChecksumFriendlyURLResolver with DescriptorRequired {
|
||||
def setPatterns() { // done this way for access to protected methods.
|
||||
setArtifactPatterns(pattern)
|
||||
setIvyPatterns(pattern)
|
||||
}
|
||||
}
|
||||
val resolver = new PluginCapableResolver
|
||||
resolver.setRepository(new LocalIfFileRepo)
|
||||
initializeMavenStyle(resolver, repo.name, repo.root)
|
||||
resolver.setPatterns() // has to be done after initializeMavenStyle, which calls methods that overwrite the patterns
|
||||
resolver
|
||||
}
|
||||
case r: 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 with DescriptorRequired { 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 with DescriptorRequired
|
||||
initializeSSHResolver(resolver, repo, settings)
|
||||
repo.publishPermissions.foreach(perm => resolver.setPublishPermissions(perm))
|
||||
resolver
|
||||
}
|
||||
case repo: SftpRepository =>
|
||||
{
|
||||
val resolver = new SFTPResolver
|
||||
initializeSSHResolver(resolver, repo, settings)
|
||||
resolver
|
||||
}
|
||||
case repo: FileRepository =>
|
||||
{
|
||||
val resolver = new FileSystemResolver with DescriptorRequired {
|
||||
// Workaround for #1156
|
||||
// Temporarily in sbt 0.13.x we deprecate overwriting
|
||||
// in local files for non-changing revisions.
|
||||
// This will be fully enforced in sbt 1.0.
|
||||
setRepository(new WarnOnOverwriteFileRepo())
|
||||
}
|
||||
resolver.setName(repo.name)
|
||||
initializePatterns(resolver, repo.patterns, settings)
|
||||
import repo.configuration.{ isLocal, isTransactional }
|
||||
resolver.setLocal(isLocal)
|
||||
isTransactional.foreach(value => resolver.setTransactional(value.toString))
|
||||
resolver
|
||||
}
|
||||
case repo: URLRepository =>
|
||||
{
|
||||
val resolver = new URLResolver with ChecksumFriendlyURLResolver with DescriptorRequired
|
||||
resolver.setName(repo.name)
|
||||
initializePatterns(resolver, repo.patterns, settings)
|
||||
resolver
|
||||
}
|
||||
case repo: ChainedResolver => IvySbt.resolverChain(repo.name, repo.resolvers, false, settings, log)
|
||||
case repo: RawRepository => repo.resolver
|
||||
}
|
||||
}
|
||||
|
||||
private[this] final class WarnOnOverwriteFileRepo extends FileRepo() {
|
||||
override def put(source: java.io.File, destination: String, overwrite: Boolean): Unit = {
|
||||
try super.put(source, destination, overwrite)
|
||||
catch {
|
||||
case e: java.io.IOException if e.getMessage.contains("destination already exists") =>
|
||||
import org.apache.ivy.util.Message
|
||||
Message.warn(s"Attempting to overwrite $destination\n\tThis usage is deprecated and will be removed in sbt 1.0.")
|
||||
super.put(source, destination, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
private sealed trait DescriptorRequired extends BasicResolver {
|
||||
override def getDependency(dd: DependencyDescriptor, data: ResolveData) =
|
||||
{
|
||||
val prev = descriptorString(isAllownomd)
|
||||
setDescriptor(descriptorString(hasExplicitURL(dd)))
|
||||
try super.getDependency(dd, data) finally setDescriptor(prev)
|
||||
}
|
||||
def descriptorString(optional: Boolean) =
|
||||
if (optional) BasicResolver.DESCRIPTOR_OPTIONAL else BasicResolver.DESCRIPTOR_REQUIRED
|
||||
def hasExplicitURL(dd: DependencyDescriptor): Boolean =
|
||||
dd.getAllDependencyArtifacts.exists(_.getUrl != null)
|
||||
}
|
||||
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, settings: IvySettings) {
|
||||
resolver.setName(repo.name)
|
||||
resolver.setPassfile(null)
|
||||
initializePatterns(resolver, repo.patterns, settings)
|
||||
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)
|
||||
password.foreach(setUserPassword)
|
||||
case RepositoryHelpers.KeyFileAuthentication(user, file, password) =>
|
||||
setKeyFile(file)
|
||||
password.foreach(setKeyFilePassword)
|
||||
setUser(user)
|
||||
}
|
||||
}
|
||||
private def initializePatterns(resolver: AbstractPatternsBasedResolver, patterns: Patterns, settings: IvySettings) {
|
||||
resolver.setM2compatible(patterns.isMavenCompatible)
|
||||
resolver.setDescriptor(if (patterns.descriptorOptional) BasicResolver.DESCRIPTOR_OPTIONAL else BasicResolver.DESCRIPTOR_REQUIRED)
|
||||
resolver.setCheckconsistency(!patterns.skipConsistencyCheck)
|
||||
patterns.ivyPatterns.foreach(p => resolver.addIvyPattern(settings substitute p))
|
||||
patterns.artifactPatterns.foreach(p => resolver.addArtifactPattern(settings substitute p))
|
||||
}
|
||||
/**
|
||||
* A custom Ivy URLRepository that returns FileResources for file URLs.
|
||||
* This allows using the artifacts from the Maven local repository instead of copying them to the Ivy cache.
|
||||
*/
|
||||
private[this] final class LocalIfFileRepo extends URLRepo {
|
||||
private[this] val repo = new WarnOnOverwriteFileRepo()
|
||||
override def getResource(source: String) = {
|
||||
val url = new URL(source)
|
||||
if (url.getProtocol == IO.FileScheme)
|
||||
new FileResource(repo, IO.toFile(url))
|
||||
else
|
||||
super.getResource(source)
|
||||
}
|
||||
}
|
||||
|
||||
private[this] final class WarnOnOverwriteFileRepo extends FileRepo() {
|
||||
override def put(source: java.io.File, destination: String, overwrite: Boolean): Unit = {
|
||||
try super.put(source, destination, overwrite)
|
||||
catch {
|
||||
case e: java.io.IOException if e.getMessage.contains("destination already exists") =>
|
||||
import org.apache.ivy.util.Message
|
||||
Message.warn(s"Attempting to overwrite $destination\n\tThis usage is deprecated and will be removed in sbt 1.0.")
|
||||
super.put(source, destination, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,71 +6,66 @@ package sbt
|
|||
import java.io.File
|
||||
import org.apache.ivy.util.url.CredentialsStore
|
||||
|
||||
object Credentials
|
||||
{
|
||||
def apply(realm: String, host: String, userName: String, passwd: String): Credentials =
|
||||
new DirectCredentials(realm, host, userName, passwd)
|
||||
def apply(file: File): Credentials =
|
||||
new FileCredentials(file)
|
||||
object Credentials {
|
||||
def apply(realm: String, host: String, userName: String, passwd: String): Credentials =
|
||||
new DirectCredentials(realm, host, userName, passwd)
|
||||
def apply(file: File): Credentials =
|
||||
new FileCredentials(file)
|
||||
|
||||
/** 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 add(path: File, log: Logger): Unit =
|
||||
loadCredentials(path) match
|
||||
{
|
||||
case Left(err) => log.warn(err)
|
||||
case Right(dc) => add(dc.realm, dc.host, dc.userName, dc.passwd)
|
||||
}
|
||||
/** 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 add(path: File, log: Logger): Unit =
|
||||
loadCredentials(path) match {
|
||||
case Left(err) => log.warn(err)
|
||||
case Right(dc) => add(dc.realm, dc.host, dc.userName, dc.passwd)
|
||||
}
|
||||
|
||||
def forHost(sc: Seq[Credentials], host: String) = allDirect(sc) find { _.host == host }
|
||||
def allDirect(sc: Seq[Credentials]): Seq[DirectCredentials] = sc map toDirect
|
||||
def toDirect(c: Credentials): DirectCredentials = c match {
|
||||
case dc: DirectCredentials => dc
|
||||
case fc: FileCredentials => loadCredentials(fc.path) match {
|
||||
case Left(err) => error(err)
|
||||
case Right(dc) => dc
|
||||
}
|
||||
}
|
||||
def forHost(sc: Seq[Credentials], host: String) = allDirect(sc) find { _.host == host }
|
||||
def allDirect(sc: Seq[Credentials]): Seq[DirectCredentials] = sc map toDirect
|
||||
def toDirect(c: Credentials): DirectCredentials = c match {
|
||||
case dc: DirectCredentials => dc
|
||||
case fc: FileCredentials => loadCredentials(fc.path) match {
|
||||
case Left(err) => error(err)
|
||||
case Right(dc) => dc
|
||||
}
|
||||
}
|
||||
|
||||
def loadCredentials(path: File): Either[String, DirectCredentials] =
|
||||
if(path.exists)
|
||||
{
|
||||
val properties = read(path)
|
||||
def get(keys: List[String]) = keys.flatMap(properties.get).headOption.toRight(keys.head + " not specified in credentials file: " + path)
|
||||
def loadCredentials(path: File): Either[String, DirectCredentials] =
|
||||
if (path.exists) {
|
||||
val properties = read(path)
|
||||
def get(keys: List[String]) = keys.flatMap(properties.get).headOption.toRight(keys.head + " not specified in credentials file: " + path)
|
||||
|
||||
IvyUtil.separate( List(RealmKeys, HostKeys, UserKeys, PasswordKeys).map(get) ) match
|
||||
{
|
||||
case (Nil, List(realm, host, user, pass)) => Right( new DirectCredentials(realm, host, user, pass) )
|
||||
case (errors, _) => Left(errors.mkString("\n"))
|
||||
}
|
||||
}
|
||||
else
|
||||
Left("Credentials file " + path + " does not exist")
|
||||
IvyUtil.separate(List(RealmKeys, HostKeys, UserKeys, PasswordKeys).map(get)) match {
|
||||
case (Nil, List(realm, host, user, pass)) => Right(new DirectCredentials(realm, host, user, pass))
|
||||
case (errors, _) => Left(errors.mkString("\n"))
|
||||
}
|
||||
} else
|
||||
Left("Credentials file " + path + " does not exist")
|
||||
|
||||
def register(cs: Seq[Credentials], log: Logger): Unit =
|
||||
cs foreach {
|
||||
case f: FileCredentials => add(f.path, log)
|
||||
case d: DirectCredentials => add(d.realm, d.host, d.userName, d.passwd)
|
||||
}
|
||||
def register(cs: Seq[Credentials], log: Logger): Unit =
|
||||
cs foreach {
|
||||
case f: FileCredentials => add(f.path, log)
|
||||
case d: DirectCredentials => add(d.realm, d.host, d.userName, d.passwd)
|
||||
}
|
||||
|
||||
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")
|
||||
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")
|
||||
|
||||
import collection.JavaConversions._
|
||||
private[this] def read(from: File): Map[String,String] =
|
||||
{
|
||||
val properties = new java.util.Properties
|
||||
IO.load(properties, from)
|
||||
properties map { case (k,v) => (k.toString, v.toString.trim) } toMap;
|
||||
}
|
||||
import collection.JavaConversions._
|
||||
private[this] def read(from: File): Map[String, String] =
|
||||
{
|
||||
val properties = new java.util.Properties
|
||||
IO.load(properties, from)
|
||||
properties map { case (k, v) => (k.toString, v.toString.trim) } toMap;
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait Credentials
|
||||
final class FileCredentials(val path: File) extends Credentials {
|
||||
override def toString = "FileCredentials('" + path + "')"
|
||||
override def toString = "FileCredentials('" + path + "')"
|
||||
}
|
||||
final class DirectCredentials(val realm: String, val host: String, val userName: String, val passwd: String) extends Credentials
|
||||
|
|
|
|||
|
|
@ -7,142 +7,159 @@ final case class ScalaVersion(full: String, binary: String)
|
|||
/** Configures how a module will be cross-versioned. */
|
||||
sealed trait CrossVersion
|
||||
|
||||
object CrossVersion
|
||||
{
|
||||
/** The first `major.minor` Scala version that the Scala binary version should be used for cross-versioning instead of the full version. */
|
||||
val TransitionScalaVersion = CrossVersionUtil.TransitionScalaVersion
|
||||
object CrossVersion {
|
||||
/** The first `major.minor` Scala version that the Scala binary version should be used for cross-versioning instead of the full version. */
|
||||
val TransitionScalaVersion = CrossVersionUtil.TransitionScalaVersion
|
||||
|
||||
/** The first `major.minor` sbt version that the sbt binary version should be used for cross-versioning instead of the full version. */
|
||||
val TransitionSbtVersion = CrossVersionUtil.TransitionSbtVersion
|
||||
/** The first `major.minor` sbt version that the sbt binary version should be used for cross-versioning instead of the full version. */
|
||||
val TransitionSbtVersion = CrossVersionUtil.TransitionSbtVersion
|
||||
|
||||
/** Disables cross versioning for a module.*/
|
||||
object Disabled extends CrossVersion { override def toString = "disabled" }
|
||||
/** Disables cross versioning for a module.*/
|
||||
object Disabled extends CrossVersion { override def toString = "disabled" }
|
||||
|
||||
/** Cross-versions a module using the result of applying `remapVersion` to the binary version.
|
||||
* For example, if `remapVersion = v => "2.10"` and the binary version is "2.9.2" or "2.10",
|
||||
* the module is cross-versioned with "2.10". */
|
||||
final class Binary(val remapVersion: String => String) extends CrossVersion {
|
||||
override def toString = "Binary"
|
||||
}
|
||||
/**
|
||||
* Cross-versions a module using the result of applying `remapVersion` to the binary version.
|
||||
* For example, if `remapVersion = v => "2.10"` and the binary version is "2.9.2" or "2.10",
|
||||
* the module is cross-versioned with "2.10".
|
||||
*/
|
||||
final class Binary(val remapVersion: String => String) extends CrossVersion {
|
||||
override def toString = "Binary"
|
||||
}
|
||||
|
||||
/** Cross-versions a module with the result of applying `remapVersion` to the full version.
|
||||
* For example, if `remapVersion = v => "2.10"` and the full version is "2.9.2" or "2.10.3",
|
||||
* the module is cross-versioned with "2.10". */
|
||||
final class Full(val remapVersion: String => String) extends CrossVersion {
|
||||
override def toString = "Full"
|
||||
}
|
||||
/**
|
||||
* Cross-versions a module with the result of applying `remapVersion` to the full version.
|
||||
* For example, if `remapVersion = v => "2.10"` and the full version is "2.9.2" or "2.10.3",
|
||||
* the module is cross-versioned with "2.10".
|
||||
*/
|
||||
final class Full(val remapVersion: String => String) extends CrossVersion {
|
||||
override def toString = "Full"
|
||||
}
|
||||
|
||||
/** Cross-versions a module with the full version (typically the full Scala version). */
|
||||
def full: CrossVersion = new Full(idFun)
|
||||
/** Cross-versions a module with the full version (typically the full Scala version). */
|
||||
def full: CrossVersion = new Full(idFun)
|
||||
|
||||
/** Cross-versions a module with the result of applying `remapVersion` to the full version
|
||||
* (typically the full Scala version). See also [[sbt.CrossVersion.Full]]. */
|
||||
def fullMapped(remapVersion: String => String): CrossVersion = new Full(remapVersion)
|
||||
/**
|
||||
* Cross-versions a module with the result of applying `remapVersion` to the full version
|
||||
* (typically the full Scala version). See also [[sbt.CrossVersion.Full]].
|
||||
*/
|
||||
def fullMapped(remapVersion: String => String): CrossVersion = new Full(remapVersion)
|
||||
|
||||
/** Cross-versions a module with the binary version (typically the binary Scala version). */
|
||||
def binary: CrossVersion = new Binary(idFun)
|
||||
/** Cross-versions a module with the binary version (typically the binary Scala version). */
|
||||
def binary: CrossVersion = new Binary(idFun)
|
||||
|
||||
/** Cross-versions a module with the result of applying `remapVersion` to the binary version
|
||||
* (typically the binary Scala version). See also [[sbt.CrossVersion.Binary]]. */
|
||||
def binaryMapped(remapVersion: String => String): CrossVersion = new Binary(remapVersion)
|
||||
/**
|
||||
* Cross-versions a module with the result of applying `remapVersion` to the binary version
|
||||
* (typically the binary Scala version). See also [[sbt.CrossVersion.Binary]].
|
||||
*/
|
||||
def binaryMapped(remapVersion: String => String): CrossVersion = new Binary(remapVersion)
|
||||
|
||||
private[this] def idFun[T]: T => T = x => x
|
||||
private[this] def idFun[T]: T => T = x => x
|
||||
|
||||
@deprecated("Will be made private.", "0.13.1")
|
||||
def append(s: String): Option[String => String] = Some(x => crossName(x, s))
|
||||
@deprecated("Will be made private.", "0.13.1")
|
||||
def append(s: String): Option[String => String] = Some(x => crossName(x, s))
|
||||
|
||||
/** Construct a cross-versioning function given cross-versioning configuration `cross`,
|
||||
* full version `fullVersion` and binary version `binaryVersion`. The behavior of the
|
||||
* constructed function is as documented for the [[sbt.CrossVersion]] datatypes. */
|
||||
def apply(cross: CrossVersion, fullVersion: String, binaryVersion: String): Option[String => String] =
|
||||
cross match
|
||||
{
|
||||
case Disabled => None
|
||||
case b: Binary => append(b.remapVersion(binaryVersion))
|
||||
case f: Full => append(f.remapVersion(fullVersion))
|
||||
}
|
||||
/**
|
||||
* Construct a cross-versioning function given cross-versioning configuration `cross`,
|
||||
* full version `fullVersion` and binary version `binaryVersion`. The behavior of the
|
||||
* constructed function is as documented for the [[sbt.CrossVersion]] datatypes.
|
||||
*/
|
||||
def apply(cross: CrossVersion, fullVersion: String, binaryVersion: String): Option[String => String] =
|
||||
cross match {
|
||||
case Disabled => None
|
||||
case b: Binary => append(b.remapVersion(binaryVersion))
|
||||
case f: Full => append(f.remapVersion(fullVersion))
|
||||
}
|
||||
|
||||
/** Constructs the cross-version function defined by `module` and `is`, if one is configured. */
|
||||
def apply(module: ModuleID, is: IvyScala): Option[String => String] =
|
||||
CrossVersion(module.crossVersion, is.scalaFullVersion, is.scalaBinaryVersion)
|
||||
/** Constructs the cross-version function defined by `module` and `is`, if one is configured. */
|
||||
def apply(module: ModuleID, is: IvyScala): Option[String => String] =
|
||||
CrossVersion(module.crossVersion, is.scalaFullVersion, is.scalaBinaryVersion)
|
||||
|
||||
/** Constructs the cross-version function defined by `module` and `is`, if one is configured. */
|
||||
def apply(module: ModuleID, is: Option[IvyScala]): Option[String => String] =
|
||||
is flatMap { i => apply(module, i) }
|
||||
/** Constructs the cross-version function defined by `module` and `is`, if one is configured. */
|
||||
def apply(module: ModuleID, is: Option[IvyScala]): Option[String => String] =
|
||||
is flatMap { i => apply(module, i) }
|
||||
|
||||
/** Cross-version each `Artifact` in `artifacts` according to cross-version function `cross`. */
|
||||
def substituteCross(artifacts: Seq[Artifact], cross: Option[String => String]): Seq[Artifact] =
|
||||
cross match {
|
||||
case None => artifacts
|
||||
case Some(is) => substituteCrossA(artifacts, cross)
|
||||
}
|
||||
/** Cross-version each `Artifact` in `artifacts` according to cross-version function `cross`. */
|
||||
def substituteCross(artifacts: Seq[Artifact], cross: Option[String => String]): Seq[Artifact] =
|
||||
cross match {
|
||||
case None => artifacts
|
||||
case Some(is) => substituteCrossA(artifacts, cross)
|
||||
}
|
||||
|
||||
@deprecated("Will be made private.", "0.13.1")
|
||||
def applyCross(s: String, fopt: Option[String => String]): String =
|
||||
fopt match {
|
||||
case None => s
|
||||
case Some(fopt) => fopt(s)
|
||||
}
|
||||
@deprecated("Will be made private.", "0.13.1")
|
||||
def applyCross(s: String, fopt: Option[String => String]): String =
|
||||
fopt match {
|
||||
case None => s
|
||||
case Some(fopt) => fopt(s)
|
||||
}
|
||||
|
||||
@deprecated("Will be made private.", "0.13.1")
|
||||
def crossName(name: String, cross: String): String =
|
||||
name + "_" + cross
|
||||
@deprecated("Will be made private.", "0.13.1")
|
||||
def crossName(name: String, cross: String): String =
|
||||
name + "_" + cross
|
||||
|
||||
/** Cross-versions `a` according to cross-version function `cross`. */
|
||||
def substituteCross(a: Artifact, cross: Option[String => String]): Artifact =
|
||||
a.copy(name = applyCross(a.name, cross))
|
||||
/** Cross-versions `a` according to cross-version function `cross`. */
|
||||
def substituteCross(a: Artifact, cross: Option[String => String]): Artifact =
|
||||
a.copy(name = applyCross(a.name, cross))
|
||||
|
||||
@deprecated("Will be made private.", "0.13.1")
|
||||
def substituteCrossA(as: Seq[Artifact], cross: Option[String => String]): Seq[Artifact] =
|
||||
as.map(art => substituteCross(art, cross))
|
||||
@deprecated("Will be made private.", "0.13.1")
|
||||
def substituteCrossA(as: Seq[Artifact], cross: Option[String => String]): Seq[Artifact] =
|
||||
as.map(art => substituteCross(art, cross))
|
||||
|
||||
/** Constructs a function that will cross-version a ModuleID
|
||||
* for the given full and binary Scala versions `scalaFullVersion` and `scalaBinaryVersion`
|
||||
* according to the ModuleID's cross-versioning setting. */
|
||||
def apply(scalaFullVersion: String, scalaBinaryVersion: String): ModuleID => ModuleID = m =>
|
||||
{
|
||||
val cross = apply(m.crossVersion, scalaFullVersion, scalaBinaryVersion)
|
||||
if(cross.isDefined)
|
||||
m.copy(name = applyCross(m.name, cross), explicitArtifacts = substituteCrossA(m.explicitArtifacts, cross))
|
||||
else
|
||||
m
|
||||
}
|
||||
/**
|
||||
* Constructs a function that will cross-version a ModuleID
|
||||
* for the given full and binary Scala versions `scalaFullVersion` and `scalaBinaryVersion`
|
||||
* according to the ModuleID's cross-versioning setting.
|
||||
*/
|
||||
def apply(scalaFullVersion: String, scalaBinaryVersion: String): ModuleID => ModuleID = m =>
|
||||
{
|
||||
val cross = apply(m.crossVersion, scalaFullVersion, scalaBinaryVersion)
|
||||
if (cross.isDefined)
|
||||
m.copy(name = applyCross(m.name, cross), explicitArtifacts = substituteCrossA(m.explicitArtifacts, cross))
|
||||
else
|
||||
m
|
||||
}
|
||||
|
||||
@deprecated("Use CrossVersion.isScalaApiCompatible or CrossVersion.isSbtApiCompatible", "0.13.0")
|
||||
def isStable(v: String): Boolean = isScalaApiCompatible(v)
|
||||
@deprecated("Use CrossVersion.isScalaApiCompatible or CrossVersion.isSbtApiCompatible", "0.13.0")
|
||||
def isStable(v: String): Boolean = isScalaApiCompatible(v)
|
||||
|
||||
@deprecated("Use CrossVersion.scalaApiVersion or CrossVersion.sbtApiVersion", "0.13.0")
|
||||
def selectVersion(full: String, binary: String): String = if(isStable(full)) binary else full
|
||||
@deprecated("Use CrossVersion.scalaApiVersion or CrossVersion.sbtApiVersion", "0.13.0")
|
||||
def selectVersion(full: String, binary: String): String = if (isStable(full)) binary else full
|
||||
|
||||
def isSbtApiCompatible(v: String): Boolean = CrossVersionUtil.isSbtApiCompatible(v)
|
||||
def isSbtApiCompatible(v: String): Boolean = CrossVersionUtil.isSbtApiCompatible(v)
|
||||
|
||||
/** Returns sbt binary interface x.y API compatible with the given version string v.
|
||||
* RCs for x.y.0 are considered API compatible.
|
||||
* Compatibile versions include 0.12.0-1 and 0.12.0-RC1 for Some(0, 12).
|
||||
*/
|
||||
def sbtApiVersion(v: String): Option[(Int, Int)] = CrossVersionUtil.sbtApiVersion(v)
|
||||
/**
|
||||
* Returns sbt binary interface x.y API compatible with the given version string v.
|
||||
* RCs for x.y.0 are considered API compatible.
|
||||
* Compatibile versions include 0.12.0-1 and 0.12.0-RC1 for Some(0, 12).
|
||||
*/
|
||||
def sbtApiVersion(v: String): Option[(Int, Int)] = CrossVersionUtil.sbtApiVersion(v)
|
||||
|
||||
def isScalaApiCompatible(v: String): Boolean = CrossVersionUtil.isScalaApiCompatible(v)
|
||||
def isScalaApiCompatible(v: String): Boolean = CrossVersionUtil.isScalaApiCompatible(v)
|
||||
|
||||
/** Returns Scala binary interface x.y API compatible with the given version string v.
|
||||
* Compatibile versions include 2.10.0-1 and 2.10.1-M1 for Some(2, 10), but not 2.10.0-RC1. */
|
||||
def scalaApiVersion(v: String): Option[(Int, Int)] = CrossVersionUtil.scalaApiVersion(v)
|
||||
/**
|
||||
* Returns Scala binary interface x.y API compatible with the given version string v.
|
||||
* Compatibile versions include 2.10.0-1 and 2.10.1-M1 for Some(2, 10), but not 2.10.0-RC1.
|
||||
*/
|
||||
def scalaApiVersion(v: String): Option[(Int, Int)] = CrossVersionUtil.scalaApiVersion(v)
|
||||
|
||||
/** Regular expression that extracts the major and minor components of a version into matched groups 1 and 2.*/
|
||||
val PartialVersion = CrossVersionUtil.PartialVersion
|
||||
/** Regular expression that extracts the major and minor components of a version into matched groups 1 and 2.*/
|
||||
val PartialVersion = CrossVersionUtil.PartialVersion
|
||||
|
||||
/** Extracts the major and minor components of a version string `s` or returns `None` if the version is improperly formatted. */
|
||||
def partialVersion(s: String): Option[(Int,Int)] = CrossVersionUtil.partialVersion(s)
|
||||
/** Extracts the major and minor components of a version string `s` or returns `None` if the version is improperly formatted. */
|
||||
def partialVersion(s: String): Option[(Int, Int)] = CrossVersionUtil.partialVersion(s)
|
||||
|
||||
/** Computes the binary Scala version from the `full` version.
|
||||
* Full Scala versions earlier than [[sbt.CrossVersion.TransitionScalaVersion]] are returned as is. */
|
||||
def binaryScalaVersion(full: String): String = CrossVersionUtil.binaryScalaVersion(full)
|
||||
/**
|
||||
* Computes the binary Scala version from the `full` version.
|
||||
* Full Scala versions earlier than [[sbt.CrossVersion.TransitionScalaVersion]] are returned as is.
|
||||
*/
|
||||
def binaryScalaVersion(full: String): String = CrossVersionUtil.binaryScalaVersion(full)
|
||||
|
||||
/** Computes the binary sbt version from the `full` version.
|
||||
* Full sbt versions earlier than [[sbt.CrossVersion.TransitionSbtVersion]] are returned as is. */
|
||||
def binarySbtVersion(full: String): String = CrossVersionUtil.binarySbtVersion(full)
|
||||
/**
|
||||
* Computes the binary sbt version from the `full` version.
|
||||
* Full sbt versions earlier than [[sbt.CrossVersion.TransitionSbtVersion]] are returned as is.
|
||||
*/
|
||||
def binarySbtVersion(full: String): String = CrossVersionUtil.binarySbtVersion(full)
|
||||
|
||||
@deprecated("Use CrossVersion.scalaApiVersion or CrossVersion.sbtApiVersion", "0.13.0")
|
||||
def binaryVersion(full: String, cutoff: String): String = CrossVersionUtil.binaryVersion(full, cutoff)
|
||||
@deprecated("Use CrossVersion.scalaApiVersion or CrossVersion.sbtApiVersion", "0.13.0")
|
||||
def binaryVersion(full: String, cutoff: String): String = CrossVersionUtil.binaryVersion(full, cutoff)
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,224 +1,222 @@
|
|||
package sbt
|
||||
|
||||
import org.apache.ivy.{core, plugins, util}
|
||||
import core.module.id.ModuleRevisionId
|
||||
import core.module.descriptor.{DefaultArtifact, DefaultExtendsDescriptor, DefaultModuleDescriptor, ModuleDescriptor}
|
||||
import core.module.descriptor.{DefaultDependencyDescriptor, DependencyDescriptor}
|
||||
import plugins.parser.{m2, ModuleDescriptorParser, ModuleDescriptorParserRegistry, ParserSettings}
|
||||
import m2.{PomModuleDescriptorBuilder, PomModuleDescriptorParser}
|
||||
import plugins.repository.Resource
|
||||
import plugins.namespace.NamespaceTransformer
|
||||
import util.extendable.ExtendableItem
|
||||
import org.apache.ivy.{ core, plugins, util }
|
||||
import core.module.id.ModuleRevisionId
|
||||
import core.module.descriptor.{ DefaultArtifact, DefaultExtendsDescriptor, DefaultModuleDescriptor, ModuleDescriptor }
|
||||
import core.module.descriptor.{ DefaultDependencyDescriptor, DependencyDescriptor }
|
||||
import plugins.parser.{ m2, ModuleDescriptorParser, ModuleDescriptorParserRegistry, ParserSettings }
|
||||
import m2.{ PomModuleDescriptorBuilder, PomModuleDescriptorParser }
|
||||
import plugins.repository.Resource
|
||||
import plugins.namespace.NamespaceTransformer
|
||||
import util.extendable.ExtendableItem
|
||||
|
||||
import java.io.{File, InputStream}
|
||||
import java.net.URL
|
||||
import java.util.regex.Pattern
|
||||
import java.io.{ File, InputStream }
|
||||
import java.net.URL
|
||||
import java.util.regex.Pattern
|
||||
|
||||
final class CustomPomParser(delegate: ModuleDescriptorParser, transform: (ModuleDescriptorParser, ModuleDescriptor) => ModuleDescriptor) extends ModuleDescriptorParser
|
||||
{
|
||||
override def parseDescriptor(ivySettings: ParserSettings, descriptorURL: URL, validate: Boolean) =
|
||||
transform(this, delegate.parseDescriptor(ivySettings, descriptorURL, validate))
|
||||
|
||||
override def parseDescriptor(ivySettings: ParserSettings, descriptorURL: URL, res: Resource, validate: Boolean) =
|
||||
transform(this, delegate.parseDescriptor(ivySettings, descriptorURL, res, validate))
|
||||
|
||||
override def toIvyFile(is: InputStream, res: Resource, destFile: File, md: ModuleDescriptor) = delegate.toIvyFile(is, res, destFile, md)
|
||||
final class CustomPomParser(delegate: ModuleDescriptorParser, transform: (ModuleDescriptorParser, ModuleDescriptor) => ModuleDescriptor) extends ModuleDescriptorParser {
|
||||
override def parseDescriptor(ivySettings: ParserSettings, descriptorURL: URL, validate: Boolean) =
|
||||
transform(this, delegate.parseDescriptor(ivySettings, descriptorURL, validate))
|
||||
|
||||
override def accept(res: Resource) = delegate.accept(res)
|
||||
override def getType() = delegate.getType()
|
||||
override def getMetadataArtifact(mrid: ModuleRevisionId, res: Resource) = delegate.getMetadataArtifact(mrid, res)
|
||||
override def parseDescriptor(ivySettings: ParserSettings, descriptorURL: URL, res: Resource, validate: Boolean) =
|
||||
transform(this, delegate.parseDescriptor(ivySettings, descriptorURL, res, validate))
|
||||
|
||||
override def toIvyFile(is: InputStream, res: Resource, destFile: File, md: ModuleDescriptor) = delegate.toIvyFile(is, res, destFile, md)
|
||||
|
||||
override def accept(res: Resource) = delegate.accept(res)
|
||||
override def getType() = delegate.getType()
|
||||
override def getMetadataArtifact(mrid: ModuleRevisionId, res: Resource) = delegate.getMetadataArtifact(mrid, res)
|
||||
}
|
||||
object CustomPomParser
|
||||
{
|
||||
/** The key prefix that indicates that this is used only to store extra information and is not intended for dependency resolution.*/
|
||||
val InfoKeyPrefix = "info."
|
||||
val ApiURLKey = "info.apiURL"
|
||||
object CustomPomParser {
|
||||
/** The key prefix that indicates that this is used only to store extra information and is not intended for dependency resolution.*/
|
||||
val InfoKeyPrefix = "info."
|
||||
val ApiURLKey = "info.apiURL"
|
||||
|
||||
val SbtVersionKey = "sbtVersion"
|
||||
val ScalaVersionKey = "scalaVersion"
|
||||
val ExtraAttributesKey = "extraDependencyAttributes"
|
||||
private[this] val unqualifiedKeys = Set(SbtVersionKey, ScalaVersionKey, ExtraAttributesKey, ApiURLKey)
|
||||
val SbtVersionKey = "sbtVersion"
|
||||
val ScalaVersionKey = "scalaVersion"
|
||||
val ExtraAttributesKey = "extraDependencyAttributes"
|
||||
private[this] val unqualifiedKeys = Set(SbtVersionKey, ScalaVersionKey, ExtraAttributesKey, ApiURLKey)
|
||||
|
||||
// packagings that should be jars, but that Ivy doesn't handle as jars
|
||||
val JarPackagings = Set("eclipse-plugin", "hk2-jar", "orbit")
|
||||
val default = new CustomPomParser(PomModuleDescriptorParser.getInstance, defaultTransform)
|
||||
// packagings that should be jars, but that Ivy doesn't handle as jars
|
||||
val JarPackagings = Set("eclipse-plugin", "hk2-jar", "orbit")
|
||||
val default = new CustomPomParser(PomModuleDescriptorParser.getInstance, defaultTransform)
|
||||
|
||||
private[this] val TransformedHashKey = "e:sbtTransformHash"
|
||||
// A hash of the parameters transformation is based on.
|
||||
// If a descriptor has a different hash, we need to retransform it.
|
||||
private[this] val TransformHash: String = hash((unqualifiedKeys ++ JarPackagings).toSeq.sorted)
|
||||
private[this] def hash(ss: Seq[String]): String = Hash.toHex(Hash(ss.flatMap(_ getBytes "UTF-8").toArray))
|
||||
private[this] val TransformedHashKey = "e:sbtTransformHash"
|
||||
// A hash of the parameters transformation is based on.
|
||||
// If a descriptor has a different hash, we need to retransform it.
|
||||
private[this] val TransformHash: String = hash((unqualifiedKeys ++ JarPackagings).toSeq.sorted)
|
||||
private[this] def hash(ss: Seq[String]): String = Hash.toHex(Hash(ss.flatMap(_ getBytes "UTF-8").toArray))
|
||||
|
||||
// Unfortunately, ModuleDescriptorParserRegistry is add-only and is a singleton instance.
|
||||
lazy val registerDefault: Unit = ModuleDescriptorParserRegistry.getInstance.addParser(default)
|
||||
// Unfortunately, ModuleDescriptorParserRegistry is add-only and is a singleton instance.
|
||||
lazy val registerDefault: Unit = ModuleDescriptorParserRegistry.getInstance.addParser(default)
|
||||
|
||||
def defaultTransform(parser: ModuleDescriptorParser, md: ModuleDescriptor): ModuleDescriptor =
|
||||
if(transformedByThisVersion(md)) md else defaultTransformImpl(parser, md)
|
||||
def defaultTransform(parser: ModuleDescriptorParser, md: ModuleDescriptor): ModuleDescriptor =
|
||||
if (transformedByThisVersion(md)) md else defaultTransformImpl(parser, md)
|
||||
|
||||
private[this] def transformedByThisVersion(md: ModuleDescriptor): Boolean =
|
||||
{
|
||||
val oldTransformedHashKey = "sbtTransformHash"
|
||||
val extraInfo = md.getExtraInfo
|
||||
// sbt 0.13.1 used "sbtTransformHash" instead of "e:sbtTransformHash" until #1192 so read both
|
||||
Option(extraInfo).isDefined &&
|
||||
((Option(extraInfo get TransformedHashKey) orElse Option(extraInfo get oldTransformedHashKey)) match {
|
||||
case Some(TransformHash) => true
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
private[this] def transformedByThisVersion(md: ModuleDescriptor): Boolean =
|
||||
{
|
||||
val oldTransformedHashKey = "sbtTransformHash"
|
||||
val extraInfo = md.getExtraInfo
|
||||
// sbt 0.13.1 used "sbtTransformHash" instead of "e:sbtTransformHash" until #1192 so read both
|
||||
Option(extraInfo).isDefined &&
|
||||
((Option(extraInfo get TransformedHashKey) orElse Option(extraInfo get oldTransformedHashKey)) match {
|
||||
case Some(TransformHash) => true
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
|
||||
private[this] def defaultTransformImpl(parser: ModuleDescriptorParser, md: ModuleDescriptor): ModuleDescriptor =
|
||||
{
|
||||
val properties = getPomProperties(md)
|
||||
private[this] def defaultTransformImpl(parser: ModuleDescriptorParser, md: ModuleDescriptor): ModuleDescriptor =
|
||||
{
|
||||
val properties = getPomProperties(md)
|
||||
|
||||
// Extracts extra attributes (currently, sbt and Scala versions) stored in the <properties> element of the pom.
|
||||
// These are attached to the module itself.
|
||||
val filtered = shouldBeUnqualified(properties)
|
||||
// Extracts extra attributes (currently, sbt and Scala versions) stored in the <properties> element of the pom.
|
||||
// These are attached to the module itself.
|
||||
val filtered = shouldBeUnqualified(properties)
|
||||
|
||||
// Extracts extra attributes for the dependencies.
|
||||
// Because the <dependency> tag in pom.xml cannot include additional metadata,
|
||||
// sbt includes extra attributes in a 'extraDependencyAttributes' property.
|
||||
// This is read/written from/to a pure string (no element structure) because Ivy only
|
||||
// parses the immediate text nodes of the property.
|
||||
val extraDepAttributes = getDependencyExtra(filtered)
|
||||
// Extracts extra attributes for the dependencies.
|
||||
// Because the <dependency> tag in pom.xml cannot include additional metadata,
|
||||
// sbt includes extra attributes in a 'extraDependencyAttributes' property.
|
||||
// This is read/written from/to a pure string (no element structure) because Ivy only
|
||||
// parses the immediate text nodes of the property.
|
||||
val extraDepAttributes = getDependencyExtra(filtered)
|
||||
|
||||
// Fixes up the detected extension in some cases missed by Ivy.
|
||||
val convertArtifacts = artifactExtIncorrect(md)
|
||||
// Fixes up the detected extension in some cases missed by Ivy.
|
||||
val convertArtifacts = artifactExtIncorrect(md)
|
||||
|
||||
// Merges artifact sections for duplicate dependency definitions
|
||||
val mergeDuplicates = IvySbt.hasDuplicateDependencies(md.getDependencies)
|
||||
// Merges artifact sections for duplicate dependency definitions
|
||||
val mergeDuplicates = IvySbt.hasDuplicateDependencies(md.getDependencies)
|
||||
|
||||
val unqualify = toUnqualify(filtered)
|
||||
if(unqualify.isEmpty && extraDepAttributes.isEmpty && !convertArtifacts && !mergeDuplicates)
|
||||
md
|
||||
else
|
||||
addExtra(unqualify, extraDepAttributes, parser, md)
|
||||
}
|
||||
// The <properties> element of the pom is used to store additional metadata, such as for sbt plugins or for the base URL for API docs.
|
||||
// This is done because the pom XSD does not appear to allow extra metadata anywhere else.
|
||||
// The extra sbt plugin metadata in pom.xml does not need to be readable by maven, but the other information may be.
|
||||
// However, the pom.xml needs to be valid in all cases because other tools like repository managers may read the pom.xml.
|
||||
private[sbt] def getPomProperties(md: ModuleDescriptor): Map[String,String] =
|
||||
{
|
||||
import collection.JavaConverters._
|
||||
PomModuleDescriptorBuilder.extractPomProperties(md.getExtraInfo).asInstanceOf[java.util.Map[String,String]].asScala.toMap
|
||||
}
|
||||
private[sbt] def toUnqualify(propertyAttributes: Map[String, String]): Map[String, String] =
|
||||
(propertyAttributes - ExtraAttributesKey) map { case (k,v) => ("e:" + k, v) }
|
||||
val unqualify = toUnqualify(filtered)
|
||||
if (unqualify.isEmpty && extraDepAttributes.isEmpty && !convertArtifacts && !mergeDuplicates)
|
||||
md
|
||||
else
|
||||
addExtra(unqualify, extraDepAttributes, parser, md)
|
||||
}
|
||||
// The <properties> element of the pom is used to store additional metadata, such as for sbt plugins or for the base URL for API docs.
|
||||
// This is done because the pom XSD does not appear to allow extra metadata anywhere else.
|
||||
// The extra sbt plugin metadata in pom.xml does not need to be readable by maven, but the other information may be.
|
||||
// However, the pom.xml needs to be valid in all cases because other tools like repository managers may read the pom.xml.
|
||||
private[sbt] def getPomProperties(md: ModuleDescriptor): Map[String, String] =
|
||||
{
|
||||
import collection.JavaConverters._
|
||||
PomModuleDescriptorBuilder.extractPomProperties(md.getExtraInfo).asInstanceOf[java.util.Map[String, String]].asScala.toMap
|
||||
}
|
||||
private[sbt] def toUnqualify(propertyAttributes: Map[String, String]): Map[String, String] =
|
||||
(propertyAttributes - ExtraAttributesKey) map { case (k, v) => ("e:" + k, v) }
|
||||
|
||||
private[this] def artifactExtIncorrect(md: ModuleDescriptor): Boolean =
|
||||
md.getConfigurations.exists(conf => md.getArtifacts(conf.getName).exists(art => JarPackagings(art.getExt)))
|
||||
private[this] def shouldBeUnqualified(m: Map[String, String]): Map[String, String] = m.filterKeys(unqualifiedKeys)
|
||||
|
||||
private[this] def condAddExtra(properties: Map[String, String], id: ModuleRevisionId): ModuleRevisionId =
|
||||
if(properties.isEmpty) id else addExtra(properties, id)
|
||||
private[this] def addExtra(properties: Map[String, String], id: ModuleRevisionId): ModuleRevisionId =
|
||||
{
|
||||
import collection.JavaConverters._
|
||||
val oldExtra = qualifiedExtra(id)
|
||||
val newExtra = (oldExtra ++ properties).asJava
|
||||
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, newExtra)
|
||||
}
|
||||
private[this] def artifactExtIncorrect(md: ModuleDescriptor): Boolean =
|
||||
md.getConfigurations.exists(conf => md.getArtifacts(conf.getName).exists(art => JarPackagings(art.getExt)))
|
||||
private[this] def shouldBeUnqualified(m: Map[String, String]): Map[String, String] = m.filterKeys(unqualifiedKeys)
|
||||
|
||||
private[this] def getDependencyExtra(m: Map[String, String]): Map[ModuleRevisionId, Map[String,String]] =
|
||||
(m get ExtraAttributesKey) match {
|
||||
case None => Map.empty
|
||||
case Some(str) =>
|
||||
def processDep(m: ModuleRevisionId) = (simplify(m), filterCustomExtra(m, include=true))
|
||||
readDependencyExtra(str).map(processDep).toMap
|
||||
}
|
||||
private[this] def condAddExtra(properties: Map[String, String], id: ModuleRevisionId): ModuleRevisionId =
|
||||
if (properties.isEmpty) id else addExtra(properties, id)
|
||||
private[this] def addExtra(properties: Map[String, String], id: ModuleRevisionId): ModuleRevisionId =
|
||||
{
|
||||
import collection.JavaConverters._
|
||||
val oldExtra = qualifiedExtra(id)
|
||||
val newExtra = (oldExtra ++ properties).asJava
|
||||
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, newExtra)
|
||||
}
|
||||
|
||||
def qualifiedExtra(item: ExtendableItem): Map[String,String] =
|
||||
{
|
||||
import collection.JavaConverters._
|
||||
item.getQualifiedExtraAttributes.asInstanceOf[java.util.Map[String,String]].asScala.toMap
|
||||
}
|
||||
def filterCustomExtra(item: ExtendableItem, include: Boolean): Map[String,String] =
|
||||
(qualifiedExtra(item) filterKeys { k => qualifiedIsExtra(k) == include })
|
||||
private[this] def getDependencyExtra(m: Map[String, String]): Map[ModuleRevisionId, Map[String, String]] =
|
||||
(m get ExtraAttributesKey) match {
|
||||
case None => Map.empty
|
||||
case Some(str) =>
|
||||
def processDep(m: ModuleRevisionId) = (simplify(m), filterCustomExtra(m, include = true))
|
||||
readDependencyExtra(str).map(processDep).toMap
|
||||
}
|
||||
|
||||
def writeDependencyExtra(s: Seq[DependencyDescriptor]): Seq[String] =
|
||||
s.flatMap { dd =>
|
||||
val revId = dd.getDependencyRevisionId
|
||||
if(filterCustomExtra(revId, include=true).isEmpty)
|
||||
Nil
|
||||
else
|
||||
revId.encodeToString :: Nil
|
||||
}
|
||||
def qualifiedExtra(item: ExtendableItem): Map[String, String] =
|
||||
{
|
||||
import collection.JavaConverters._
|
||||
item.getQualifiedExtraAttributes.asInstanceOf[java.util.Map[String, String]].asScala.toMap
|
||||
}
|
||||
def filterCustomExtra(item: ExtendableItem, include: Boolean): Map[String, String] =
|
||||
(qualifiedExtra(item) filterKeys { k => qualifiedIsExtra(k) == include })
|
||||
|
||||
// parses the sequence of dependencies with extra attribute information, with one dependency per line
|
||||
def readDependencyExtra(s: String): Seq[ModuleRevisionId] =
|
||||
LinesP.split(s).map(_.trim).filter(!_.isEmpty).map(ModuleRevisionId.decode)
|
||||
def writeDependencyExtra(s: Seq[DependencyDescriptor]): Seq[String] =
|
||||
s.flatMap { dd =>
|
||||
val revId = dd.getDependencyRevisionId
|
||||
if (filterCustomExtra(revId, include = true).isEmpty)
|
||||
Nil
|
||||
else
|
||||
revId.encodeToString :: Nil
|
||||
}
|
||||
|
||||
private[this] val LinesP = Pattern.compile("(?m)^")
|
||||
// parses the sequence of dependencies with extra attribute information, with one dependency per line
|
||||
def readDependencyExtra(s: String): Seq[ModuleRevisionId] =
|
||||
LinesP.split(s).map(_.trim).filter(!_.isEmpty).map(ModuleRevisionId.decode)
|
||||
|
||||
def qualifiedIsExtra(k: String): Boolean = k.endsWith(ScalaVersionKey) || k.endsWith(SbtVersionKey)
|
||||
private[this] val LinesP = Pattern.compile("(?m)^")
|
||||
|
||||
// Reduces the id to exclude custom extra attributes
|
||||
// This makes the id suitable as a key to associate a dependency parsed from a <dependency> element
|
||||
// with the extra attributes from the <properties> section
|
||||
def simplify(id: ModuleRevisionId): ModuleRevisionId =
|
||||
{
|
||||
import collection.JavaConverters._
|
||||
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, filterCustomExtra(id, include=false).asJava)
|
||||
}
|
||||
def qualifiedIsExtra(k: String): Boolean = k.endsWith(ScalaVersionKey) || k.endsWith(SbtVersionKey)
|
||||
|
||||
private[this] def addExtra(dep: DependencyDescriptor, extra: Map[ModuleRevisionId, Map[String, String]]): DependencyDescriptor =
|
||||
{
|
||||
val extras = if(extra.isEmpty) None else extra get simplify(dep.getDependencyRevisionId)
|
||||
extras match {
|
||||
case None => dep
|
||||
case Some(extraAttrs) => transform(dep, revId => addExtra(extraAttrs, revId))
|
||||
}
|
||||
}
|
||||
private[this] def transform(dep: DependencyDescriptor, f: ModuleRevisionId => ModuleRevisionId): DependencyDescriptor =
|
||||
DefaultDependencyDescriptor.transformInstance(dep, namespaceTransformer(dep.getDependencyRevisionId, f), false)
|
||||
private[this] def extraTransformer(txId: ModuleRevisionId, extra: Map[String, String]): NamespaceTransformer =
|
||||
namespaceTransformer(txId, revId => addExtra(extra, revId) )
|
||||
// Reduces the id to exclude custom extra attributes
|
||||
// This makes the id suitable as a key to associate a dependency parsed from a <dependency> element
|
||||
// with the extra attributes from the <properties> section
|
||||
def simplify(id: ModuleRevisionId): ModuleRevisionId =
|
||||
{
|
||||
import collection.JavaConverters._
|
||||
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, filterCustomExtra(id, include = false).asJava)
|
||||
}
|
||||
|
||||
private[this] def namespaceTransformer(txId: ModuleRevisionId, f: ModuleRevisionId => ModuleRevisionId): NamespaceTransformer =
|
||||
new NamespaceTransformer {
|
||||
def transform(revId: ModuleRevisionId): ModuleRevisionId = if(revId == txId) f(revId) else revId
|
||||
def isIdentity = false
|
||||
}
|
||||
private[this] def addExtra(dep: DependencyDescriptor, extra: Map[ModuleRevisionId, Map[String, String]]): DependencyDescriptor =
|
||||
{
|
||||
val extras = if (extra.isEmpty) None else extra get simplify(dep.getDependencyRevisionId)
|
||||
extras match {
|
||||
case None => dep
|
||||
case Some(extraAttrs) => transform(dep, revId => addExtra(extraAttrs, revId))
|
||||
}
|
||||
}
|
||||
private[this] def transform(dep: DependencyDescriptor, f: ModuleRevisionId => ModuleRevisionId): DependencyDescriptor =
|
||||
DefaultDependencyDescriptor.transformInstance(dep, namespaceTransformer(dep.getDependencyRevisionId, f), false)
|
||||
private[this] def extraTransformer(txId: ModuleRevisionId, extra: Map[String, String]): NamespaceTransformer =
|
||||
namespaceTransformer(txId, revId => addExtra(extra, revId))
|
||||
|
||||
import collection.JavaConverters._
|
||||
def addExtra(properties: Map[String, String], dependencyExtra: Map[ModuleRevisionId, Map[String,String]], parser: ModuleDescriptorParser, md: ModuleDescriptor): ModuleDescriptor =
|
||||
{
|
||||
val dmd = new DefaultModuleDescriptor(parser, md.getResource)
|
||||
private[this] def namespaceTransformer(txId: ModuleRevisionId, f: ModuleRevisionId => ModuleRevisionId): NamespaceTransformer =
|
||||
new NamespaceTransformer {
|
||||
def transform(revId: ModuleRevisionId): ModuleRevisionId = if (revId == txId) f(revId) else revId
|
||||
def isIdentity = false
|
||||
}
|
||||
|
||||
val mrid = addExtra(properties, md.getModuleRevisionId)
|
||||
val resolvedMrid = addExtra(properties, md.getResolvedModuleRevisionId)
|
||||
dmd.setModuleRevisionId(mrid)
|
||||
dmd.setResolvedModuleRevisionId(resolvedMrid)
|
||||
import collection.JavaConverters._
|
||||
def addExtra(properties: Map[String, String], dependencyExtra: Map[ModuleRevisionId, Map[String, String]], parser: ModuleDescriptorParser, md: ModuleDescriptor): ModuleDescriptor =
|
||||
{
|
||||
val dmd = new DefaultModuleDescriptor(parser, md.getResource)
|
||||
|
||||
dmd.setDefault(md.isDefault)
|
||||
dmd.setHomePage(md.getHomePage)
|
||||
dmd.setDescription(md.getDescription)
|
||||
dmd.setLastModified(md.getLastModified)
|
||||
dmd.setStatus(md.getStatus())
|
||||
dmd.setPublicationDate(md.getPublicationDate())
|
||||
dmd.setResolvedPublicationDate(md.getResolvedPublicationDate())
|
||||
val mrid = addExtra(properties, md.getModuleRevisionId)
|
||||
val resolvedMrid = addExtra(properties, md.getResolvedModuleRevisionId)
|
||||
dmd.setModuleRevisionId(mrid)
|
||||
dmd.setResolvedModuleRevisionId(resolvedMrid)
|
||||
|
||||
for(l <- md.getLicenses) dmd.addLicense(l)
|
||||
for( (key,value) <- md.getExtraInfo.asInstanceOf[java.util.Map[String,String]].asScala ) dmd.addExtraInfo(key, value)
|
||||
dmd.addExtraInfo(TransformedHashKey, TransformHash) // mark as transformed by this version, so we don't need to do it again
|
||||
for( (key, value) <- md.getExtraAttributesNamespaces.asInstanceOf[java.util.Map[String,String]].asScala ) dmd.addExtraAttributeNamespace(key, value)
|
||||
IvySbt.addExtraNamespace(dmd)
|
||||
dmd.setDefault(md.isDefault)
|
||||
dmd.setHomePage(md.getHomePage)
|
||||
dmd.setDescription(md.getDescription)
|
||||
dmd.setLastModified(md.getLastModified)
|
||||
dmd.setStatus(md.getStatus())
|
||||
dmd.setPublicationDate(md.getPublicationDate())
|
||||
dmd.setResolvedPublicationDate(md.getResolvedPublicationDate())
|
||||
|
||||
val withExtra = md.getDependencies map { dd => addExtra(dd, dependencyExtra) }
|
||||
val unique = IvySbt.mergeDuplicateDefinitions(withExtra)
|
||||
unique foreach dmd.addDependency
|
||||
for (l <- md.getLicenses) dmd.addLicense(l)
|
||||
for ((key, value) <- md.getExtraInfo.asInstanceOf[java.util.Map[String, String]].asScala) dmd.addExtraInfo(key, value)
|
||||
dmd.addExtraInfo(TransformedHashKey, TransformHash) // mark as transformed by this version, so we don't need to do it again
|
||||
for ((key, value) <- md.getExtraAttributesNamespaces.asInstanceOf[java.util.Map[String, String]].asScala) dmd.addExtraAttributeNamespace(key, value)
|
||||
IvySbt.addExtraNamespace(dmd)
|
||||
|
||||
for( ed <- md.getInheritedDescriptors) dmd.addInheritedDescriptor( new DefaultExtendsDescriptor( md, ed.getLocation, ed.getExtendsTypes) )
|
||||
for( conf <- md.getConfigurations) {
|
||||
dmd.addConfiguration(conf)
|
||||
for(art <- md.getArtifacts(conf.getName)) {
|
||||
val ext = art.getExt
|
||||
val newExt = if( JarPackagings(ext) ) "jar" else ext
|
||||
val nart = new DefaultArtifact(mrid, art.getPublicationDate, art.getName, art.getType, newExt, art.getUrl, art.getQualifiedExtraAttributes)
|
||||
dmd.addArtifact(conf.getName, nart)
|
||||
}
|
||||
}
|
||||
dmd
|
||||
}
|
||||
val withExtra = md.getDependencies map { dd => addExtra(dd, dependencyExtra) }
|
||||
val unique = IvySbt.mergeDuplicateDefinitions(withExtra)
|
||||
unique foreach dmd.addDependency
|
||||
|
||||
for (ed <- md.getInheritedDescriptors) dmd.addInheritedDescriptor(new DefaultExtendsDescriptor(md, ed.getLocation, ed.getExtendsTypes))
|
||||
for (conf <- md.getConfigurations) {
|
||||
dmd.addConfiguration(conf)
|
||||
for (art <- md.getArtifacts(conf.getName)) {
|
||||
val ext = art.getExt
|
||||
val newExt = if (JarPackagings(ext)) "jar" else ext
|
||||
val nart = new DefaultArtifact(mrid, art.getPublicationDate, art.getName, art.getType, newExt, art.getUrl, art.getQualifiedExtraAttributes)
|
||||
dmd.addArtifact(conf.getName, nart)
|
||||
}
|
||||
}
|
||||
dmd
|
||||
}
|
||||
}
|
||||
|
|
@ -6,33 +6,31 @@ package sbt
|
|||
import java.io.ByteArrayInputStream
|
||||
import java.net.URL
|
||||
|
||||
import org.apache.ivy.{core, plugins}
|
||||
import core.module.descriptor.{DefaultDependencyDescriptor, DefaultModuleDescriptor}
|
||||
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[sbt] object CustomXmlParser extends XmlModuleDescriptorParser
|
||||
{
|
||||
import XmlModuleDescriptorParser.Parser
|
||||
class CustomParser(settings: IvySettings, defaultConfig: Option[String]) extends Parser(CustomXmlParser, settings)
|
||||
{
|
||||
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)
|
||||
if(defaultConfig.isDefined) setDefaultConfMapping("*->default(compile)")
|
||||
}
|
||||
override def parseDepsConfs(confs: String, dd: DefaultDependencyDescriptor) = super.parseDepsConfs(confs, dd)
|
||||
override def getDefaultConf = defaultConfig.getOrElse(super.getDefaultConf)
|
||||
}
|
||||
private[sbt] object CustomXmlParser extends XmlModuleDescriptorParser {
|
||||
import XmlModuleDescriptorParser.Parser
|
||||
class CustomParser(settings: IvySettings, defaultConfig: Option[String]) extends Parser(CustomXmlParser, settings) {
|
||||
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)
|
||||
if (defaultConfig.isDefined) setDefaultConfMapping("*->default(compile)")
|
||||
}
|
||||
override def parseDepsConfs(confs: String, dd: DefaultDependencyDescriptor) = super.parseDepsConfs(confs, dd)
|
||||
override def getDefaultConf = defaultConfig.getOrElse(super.getDefaultConf)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,65 +3,58 @@
|
|||
*/
|
||||
package sbt
|
||||
|
||||
trait DependencyFilterExtra
|
||||
{
|
||||
def moduleFilter(organization: NameFilter = AllPassFilter, name: NameFilter = AllPassFilter, revision: NameFilter = AllPassFilter): ModuleFilter =
|
||||
new ModuleFilter {
|
||||
def apply(m: ModuleID): Boolean = organization.accept(m.organization) && name.accept(m.name) && revision.accept(m.revision)
|
||||
}
|
||||
def artifactFilter(name: NameFilter = AllPassFilter, `type`: NameFilter = AllPassFilter, extension: NameFilter = AllPassFilter, classifier: NameFilter = AllPassFilter): ArtifactFilter =
|
||||
new ArtifactFilter {
|
||||
def apply(a: Artifact): Boolean = name.accept(a.name) && `type`.accept(a.`type`) && extension.accept(a.extension) && classifier.accept(a.classifier getOrElse "")
|
||||
}
|
||||
def configurationFilter(name: NameFilter = AllPassFilter): ConfigurationFilter =
|
||||
new ConfigurationFilter {
|
||||
def apply(c: String): Boolean = name.accept(c)
|
||||
}
|
||||
trait DependencyFilterExtra {
|
||||
def moduleFilter(organization: NameFilter = AllPassFilter, name: NameFilter = AllPassFilter, revision: NameFilter = AllPassFilter): ModuleFilter =
|
||||
new ModuleFilter {
|
||||
def apply(m: ModuleID): Boolean = organization.accept(m.organization) && name.accept(m.name) && revision.accept(m.revision)
|
||||
}
|
||||
def artifactFilter(name: NameFilter = AllPassFilter, `type`: NameFilter = AllPassFilter, extension: NameFilter = AllPassFilter, classifier: NameFilter = AllPassFilter): ArtifactFilter =
|
||||
new ArtifactFilter {
|
||||
def apply(a: Artifact): Boolean = name.accept(a.name) && `type`.accept(a.`type`) && extension.accept(a.extension) && classifier.accept(a.classifier getOrElse "")
|
||||
}
|
||||
def configurationFilter(name: NameFilter = AllPassFilter): ConfigurationFilter =
|
||||
new ConfigurationFilter {
|
||||
def apply(c: String): Boolean = name.accept(c)
|
||||
}
|
||||
}
|
||||
object DependencyFilter extends DependencyFilterExtra
|
||||
{
|
||||
def make(configuration: ConfigurationFilter = configurationFilter(), module: ModuleFilter = moduleFilter(), artifact: ArtifactFilter = artifactFilter()): DependencyFilter =
|
||||
new DependencyFilter {
|
||||
def apply(c: String, m: ModuleID, a: Artifact): Boolean = configuration(c) && module(m) && artifact(a)
|
||||
}
|
||||
def apply(x: DependencyFilter, y: DependencyFilter, combine: (Boolean, Boolean) => Boolean): DependencyFilter =
|
||||
new DependencyFilter {
|
||||
def apply(c: String, m: ModuleID, a: Artifact): Boolean = combine(x(c, m, a), y(c, m, a))
|
||||
}
|
||||
def allPass: DependencyFilter = configurationFilter()
|
||||
implicit def fnToModuleFilter(f: ModuleID => Boolean): ModuleFilter = new ModuleFilter { def apply(m: ModuleID) = f(m) }
|
||||
implicit def fnToArtifactFilter(f: Artifact => Boolean): ArtifactFilter = new ArtifactFilter { def apply(m: Artifact) = f(m) }
|
||||
implicit def fnToConfigurationFilter(f: String => Boolean): ConfigurationFilter = new ConfigurationFilter { def apply(c: String) = f(c) }
|
||||
implicit def subDepFilterToFn[Arg](f: SubDepFilter[Arg, _]): Arg => Boolean = f apply _
|
||||
object DependencyFilter extends DependencyFilterExtra {
|
||||
def make(configuration: ConfigurationFilter = configurationFilter(), module: ModuleFilter = moduleFilter(), artifact: ArtifactFilter = artifactFilter()): DependencyFilter =
|
||||
new DependencyFilter {
|
||||
def apply(c: String, m: ModuleID, a: Artifact): Boolean = configuration(c) && module(m) && artifact(a)
|
||||
}
|
||||
def apply(x: DependencyFilter, y: DependencyFilter, combine: (Boolean, Boolean) => Boolean): DependencyFilter =
|
||||
new DependencyFilter {
|
||||
def apply(c: String, m: ModuleID, a: Artifact): Boolean = combine(x(c, m, a), y(c, m, a))
|
||||
}
|
||||
def allPass: DependencyFilter = configurationFilter()
|
||||
implicit def fnToModuleFilter(f: ModuleID => Boolean): ModuleFilter = new ModuleFilter { def apply(m: ModuleID) = f(m) }
|
||||
implicit def fnToArtifactFilter(f: Artifact => Boolean): ArtifactFilter = new ArtifactFilter { def apply(m: Artifact) = f(m) }
|
||||
implicit def fnToConfigurationFilter(f: String => Boolean): ConfigurationFilter = new ConfigurationFilter { def apply(c: String) = f(c) }
|
||||
implicit def subDepFilterToFn[Arg](f: SubDepFilter[Arg, _]): Arg => Boolean = f apply _
|
||||
}
|
||||
trait DependencyFilter
|
||||
{
|
||||
def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean
|
||||
final def &&(o: DependencyFilter) = DependencyFilter(this, o, _ && _)
|
||||
final def ||(o: DependencyFilter) = DependencyFilter(this, o, _ || _)
|
||||
final def -- (o: DependencyFilter) = DependencyFilter(this, o, _ && !_)
|
||||
trait DependencyFilter {
|
||||
def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean
|
||||
final def &&(o: DependencyFilter) = DependencyFilter(this, o, _ && _)
|
||||
final def ||(o: DependencyFilter) = DependencyFilter(this, o, _ || _)
|
||||
final def --(o: DependencyFilter) = DependencyFilter(this, o, _ && !_)
|
||||
}
|
||||
sealed trait SubDepFilter[Arg, Self <: SubDepFilter[Arg, Self]] extends DependencyFilter
|
||||
{ self: Self =>
|
||||
def apply(a: Arg): Boolean
|
||||
protected def make(f: Arg => Boolean): Self
|
||||
final def &(o: Self): Self = combine(o, _ && _)
|
||||
final def |(o: Self): Self = combine(o, _ || _)
|
||||
final def -(o: Self): Self = combine(o, _ && !_)
|
||||
private[this] def combine(o: Self, f: (Boolean, Boolean) => Boolean): Self = make( (m: Arg) => f(this(m), o(m)) )
|
||||
sealed trait SubDepFilter[Arg, Self <: SubDepFilter[Arg, Self]] extends DependencyFilter { self: Self =>
|
||||
def apply(a: Arg): Boolean
|
||||
protected def make(f: Arg => Boolean): Self
|
||||
final def &(o: Self): Self = combine(o, _ && _)
|
||||
final def |(o: Self): Self = combine(o, _ || _)
|
||||
final def -(o: Self): Self = combine(o, _ && !_)
|
||||
private[this] def combine(o: Self, f: (Boolean, Boolean) => Boolean): Self = make((m: Arg) => f(this(m), o(m)))
|
||||
}
|
||||
trait ModuleFilter extends SubDepFilter[ModuleID, ModuleFilter]
|
||||
{
|
||||
protected final def make(f: ModuleID => Boolean) = new ModuleFilter { def apply(m: ModuleID) = f(m) }
|
||||
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean = apply(module)
|
||||
trait ModuleFilter extends SubDepFilter[ModuleID, ModuleFilter] {
|
||||
protected final def make(f: ModuleID => Boolean) = new ModuleFilter { def apply(m: ModuleID) = f(m) }
|
||||
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean = apply(module)
|
||||
}
|
||||
trait ArtifactFilter extends SubDepFilter[Artifact, ArtifactFilter]
|
||||
{
|
||||
protected final def make(f: Artifact => Boolean) = new ArtifactFilter { def apply(m: Artifact) = f(m) }
|
||||
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean = apply(artifact)
|
||||
trait ArtifactFilter extends SubDepFilter[Artifact, ArtifactFilter] {
|
||||
protected final def make(f: Artifact => Boolean) = new ArtifactFilter { def apply(m: Artifact) = f(m) }
|
||||
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean = apply(artifact)
|
||||
}
|
||||
trait ConfigurationFilter extends SubDepFilter[String, ConfigurationFilter]
|
||||
{
|
||||
protected final def make(f: String => Boolean) = new ConfigurationFilter { def apply(m: String) = f(m) }
|
||||
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean = apply(configuration)
|
||||
trait ConfigurationFilter extends SubDepFilter[String, ConfigurationFilter] {
|
||||
protected final def make(f: String => Boolean) = new ConfigurationFilter { def apply(m: String) = f(m) }
|
||||
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean = apply(configuration)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -4,276 +4,269 @@
|
|||
package sbt
|
||||
|
||||
import java.io.File
|
||||
import scala.xml.{Node => XNode, NodeSeq}
|
||||
import scala.xml.{ Node => XNode, NodeSeq }
|
||||
|
||||
import org.apache.ivy.{core, plugins, Ivy}
|
||||
import core.{IvyPatternHelper, LogOptions}
|
||||
import org.apache.ivy.{ core, plugins, Ivy }
|
||||
import core.{ IvyPatternHelper, LogOptions }
|
||||
import core.deliver.DeliverOptions
|
||||
import core.install.InstallOptions
|
||||
import core.module.descriptor.{Artifact => IArtifact, MDArtifact, ModuleDescriptor, DefaultModuleDescriptor}
|
||||
import core.module.descriptor.{ Artifact => IArtifact, MDArtifact, ModuleDescriptor, DefaultModuleDescriptor }
|
||||
import core.report.ResolveReport
|
||||
import core.resolve.ResolveOptions
|
||||
import plugins.resolver.{BasicResolver, DependencyResolver}
|
||||
import plugins.resolver.{ BasicResolver, DependencyResolver }
|
||||
|
||||
final class DeliverConfiguration(val deliverIvyPattern: String, val status: String, val configurations: Option[Seq[Configuration]], val logging: UpdateLogging.Value)
|
||||
final class PublishConfiguration(val ivyFile: Option[File], val resolverName: String, val artifacts: Map[Artifact, File], val checksums: Seq[String], val logging: UpdateLogging.Value,
|
||||
val overwrite: Boolean) {
|
||||
def this(ivyFile: Option[File], resolverName: String, artifacts: Map[Artifact, File], checksums: Seq[String], logging: UpdateLogging.Value) =
|
||||
this(ivyFile, resolverName, artifacts, checksums, logging, false)
|
||||
val overwrite: Boolean) {
|
||||
def this(ivyFile: Option[File], resolverName: String, artifacts: Map[Artifact, File], checksums: Seq[String], logging: UpdateLogging.Value) =
|
||||
this(ivyFile, resolverName, artifacts, checksums, logging, false)
|
||||
}
|
||||
|
||||
final class UpdateConfiguration(val retrieve: Option[RetrieveConfiguration], val missingOk: Boolean, val logging: UpdateLogging.Value)
|
||||
final class RetrieveConfiguration(val retrieveDirectory: File, val outputPattern: String)
|
||||
final case class MakePomConfiguration(file: File, moduleInfo: ModuleInfo, configurations: Option[Seq[Configuration]] = None, extra: NodeSeq = NodeSeq.Empty, process: XNode => XNode = n => n, filterRepositories: MavenRepository => Boolean = _ => true, allRepositories: Boolean, includeTypes: Set[String] = Set(Artifact.DefaultType, Artifact.PomType))
|
||||
// exclude is a map on a restricted ModuleID
|
||||
// exclude is a map on a restricted ModuleID
|
||||
final case class GetClassifiersConfiguration(module: GetClassifiersModule, exclude: Map[ModuleID, Set[String]], configuration: UpdateConfiguration, ivyScala: Option[IvyScala])
|
||||
final case class GetClassifiersModule(id: ModuleID, modules: Seq[ModuleID], configurations: Seq[Configuration], classifiers: Seq[String])
|
||||
|
||||
/** Configures logging during an 'update'. `level` determines the amount of other information logged.
|
||||
* `Full` is the default and logs the most.
|
||||
* `DownloadOnly` only logs what is downloaded.
|
||||
* `Quiet` only displays errors.*/
|
||||
object UpdateLogging extends Enumeration
|
||||
{
|
||||
val Full, DownloadOnly, Quiet = Value
|
||||
/**
|
||||
* Configures logging during an 'update'. `level` determines the amount of other information logged.
|
||||
* `Full` is the default and logs the most.
|
||||
* `DownloadOnly` only logs what is downloaded.
|
||||
* `Quiet` only displays errors.
|
||||
*/
|
||||
object UpdateLogging extends Enumeration {
|
||||
val Full, DownloadOnly, Quiet = Value
|
||||
}
|
||||
|
||||
object IvyActions
|
||||
{
|
||||
/** Installs the dependencies of the given 'module' from the resolver named 'from' to the resolver named 'to'.*/
|
||||
def install(module: IvySbt#Module, from: String, to: String, log: Logger)
|
||||
{
|
||||
module.withModule(log) { (ivy, md, default) =>
|
||||
for(dependency <- md.getDependencies)
|
||||
{
|
||||
log.info("Installing " + dependency)
|
||||
val options = new InstallOptions
|
||||
options.setValidate(module.moduleSettings.validate)
|
||||
options.setTransitive(dependency.isTransitive)
|
||||
ivy.install(dependency.getDependencyRevisionId, from, to, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
object IvyActions {
|
||||
/** Installs the dependencies of the given 'module' from the resolver named 'from' to the resolver named 'to'.*/
|
||||
def install(module: IvySbt#Module, from: String, to: String, log: Logger) {
|
||||
module.withModule(log) { (ivy, md, default) =>
|
||||
for (dependency <- md.getDependencies) {
|
||||
log.info("Installing " + dependency)
|
||||
val options = new InstallOptions
|
||||
options.setValidate(module.moduleSettings.validate)
|
||||
options.setTransitive(dependency.isTransitive)
|
||||
ivy.install(dependency.getDependencyRevisionId, from, to, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Clears the Ivy cache, as configured by 'config'. */
|
||||
def cleanCache(ivy: IvySbt, log: Logger) = ivy.withIvy(log) { iv =>
|
||||
iv.getSettings.getResolutionCacheManager.clean()
|
||||
iv.getSettings.getRepositoryCacheManagers.foreach(_.clean())
|
||||
}
|
||||
/** Clears the Ivy cache, as configured by 'config'. */
|
||||
def cleanCache(ivy: IvySbt, log: Logger) = ivy.withIvy(log) { iv =>
|
||||
iv.getSettings.getResolutionCacheManager.clean()
|
||||
iv.getSettings.getRepositoryCacheManagers.foreach(_.clean())
|
||||
}
|
||||
|
||||
/** Creates a Maven pom from the given Ivy configuration*/
|
||||
def makePom(module: IvySbt#Module, configuration: MakePomConfiguration, log: Logger)
|
||||
{
|
||||
import configuration.{allRepositories, moduleInfo, configurations, extra, file, filterRepositories, process, includeTypes}
|
||||
module.withModule(log) { (ivy, md, default) =>
|
||||
(new MakePom(log)).write(ivy, md, moduleInfo, configurations, includeTypes, extra, process, filterRepositories, allRepositories, file)
|
||||
log.info("Wrote " + file.getAbsolutePath)
|
||||
}
|
||||
}
|
||||
/** Creates a Maven pom from the given Ivy configuration*/
|
||||
def makePom(module: IvySbt#Module, configuration: MakePomConfiguration, log: Logger) {
|
||||
import configuration.{ allRepositories, moduleInfo, configurations, extra, file, filterRepositories, process, includeTypes }
|
||||
module.withModule(log) { (ivy, md, default) =>
|
||||
(new MakePom(log)).write(ivy, md, moduleInfo, configurations, includeTypes, extra, process, filterRepositories, allRepositories, file)
|
||||
log.info("Wrote " + file.getAbsolutePath)
|
||||
}
|
||||
}
|
||||
|
||||
def deliver(module: IvySbt#Module, configuration: DeliverConfiguration, log: Logger): File =
|
||||
{
|
||||
import configuration._
|
||||
module.withModule(log) { case (ivy, md, default) =>
|
||||
val revID = md.getModuleRevisionId
|
||||
val options = DeliverOptions.newInstance(ivy.getSettings).setStatus(status)
|
||||
options.setConfs(IvySbt.getConfigurations(md, configurations))
|
||||
ivy.deliver(revID, revID.getRevision, deliverIvyPattern, options)
|
||||
deliveredFile(ivy, deliverIvyPattern, md)
|
||||
}
|
||||
}
|
||||
def deliveredFile(ivy: Ivy, pattern: String, md: ModuleDescriptor): File =
|
||||
ivy.getSettings.resolveFile(IvyPatternHelper.substitute(pattern, md.getResolvedModuleRevisionId))
|
||||
def deliver(module: IvySbt#Module, configuration: DeliverConfiguration, log: Logger): File =
|
||||
{
|
||||
import configuration._
|
||||
module.withModule(log) {
|
||||
case (ivy, md, default) =>
|
||||
val revID = md.getModuleRevisionId
|
||||
val options = DeliverOptions.newInstance(ivy.getSettings).setStatus(status)
|
||||
options.setConfs(IvySbt.getConfigurations(md, configurations))
|
||||
ivy.deliver(revID, revID.getRevision, deliverIvyPattern, options)
|
||||
deliveredFile(ivy, deliverIvyPattern, md)
|
||||
}
|
||||
}
|
||||
def deliveredFile(ivy: Ivy, pattern: String, md: ModuleDescriptor): File =
|
||||
ivy.getSettings.resolveFile(IvyPatternHelper.substitute(pattern, md.getResolvedModuleRevisionId))
|
||||
|
||||
def publish(module: IvySbt#Module, configuration: PublishConfiguration, log: Logger)
|
||||
{
|
||||
import configuration._
|
||||
module.withModule(log) { case (ivy, md, default) =>
|
||||
val resolver = ivy.getSettings.getResolver(resolverName)
|
||||
if(resolver eq null) sys.error("Undefined resolver '" + resolverName + "'")
|
||||
val ivyArtifact = ivyFile map { file => (MDArtifact.newIvyArtifact(md), file) }
|
||||
val cross = crossVersionMap(module.moduleSettings)
|
||||
val as = mapArtifacts(md, cross, artifacts) ++ ivyArtifact.toSeq
|
||||
withChecksums(resolver, checksums) { publish(md, as, resolver, overwrite = overwrite) }
|
||||
}
|
||||
}
|
||||
private[this] def withChecksums[T](resolver: DependencyResolver, checksums: Seq[String])(act: => T): T =
|
||||
resolver match { case br: BasicResolver => withChecksums(br, checksums)(act); case _ => act }
|
||||
private[this] def withChecksums[T](resolver: BasicResolver, checksums: Seq[String])(act: => T): T =
|
||||
{
|
||||
val previous = resolver.getChecksumAlgorithms
|
||||
resolver.setChecksums(checksums mkString ",")
|
||||
try { act }
|
||||
finally { resolver.setChecksums(previous mkString ",") }
|
||||
}
|
||||
private def crossVersionMap(moduleSettings: ModuleSettings): Option[String => String] =
|
||||
moduleSettings match {
|
||||
case i: InlineConfiguration => CrossVersion(i.module, i.ivyScala)
|
||||
case e: EmptyConfiguration => CrossVersion(e.module, e.ivyScala)
|
||||
case _ => None
|
||||
}
|
||||
def mapArtifacts(module: ModuleDescriptor, cross: Option[String => String], artifacts: Map[Artifact, File]): Seq[(IArtifact, File)] =
|
||||
{
|
||||
val rawa = artifacts.keys.toSeq
|
||||
val seqa = CrossVersion.substituteCross(rawa, cross)
|
||||
val zipped = rawa zip IvySbt.mapArtifacts(module, seqa)
|
||||
zipped map { case (a, ivyA) => (ivyA, artifacts(a)) }
|
||||
}
|
||||
/** 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, log: Logger): UpdateReport =
|
||||
module.withModule(log) { case (ivy, md, default) =>
|
||||
val (report, err) = resolve(configuration.logging)(ivy, md, default)
|
||||
err match
|
||||
{
|
||||
case Some(x) if !configuration.missingOk =>
|
||||
processUnresolved(x, log)
|
||||
throw x
|
||||
case _ =>
|
||||
val cachedDescriptor = ivy.getSettings.getResolutionCacheManager.getResolvedIvyFileInCache(md.getModuleRevisionId)
|
||||
val uReport = IvyRetrieve.updateReport(report, cachedDescriptor)
|
||||
configuration.retrieve match
|
||||
{
|
||||
case Some(rConf) => retrieve(ivy, uReport, rConf)
|
||||
case None => uReport
|
||||
}
|
||||
}
|
||||
}
|
||||
def publish(module: IvySbt#Module, configuration: PublishConfiguration, log: Logger) {
|
||||
import configuration._
|
||||
module.withModule(log) {
|
||||
case (ivy, md, default) =>
|
||||
val resolver = ivy.getSettings.getResolver(resolverName)
|
||||
if (resolver eq null) sys.error("Undefined resolver '" + resolverName + "'")
|
||||
val ivyArtifact = ivyFile map { file => (MDArtifact.newIvyArtifact(md), file) }
|
||||
val cross = crossVersionMap(module.moduleSettings)
|
||||
val as = mapArtifacts(md, cross, artifacts) ++ ivyArtifact.toSeq
|
||||
withChecksums(resolver, checksums) { publish(md, as, resolver, overwrite = overwrite) }
|
||||
}
|
||||
}
|
||||
private[this] def withChecksums[T](resolver: DependencyResolver, checksums: Seq[String])(act: => T): T =
|
||||
resolver match { case br: BasicResolver => withChecksums(br, checksums)(act); case _ => act }
|
||||
private[this] def withChecksums[T](resolver: BasicResolver, checksums: Seq[String])(act: => T): T =
|
||||
{
|
||||
val previous = resolver.getChecksumAlgorithms
|
||||
resolver.setChecksums(checksums mkString ",")
|
||||
try { act }
|
||||
finally { resolver.setChecksums(previous mkString ",") }
|
||||
}
|
||||
private def crossVersionMap(moduleSettings: ModuleSettings): Option[String => String] =
|
||||
moduleSettings match {
|
||||
case i: InlineConfiguration => CrossVersion(i.module, i.ivyScala)
|
||||
case e: EmptyConfiguration => CrossVersion(e.module, e.ivyScala)
|
||||
case _ => None
|
||||
}
|
||||
def mapArtifacts(module: ModuleDescriptor, cross: Option[String => String], artifacts: Map[Artifact, File]): Seq[(IArtifact, File)] =
|
||||
{
|
||||
val rawa = artifacts.keys.toSeq
|
||||
val seqa = CrossVersion.substituteCross(rawa, cross)
|
||||
val zipped = rawa zip IvySbt.mapArtifacts(module, seqa)
|
||||
zipped map { case (a, ivyA) => (ivyA, artifacts(a)) }
|
||||
}
|
||||
/**
|
||||
* 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, log: Logger): UpdateReport =
|
||||
module.withModule(log) {
|
||||
case (ivy, md, default) =>
|
||||
val (report, err) = resolve(configuration.logging)(ivy, md, default)
|
||||
err match {
|
||||
case Some(x) if !configuration.missingOk =>
|
||||
processUnresolved(x, log)
|
||||
throw x
|
||||
case _ =>
|
||||
val cachedDescriptor = ivy.getSettings.getResolutionCacheManager.getResolvedIvyFileInCache(md.getModuleRevisionId)
|
||||
val uReport = IvyRetrieve.updateReport(report, cachedDescriptor)
|
||||
configuration.retrieve match {
|
||||
case Some(rConf) => retrieve(ivy, uReport, rConf)
|
||||
case None => uReport
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def processUnresolved(err: ResolveException, log: Logger)
|
||||
{
|
||||
val withExtra = err.failed.filter(!_.extraDependencyAttributes.isEmpty)
|
||||
if(!withExtra.isEmpty)
|
||||
{
|
||||
log.warn("\n\tNote: Some unresolved dependencies have extra attributes. Check that these dependencies exist with the requested attributes.")
|
||||
withExtra foreach { id => log.warn("\t\t" + id) }
|
||||
log.warn("")
|
||||
}
|
||||
}
|
||||
def groupedConflicts[T](moduleFilter: ModuleFilter, grouping: ModuleID => T)(report: UpdateReport): Map[T, Set[String]] =
|
||||
report.configurations.flatMap { confReport =>
|
||||
val evicted = confReport.evicted.filter(moduleFilter)
|
||||
val evictedSet = evicted.map( m => (m.organization, m.name) ).toSet
|
||||
val conflicted = confReport.allModules.filter( mod => evictedSet( (mod.organization, mod.name) ) )
|
||||
grouped(grouping)(conflicted ++ evicted)
|
||||
} toMap;
|
||||
def processUnresolved(err: ResolveException, log: Logger) {
|
||||
val withExtra = err.failed.filter(!_.extraDependencyAttributes.isEmpty)
|
||||
if (!withExtra.isEmpty) {
|
||||
log.warn("\n\tNote: Some unresolved dependencies have extra attributes. Check that these dependencies exist with the requested attributes.")
|
||||
withExtra foreach { id => log.warn("\t\t" + id) }
|
||||
log.warn("")
|
||||
}
|
||||
}
|
||||
def groupedConflicts[T](moduleFilter: ModuleFilter, grouping: ModuleID => T)(report: UpdateReport): Map[T, Set[String]] =
|
||||
report.configurations.flatMap { confReport =>
|
||||
val evicted = confReport.evicted.filter(moduleFilter)
|
||||
val evictedSet = evicted.map(m => (m.organization, m.name)).toSet
|
||||
val conflicted = confReport.allModules.filter(mod => evictedSet((mod.organization, mod.name)))
|
||||
grouped(grouping)(conflicted ++ evicted)
|
||||
} toMap;
|
||||
|
||||
def grouped[T](grouping: ModuleID => T)(mods: Seq[ModuleID]): Map[T, Set[String]] =
|
||||
mods groupBy(grouping) mapValues(_.map(_.revision).toSet)
|
||||
def grouped[T](grouping: ModuleID => T)(mods: Seq[ModuleID]): Map[T, Set[String]] =
|
||||
mods groupBy (grouping) mapValues (_.map(_.revision).toSet)
|
||||
|
||||
def transitiveScratch(ivySbt: IvySbt, label: String, config: GetClassifiersConfiguration, log: Logger): UpdateReport =
|
||||
{
|
||||
import config.{configuration => c, ivyScala, module => mod}
|
||||
import mod.{id, modules => deps}
|
||||
val base = restrictedCopy(id, true).copy(name = id.name + "$" + label)
|
||||
val module = new ivySbt.Module(InlineConfiguration(base, ModuleInfo(base.name), deps).copy(ivyScala = ivyScala))
|
||||
val report = update(module, c, log)
|
||||
val newConfig = config.copy(module = mod.copy(modules = report.allModules))
|
||||
updateClassifiers(ivySbt, newConfig, log)
|
||||
}
|
||||
def updateClassifiers(ivySbt: IvySbt, config: GetClassifiersConfiguration, log: Logger): UpdateReport =
|
||||
{
|
||||
import config.{configuration => c, module => mod, _}
|
||||
import mod.{configurations => confs, _}
|
||||
assert(!classifiers.isEmpty, "classifiers cannot be empty")
|
||||
val baseModules = modules map { m => restrictedCopy(m, true) }
|
||||
val deps = baseModules.distinct flatMap classifiedArtifacts(classifiers, exclude)
|
||||
val base = restrictedCopy(id, true).copy(name = id.name + classifiers.mkString("$","_",""))
|
||||
val module = new ivySbt.Module(InlineConfiguration(base, ModuleInfo(base.name), deps).copy(ivyScala = ivyScala, configurations = confs))
|
||||
val upConf = new UpdateConfiguration(c.retrieve, true, c.logging)
|
||||
update(module, upConf, log)
|
||||
}
|
||||
def classifiedArtifacts(classifiers: Seq[String], exclude: Map[ModuleID, Set[String]])(m: ModuleID): Option[ModuleID] =
|
||||
{
|
||||
val excluded = exclude getOrElse(restrictedCopy(m, false), Set.empty)
|
||||
val included = classifiers filterNot excluded
|
||||
if(included.isEmpty) None else Some(m.copy(isTransitive = false, explicitArtifacts = classifiedArtifacts(m.name, included) ))
|
||||
}
|
||||
def addExcluded(report: UpdateReport, classifiers: Seq[String], exclude: Map[ModuleID, Set[String]]): UpdateReport =
|
||||
report.addMissing { id => classifiedArtifacts(id.name, classifiers filter getExcluded(id, exclude)) }
|
||||
def classifiedArtifacts(name: String, classifiers: Seq[String]): Seq[Artifact] =
|
||||
classifiers map { c => Artifact.classified(name, c) }
|
||||
private[this] def getExcluded(id: ModuleID, exclude: Map[ModuleID, Set[String]]): Set[String] =
|
||||
exclude.getOrElse(restrictedCopy(id, false), Set.empty[String])
|
||||
def transitiveScratch(ivySbt: IvySbt, label: String, config: GetClassifiersConfiguration, log: Logger): UpdateReport =
|
||||
{
|
||||
import config.{ configuration => c, ivyScala, module => mod }
|
||||
import mod.{ id, modules => deps }
|
||||
val base = restrictedCopy(id, true).copy(name = id.name + "$" + label)
|
||||
val module = new ivySbt.Module(InlineConfiguration(base, ModuleInfo(base.name), deps).copy(ivyScala = ivyScala))
|
||||
val report = update(module, c, log)
|
||||
val newConfig = config.copy(module = mod.copy(modules = report.allModules))
|
||||
updateClassifiers(ivySbt, newConfig, log)
|
||||
}
|
||||
def updateClassifiers(ivySbt: IvySbt, config: GetClassifiersConfiguration, log: Logger): UpdateReport =
|
||||
{
|
||||
import config.{ configuration => c, module => mod, _ }
|
||||
import mod.{ configurations => confs, _ }
|
||||
assert(!classifiers.isEmpty, "classifiers cannot be empty")
|
||||
val baseModules = modules map { m => restrictedCopy(m, true) }
|
||||
val deps = baseModules.distinct flatMap classifiedArtifacts(classifiers, exclude)
|
||||
val base = restrictedCopy(id, true).copy(name = id.name + classifiers.mkString("$", "_", ""))
|
||||
val module = new ivySbt.Module(InlineConfiguration(base, ModuleInfo(base.name), deps).copy(ivyScala = ivyScala, configurations = confs))
|
||||
val upConf = new UpdateConfiguration(c.retrieve, true, c.logging)
|
||||
update(module, upConf, log)
|
||||
}
|
||||
def classifiedArtifacts(classifiers: Seq[String], exclude: Map[ModuleID, Set[String]])(m: ModuleID): Option[ModuleID] =
|
||||
{
|
||||
val excluded = exclude getOrElse (restrictedCopy(m, false), Set.empty)
|
||||
val included = classifiers filterNot excluded
|
||||
if (included.isEmpty) None else Some(m.copy(isTransitive = false, explicitArtifacts = classifiedArtifacts(m.name, included)))
|
||||
}
|
||||
def addExcluded(report: UpdateReport, classifiers: Seq[String], exclude: Map[ModuleID, Set[String]]): UpdateReport =
|
||||
report.addMissing { id => classifiedArtifacts(id.name, classifiers filter getExcluded(id, exclude)) }
|
||||
def classifiedArtifacts(name: String, classifiers: Seq[String]): Seq[Artifact] =
|
||||
classifiers map { c => Artifact.classified(name, c) }
|
||||
private[this] def getExcluded(id: ModuleID, exclude: Map[ModuleID, Set[String]]): Set[String] =
|
||||
exclude.getOrElse(restrictedCopy(id, false), Set.empty[String])
|
||||
|
||||
def extractExcludes(report: UpdateReport): Map[ModuleID, Set[String]] =
|
||||
report.allMissing flatMap { case (_, mod, art) => art.classifier.map { c => (restrictedCopy(mod, false), c) } } groupBy(_._1) map { case (mod, pairs) => (mod, pairs.map(_._2).toSet) }
|
||||
def extractExcludes(report: UpdateReport): Map[ModuleID, Set[String]] =
|
||||
report.allMissing flatMap { case (_, mod, art) => art.classifier.map { c => (restrictedCopy(mod, false), c) } } groupBy (_._1) map { case (mod, pairs) => (mod, pairs.map(_._2).toSet) }
|
||||
|
||||
private[this] def restrictedCopy(m: ModuleID, confs: Boolean) =
|
||||
ModuleID(m.organization, m.name, m.revision, crossVersion = m.crossVersion, extraAttributes = m.extraAttributes, configurations = if(confs) m.configurations else None)
|
||||
private[this] def resolve(logging: UpdateLogging.Value)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String): (ResolveReport, Option[ResolveException]) =
|
||||
{
|
||||
val resolveOptions = new ResolveOptions
|
||||
val resolveId = ResolveOptions.getDefaultResolveId(module)
|
||||
resolveOptions.setResolveId(resolveId)
|
||||
resolveOptions.setLog(ivyLogLevel(logging))
|
||||
ResolutionCache.cleanModule(module.getModuleRevisionId, resolveId, ivy.getSettings.getResolutionCacheManager)
|
||||
val resolveReport = ivy.resolve(module, resolveOptions)
|
||||
val err =
|
||||
if(resolveReport.hasError)
|
||||
{
|
||||
val messages = resolveReport.getAllProblemMessages.toArray.map(_.toString).distinct
|
||||
val failed = resolveReport.getUnresolvedDependencies.map(node => IvyRetrieve.toModuleID(node.getId))
|
||||
Some(new ResolveException(messages, failed))
|
||||
}
|
||||
else None
|
||||
(resolveReport, err)
|
||||
}
|
||||
private def retrieve(ivy: Ivy, report: UpdateReport, config: RetrieveConfiguration): UpdateReport =
|
||||
retrieve(ivy, report, config.retrieveDirectory, config.outputPattern)
|
||||
private[this] def restrictedCopy(m: ModuleID, confs: Boolean) =
|
||||
ModuleID(m.organization, m.name, m.revision, crossVersion = m.crossVersion, extraAttributes = m.extraAttributes, configurations = if (confs) m.configurations else None)
|
||||
private[this] def resolve(logging: UpdateLogging.Value)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String): (ResolveReport, Option[ResolveException]) =
|
||||
{
|
||||
val resolveOptions = new ResolveOptions
|
||||
val resolveId = ResolveOptions.getDefaultResolveId(module)
|
||||
resolveOptions.setResolveId(resolveId)
|
||||
resolveOptions.setLog(ivyLogLevel(logging))
|
||||
ResolutionCache.cleanModule(module.getModuleRevisionId, resolveId, ivy.getSettings.getResolutionCacheManager)
|
||||
val resolveReport = ivy.resolve(module, resolveOptions)
|
||||
val err =
|
||||
if (resolveReport.hasError) {
|
||||
val messages = resolveReport.getAllProblemMessages.toArray.map(_.toString).distinct
|
||||
val failed = resolveReport.getUnresolvedDependencies.map(node => IvyRetrieve.toModuleID(node.getId))
|
||||
Some(new ResolveException(messages, failed))
|
||||
} else None
|
||||
(resolveReport, err)
|
||||
}
|
||||
private def retrieve(ivy: Ivy, report: UpdateReport, config: RetrieveConfiguration): UpdateReport =
|
||||
retrieve(ivy, report, config.retrieveDirectory, config.outputPattern)
|
||||
|
||||
private def retrieve(ivy: Ivy, report: UpdateReport, base: File, pattern: String): UpdateReport =
|
||||
{
|
||||
val toCopy = new collection.mutable.HashSet[(File,File)]
|
||||
val retReport = report retrieve { (conf, mid, art, cached) =>
|
||||
val to = retrieveTarget(conf, mid, art, base, pattern)
|
||||
toCopy += ((cached, to))
|
||||
to
|
||||
}
|
||||
IO.copy( toCopy )
|
||||
retReport
|
||||
}
|
||||
private def retrieveTarget(conf: String, mid: ModuleID, art: Artifact, base: File, pattern: String): File =
|
||||
new File(base, substitute(conf, mid, art, pattern))
|
||||
private def retrieve(ivy: Ivy, report: UpdateReport, base: File, pattern: String): UpdateReport =
|
||||
{
|
||||
val toCopy = new collection.mutable.HashSet[(File, File)]
|
||||
val retReport = report retrieve { (conf, mid, art, cached) =>
|
||||
val to = retrieveTarget(conf, mid, art, base, pattern)
|
||||
toCopy += ((cached, to))
|
||||
to
|
||||
}
|
||||
IO.copy(toCopy)
|
||||
retReport
|
||||
}
|
||||
private def retrieveTarget(conf: String, mid: ModuleID, art: Artifact, base: File, pattern: String): File =
|
||||
new File(base, substitute(conf, mid, art, pattern))
|
||||
|
||||
private def substitute(conf: String, mid: ModuleID, art: Artifact, pattern: String): String =
|
||||
{
|
||||
val mextra = IvySbt.javaMap(mid.extraAttributes, true)
|
||||
val aextra = IvySbt.extra(art, true)
|
||||
IvyPatternHelper.substitute(pattern, mid.organization, mid.name, mid.revision, art.name, art.`type`, art.extension, conf, mextra, aextra)
|
||||
}
|
||||
private def substitute(conf: String, mid: ModuleID, art: Artifact, pattern: String): String =
|
||||
{
|
||||
val mextra = IvySbt.javaMap(mid.extraAttributes, true)
|
||||
val aextra = IvySbt.extra(art, true)
|
||||
IvyPatternHelper.substitute(pattern, mid.organization, mid.name, mid.revision, art.name, art.`type`, art.extension, conf, mextra, aextra)
|
||||
}
|
||||
|
||||
import UpdateLogging.{Quiet, Full, DownloadOnly}
|
||||
import LogOptions.{LOG_QUIET, LOG_DEFAULT, LOG_DOWNLOAD_ONLY}
|
||||
private def ivyLogLevel(level: UpdateLogging.Value) =
|
||||
level match
|
||||
{
|
||||
case Quiet => LOG_QUIET
|
||||
case DownloadOnly => LOG_DOWNLOAD_ONLY
|
||||
case Full => LOG_DEFAULT
|
||||
}
|
||||
import UpdateLogging.{ Quiet, Full, DownloadOnly }
|
||||
import LogOptions.{ LOG_QUIET, LOG_DEFAULT, LOG_DOWNLOAD_ONLY }
|
||||
private def ivyLogLevel(level: UpdateLogging.Value) =
|
||||
level match {
|
||||
case Quiet => LOG_QUIET
|
||||
case DownloadOnly => LOG_DOWNLOAD_ONLY
|
||||
case Full => LOG_DEFAULT
|
||||
}
|
||||
|
||||
def publish(module: ModuleDescriptor, artifacts: Seq[(IArtifact, File)], resolver: DependencyResolver, overwrite: Boolean): Unit =
|
||||
{
|
||||
if (artifacts.nonEmpty) {
|
||||
checkFilesPresent(artifacts)
|
||||
try {
|
||||
resolver.beginPublishTransaction(module.getModuleRevisionId(), overwrite);
|
||||
for( (artifact, file) <- artifacts)
|
||||
resolver.publish(artifact, file, overwrite)
|
||||
resolver.commitPublishTransaction()
|
||||
} catch {
|
||||
case e: Throwable =>
|
||||
try { resolver.abortPublishTransaction() }
|
||||
finally { throw e }
|
||||
}
|
||||
}
|
||||
}
|
||||
private[this] def checkFilesPresent(artifacts: Seq[(IArtifact, File)])
|
||||
{
|
||||
val missing = artifacts filter { case (a, file) => !file.exists }
|
||||
if(missing.nonEmpty)
|
||||
error("Missing files for publishing:\n\t" + missing.map(_._2.getAbsolutePath).mkString("\n\t"))
|
||||
}
|
||||
def publish(module: ModuleDescriptor, artifacts: Seq[(IArtifact, File)], resolver: DependencyResolver, overwrite: Boolean): Unit =
|
||||
{
|
||||
if (artifacts.nonEmpty) {
|
||||
checkFilesPresent(artifacts)
|
||||
try {
|
||||
resolver.beginPublishTransaction(module.getModuleRevisionId(), overwrite);
|
||||
for ((artifact, file) <- artifacts)
|
||||
resolver.publish(artifact, file, overwrite)
|
||||
resolver.commitPublishTransaction()
|
||||
} catch {
|
||||
case e: Throwable =>
|
||||
try { resolver.abortPublishTransaction() }
|
||||
finally { throw e }
|
||||
}
|
||||
}
|
||||
}
|
||||
private[this] def checkFilesPresent(artifacts: Seq[(IArtifact, File)]) {
|
||||
val missing = artifacts filter { case (a, file) => !file.exists }
|
||||
if (missing.nonEmpty)
|
||||
error("Missing files for publishing:\n\t" + missing.map(_._2.getAbsolutePath).mkString("\n\t"))
|
||||
}
|
||||
}
|
||||
final class ResolveException(val messages: Seq[String], val failed: Seq[ModuleID]) extends RuntimeException(messages.mkString("\n"))
|
||||
|
|
|
|||
|
|
@ -6,102 +6,93 @@ package sbt
|
|||
import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
import org.apache.ivy.{core, plugins, util}
|
||||
import core.cache.{ArtifactOrigin, CacheDownloadOptions, DefaultRepositoryCacheManager}
|
||||
import core.module.descriptor.{Artifact => IvyArtifact, DefaultArtifact}
|
||||
import plugins.repository.file.{FileRepository=>IvyFileRepository, FileResource}
|
||||
import plugins.repository.{ArtifactResourceResolver, Resource, ResourceDownloader}
|
||||
import org.apache.ivy.{ core, plugins, util }
|
||||
import core.cache.{ ArtifactOrigin, CacheDownloadOptions, DefaultRepositoryCacheManager }
|
||||
import core.module.descriptor.{ Artifact => IvyArtifact, DefaultArtifact }
|
||||
import plugins.repository.file.{ FileRepository => IvyFileRepository, FileResource }
|
||||
import plugins.repository.{ ArtifactResourceResolver, Resource, ResourceDownloader }
|
||||
import plugins.resolver.util.ResolvedResource
|
||||
import util.FileUtil
|
||||
|
||||
class NotInCache(val id: ModuleID, cause: Throwable)
|
||||
extends RuntimeException(NotInCache(id, cause), cause)
|
||||
{
|
||||
def this(id: ModuleID) = this(id, null)
|
||||
extends RuntimeException(NotInCache(id, cause), cause) {
|
||||
def this(id: ModuleID) = this(id, null)
|
||||
}
|
||||
private object NotInCache
|
||||
{
|
||||
def apply(id: ModuleID, cause: Throwable) =
|
||||
{
|
||||
val postfix = if(cause == null) "" else (": " +cause.toString)
|
||||
"File for " + id + " not in cache" + postfix
|
||||
}
|
||||
private object NotInCache {
|
||||
def apply(id: ModuleID, cause: Throwable) =
|
||||
{
|
||||
val postfix = if (cause == null) "" else (": " + cause.toString)
|
||||
"File for " + id + " not in cache" + postfix
|
||||
}
|
||||
}
|
||||
/** Provides methods for working at the level of a single jar file with the default Ivy cache.*/
|
||||
class IvyCache(val ivyHome: Option[File])
|
||||
{
|
||||
def lockFile = new File(ivyHome getOrElse Path.userHome, ".sbt.cache.lock")
|
||||
/** Caches the given 'file' with the given ID. It may be retrieved or cleared using this ID.*/
|
||||
def cacheJar(moduleID: ModuleID, file: File, lock: Option[xsbti.GlobalLock], log: Logger)
|
||||
{
|
||||
val artifact = defaultArtifact(moduleID)
|
||||
val resolved = new ResolvedResource(new FileResource(new IvyFileRepository, file), moduleID.revision)
|
||||
withDefaultCache(lock, log) { cache =>
|
||||
val resolver = new ArtifactResourceResolver { def resolve(artifact: IvyArtifact) = resolved }
|
||||
cache.download(artifact, resolver, new FileDownloader, new CacheDownloadOptions)
|
||||
}
|
||||
}
|
||||
/** Clears the cache of the jar for the given ID.*/
|
||||
def clearCachedJar(id: ModuleID, lock: Option[xsbti.GlobalLock], log: Logger)
|
||||
{
|
||||
try { withCachedJar(id, lock, 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, lock: Option[xsbti.GlobalLock], log: Logger) =
|
||||
withCachedJar(id, lock, log) { cachedFile =>
|
||||
val copyTo = new File(toDirectory, cachedFile.getName)
|
||||
FileUtil.copy(cachedFile, copyTo, null)
|
||||
copyTo
|
||||
}
|
||||
class IvyCache(val ivyHome: Option[File]) {
|
||||
def lockFile = new File(ivyHome getOrElse Path.userHome, ".sbt.cache.lock")
|
||||
/** Caches the given 'file' with the given ID. It may be retrieved or cleared using this ID.*/
|
||||
def cacheJar(moduleID: ModuleID, file: File, lock: Option[xsbti.GlobalLock], log: Logger) {
|
||||
val artifact = defaultArtifact(moduleID)
|
||||
val resolved = new ResolvedResource(new FileResource(new IvyFileRepository, file), moduleID.revision)
|
||||
withDefaultCache(lock, log) { cache =>
|
||||
val resolver = new ArtifactResourceResolver { def resolve(artifact: IvyArtifact) = resolved }
|
||||
cache.download(artifact, resolver, new FileDownloader, new CacheDownloadOptions)
|
||||
}
|
||||
}
|
||||
/** Clears the cache of the jar for the given ID.*/
|
||||
def clearCachedJar(id: ModuleID, lock: Option[xsbti.GlobalLock], log: Logger) {
|
||||
try { withCachedJar(id, lock, 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, lock: Option[xsbti.GlobalLock], log: Logger) =
|
||||
withCachedJar(id, lock, 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 .*/
|
||||
def withCachedJar[T](id: ModuleID, lock: Option[xsbti.GlobalLock], log: Logger)(f: File => T): T =
|
||||
{
|
||||
val cachedFile =
|
||||
try
|
||||
{
|
||||
withDefaultCache(lock, log) { cache =>
|
||||
val artifact = defaultArtifact(id)
|
||||
cache.getArchiveFileInCache(artifact, unknownOrigin(artifact))
|
||||
}
|
||||
}
|
||||
catch { case e: Exception => throw new NotInCache(id, e) }
|
||||
/** 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 withCachedJar[T](id: ModuleID, lock: Option[xsbti.GlobalLock], log: Logger)(f: File => T): T =
|
||||
{
|
||||
val cachedFile =
|
||||
try {
|
||||
withDefaultCache(lock, log) { cache =>
|
||||
val artifact = defaultArtifact(id)
|
||||
cache.getArchiveFileInCache(artifact, unknownOrigin(artifact))
|
||||
}
|
||||
} catch { case e: Exception => throw new NotInCache(id, e) }
|
||||
|
||||
if(cachedFile.exists) f(cachedFile) else throw new NotInCache(id)
|
||||
}
|
||||
/** Calls the given function with the default Ivy cache.*/
|
||||
def withDefaultCache[T](lock: Option[xsbti.GlobalLock], log: Logger)(f: DefaultRepositoryCacheManager => T): T =
|
||||
{
|
||||
val (ivy, local) = basicLocalIvy(lock, log)
|
||||
ivy.withIvy(log) { ivy =>
|
||||
val cache = ivy.getSettings.getDefaultRepositoryCacheManager.asInstanceOf[DefaultRepositoryCacheManager]
|
||||
cache.setUseOrigin(false)
|
||||
f(cache)
|
||||
}
|
||||
}
|
||||
private def unknownOrigin(artifact: IvyArtifact) = ArtifactOrigin.unkwnown(artifact)
|
||||
/** A minimal Ivy setup with only a local resolver and the current directory as the base directory.*/
|
||||
private def basicLocalIvy(lock: Option[xsbti.GlobalLock], log: Logger) =
|
||||
{
|
||||
val local = Resolver.defaultLocal
|
||||
val paths = new IvyPaths(new File("."), ivyHome)
|
||||
val conf = new InlineIvyConfiguration(paths, Seq(local), Nil, Nil, false, lock, IvySbt.DefaultChecksums, None, log)
|
||||
(new IvySbt(conf), local)
|
||||
}
|
||||
/** Creates a default jar artifact based on the given ID.*/
|
||||
private def defaultArtifact(moduleID: ModuleID): IvyArtifact =
|
||||
new DefaultArtifact(IvySbt.toID(moduleID), null, moduleID.name, "jar", "jar")
|
||||
if (cachedFile.exists) f(cachedFile) else throw new NotInCache(id)
|
||||
}
|
||||
/** Calls the given function with the default Ivy cache.*/
|
||||
def withDefaultCache[T](lock: Option[xsbti.GlobalLock], log: Logger)(f: DefaultRepositoryCacheManager => T): T =
|
||||
{
|
||||
val (ivy, local) = basicLocalIvy(lock, log)
|
||||
ivy.withIvy(log) { ivy =>
|
||||
val cache = ivy.getSettings.getDefaultRepositoryCacheManager.asInstanceOf[DefaultRepositoryCacheManager]
|
||||
cache.setUseOrigin(false)
|
||||
f(cache)
|
||||
}
|
||||
}
|
||||
private def unknownOrigin(artifact: IvyArtifact) = ArtifactOrigin.unkwnown(artifact)
|
||||
/** A minimal Ivy setup with only a local resolver and the current directory as the base directory.*/
|
||||
private def basicLocalIvy(lock: Option[xsbti.GlobalLock], log: Logger) =
|
||||
{
|
||||
val local = Resolver.defaultLocal
|
||||
val paths = new IvyPaths(new File("."), ivyHome)
|
||||
val conf = new InlineIvyConfiguration(paths, Seq(local), Nil, Nil, false, lock, IvySbt.DefaultChecksums, None, log)
|
||||
(new IvySbt(conf), local)
|
||||
}
|
||||
/** Creates a default jar artifact based on the given ID.*/
|
||||
private def defaultArtifact(moduleID: ModuleID): IvyArtifact =
|
||||
new DefaultArtifact(IvySbt.toID(moduleID), null, moduleID.name, "jar", "jar")
|
||||
}
|
||||
/** Required by Ivy for copying to the cache.*/
|
||||
private class FileDownloader extends ResourceDownloader with NotNull
|
||||
{
|
||||
def download(artifact: IvyArtifact, resource: Resource, dest: File)
|
||||
{
|
||||
if(dest.exists()) dest.delete()
|
||||
val part = new File(dest.getAbsolutePath + ".part")
|
||||
FileUtil.copy(resource.openStream, part, null)
|
||||
if(!part.renameTo(dest))
|
||||
sys.error("Could not move temporary file " + part + " to final location " + dest)
|
||||
}
|
||||
private class FileDownloader extends ResourceDownloader with NotNull {
|
||||
def download(artifact: IvyArtifact, resource: Resource, dest: File) {
|
||||
if (dest.exists()) dest.delete()
|
||||
val part = new File(dest.getAbsolutePath + ".part")
|
||||
FileUtil.copy(resource.openStream, part, null)
|
||||
if (!part.renameTo(dest))
|
||||
sys.error("Could not move temporary file " + part + " to final location " + dest)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,120 +4,104 @@
|
|||
package sbt
|
||||
|
||||
import java.io.File
|
||||
import java.net.{URI,URL}
|
||||
import java.net.{ URI, URL }
|
||||
import scala.xml.NodeSeq
|
||||
|
||||
final class IvyPaths(val baseDirectory: File, val ivyHome: Option[File])
|
||||
{
|
||||
def withBase(newBaseDirectory: File) = new IvyPaths(newBaseDirectory, ivyHome)
|
||||
final class IvyPaths(val baseDirectory: File, val ivyHome: Option[File]) {
|
||||
def withBase(newBaseDirectory: File) = new IvyPaths(newBaseDirectory, ivyHome)
|
||||
}
|
||||
sealed trait IvyConfiguration
|
||||
{
|
||||
type This <: IvyConfiguration
|
||||
def lock: Option[xsbti.GlobalLock]
|
||||
def baseDirectory: File
|
||||
def log: Logger
|
||||
def withBase(newBaseDirectory: File): This
|
||||
sealed trait IvyConfiguration {
|
||||
type This <: IvyConfiguration
|
||||
def lock: Option[xsbti.GlobalLock]
|
||||
def baseDirectory: File
|
||||
def log: Logger
|
||||
def withBase(newBaseDirectory: File): This
|
||||
}
|
||||
final class InlineIvyConfiguration(val paths: IvyPaths, val resolvers: Seq[Resolver], val otherResolvers: Seq[Resolver],
|
||||
val moduleConfigurations: Seq[ModuleConfiguration], val localOnly: Boolean, val lock: Option[xsbti.GlobalLock],
|
||||
val checksums: Seq[String], val resolutionCacheDir: Option[File], val log: Logger) extends IvyConfiguration
|
||||
{
|
||||
@deprecated("Use the variant that accepts the resolution cache location.", "0.13.0")
|
||||
def this(paths: IvyPaths, resolvers: Seq[Resolver], otherResolvers: Seq[Resolver],
|
||||
moduleConfigurations: Seq[ModuleConfiguration], localOnly: Boolean, lock: Option[xsbti.GlobalLock],
|
||||
checksums: Seq[String], log: Logger) =
|
||||
this(paths, resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, None, log)
|
||||
val moduleConfigurations: Seq[ModuleConfiguration], val localOnly: Boolean, val lock: Option[xsbti.GlobalLock],
|
||||
val checksums: Seq[String], val resolutionCacheDir: Option[File], val log: Logger) extends IvyConfiguration {
|
||||
@deprecated("Use the variant that accepts the resolution cache location.", "0.13.0")
|
||||
def this(paths: IvyPaths, resolvers: Seq[Resolver], otherResolvers: Seq[Resolver],
|
||||
moduleConfigurations: Seq[ModuleConfiguration], localOnly: Boolean, lock: Option[xsbti.GlobalLock],
|
||||
checksums: Seq[String], log: Logger) =
|
||||
this(paths, resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, None, log)
|
||||
|
||||
type This = InlineIvyConfiguration
|
||||
def baseDirectory = paths.baseDirectory
|
||||
def withBase(newBase: File) = new InlineIvyConfiguration(paths.withBase(newBase), resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, resolutionCacheDir, log)
|
||||
def changeResolvers(newResolvers: Seq[Resolver]) = new InlineIvyConfiguration(paths, newResolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, resolutionCacheDir, log)
|
||||
type This = InlineIvyConfiguration
|
||||
def baseDirectory = paths.baseDirectory
|
||||
def withBase(newBase: File) = new InlineIvyConfiguration(paths.withBase(newBase), resolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, resolutionCacheDir, log)
|
||||
def changeResolvers(newResolvers: Seq[Resolver]) = new InlineIvyConfiguration(paths, newResolvers, otherResolvers, moduleConfigurations, localOnly, lock, checksums, resolutionCacheDir, log)
|
||||
}
|
||||
final class ExternalIvyConfiguration(val baseDirectory: File, val uri: URI, val lock: Option[xsbti.GlobalLock], val extraResolvers: Seq[Resolver], val log: Logger) extends IvyConfiguration
|
||||
{
|
||||
type This = ExternalIvyConfiguration
|
||||
def withBase(newBase: File) = new ExternalIvyConfiguration(newBase, uri, lock, extraResolvers, log)
|
||||
final class ExternalIvyConfiguration(val baseDirectory: File, val uri: URI, val lock: Option[xsbti.GlobalLock], val extraResolvers: Seq[Resolver], val log: Logger) extends IvyConfiguration {
|
||||
type This = ExternalIvyConfiguration
|
||||
def withBase(newBase: File) = new ExternalIvyConfiguration(newBase, uri, lock, extraResolvers, log)
|
||||
}
|
||||
object ExternalIvyConfiguration
|
||||
{
|
||||
def apply(baseDirectory: File, file: File, lock: Option[xsbti.GlobalLock], log: Logger) = new ExternalIvyConfiguration(baseDirectory, file.toURI, lock, Nil, log)
|
||||
object ExternalIvyConfiguration {
|
||||
def apply(baseDirectory: File, file: File, lock: Option[xsbti.GlobalLock], log: Logger) = new ExternalIvyConfiguration(baseDirectory, file.toURI, lock, Nil, log)
|
||||
}
|
||||
|
||||
object IvyConfiguration
|
||||
{
|
||||
/** 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.*/
|
||||
@deprecated("Explicitly use either external or inline configuration.", "0.12.0")
|
||||
def apply(paths: IvyPaths, lock: Option[xsbti.GlobalLock], localOnly: Boolean, checksums: Seq[String], log: Logger): IvyConfiguration =
|
||||
{
|
||||
log.debug("Autodetecting configuration.")
|
||||
val defaultIvyConfigFile = IvySbt.defaultIvyConfiguration(paths.baseDirectory)
|
||||
if(defaultIvyConfigFile.canRead)
|
||||
ExternalIvyConfiguration(paths.baseDirectory, defaultIvyConfigFile, lock, log)
|
||||
else
|
||||
new InlineIvyConfiguration(paths, Resolver.withDefaultResolvers(Nil), Nil, Nil, localOnly, lock, checksums, None, log)
|
||||
}
|
||||
object IvyConfiguration {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@deprecated("Explicitly use either external or inline configuration.", "0.12.0")
|
||||
def apply(paths: IvyPaths, lock: Option[xsbti.GlobalLock], localOnly: Boolean, checksums: Seq[String], log: Logger): IvyConfiguration =
|
||||
{
|
||||
log.debug("Autodetecting configuration.")
|
||||
val defaultIvyConfigFile = IvySbt.defaultIvyConfiguration(paths.baseDirectory)
|
||||
if (defaultIvyConfigFile.canRead)
|
||||
ExternalIvyConfiguration(paths.baseDirectory, defaultIvyConfigFile, lock, log)
|
||||
else
|
||||
new InlineIvyConfiguration(paths, Resolver.withDefaultResolvers(Nil), Nil, Nil, localOnly, lock, checksums, None, log)
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait ModuleSettings
|
||||
{
|
||||
def validate: Boolean
|
||||
def ivyScala: Option[IvyScala]
|
||||
def noScala: ModuleSettings
|
||||
sealed trait ModuleSettings {
|
||||
def validate: Boolean
|
||||
def ivyScala: Option[IvyScala]
|
||||
def noScala: ModuleSettings
|
||||
}
|
||||
final case class IvyFileConfiguration(file: File, ivyScala: Option[IvyScala], validate: Boolean, autoScalaTools: Boolean = true) extends ModuleSettings
|
||||
{
|
||||
def noScala = copy(ivyScala = None)
|
||||
final case class IvyFileConfiguration(file: File, ivyScala: Option[IvyScala], validate: Boolean, autoScalaTools: Boolean = true) extends ModuleSettings {
|
||||
def noScala = copy(ivyScala = None)
|
||||
}
|
||||
final case class PomConfiguration(file: File, ivyScala: Option[IvyScala], validate: Boolean, autoScalaTools: Boolean = true) extends ModuleSettings
|
||||
{
|
||||
def noScala = copy(ivyScala = None)
|
||||
final case class PomConfiguration(file: File, ivyScala: Option[IvyScala], validate: Boolean, autoScalaTools: Boolean = true) extends ModuleSettings {
|
||||
def noScala = copy(ivyScala = None)
|
||||
}
|
||||
final case class InlineConfiguration(module: ModuleID, moduleInfo: ModuleInfo, dependencies: Seq[ModuleID], overrides: Set[ModuleID] = Set.empty, ivyXML: NodeSeq = NodeSeq.Empty, configurations: Seq[Configuration] = Nil, defaultConfiguration: Option[Configuration] = None, ivyScala: Option[IvyScala] = None, validate: Boolean = false, conflictManager: ConflictManager = ConflictManager.default) extends ModuleSettings
|
||||
{
|
||||
def withConfigurations(configurations: Seq[Configuration]) = copy(configurations = configurations)
|
||||
def noScala = copy(ivyScala = None)
|
||||
final case class InlineConfiguration(module: ModuleID, moduleInfo: ModuleInfo, dependencies: Seq[ModuleID], overrides: Set[ModuleID] = Set.empty, ivyXML: NodeSeq = NodeSeq.Empty, configurations: Seq[Configuration] = Nil, defaultConfiguration: Option[Configuration] = None, ivyScala: Option[IvyScala] = None, validate: Boolean = false, conflictManager: ConflictManager = ConflictManager.default) extends ModuleSettings {
|
||||
def withConfigurations(configurations: Seq[Configuration]) = copy(configurations = configurations)
|
||||
def noScala = copy(ivyScala = None)
|
||||
}
|
||||
@deprecated("Define a module using inline Scala (InlineConfiguration), a pom.xml (PomConfiguration), or an ivy.xml (IvyFileConfiguration).", "0.13.0")
|
||||
final case class EmptyConfiguration(module: ModuleID, moduleInfo: ModuleInfo, ivyScala: Option[IvyScala], validate: Boolean) extends ModuleSettings
|
||||
{
|
||||
def noScala = copy(ivyScala = None)
|
||||
final case class EmptyConfiguration(module: ModuleID, moduleInfo: ModuleInfo, ivyScala: Option[IvyScala], validate: Boolean) extends ModuleSettings {
|
||||
def noScala = copy(ivyScala = None)
|
||||
}
|
||||
object InlineConfiguration
|
||||
{
|
||||
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
|
||||
object InlineConfiguration {
|
||||
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
|
||||
}
|
||||
object ModuleSettings
|
||||
{
|
||||
@deprecated("Explicitly select configuration from pom.xml, ivy.xml, or inline Scala.", "0.13.0")
|
||||
def apply(ivyScala: Option[IvyScala], validate: Boolean, module: => ModuleID, moduleInfo: => ModuleInfo)(baseDirectory: File, log: Logger): ModuleSettings =
|
||||
{
|
||||
log.debug("Autodetecting dependencies.")
|
||||
val defaultPOMFile = IvySbt.defaultPOM(baseDirectory)
|
||||
if(defaultPOMFile.canRead)
|
||||
new PomConfiguration(defaultPOMFile, ivyScala, validate, true)
|
||||
else
|
||||
{
|
||||
val defaultIvy = IvySbt.defaultIvyFile(baseDirectory)
|
||||
if(defaultIvy.canRead)
|
||||
new IvyFileConfiguration(defaultIvy, ivyScala, validate, true)
|
||||
else
|
||||
{
|
||||
log.warn("No dependency configuration found, using defaults.")
|
||||
new EmptyConfiguration(module, moduleInfo, ivyScala, validate)
|
||||
}
|
||||
}
|
||||
}
|
||||
object ModuleSettings {
|
||||
@deprecated("Explicitly select configuration from pom.xml, ivy.xml, or inline Scala.", "0.13.0")
|
||||
def apply(ivyScala: Option[IvyScala], validate: Boolean, module: => ModuleID, moduleInfo: => ModuleInfo)(baseDirectory: File, log: Logger): ModuleSettings =
|
||||
{
|
||||
log.debug("Autodetecting dependencies.")
|
||||
val defaultPOMFile = IvySbt.defaultPOM(baseDirectory)
|
||||
if (defaultPOMFile.canRead)
|
||||
new PomConfiguration(defaultPOMFile, ivyScala, validate, true)
|
||||
else {
|
||||
val defaultIvy = IvySbt.defaultIvyFile(baseDirectory)
|
||||
if (defaultIvy.canRead)
|
||||
new IvyFileConfiguration(defaultIvy, ivyScala, validate, true)
|
||||
else {
|
||||
log.warn("No dependency configuration found, using defaults.")
|
||||
new EmptyConfiguration(module, moduleInfo, ivyScala, validate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,18 +4,17 @@
|
|||
package sbt
|
||||
|
||||
import java.io.File
|
||||
import java.net.{URI, URL}
|
||||
import java.net.{ URI, URL }
|
||||
import scala.xml.NodeSeq
|
||||
import org.apache.ivy.plugins.resolver.{DependencyResolver, IBiblioResolver}
|
||||
import org.apache.ivy.plugins.resolver.{ DependencyResolver, IBiblioResolver }
|
||||
import org.apache.ivy.util.url.CredentialsStore
|
||||
|
||||
/** Additional information about a project module */
|
||||
final case class ModuleInfo(nameFormal: String, description: String = "", homepage: Option[URL] = None, startYear: Option[Int] = None, licenses: Seq[(String, URL)] = Nil, organizationName: String = "", organizationHomepage: Option[URL] = None, scmInfo: Option[ScmInfo] = None)
|
||||
{
|
||||
def formally(name: String) = copy(nameFormal = name)
|
||||
def describing(desc: String, home: Option[URL]) = copy(description = desc, homepage = home)
|
||||
def licensed(lics: (String, URL)*) = copy(licenses = lics)
|
||||
def organization(name: String, home: Option[URL]) = copy(organizationName = name, organizationHomepage = home)
|
||||
final case class ModuleInfo(nameFormal: String, description: String = "", homepage: Option[URL] = None, startYear: Option[Int] = None, licenses: Seq[(String, URL)] = Nil, organizationName: String = "", organizationHomepage: Option[URL] = None, scmInfo: Option[ScmInfo] = None) {
|
||||
def formally(name: String) = copy(nameFormal = name)
|
||||
def describing(desc: String, home: Option[URL]) = copy(description = desc, homepage = home)
|
||||
def licensed(lics: (String, URL)*) = copy(licenses = lics)
|
||||
def organization(name: String, home: Option[URL]) = copy(organizationName = name, organizationHomepage = home)
|
||||
}
|
||||
|
||||
/** Basic SCM information for a project module */
|
||||
|
|
@ -25,20 +24,19 @@ final case class ScmInfo(browseUrl: URL, connection: String, devConnection: Opti
|
|||
final case class ExclusionRule(organization: String = "*", name: String = "*", artifact: String = "*", configurations: Seq[String] = Nil)
|
||||
|
||||
final case class ModuleConfiguration(organization: String, name: String, revision: String, resolver: Resolver)
|
||||
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 ModuleConfiguration {
|
||||
def apply(org: String, resolver: Resolver): ModuleConfiguration = apply(org, "*", "*", resolver)
|
||||
def apply(org: String, name: String, resolver: Resolver): ModuleConfiguration = ModuleConfiguration(org, name, "*", resolver)
|
||||
}
|
||||
|
||||
final case class ConflictManager(name: String, organization: String = "*", module: String = "*")
|
||||
|
||||
/** See http://ant.apache.org/ivy/history/latest-milestone/settings/conflict-managers.html for details of the different conflict managers.*/
|
||||
object ConflictManager {
|
||||
val all = ConflictManager("all")
|
||||
val latestTime = ConflictManager("latest-time")
|
||||
val latestRevision = ConflictManager("latest-revision")
|
||||
val latestCompatible = ConflictManager("latest-compatible")
|
||||
val strict = ConflictManager("strict")
|
||||
val default = latestRevision
|
||||
val all = ConflictManager("all")
|
||||
val latestTime = ConflictManager("latest-time")
|
||||
val latestRevision = ConflictManager("latest-revision")
|
||||
val latestCompatible = ConflictManager("latest-compatible")
|
||||
val strict = ConflictManager("strict")
|
||||
val default = latestRevision
|
||||
}
|
||||
|
|
@ -3,56 +3,51 @@
|
|||
*/
|
||||
package sbt
|
||||
|
||||
import org.apache.ivy.util.{Message, MessageLogger, MessageLoggerEngine}
|
||||
import org.apache.ivy.util.{ Message, MessageLogger, MessageLoggerEngine }
|
||||
|
||||
/** Interface to Ivy logging. */
|
||||
private final class IvyLoggerInterface(logger: Logger) 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)
|
||||
}
|
||||
}
|
||||
//DEBUG level messages are very verbose and rarely useful to users.
|
||||
// TODO: provide access to this information some other way
|
||||
def debug(msg: String) {}
|
||||
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) = if(SbtIvyLogger.acceptError(msg)) logger.error(msg)
|
||||
|
||||
private def emptyList = java.util.Collections.emptyList[String]
|
||||
def getProblems = emptyList
|
||||
def getWarns = emptyList
|
||||
def getErrors = emptyList
|
||||
private final class IvyLoggerInterface(logger: Logger) 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)
|
||||
}
|
||||
}
|
||||
//DEBUG level messages are very verbose and rarely useful to users.
|
||||
// TODO: provide access to this information some other way
|
||||
def debug(msg: String) {}
|
||||
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) = if (SbtIvyLogger.acceptError(msg)) logger.error(msg)
|
||||
|
||||
def clearProblems = ()
|
||||
def sumupProblems = clearProblems()
|
||||
def progress = ()
|
||||
def endProgress = ()
|
||||
private def emptyList = java.util.Collections.emptyList[String]
|
||||
def getProblems = emptyList
|
||||
def getWarns = emptyList
|
||||
def getErrors = emptyList
|
||||
|
||||
def endProgress(msg: String) = info(msg)
|
||||
def isShowProgress = false
|
||||
def setShowProgress(progress: Boolean) {}
|
||||
def clearProblems = ()
|
||||
def sumupProblems = clearProblems()
|
||||
def progress = ()
|
||||
def endProgress = ()
|
||||
|
||||
def endProgress(msg: String) = info(msg)
|
||||
def isShowProgress = false
|
||||
def setShowProgress(progress: Boolean) {}
|
||||
}
|
||||
private final class SbtMessageLoggerEngine extends MessageLoggerEngine
|
||||
{
|
||||
/** This is a hack to filter error messages about 'unknown resolver ...'. */
|
||||
override def error(msg: String) = if(SbtIvyLogger.acceptError(msg)) super.error(msg)
|
||||
override def sumupProblems = clearProblems()
|
||||
private final class SbtMessageLoggerEngine extends MessageLoggerEngine {
|
||||
/** This is a hack to filter error messages about 'unknown resolver ...'. */
|
||||
override def error(msg: String) = if (SbtIvyLogger.acceptError(msg)) super.error(msg)
|
||||
override def sumupProblems = clearProblems()
|
||||
}
|
||||
private object SbtIvyLogger
|
||||
{
|
||||
val UnknownResolver = "unknown resolver"
|
||||
def acceptError(msg: String) = (msg ne null) && !msg.startsWith(UnknownResolver)
|
||||
private object SbtIvyLogger {
|
||||
val UnknownResolver = "unknown resolver"
|
||||
def acceptError(msg: String) = (msg ne null) && !msg.startsWith(UnknownResolver)
|
||||
}
|
||||
|
|
@ -6,51 +6,49 @@ package sbt
|
|||
import java.io.File
|
||||
import collection.mutable
|
||||
|
||||
import org.apache.ivy.core.{module, report}
|
||||
import module.descriptor.{Artifact => IvyArtifact}
|
||||
import org.apache.ivy.core.{ module, report }
|
||||
import module.descriptor.{ Artifact => IvyArtifact }
|
||||
import module.id.ModuleRevisionId
|
||||
import report.{ArtifactDownloadReport, ConfigurationResolveReport, ResolveReport}
|
||||
import report.{ ArtifactDownloadReport, ConfigurationResolveReport, ResolveReport }
|
||||
|
||||
object IvyRetrieve
|
||||
{
|
||||
def reports(report: ResolveReport): Seq[ConfigurationResolveReport] =
|
||||
report.getConfigurations map report.getConfigurationReport
|
||||
object IvyRetrieve {
|
||||
def reports(report: ResolveReport): Seq[ConfigurationResolveReport] =
|
||||
report.getConfigurations map report.getConfigurationReport
|
||||
|
||||
def moduleReports(confReport: ConfigurationResolveReport): Seq[ModuleReport] =
|
||||
for( revId <- confReport.getModuleRevisionIds.toArray collect { case revId: ModuleRevisionId => revId }) yield
|
||||
artifactReports(toModuleID(revId), confReport getDownloadReports revId)
|
||||
def moduleReports(confReport: ConfigurationResolveReport): Seq[ModuleReport] =
|
||||
for (revId <- confReport.getModuleRevisionIds.toArray collect { case revId: ModuleRevisionId => revId }) yield artifactReports(toModuleID(revId), confReport getDownloadReports revId)
|
||||
|
||||
def artifactReports(mid: ModuleID, artReport: Seq[ArtifactDownloadReport]): ModuleReport =
|
||||
{
|
||||
val missing = new mutable.ListBuffer[Artifact]
|
||||
val resolved = new mutable.ListBuffer[(Artifact,File)]
|
||||
for(r <- artReport) {
|
||||
val file = r.getLocalFile
|
||||
val art = toArtifact(r.getArtifact)
|
||||
if(file eq null)
|
||||
missing += art
|
||||
else
|
||||
resolved += ((art,file))
|
||||
}
|
||||
new ModuleReport(mid, resolved.toSeq, missing.toSeq)
|
||||
}
|
||||
def artifactReports(mid: ModuleID, artReport: Seq[ArtifactDownloadReport]): ModuleReport =
|
||||
{
|
||||
val missing = new mutable.ListBuffer[Artifact]
|
||||
val resolved = new mutable.ListBuffer[(Artifact, File)]
|
||||
for (r <- artReport) {
|
||||
val file = r.getLocalFile
|
||||
val art = toArtifact(r.getArtifact)
|
||||
if (file eq null)
|
||||
missing += art
|
||||
else
|
||||
resolved += ((art, file))
|
||||
}
|
||||
new ModuleReport(mid, resolved.toSeq, missing.toSeq)
|
||||
}
|
||||
|
||||
def evicted(confReport: ConfigurationResolveReport): Seq[ModuleID] =
|
||||
confReport.getEvictedNodes.map(node => toModuleID(node.getId))
|
||||
|
||||
def toModuleID(revID: ModuleRevisionId): ModuleID =
|
||||
ModuleID(revID.getOrganisation, revID.getName, revID.getRevision, extraAttributes = IvySbt.getExtraAttributes(revID))
|
||||
|
||||
def toArtifact(art: IvyArtifact): Artifact =
|
||||
{
|
||||
import art._
|
||||
Artifact(getName, getType, getExt, Option(getExtraAttribute("classifier")), getConfigurations map Configurations.config, Option(getUrl))
|
||||
}
|
||||
def evicted(confReport: ConfigurationResolveReport): Seq[ModuleID] =
|
||||
confReport.getEvictedNodes.map(node => toModuleID(node.getId))
|
||||
|
||||
def updateReport(report: ResolveReport, cachedDescriptor: File): UpdateReport =
|
||||
new UpdateReport(cachedDescriptor, reports(report) map configurationReport, updateStats(report), Map.empty) recomputeStamps()
|
||||
def updateStats(report: ResolveReport): UpdateStats =
|
||||
new UpdateStats(report.getResolveTime, report.getDownloadTime, report.getDownloadSize, false)
|
||||
def configurationReport(confReport: ConfigurationResolveReport): ConfigurationReport =
|
||||
new ConfigurationReport(confReport.getConfiguration, moduleReports(confReport), evicted(confReport))
|
||||
def toModuleID(revID: ModuleRevisionId): ModuleID =
|
||||
ModuleID(revID.getOrganisation, revID.getName, revID.getRevision, extraAttributes = IvySbt.getExtraAttributes(revID))
|
||||
|
||||
def toArtifact(art: IvyArtifact): Artifact =
|
||||
{
|
||||
import art._
|
||||
Artifact(getName, getType, getExt, Option(getExtraAttribute("classifier")), getConfigurations map Configurations.config, Option(getUrl))
|
||||
}
|
||||
|
||||
def updateReport(report: ResolveReport, cachedDescriptor: File): UpdateReport =
|
||||
new UpdateReport(cachedDescriptor, reports(report) map configurationReport, updateStats(report), Map.empty) recomputeStamps ()
|
||||
def updateStats(report: ResolveReport): UpdateStats =
|
||||
new UpdateStats(report.getResolveTime, report.getDownloadTime, report.getDownloadSize, false)
|
||||
def configurationReport(confReport: ConfigurationResolveReport): ConfigurationReport =
|
||||
new ConfigurationReport(confReport.getConfiguration, moduleReports(confReport), evicted(confReport))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,111 +6,108 @@ package sbt
|
|||
import java.util.Collections.emptyMap
|
||||
import scala.collection.mutable.HashSet
|
||||
|
||||
import org.apache.ivy.{core, plugins}
|
||||
import core.module.descriptor.{DefaultExcludeRule, ExcludeRule}
|
||||
import core.module.descriptor.{DependencyDescriptor, DefaultModuleDescriptor, ModuleDescriptor, OverrideDependencyDescriptorMediator}
|
||||
import core.module.id.{ArtifactId,ModuleId, ModuleRevisionId}
|
||||
import org.apache.ivy.{ core, plugins }
|
||||
import core.module.descriptor.{ DefaultExcludeRule, ExcludeRule }
|
||||
import core.module.descriptor.{ DependencyDescriptor, DefaultModuleDescriptor, ModuleDescriptor, OverrideDependencyDescriptorMediator }
|
||||
import core.module.id.{ ArtifactId, ModuleId, ModuleRevisionId }
|
||||
import plugins.matcher.ExactPatternMatcher
|
||||
|
||||
object ScalaArtifacts
|
||||
{
|
||||
import xsbti.ArtifactInfo._
|
||||
val Organization = ScalaOrganization
|
||||
val LibraryID = ScalaLibraryID
|
||||
val CompilerID = ScalaCompilerID
|
||||
def libraryDependency(version: String): ModuleID = ModuleID(Organization, LibraryID, version)
|
||||
object ScalaArtifacts {
|
||||
import xsbti.ArtifactInfo._
|
||||
val Organization = ScalaOrganization
|
||||
val LibraryID = ScalaLibraryID
|
||||
val CompilerID = ScalaCompilerID
|
||||
def libraryDependency(version: String): ModuleID = ModuleID(Organization, LibraryID, version)
|
||||
|
||||
private[sbt] def toolDependencies(org: String, version: String): Seq[ModuleID] = Seq(
|
||||
scalaToolDependency(org, ScalaArtifacts.CompilerID, version),
|
||||
scalaToolDependency(org, ScalaArtifacts.LibraryID, version)
|
||||
)
|
||||
private[this] def scalaToolDependency(org: String, id: String, version: String): ModuleID =
|
||||
ModuleID(org, id, version, Some(Configurations.ScalaTool.name + "->default,optional(default)") )
|
||||
private[sbt] def toolDependencies(org: String, version: String): Seq[ModuleID] = Seq(
|
||||
scalaToolDependency(org, ScalaArtifacts.CompilerID, version),
|
||||
scalaToolDependency(org, ScalaArtifacts.LibraryID, version)
|
||||
)
|
||||
private[this] def scalaToolDependency(org: String, id: String, version: String): ModuleID =
|
||||
ModuleID(org, id, version, Some(Configurations.ScalaTool.name + "->default,optional(default)"))
|
||||
}
|
||||
object SbtArtifacts
|
||||
{
|
||||
import xsbti.ArtifactInfo._
|
||||
val Organization = SbtOrganization
|
||||
object SbtArtifacts {
|
||||
import xsbti.ArtifactInfo._
|
||||
val Organization = SbtOrganization
|
||||
}
|
||||
|
||||
import ScalaArtifacts._
|
||||
|
||||
final case class IvyScala(scalaFullVersion: String, scalaBinaryVersion: String, configurations: Iterable[Configuration], checkExplicit: Boolean, filterImplicit: Boolean, overrideScalaVersion: Boolean, scalaOrganization: String = ScalaArtifacts.Organization)
|
||||
|
||||
private object IvyScala
|
||||
{
|
||||
/** Performs checks/adds filters on Scala dependencies (if enabled in IvyScala). */
|
||||
def checkModule(module: DefaultModuleDescriptor, conf: String, log: Logger)(check: IvyScala)
|
||||
{
|
||||
if(check.checkExplicit)
|
||||
checkDependencies(module, check.scalaBinaryVersion, check.configurations, log)
|
||||
if(check.filterImplicit)
|
||||
excludeScalaJars(module, check.configurations)
|
||||
if(check.overrideScalaVersion)
|
||||
overrideScalaVersion(module, check.scalaFullVersion)
|
||||
}
|
||||
def overrideScalaVersion(module: DefaultModuleDescriptor, version: String)
|
||||
{
|
||||
overrideVersion(module, Organization, LibraryID, version)
|
||||
overrideVersion(module, Organization, CompilerID, version)
|
||||
}
|
||||
def overrideVersion(module: DefaultModuleDescriptor, org: String, name: String, version: String)
|
||||
{
|
||||
val id = new ModuleId(org, name)
|
||||
val over = new OverrideDependencyDescriptorMediator(null, version)
|
||||
module.addDependencyDescriptorMediator(id, ExactPatternMatcher.INSTANCE, over)
|
||||
}
|
||||
|
||||
/** 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, scalaBinaryVersion: String, configurations: Iterable[Configuration], log: Logger)
|
||||
{
|
||||
val configSet = if(configurations.isEmpty) (c: String) => true else configurationSet(configurations)
|
||||
def binaryScalaWarning(dep: DependencyDescriptor): Option[String] =
|
||||
{
|
||||
val id = dep.getDependencyRevisionId
|
||||
val depBinaryVersion = CrossVersion.binaryScalaVersion(id.getRevision)
|
||||
val mismatched = id.getOrganisation == Organization && depBinaryVersion != scalaBinaryVersion && dep.getModuleConfigurations.exists(configSet)
|
||||
if(mismatched)
|
||||
Some("Binary version (" + depBinaryVersion + ") for dependency " + id +
|
||||
"\n\tin " + module.getModuleRevisionId +
|
||||
" differs from Scala binary version in project (" + scalaBinaryVersion + ").")
|
||||
else
|
||||
None
|
||||
}
|
||||
module.getDependencies.toList.flatMap(binaryScalaWarning).toSet foreach { (s: String) => log.warn(s) }
|
||||
}
|
||||
private def configurationSet(configurations: Iterable[Configuration]) = configurations.map(_.toString).toSet
|
||||
private object IvyScala {
|
||||
/** Performs checks/adds filters on Scala dependencies (if enabled in IvyScala). */
|
||||
def checkModule(module: DefaultModuleDescriptor, conf: String, log: Logger)(check: IvyScala) {
|
||||
if (check.checkExplicit)
|
||||
checkDependencies(module, check.scalaBinaryVersion, check.configurations, log)
|
||||
if (check.filterImplicit)
|
||||
excludeScalaJars(module, check.configurations)
|
||||
if (check.overrideScalaVersion)
|
||||
overrideScalaVersion(module, check.scalaFullVersion)
|
||||
}
|
||||
def overrideScalaVersion(module: DefaultModuleDescriptor, version: String) {
|
||||
overrideVersion(module, Organization, LibraryID, version)
|
||||
overrideVersion(module, Organization, CompilerID, version)
|
||||
}
|
||||
def overrideVersion(module: DefaultModuleDescriptor, org: String, name: String, version: String) {
|
||||
val id = new ModuleId(org, name)
|
||||
val over = new OverrideDependencyDescriptorMediator(null, version)
|
||||
module.addDependencyDescriptorMediator(id, ExactPatternMatcher.INSTANCE, over)
|
||||
}
|
||||
|
||||
/** Adds exclusions for the scala library and compiler jars so that they are not downloaded. This is
|
||||
* done because these jars are provided by the ScalaInstance of the project. The version of Scala to use
|
||||
* is done by setting scalaVersion 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(Organization, name, configurationNames, "jar"))
|
||||
excludeScalaJar(LibraryID)
|
||||
excludeScalaJar(CompilerID)
|
||||
}
|
||||
/** Creates an ExcludeRule that excludes artifacts with the given module organization and name for
|
||||
* the given configurations. */
|
||||
private[sbt] def excludeRule(organization: String, name: String, configurationNames: Iterable[String], excludeTypePattern: String): ExcludeRule =
|
||||
{
|
||||
val artifact = new ArtifactId(ModuleId.newInstance(organization, name), "*", excludeTypePattern, "*")
|
||||
val rule = new DefaultExcludeRule(artifact, ExactPatternMatcher.INSTANCE, emptyMap[AnyRef,AnyRef])
|
||||
configurationNames.foreach(rule.addConfiguration)
|
||||
rule
|
||||
}
|
||||
/**
|
||||
* 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, scalaBinaryVersion: String, configurations: Iterable[Configuration], log: Logger) {
|
||||
val configSet = if (configurations.isEmpty) (c: String) => true else configurationSet(configurations)
|
||||
def binaryScalaWarning(dep: DependencyDescriptor): Option[String] =
|
||||
{
|
||||
val id = dep.getDependencyRevisionId
|
||||
val depBinaryVersion = CrossVersion.binaryScalaVersion(id.getRevision)
|
||||
val mismatched = id.getOrganisation == Organization && depBinaryVersion != scalaBinaryVersion && dep.getModuleConfigurations.exists(configSet)
|
||||
if (mismatched)
|
||||
Some("Binary version (" + depBinaryVersion + ") for dependency " + id +
|
||||
"\n\tin " + module.getModuleRevisionId +
|
||||
" differs from Scala binary version in project (" + scalaBinaryVersion + ").")
|
||||
else
|
||||
None
|
||||
}
|
||||
module.getDependencies.toList.flatMap(binaryScalaWarning).toSet foreach { (s: String) => log.warn(s) }
|
||||
}
|
||||
private def configurationSet(configurations: Iterable[Configuration]) = configurations.map(_.toString).toSet
|
||||
|
||||
/**
|
||||
* Adds exclusions for the scala library and compiler jars so that they are not downloaded. This is
|
||||
* done because these jars are provided by the ScalaInstance of the project. The version of Scala to use
|
||||
* is done by setting scalaVersion 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(Organization, name, configurationNames, "jar"))
|
||||
excludeScalaJar(LibraryID)
|
||||
excludeScalaJar(CompilerID)
|
||||
}
|
||||
/**
|
||||
* Creates an ExcludeRule that excludes artifacts with the given module organization and name for
|
||||
* the given configurations.
|
||||
*/
|
||||
private[sbt] def excludeRule(organization: String, name: String, configurationNames: Iterable[String], excludeTypePattern: String): ExcludeRule =
|
||||
{
|
||||
val artifact = new ArtifactId(ModuleId.newInstance(organization, name), "*", excludeTypePattern, "*")
|
||||
val rule = new DefaultExcludeRule(artifact, ExactPatternMatcher.INSTANCE, emptyMap[AnyRef, AnyRef])
|
||||
configurationNames.foreach(rule.addConfiguration)
|
||||
rule
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package sbt
|
||||
|
||||
private[sbt] object IvyUtil
|
||||
{
|
||||
def separate[A,B](l: Seq[Either[A,B]]): (Seq[A], Seq[B]) =
|
||||
(l.flatMap(_.left.toOption), l.flatMap(_.right.toOption))
|
||||
private[sbt] object IvyUtil {
|
||||
def separate[A, B](l: Seq[Either[A, B]]): (Seq[A], Seq[B]) =
|
||||
(l.flatMap(_.left.toOption), l.flatMap(_.right.toOption))
|
||||
}
|
||||
|
|
@ -10,349 +10,348 @@ package sbt
|
|||
import java.io.File
|
||||
// Node needs to be renamed to XNode because the task subproject contains a Node type that will shadow
|
||||
// scala.xml.Node when generating aggregated API documentation
|
||||
import scala.xml.{Elem, Node => XNode, NodeSeq, PrettyPrinter, PrefixedAttribute}
|
||||
import scala.xml.{ Elem, Node => XNode, NodeSeq, PrettyPrinter, PrefixedAttribute }
|
||||
import Configurations.Optional
|
||||
|
||||
import org.apache.ivy.{core, plugins, Ivy}
|
||||
import org.apache.ivy.{ core, plugins, Ivy }
|
||||
import core.settings.IvySettings
|
||||
import core.module.descriptor.{DependencyArtifactDescriptor, DependencyDescriptor, License, ModuleDescriptor, ExcludeRule}
|
||||
import plugins.resolver.{ChainResolver, DependencyResolver, IBiblioResolver}
|
||||
import core.module.descriptor.{ DependencyArtifactDescriptor, DependencyDescriptor, License, ModuleDescriptor, ExcludeRule }
|
||||
import plugins.resolver.{ ChainResolver, DependencyResolver, IBiblioResolver }
|
||||
|
||||
class MakePom(val log: Logger)
|
||||
{
|
||||
@deprecated("Use `write(Ivy, ModuleDescriptor, ModuleInfo, Option[Iterable[Configuration]], Set[String], NodeSeq, XNode => XNode, MavenRepository => Boolean, Boolean, File)` instead", "0.11.2")
|
||||
def write(ivy: Ivy, module: ModuleDescriptor, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], extra: NodeSeq, process: XNode => XNode, filterRepositories: MavenRepository => Boolean, allRepositories: Boolean, output: File): Unit =
|
||||
write(ivy, module, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], Set(Artifact.DefaultType), extra, process, filterRepositories, allRepositories, output)
|
||||
def write(ivy: Ivy, module: ModuleDescriptor, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], includeTypes: Set[String], extra: NodeSeq, process: XNode => XNode, filterRepositories: MavenRepository => Boolean, allRepositories: Boolean, output: File): Unit =
|
||||
write(process(toPom(ivy, module, moduleInfo, configurations, includeTypes, extra, filterRepositories, allRepositories)), output)
|
||||
// use \n as newline because toString uses PrettyPrinter, which hard codes line endings to be \n
|
||||
def write(node: XNode, output: File): Unit = write(toString(node), output, "\n")
|
||||
def write(xmlString: String, output: File, newline: String)
|
||||
{
|
||||
IO.write(output, "<?xml version='1.0' encoding='" + IO.utf8.name + "'?>" + newline + xmlString)
|
||||
}
|
||||
class MakePom(val log: Logger) {
|
||||
@deprecated("Use `write(Ivy, ModuleDescriptor, ModuleInfo, Option[Iterable[Configuration]], Set[String], NodeSeq, XNode => XNode, MavenRepository => Boolean, Boolean, File)` instead", "0.11.2")
|
||||
def write(ivy: Ivy, module: ModuleDescriptor, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], extra: NodeSeq, process: XNode => XNode, filterRepositories: MavenRepository => Boolean, allRepositories: Boolean, output: File): Unit =
|
||||
write(ivy, module, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], Set(Artifact.DefaultType), extra, process, filterRepositories, allRepositories, output)
|
||||
def write(ivy: Ivy, module: ModuleDescriptor, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], includeTypes: Set[String], extra: NodeSeq, process: XNode => XNode, filterRepositories: MavenRepository => Boolean, allRepositories: Boolean, output: File): Unit =
|
||||
write(process(toPom(ivy, module, moduleInfo, configurations, includeTypes, extra, filterRepositories, allRepositories)), output)
|
||||
// use \n as newline because toString uses PrettyPrinter, which hard codes line endings to be \n
|
||||
def write(node: XNode, output: File): Unit = write(toString(node), output, "\n")
|
||||
def write(xmlString: String, output: File, newline: String) {
|
||||
IO.write(output, "<?xml version='1.0' encoding='" + IO.utf8.name + "'?>" + newline + xmlString)
|
||||
}
|
||||
|
||||
def toString(node: XNode): String = new PrettyPrinter(1000, 4).format(node)
|
||||
@deprecated("Use `toPom(Ivy, ModuleDescriptor, ModuleInfo, Option[Iterable[Configuration]], Set[String], NodeSeq, MavenRepository => Boolean, Boolean)` instead", "0.11.2")
|
||||
def toPom(ivy: Ivy, module: ModuleDescriptor, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], extra: NodeSeq, filterRepositories: MavenRepository => Boolean, allRepositories: Boolean): XNode =
|
||||
toPom(ivy, module, moduleInfo, configurations, Set(Artifact.DefaultType), extra, filterRepositories, allRepositories)
|
||||
def toPom(ivy: Ivy, module: ModuleDescriptor, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], includeTypes: Set[String], extra: NodeSeq, filterRepositories: MavenRepository => Boolean, allRepositories: Boolean): XNode =
|
||||
(<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
{ makeModuleID(module) }
|
||||
<name>{moduleInfo.nameFormal}</name>
|
||||
{ makeStartYear(moduleInfo) }
|
||||
{ makeOrganization(moduleInfo) }
|
||||
{ makeScmInfo(moduleInfo) }
|
||||
{ extra }
|
||||
{
|
||||
val deps = depsInConfs(module, configurations)
|
||||
makeProperties(module, deps) ++
|
||||
makeDependencies(deps, includeTypes)
|
||||
}
|
||||
{ makeRepositories(ivy.getSettings, allRepositories, filterRepositories) }
|
||||
</project>)
|
||||
def toString(node: XNode): String = new PrettyPrinter(1000, 4).format(node)
|
||||
@deprecated("Use `toPom(Ivy, ModuleDescriptor, ModuleInfo, Option[Iterable[Configuration]], Set[String], NodeSeq, MavenRepository => Boolean, Boolean)` instead", "0.11.2")
|
||||
def toPom(ivy: Ivy, module: ModuleDescriptor, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], extra: NodeSeq, filterRepositories: MavenRepository => Boolean, allRepositories: Boolean): XNode =
|
||||
toPom(ivy, module, moduleInfo, configurations, Set(Artifact.DefaultType), extra, filterRepositories, allRepositories)
|
||||
def toPom(ivy: Ivy, module: ModuleDescriptor, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], includeTypes: Set[String], extra: NodeSeq, filterRepositories: MavenRepository => Boolean, allRepositories: Boolean): XNode =
|
||||
(<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
{ makeModuleID(module) }
|
||||
<name>{ moduleInfo.nameFormal }</name>
|
||||
{ makeStartYear(moduleInfo) }
|
||||
{ makeOrganization(moduleInfo) }
|
||||
{ makeScmInfo(moduleInfo) }
|
||||
{ extra }
|
||||
{
|
||||
val deps = depsInConfs(module, configurations)
|
||||
makeProperties(module, deps) ++
|
||||
makeDependencies(deps, includeTypes)
|
||||
}
|
||||
{ makeRepositories(ivy.getSettings, allRepositories, filterRepositories) }
|
||||
</project>)
|
||||
|
||||
def makeModuleID(module: ModuleDescriptor): NodeSeq =
|
||||
{
|
||||
val mrid = moduleDescriptor(module)
|
||||
val a: NodeSeq =
|
||||
(<groupId>{ mrid.getOrganisation }</groupId>
|
||||
<artifactId>{ mrid.getName }</artifactId>
|
||||
<packaging>{ packaging(module) }</packaging>)
|
||||
val b: NodeSeq =
|
||||
( (description(module.getDescription) ++
|
||||
homePage(module.getHomePage) ++
|
||||
revision(mrid.getRevision) ++
|
||||
licenses(module.getLicenses)) : NodeSeq )
|
||||
a ++ b
|
||||
}
|
||||
def makeModuleID(module: ModuleDescriptor): NodeSeq =
|
||||
{
|
||||
val mrid = moduleDescriptor(module)
|
||||
val a: NodeSeq =
|
||||
(<groupId>{ mrid.getOrganisation }</groupId>
|
||||
<artifactId>{ mrid.getName }</artifactId>
|
||||
<packaging>{ packaging(module) }</packaging>)
|
||||
val b: NodeSeq =
|
||||
((description(module.getDescription) ++
|
||||
homePage(module.getHomePage) ++
|
||||
revision(mrid.getRevision) ++
|
||||
licenses(module.getLicenses)): NodeSeq)
|
||||
a ++ b
|
||||
}
|
||||
|
||||
def makeStartYear(moduleInfo: ModuleInfo): NodeSeq =
|
||||
moduleInfo.startYear match {
|
||||
case Some(y) => <inceptionYear>{y}</inceptionYear>
|
||||
case _ => NodeSeq.Empty
|
||||
}
|
||||
def makeOrganization(moduleInfo: ModuleInfo): NodeSeq =
|
||||
{
|
||||
<organization>
|
||||
<name>{moduleInfo.organizationName}</name>
|
||||
{ moduleInfo.organizationHomepage match {
|
||||
case Some(h) => <url>{h}</url>
|
||||
case _ => NodeSeq.Empty
|
||||
}}
|
||||
</organization>
|
||||
}
|
||||
def makeScmInfo(moduleInfo: ModuleInfo): NodeSeq =
|
||||
{
|
||||
moduleInfo.scmInfo match {
|
||||
case Some(s) =>
|
||||
<scm>
|
||||
<url>{s.browseUrl}</url>
|
||||
<connection>{s.connection}</connection>
|
||||
{s.devConnection match {
|
||||
case Some(d) => <developerConnection>{d}</developerConnection>
|
||||
case _ => NodeSeq.Empty
|
||||
}}
|
||||
</scm>
|
||||
case _ => NodeSeq.Empty
|
||||
}
|
||||
}
|
||||
def makeProperties(module: ModuleDescriptor, dependencies: Seq[DependencyDescriptor]): NodeSeq =
|
||||
{
|
||||
val extra = IvySbt.getExtraAttributes(module)
|
||||
val depExtra = CustomPomParser.writeDependencyExtra(dependencies).mkString("\n")
|
||||
val allExtra = if(depExtra.isEmpty) extra else extra.updated(CustomPomParser.ExtraAttributesKey, depExtra)
|
||||
if(allExtra.isEmpty) NodeSeq.Empty else makeProperties(allExtra)
|
||||
}
|
||||
def makeProperties(extra: Map[String,String]): NodeSeq = {
|
||||
def _extraAttributes(k: String) = if (k == CustomPomParser.ExtraAttributesKey) xmlSpacePreserve else scala.xml.Null
|
||||
<properties> {
|
||||
for( (key,value) <- extra ) yield
|
||||
(<x>{value}</x>).copy(label = key, attributes = _extraAttributes(key))
|
||||
} </properties>
|
||||
}
|
||||
def makeStartYear(moduleInfo: ModuleInfo): NodeSeq =
|
||||
moduleInfo.startYear match {
|
||||
case Some(y) => <inceptionYear>{ y }</inceptionYear>
|
||||
case _ => NodeSeq.Empty
|
||||
}
|
||||
def makeOrganization(moduleInfo: ModuleInfo): NodeSeq =
|
||||
{
|
||||
<organization>
|
||||
<name>{ moduleInfo.organizationName }</name>
|
||||
{
|
||||
moduleInfo.organizationHomepage match {
|
||||
case Some(h)=> <url>{ h }</url>
|
||||
case _ => NodeSeq.Empty
|
||||
}
|
||||
}
|
||||
</organization>
|
||||
}
|
||||
def makeScmInfo(moduleInfo: ModuleInfo): NodeSeq =
|
||||
{
|
||||
moduleInfo.scmInfo match {
|
||||
case Some(s) =>
|
||||
<scm>
|
||||
<url>{ s.browseUrl }</url>
|
||||
<connection>{ s.connection }</connection>
|
||||
{
|
||||
s.devConnection match {
|
||||
case Some(d)=> <developerConnection>{ d }</developerConnection>
|
||||
case _=> NodeSeq.Empty
|
||||
}
|
||||
}
|
||||
</scm>
|
||||
case _ => NodeSeq.Empty
|
||||
}
|
||||
}
|
||||
def makeProperties(module: ModuleDescriptor, dependencies: Seq[DependencyDescriptor]): NodeSeq =
|
||||
{
|
||||
val extra = IvySbt.getExtraAttributes(module)
|
||||
val depExtra = CustomPomParser.writeDependencyExtra(dependencies).mkString("\n")
|
||||
val allExtra = if (depExtra.isEmpty) extra else extra.updated(CustomPomParser.ExtraAttributesKey, depExtra)
|
||||
if (allExtra.isEmpty) NodeSeq.Empty else makeProperties(allExtra)
|
||||
}
|
||||
def makeProperties(extra: Map[String, String]): NodeSeq = {
|
||||
def _extraAttributes(k: String) = if (k == CustomPomParser.ExtraAttributesKey) xmlSpacePreserve else scala.xml.Null
|
||||
<properties> {
|
||||
for ((key, value) <- extra) yield (<x>{ value }</x>).copy(label = key, attributes = _extraAttributes(key))
|
||||
} </properties>
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute tag that PrettyPrinter won't ignore, saying "don't mess with my spaces"
|
||||
* Without this, PrettyPrinter will flatten multiple entries for ExtraDependencyAttributes and make them
|
||||
* unparseable. (e.g. a plugin that depends on multiple plugins will fail)
|
||||
*/
|
||||
def xmlSpacePreserve = new PrefixedAttribute("xml", "space", "preserve", scala.xml.Null)
|
||||
/**
|
||||
* Attribute tag that PrettyPrinter won't ignore, saying "don't mess with my spaces"
|
||||
* Without this, PrettyPrinter will flatten multiple entries for ExtraDependencyAttributes and make them
|
||||
* unparseable. (e.g. a plugin that depends on multiple plugins will fail)
|
||||
*/
|
||||
def xmlSpacePreserve = new PrefixedAttribute("xml", "space", "preserve", scala.xml.Null)
|
||||
|
||||
def description(d: String) = if((d eq null) || d.isEmpty) NodeSeq.Empty else <description>{d}</description>
|
||||
def licenses(ls: Array[License]) = if(ls == null || ls.isEmpty) NodeSeq.Empty else <licenses>{ls.map(license)}</licenses>
|
||||
def license(l: License) =
|
||||
<license>
|
||||
<name>{l.getName}</name>
|
||||
<url>{l.getUrl}</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
def homePage(homePage: String) = if(homePage eq null) NodeSeq.Empty else <url>{homePage}</url>
|
||||
def revision(version: String) = if(version ne null) <version>{version}</version> else NodeSeq.Empty
|
||||
def packaging(module: ModuleDescriptor) =
|
||||
module.getAllArtifacts match
|
||||
{
|
||||
case Array() => "pom"
|
||||
case Array(x) => x.getType
|
||||
case xs =>
|
||||
val types = xs.map(_.getType).toList.filterNot(IgnoreTypes)
|
||||
types match {
|
||||
case Nil => Artifact.PomType
|
||||
case xs if xs.contains(Artifact.DefaultType) => Artifact.DefaultType
|
||||
case x :: xs => x
|
||||
}
|
||||
}
|
||||
val IgnoreTypes: Set[String] = Set(Artifact.SourceType, Artifact.DocType, Artifact.PomType)
|
||||
def description(d: String) = if ((d eq null) || d.isEmpty) NodeSeq.Empty else <description>{ d }</description>
|
||||
def licenses(ls: Array[License]) = if (ls == null || ls.isEmpty) NodeSeq.Empty else <licenses>{ ls.map(license) }</licenses>
|
||||
def license(l: License) =
|
||||
<license>
|
||||
<name>{ l.getName }</name>
|
||||
<url>{ l.getUrl }</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
def homePage(homePage: String) = if (homePage eq null) NodeSeq.Empty else <url>{ homePage }</url>
|
||||
def revision(version: String) = if (version ne null) <version>{ version }</version> else NodeSeq.Empty
|
||||
def packaging(module: ModuleDescriptor) =
|
||||
module.getAllArtifacts match {
|
||||
case Array() => "pom"
|
||||
case Array(x) => x.getType
|
||||
case xs =>
|
||||
val types = xs.map(_.getType).toList.filterNot(IgnoreTypes)
|
||||
types match {
|
||||
case Nil => Artifact.PomType
|
||||
case xs if xs.contains(Artifact.DefaultType) => Artifact.DefaultType
|
||||
case x :: xs => x
|
||||
}
|
||||
}
|
||||
val IgnoreTypes: Set[String] = Set(Artifact.SourceType, Artifact.DocType, Artifact.PomType)
|
||||
|
||||
def makeDependencies(dependencies: Seq[DependencyDescriptor], includeTypes: Set[String]): NodeSeq =
|
||||
if(dependencies.isEmpty)
|
||||
NodeSeq.Empty
|
||||
else
|
||||
<dependencies>
|
||||
{ dependencies.map(makeDependency(_, includeTypes)) }
|
||||
</dependencies>
|
||||
def makeDependencies(dependencies: Seq[DependencyDescriptor], includeTypes: Set[String]): NodeSeq =
|
||||
if (dependencies.isEmpty)
|
||||
NodeSeq.Empty
|
||||
else
|
||||
<dependencies>
|
||||
{ dependencies.map(makeDependency(_, includeTypes)) }
|
||||
</dependencies>
|
||||
|
||||
def makeDependency(dependency: DependencyDescriptor, includeTypes: Set[String]): NodeSeq =
|
||||
{
|
||||
val artifacts = dependency.getAllDependencyArtifacts
|
||||
val includeArtifacts = artifacts.filter(d => includeTypes(d.getType))
|
||||
if(artifacts.isEmpty) {
|
||||
val (scope, optional) = getScopeAndOptional(dependency.getModuleConfigurations)
|
||||
makeDependencyElem(dependency, scope, optional, None, None)
|
||||
}
|
||||
else if(includeArtifacts.isEmpty)
|
||||
NodeSeq.Empty
|
||||
else
|
||||
NodeSeq.fromSeq(artifacts.map( a => makeDependencyElem(dependency, a) ))
|
||||
}
|
||||
def makeDependency(dependency: DependencyDescriptor, includeTypes: Set[String]): NodeSeq =
|
||||
{
|
||||
val artifacts = dependency.getAllDependencyArtifacts
|
||||
val includeArtifacts = artifacts.filter(d => includeTypes(d.getType))
|
||||
if (artifacts.isEmpty) {
|
||||
val (scope, optional) = getScopeAndOptional(dependency.getModuleConfigurations)
|
||||
makeDependencyElem(dependency, scope, optional, None, None)
|
||||
} else if (includeArtifacts.isEmpty)
|
||||
NodeSeq.Empty
|
||||
else
|
||||
NodeSeq.fromSeq(artifacts.map(a => makeDependencyElem(dependency, a)))
|
||||
}
|
||||
|
||||
def makeDependencyElem(dependency: DependencyDescriptor, artifact: DependencyArtifactDescriptor): Elem =
|
||||
{
|
||||
val configs = artifact.getConfigurations.toList match {
|
||||
case Nil | "*" :: Nil => dependency.getModuleConfigurations
|
||||
case x => x.toArray
|
||||
}
|
||||
val (scope, optional) = getScopeAndOptional(configs)
|
||||
val classifier = artifactClassifier(artifact)
|
||||
val baseType = artifactType(artifact)
|
||||
val tpe = (classifier, baseType) match {
|
||||
case (Some(c), Some(tpe)) if Artifact.classifierType(c) == tpe => None
|
||||
case _ => baseType
|
||||
}
|
||||
makeDependencyElem(dependency, scope, optional, classifier, tpe)
|
||||
}
|
||||
def makeDependencyElem(dependency: DependencyDescriptor, scope: Option[String], optional: Boolean, classifier: Option[String], tpe: Option[String]): Elem =
|
||||
{
|
||||
val mrid = dependency.getDependencyRevisionId
|
||||
<dependency>
|
||||
<groupId>{mrid.getOrganisation}</groupId>
|
||||
<artifactId>{mrid.getName}</artifactId>
|
||||
<version>{makeDependencyVersion(mrid.getRevision)}</version>
|
||||
{ scopeElem(scope) }
|
||||
{ optionalElem(optional) }
|
||||
{ classifierElem(classifier) }
|
||||
{ typeElem(tpe) }
|
||||
{ exclusions(dependency) }
|
||||
</dependency>
|
||||
}
|
||||
def makeDependencyElem(dependency: DependencyDescriptor, artifact: DependencyArtifactDescriptor): Elem =
|
||||
{
|
||||
val configs = artifact.getConfigurations.toList match {
|
||||
case Nil | "*" :: Nil => dependency.getModuleConfigurations
|
||||
case x => x.toArray
|
||||
}
|
||||
val (scope, optional) = getScopeAndOptional(configs)
|
||||
val classifier = artifactClassifier(artifact)
|
||||
val baseType = artifactType(artifact)
|
||||
val tpe = (classifier, baseType) match {
|
||||
case (Some(c), Some(tpe)) if Artifact.classifierType(c) == tpe => None
|
||||
case _ => baseType
|
||||
}
|
||||
makeDependencyElem(dependency, scope, optional, classifier, tpe)
|
||||
}
|
||||
def makeDependencyElem(dependency: DependencyDescriptor, scope: Option[String], optional: Boolean, classifier: Option[String], tpe: Option[String]): Elem =
|
||||
{
|
||||
val mrid = dependency.getDependencyRevisionId
|
||||
<dependency>
|
||||
<groupId>{ mrid.getOrganisation }</groupId>
|
||||
<artifactId>{ mrid.getName }</artifactId>
|
||||
<version>{ makeDependencyVersion(mrid.getRevision) }</version>
|
||||
{ scopeElem(scope) }
|
||||
{ optionalElem(optional) }
|
||||
{ classifierElem(classifier) }
|
||||
{ typeElem(tpe) }
|
||||
{ exclusions(dependency) }
|
||||
</dependency>
|
||||
}
|
||||
|
||||
def makeDependencyVersion(revision: String): String = {
|
||||
def plusRange(s: String, shift: Int = 0) = {
|
||||
def pow(i: Int): Int = if (i > 0) 10 * pow(i - 1) else 1
|
||||
val (prefixVersion, lastVersion) = (s + "0" * shift).reverse.split("\\.", 2) match {
|
||||
case Array(revLast, revRest) =>
|
||||
(revRest.reverse + ".", revLast.reverse)
|
||||
case Array(revLast) => ("", revLast.reverse)
|
||||
}
|
||||
val lastVersionInt = lastVersion.toInt
|
||||
s"[${prefixVersion}${lastVersion},${prefixVersion}${lastVersionInt + pow(shift)})"
|
||||
}
|
||||
val startSym = Set(']', '[', '(')
|
||||
val stopSym = Set(']', '[', ')')
|
||||
try {
|
||||
if (revision endsWith ".+") {
|
||||
plusRange(revision.substring(0, revision.length - 2))
|
||||
} else if (revision endsWith "+") {
|
||||
val base = revision.take(revision.length - 1)
|
||||
// This is a heuristic. Maven just doesn't support Ivy's notions of 1+, so
|
||||
// we assume version ranges never go beyond 5 siginificant digits.
|
||||
(0 to 5).map(plusRange(base, _)).mkString(",")
|
||||
} else if (startSym(revision(0)) && stopSym(revision(revision.length - 1))) {
|
||||
val start = revision(0)
|
||||
val stop = revision(revision.length - 1)
|
||||
val mid = revision.substring(1, revision.length - 1)
|
||||
(if (start == ']') "(" else start) + mid + (if (stop == '[') ")" else stop)
|
||||
} else revision
|
||||
} catch {
|
||||
case e: NumberFormatException =>
|
||||
// TODO - if the version doesn't meet our expectations, maybe we just issue a hard
|
||||
// error instead of softly ignoring the attempt to rewrite.
|
||||
//sys.error(s"Could not fix version [$revision] into maven style version")
|
||||
revision
|
||||
}
|
||||
}
|
||||
|
||||
@deprecated("No longer used and will be removed.", "0.12.1")
|
||||
def classifier(dependency: DependencyDescriptor, includeTypes: Set[String]): NodeSeq =
|
||||
{
|
||||
val jarDep = dependency.getAllDependencyArtifacts.filter(d => includeTypes(d.getType)).headOption
|
||||
jarDep match {
|
||||
case Some(a) => classifierElem(artifactClassifier(a))
|
||||
case None => NodeSeq.Empty
|
||||
}
|
||||
}
|
||||
def artifactType(artifact: DependencyArtifactDescriptor): Option[String] =
|
||||
Option(artifact.getType).flatMap { tpe => if (tpe == "jar") None else Some(tpe) }
|
||||
def typeElem(tpe: Option[String]): NodeSeq =
|
||||
tpe match {
|
||||
case Some(t) => <type>{ t }</type>
|
||||
case None => NodeSeq.Empty
|
||||
}
|
||||
|
||||
def makeDependencyVersion(revision: String): String = {
|
||||
def plusRange(s:String, shift:Int = 0) = {
|
||||
def pow(i:Int):Int = if (i>0) 10 * pow(i-1) else 1
|
||||
val (prefixVersion, lastVersion) = (s+"0"*shift).reverse.split("\\.",2) match {
|
||||
case Array(revLast,revRest) =>
|
||||
( revRest.reverse + ".", revLast.reverse )
|
||||
case Array(revLast) => ("", revLast.reverse)
|
||||
}
|
||||
val lastVersionInt = lastVersion.toInt
|
||||
s"[${prefixVersion}${lastVersion},${prefixVersion}${lastVersionInt+pow(shift)})"
|
||||
}
|
||||
val startSym=Set(']','[','(')
|
||||
val stopSym=Set(']','[',')')
|
||||
try {
|
||||
if (revision endsWith ".+") {
|
||||
plusRange(revision.substring(0,revision.length-2))
|
||||
} else if (revision endsWith "+") {
|
||||
val base = revision.take(revision.length-1)
|
||||
// This is a heuristic. Maven just doesn't support Ivy's notions of 1+, so
|
||||
// we assume version ranges never go beyond 5 siginificant digits.
|
||||
(0 to 5).map(plusRange(base,_)).mkString(",")
|
||||
} else if (startSym(revision(0)) && stopSym(revision(revision.length-1))) {
|
||||
val start = revision(0)
|
||||
val stop = revision(revision.length-1)
|
||||
val mid = revision.substring(1,revision.length-1)
|
||||
(if (start == ']') "(" else start) + mid + (if (stop == '[') ")" else stop)
|
||||
} else revision
|
||||
} catch {
|
||||
case e: NumberFormatException =>
|
||||
// TODO - if the version doesn't meet our expectations, maybe we just issue a hard
|
||||
// error instead of softly ignoring the attempt to rewrite.
|
||||
//sys.error(s"Could not fix version [$revision] into maven style version")
|
||||
revision
|
||||
}
|
||||
}
|
||||
def artifactClassifier(artifact: DependencyArtifactDescriptor): Option[String] =
|
||||
Option(artifact.getExtraAttribute("classifier"))
|
||||
def classifierElem(classifier: Option[String]): NodeSeq =
|
||||
classifier match {
|
||||
case Some(c) => <classifier>{ c }</classifier>
|
||||
case None => NodeSeq.Empty
|
||||
}
|
||||
|
||||
@deprecated("No longer used and will be removed.", "0.12.1")
|
||||
def classifier(dependency: DependencyDescriptor, includeTypes: Set[String]): NodeSeq =
|
||||
{
|
||||
val jarDep = dependency.getAllDependencyArtifacts.filter(d => includeTypes(d.getType)).headOption
|
||||
jarDep match {
|
||||
case Some(a) => classifierElem(artifactClassifier(a))
|
||||
case None => NodeSeq.Empty
|
||||
}
|
||||
}
|
||||
def artifactType(artifact: DependencyArtifactDescriptor): Option[String] =
|
||||
Option(artifact.getType).flatMap { tpe => if(tpe == "jar") None else Some(tpe) }
|
||||
def typeElem(tpe: Option[String]): NodeSeq =
|
||||
tpe match {
|
||||
case Some(t) => <type>{t}</type>
|
||||
case None => NodeSeq.Empty
|
||||
}
|
||||
|
||||
def artifactClassifier(artifact: DependencyArtifactDescriptor): Option[String] =
|
||||
Option(artifact.getExtraAttribute("classifier"))
|
||||
def classifierElem(classifier: Option[String]): NodeSeq =
|
||||
classifier match {
|
||||
case Some(c) => <classifier>{c}</classifier>
|
||||
case None => NodeSeq.Empty
|
||||
}
|
||||
@deprecated("No longer used and will be removed.", "0.12.1")
|
||||
def scopeAndOptional(dependency: DependencyDescriptor): NodeSeq =
|
||||
{
|
||||
val (scope, opt) = getScopeAndOptional(dependency.getModuleConfigurations)
|
||||
scopeElem(scope) ++ optionalElem(opt)
|
||||
}
|
||||
def scopeElem(scope: Option[String]): NodeSeq = scope match {
|
||||
case None | Some(Configurations.Compile.name) => NodeSeq.Empty
|
||||
case Some(s) => <scope>{ s }</scope>
|
||||
}
|
||||
def optionalElem(opt: Boolean) = if (opt) <optional>true</optional> else NodeSeq.Empty
|
||||
def moduleDescriptor(module: ModuleDescriptor) = module.getModuleRevisionId
|
||||
|
||||
@deprecated("No longer used and will be removed.", "0.12.1")
|
||||
def scopeAndOptional(dependency: DependencyDescriptor): NodeSeq =
|
||||
{
|
||||
val (scope, opt) = getScopeAndOptional(dependency.getModuleConfigurations)
|
||||
scopeElem(scope) ++ optionalElem(opt)
|
||||
}
|
||||
def scopeElem(scope: Option[String]): NodeSeq = scope match {
|
||||
case None | Some(Configurations.Compile.name) => NodeSeq.Empty
|
||||
case Some(s) => <scope>{s}</scope>
|
||||
}
|
||||
def optionalElem(opt: Boolean) = if(opt) <optional>true</optional> else NodeSeq.Empty
|
||||
def moduleDescriptor(module: ModuleDescriptor) = module.getModuleRevisionId
|
||||
def getScopeAndOptional(confs: Array[String]): (Option[String], Boolean) =
|
||||
{
|
||||
val (opt, notOptional) = confs.partition(_ == Optional.name)
|
||||
val defaultNotOptional = Configurations.defaultMavenConfigurations.find(notOptional contains _.name)
|
||||
val scope = defaultNotOptional.map(_.name)
|
||||
(scope, !opt.isEmpty)
|
||||
}
|
||||
|
||||
def getScopeAndOptional(confs: Array[String]): (Option[String], Boolean) =
|
||||
{
|
||||
val (opt, notOptional) = confs.partition(_ == Optional.name)
|
||||
val defaultNotOptional = Configurations.defaultMavenConfigurations.find(notOptional contains _.name)
|
||||
val scope = defaultNotOptional.map(_.name)
|
||||
(scope, !opt.isEmpty)
|
||||
}
|
||||
def exclusions(dependency: DependencyDescriptor): NodeSeq =
|
||||
{
|
||||
val excl = dependency.getExcludeRules(dependency.getModuleConfigurations)
|
||||
val (warns, excls) = IvyUtil.separate(excl.map(makeExclusion))
|
||||
if (!warns.isEmpty) log.warn(warns.mkString(IO.Newline))
|
||||
if (!excls.isEmpty) <exclusions>{ excls }</exclusions>
|
||||
else NodeSeq.Empty
|
||||
}
|
||||
def makeExclusion(exclRule: ExcludeRule): Either[String, NodeSeq] =
|
||||
{
|
||||
val m = exclRule.getId.getModuleId
|
||||
val (g, a) = (m.getOrganisation, m.getName)
|
||||
if (g == null || g.isEmpty || g == "*" || a.isEmpty || a == "*")
|
||||
Left("Skipped generating '<exclusion/>' for %s. Dependency exclusion should have both 'org' and 'module' to comply with Maven POM's schema.".format(m))
|
||||
else
|
||||
Right(
|
||||
<exclusion>
|
||||
<groupId>{ g }</groupId>
|
||||
<artifactId>{ a }</artifactId>
|
||||
</exclusion>
|
||||
)
|
||||
}
|
||||
|
||||
def exclusions(dependency: DependencyDescriptor): NodeSeq =
|
||||
{
|
||||
val excl = dependency.getExcludeRules(dependency.getModuleConfigurations)
|
||||
val (warns, excls) = IvyUtil.separate(excl.map(makeExclusion))
|
||||
if(!warns.isEmpty) log.warn(warns.mkString(IO.Newline))
|
||||
if(!excls.isEmpty) <exclusions>{excls}</exclusions>
|
||||
else NodeSeq.Empty
|
||||
}
|
||||
def makeExclusion(exclRule: ExcludeRule): Either[String, NodeSeq] =
|
||||
{
|
||||
val m = exclRule.getId.getModuleId
|
||||
val (g, a) = (m.getOrganisation, m.getName)
|
||||
if(g == null || g.isEmpty || g == "*" || a.isEmpty || a == "*")
|
||||
Left("Skipped generating '<exclusion/>' for %s. Dependency exclusion should have both 'org' and 'module' to comply with Maven POM's schema.".format(m))
|
||||
else
|
||||
Right(
|
||||
<exclusion>
|
||||
<groupId>{g}</groupId>
|
||||
<artifactId>{a}</artifactId>
|
||||
</exclusion>
|
||||
)
|
||||
}
|
||||
def makeRepositories(settings: IvySettings, includeAll: Boolean, filterRepositories: MavenRepository => Boolean) =
|
||||
{
|
||||
class MavenRepo(name: String, snapshots: Boolean, releases: Boolean)
|
||||
val repositories = if (includeAll) allResolvers(settings) else resolvers(settings.getDefaultResolver)
|
||||
val mavenRepositories =
|
||||
repositories.flatMap {
|
||||
case m: IBiblioResolver if m.isM2compatible && m.getRoot != IBiblioResolver.DEFAULT_M2_ROOT =>
|
||||
MavenRepository(m.getName, m.getRoot) :: Nil
|
||||
case _ => Nil
|
||||
}
|
||||
val repositoryElements = mavenRepositories.filter(filterRepositories).map(mavenRepository)
|
||||
if (repositoryElements.isEmpty) repositoryElements else <repositories>{ repositoryElements }</repositories>
|
||||
}
|
||||
def allResolvers(settings: IvySettings): Seq[DependencyResolver] = flatten(castResolvers(settings.getResolvers)).distinct
|
||||
def flatten(rs: Seq[DependencyResolver]): Seq[DependencyResolver] = if (rs eq null) Nil else rs.flatMap(resolvers)
|
||||
def resolvers(r: DependencyResolver): Seq[DependencyResolver] =
|
||||
r match { case c: ChainResolver => flatten(castResolvers(c.getResolvers)); case _ => r :: Nil }
|
||||
|
||||
def makeRepositories(settings: IvySettings, includeAll: Boolean, filterRepositories: MavenRepository => Boolean) =
|
||||
{
|
||||
class MavenRepo(name: String, snapshots: Boolean, releases: Boolean)
|
||||
val repositories = if(includeAll) allResolvers(settings) else resolvers(settings.getDefaultResolver)
|
||||
val mavenRepositories =
|
||||
repositories.flatMap {
|
||||
case m: IBiblioResolver if m.isM2compatible && m.getRoot != IBiblioResolver.DEFAULT_M2_ROOT =>
|
||||
MavenRepository(m.getName, m.getRoot) :: Nil
|
||||
case _ => Nil
|
||||
}
|
||||
val repositoryElements = mavenRepositories.filter(filterRepositories).map(mavenRepository)
|
||||
if(repositoryElements.isEmpty) repositoryElements else <repositories>{repositoryElements}</repositories>
|
||||
}
|
||||
def allResolvers(settings: IvySettings): Seq[DependencyResolver] = flatten(castResolvers(settings.getResolvers)).distinct
|
||||
def flatten(rs: Seq[DependencyResolver]): Seq[DependencyResolver] = if(rs eq null) Nil else rs.flatMap(resolvers)
|
||||
def resolvers(r: DependencyResolver): Seq[DependencyResolver] =
|
||||
r match { case c: ChainResolver => flatten(castResolvers(c.getResolvers)); case _ => r :: Nil }
|
||||
// cast the contents of a pre-generics collection
|
||||
private def castResolvers(s: java.util.Collection[_]): Seq[DependencyResolver] =
|
||||
s.toArray.map(_.asInstanceOf[DependencyResolver])
|
||||
|
||||
// cast the contents of a pre-generics collection
|
||||
private def castResolvers(s: java.util.Collection[_]): Seq[DependencyResolver] =
|
||||
s.toArray.map(_.asInstanceOf[DependencyResolver])
|
||||
def toID(name: String) = checkID(name.filter(isValidIDCharacter).mkString, name)
|
||||
def isValidIDCharacter(c: Char) = c.isLetterOrDigit
|
||||
private def checkID(id: String, name: String) = if (id.isEmpty) sys.error("Could not convert '" + name + "' to an ID") else id
|
||||
def mavenRepository(repo: MavenRepository): XNode =
|
||||
mavenRepository(toID(repo.name), repo.name, repo.root)
|
||||
def mavenRepository(id: String, name: String, root: String): XNode =
|
||||
<repository>
|
||||
<id>{ id }</id>
|
||||
<name>{ name }</name>
|
||||
<url>{ root }</url>
|
||||
<layout>{ if (name == JavaNet1Repository.name) "legacy" else "default" }</layout>
|
||||
</repository>
|
||||
|
||||
def toID(name: String) = checkID(name.filter(isValidIDCharacter).mkString, name)
|
||||
def isValidIDCharacter(c: Char) = c.isLetterOrDigit
|
||||
private def checkID(id: String, name: String) = if(id.isEmpty) sys.error("Could not convert '" + name + "' to an ID") else id
|
||||
def mavenRepository(repo: MavenRepository): XNode =
|
||||
mavenRepository(toID(repo.name), repo.name, repo.root)
|
||||
def mavenRepository(id: String, name: String, root: String): XNode =
|
||||
<repository>
|
||||
<id>{id}</id>
|
||||
<name>{name}</name>
|
||||
<url>{root}</url>
|
||||
<layout>{ if(name == JavaNet1Repository.name) "legacy" else "default" }</layout>
|
||||
</repository>
|
||||
|
||||
/** 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 depsInConfs(module: ModuleDescriptor, configurations: Option[Iterable[Configuration]]): Seq[DependencyDescriptor] =
|
||||
{
|
||||
val keepConfigurations = IvySbt.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)
|
||||
}
|
||||
module.getDependencies flatMap translate
|
||||
}
|
||||
/**
|
||||
* 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 depsInConfs(module: ModuleDescriptor, configurations: Option[Iterable[Configuration]]): Seq[DependencyDescriptor] =
|
||||
{
|
||||
val keepConfigurations = IvySbt.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)
|
||||
}
|
||||
module.getDependencies flatMap translate
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,103 +3,121 @@
|
|||
*/
|
||||
package sbt
|
||||
|
||||
import java.net.URL
|
||||
import java.net.URL
|
||||
|
||||
final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, isForce: Boolean = false, explicitArtifacts: Seq[Artifact] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String,String] = Map.empty, crossVersion: CrossVersion = CrossVersion.Disabled)
|
||||
{
|
||||
override def toString: String =
|
||||
organization + ":" + name + ":" + revision +
|
||||
(configurations match { case Some(s) => ":" + s; case None => "" }) +
|
||||
(if(extraAttributes.isEmpty) "" else " " + extraString)
|
||||
final case class ModuleID(organization: String, name: String, revision: String, configurations: Option[String] = None, isChanging: Boolean = false, isTransitive: Boolean = true, isForce: Boolean = false, explicitArtifacts: Seq[Artifact] = Nil, exclusions: Seq[ExclusionRule] = Nil, extraAttributes: Map[String, String] = Map.empty, crossVersion: CrossVersion = CrossVersion.Disabled) {
|
||||
override def toString: String =
|
||||
organization + ":" + name + ":" + revision +
|
||||
(configurations match { case Some(s) => ":" + s; case None => "" }) +
|
||||
(if (extraAttributes.isEmpty) "" else " " + extraString)
|
||||
|
||||
/** String representation of the extra attributes, excluding any information only attributes. */
|
||||
def extraString: String = extraDependencyAttributes.map { case (k,v) => k + "=" + v } mkString("(",", ",")")
|
||||
/** String representation of the extra attributes, excluding any information only attributes. */
|
||||
def extraString: String = extraDependencyAttributes.map { case (k, v) => k + "=" + v } mkString ("(", ", ", ")")
|
||||
|
||||
/** Returns the extra attributes except for ones marked as information only (ones that typically would not be used for dependency resolution). */
|
||||
def extraDependencyAttributes: Map[String,String] = extraAttributes.filterKeys(!_.startsWith(CustomPomParser.InfoKeyPrefix))
|
||||
/** Returns the extra attributes except for ones marked as information only (ones that typically would not be used for dependency resolution). */
|
||||
def extraDependencyAttributes: Map[String, String] = extraAttributes.filterKeys(!_.startsWith(CustomPomParser.InfoKeyPrefix))
|
||||
|
||||
@deprecated("Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.", "0.12.0")
|
||||
def cross(v: Boolean): ModuleID = cross(if(v) CrossVersion.binary else CrossVersion.Disabled)
|
||||
@deprecated("Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.", "0.12.0")
|
||||
def cross(v: Boolean): ModuleID = cross(if (v) CrossVersion.binary else CrossVersion.Disabled)
|
||||
|
||||
@deprecated("Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.", "0.12.0")
|
||||
def cross(v: Boolean, verRemap: String => String): ModuleID = cross(if(v) CrossVersion.binaryMapped(verRemap) else CrossVersion.Disabled)
|
||||
@deprecated("Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.", "0.12.0")
|
||||
def cross(v: Boolean, verRemap: String => String): ModuleID = cross(if (v) CrossVersion.binaryMapped(verRemap) else CrossVersion.Disabled)
|
||||
|
||||
/** Specifies the cross-version behavior for this module. See [CrossVersion] for details.*/
|
||||
def cross(v: CrossVersion): ModuleID = copy(crossVersion = v)
|
||||
/** Specifies the cross-version behavior for this module. See [CrossVersion] for details.*/
|
||||
def cross(v: CrossVersion): ModuleID = copy(crossVersion = v)
|
||||
|
||||
// () required for chaining
|
||||
/** Do not follow dependencies of this module. Synonym for `intransitive`.*/
|
||||
def notTransitive() = intransitive()
|
||||
// () required for chaining
|
||||
/** Do not follow dependencies of this module. Synonym for `intransitive`.*/
|
||||
def notTransitive() = intransitive()
|
||||
|
||||
/** Do not follow dependencies of this module. Synonym for `notTransitive`.*/
|
||||
def intransitive() = copy(isTransitive = false)
|
||||
/** Do not follow dependencies of this module. Synonym for `notTransitive`.*/
|
||||
def intransitive() = copy(isTransitive = false)
|
||||
|
||||
/** Marks this dependency as "changing". Ivy will always check if the metadata has changed and then if the artifact has changed,
|
||||
* redownload it. sbt configures all -SNAPSHOT dependencies to be changing.
|
||||
*
|
||||
* See the "Changes in artifacts" section of https://ant.apache.org/ivy/history/trunk/concept.html for full details.
|
||||
* */
|
||||
def changing() = copy(isChanging = true)
|
||||
/**
|
||||
* Marks this dependency as "changing". Ivy will always check if the metadata has changed and then if the artifact has changed,
|
||||
* redownload it. sbt configures all -SNAPSHOT dependencies to be changing.
|
||||
*
|
||||
* See the "Changes in artifacts" section of https://ant.apache.org/ivy/history/trunk/concept.html for full details.
|
||||
*/
|
||||
def changing() = copy(isChanging = true)
|
||||
|
||||
/** Indicates that conflict resolution should only select this module's revision.
|
||||
* This prevents a newer revision from being pulled in by a transitive dependency, for example.*/
|
||||
def force() = copy(isForce = true)
|
||||
/**
|
||||
* Indicates that conflict resolution should only select this module's revision.
|
||||
* This prevents a newer revision from being pulled in by a transitive dependency, for example.
|
||||
*/
|
||||
def force() = copy(isForce = true)
|
||||
|
||||
/** Specifies a URL from which the main artifact for this dependency can be downloaded.
|
||||
* This value is only consulted if the module is not found in a repository.
|
||||
* It is not included in published metadata.*/
|
||||
def from(url: String) = artifacts(Artifact(name, new URL(url)))
|
||||
/**
|
||||
* Specifies a URL from which the main artifact for this dependency can be downloaded.
|
||||
* This value is only consulted if the module is not found in a repository.
|
||||
* It is not included in published metadata.
|
||||
*/
|
||||
def from(url: String) = artifacts(Artifact(name, new URL(url)))
|
||||
|
||||
/** Adds a dependency on the artifact for this module with classifier `c`. */
|
||||
def classifier(c: String) = artifacts(Artifact(name, c))
|
||||
/** Adds a dependency on the artifact for this module with classifier `c`. */
|
||||
def classifier(c: String) = artifacts(Artifact(name, c))
|
||||
|
||||
/** Declares the explicit artifacts for this module. If this ModuleID represents a dependency,
|
||||
* these artifact definitions override the information in the dependency's published metadata. */
|
||||
def artifacts(newArtifacts: Artifact*) = copy(explicitArtifacts = newArtifacts ++ this.explicitArtifacts)
|
||||
/**
|
||||
* Declares the explicit artifacts for this module. If this ModuleID represents a dependency,
|
||||
* these artifact definitions override the information in the dependency's published metadata.
|
||||
*/
|
||||
def artifacts(newArtifacts: Artifact*) = copy(explicitArtifacts = newArtifacts ++ this.explicitArtifacts)
|
||||
|
||||
/** Applies the provided exclusions to dependencies of this module. Note that only exclusions that specify
|
||||
* both the exact organization and name and nothing else will be included in a pom.xml.*/
|
||||
def excludeAll(rules: ExclusionRule*) = copy(exclusions = this.exclusions ++ rules)
|
||||
/**
|
||||
* Applies the provided exclusions to dependencies of this module. Note that only exclusions that specify
|
||||
* both the exact organization and name and nothing else will be included in a pom.xml.
|
||||
*/
|
||||
def excludeAll(rules: ExclusionRule*) = copy(exclusions = this.exclusions ++ rules)
|
||||
|
||||
/** Excludes the dependency with organization `org` and `name` from being introduced by this dependency during resolution. */
|
||||
def exclude(org: String, name: String) = excludeAll(ExclusionRule(org, name))
|
||||
/** Excludes the dependency with organization `org` and `name` from being introduced by this dependency during resolution. */
|
||||
def exclude(org: String, name: String) = excludeAll(ExclusionRule(org, name))
|
||||
|
||||
/** Adds extra attributes for this module. All keys are prefixed with `e:` if they are not already so prefixed.
|
||||
* This information will only be published in an ivy.xml and not in a pom.xml. */
|
||||
def extra(attributes: (String,String)*) = copy(extraAttributes = this.extraAttributes ++ ModuleID.checkE(attributes))
|
||||
/**
|
||||
* Adds extra attributes for this module. All keys are prefixed with `e:` if they are not already so prefixed.
|
||||
* This information will only be published in an ivy.xml and not in a pom.xml.
|
||||
*/
|
||||
def extra(attributes: (String, String)*) = copy(extraAttributes = this.extraAttributes ++ ModuleID.checkE(attributes))
|
||||
|
||||
/** Not recommended for new use. This method is not deprecated, but the `update-classifiers` task is preferred
|
||||
* for performance and correctness. This method adds a dependency on this module's artifact with the "sources"
|
||||
* classifier. If you want to also depend on the main artifact, be sure to also call `jar()` or use `withSources()` instead.*/
|
||||
def sources() = artifacts(Artifact.sources(name))
|
||||
/**
|
||||
* Not recommended for new use. This method is not deprecated, but the `update-classifiers` task is preferred
|
||||
* for performance and correctness. This method adds a dependency on this module's artifact with the "sources"
|
||||
* classifier. If you want to also depend on the main artifact, be sure to also call `jar()` or use `withSources()` instead.
|
||||
*/
|
||||
def sources() = artifacts(Artifact.sources(name))
|
||||
|
||||
/** Not recommended for new use. This method is not deprecated, but the `update-classifiers` task is preferred
|
||||
* for performance and correctness. This method adds a dependency on this module's artifact with the "javadoc"
|
||||
* classifier. If you want to also depend on the main artifact, be sure to also call `jar()` or use `withJavadoc()` instead.*/
|
||||
def javadoc() = artifacts(Artifact.javadoc(name))
|
||||
/**
|
||||
* Not recommended for new use. This method is not deprecated, but the `update-classifiers` task is preferred
|
||||
* for performance and correctness. This method adds a dependency on this module's artifact with the "javadoc"
|
||||
* classifier. If you want to also depend on the main artifact, be sure to also call `jar()` or use `withJavadoc()` instead.
|
||||
*/
|
||||
def javadoc() = artifacts(Artifact.javadoc(name))
|
||||
|
||||
def pomOnly() = artifacts(Artifact.pom(name))
|
||||
def pomOnly() = artifacts(Artifact.pom(name))
|
||||
|
||||
/** Not recommended for new use. This method is not deprecated, but the `update-classifiers` task is preferred
|
||||
* for performance and correctness. This method adds a dependency on this module's artifact with the "sources"
|
||||
* classifier. If there is not already an explicit dependency on the main artifact, this adds one.*/
|
||||
def withSources() = jarIfEmpty.sources()
|
||||
/**
|
||||
* Not recommended for new use. This method is not deprecated, but the `update-classifiers` task is preferred
|
||||
* for performance and correctness. This method adds a dependency on this module's artifact with the "sources"
|
||||
* classifier. If there is not already an explicit dependency on the main artifact, this adds one.
|
||||
*/
|
||||
def withSources() = jarIfEmpty.sources()
|
||||
|
||||
/** Not recommended for new use. This method is not deprecated, but the `update-classifiers` task is preferred
|
||||
* for performance and correctness. This method adds a dependency on this module's artifact with the "javadoc"
|
||||
* classifier. If there is not already an explicit dependency on the main artifact, this adds one.*/
|
||||
def withJavadoc() = jarIfEmpty.javadoc()
|
||||
/**
|
||||
* Not recommended for new use. This method is not deprecated, but the `update-classifiers` task is preferred
|
||||
* for performance and correctness. This method adds a dependency on this module's artifact with the "javadoc"
|
||||
* classifier. If there is not already an explicit dependency on the main artifact, this adds one.
|
||||
*/
|
||||
def withJavadoc() = jarIfEmpty.javadoc()
|
||||
|
||||
private def jarIfEmpty = if(explicitArtifacts.isEmpty) jar() else this
|
||||
private def jarIfEmpty = if (explicitArtifacts.isEmpty) jar() else this
|
||||
|
||||
/** Declares a dependency on the main artifact. This is implied by default unless artifacts are explicitly declared, such
|
||||
* as when adding a dependency on an artifact with a classifier.*/
|
||||
def jar() = artifacts(Artifact(name))
|
||||
/**
|
||||
* Declares a dependency on the main artifact. This is implied by default unless artifacts are explicitly declared, such
|
||||
* as when adding a dependency on an artifact with a classifier.
|
||||
*/
|
||||
def jar() = artifacts(Artifact(name))
|
||||
}
|
||||
object ModuleID
|
||||
{
|
||||
/** Prefixes all keys with `e:` if they are not already so prefixed. */
|
||||
def checkE(attributes: Seq[(String, String)]) =
|
||||
for ( (key, value) <- attributes) yield
|
||||
if(key.startsWith("e:")) (key, value) else ("e:" + key, value)
|
||||
object ModuleID {
|
||||
/** Prefixes all keys with `e:` if they are not already so prefixed. */
|
||||
def checkE(attributes: Seq[(String, String)]) =
|
||||
for ((key, value) <- attributes) yield if (key.startsWith("e:")) (key, value) else ("e:" + key, value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,87 +3,88 @@
|
|||
*/
|
||||
package sbt
|
||||
|
||||
import java.io.File
|
||||
import java.util.Date
|
||||
import java.io.File
|
||||
import java.util.Date
|
||||
|
||||
import org.apache.ivy.{core,plugins}
|
||||
import core.{cache,module, report, resolve,search}
|
||||
import cache.{ArtifactOrigin,RepositoryCacheManager}
|
||||
import search.{ModuleEntry, OrganisationEntry, RevisionEntry}
|
||||
import module.id.ModuleRevisionId
|
||||
import module.descriptor.{Artifact => IArtifact, DefaultArtifact, DependencyDescriptor, ModuleDescriptor}
|
||||
import plugins.namespace.Namespace
|
||||
import plugins.resolver.{DependencyResolver,ResolverSettings}
|
||||
import report.{ArtifactDownloadReport, DownloadReport, DownloadStatus, MetadataArtifactDownloadReport}
|
||||
import resolve.{DownloadOptions, ResolveData, ResolvedModuleRevision}
|
||||
import org.apache.ivy.{ core, plugins }
|
||||
import core.{ cache, module, report, resolve, search }
|
||||
import cache.{ ArtifactOrigin, RepositoryCacheManager }
|
||||
import search.{ ModuleEntry, OrganisationEntry, RevisionEntry }
|
||||
import module.id.ModuleRevisionId
|
||||
import module.descriptor.{ Artifact => IArtifact, DefaultArtifact, DependencyDescriptor, ModuleDescriptor }
|
||||
import plugins.namespace.Namespace
|
||||
import plugins.resolver.{ DependencyResolver, ResolverSettings }
|
||||
import report.{ ArtifactDownloadReport, DownloadReport, DownloadStatus, MetadataArtifactDownloadReport }
|
||||
import resolve.{ DownloadOptions, ResolveData, ResolvedModuleRevision }
|
||||
|
||||
/**A Resolver that uses a predefined mapping from module ids to in-memory descriptors.
|
||||
* It does not handle artifacts.*/
|
||||
class ProjectResolver(name: String, map: Map[ModuleRevisionId, ModuleDescriptor]) extends ResolverAdapter
|
||||
{
|
||||
def getName = name
|
||||
def setName(name: String) = sys.error("Setting name not supported by ProjectResolver")
|
||||
override def toString = "ProjectResolver(" + name + ", mapped: " + map.keys.mkString(", ") + ")"
|
||||
/**
|
||||
* A Resolver that uses a predefined mapping from module ids to in-memory descriptors.
|
||||
* It does not handle artifacts.
|
||||
*/
|
||||
class ProjectResolver(name: String, map: Map[ModuleRevisionId, ModuleDescriptor]) extends ResolverAdapter {
|
||||
def getName = name
|
||||
def setName(name: String) = sys.error("Setting name not supported by ProjectResolver")
|
||||
override def toString = "ProjectResolver(" + name + ", mapped: " + map.keys.mkString(", ") + ")"
|
||||
|
||||
def getDependency(dd: DependencyDescriptor, data: ResolveData): ResolvedModuleRevision =
|
||||
getDependency(dd.getDependencyRevisionId).orNull
|
||||
def getDependency(dd: DependencyDescriptor, data: ResolveData): ResolvedModuleRevision =
|
||||
getDependency(dd.getDependencyRevisionId).orNull
|
||||
|
||||
private[this] def getDependency(revisionId: ModuleRevisionId): Option[ResolvedModuleRevision] =
|
||||
{
|
||||
def constructResult(descriptor: ModuleDescriptor) = new ResolvedModuleRevision(this, this, descriptor, report(revisionId), true)
|
||||
map get revisionId map constructResult
|
||||
}
|
||||
private[this] def getDependency(revisionId: ModuleRevisionId): Option[ResolvedModuleRevision] =
|
||||
{
|
||||
def constructResult(descriptor: ModuleDescriptor) = new ResolvedModuleRevision(this, this, descriptor, report(revisionId), true)
|
||||
map get revisionId map constructResult
|
||||
}
|
||||
|
||||
def report(revisionId: ModuleRevisionId): MetadataArtifactDownloadReport =
|
||||
{
|
||||
val artifact = DefaultArtifact.newIvyArtifact(revisionId, new Date)
|
||||
val r = new MetadataArtifactDownloadReport(artifact)
|
||||
r.setSearched(false)
|
||||
r.setDownloadStatus(DownloadStatus.FAILED)
|
||||
r
|
||||
}
|
||||
def report(revisionId: ModuleRevisionId): MetadataArtifactDownloadReport =
|
||||
{
|
||||
val artifact = DefaultArtifact.newIvyArtifact(revisionId, new Date)
|
||||
val r = new MetadataArtifactDownloadReport(artifact)
|
||||
r.setSearched(false)
|
||||
r.setDownloadStatus(DownloadStatus.FAILED)
|
||||
r
|
||||
}
|
||||
|
||||
// this resolver nevers locates artifacts, only resolves dependencies
|
||||
def exists(artifact: IArtifact) = false
|
||||
def locate(artifact: IArtifact) = null
|
||||
def download(artifacts: Array[IArtifact], options: DownloadOptions): DownloadReport =
|
||||
{
|
||||
val r = new DownloadReport
|
||||
for(artifact <- artifacts)
|
||||
if(getDependency(artifact.getModuleRevisionId).isEmpty)
|
||||
r.addArtifactReport(notDownloaded(artifact))
|
||||
r
|
||||
}
|
||||
// this resolver nevers locates artifacts, only resolves dependencies
|
||||
def exists(artifact: IArtifact) = false
|
||||
def locate(artifact: IArtifact) = null
|
||||
def download(artifacts: Array[IArtifact], options: DownloadOptions): DownloadReport =
|
||||
{
|
||||
val r = new DownloadReport
|
||||
for (artifact <- artifacts)
|
||||
if (getDependency(artifact.getModuleRevisionId).isEmpty)
|
||||
r.addArtifactReport(notDownloaded(artifact))
|
||||
r
|
||||
}
|
||||
|
||||
def download(artifact: ArtifactOrigin, options: DownloadOptions): ArtifactDownloadReport =
|
||||
notDownloaded(artifact.getArtifact)
|
||||
def findIvyFileRef(dd: DependencyDescriptor, data: ResolveData) = null
|
||||
def download(artifact: ArtifactOrigin, options: DownloadOptions): ArtifactDownloadReport =
|
||||
notDownloaded(artifact.getArtifact)
|
||||
def findIvyFileRef(dd: DependencyDescriptor, data: ResolveData) = null
|
||||
|
||||
def notDownloaded(artifact: IArtifact): ArtifactDownloadReport=
|
||||
{
|
||||
val r = new ArtifactDownloadReport(artifact)
|
||||
r.setDownloadStatus(DownloadStatus.FAILED)
|
||||
r
|
||||
}
|
||||
def notDownloaded(artifact: IArtifact): ArtifactDownloadReport =
|
||||
{
|
||||
val r = new ArtifactDownloadReport(artifact)
|
||||
r.setDownloadStatus(DownloadStatus.FAILED)
|
||||
r
|
||||
}
|
||||
|
||||
// doesn't support publishing
|
||||
def publish(artifact: IArtifact, src: File, overwrite: Boolean) = sys.error("Publish not supported by ProjectResolver")
|
||||
def beginPublishTransaction(module: ModuleRevisionId, overwrite: Boolean) {}
|
||||
def abortPublishTransaction() {}
|
||||
def commitPublishTransaction() {}
|
||||
// doesn't support publishing
|
||||
def publish(artifact: IArtifact, src: File, overwrite: Boolean) = sys.error("Publish not supported by ProjectResolver")
|
||||
def beginPublishTransaction(module: ModuleRevisionId, overwrite: Boolean) {}
|
||||
def abortPublishTransaction() {}
|
||||
def commitPublishTransaction() {}
|
||||
|
||||
def reportFailure() {}
|
||||
def reportFailure(art: IArtifact) {}
|
||||
def reportFailure() {}
|
||||
def reportFailure(art: IArtifact) {}
|
||||
|
||||
def listOrganisations() = new Array[OrganisationEntry](0)
|
||||
def listModules(org: OrganisationEntry) = new Array[ModuleEntry](0)
|
||||
def listRevisions(module: ModuleEntry) = new Array[RevisionEntry](0)
|
||||
def listOrganisations() = new Array[OrganisationEntry](0)
|
||||
def listModules(org: OrganisationEntry) = new Array[ModuleEntry](0)
|
||||
def listRevisions(module: ModuleEntry) = new Array[RevisionEntry](0)
|
||||
|
||||
def getNamespace = Namespace.SYSTEM_NAMESPACE
|
||||
def getNamespace = Namespace.SYSTEM_NAMESPACE
|
||||
|
||||
private[this] var settings: Option[ResolverSettings] = None
|
||||
private[this] var settings: Option[ResolverSettings] = None
|
||||
|
||||
def dumpSettings() {}
|
||||
def setSettings(settings: ResolverSettings) { this.settings = Some(settings) }
|
||||
def getRepositoryCacheManager = settings match { case Some(s) => s.getDefaultRepositoryCacheManager; case None => sys.error("No settings defined for ProjectResolver") }
|
||||
def dumpSettings() {}
|
||||
def setSettings(settings: ResolverSettings) { this.settings = Some(settings) }
|
||||
def getRepositoryCacheManager = settings match { case Some(s) => s.getDefaultRepositoryCacheManager; case None => sys.error("No settings defined for ProjectResolver") }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,84 +7,84 @@ import org.apache.ivy.core
|
|||
import org.apache.ivy.plugins.parser
|
||||
import core.IvyPatternHelper
|
||||
import core.settings.IvySettings
|
||||
import core.cache.{CacheMetadataOptions, DefaultRepositoryCacheManager, DefaultResolutionCacheManager, ResolutionCacheManager}
|
||||
import core.cache.{ CacheMetadataOptions, DefaultRepositoryCacheManager, DefaultResolutionCacheManager, ResolutionCacheManager }
|
||||
import core.module.id.ModuleRevisionId
|
||||
import core.module.descriptor.ModuleDescriptor
|
||||
import ResolutionCache.{Name, ReportDirectory, ResolvedName, ResolvedPattern}
|
||||
import ResolutionCache.{ Name, ReportDirectory, ResolvedName, ResolvedPattern }
|
||||
import parser.xml.XmlModuleDescriptorParser
|
||||
|
||||
/** Replaces the standard Ivy resolution cache in order to:
|
||||
* 1. Separate cached resolved Ivy files from resolution reports, making the resolution reports easier to find.
|
||||
* 2. Have them per-project for easier cleaning (possible with standard cache, but central to this custom one).
|
||||
* 3. Cache location includes extra attributes so that cross builds of a plugin do not overwrite each other.
|
||||
*/
|
||||
private[sbt] final class ResolutionCache(base: File, settings: IvySettings) extends ResolutionCacheManager
|
||||
{
|
||||
private[this] def resolvedFileInCache(m: ModuleRevisionId, name: String, ext: String): File = {
|
||||
val p = ResolvedPattern
|
||||
val f = IvyPatternHelper.substitute(p, m.getOrganisation, m.getName, m.getBranch, m.getRevision, name, name, ext, null, null, m.getAttributes, null)
|
||||
new File(base, f)
|
||||
}
|
||||
private[this] val reportBase: File = new File(base, ReportDirectory)
|
||||
/**
|
||||
* Replaces the standard Ivy resolution cache in order to:
|
||||
* 1. Separate cached resolved Ivy files from resolution reports, making the resolution reports easier to find.
|
||||
* 2. Have them per-project for easier cleaning (possible with standard cache, but central to this custom one).
|
||||
* 3. Cache location includes extra attributes so that cross builds of a plugin do not overwrite each other.
|
||||
*/
|
||||
private[sbt] final class ResolutionCache(base: File, settings: IvySettings) extends ResolutionCacheManager {
|
||||
private[this] def resolvedFileInCache(m: ModuleRevisionId, name: String, ext: String): File = {
|
||||
val p = ResolvedPattern
|
||||
val f = IvyPatternHelper.substitute(p, m.getOrganisation, m.getName, m.getBranch, m.getRevision, name, name, ext, null, null, m.getAttributes, null)
|
||||
new File(base, f)
|
||||
}
|
||||
private[this] val reportBase: File = new File(base, ReportDirectory)
|
||||
|
||||
def getResolutionCacheRoot: File = base
|
||||
def clean() { IO.delete(base) }
|
||||
override def toString = Name
|
||||
def getResolutionCacheRoot: File = base
|
||||
def clean() { IO.delete(base) }
|
||||
override def toString = Name
|
||||
|
||||
def getResolvedIvyFileInCache(mrid: ModuleRevisionId): File =
|
||||
resolvedFileInCache(mrid, ResolvedName, "xml")
|
||||
def getResolvedIvyPropertiesInCache(mrid: ModuleRevisionId): File =
|
||||
resolvedFileInCache(mrid, ResolvedName, "properties")
|
||||
// name needs to be the same as Ivy's default because the ivy-report.xsl stylesheet assumes this
|
||||
// when making links to reports for other configurations
|
||||
def getConfigurationResolveReportInCache(resolveId: String, conf: String): File =
|
||||
new File(reportBase, resolveId + "-" + conf + ".xml")
|
||||
def getConfigurationResolveReportsInCache(resolveId: String): Array[File] =
|
||||
IO.listFiles(reportBase).filter(_.getName.startsWith(resolveId + "-"))
|
||||
|
||||
// XXX: this method is required by ResolutionCacheManager in Ivy 2.3.0 final,
|
||||
// but it is apparently unused by Ivy as sbt uses Ivy. Therefore, it is
|
||||
// unexercised in tests. Note that the implementation of this method in Ivy 2.3.0's
|
||||
// DefaultResolutionCache also resolves parent properties for a given mrid
|
||||
def getResolvedModuleDescriptor(mrid: ModuleRevisionId): ModuleDescriptor = {
|
||||
val ivyFile = getResolvedIvyFileInCache(mrid)
|
||||
if (!ivyFile.exists()) {
|
||||
throw new IllegalStateException("Ivy file not found in cache for " + mrid + "!")
|
||||
}
|
||||
|
||||
return XmlModuleDescriptorParser.getInstance().parseDescriptor(settings, ivyFile.toURI().toURL(), false)
|
||||
}
|
||||
|
||||
def saveResolvedModuleDescriptor(md: ModuleDescriptor): Unit = {
|
||||
val mrid = md.getResolvedModuleRevisionId
|
||||
val cachedIvyFile = getResolvedIvyFileInCache(mrid)
|
||||
md.toIvyFile(cachedIvyFile)
|
||||
}
|
||||
def getResolvedIvyFileInCache(mrid: ModuleRevisionId): File =
|
||||
resolvedFileInCache(mrid, ResolvedName, "xml")
|
||||
def getResolvedIvyPropertiesInCache(mrid: ModuleRevisionId): File =
|
||||
resolvedFileInCache(mrid, ResolvedName, "properties")
|
||||
// name needs to be the same as Ivy's default because the ivy-report.xsl stylesheet assumes this
|
||||
// when making links to reports for other configurations
|
||||
def getConfigurationResolveReportInCache(resolveId: String, conf: String): File =
|
||||
new File(reportBase, resolveId + "-" + conf + ".xml")
|
||||
def getConfigurationResolveReportsInCache(resolveId: String): Array[File] =
|
||||
IO.listFiles(reportBase).filter(_.getName.startsWith(resolveId + "-"))
|
||||
|
||||
// XXX: this method is required by ResolutionCacheManager in Ivy 2.3.0 final,
|
||||
// but it is apparently unused by Ivy as sbt uses Ivy. Therefore, it is
|
||||
// unexercised in tests. Note that the implementation of this method in Ivy 2.3.0's
|
||||
// DefaultResolutionCache also resolves parent properties for a given mrid
|
||||
def getResolvedModuleDescriptor(mrid: ModuleRevisionId): ModuleDescriptor = {
|
||||
val ivyFile = getResolvedIvyFileInCache(mrid)
|
||||
if (!ivyFile.exists()) {
|
||||
throw new IllegalStateException("Ivy file not found in cache for " + mrid + "!")
|
||||
}
|
||||
|
||||
return XmlModuleDescriptorParser.getInstance().parseDescriptor(settings, ivyFile.toURI().toURL(), false)
|
||||
}
|
||||
|
||||
def saveResolvedModuleDescriptor(md: ModuleDescriptor): Unit = {
|
||||
val mrid = md.getResolvedModuleRevisionId
|
||||
val cachedIvyFile = getResolvedIvyFileInCache(mrid)
|
||||
md.toIvyFile(cachedIvyFile)
|
||||
}
|
||||
}
|
||||
private[sbt] object ResolutionCache
|
||||
{
|
||||
/** Removes cached files from the resolution cache for the module with ID `mrid`
|
||||
* and the resolveId (as set on `ResolveOptions`). */
|
||||
private[sbt] def cleanModule(mrid: ModuleRevisionId, resolveId: String, manager: ResolutionCacheManager)
|
||||
{
|
||||
val files =
|
||||
Option(manager.getResolvedIvyFileInCache(mrid)).toList :::
|
||||
Option(manager.getResolvedIvyPropertiesInCache(mrid)).toList :::
|
||||
Option(manager.getConfigurationResolveReportsInCache(resolveId)).toList.flatten
|
||||
IO.delete(files)
|
||||
}
|
||||
private[sbt] object ResolutionCache {
|
||||
/**
|
||||
* Removes cached files from the resolution cache for the module with ID `mrid`
|
||||
* and the resolveId (as set on `ResolveOptions`).
|
||||
*/
|
||||
private[sbt] def cleanModule(mrid: ModuleRevisionId, resolveId: String, manager: ResolutionCacheManager) {
|
||||
val files =
|
||||
Option(manager.getResolvedIvyFileInCache(mrid)).toList :::
|
||||
Option(manager.getResolvedIvyPropertiesInCache(mrid)).toList :::
|
||||
Option(manager.getConfigurationResolveReportsInCache(resolveId)).toList.flatten
|
||||
IO.delete(files)
|
||||
}
|
||||
|
||||
private val ReportDirectory = "reports"
|
||||
private val ReportDirectory = "reports"
|
||||
|
||||
// name of the file providing a dependency resolution report for a configuration
|
||||
private val ReportFileName = "report.xml"
|
||||
// name of the file providing a dependency resolution report for a configuration
|
||||
private val ReportFileName = "report.xml"
|
||||
|
||||
// base name (name except for extension) of resolution report file
|
||||
private val ResolvedName = "resolved.xml"
|
||||
// base name (name except for extension) of resolution report file
|
||||
private val ResolvedName = "resolved.xml"
|
||||
|
||||
// Cache name
|
||||
private val Name = "sbt-resolution-cache"
|
||||
// Cache name
|
||||
private val Name = "sbt-resolution-cache"
|
||||
|
||||
// use sbt-specific extra attributes so that resolved xml files do not get overwritten when using different Scala/sbt versions
|
||||
private val ResolvedPattern = "[organisation]/[module]/" + Resolver.PluginPattern + "[revision]/[artifact].[ext]"
|
||||
// use sbt-specific extra attributes so that resolved xml files do not get overwritten when using different Scala/sbt versions
|
||||
private val ResolvedPattern = "[organisation]/[module]/" + Resolver.PluginPattern + "[revision]/[artifact].[ext]"
|
||||
}
|
||||
|
|
@ -6,145 +6,131 @@ package sbt
|
|||
import java.io.File
|
||||
import java.net.URL
|
||||
import scala.xml.NodeSeq
|
||||
import org.apache.ivy.plugins.resolver.{DependencyResolver, IBiblioResolver}
|
||||
import org.apache.ivy.plugins.resolver.{ DependencyResolver, IBiblioResolver }
|
||||
|
||||
sealed trait Resolver
|
||||
{
|
||||
def name: String
|
||||
sealed trait Resolver {
|
||||
def name: String
|
||||
}
|
||||
final class RawRepository(val resolver: DependencyResolver) extends Resolver
|
||||
{
|
||||
def name = resolver.getName
|
||||
override def toString = "Raw(" + resolver.toString + ")"
|
||||
final class RawRepository(val resolver: DependencyResolver) extends Resolver {
|
||||
def name = resolver.getName
|
||||
override def toString = "Raw(" + resolver.toString + ")"
|
||||
}
|
||||
sealed case class ChainedResolver(name: String, resolvers: Seq[Resolver]) extends Resolver
|
||||
sealed case class MavenRepository(name: String, root: String) extends Resolver
|
||||
{
|
||||
override def toString = name + ": " + root
|
||||
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, val descriptorOptional: Boolean, val skipConsistencyCheck: Boolean)
|
||||
{
|
||||
private[sbt] def mavenStyle(): Patterns = Patterns(ivyPatterns, artifactPatterns, true)
|
||||
private[sbt] def withDescriptorOptional(): Patterns = Patterns(ivyPatterns, artifactPatterns, isMavenCompatible, true, skipConsistencyCheck)
|
||||
private[sbt] def withoutConsistencyCheck(): Patterns = Patterns(ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, true)
|
||||
private[sbt] def withIvys(patterns: Seq[String]): Patterns = Patterns(patterns ++ ivyPatterns, artifactPatterns, isMavenCompatible)
|
||||
private[sbt] def withArtifacts(patterns: Seq[String]): Patterns = Patterns(ivyPatterns, patterns ++ artifactPatterns, isMavenCompatible)
|
||||
override def toString = "Patterns(ivyPatterns=%s, artifactPatterns=%s, isMavenCompatible=%s, descriptorOptional=%s, skipConsistencyCheck=%s)".format(ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, skipConsistencyCheck)
|
||||
override def equals(obj: Any): Boolean = {
|
||||
obj match {
|
||||
case other: Patterns =>
|
||||
ivyPatterns == other.ivyPatterns && artifactPatterns == other.artifactPatterns && isMavenCompatible == other.isMavenCompatible && descriptorOptional == other.descriptorOptional && skipConsistencyCheck == other.skipConsistencyCheck
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
override def hashCode: Int = (ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, skipConsistencyCheck).hashCode
|
||||
final class Patterns(val ivyPatterns: Seq[String], val artifactPatterns: Seq[String], val isMavenCompatible: Boolean, val descriptorOptional: Boolean, val skipConsistencyCheck: Boolean) {
|
||||
private[sbt] def mavenStyle(): Patterns = Patterns(ivyPatterns, artifactPatterns, true)
|
||||
private[sbt] def withDescriptorOptional(): Patterns = Patterns(ivyPatterns, artifactPatterns, isMavenCompatible, true, skipConsistencyCheck)
|
||||
private[sbt] def withoutConsistencyCheck(): Patterns = Patterns(ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, true)
|
||||
private[sbt] def withIvys(patterns: Seq[String]): Patterns = Patterns(patterns ++ ivyPatterns, artifactPatterns, isMavenCompatible)
|
||||
private[sbt] def withArtifacts(patterns: Seq[String]): Patterns = Patterns(ivyPatterns, patterns ++ artifactPatterns, isMavenCompatible)
|
||||
override def toString = "Patterns(ivyPatterns=%s, artifactPatterns=%s, isMavenCompatible=%s, descriptorOptional=%s, skipConsistencyCheck=%s)".format(ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, skipConsistencyCheck)
|
||||
override def equals(obj: Any): Boolean = {
|
||||
obj match {
|
||||
case other: Patterns =>
|
||||
ivyPatterns == other.ivyPatterns && artifactPatterns == other.artifactPatterns && isMavenCompatible == other.isMavenCompatible && descriptorOptional == other.descriptorOptional && skipConsistencyCheck == other.skipConsistencyCheck
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
override def hashCode: Int = (ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, skipConsistencyCheck).hashCode
|
||||
|
||||
@deprecated
|
||||
def this(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean) = this(ivyPatterns, artifactPatterns, isMavenCompatible, false, false)
|
||||
@deprecated
|
||||
def this(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean) = this(ivyPatterns, artifactPatterns, isMavenCompatible, false, false)
|
||||
}
|
||||
object Patterns
|
||||
{
|
||||
implicit def defaultPatterns: Patterns = Resolver.defaultPatterns
|
||||
object Patterns {
|
||||
implicit def defaultPatterns: Patterns = Resolver.defaultPatterns
|
||||
|
||||
def apply(artifactPatterns: String*): Patterns = Patterns(true, artifactPatterns : _*)
|
||||
def apply(isMavenCompatible: Boolean, artifactPatterns: String*): Patterns = Patterns(artifactPatterns, artifactPatterns, isMavenCompatible)
|
||||
def apply(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean): Patterns = apply(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean, false, false)
|
||||
def apply(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean, descriptorOptional: Boolean, skipConsistencyCheck: Boolean): Patterns = new Patterns(ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, skipConsistencyCheck)
|
||||
def apply(artifactPatterns: String*): Patterns = Patterns(true, artifactPatterns: _*)
|
||||
def apply(isMavenCompatible: Boolean, artifactPatterns: String*): Patterns = Patterns(artifactPatterns, artifactPatterns, isMavenCompatible)
|
||||
def apply(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean): Patterns = apply(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean, false, false)
|
||||
def apply(ivyPatterns: Seq[String], artifactPatterns: Seq[String], isMavenCompatible: Boolean, descriptorOptional: Boolean, skipConsistencyCheck: Boolean): Patterns = new Patterns(ivyPatterns, artifactPatterns, isMavenCompatible, descriptorOptional, skipConsistencyCheck)
|
||||
}
|
||||
object RepositoryHelpers
|
||||
{
|
||||
final case class SshConnection(authentication: Option[SshAuthentication], hostname: Option[String], port: Option[Int])
|
||||
{
|
||||
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])
|
||||
{
|
||||
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: Option[String]) extends SshAuthentication
|
||||
final case class KeyFileAuthentication(user: String, keyfile: File, password: Option[String]) extends SshAuthentication
|
||||
object RepositoryHelpers {
|
||||
final case class SshConnection(authentication: Option[SshAuthentication], hostname: Option[String], port: Option[Int]) {
|
||||
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]) {
|
||||
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: Option[String]) extends SshAuthentication
|
||||
final case class KeyFileAuthentication(user: String, keyfile: File, password: Option[String]) extends SshAuthentication
|
||||
}
|
||||
import RepositoryHelpers.{SshConnection, FileConfiguration}
|
||||
import RepositoryHelpers.{KeyFileAuthentication, PasswordAuthentication, SshAuthentication}
|
||||
import RepositoryHelpers.{ 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
|
||||
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
|
||||
/** The object representing the configured patterns for this repository. */
|
||||
def patterns: Patterns
|
||||
|
||||
/** Enables maven 2 compatibility for this repository. */
|
||||
def mavenStyle() = copy(patterns.mavenStyle())
|
||||
/** Enables maven 2 compatibility for this repository. */
|
||||
def mavenStyle() = copy(patterns.mavenStyle())
|
||||
|
||||
/** Makes descriptor metadata optional for this repository. */
|
||||
def descriptorOptional() = copy(patterns.withDescriptorOptional())
|
||||
/** Makes descriptor metadata optional for this repository. */
|
||||
def descriptorOptional() = copy(patterns.withDescriptorOptional())
|
||||
|
||||
/** Disables consistency checking for this repository. */
|
||||
def skipConsistencyCheck() = copy(patterns.withoutConsistencyCheck())
|
||||
/** Disables consistency checking for this repository. */
|
||||
def skipConsistencyCheck() = copy(patterns.withoutConsistencyCheck())
|
||||
|
||||
/** 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))
|
||||
/** 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 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)
|
||||
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)))
|
||||
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
|
||||
/** 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 = as(user, Some(password))
|
||||
def as(user: String): RepositoryType = as(user, None)
|
||||
def as(user: String, password: Option[String]) = 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(user: String, keyfile: File): RepositoryType = as(user, keyfile, None)
|
||||
def as(user: String, keyfile: File, password: String): RepositoryType = as(user, keyfile, Some(password))
|
||||
def as(user: String, keyfile: File, password: Option[String]): RepositoryType = copy(new KeyFileAuthentication(user, keyfile, password))
|
||||
/** Configures this to use the specified user name and password when connecting to the remote repository. */
|
||||
def as(user: String, password: String): RepositoryType = as(user, Some(password))
|
||||
def as(user: String): RepositoryType = as(user, None)
|
||||
def as(user: String, password: Option[String]) = 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(user: String, keyfile: File): RepositoryType = as(user, keyfile, None)
|
||||
def as(user: String, keyfile: File, password: String): RepositoryType = as(user, keyfile, Some(password))
|
||||
def as(user: String, keyfile: File, password: Option[String]): RepositoryType = copy(new KeyFileAuthentication(user, 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)
|
||||
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)
|
||||
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._
|
||||
|
|
@ -152,151 +138,163 @@ import Resolver._
|
|||
object DefaultMavenRepository extends MavenRepository("public", IBiblioResolver.DEFAULT_M2_ROOT)
|
||||
object JavaNet2Repository extends MavenRepository(JavaNet2RepositoryName, JavaNet2RepositoryRoot)
|
||||
object JavaNet1Repository extends JavaNet1Repository
|
||||
sealed trait JavaNet1Repository extends Resolver
|
||||
{
|
||||
def name = "java.net Maven1 Repository"
|
||||
sealed trait JavaNet1Repository extends Resolver {
|
||||
def name = "java.net Maven1 Repository"
|
||||
}
|
||||
|
||||
object Resolver
|
||||
{
|
||||
val TypesafeRepositoryRoot = "http://repo.typesafe.com/typesafe"
|
||||
val SbtPluginRepositoryRoot = "http://repo.scala-sbt.org/scalasbt"
|
||||
val SonatypeRepositoryRoot = "https://oss.sonatype.org/content/repositories"
|
||||
object Resolver {
|
||||
val TypesafeRepositoryRoot = "http://repo.typesafe.com/typesafe"
|
||||
val SbtPluginRepositoryRoot = "http://repo.scala-sbt.org/scalasbt"
|
||||
val SonatypeRepositoryRoot = "https://oss.sonatype.org/content/repositories"
|
||||
|
||||
// obsolete: kept only for launcher compatibility
|
||||
private[sbt] val ScalaToolsReleasesName = "Sonatype OSS Releases"
|
||||
private[sbt] val ScalaToolsSnapshotsName = "Sonatype OSS Snapshots"
|
||||
private[sbt] val ScalaToolsReleasesRoot = SonatypeRepositoryRoot + "/releases"
|
||||
private[sbt] val ScalaToolsSnapshotsRoot = SonatypeRepositoryRoot + "/snapshots"
|
||||
private[sbt] val ScalaToolsReleases = new MavenRepository(ScalaToolsReleasesName, ScalaToolsReleasesRoot)
|
||||
private[sbt] val ScalaToolsSnapshots = new MavenRepository(ScalaToolsSnapshotsName, ScalaToolsSnapshotsRoot)
|
||||
// obsolete: kept only for launcher compatibility
|
||||
private[sbt] val ScalaToolsReleasesName = "Sonatype OSS Releases"
|
||||
private[sbt] val ScalaToolsSnapshotsName = "Sonatype OSS Snapshots"
|
||||
private[sbt] val ScalaToolsReleasesRoot = SonatypeRepositoryRoot + "/releases"
|
||||
private[sbt] val ScalaToolsSnapshotsRoot = SonatypeRepositoryRoot + "/snapshots"
|
||||
private[sbt] val ScalaToolsReleases = new MavenRepository(ScalaToolsReleasesName, ScalaToolsReleasesRoot)
|
||||
private[sbt] val ScalaToolsSnapshots = new MavenRepository(ScalaToolsSnapshotsName, ScalaToolsSnapshotsRoot)
|
||||
|
||||
val JavaNet2RepositoryName = "java.net Maven2 Repository"
|
||||
val JavaNet2RepositoryRoot = "http://download.java.net/maven/2"
|
||||
val JavaNet2RepositoryName = "java.net Maven2 Repository"
|
||||
val JavaNet2RepositoryRoot = "http://download.java.net/maven/2"
|
||||
|
||||
def typesafeRepo(status: String) = new MavenRepository("typesafe-" + status, TypesafeRepositoryRoot + "/" + status)
|
||||
def typesafeIvyRepo(status: String) = url("typesafe-ivy-" + status, new URL(TypesafeRepositoryRoot + "/ivy-" + status + "/"))(ivyStylePatterns)
|
||||
def sbtPluginRepo(status: String) = url("sbt-plugin-" + status, new URL(SbtPluginRepositoryRoot + "/sbt-plugin-" + status + "/"))(ivyStylePatterns)
|
||||
def sonatypeRepo(status: String) = new MavenRepository("sonatype-" + status, SonatypeRepositoryRoot + "/" + status)
|
||||
def typesafeRepo(status: String) = new MavenRepository("typesafe-" + status, TypesafeRepositoryRoot + "/" + status)
|
||||
def typesafeIvyRepo(status: String) = url("typesafe-ivy-" + status, new URL(TypesafeRepositoryRoot + "/ivy-" + status + "/"))(ivyStylePatterns)
|
||||
def sbtPluginRepo(status: String) = url("sbt-plugin-" + status, new URL(SbtPluginRepositoryRoot + "/sbt-plugin-" + status + "/"))(ivyStylePatterns)
|
||||
def sonatypeRepo(status: String) = new MavenRepository("sonatype-" + status, SonatypeRepositoryRoot + "/" + status)
|
||||
|
||||
/** Add the local and Maven Central repositories to the user repositories. */
|
||||
def withDefaultResolvers(userResolvers: Seq[Resolver]): Seq[Resolver] =
|
||||
withDefaultResolvers(userResolvers, true)
|
||||
/** Add the local Ivy repository to the user repositories.
|
||||
* If `mavenCentral` is true, add the Maven Central repository. */
|
||||
def withDefaultResolvers(userResolvers: Seq[Resolver], mavenCentral: Boolean): Seq[Resolver] =
|
||||
Seq(Resolver.defaultLocal) ++
|
||||
userResolvers ++
|
||||
single(DefaultMavenRepository, mavenCentral)
|
||||
private def single[T](value: T, nonEmpty: Boolean): Seq[T] = if(nonEmpty) Seq(value) else Nil
|
||||
/** Add the local and Maven Central repositories to the user repositories. */
|
||||
def withDefaultResolvers(userResolvers: Seq[Resolver]): Seq[Resolver] =
|
||||
withDefaultResolvers(userResolvers, true)
|
||||
/**
|
||||
* Add the local Ivy repository to the user repositories.
|
||||
* If `mavenCentral` is true, add the Maven Central repository.
|
||||
*/
|
||||
def withDefaultResolvers(userResolvers: Seq[Resolver], mavenCentral: Boolean): Seq[Resolver] =
|
||||
Seq(Resolver.defaultLocal) ++
|
||||
userResolvers ++
|
||||
single(DefaultMavenRepository, mavenCentral)
|
||||
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, Patterns(false))
|
||||
/** Constructs a file resolver with the given name and base directory. */
|
||||
def apply(name: String, baseDirectory: File)(implicit basePatterns: Patterns): FileRepository =
|
||||
baseRepository(new File(baseDirectory.toURI.normalize) getAbsolutePath)(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, Patterns(false))
|
||||
/** Constructs a file resolver with the given name and base directory. */
|
||||
def apply(name: String, baseURL: URL)(implicit basePatterns: Patterns): URLRepository =
|
||||
baseRepository(baseURL.toURI.normalize.toString)(URLRepository(name, _))
|
||||
}
|
||||
private def baseRepository[T](base: String)(construct: Patterns => T)(implicit basePatterns: Patterns): T =
|
||||
construct(resolvePatterns(base, basePatterns))
|
||||
/** 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, Patterns(false))
|
||||
/** Constructs a file resolver with the given name and base directory. */
|
||||
def apply(name: String, baseDirectory: File)(implicit basePatterns: Patterns): FileRepository =
|
||||
baseRepository(new File(baseDirectory.toURI.normalize) getAbsolutePath)(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, Patterns(false))
|
||||
/** Constructs a file resolver with the given name and base directory. */
|
||||
def apply(name: String, baseURL: URL)(implicit basePatterns: Patterns): URLRepository =
|
||||
baseRepository(baseURL.toURI.normalize.toString)(URLRepository(name, _))
|
||||
}
|
||||
private def baseRepository[T](base: String)(construct: Patterns => T)(implicit basePatterns: Patterns): T =
|
||||
construct(resolvePatterns(base, 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(path, patterns)
|
||||
case None => patterns
|
||||
}
|
||||
/** Resolves the ivy file and artifact patterns in `patterns` against the given base. */
|
||||
private def resolvePatterns(base: String, basePatterns: Patterns): Patterns =
|
||||
{
|
||||
def resolveAll(patterns: Seq[String]) = patterns.map(p => resolvePattern(base, p))
|
||||
Patterns(resolveAll(basePatterns.ivyPatterns), resolveAll(basePatterns.artifactPatterns), basePatterns.isMavenCompatible)
|
||||
}
|
||||
private[sbt] def resolvePattern(base: String, pattern: String): String =
|
||||
{
|
||||
val normBase = base.replace('\\', '/')
|
||||
if(normBase.endsWith("/") || pattern.startsWith("/")) normBase + pattern else normBase + "/" + pattern
|
||||
}
|
||||
def defaultFileConfiguration = FileConfiguration(true, None)
|
||||
def mavenStylePatterns = Patterns(Nil, mavenStyleBasePattern :: Nil, true)
|
||||
def ivyStylePatterns = defaultIvyPatterns//Patterns(Nil, Nil, false)
|
||||
/**
|
||||
* 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(path, patterns)
|
||||
case None => patterns
|
||||
}
|
||||
/** Resolves the ivy file and artifact patterns in `patterns` against the given base. */
|
||||
private def resolvePatterns(base: String, basePatterns: Patterns): Patterns =
|
||||
{
|
||||
def resolveAll(patterns: Seq[String]) = patterns.map(p => resolvePattern(base, p))
|
||||
Patterns(resolveAll(basePatterns.ivyPatterns), resolveAll(basePatterns.artifactPatterns), basePatterns.isMavenCompatible)
|
||||
}
|
||||
private[sbt] def resolvePattern(base: String, pattern: String): String =
|
||||
{
|
||||
val normBase = base.replace('\\', '/')
|
||||
if (normBase.endsWith("/") || pattern.startsWith("/")) normBase + pattern else normBase + "/" + pattern
|
||||
}
|
||||
def defaultFileConfiguration = FileConfiguration(true, None)
|
||||
def mavenStylePatterns = Patterns(Nil, mavenStyleBasePattern :: Nil, true)
|
||||
def ivyStylePatterns = defaultIvyPatterns //Patterns(Nil, Nil, false)
|
||||
|
||||
def defaultPatterns = mavenStylePatterns
|
||||
def mavenStyleBasePattern = "[organisation]/[module](_[scalaVersion])(_[sbtVersion])/[revision]/[artifact]-[revision](-[classifier]).[ext]"
|
||||
def localBasePattern = "[organisation]/[module]/" + PluginPattern + "[revision]/[type]s/[artifact](-[classifier]).[ext]"
|
||||
def defaultRetrievePattern = "[type]s/[organisation]/[module]/" + PluginPattern + "[artifact](-[revision])(-[classifier]).[ext]"
|
||||
final val PluginPattern = "(scala_[scalaVersion]/)(sbt_[sbtVersion]/)"
|
||||
def defaultPatterns = mavenStylePatterns
|
||||
def mavenStyleBasePattern = "[organisation]/[module](_[scalaVersion])(_[sbtVersion])/[revision]/[artifact]-[revision](-[classifier]).[ext]"
|
||||
def localBasePattern = "[organisation]/[module]/" + PluginPattern + "[revision]/[type]s/[artifact](-[classifier]).[ext]"
|
||||
def defaultRetrievePattern = "[type]s/[organisation]/[module]/" + PluginPattern + "[artifact](-[revision])(-[classifier]).[ext]"
|
||||
final val PluginPattern = "(scala_[scalaVersion]/)(sbt_[sbtVersion]/)"
|
||||
|
||||
private[this] def mavenLocalDir = new File(Path.userHome, ".m2/repository/")
|
||||
def publishMavenLocal = Resolver.file("publish-m2-local", mavenLocalDir)
|
||||
def mavenLocal = MavenRepository("Maven2 Local", mavenLocalDir.toURI.toString)
|
||||
def defaultLocal = defaultUserFileRepository("local")
|
||||
def defaultShared = defaultUserFileRepository("shared")
|
||||
def defaultUserFileRepository(id: String) =
|
||||
{
|
||||
val pList = ("${ivy.home}/" + id + "/" + localBasePattern) :: Nil
|
||||
FileRepository(id, defaultFileConfiguration, Patterns(pList, pList, false))
|
||||
}
|
||||
def defaultIvyPatterns =
|
||||
{
|
||||
val pList = List(localBasePattern)
|
||||
Patterns(pList, pList, false)
|
||||
}
|
||||
private[this] def mavenLocalDir = new File(Path.userHome, ".m2/repository/")
|
||||
def publishMavenLocal = Resolver.file("publish-m2-local", mavenLocalDir)
|
||||
def mavenLocal = MavenRepository("Maven2 Local", mavenLocalDir.toURI.toString)
|
||||
def defaultLocal = defaultUserFileRepository("local")
|
||||
def defaultShared = defaultUserFileRepository("shared")
|
||||
def defaultUserFileRepository(id: String) =
|
||||
{
|
||||
val pList = ("${ivy.home}/" + id + "/" + localBasePattern) :: Nil
|
||||
FileRepository(id, defaultFileConfiguration, Patterns(pList, pList, false))
|
||||
}
|
||||
def defaultIvyPatterns =
|
||||
{
|
||||
val pList = List(localBasePattern)
|
||||
Patterns(pList, pList, false)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,13 +5,11 @@ package sbt
|
|||
|
||||
import java.util.Locale
|
||||
|
||||
object StringUtilities
|
||||
{
|
||||
@deprecated("Different use cases require different normalization. Use Project.normalizeModuleID or normalizeProjectID instead.", "0.13.0")
|
||||
def normalize(s: String) = s.toLowerCase(Locale.ENGLISH).replaceAll("""\W+""", "-")
|
||||
def nonEmpty(s: String, label: String)
|
||||
{
|
||||
require(s.trim.length > 0, label + " cannot be empty.")
|
||||
}
|
||||
def appendable(s: String) = if(s.isEmpty) "" else "_" + s
|
||||
object StringUtilities {
|
||||
@deprecated("Different use cases require different normalization. Use Project.normalizeModuleID or normalizeProjectID instead.", "0.13.0")
|
||||
def normalize(s: String) = s.toLowerCase(Locale.ENGLISH).replaceAll("""\W+""", "-")
|
||||
def nonEmpty(s: String, label: String) {
|
||||
require(s.trim.length > 0, label + " cannot be empty.")
|
||||
}
|
||||
def appendable(s: String) = if (s.isEmpty) "" else "_" + s
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,142 +3,138 @@
|
|||
*/
|
||||
package sbt
|
||||
|
||||
import java.io.File
|
||||
import java.io.File
|
||||
|
||||
/** Provides information about dependency resolution.
|
||||
* It does not include information about evicted modules, only about the modules ultimately selected by the conflict manager.
|
||||
* This means that for a given configuration, there should only be one revision for a given organization and module name.
|
||||
* @param cachedDescriptor the location of the resolved module descriptor in the cache
|
||||
* @param configurations a sequence containing one report for each configuration resolved.
|
||||
* @param stats information about the update that produced this report
|
||||
* @see sbt.RichUpdateReport
|
||||
*/
|
||||
final class UpdateReport(val cachedDescriptor: File, val configurations: Seq[ConfigurationReport], val stats: UpdateStats, private[sbt] val stamps: Map[File,Long])
|
||||
{
|
||||
@deprecated("Use the variant that provides timestamps of files.", "0.13.0")
|
||||
def this(cachedDescriptor: File, configurations: Seq[ConfigurationReport], stats: UpdateStats) =
|
||||
this(cachedDescriptor, configurations, stats, Map.empty)
|
||||
/**
|
||||
* Provides information about dependency resolution.
|
||||
* It does not include information about evicted modules, only about the modules ultimately selected by the conflict manager.
|
||||
* This means that for a given configuration, there should only be one revision for a given organization and module name.
|
||||
* @param cachedDescriptor the location of the resolved module descriptor in the cache
|
||||
* @param configurations a sequence containing one report for each configuration resolved.
|
||||
* @param stats information about the update that produced this report
|
||||
* @see sbt.RichUpdateReport
|
||||
*/
|
||||
final class UpdateReport(val cachedDescriptor: File, val configurations: Seq[ConfigurationReport], val stats: UpdateStats, private[sbt] val stamps: Map[File, Long]) {
|
||||
@deprecated("Use the variant that provides timestamps of files.", "0.13.0")
|
||||
def this(cachedDescriptor: File, configurations: Seq[ConfigurationReport], stats: UpdateStats) =
|
||||
this(cachedDescriptor, configurations, stats, Map.empty)
|
||||
|
||||
override def toString = "Update report:\n\t" + stats + "\n" + configurations.mkString
|
||||
override def toString = "Update report:\n\t" + stats + "\n" + configurations.mkString
|
||||
|
||||
/** All resolved modules in all configurations. */
|
||||
def allModules: Seq[ModuleID] = configurations.flatMap(_.allModules).distinct
|
||||
/** All resolved modules in all configurations. */
|
||||
def allModules: Seq[ModuleID] = configurations.flatMap(_.allModules).distinct
|
||||
|
||||
def retrieve(f: (String, ModuleID, Artifact, File) => File): UpdateReport =
|
||||
new UpdateReport(cachedDescriptor, configurations map { _ retrieve f}, stats, stamps )
|
||||
def retrieve(f: (String, ModuleID, Artifact, File) => File): UpdateReport =
|
||||
new UpdateReport(cachedDescriptor, configurations map { _ retrieve f }, stats, stamps)
|
||||
|
||||
/** Gets the report for the given configuration, or `None` if the configuration was not resolved.*/
|
||||
def configuration(s: String) = configurations.find(_.configuration == s)
|
||||
/** Gets the report for the given configuration, or `None` if the configuration was not resolved.*/
|
||||
def configuration(s: String) = configurations.find(_.configuration == s)
|
||||
|
||||
/** Gets the names of all resolved configurations. This `UpdateReport` contains one `ConfigurationReport` for each configuration in this list. */
|
||||
def allConfigurations: Seq[String] = configurations.map(_.configuration)
|
||||
/** Gets the names of all resolved configurations. This `UpdateReport` contains one `ConfigurationReport` for each configuration in this list. */
|
||||
def allConfigurations: Seq[String] = configurations.map(_.configuration)
|
||||
}
|
||||
|
||||
/** Provides information about resolution of a single configuration.
|
||||
* @param configuration the configuration this report is for.
|
||||
* @param modules a seqeuence containing one report for each module resolved for this configuration.
|
||||
*/
|
||||
final class ConfigurationReport(val configuration: String, val modules: Seq[ModuleReport], val evicted: Seq[ModuleID])
|
||||
{
|
||||
override def toString = "\t" + configuration + ":\n" + modules.mkString + evicted.map("\t\t(EVICTED) " + _ + "\n").mkString
|
||||
/**
|
||||
* Provides information about resolution of a single configuration.
|
||||
* @param configuration the configuration this report is for.
|
||||
* @param modules a seqeuence containing one report for each module resolved for this configuration.
|
||||
*/
|
||||
final class ConfigurationReport(val configuration: String, val modules: Seq[ModuleReport], val evicted: Seq[ModuleID]) {
|
||||
override def toString = "\t" + configuration + ":\n" + modules.mkString + evicted.map("\t\t(EVICTED) " + _ + "\n").mkString
|
||||
|
||||
/** All resolved modules for this configuration.
|
||||
* For a given organization and module name, there is only one revision/`ModuleID` in this sequence.
|
||||
*/
|
||||
def allModules: Seq[ModuleID] = modules.map(mr => addConfiguration(mr.module))
|
||||
private[this] def addConfiguration(mod: ModuleID): ModuleID = if(mod.configurations.isEmpty) mod.copy(configurations = Some(configuration)) else mod
|
||||
|
||||
def retrieve(f: (String, ModuleID, Artifact, File) => File): ConfigurationReport =
|
||||
new ConfigurationReport(configuration, modules map { _.retrieve( (mid,art,file) => f(configuration, mid, art, file)) }, evicted)
|
||||
/**
|
||||
* All resolved modules for this configuration.
|
||||
* For a given organization and module name, there is only one revision/`ModuleID` in this sequence.
|
||||
*/
|
||||
def allModules: Seq[ModuleID] = modules.map(mr => addConfiguration(mr.module))
|
||||
private[this] def addConfiguration(mod: ModuleID): ModuleID = if (mod.configurations.isEmpty) mod.copy(configurations = Some(configuration)) else mod
|
||||
|
||||
def retrieve(f: (String, ModuleID, Artifact, File) => File): ConfigurationReport =
|
||||
new ConfigurationReport(configuration, modules map { _.retrieve((mid, art, file) => f(configuration, mid, art, file)) }, evicted)
|
||||
}
|
||||
|
||||
/** Provides information about the resolution of a module.
|
||||
* This information is in the context of a specific configuration.
|
||||
* @param module the `ModuleID` this report is for.
|
||||
* @param artifacts the resolved artifacts for this module, paired with the File the artifact was retrieved to. This File may be in the
|
||||
*/
|
||||
final class ModuleReport(val module: ModuleID, val artifacts: Seq[(Artifact, File)], val missingArtifacts: Seq[Artifact])
|
||||
{
|
||||
override def toString =
|
||||
{
|
||||
val arts = artifacts.map(_.toString) ++ missingArtifacts.map(art => "(MISSING) " + art)
|
||||
"\t\t" + module + ": " +
|
||||
(if(arts.size <= 1) "" else "\n\t\t\t") + arts.mkString("\n\t\t\t") + "\n"
|
||||
}
|
||||
def retrieve(f: (ModuleID, Artifact, File) => File): ModuleReport =
|
||||
new ModuleReport(module, artifacts.map { case (art,file) => (art, f(module, art, file)) }, missingArtifacts)
|
||||
/**
|
||||
* Provides information about the resolution of a module.
|
||||
* This information is in the context of a specific configuration.
|
||||
* @param module the `ModuleID` this report is for.
|
||||
* @param artifacts the resolved artifacts for this module, paired with the File the artifact was retrieved to. This File may be in the
|
||||
*/
|
||||
final class ModuleReport(val module: ModuleID, val artifacts: Seq[(Artifact, File)], val missingArtifacts: Seq[Artifact]) {
|
||||
override def toString =
|
||||
{
|
||||
val arts = artifacts.map(_.toString) ++ missingArtifacts.map(art => "(MISSING) " + art)
|
||||
"\t\t" + module + ": " +
|
||||
(if (arts.size <= 1) "" else "\n\t\t\t") + arts.mkString("\n\t\t\t") + "\n"
|
||||
}
|
||||
def retrieve(f: (ModuleID, Artifact, File) => File): ModuleReport =
|
||||
new ModuleReport(module, artifacts.map { case (art, file) => (art, f(module, art, file)) }, missingArtifacts)
|
||||
}
|
||||
object UpdateReport
|
||||
{
|
||||
implicit def richUpdateReport(report: UpdateReport): RichUpdateReport = new RichUpdateReport(report)
|
||||
object UpdateReport {
|
||||
implicit def richUpdateReport(report: UpdateReport): RichUpdateReport = new RichUpdateReport(report)
|
||||
|
||||
/** Provides extra methods for filtering the contents of an `UpdateReport` and for obtaining references to a selected subset of the underlying files. */
|
||||
final class RichUpdateReport(report: UpdateReport)
|
||||
{
|
||||
def recomputeStamps(): UpdateReport =
|
||||
{
|
||||
val files = report.cachedDescriptor +: allFiles
|
||||
val stamps = files.map(f => (f, f.lastModified)).toMap
|
||||
new UpdateReport(report.cachedDescriptor, report.configurations, report.stats, stamps)
|
||||
}
|
||||
/** Provides extra methods for filtering the contents of an `UpdateReport` and for obtaining references to a selected subset of the underlying files. */
|
||||
final class RichUpdateReport(report: UpdateReport) {
|
||||
def recomputeStamps(): UpdateReport =
|
||||
{
|
||||
val files = report.cachedDescriptor +: allFiles
|
||||
val stamps = files.map(f => (f, f.lastModified)).toMap
|
||||
new UpdateReport(report.cachedDescriptor, report.configurations, report.stats, stamps)
|
||||
}
|
||||
|
||||
import DependencyFilter._
|
||||
/** Obtains all successfully retrieved files in all configurations and modules. */
|
||||
def allFiles: Seq[File] = matching(DependencyFilter.allPass)
|
||||
import DependencyFilter._
|
||||
/** Obtains all successfully retrieved files in all configurations and modules. */
|
||||
def allFiles: Seq[File] = matching(DependencyFilter.allPass)
|
||||
|
||||
/** Obtains all successfully retrieved files in configurations, modules, and artifacts matching the specified filter. */
|
||||
def matching(f: DependencyFilter): Seq[File] = select0(f).distinct
|
||||
/** Obtains all successfully retrieved files in configurations, modules, and artifacts matching the specified filter. */
|
||||
def matching(f: DependencyFilter): Seq[File] = select0(f).distinct
|
||||
|
||||
/** Obtains all successfully retrieved files matching all provided filters. An unspecified argument matches all files. */
|
||||
def select(configuration: ConfigurationFilter = configurationFilter(), module: ModuleFilter = moduleFilter(), artifact: ArtifactFilter = artifactFilter()): Seq[File] =
|
||||
matching(DependencyFilter.make(configuration, module, artifact))
|
||||
/** Obtains all successfully retrieved files matching all provided filters. An unspecified argument matches all files. */
|
||||
def select(configuration: ConfigurationFilter = configurationFilter(), module: ModuleFilter = moduleFilter(), artifact: ArtifactFilter = artifactFilter()): Seq[File] =
|
||||
matching(DependencyFilter.make(configuration, module, artifact))
|
||||
|
||||
private[this] def select0(f: DependencyFilter): Seq[File] =
|
||||
for(cReport <- report.configurations; mReport <- cReport.modules; (artifact, file) <- mReport.artifacts if f(cReport.configuration, mReport.module, artifact)) yield {
|
||||
if(file == null) error("Null file: conf=" + cReport.configuration + ", module=" + mReport.module + ", art: " + artifact)
|
||||
file
|
||||
}
|
||||
|
||||
/** Constructs a new report that only contains files matching the specified filter.*/
|
||||
def filter(f: DependencyFilter): UpdateReport =
|
||||
moduleReportMap { (configuration, modReport) =>
|
||||
import modReport._
|
||||
val newArtifacts = artifacts filter { case (art, file) => f(configuration, module, art) }
|
||||
val newMissing = missingArtifacts filter { art => f(configuration, module, art) }
|
||||
new ModuleReport(module, newArtifacts, newMissing)
|
||||
}
|
||||
def substitute(f: (String, ModuleID, Seq[(Artifact, File)]) => Seq[(Artifact, File)]): UpdateReport =
|
||||
moduleReportMap { (configuration, modReport) =>
|
||||
val newArtifacts = f(configuration, modReport.module, modReport.artifacts)
|
||||
new ModuleReport(modReport.module, newArtifacts, Nil)
|
||||
}
|
||||
private[this] def select0(f: DependencyFilter): Seq[File] =
|
||||
for (cReport <- report.configurations; mReport <- cReport.modules; (artifact, file) <- mReport.artifacts if f(cReport.configuration, mReport.module, artifact)) yield {
|
||||
if (file == null) error("Null file: conf=" + cReport.configuration + ", module=" + mReport.module + ", art: " + artifact)
|
||||
file
|
||||
}
|
||||
|
||||
def toSeq: Seq[(String, ModuleID, Artifact, File)] =
|
||||
for(confReport <- report.configurations; modReport <- confReport.modules; (artifact, file) <- modReport.artifacts) yield
|
||||
(confReport.configuration, modReport.module, artifact, file)
|
||||
/** Constructs a new report that only contains files matching the specified filter.*/
|
||||
def filter(f: DependencyFilter): UpdateReport =
|
||||
moduleReportMap { (configuration, modReport) =>
|
||||
import modReport._
|
||||
val newArtifacts = artifacts filter { case (art, file) => f(configuration, module, art) }
|
||||
val newMissing = missingArtifacts filter { art => f(configuration, module, art) }
|
||||
new ModuleReport(module, newArtifacts, newMissing)
|
||||
}
|
||||
def substitute(f: (String, ModuleID, Seq[(Artifact, File)]) => Seq[(Artifact, File)]): UpdateReport =
|
||||
moduleReportMap { (configuration, modReport) =>
|
||||
val newArtifacts = f(configuration, modReport.module, modReport.artifacts)
|
||||
new ModuleReport(modReport.module, newArtifacts, Nil)
|
||||
}
|
||||
|
||||
def allMissing: Seq[(String, ModuleID, Artifact)] =
|
||||
for(confReport <- report.configurations; modReport <- confReport.modules; artifact <- modReport.missingArtifacts) yield
|
||||
(confReport.configuration, modReport.module, artifact)
|
||||
def toSeq: Seq[(String, ModuleID, Artifact, File)] =
|
||||
for (confReport <- report.configurations; modReport <- confReport.modules; (artifact, file) <- modReport.artifacts) yield (confReport.configuration, modReport.module, artifact, file)
|
||||
|
||||
def addMissing(f: ModuleID => Seq[Artifact]): UpdateReport =
|
||||
moduleReportMap { (configuration, modReport) =>
|
||||
import modReport._
|
||||
new ModuleReport(module, artifacts, (missingArtifacts ++ f(module)).distinct)
|
||||
}
|
||||
def allMissing: Seq[(String, ModuleID, Artifact)] =
|
||||
for (confReport <- report.configurations; modReport <- confReport.modules; artifact <- modReport.missingArtifacts) yield (confReport.configuration, modReport.module, artifact)
|
||||
|
||||
def moduleReportMap(f: (String, ModuleReport) => ModuleReport): UpdateReport =
|
||||
{
|
||||
val newConfigurations = report.configurations.map { confReport =>
|
||||
import confReport._
|
||||
val newModules = modules map { modReport => f(configuration, modReport) }
|
||||
new ConfigurationReport(configuration, newModules, evicted)
|
||||
}
|
||||
new UpdateReport(report.cachedDescriptor, newConfigurations, report.stats, report.stamps)
|
||||
}
|
||||
}
|
||||
def addMissing(f: ModuleID => Seq[Artifact]): UpdateReport =
|
||||
moduleReportMap { (configuration, modReport) =>
|
||||
import modReport._
|
||||
new ModuleReport(module, artifacts, (missingArtifacts ++ f(module)).distinct)
|
||||
}
|
||||
|
||||
def moduleReportMap(f: (String, ModuleReport) => ModuleReport): UpdateReport =
|
||||
{
|
||||
val newConfigurations = report.configurations.map { confReport =>
|
||||
import confReport._
|
||||
val newModules = modules map { modReport => f(configuration, modReport) }
|
||||
new ConfigurationReport(configuration, newModules, evicted)
|
||||
}
|
||||
new UpdateReport(report.cachedDescriptor, newConfigurations, report.stats, report.stamps)
|
||||
}
|
||||
}
|
||||
}
|
||||
final class UpdateStats(val resolveTime: Long, val downloadTime: Long, val downloadSize: Long, val cached: Boolean)
|
||||
{
|
||||
override def toString = Seq("Resolve time: " + resolveTime + " ms", "Download time: " + downloadTime + " ms", "Download size: " + downloadSize + " bytes").mkString(", ")
|
||||
final class UpdateStats(val resolveTime: Long, val downloadTime: Long, val downloadSize: Long, val cached: Boolean) {
|
||||
override def toString = Seq("Resolve time: " + resolveTime + " ms", "Download time: " + downloadTime + " ms", "Download size: " + downloadSize + " bytes").mkString(", ")
|
||||
}
|
||||
|
|
@ -6,67 +6,62 @@ package impl
|
|||
|
||||
import StringUtilities.nonEmpty
|
||||
|
||||
trait DependencyBuilders
|
||||
{
|
||||
final implicit def toGroupID(groupID: String): GroupID =
|
||||
{
|
||||
nonEmpty(groupID, "Group ID")
|
||||
new GroupID(groupID)
|
||||
}
|
||||
final implicit def toRepositoryName(name: String): RepositoryName =
|
||||
{
|
||||
nonEmpty(name, "Repository name")
|
||||
new RepositoryName(name)
|
||||
}
|
||||
final implicit def moduleIDConfigurable(m: ModuleID): ModuleIDConfigurable =
|
||||
{
|
||||
require(m.configurations.isEmpty, "Configurations already specified for module " + m)
|
||||
new ModuleIDConfigurable(m)
|
||||
}
|
||||
trait DependencyBuilders {
|
||||
final implicit def toGroupID(groupID: String): GroupID =
|
||||
{
|
||||
nonEmpty(groupID, "Group ID")
|
||||
new GroupID(groupID)
|
||||
}
|
||||
final implicit def toRepositoryName(name: String): RepositoryName =
|
||||
{
|
||||
nonEmpty(name, "Repository name")
|
||||
new RepositoryName(name)
|
||||
}
|
||||
final implicit def moduleIDConfigurable(m: ModuleID): ModuleIDConfigurable =
|
||||
{
|
||||
require(m.configurations.isEmpty, "Configurations already specified for module " + m)
|
||||
new ModuleIDConfigurable(m)
|
||||
}
|
||||
}
|
||||
|
||||
final class GroupID private[sbt] (groupID: String)
|
||||
{
|
||||
def % (artifactID: String) = groupArtifact(artifactID, CrossVersion.Disabled)
|
||||
def %% (artifactID: String): GroupArtifactID = groupArtifact(artifactID, CrossVersion.binary)
|
||||
final class GroupID private[sbt] (groupID: String) {
|
||||
def %(artifactID: String) = groupArtifact(artifactID, CrossVersion.Disabled)
|
||||
def %%(artifactID: String): GroupArtifactID = groupArtifact(artifactID, CrossVersion.binary)
|
||||
|
||||
@deprecated(deprecationMessage, "0.12.0")
|
||||
def %% (artifactID: String, crossVersion: String => String) = groupArtifact(artifactID, CrossVersion.binaryMapped(crossVersion))
|
||||
@deprecated(deprecationMessage, "0.12.0")
|
||||
def %% (artifactID: String, alternatives: (String, String)*) = groupArtifact(artifactID, CrossVersion.binaryMapped(Map(alternatives: _*) orElse { case s => s }))
|
||||
@deprecated(deprecationMessage, "0.12.0")
|
||||
def %%(artifactID: String, crossVersion: String => String) = groupArtifact(artifactID, CrossVersion.binaryMapped(crossVersion))
|
||||
@deprecated(deprecationMessage, "0.12.0")
|
||||
def %%(artifactID: String, alternatives: (String, String)*) = groupArtifact(artifactID, CrossVersion.binaryMapped(Map(alternatives: _*) orElse { case s => s }))
|
||||
|
||||
private def groupArtifact(artifactID: String, cross: CrossVersion) =
|
||||
{
|
||||
nonEmpty(artifactID, "Artifact ID")
|
||||
new GroupArtifactID(groupID, artifactID, cross)
|
||||
}
|
||||
private def groupArtifact(artifactID: String, cross: CrossVersion) =
|
||||
{
|
||||
nonEmpty(artifactID, "Artifact ID")
|
||||
new GroupArtifactID(groupID, artifactID, cross)
|
||||
}
|
||||
|
||||
private[this] def deprecationMessage = """Use the cross method on the constructed ModuleID. For example: ("a" % "b" % "1").cross(...)"""
|
||||
private[this] def deprecationMessage = """Use the cross method on the constructed ModuleID. For example: ("a" % "b" % "1").cross(...)"""
|
||||
}
|
||||
final class GroupArtifactID private[sbt] (groupID: String, artifactID: String, crossVersion: CrossVersion)
|
||||
{
|
||||
def % (revision: String): ModuleID =
|
||||
{
|
||||
nonEmpty(revision, "Revision")
|
||||
ModuleID(groupID, artifactID, revision).cross(crossVersion)
|
||||
}
|
||||
final class GroupArtifactID private[sbt] (groupID: String, artifactID: String, crossVersion: CrossVersion) {
|
||||
def %(revision: String): ModuleID =
|
||||
{
|
||||
nonEmpty(revision, "Revision")
|
||||
ModuleID(groupID, artifactID, revision).cross(crossVersion)
|
||||
}
|
||||
}
|
||||
final class ModuleIDConfigurable private[sbt] (moduleID: ModuleID)
|
||||
{
|
||||
def % (configuration: Configuration): ModuleID = %(configuration.name)
|
||||
final class ModuleIDConfigurable private[sbt] (moduleID: ModuleID) {
|
||||
def %(configuration: Configuration): ModuleID = %(configuration.name)
|
||||
|
||||
def % (configurations: String): ModuleID =
|
||||
{
|
||||
nonEmpty(configurations, "Configurations")
|
||||
val c = configurations
|
||||
moduleID.copy(configurations = Some(c))
|
||||
}
|
||||
def %(configurations: String): ModuleID =
|
||||
{
|
||||
nonEmpty(configurations, "Configurations")
|
||||
val c = configurations
|
||||
moduleID.copy(configurations = Some(c))
|
||||
}
|
||||
}
|
||||
final class RepositoryName private[sbt] (name: String)
|
||||
{
|
||||
def at (location: String) =
|
||||
{
|
||||
nonEmpty(location, "Repository location")
|
||||
new MavenRepository(name, location)
|
||||
}
|
||||
final class RepositoryName private[sbt] (name: String) {
|
||||
def at(location: String) =
|
||||
{
|
||||
nonEmpty(location, "Repository location")
|
||||
new MavenRepository(name, location)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import org.apache.ivy.util.url.CredentialsStore
|
|||
*/
|
||||
object ErrorMessageAuthenticator {
|
||||
private var securityWarningLogged = false
|
||||
|
||||
|
||||
private def originalAuthenticator: Option[Authenticator] = {
|
||||
try {
|
||||
val f = classOf[Authenticator].getDeclaredField("theAuthenticator");
|
||||
|
|
@ -29,7 +29,7 @@ object ErrorMessageAuthenticator {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private lazy val ivyOriginalField = {
|
||||
val field = classOf[IvyAuthenticator].getDeclaredField("original")
|
||||
field.setAccessible(true)
|
||||
|
|
@ -42,17 +42,17 @@ object ErrorMessageAuthenticator {
|
|||
val newOriginal = new ErrorMessageAuthenticator(original)
|
||||
ivyOriginalField.set(ivy, newOriginal)
|
||||
}
|
||||
|
||||
|
||||
try Option(ivyOriginalField.get(ivy).asInstanceOf[Authenticator]) match {
|
||||
case Some(alreadyThere: ErrorMessageAuthenticator) => // We're already installed, no need to do the work again.
|
||||
case originalOpt => installIntoIvyImpl(originalOpt)
|
||||
case originalOpt => installIntoIvyImpl(originalOpt)
|
||||
} catch {
|
||||
case t: Throwable =>
|
||||
case t: Throwable =>
|
||||
Message.debug("Error occurred will trying to install debug messages into Ivy Authentication" + t.getMessage)
|
||||
}
|
||||
Some(ivy)
|
||||
}
|
||||
|
||||
|
||||
/** Installs the error message authenticator so we have nicer error messages when using java's URL for downloading. */
|
||||
def install() {
|
||||
// Actually installs the error message authenticator.
|
||||
|
|
@ -62,67 +62,68 @@ object ErrorMessageAuthenticator {
|
|||
case e: SecurityException if !securityWarningLogged =>
|
||||
securityWarningLogged = true;
|
||||
Message.warn("Not enough permissions to set the ErorrMessageAuthenticator. "
|
||||
+ "Helpful debug messages disabled!");
|
||||
}
|
||||
// We will try to use the original authenticator as backup authenticator.
|
||||
// Since there is no getter available, so try to use some reflection to
|
||||
// obtain it. If that doesn't work, assume there is no original authenticator
|
||||
def doInstallIfIvy(original: Option[Authenticator]): Unit =
|
||||
original match {
|
||||
case Some(installed: ErrorMessageAuthenticator) => // Ignore, we're already installed
|
||||
case Some(ivy: IvyAuthenticator) => installIntoIvy(ivy)
|
||||
case original => doInstall(original)
|
||||
}
|
||||
doInstallIfIvy(originalAuthenticator)
|
||||
+ "Helpful debug messages disabled!");
|
||||
}
|
||||
// We will try to use the original authenticator as backup authenticator.
|
||||
// Since there is no getter available, so try to use some reflection to
|
||||
// obtain it. If that doesn't work, assume there is no original authenticator
|
||||
def doInstallIfIvy(original: Option[Authenticator]): Unit =
|
||||
original match {
|
||||
case Some(installed: ErrorMessageAuthenticator) => // Ignore, we're already installed
|
||||
case Some(ivy: IvyAuthenticator) => installIntoIvy(ivy)
|
||||
case original => doInstall(original)
|
||||
}
|
||||
doInstallIfIvy(originalAuthenticator)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* An authenticator which just delegates to a previous authenticator and issues *nice*
|
||||
* error messages on failure to find credentials.
|
||||
*
|
||||
* Since ivy installs its own credentials handler EVERY TIME it resolves or publishes, we want to
|
||||
* An authenticator which just delegates to a previous authenticator and issues *nice*
|
||||
* error messages on failure to find credentials.
|
||||
*
|
||||
* Since ivy installs its own credentials handler EVERY TIME it resolves or publishes, we want to
|
||||
* install this one at some point and eventually ivy will capture it and use it.
|
||||
*/
|
||||
private[sbt] final class ErrorMessageAuthenticator(original: Option[Authenticator]) extends Authenticator {
|
||||
|
||||
protected override def getPasswordAuthentication(): PasswordAuthentication = {
|
||||
// We're guaranteed to only get here if Ivy's authentication fails
|
||||
if (!isProxyAuthentication) {
|
||||
val host = getRequestingHost
|
||||
// TODO - levenshtein distance "did you mean" message.
|
||||
Message.error(s"Unable to find credentials for [${getRequestingPrompt} @ ${host}].")
|
||||
val configuredRealms = IvyCredentialsLookup.realmsForHost.getOrElse(host, Set.empty)
|
||||
if(!configuredRealms.isEmpty) {
|
||||
Message.error(s" Is one of these realms mispelled for host [${host}]:")
|
||||
configuredRealms foreach { realm =>
|
||||
Message.error(s" * ${realm}")
|
||||
}
|
||||
}
|
||||
protected override def getPasswordAuthentication(): PasswordAuthentication = {
|
||||
// We're guaranteed to only get here if Ivy's authentication fails
|
||||
if (!isProxyAuthentication) {
|
||||
val host = getRequestingHost
|
||||
// TODO - levenshtein distance "did you mean" message.
|
||||
Message.error(s"Unable to find credentials for [${getRequestingPrompt} @ ${host}].")
|
||||
val configuredRealms = IvyCredentialsLookup.realmsForHost.getOrElse(host, Set.empty)
|
||||
if (!configuredRealms.isEmpty) {
|
||||
Message.error(s" Is one of these realms mispelled for host [${host}]:")
|
||||
configuredRealms foreach { realm =>
|
||||
Message.error(s" * ${realm}")
|
||||
}
|
||||
// TODO - Maybe we should work on a helpful proxy message...
|
||||
|
||||
// TODO - To be more maven friendly, we may want to also try to grab the "first" authentication that shows up for a server and try it.
|
||||
// or maybe allow that behavior to be configured, since maven users aren't used to realms (which they should be).
|
||||
|
||||
// Grabs the authentication that would have been provided had we not been installed...
|
||||
def originalAuthentication: Option[PasswordAuthentication] = {
|
||||
Authenticator.setDefault(original.getOrElse(null))
|
||||
try Option(Authenticator.requestPasswordAuthentication(
|
||||
getRequestingHost,
|
||||
getRequestingSite,
|
||||
getRequestingPort,
|
||||
getRequestingProtocol,
|
||||
getRequestingPrompt,
|
||||
getRequestingScheme))
|
||||
finally Authenticator.setDefault(this)
|
||||
}
|
||||
originalAuthentication.getOrElse(null)
|
||||
}
|
||||
}
|
||||
// TODO - Maybe we should work on a helpful proxy message...
|
||||
|
||||
/** Returns true if this authentication if for a proxy and not for an HTTP server.
|
||||
* We want to display different error messages, depending.
|
||||
*/
|
||||
private def isProxyAuthentication: Boolean =
|
||||
getRequestorType == Authenticator.RequestorType.PROXY
|
||||
// TODO - To be more maven friendly, we may want to also try to grab the "first" authentication that shows up for a server and try it.
|
||||
// or maybe allow that behavior to be configured, since maven users aren't used to realms (which they should be).
|
||||
|
||||
// Grabs the authentication that would have been provided had we not been installed...
|
||||
def originalAuthentication: Option[PasswordAuthentication] = {
|
||||
Authenticator.setDefault(original.getOrElse(null))
|
||||
try Option(Authenticator.requestPasswordAuthentication(
|
||||
getRequestingHost,
|
||||
getRequestingSite,
|
||||
getRequestingPort,
|
||||
getRequestingProtocol,
|
||||
getRequestingPrompt,
|
||||
getRequestingScheme))
|
||||
finally Authenticator.setDefault(this)
|
||||
}
|
||||
originalAuthentication.getOrElse(null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this authentication if for a proxy and not for an HTTP server.
|
||||
* We want to display different error messages, depending.
|
||||
*/
|
||||
private def isProxyAuthentication: Boolean =
|
||||
getRequestorType == Authenticator.RequestorType.PROXY
|
||||
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ private[sbt] case class Realm(host: String, realm: String) extends CredentialKey
|
|||
|
||||
/**
|
||||
* Helper mechanism to improve credential related error messages.
|
||||
*
|
||||
*
|
||||
* This evil class exposes to us the necessary information to warn on credential failure and offer
|
||||
* spelling/typo suggestions.
|
||||
*/
|
||||
|
|
@ -21,17 +21,18 @@ private[sbt] object IvyCredentialsLookup {
|
|||
|
||||
/** Helper extractor for Ivy's key-value store of credentials. */
|
||||
private object KeySplit {
|
||||
def unapply(key: String): Option[(String,String)] = {
|
||||
def unapply(key: String): Option[(String, String)] = {
|
||||
key.indexOf('@') match {
|
||||
case -1 => None
|
||||
case n => Some(key.take(n) -> key.drop(n+1))
|
||||
case n => Some(key.take(n) -> key.drop(n + 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Here we cheat runtime private so we can look in the credentials store.
|
||||
/**
|
||||
* Here we cheat runtime private so we can look in the credentials store.
|
||||
*
|
||||
* TODO - Don't bomb at class load time...
|
||||
* TODO - Don't bomb at class load time...
|
||||
*/
|
||||
private val credKeyringField = {
|
||||
val tmp = classOf[CredentialsStore].getDeclaredField("KEYRING")
|
||||
|
|
@ -45,10 +46,10 @@ private[sbt] object IvyCredentialsLookup {
|
|||
// make a clone of the set...
|
||||
(map.keySet.asScala.map {
|
||||
case KeySplit(realm, host) => Realm(host, realm)
|
||||
case host => Host(host)
|
||||
case host => Host(host)
|
||||
})(collection.breakOut)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A mapping of host -> realms in the ivy credentials store.
|
||||
*/
|
||||
|
|
@ -58,6 +59,6 @@ private[sbt] object IvyCredentialsLookup {
|
|||
} groupBy { realm =>
|
||||
realm.host
|
||||
} mapValues { realms =>
|
||||
realms map (_.realm)
|
||||
realms map (_.realm)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,134 +3,132 @@ package ivyint
|
|||
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import java.util.{Collection, Collections => CS}
|
||||
import java.util.{ Collection, Collections => CS }
|
||||
import CS.singleton
|
||||
|
||||
import org.apache.ivy.{core, plugins, util, Ivy}
|
||||
import core.module.descriptor.{DependencyArtifactDescriptor, DefaultDependencyArtifactDescriptor}
|
||||
import core.module.descriptor.{DefaultDependencyDescriptor => DDD, DependencyDescriptor}
|
||||
import core.module.id.{ArtifactId,ModuleId, ModuleRevisionId}
|
||||
import org.apache.ivy.{ core, plugins, util, Ivy }
|
||||
import core.module.descriptor.{ DependencyArtifactDescriptor, DefaultDependencyArtifactDescriptor }
|
||||
import core.module.descriptor.{ DefaultDependencyDescriptor => DDD, DependencyDescriptor }
|
||||
import core.module.id.{ ArtifactId, ModuleId, ModuleRevisionId }
|
||||
import plugins.namespace.Namespace
|
||||
import util.extendable.ExtendableItem
|
||||
|
||||
private[sbt] object MergeDescriptors
|
||||
{
|
||||
def mergeable(a: DependencyDescriptor, b: DependencyDescriptor): Boolean =
|
||||
a.isForce == b.isForce &&
|
||||
a.isChanging == b.isChanging &&
|
||||
a.isTransitive == b.isTransitive &&
|
||||
a.getParentRevisionId == b.getParentRevisionId &&
|
||||
a.getNamespace == b.getNamespace && {
|
||||
val amrid = a.getDependencyRevisionId
|
||||
val bmrid = b.getDependencyRevisionId
|
||||
amrid == bmrid
|
||||
} && {
|
||||
val adyn = a.getDynamicConstraintDependencyRevisionId
|
||||
val bdyn = b.getDynamicConstraintDependencyRevisionId
|
||||
adyn == bdyn
|
||||
}
|
||||
private[sbt] object MergeDescriptors {
|
||||
def mergeable(a: DependencyDescriptor, b: DependencyDescriptor): Boolean =
|
||||
a.isForce == b.isForce &&
|
||||
a.isChanging == b.isChanging &&
|
||||
a.isTransitive == b.isTransitive &&
|
||||
a.getParentRevisionId == b.getParentRevisionId &&
|
||||
a.getNamespace == b.getNamespace && {
|
||||
val amrid = a.getDependencyRevisionId
|
||||
val bmrid = b.getDependencyRevisionId
|
||||
amrid == bmrid
|
||||
} && {
|
||||
val adyn = a.getDynamicConstraintDependencyRevisionId
|
||||
val bdyn = b.getDynamicConstraintDependencyRevisionId
|
||||
adyn == bdyn
|
||||
}
|
||||
|
||||
def apply(a: DependencyDescriptor, b: DependencyDescriptor): DependencyDescriptor =
|
||||
{
|
||||
assert(mergeable(a,b))
|
||||
new MergedDescriptors(a,b)
|
||||
}
|
||||
def apply(a: DependencyDescriptor, b: DependencyDescriptor): DependencyDescriptor =
|
||||
{
|
||||
assert(mergeable(a, b))
|
||||
new MergedDescriptors(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
// combines the artifacts, configurations, includes, and excludes for DependencyDescriptors `a` and `b`
|
||||
// that otherwise have equal IDs
|
||||
private final class MergedDescriptors(a: DependencyDescriptor, b: DependencyDescriptor) extends DependencyDescriptor
|
||||
{
|
||||
def getDependencyId = a.getDependencyId
|
||||
def isForce = a.isForce
|
||||
def isChanging = a.isChanging
|
||||
def isTransitive = a.isTransitive
|
||||
def getNamespace = a.getNamespace
|
||||
def getParentRevisionId = a.getParentRevisionId
|
||||
def getDependencyRevisionId = a.getDependencyRevisionId
|
||||
def getDynamicConstraintDependencyRevisionId = a.getDynamicConstraintDependencyRevisionId
|
||||
private final class MergedDescriptors(a: DependencyDescriptor, b: DependencyDescriptor) extends DependencyDescriptor {
|
||||
def getDependencyId = a.getDependencyId
|
||||
def isForce = a.isForce
|
||||
def isChanging = a.isChanging
|
||||
def isTransitive = a.isTransitive
|
||||
def getNamespace = a.getNamespace
|
||||
def getParentRevisionId = a.getParentRevisionId
|
||||
def getDependencyRevisionId = a.getDependencyRevisionId
|
||||
def getDynamicConstraintDependencyRevisionId = a.getDynamicConstraintDependencyRevisionId
|
||||
|
||||
def getModuleConfigurations = concat(a.getModuleConfigurations, b.getModuleConfigurations)
|
||||
def getModuleConfigurations = concat(a.getModuleConfigurations, b.getModuleConfigurations)
|
||||
|
||||
def getDependencyConfigurations(moduleConfiguration: String, requestedConfiguration: String) =
|
||||
concat(a.getDependencyConfigurations(moduleConfiguration, requestedConfiguration), b.getDependencyConfigurations(moduleConfiguration))
|
||||
def getDependencyConfigurations(moduleConfiguration: String, requestedConfiguration: String) =
|
||||
concat(a.getDependencyConfigurations(moduleConfiguration, requestedConfiguration), b.getDependencyConfigurations(moduleConfiguration))
|
||||
|
||||
def getDependencyConfigurations(moduleConfiguration: String) =
|
||||
concat(a.getDependencyConfigurations(moduleConfiguration), b.getDependencyConfigurations(moduleConfiguration))
|
||||
def getDependencyConfigurations(moduleConfiguration: String) =
|
||||
concat(a.getDependencyConfigurations(moduleConfiguration), b.getDependencyConfigurations(moduleConfiguration))
|
||||
|
||||
def getDependencyConfigurations(moduleConfigurations: Array[String]) =
|
||||
concat(a.getDependencyConfigurations(moduleConfigurations), b.getDependencyConfigurations(moduleConfigurations))
|
||||
def getDependencyConfigurations(moduleConfigurations: Array[String]) =
|
||||
concat(a.getDependencyConfigurations(moduleConfigurations), b.getDependencyConfigurations(moduleConfigurations))
|
||||
|
||||
def getAllDependencyArtifacts = concatArtifacts(a, a.getAllDependencyArtifacts, b, b.getAllDependencyArtifacts)
|
||||
def getAllDependencyArtifacts = concatArtifacts(a, a.getAllDependencyArtifacts, b, b.getAllDependencyArtifacts)
|
||||
|
||||
def getDependencyArtifacts(moduleConfigurations: String) =
|
||||
concatArtifacts(a, a.getDependencyArtifacts(moduleConfigurations), b, b.getDependencyArtifacts(moduleConfigurations))
|
||||
def getDependencyArtifacts(moduleConfigurations: String) =
|
||||
concatArtifacts(a, a.getDependencyArtifacts(moduleConfigurations), b, b.getDependencyArtifacts(moduleConfigurations))
|
||||
|
||||
def getDependencyArtifacts(moduleConfigurations: Array[String]) =
|
||||
concatArtifacts(a, a.getDependencyArtifacts(moduleConfigurations), b, b.getDependencyArtifacts(moduleConfigurations))
|
||||
def getDependencyArtifacts(moduleConfigurations: Array[String]) =
|
||||
concatArtifacts(a, a.getDependencyArtifacts(moduleConfigurations), b, b.getDependencyArtifacts(moduleConfigurations))
|
||||
|
||||
def getAllIncludeRules = concat(a.getAllIncludeRules, b.getAllIncludeRules)
|
||||
def getAllIncludeRules = concat(a.getAllIncludeRules, b.getAllIncludeRules)
|
||||
|
||||
def getIncludeRules(moduleConfigurations: String) =
|
||||
concat(a.getIncludeRules(moduleConfigurations), b.getIncludeRules(moduleConfigurations))
|
||||
def getIncludeRules(moduleConfigurations: String) =
|
||||
concat(a.getIncludeRules(moduleConfigurations), b.getIncludeRules(moduleConfigurations))
|
||||
|
||||
def getIncludeRules(moduleConfigurations: Array[String]) =
|
||||
concat(a.getIncludeRules(moduleConfigurations), b.getIncludeRules(moduleConfigurations))
|
||||
def getIncludeRules(moduleConfigurations: Array[String]) =
|
||||
concat(a.getIncludeRules(moduleConfigurations), b.getIncludeRules(moduleConfigurations))
|
||||
|
||||
private[this] def concatArtifacts(a: DependencyDescriptor, as: Array[DependencyArtifactDescriptor], b: DependencyDescriptor, bs: Array[DependencyArtifactDescriptor]) =
|
||||
{
|
||||
if(as.isEmpty)
|
||||
if(bs.isEmpty) as
|
||||
else defaultArtifact(a) +: explicitConfigurations(b, bs)
|
||||
else if(bs.isEmpty) explicitConfigurations(a, as) :+ defaultArtifact(b)
|
||||
else concat(explicitConfigurations(a, as), explicitConfigurations(b, bs))
|
||||
}
|
||||
private[this] def explicitConfigurations(base: DependencyDescriptor, arts: Array[DependencyArtifactDescriptor]): Array[DependencyArtifactDescriptor] =
|
||||
arts map { art => explicitConfigurations(base, art) }
|
||||
private[this] def explicitConfigurations(base: DependencyDescriptor, art: DependencyArtifactDescriptor): DependencyArtifactDescriptor =
|
||||
{
|
||||
val aConfs = art.getConfigurations
|
||||
if(aConfs == null || aConfs.isEmpty)
|
||||
copyWithConfigurations(art, base.getModuleConfigurations)
|
||||
else
|
||||
art
|
||||
}
|
||||
private[this] def defaultArtifact(a: DependencyDescriptor): DependencyArtifactDescriptor =
|
||||
{
|
||||
val dd = new DefaultDependencyArtifactDescriptor(a, a.getDependencyRevisionId.getName, "jar", "jar", null, null)
|
||||
addConfigurations(dd, a.getModuleConfigurations)
|
||||
dd
|
||||
}
|
||||
private[this] def copyWithConfigurations(dd: DependencyArtifactDescriptor, confs: Seq[String]): DependencyArtifactDescriptor =
|
||||
{
|
||||
val dextra = dd.getQualifiedExtraAttributes
|
||||
val newd = new DefaultDependencyArtifactDescriptor(dd.getDependencyDescriptor, dd.getName, dd.getType, dd.getExt, dd.getUrl, dextra)
|
||||
addConfigurations(newd, confs)
|
||||
newd
|
||||
}
|
||||
private[this] def addConfigurations(dd: DefaultDependencyArtifactDescriptor, confs: Seq[String]): Unit =
|
||||
confs foreach dd.addConfiguration
|
||||
private[this] def concatArtifacts(a: DependencyDescriptor, as: Array[DependencyArtifactDescriptor], b: DependencyDescriptor, bs: Array[DependencyArtifactDescriptor]) =
|
||||
{
|
||||
if (as.isEmpty)
|
||||
if (bs.isEmpty) as
|
||||
else defaultArtifact(a) +: explicitConfigurations(b, bs)
|
||||
else if (bs.isEmpty) explicitConfigurations(a, as) :+ defaultArtifact(b)
|
||||
else concat(explicitConfigurations(a, as), explicitConfigurations(b, bs))
|
||||
}
|
||||
private[this] def explicitConfigurations(base: DependencyDescriptor, arts: Array[DependencyArtifactDescriptor]): Array[DependencyArtifactDescriptor] =
|
||||
arts map { art => explicitConfigurations(base, art) }
|
||||
private[this] def explicitConfigurations(base: DependencyDescriptor, art: DependencyArtifactDescriptor): DependencyArtifactDescriptor =
|
||||
{
|
||||
val aConfs = art.getConfigurations
|
||||
if (aConfs == null || aConfs.isEmpty)
|
||||
copyWithConfigurations(art, base.getModuleConfigurations)
|
||||
else
|
||||
art
|
||||
}
|
||||
private[this] def defaultArtifact(a: DependencyDescriptor): DependencyArtifactDescriptor =
|
||||
{
|
||||
val dd = new DefaultDependencyArtifactDescriptor(a, a.getDependencyRevisionId.getName, "jar", "jar", null, null)
|
||||
addConfigurations(dd, a.getModuleConfigurations)
|
||||
dd
|
||||
}
|
||||
private[this] def copyWithConfigurations(dd: DependencyArtifactDescriptor, confs: Seq[String]): DependencyArtifactDescriptor =
|
||||
{
|
||||
val dextra = dd.getQualifiedExtraAttributes
|
||||
val newd = new DefaultDependencyArtifactDescriptor(dd.getDependencyDescriptor, dd.getName, dd.getType, dd.getExt, dd.getUrl, dextra)
|
||||
addConfigurations(newd, confs)
|
||||
newd
|
||||
}
|
||||
private[this] def addConfigurations(dd: DefaultDependencyArtifactDescriptor, confs: Seq[String]): Unit =
|
||||
confs foreach dd.addConfiguration
|
||||
|
||||
private[this] def concat[T: ClassManifest](a: Array[T], b: Array[T]): Array[T] = (a ++ b).distinct.toArray
|
||||
private[this] def concat[T: ClassManifest](a: Array[T], b: Array[T]): Array[T] = (a ++ b).distinct.toArray
|
||||
|
||||
def getAllExcludeRules = concat(a.getAllExcludeRules, b.getAllExcludeRules)
|
||||
def getAllExcludeRules = concat(a.getAllExcludeRules, b.getAllExcludeRules)
|
||||
|
||||
def getExcludeRules(moduleConfigurations: String) = concat(a.getExcludeRules(moduleConfigurations), b.getExcludeRules(moduleConfigurations))
|
||||
def getExcludeRules(moduleConfigurations: String) = concat(a.getExcludeRules(moduleConfigurations), b.getExcludeRules(moduleConfigurations))
|
||||
|
||||
def getExcludeRules(moduleConfigurations: Array[String]) = concat(a.getExcludeRules(moduleConfigurations), b.getExcludeRules(moduleConfigurations))
|
||||
def getExcludeRules(moduleConfigurations: Array[String]) = concat(a.getExcludeRules(moduleConfigurations), b.getExcludeRules(moduleConfigurations))
|
||||
|
||||
def doesExclude(moduleConfigurations: Array[String], artifactId: ArtifactId) = a.doesExclude(moduleConfigurations, artifactId) || b.doesExclude(moduleConfigurations, artifactId)
|
||||
def doesExclude(moduleConfigurations: Array[String], artifactId: ArtifactId) = a.doesExclude(moduleConfigurations, artifactId) || b.doesExclude(moduleConfigurations, artifactId)
|
||||
|
||||
def canExclude = a.canExclude || b.canExclude
|
||||
def canExclude = a.canExclude || b.canExclude
|
||||
|
||||
def asSystem = this
|
||||
def asSystem = this
|
||||
|
||||
def clone(revision: ModuleRevisionId) = new MergedDescriptors(a.clone(revision), b.clone(revision))
|
||||
def clone(revision: ModuleRevisionId) = new MergedDescriptors(a.clone(revision), b.clone(revision))
|
||||
|
||||
def getAttribute(name: String): String = a.getAttribute(name)
|
||||
def getAttributes = a.getAttributes
|
||||
def getExtraAttribute(name: String) = a.getExtraAttribute(name)
|
||||
def getExtraAttributes = a.getExtraAttributes
|
||||
def getQualifiedExtraAttributes = a.getQualifiedExtraAttributes
|
||||
def getSourceModule = a.getSourceModule
|
||||
def getAttribute(name: String): String = a.getAttribute(name)
|
||||
def getAttributes = a.getAttributes
|
||||
def getExtraAttribute(name: String) = a.getExtraAttribute(name)
|
||||
def getExtraAttributes = a.getExtraAttributes
|
||||
def getQualifiedExtraAttributes = a.getQualifiedExtraAttributes
|
||||
def getSourceModule = a.getSourceModule
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue