mirror of https://github.com/sbt/sbt.git
Apply formatting
This commit is contained in:
parent
712c83f859
commit
d42ea869d0
62
build.sbt
62
build.sbt
|
|
@ -28,17 +28,19 @@ def commonSettings: Seq[Setting[_]] = Seq(
|
|||
}
|
||||
)
|
||||
|
||||
lazy val lmRoot = (project in file(".")).
|
||||
aggregate(lm).
|
||||
disablePlugins(com.typesafe.sbt.SbtScalariform).
|
||||
settings(
|
||||
inThisBuild(Seq(
|
||||
homepage := Some(url("https://github.com/sbt/librarymanagement")),
|
||||
description := "Library management module for sbt",
|
||||
scmInfo := Some(ScmInfo(url("https://github.com/sbt/librarymanagement"), "git@github.com:sbt/librarymanagement.git")),
|
||||
bintrayPackage := "librarymanagement",
|
||||
git.baseVersion := baseVersion
|
||||
)),
|
||||
lazy val lmRoot = (project in file("."))
|
||||
.aggregate(lm)
|
||||
.disablePlugins(com.typesafe.sbt.SbtScalariform)
|
||||
.settings(
|
||||
inThisBuild(
|
||||
Seq(
|
||||
homepage := Some(url("https://github.com/sbt/librarymanagement")),
|
||||
description := "Library management module for sbt",
|
||||
scmInfo := Some(ScmInfo(url("https://github.com/sbt/librarymanagement"),
|
||||
"git@github.com:sbt/librarymanagement.git")),
|
||||
bintrayPackage := "librarymanagement",
|
||||
git.baseVersion := baseVersion
|
||||
)),
|
||||
commonSettings,
|
||||
name := "LM Root",
|
||||
publish := {},
|
||||
|
|
@ -48,15 +50,24 @@ lazy val lmRoot = (project in file(".")).
|
|||
customCommands
|
||||
)
|
||||
|
||||
lazy val lm = (project in file("librarymanagement")).
|
||||
disablePlugins(com.typesafe.sbt.SbtScalariform).
|
||||
settings(
|
||||
lazy val lm = (project in file("librarymanagement"))
|
||||
.disablePlugins(com.typesafe.sbt.SbtScalariform)
|
||||
.settings(
|
||||
commonSettings,
|
||||
name := "librarymanagement",
|
||||
libraryDependencies ++= Seq(
|
||||
ivy, jsch, scalaReflect.value, launcherInterface, sjsonnewScalaJson % Optional),
|
||||
libraryDependencies ++= Seq(ivy,
|
||||
jsch,
|
||||
scalaReflect.value,
|
||||
launcherInterface,
|
||||
sjsonnewScalaJson % Optional),
|
||||
libraryDependencies ++= scalaXml.value,
|
||||
resourceGenerators in Compile += Def.task(Util.generateVersionFile(version.value, resourceManaged.value, streams.value, (compile in Compile).value)).taskValue,
|
||||
resourceGenerators in Compile += Def
|
||||
.task(
|
||||
Util.generateVersionFile(version.value,
|
||||
resourceManaged.value,
|
||||
streams.value,
|
||||
(compile in Compile).value))
|
||||
.taskValue,
|
||||
mimaBinaryIssueFilters ++= Seq(),
|
||||
contrabandFormatsForType in generateContrabands in Compile := DatatypeConfig.getFormats,
|
||||
// WORKAROUND sbt/sbt#2205 include managed sources in packageSrc
|
||||
|
|
@ -66,16 +77,21 @@ lazy val lm = (project in file("librarymanagement")).
|
|||
val base = baseDirectory.value
|
||||
(((srcs --- sdirs --- base) pair (relativeTo(sdirs) | relativeTo(base) | flat)) toSeq)
|
||||
}
|
||||
).
|
||||
configure(addSbtIO, addSbtUtilLogging, addSbtUtilTesting, addSbtUtilCollection, addSbtUtilCompletion, addSbtUtilCache).
|
||||
enablePlugins(ContrabandPlugin, JsonCodecPlugin)
|
||||
)
|
||||
.configure(addSbtIO,
|
||||
addSbtUtilLogging,
|
||||
addSbtUtilTesting,
|
||||
addSbtUtilCollection,
|
||||
addSbtUtilCompletion,
|
||||
addSbtUtilCache)
|
||||
.enablePlugins(ContrabandPlugin, JsonCodecPlugin)
|
||||
|
||||
def customCommands: Seq[Setting[_]] = Seq(
|
||||
commands += Command.command("release") { state =>
|
||||
// "clean" ::
|
||||
"so compile" ::
|
||||
"so publishSigned" ::
|
||||
"reload" ::
|
||||
state
|
||||
"so publishSigned" ::
|
||||
"reload" ::
|
||||
state
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -37,68 +37,83 @@ object ReplaceMavenConfigurationMappings {
|
|||
|
||||
// NOTE - This code is copied from org.apache.ivy.plugins.parser.m2.PomModuleDescriptorBuilder
|
||||
// except with altered default configurations...
|
||||
REPLACEMENT_MAPPINGS.put("compile", new PomModuleDescriptorBuilder.ConfMapper {
|
||||
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
|
||||
if (isOptional) {
|
||||
dd.addDependencyConfiguration("optional", "compile(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("optional", "master(compile)")
|
||||
} else {
|
||||
dd.addDependencyConfiguration("compile", "compile(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("compile", "master(compile)")
|
||||
dd.addDependencyConfiguration("runtime", "runtime(*)")
|
||||
REPLACEMENT_MAPPINGS.put(
|
||||
"compile",
|
||||
new PomModuleDescriptorBuilder.ConfMapper {
|
||||
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
|
||||
if (isOptional) {
|
||||
dd.addDependencyConfiguration("optional", "compile(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("optional", "master(compile)")
|
||||
} else {
|
||||
dd.addDependencyConfiguration("compile", "compile(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("compile", "master(compile)")
|
||||
dd.addDependencyConfiguration("runtime", "runtime(*)")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
REPLACEMENT_MAPPINGS.put("provided", new PomModuleDescriptorBuilder.ConfMapper {
|
||||
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
|
||||
if (isOptional) {
|
||||
dd.addDependencyConfiguration("optional", "compile(*)")
|
||||
dd.addDependencyConfiguration("optional", "provided(*)")
|
||||
dd.addDependencyConfiguration("optional", "runtime(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("optional", "master(compile)")
|
||||
} else {
|
||||
dd.addDependencyConfiguration("provided", "compile(*)")
|
||||
dd.addDependencyConfiguration("provided", "provided(*)")
|
||||
dd.addDependencyConfiguration("provided", "runtime(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("provided", "master(compile)")
|
||||
)
|
||||
REPLACEMENT_MAPPINGS.put(
|
||||
"provided",
|
||||
new PomModuleDescriptorBuilder.ConfMapper {
|
||||
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
|
||||
if (isOptional) {
|
||||
dd.addDependencyConfiguration("optional", "compile(*)")
|
||||
dd.addDependencyConfiguration("optional", "provided(*)")
|
||||
dd.addDependencyConfiguration("optional", "runtime(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("optional", "master(compile)")
|
||||
} else {
|
||||
dd.addDependencyConfiguration("provided", "compile(*)")
|
||||
dd.addDependencyConfiguration("provided", "provided(*)")
|
||||
dd.addDependencyConfiguration("provided", "runtime(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("provided", "master(compile)")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
REPLACEMENT_MAPPINGS.put("runtime", new PomModuleDescriptorBuilder.ConfMapper {
|
||||
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
|
||||
if (isOptional) {
|
||||
dd.addDependencyConfiguration("optional", "compile(*)")
|
||||
dd.addDependencyConfiguration("optional", "provided(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("optional", "master(compile)")
|
||||
} else {
|
||||
dd.addDependencyConfiguration("runtime", "compile(*)")
|
||||
dd.addDependencyConfiguration("runtime", "runtime(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("runtime", "master(compile)")
|
||||
REPLACEMENT_MAPPINGS.put(
|
||||
"runtime",
|
||||
new PomModuleDescriptorBuilder.ConfMapper {
|
||||
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
|
||||
if (isOptional) {
|
||||
dd.addDependencyConfiguration("optional", "compile(*)")
|
||||
dd.addDependencyConfiguration("optional", "provided(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("optional", "master(compile)")
|
||||
} else {
|
||||
dd.addDependencyConfiguration("runtime", "compile(*)")
|
||||
dd.addDependencyConfiguration("runtime", "runtime(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("runtime", "master(compile)")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
REPLACEMENT_MAPPINGS.put("test", new PomModuleDescriptorBuilder.ConfMapper {
|
||||
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
|
||||
dd.addDependencyConfiguration("test", "runtime(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("test", "master(compile)")
|
||||
REPLACEMENT_MAPPINGS.put(
|
||||
"test",
|
||||
new PomModuleDescriptorBuilder.ConfMapper {
|
||||
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
|
||||
dd.addDependencyConfiguration("test", "runtime(*)")
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("test", "master(compile)")
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
REPLACEMENT_MAPPINGS.put("system", new PomModuleDescriptorBuilder.ConfMapper {
|
||||
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("system", "master(compile)")
|
||||
REPLACEMENT_MAPPINGS.put(
|
||||
"system",
|
||||
new PomModuleDescriptorBuilder.ConfMapper {
|
||||
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
|
||||
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
|
||||
dd.addDependencyConfiguration("system", "master(compile)")
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
REPLACEMENT_MAPPINGS
|
||||
}
|
||||
|
|
@ -106,13 +121,17 @@ object ReplaceMavenConfigurationMappings {
|
|||
def init(): Unit = {
|
||||
// Here we mutate a static final field, because we have to AND because it's evil.
|
||||
try {
|
||||
val map = PomModuleDescriptorBuilder.MAVEN2_CONF_MAPPING.asInstanceOf[java.util.Map[String, PomModuleDescriptorBuilder.ConfMapper]]
|
||||
val map = PomModuleDescriptorBuilder.MAVEN2_CONF_MAPPING
|
||||
.asInstanceOf[java.util.Map[String, PomModuleDescriptorBuilder.ConfMapper]]
|
||||
map.clear()
|
||||
map.putAll(REPLACEMENT_MAVEN_MAPPINGS)
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
// TODO - Log that Ivy may not be configured correctly and you could have maven/ivy issues.
|
||||
throw new RuntimeException("FAILURE to install Ivy maven hooks. Your ivy-maven interaction may suffer resolution errors", e)
|
||||
throw new RuntimeException(
|
||||
"FAILURE to install Ivy maven hooks. Your ivy-maven interaction may suffer resolution errors",
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@ import sbt.util.{ Level, Logger }
|
|||
import Configurations._
|
||||
|
||||
final class CompatibilityWarningOptions private[sbt] (
|
||||
val configurations: Seq[Configuration],
|
||||
val level: Level.Value
|
||||
val configurations: Seq[Configuration],
|
||||
val level: Level.Value
|
||||
)
|
||||
|
||||
object CompatibilityWarningOptions {
|
||||
def default: CompatibilityWarningOptions =
|
||||
apply(configurations = List(Compile, Runtime), level = Level.Warn)
|
||||
def apply(
|
||||
configurations: List[Configuration],
|
||||
level: Level.Value
|
||||
configurations: List[Configuration],
|
||||
level: Level.Value
|
||||
): CompatibilityWarningOptions =
|
||||
new CompatibilityWarningOptions(
|
||||
configurations = configurations,
|
||||
|
|
@ -24,12 +24,21 @@ object CompatibilityWarningOptions {
|
|||
}
|
||||
|
||||
private[sbt] object CompatibilityWarning {
|
||||
def run(config: CompatibilityWarningOptions, module: IvySbt#Module, mavenStyle: Boolean, log: Logger): Unit = {
|
||||
def run(
|
||||
config: CompatibilityWarningOptions,
|
||||
module: IvySbt#Module,
|
||||
mavenStyle: Boolean,
|
||||
log: Logger
|
||||
): Unit = {
|
||||
if (mavenStyle) {
|
||||
processIntransitive(config, module, log)
|
||||
}
|
||||
}
|
||||
def processIntransitive(config: CompatibilityWarningOptions, module: IvySbt#Module, log: Logger): Unit = {
|
||||
def processIntransitive(
|
||||
config: CompatibilityWarningOptions,
|
||||
module: IvySbt#Module,
|
||||
log: Logger
|
||||
): Unit = {
|
||||
val monitoredConfigsStr: Set[String] = (config.configurations map { _.name }).toSet
|
||||
val directDependencies: Seq[ModuleID] = module.moduleSettings match {
|
||||
case x: InlineConfiguration => x.dependencies
|
||||
|
|
|
|||
|
|
@ -18,54 +18,73 @@ import sbt.librarymanagement._
|
|||
* 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) {
|
||||
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) }
|
||||
/** 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 })
|
||||
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(", "))
|
||||
case xs =>
|
||||
invalid("Expected single file for component '" + id + "', found: " + xs.mkString(", "))
|
||||
}
|
||||
private def invalid(msg: String) = throw new InvalidComponent(msg)
|
||||
|
||||
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)
|
||||
|
||||
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) }
|
||||
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)
|
||||
|
|
@ -73,16 +92,17 @@ class InvalidComponent(msg: String, cause: Throwable) extends RuntimeException(m
|
|||
sealed trait IfMissing
|
||||
object IfMissing {
|
||||
object Fail extends IfMissing
|
||||
final class Define(val cache: Boolean, define: => Unit) extends IfMissing { def apply() = define }
|
||||
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 (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
|
||||
|
|
|
|||
|
|
@ -9,8 +9,20 @@ import org.apache.ivy.core.module.descriptor.DependencyDescriptor
|
|||
import org.apache.ivy.core.resolve.ResolveData
|
||||
import org.apache.ivy.core.settings.IvySettings
|
||||
import org.apache.ivy.plugins.repository.{ RepositoryCopyProgressListener, TransferEvent }
|
||||
import org.apache.ivy.plugins.resolver.{ BasicResolver, DependencyResolver, IBiblioResolver, RepositoryResolver }
|
||||
import org.apache.ivy.plugins.resolver.{ AbstractPatternsBasedResolver, AbstractSshBasedResolver, FileSystemResolver, SFTPResolver, SshResolver, URLResolver }
|
||||
import org.apache.ivy.plugins.resolver.{
|
||||
BasicResolver,
|
||||
DependencyResolver,
|
||||
IBiblioResolver,
|
||||
RepositoryResolver
|
||||
}
|
||||
import org.apache.ivy.plugins.resolver.{
|
||||
AbstractPatternsBasedResolver,
|
||||
AbstractSshBasedResolver,
|
||||
FileSystemResolver,
|
||||
SFTPResolver,
|
||||
SshResolver,
|
||||
URLResolver
|
||||
}
|
||||
import org.apache.ivy.plugins.repository.url.{ URLRepository => URLRepo }
|
||||
import org.apache.ivy.plugins.repository.file.{ FileRepository => FileRepo, FileResource }
|
||||
import java.io.{ IOException, File }
|
||||
|
|
@ -41,25 +53,35 @@ private[sbt] object ConvertResolver {
|
|||
thing.setAccessible(true)
|
||||
Some(thing)
|
||||
} catch {
|
||||
case (_: java.lang.NoSuchFieldException) |
|
||||
(_: java.lang.SecurityException) |
|
||||
(_: java.lang.NoSuchMethodException) => None
|
||||
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]
|
||||
))
|
||||
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]
|
||||
))
|
||||
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
|
||||
|
|
@ -76,7 +98,12 @@ private[sbt] object ConvertResolver {
|
|||
case Some(field) => field.get(this).asInstanceOf[String]
|
||||
case None => null
|
||||
}
|
||||
override protected def put(artifact: IArtifact, src: File, dest: String, overwrite: Boolean): Unit = {
|
||||
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()
|
||||
|
|
@ -89,8 +116,9 @@ private[sbt] object ConvertResolver {
|
|||
// 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?
|
||||
case Some(method) =>
|
||||
method.invoke(this, artifact, src, dest, true: java.lang.Boolean, checksum)
|
||||
case None => // TODO - issue warning?
|
||||
}
|
||||
}
|
||||
if (signerName != null) {
|
||||
|
|
@ -108,77 +136,84 @@ private[sbt] object ConvertResolver {
|
|||
apply(r, settings, UpdateOptions(), log)
|
||||
|
||||
/** Converts the given sbt resolver into an Ivy resolver. */
|
||||
def apply(r: Resolver, settings: IvySettings, updateOptions: UpdateOptions, log: Logger): DependencyResolver =
|
||||
def apply(
|
||||
r: Resolver,
|
||||
settings: IvySettings,
|
||||
updateOptions: UpdateOptions,
|
||||
log: Logger
|
||||
): DependencyResolver =
|
||||
(updateOptions.resolverConverter orElse defaultConvert)((r, settings, log))
|
||||
|
||||
/** The default implementation of converter. */
|
||||
lazy val defaultConvert: ResolverConverter = {
|
||||
case (r, settings, log) =>
|
||||
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(): Unit = {
|
||||
// done this way for access to protected methods.
|
||||
setArtifactPatterns(pattern)
|
||||
setIvyPatterns(pattern)
|
||||
}
|
||||
case repo: MavenRepository => {
|
||||
val pattern = Collections.singletonList(
|
||||
Resolver.resolvePattern(repo.root, Resolver.mavenStyleBasePattern)
|
||||
)
|
||||
final class PluginCapableResolver
|
||||
extends IBiblioResolver
|
||||
with ChecksumFriendlyURLResolver
|
||||
with DescriptorRequired {
|
||||
def setPatterns(): Unit = {
|
||||
// done this way for access to protected methods.
|
||||
setArtifactPatterns(pattern)
|
||||
setIvyPatterns(pattern)
|
||||
}
|
||||
val resolver = new PluginCapableResolver
|
||||
if (repo.localIfFile) 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 repo: SshRepository =>
|
||||
{
|
||||
val resolver = new SshResolver with DescriptorRequired
|
||||
initializeSSHResolver(resolver, repo, settings)
|
||||
repo.publishPermissions.foreach(perm => resolver.setPublishPermissions(perm))
|
||||
resolver
|
||||
val resolver = new PluginCapableResolver
|
||||
if (repo.localIfFile) 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 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())
|
||||
}
|
||||
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
|
||||
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)
|
||||
}
|
||||
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 =
|
||||
|
|
@ -189,35 +224,49 @@ private[sbt] object ConvertResolver {
|
|||
resolver.setM2compatible(true)
|
||||
resolver.setRoot(root)
|
||||
}
|
||||
private def initializeSSHResolver(resolver: AbstractSshBasedResolver, repo: SshBasedRepository, settings: IvySettings): Unit = {
|
||||
private def initializeSSHResolver(
|
||||
resolver: AbstractSshBasedResolver,
|
||||
repo: SshBasedRepository,
|
||||
settings: IvySettings
|
||||
): Unit = {
|
||||
resolver.setName(repo.name)
|
||||
resolver.setPassfile(null)
|
||||
initializePatterns(resolver, repo.patterns, settings)
|
||||
initializeConnection(resolver, repo.connection)
|
||||
}
|
||||
private def initializeConnection(resolver: AbstractSshBasedResolver, connection: SshConnection): Unit = {
|
||||
private def initializeConnection(
|
||||
resolver: AbstractSshBasedResolver,
|
||||
connection: SshConnection
|
||||
): Unit = {
|
||||
import resolver._
|
||||
import connection._
|
||||
hostname.foreach(setHost)
|
||||
port.foreach(setPort)
|
||||
authentication foreach
|
||||
{
|
||||
case pa: PasswordAuthentication =>
|
||||
setUser(pa.user)
|
||||
pa.password.foreach(setUserPassword)
|
||||
case kfa: KeyFileAuthentication =>
|
||||
setKeyFile(kfa.keyfile)
|
||||
kfa.password.foreach(setKeyFilePassword)
|
||||
setUser(kfa.user)
|
||||
}
|
||||
authentication foreach {
|
||||
case pa: PasswordAuthentication =>
|
||||
setUser(pa.user)
|
||||
pa.password.foreach(setUserPassword)
|
||||
case kfa: KeyFileAuthentication =>
|
||||
setKeyFile(kfa.keyfile)
|
||||
kfa.password.foreach(setKeyFilePassword)
|
||||
setUser(kfa.user)
|
||||
}
|
||||
}
|
||||
private def initializePatterns(resolver: AbstractPatternsBasedResolver, patterns: Patterns, settings: IvySettings): Unit = {
|
||||
private def initializePatterns(
|
||||
resolver: AbstractPatternsBasedResolver,
|
||||
patterns: Patterns,
|
||||
settings: IvySettings
|
||||
): Unit = {
|
||||
resolver.setM2compatible(patterns.isMavenCompatible)
|
||||
resolver.setDescriptor(if (patterns.descriptorOptional) BasicResolver.DESCRIPTOR_OPTIONAL else BasicResolver.DESCRIPTOR_REQUIRED)
|
||||
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.
|
||||
|
|
@ -270,7 +319,9 @@ private[sbt] object ConvertResolver {
|
|||
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.")
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,62 @@
|
|||
package sbt.internal.librarymanagement
|
||||
|
||||
import org.apache.ivy.core.module.id.ModuleRevisionId
|
||||
import org.apache.ivy.core.module.descriptor.{ DefaultArtifact, DefaultExtendsDescriptor, DefaultModuleDescriptor, ModuleDescriptor }
|
||||
import org.apache.ivy.core.module.descriptor.{
|
||||
DefaultArtifact,
|
||||
DefaultExtendsDescriptor,
|
||||
DefaultModuleDescriptor,
|
||||
ModuleDescriptor
|
||||
}
|
||||
import org.apache.ivy.core.module.descriptor.{ DefaultDependencyDescriptor, DependencyDescriptor }
|
||||
import org.apache.ivy.plugins.parser.{ ModuleDescriptorParser, ModuleDescriptorParserRegistry, ParserSettings }
|
||||
import org.apache.ivy.plugins.parser.m2.{ ReplaceMavenConfigurationMappings, PomModuleDescriptorBuilder, PomModuleDescriptorParser }
|
||||
import org.apache.ivy.plugins.parser.{
|
||||
ModuleDescriptorParser,
|
||||
ModuleDescriptorParserRegistry,
|
||||
ParserSettings
|
||||
}
|
||||
import org.apache.ivy.plugins.parser.m2.{
|
||||
ReplaceMavenConfigurationMappings,
|
||||
PomModuleDescriptorBuilder,
|
||||
PomModuleDescriptorParser
|
||||
}
|
||||
import org.apache.ivy.plugins.repository.Resource
|
||||
import org.apache.ivy.plugins.namespace.NamespaceTransformer
|
||||
import org.apache.ivy.util.extendable.ExtendableItem
|
||||
|
||||
import java.io.{ File, InputStream }
|
||||
import java.net.URL
|
||||
import sbt.internal.librarymanagement.mavenint.{ PomExtraDependencyAttributes, SbtPomExtraProperties }
|
||||
import sbt.internal.librarymanagement.mavenint.{
|
||||
PomExtraDependencyAttributes,
|
||||
SbtPomExtraProperties
|
||||
}
|
||||
import sbt.io.Hash
|
||||
|
||||
// @deprecated("We now use an Aether-based pom parser.", "0.13.8")
|
||||
final class CustomPomParser(delegate: ModuleDescriptorParser, transform: (ModuleDescriptorParser, ModuleDescriptor) => ModuleDescriptor) extends ModuleDescriptorParser {
|
||||
override def parseDescriptor(ivySettings: ParserSettings, descriptorURL: URL, validate: Boolean) =
|
||||
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) =
|
||||
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 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)
|
||||
override def getMetadataArtifact(mrid: ModuleRevisionId, res: Resource) =
|
||||
delegate.getMetadataArtifact(mrid, res)
|
||||
}
|
||||
// @deprecated("We now use an Aether-based pom parser.", "0.13.8")
|
||||
object CustomPomParser {
|
||||
|
|
@ -41,7 +71,8 @@ object CustomPomParser {
|
|||
val SbtVersionKey = PomExtraDependencyAttributes.SbtVersionKey
|
||||
val ScalaVersionKey = PomExtraDependencyAttributes.ScalaVersionKey
|
||||
val ExtraAttributesKey = PomExtraDependencyAttributes.ExtraAttributesKey
|
||||
private[this] val unqualifiedKeys = Set(SbtVersionKey, ScalaVersionKey, ExtraAttributesKey, ApiURLKey)
|
||||
private[this] val unqualifiedKeys =
|
||||
Set(SbtVersionKey, ScalaVersionKey, ExtraAttributesKey, ApiURLKey)
|
||||
|
||||
// packagings that should be jars, but that Ivy doesn't handle as jars
|
||||
// TODO - move this elsewhere.
|
||||
|
|
@ -51,7 +82,8 @@ object CustomPomParser {
|
|||
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] def makeCoords(mrid: ModuleRevisionId): String = s"${mrid.getOrganisation}:${mrid.getName}:${mrid.getRevision}"
|
||||
private[this] def makeCoords(mrid: ModuleRevisionId): String =
|
||||
s"${mrid.getOrganisation}:${mrid.getName}:${mrid.getRevision}"
|
||||
|
||||
// We now include the ModuleID in a hash, to ensure that parent-pom transformations don't corrupt child poms.
|
||||
private[this] def MakeTransformHash(md: ModuleDescriptor): String = {
|
||||
|
|
@ -60,7 +92,8 @@ object CustomPomParser {
|
|||
hash((unqualifiedKeys ++ JarPackagings ++ Set(coords)).toSeq.sorted)
|
||||
}
|
||||
|
||||
private[this] def hash(ss: Seq[String]): String = Hash.toHex(Hash(ss.flatMap(_ getBytes "UTF-8").toArray))
|
||||
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)
|
||||
|
|
@ -69,74 +102,93 @@ object CustomPomParser {
|
|||
if (transformedByThisVersion(md)) md
|
||||
else defaultTransformImpl(parser, md)
|
||||
|
||||
private[this] def transformedByThisVersion(md: ModuleDescriptor): Boolean =
|
||||
{
|
||||
val oldTransformedHashKey = "sbtTransformHash"
|
||||
val extraInfo = md.getExtraInfo
|
||||
val MyHash = MakeTransformHash(md)
|
||||
// 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(MyHash) => true
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
private[this] def transformedByThisVersion(md: ModuleDescriptor): Boolean = {
|
||||
val oldTransformedHashKey = "sbtTransformHash"
|
||||
val extraInfo = md.getExtraInfo
|
||||
val MyHash = MakeTransformHash(md)
|
||||
// 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(MyHash) => 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)
|
||||
|
||||
val unqualify = toUnqualify(filtered)
|
||||
val unqualify = toUnqualify(filtered)
|
||||
|
||||
// Here we always add extra attributes. There's a scenario where parent-pom information corrupts child-poms with "e:" namespaced xml elements
|
||||
// and we have to force the every generated xml file to have the appropriate xml namespace
|
||||
addExtra(unqualify, extraDepAttributes, parser, md)
|
||||
}
|
||||
// Here we always add extra attributes. There's a scenario where parent-pom information corrupts child-poms with "e:" namespaced xml elements
|
||||
// and we have to force the every generated xml file to have the appropriate xml namespace
|
||||
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 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 shouldBeUnqualified(m: Map[String, String]): Map[String, String] = m.filterKeys(unqualifiedKeys)
|
||||
private[this] def shouldBeUnqualified(m: Map[String, String]): Map[String, String] =
|
||||
m.filterKeys(unqualifiedKeys)
|
||||
|
||||
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 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 getDependencyExtra(m: Map[String, String]): Map[ModuleRevisionId, Map[String, String]] =
|
||||
private[this] def getDependencyExtra(
|
||||
m: Map[String, String]
|
||||
): Map[ModuleRevisionId, Map[String, String]] =
|
||||
PomExtraDependencyAttributes.getDependencyExtra(m)
|
||||
|
||||
def qualifiedExtra(item: ExtendableItem): Map[String, String] = PomExtraDependencyAttributes.qualifiedExtra(item)
|
||||
def qualifiedExtra(item: ExtendableItem): Map[String, String] =
|
||||
PomExtraDependencyAttributes.qualifiedExtra(item)
|
||||
def filterCustomExtra(item: ExtendableItem, include: Boolean): Map[String, String] =
|
||||
(qualifiedExtra(item) filterKeys { k => qualifiedIsExtra(k) == include })
|
||||
(qualifiedExtra(item) filterKeys { k =>
|
||||
qualifiedIsExtra(k) == include
|
||||
})
|
||||
|
||||
def writeDependencyExtra(s: Seq[DependencyDescriptor]): Seq[String] =
|
||||
PomExtraDependencyAttributes.writeDependencyExtra(s)
|
||||
|
||||
// parses the sequence of dependencies with extra attribute information, with one dependency per line
|
||||
def readDependencyExtra(s: String): Seq[ModuleRevisionId] = PomExtraDependencyAttributes.readDependencyExtra(s)
|
||||
def readDependencyExtra(s: String): Seq[ModuleRevisionId] =
|
||||
PomExtraDependencyAttributes.readDependencyExtra(s)
|
||||
|
||||
def qualifiedIsExtra(k: String): Boolean = PomExtraDependencyAttributes.qualifiedIsExtra(k)
|
||||
|
||||
|
|
@ -145,20 +197,33 @@ object CustomPomParser {
|
|||
// with the extra attributes from the <properties> section
|
||||
def simplify(id: ModuleRevisionId): ModuleRevisionId = PomExtraDependencyAttributes.simplify(id)
|
||||
|
||||
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 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 transform(
|
||||
dep: DependencyDescriptor,
|
||||
f: ModuleRevisionId => ModuleRevisionId
|
||||
): DependencyDescriptor =
|
||||
DefaultDependencyDescriptor.transformInstance(
|
||||
dep,
|
||||
namespaceTransformer(dep.getDependencyRevisionId, f),
|
||||
false
|
||||
)
|
||||
|
||||
private[this] def namespaceTransformer(txId: ModuleRevisionId, f: ModuleRevisionId => ModuleRevisionId): NamespaceTransformer =
|
||||
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 transform(revId: ModuleRevisionId): ModuleRevisionId =
|
||||
if (revId == txId) f(revId) else revId
|
||||
def isIdentity = false
|
||||
}
|
||||
|
||||
|
|
@ -167,53 +232,80 @@ object CustomPomParser {
|
|||
VersionRange.stripMavenVersionRange(dd.getDependencyRevisionId.getRevision) match {
|
||||
case Some(newVersion) =>
|
||||
val id = dd.getDependencyRevisionId
|
||||
val newId = ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, newVersion, id.getExtraAttributes)
|
||||
val newId = ModuleRevisionId.newInstance(
|
||||
id.getOrganisation,
|
||||
id.getName,
|
||||
id.getBranch,
|
||||
newVersion,
|
||||
id.getExtraAttributes
|
||||
)
|
||||
transform(dd, _ => newId)
|
||||
case None => dd
|
||||
}
|
||||
private[sbt] lazy val versionRangeFlag = sys.props.get("sbt.modversionrange") map { _.toLowerCase == "true" } getOrElse true
|
||||
private[sbt] lazy val versionRangeFlag = sys.props.get("sbt.modversionrange") map {
|
||||
_.toLowerCase == "true"
|
||||
} getOrElse true
|
||||
|
||||
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)
|
||||
def addExtra(
|
||||
properties: Map[String, String],
|
||||
dependencyExtra: Map[ModuleRevisionId, Map[String, String]],
|
||||
parser: ModuleDescriptorParser,
|
||||
md: ModuleDescriptor
|
||||
): ModuleDescriptor = {
|
||||
val dmd = new DefaultModuleDescriptor(parser, md.getResource)
|
||||
|
||||
val mrid = addExtra(properties, md.getModuleRevisionId)
|
||||
val resolvedMrid = addExtra(properties, md.getResolvedModuleRevisionId)
|
||||
dmd.setModuleRevisionId(mrid)
|
||||
dmd.setResolvedModuleRevisionId(resolvedMrid)
|
||||
val mrid = addExtra(properties, md.getModuleRevisionId)
|
||||
val resolvedMrid = addExtra(properties, md.getResolvedModuleRevisionId)
|
||||
dmd.setModuleRevisionId(mrid)
|
||||
dmd.setResolvedModuleRevisionId(resolvedMrid)
|
||||
|
||||
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())
|
||||
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())
|
||||
|
||||
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, MakeTransformHash(md)) // 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 (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, MakeTransformHash(md)) // 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)
|
||||
|
||||
val withExtra = md.getDependencies map { dd => addExtra(dd, dependencyExtra) }
|
||||
val withVersionRangeMod: Seq[DependencyDescriptor] =
|
||||
if (versionRangeFlag) withExtra map { stripVersionRange }
|
||||
else withExtra
|
||||
val unique = IvySbt.mergeDuplicateDefinitions(withVersionRangeMod)
|
||||
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
|
||||
val withExtra = md.getDependencies map { dd =>
|
||||
addExtra(dd, dependencyExtra)
|
||||
}
|
||||
val withVersionRangeMod: Seq[DependencyDescriptor] =
|
||||
if (versionRangeFlag) withExtra map { stripVersionRange } else withExtra
|
||||
val unique = IvySbt.mergeDuplicateDefinitions(withVersionRangeMod)
|
||||
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,7 +6,10 @@ package sbt.internal.librarymanagement
|
|||
import java.io.ByteArrayInputStream
|
||||
import java.net.URL
|
||||
|
||||
import org.apache.ivy.core.module.descriptor.{ DefaultDependencyDescriptor, DefaultModuleDescriptor }
|
||||
import org.apache.ivy.core.module.descriptor.{
|
||||
DefaultDependencyDescriptor,
|
||||
DefaultModuleDescriptor
|
||||
}
|
||||
import org.apache.ivy.core.settings.IvySettings
|
||||
import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser
|
||||
import org.apache.ivy.plugins.repository.Resource
|
||||
|
|
@ -15,21 +18,22 @@ import org.apache.ivy.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)
|
||||
}
|
||||
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]): Unit = setInput(new ByteArrayInputStream(bytes))
|
||||
|
||||
/** Overridden because the super implementation overwrites the module descriptor.*/
|
||||
override def setResource(res: Resource): Unit = ()
|
||||
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 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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,14 @@ import java.net.URL
|
|||
|
||||
import org.apache.ivy.core.cache.ArtifactOrigin
|
||||
import org.apache.ivy.core.cache.{ DefaultRepositoryCacheManager, RepositoryCacheManager }
|
||||
import org.apache.ivy.core.module.descriptor.{ Artifact => IvyArtifact, DefaultArtifact, DefaultDependencyArtifactDescriptor, DefaultModuleDescriptor, DependencyArtifactDescriptor, DependencyDescriptor }
|
||||
import org.apache.ivy.core.module.descriptor.{
|
||||
Artifact => IvyArtifact,
|
||||
DefaultArtifact,
|
||||
DefaultDependencyArtifactDescriptor,
|
||||
DefaultModuleDescriptor,
|
||||
DependencyArtifactDescriptor,
|
||||
DependencyDescriptor
|
||||
}
|
||||
import org.apache.ivy.core.module.id.ModuleRevisionId
|
||||
import org.apache.ivy.core.report.ArtifactDownloadReport
|
||||
import org.apache.ivy.core.report.{ DownloadReport, DownloadStatus }
|
||||
|
|
@ -22,7 +29,8 @@ import FakeResolver._
|
|||
/**
|
||||
* A fake `DependencyResolver` that statically serves predefined artifacts.
|
||||
*/
|
||||
private[sbt] class FakeResolver(private var name: String, cacheDir: File, modules: ModulesMap) extends DependencyResolver {
|
||||
private[sbt] class FakeResolver(private var name: String, cacheDir: File, modules: ModulesMap)
|
||||
extends DependencyResolver {
|
||||
|
||||
private object Artifact {
|
||||
def unapply(art: IvyArtifact): Some[(String, String, String)] = {
|
||||
|
|
@ -55,7 +63,10 @@ private[sbt] class FakeResolver(private var name: String, cacheDir: File, module
|
|||
override def commitPublishTransaction(): Unit =
|
||||
throw new UnsupportedOperationException("This resolver doesn't support publishing.")
|
||||
|
||||
override def download(artifact: ArtifactOrigin, options: DownloadOptions): ArtifactDownloadReport = {
|
||||
override def download(
|
||||
artifact: ArtifactOrigin,
|
||||
options: DownloadOptions
|
||||
): ArtifactDownloadReport = {
|
||||
|
||||
val report = new ArtifactDownloadReport(artifact.getArtifact)
|
||||
val path = new URL(artifact.getLocation).toURI.getPath
|
||||
|
|
@ -99,12 +110,12 @@ private[sbt] class FakeResolver(private var name: String, cacheDir: File, module
|
|||
val mrid = dd.getDependencyRevisionId()
|
||||
|
||||
val artifact = modules get ((organisation, name, revision)) map { arts =>
|
||||
|
||||
val artifacts: Array[DependencyArtifactDescriptor] = arts.toArray map (_ artifactOf dd)
|
||||
val moduleDescriptor = DefaultModuleDescriptor.newDefaultInstance(mrid, artifacts)
|
||||
val defaultArtifact = arts.headOption match {
|
||||
case Some(FakeArtifact(name, tpe, ext, _)) => new DefaultArtifact(mrid, new java.util.Date, name, tpe, ext)
|
||||
case None => null
|
||||
case Some(FakeArtifact(name, tpe, ext, _)) =>
|
||||
new DefaultArtifact(mrid, new java.util.Date, name, tpe, ext)
|
||||
case None => null
|
||||
}
|
||||
val metadataReport = new MetadataArtifactDownloadReport(defaultArtifact)
|
||||
metadataReport.setDownloadStatus(DownloadStatus.SUCCESSFUL)
|
||||
|
|
@ -147,10 +158,16 @@ private[sbt] class FakeResolver(private var name: String, cacheDir: File, module
|
|||
new RevisionEntry(module, v)
|
||||
}.toArray
|
||||
|
||||
override def listTokenValues(tokens: Array[String], criteria: java.util.Map[_, _]): Array[java.util.Map[_, _]] =
|
||||
override def listTokenValues(
|
||||
tokens: Array[String],
|
||||
criteria: java.util.Map[_, _]
|
||||
): Array[java.util.Map[_, _]] =
|
||||
Array.empty
|
||||
|
||||
override def listTokenValues(token: String, otherTokenValues: java.util.Map[_, _]): Array[String] =
|
||||
override def listTokenValues(
|
||||
token: String,
|
||||
otherTokenValues: java.util.Map[_, _]
|
||||
): Array[String] =
|
||||
Array.empty
|
||||
|
||||
override def locate(art: IvyArtifact): ArtifactOrigin = {
|
||||
|
|
@ -158,7 +175,8 @@ private[sbt] class FakeResolver(private var name: String, cacheDir: File, module
|
|||
val artifact =
|
||||
for {
|
||||
artifacts <- modules get ((moduleOrganisation, moduleName, moduleRevision))
|
||||
artifact <- artifacts find (a => a.name == art.getName && a.tpe == art.getType && a.ext == art.getExt)
|
||||
artifact <- artifacts find (a =>
|
||||
a.name == art.getName && a.tpe == art.getType && a.ext == art.getExt)
|
||||
} yield new ArtifactOrigin(art, /* isLocal = */ true, artifact.file.toURI.toURL.toString)
|
||||
|
||||
artifact.orNull
|
||||
|
|
@ -183,6 +201,13 @@ private[sbt] object FakeResolver {
|
|||
|
||||
final case class FakeArtifact(name: String, tpe: String, ext: String, file: File) {
|
||||
def artifactOf(dd: DependencyDescriptor): DependencyArtifactDescriptor =
|
||||
new DefaultDependencyArtifactDescriptor(dd, name, tpe, ext, file.toURI.toURL, new java.util.HashMap)
|
||||
new DefaultDependencyArtifactDescriptor(
|
||||
dd,
|
||||
name,
|
||||
tpe,
|
||||
ext,
|
||||
file.toURI.toURL,
|
||||
new java.util.HashMap
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -12,7 +12,12 @@ import org.apache.ivy.Ivy
|
|||
import org.apache.ivy.core.{ IvyPatternHelper, LogOptions }
|
||||
import org.apache.ivy.core.deliver.DeliverOptions
|
||||
import org.apache.ivy.core.install.InstallOptions
|
||||
import org.apache.ivy.core.module.descriptor.{ Artifact => IArtifact, MDArtifact, ModuleDescriptor, DefaultModuleDescriptor }
|
||||
import org.apache.ivy.core.module.descriptor.{
|
||||
Artifact => IArtifact,
|
||||
MDArtifact,
|
||||
ModuleDescriptor,
|
||||
DefaultModuleDescriptor
|
||||
}
|
||||
import org.apache.ivy.core.report.ResolveReport
|
||||
import org.apache.ivy.core.resolve.ResolveOptions
|
||||
import org.apache.ivy.plugins.resolver.{ BasicResolver, DependencyResolver }
|
||||
|
|
@ -21,20 +26,59 @@ import sbt.util.{ Logger, ShowLines }
|
|||
import sbt.internal.util.{ SourcePosition, LinePosition, RangePosition, LineRange }
|
||||
import sbt.librarymanagement._, syntax._
|
||||
|
||||
final class DeliverConfiguration(val deliverIvyPattern: String, val status: String, val configurations: Option[Vector[Configuration]], val logging: UpdateLogging)
|
||||
final class PublishConfiguration(val ivyFile: Option[File], val resolverName: String, val artifacts: Map[Artifact, File], val checksums: Vector[String], val logging: UpdateLogging,
|
||||
val overwrite: Boolean) {
|
||||
def this(ivyFile: Option[File], resolverName: String, artifacts: Map[Artifact, File], checksums: Vector[String], logging: UpdateLogging) =
|
||||
final class DeliverConfiguration(
|
||||
val deliverIvyPattern: String,
|
||||
val status: String,
|
||||
val configurations: Option[Vector[Configuration]],
|
||||
val logging: UpdateLogging
|
||||
)
|
||||
final class PublishConfiguration(
|
||||
val ivyFile: Option[File],
|
||||
val resolverName: String,
|
||||
val artifacts: Map[Artifact, File],
|
||||
val checksums: Vector[String],
|
||||
val logging: UpdateLogging,
|
||||
val overwrite: Boolean
|
||||
) {
|
||||
def this(
|
||||
ivyFile: Option[File],
|
||||
resolverName: String,
|
||||
artifacts: Map[Artifact, File],
|
||||
checksums: Vector[String],
|
||||
logging: UpdateLogging
|
||||
) =
|
||||
this(ivyFile, resolverName, artifacts, checksums, logging, false)
|
||||
}
|
||||
|
||||
final case class MakePomConfiguration(file: File, moduleInfo: ModuleInfo, configurations: Option[Vector[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))
|
||||
final case class MakePomConfiguration(
|
||||
file: File,
|
||||
moduleInfo: ModuleInfo,
|
||||
configurations: Option[Vector[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)
|
||||
)
|
||||
|
||||
/** @param exclude is a map from ModuleID to classifiers that were previously tried and failed, so should now be excluded */
|
||||
final case class GetClassifiersConfiguration(module: GetClassifiersModule, exclude: Map[ModuleID, Set[String]], configuration: UpdateConfiguration, ivyScala: Option[IvyScala], sourceArtifactTypes: Set[String], docArtifactTypes: Set[String])
|
||||
final case class GetClassifiersModule(id: ModuleID, modules: Vector[ModuleID], configurations: Vector[Configuration], classifiers: Vector[String])
|
||||
final case class GetClassifiersConfiguration(
|
||||
module: GetClassifiersModule,
|
||||
exclude: Map[ModuleID, Set[String]],
|
||||
configuration: UpdateConfiguration,
|
||||
ivyScala: Option[IvyScala],
|
||||
sourceArtifactTypes: Set[String],
|
||||
docArtifactTypes: Set[String]
|
||||
)
|
||||
final case class GetClassifiersModule(
|
||||
id: ModuleID,
|
||||
modules: Vector[ModuleID],
|
||||
configurations: Vector[Configuration],
|
||||
classifiers: Vector[String]
|
||||
)
|
||||
|
||||
final class UnresolvedWarningConfiguration private[sbt] (
|
||||
val modulePositions: Map[ModuleID, SourcePosition]
|
||||
val modulePositions: Map[ModuleID, SourcePosition]
|
||||
)
|
||||
object UnresolvedWarningConfiguration {
|
||||
def apply(): UnresolvedWarningConfiguration = apply(Map())
|
||||
|
|
@ -43,6 +87,7 @@ object UnresolvedWarningConfiguration {
|
|||
}
|
||||
|
||||
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): Unit = {
|
||||
module.withModule(log) { (ivy, md, default) =>
|
||||
|
|
@ -73,27 +118,48 @@ object IvyActions {
|
|||
|
||||
/** Creates a Maven pom from the given Ivy configuration*/
|
||||
def makePom(module: IvySbt#Module, configuration: MakePomConfiguration, log: Logger): Unit = {
|
||||
import configuration.{ allRepositories, moduleInfo, configurations, extra, file, filterRepositories, process, includeTypes }
|
||||
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)
|
||||
(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 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))
|
||||
ivy.getSettings.resolveFile(
|
||||
IvyPatternHelper.substitute(pattern, md.getResolvedModuleRevisionId)
|
||||
)
|
||||
|
||||
def publish(module: IvySbt#Module, configuration: PublishConfiguration, log: Logger): Unit = {
|
||||
import configuration._
|
||||
|
|
@ -101,40 +167,59 @@ object IvyActions {
|
|||
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 ivyArtifact = ivyFile map { file =>
|
||||
(MDArtifact.newIvyArtifact(md), file)
|
||||
}
|
||||
val cross = crossVersionMap(module.moduleSettings)
|
||||
val as = mapArtifacts(md, cross, artifacts) ++ ivyArtifact.toList
|
||||
withChecksums(resolver, checksums) { publish(md, as, resolver, overwrite = overwrite) }
|
||||
}
|
||||
}
|
||||
private[this] def withChecksums[T](resolver: DependencyResolver, checksums: Vector[String])(act: => T): T =
|
||||
private[this] def withChecksums[T](resolver: DependencyResolver, checksums: Vector[String])(
|
||||
act: => T
|
||||
): T =
|
||||
resolver match { case br: BasicResolver => withChecksums(br, checksums)(act); case _ => act }
|
||||
private[this] def withChecksums[T](resolver: BasicResolver, checksums: Vector[String])(act: => T): T =
|
||||
{
|
||||
val previous = resolver.getChecksumAlgorithms
|
||||
resolver.setChecksums(checksums mkString ",")
|
||||
try { act }
|
||||
finally { resolver.setChecksums(previous mkString ",") }
|
||||
}
|
||||
private[this] def withChecksums[T](resolver: BasicResolver, checksums: Vector[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 _ => None
|
||||
}
|
||||
def mapArtifacts(module: ModuleDescriptor, cross: Option[String => String], artifacts: Map[Artifact, File]): Vector[(IArtifact, File)] =
|
||||
{
|
||||
val rawa = artifacts.keys.toVector
|
||||
val seqa = CrossVersion.substituteCross(rawa, cross)
|
||||
val zipped = rawa zip IvySbt.mapArtifacts(module, seqa)
|
||||
zipped map { case (a, ivyA) => (ivyA, artifacts(a)) }
|
||||
}
|
||||
def mapArtifacts(
|
||||
module: ModuleDescriptor,
|
||||
cross: Option[String => String],
|
||||
artifacts: Map[Artifact, File]
|
||||
): Vector[(IArtifact, File)] = {
|
||||
val rawa = artifacts.keys.toVector
|
||||
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.
|
||||
*/
|
||||
@deprecated("This is no longer public.", "0.13.6")
|
||||
def update(module: IvySbt#Module, configuration: UpdateConfiguration, log: Logger): UpdateReport =
|
||||
updateEither(module, configuration, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, log) match {
|
||||
def update(
|
||||
module: IvySbt#Module,
|
||||
configuration: UpdateConfiguration,
|
||||
log: Logger
|
||||
): UpdateReport =
|
||||
updateEither(
|
||||
module,
|
||||
configuration,
|
||||
UnresolvedWarningConfiguration(),
|
||||
LogicalClock.unknown,
|
||||
None,
|
||||
log
|
||||
) match {
|
||||
case Right(r) => r
|
||||
case Left(w) =>
|
||||
throw w.resolveException
|
||||
|
|
@ -144,10 +229,17 @@ object IvyActions {
|
|||
* Resolves and retrieves dependencies. 'ivyConfig' is used to produce an Ivy file and configuration.
|
||||
* 'updateConfig' configures the actual resolution and retrieval process.
|
||||
*/
|
||||
private[sbt] def updateEither(module: IvySbt#Module, configuration: UpdateConfiguration,
|
||||
uwconfig: UnresolvedWarningConfiguration, logicalClock: LogicalClock, depDir: Option[File], log: Logger): Either[UnresolvedWarning, UpdateReport] =
|
||||
private[sbt] def updateEither(
|
||||
module: IvySbt#Module,
|
||||
configuration: UpdateConfiguration,
|
||||
uwconfig: UnresolvedWarningConfiguration,
|
||||
logicalClock: LogicalClock,
|
||||
depDir: Option[File],
|
||||
log: Logger
|
||||
): Either[UnresolvedWarning, UpdateReport] =
|
||||
module.withModule(log) {
|
||||
case (ivy, md, default) if module.owner.configuration.updateOptions.cachedResolution && depDir.isDefined =>
|
||||
case (ivy, md, default)
|
||||
if module.owner.configuration.updateOptions.cachedResolution && depDir.isDefined =>
|
||||
ivy.getResolveEngine match {
|
||||
case x: CachedResolutionResolveEngine =>
|
||||
val iw = IvySbt.inconsistentDuplicateWarning(md)
|
||||
|
|
@ -157,7 +249,16 @@ object IvyActions {
|
|||
resolveOptions.setResolveId(resolveId)
|
||||
resolveOptions.setArtifactFilter(configuration.artifactFilter)
|
||||
resolveOptions.setLog(ivyLogLevel(configuration.logging))
|
||||
x.customResolve(md, configuration.missingOk, logicalClock, resolveOptions, depDir getOrElse { sys.error("dependency base directory is not specified") }, log) match {
|
||||
x.customResolve(
|
||||
md,
|
||||
configuration.missingOk,
|
||||
logicalClock,
|
||||
resolveOptions,
|
||||
depDir getOrElse {
|
||||
sys.error("dependency base directory is not specified")
|
||||
},
|
||||
log
|
||||
) match {
|
||||
case Left(x) =>
|
||||
Left(UnresolvedWarning(x, uwconfig))
|
||||
case Right(uReport) =>
|
||||
|
|
@ -170,12 +271,14 @@ object IvyActions {
|
|||
case (ivy, md, default) =>
|
||||
val iw = IvySbt.inconsistentDuplicateWarning(md)
|
||||
iw foreach { log.warn(_) }
|
||||
val (report, err) = resolve(configuration.logging)(ivy, md, default, configuration.artifactFilter)
|
||||
val (report, err) =
|
||||
resolve(configuration.logging)(ivy, md, default, configuration.artifactFilter)
|
||||
err match {
|
||||
case Some(x) if !configuration.missingOk =>
|
||||
Left(UnresolvedWarning(x, uwconfig))
|
||||
case _ =>
|
||||
val cachedDescriptor = ivy.getSettings.getResolutionCacheManager.getResolvedIvyFileInCache(md.getModuleRevisionId)
|
||||
val cachedDescriptor = ivy.getSettings.getResolutionCacheManager
|
||||
.getResolvedIvyFileInCache(md.getModuleRevisionId)
|
||||
val uReport = IvyRetrieve.updateReport(report, cachedDescriptor)
|
||||
configuration.retrieve match {
|
||||
case Some(rConf) => Right(retrieve(log, ivy, uReport, rConf))
|
||||
|
|
@ -185,11 +288,14 @@ object IvyActions {
|
|||
}
|
||||
@deprecated("No longer used.", "0.13.6")
|
||||
def processUnresolved(err: ResolveException, log: Logger): Unit = ()
|
||||
def groupedConflicts[T](moduleFilter: ModuleFilter, grouping: ModuleID => T)(report: UpdateReport): Map[T, Set[String]] =
|
||||
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)))
|
||||
val conflicted =
|
||||
confReport.allModules.filter(mod => evictedSet((mod.organization, mod.name)))
|
||||
grouped(grouping)(conflicted ++ evicted)
|
||||
}.toMap
|
||||
|
||||
|
|
@ -197,27 +303,59 @@ object IvyActions {
|
|||
mods groupBy (grouping) mapValues (_.map(_.revision).toSet)
|
||||
|
||||
@deprecated("This is no longer public.", "0.13.6")
|
||||
def transitiveScratch(ivySbt: IvySbt, label: String, config: GetClassifiersConfiguration, log: Logger): UpdateReport =
|
||||
transitiveScratch(ivySbt, label, config, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, log)
|
||||
def transitiveScratch(
|
||||
ivySbt: IvySbt,
|
||||
label: String,
|
||||
config: GetClassifiersConfiguration,
|
||||
log: Logger
|
||||
): UpdateReport =
|
||||
transitiveScratch(
|
||||
ivySbt,
|
||||
label,
|
||||
config,
|
||||
UnresolvedWarningConfiguration(),
|
||||
LogicalClock.unknown,
|
||||
None,
|
||||
log
|
||||
)
|
||||
|
||||
private[sbt] def transitiveScratch(ivySbt: IvySbt, label: String, config: GetClassifiersConfiguration,
|
||||
uwconfig: UnresolvedWarningConfiguration, logicalClock: LogicalClock, depDir: Option[File], log: Logger): UpdateReport =
|
||||
{
|
||||
import config.{ configuration => c, ivyScala, module => mod }
|
||||
import mod.{ id, modules => deps }
|
||||
val base = restrictedCopy(id, true).withName(id.name + "$" + label)
|
||||
val module = new ivySbt.Module(InlineConfiguration(false, ivyScala, base, ModuleInfo(base.name), deps))
|
||||
val report = updateEither(module, c, uwconfig, logicalClock, depDir, log) match {
|
||||
case Right(r) => r
|
||||
case Left(w) =>
|
||||
throw w.resolveException
|
||||
}
|
||||
val newConfig = config.copy(module = mod.copy(modules = report.allModules))
|
||||
updateClassifiers(ivySbt, newConfig, uwconfig, logicalClock, depDir, Vector(), log)
|
||||
private[sbt] def transitiveScratch(
|
||||
ivySbt: IvySbt,
|
||||
label: String,
|
||||
config: GetClassifiersConfiguration,
|
||||
uwconfig: UnresolvedWarningConfiguration,
|
||||
logicalClock: LogicalClock,
|
||||
depDir: Option[File],
|
||||
log: Logger
|
||||
): UpdateReport = {
|
||||
import config.{ configuration => c, ivyScala, module => mod }
|
||||
import mod.{ id, modules => deps }
|
||||
val base = restrictedCopy(id, true).withName(id.name + "$" + label)
|
||||
val module =
|
||||
new ivySbt.Module(InlineConfiguration(false, ivyScala, base, ModuleInfo(base.name), deps))
|
||||
val report = updateEither(module, c, uwconfig, logicalClock, depDir, log) match {
|
||||
case Right(r) => r
|
||||
case Left(w) =>
|
||||
throw w.resolveException
|
||||
}
|
||||
val newConfig = config.copy(module = mod.copy(modules = report.allModules))
|
||||
updateClassifiers(ivySbt, newConfig, uwconfig, logicalClock, depDir, Vector(), log)
|
||||
}
|
||||
@deprecated("This is no longer public.", "0.13.6")
|
||||
def updateClassifiers(ivySbt: IvySbt, config: GetClassifiersConfiguration, log: Logger): UpdateReport =
|
||||
updateClassifiers(ivySbt, config, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, Vector(), log)
|
||||
def updateClassifiers(
|
||||
ivySbt: IvySbt,
|
||||
config: GetClassifiersConfiguration,
|
||||
log: Logger
|
||||
): UpdateReport =
|
||||
updateClassifiers(
|
||||
ivySbt,
|
||||
config,
|
||||
UnresolvedWarningConfiguration(),
|
||||
LogicalClock.unknown,
|
||||
None,
|
||||
Vector(),
|
||||
log
|
||||
)
|
||||
|
||||
/**
|
||||
* Creates explicit artifacts for each classifier in `config.module`, and then attempts to resolve them directly. This
|
||||
|
|
@ -228,64 +366,83 @@ object IvyActions {
|
|||
* @param config important to set `config.configuration.types` to only allow artifact types that can correspond to
|
||||
* "classified" artifacts (sources and javadocs).
|
||||
*/
|
||||
private[sbt] def updateClassifiers(ivySbt: IvySbt, config: GetClassifiersConfiguration,
|
||||
uwconfig: UnresolvedWarningConfiguration, logicalClock: LogicalClock, depDir: Option[File],
|
||||
artifacts: Vector[(String, ModuleID, Artifact, File)],
|
||||
log: Logger): UpdateReport =
|
||||
{
|
||||
import config.{ configuration => c, module => mod, _ }
|
||||
import mod.{ configurations => confs, _ }
|
||||
assert(classifiers.nonEmpty, "classifiers cannot be empty")
|
||||
assert(c.artifactFilter.types.nonEmpty, "UpdateConfiguration must filter on some types")
|
||||
val baseModules = modules map { m => restrictedCopy(m, true) }
|
||||
// Adding list of explicit artifacts here.
|
||||
val deps = baseModules.distinct flatMap classifiedArtifacts(classifiers, exclude, artifacts)
|
||||
val base = restrictedCopy(id, true).withName(id.name + classifiers.mkString("$", "_", ""))
|
||||
val module = new ivySbt.Module(InlineConfiguration(false, ivyScala, base, ModuleInfo(base.name), deps).withConfigurations(confs))
|
||||
// c.copy ensures c.types is preserved too
|
||||
val upConf = c.withMissingOk(true)
|
||||
updateEither(module, upConf, uwconfig, logicalClock, depDir, log) match {
|
||||
case Right(r) =>
|
||||
// The artifacts that came from Ivy don't have their classifier set, let's set it according to
|
||||
// FIXME: this is only done because IDE plugins depend on `classifier` to determine type. They
|
||||
val typeClassifierMap: Map[String, String] =
|
||||
((sourceArtifactTypes.toIterable map (_ -> Artifact.SourceClassifier))
|
||||
:: (docArtifactTypes.toIterable map (_ -> Artifact.DocClassifier)) :: Nil).flatten.toMap
|
||||
r.substitute { (conf, mid, artFileSeq) =>
|
||||
artFileSeq map {
|
||||
case (art, f) =>
|
||||
// Deduce the classifier from the type if no classifier is present already
|
||||
art.withClassifier(art.classifier orElse typeClassifierMap.get(art.`type`)) -> f
|
||||
}
|
||||
}
|
||||
case Left(w) =>
|
||||
throw w.resolveException
|
||||
}
|
||||
private[sbt] def updateClassifiers(
|
||||
ivySbt: IvySbt,
|
||||
config: GetClassifiersConfiguration,
|
||||
uwconfig: UnresolvedWarningConfiguration,
|
||||
logicalClock: LogicalClock,
|
||||
depDir: Option[File],
|
||||
artifacts: Vector[(String, ModuleID, Artifact, File)],
|
||||
log: Logger
|
||||
): UpdateReport = {
|
||||
import config.{ configuration => c, module => mod, _ }
|
||||
import mod.{ configurations => confs, _ }
|
||||
assert(classifiers.nonEmpty, "classifiers cannot be empty")
|
||||
assert(c.artifactFilter.types.nonEmpty, "UpdateConfiguration must filter on some types")
|
||||
val baseModules = modules map { m =>
|
||||
restrictedCopy(m, true)
|
||||
}
|
||||
// Adding list of explicit artifacts here.
|
||||
val deps = baseModules.distinct flatMap classifiedArtifacts(classifiers, exclude, artifacts)
|
||||
val base = restrictedCopy(id, true).withName(id.name + classifiers.mkString("$", "_", ""))
|
||||
val module = new ivySbt.Module(
|
||||
InlineConfiguration(false, ivyScala, base, ModuleInfo(base.name), deps)
|
||||
.withConfigurations(confs)
|
||||
)
|
||||
// c.copy ensures c.types is preserved too
|
||||
val upConf = c.withMissingOk(true)
|
||||
updateEither(module, upConf, uwconfig, logicalClock, depDir, log) match {
|
||||
case Right(r) =>
|
||||
// The artifacts that came from Ivy don't have their classifier set, let's set it according to
|
||||
// FIXME: this is only done because IDE plugins depend on `classifier` to determine type. They
|
||||
val typeClassifierMap: Map[String, String] =
|
||||
((sourceArtifactTypes.toIterable map (_ -> Artifact.SourceClassifier))
|
||||
:: (docArtifactTypes.toIterable map (_ -> Artifact.DocClassifier)) :: Nil).flatten.toMap
|
||||
r.substitute { (conf, mid, artFileSeq) =>
|
||||
artFileSeq map {
|
||||
case (art, f) =>
|
||||
// Deduce the classifier from the type if no classifier is present already
|
||||
art.withClassifier(art.classifier orElse typeClassifierMap.get(art.`type`)) -> f
|
||||
}
|
||||
}
|
||||
case Left(w) =>
|
||||
throw w.resolveException
|
||||
}
|
||||
}
|
||||
// This version adds explicit artifact
|
||||
private[sbt] def classifiedArtifacts(
|
||||
classifiers: Vector[String],
|
||||
exclude: Map[ModuleID, Set[String]],
|
||||
artifacts: Vector[(String, ModuleID, Artifact, File)]
|
||||
classifiers: Vector[String],
|
||||
exclude: Map[ModuleID, Set[String]],
|
||||
artifacts: Vector[(String, ModuleID, Artifact, File)]
|
||||
)(m: ModuleID): Option[ModuleID] = {
|
||||
def sameModule(m1: ModuleID, m2: ModuleID): Boolean = m1.organization == m2.organization && m1.name == m2.name && m1.revision == m2.revision
|
||||
def explicitArtifacts =
|
||||
{
|
||||
val arts = (artifacts collect { case (_, x, art, _) if sameModule(m, x) && art.classifier.isDefined => art }).distinct
|
||||
if (arts.isEmpty) None
|
||||
else Some(intransitiveModuleWithExplicitArts(m, arts))
|
||||
}
|
||||
def sameModule(m1: ModuleID, m2: ModuleID): Boolean =
|
||||
m1.organization == m2.organization && m1.name == m2.name && m1.revision == m2.revision
|
||||
def explicitArtifacts = {
|
||||
val arts = (artifacts collect {
|
||||
case (_, x, art, _) if sameModule(m, x) && art.classifier.isDefined => art
|
||||
}).distinct
|
||||
if (arts.isEmpty) None
|
||||
else Some(intransitiveModuleWithExplicitArts(m, arts))
|
||||
}
|
||||
def hardcodedArtifacts = classifiedArtifacts(classifiers, exclude)(m)
|
||||
explicitArtifacts orElse hardcodedArtifacts
|
||||
}
|
||||
private def classifiedArtifacts(classifiers: Vector[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(intransitiveModuleWithExplicitArts(module = m, arts = classifiedArtifacts(m.name, included)))
|
||||
}
|
||||
private def classifiedArtifacts(
|
||||
classifiers: Vector[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(
|
||||
intransitiveModuleWithExplicitArts(
|
||||
module = m,
|
||||
arts = classifiedArtifacts(m.name, included)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly set an "include all" rule (the default) because otherwise, if we declare ANY explicitArtifacts,
|
||||
|
|
@ -300,93 +457,170 @@ object IvyActions {
|
|||
* }}}
|
||||
* `usage.getDependencyIncludesSet` returns null if there are no (explicit) include rules.
|
||||
*/
|
||||
private def intransitiveModuleWithExplicitArts(module: ModuleID, arts: Vector[Artifact]): ModuleID =
|
||||
module.withIsTransitive(false).withExplicitArtifacts(arts).withInclusions(Vector(InclExclRule.everything))
|
||||
private def intransitiveModuleWithExplicitArts(
|
||||
module: ModuleID,
|
||||
arts: Vector[Artifact]
|
||||
): ModuleID =
|
||||
module
|
||||
.withIsTransitive(false)
|
||||
.withExplicitArtifacts(arts)
|
||||
.withInclusions(Vector(InclExclRule.everything))
|
||||
|
||||
def addExcluded(report: UpdateReport, classifiers: Vector[String], exclude: Map[ModuleID, Set[String]]): UpdateReport =
|
||||
report.addMissing { id => classifiedArtifacts(id.name, classifiers filter getExcluded(id, exclude)) }
|
||||
def addExcluded(
|
||||
report: UpdateReport,
|
||||
classifiers: Vector[String],
|
||||
exclude: Map[ModuleID, Set[String]]
|
||||
): UpdateReport =
|
||||
report.addMissing { id =>
|
||||
classifiedArtifacts(id.name, classifiers filter getExcluded(id, exclude))
|
||||
}
|
||||
def classifiedArtifacts(name: String, classifiers: Vector[String]): Vector[Artifact] =
|
||||
classifiers map { c => Artifact.classified(name, c) }
|
||||
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) }
|
||||
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).withCrossVersion(m.crossVersion).withExtraAttributes(m.extraAttributes).withConfigurations(if (confs) m.configurations else None)
|
||||
ModuleID(m.organization, m.name, m.revision)
|
||||
.withCrossVersion(m.crossVersion)
|
||||
.withExtraAttributes(m.extraAttributes)
|
||||
.withConfigurations(if (confs) m.configurations else None)
|
||||
.branch(m.branchName)
|
||||
|
||||
private[this] def resolve(logging: UpdateLogging)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String, filter: ArtifactTypeFilter): (ResolveReport, Option[ResolveException]) =
|
||||
{
|
||||
val resolveOptions = new ResolveOptions
|
||||
val resolveId = ResolveOptions.getDefaultResolveId(module)
|
||||
resolveOptions.setResolveId(resolveId)
|
||||
resolveOptions.setArtifactFilter(filter)
|
||||
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 failedPaths = Map(resolveReport.getUnresolvedDependencies map { node =>
|
||||
val m = IvyRetrieve.toModuleID(node.getId)
|
||||
val path = IvyRetrieve.findPath(node, module.getModuleRevisionId) map { x =>
|
||||
IvyRetrieve.toModuleID(x.getId)
|
||||
}
|
||||
m -> path
|
||||
}: _*)
|
||||
val failed = failedPaths.keys.toSeq
|
||||
Some(new ResolveException(messages, failed, failedPaths))
|
||||
} else None
|
||||
(resolveReport, err)
|
||||
private[this] def resolve(logging: UpdateLogging)(
|
||||
ivy: Ivy,
|
||||
module: DefaultModuleDescriptor,
|
||||
defaultConf: String,
|
||||
filter: ArtifactTypeFilter
|
||||
): (ResolveReport, Option[ResolveException]) = {
|
||||
val resolveOptions = new ResolveOptions
|
||||
val resolveId = ResolveOptions.getDefaultResolveId(module)
|
||||
resolveOptions.setResolveId(resolveId)
|
||||
resolveOptions.setArtifactFilter(filter)
|
||||
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 failedPaths = Map(resolveReport.getUnresolvedDependencies map { node =>
|
||||
val m = IvyRetrieve.toModuleID(node.getId)
|
||||
val path = IvyRetrieve.findPath(node, module.getModuleRevisionId) map { x =>
|
||||
IvyRetrieve.toModuleID(x.getId)
|
||||
}
|
||||
m -> path
|
||||
}: _*)
|
||||
val failed = failedPaths.keys.toSeq
|
||||
Some(new ResolveException(messages, failed, failedPaths))
|
||||
} else None
|
||||
(resolveReport, err)
|
||||
}
|
||||
private def retrieve(
|
||||
log: Logger,
|
||||
ivy: Ivy,
|
||||
report: UpdateReport,
|
||||
config: RetrieveConfiguration
|
||||
): UpdateReport =
|
||||
retrieve(
|
||||
log,
|
||||
ivy,
|
||||
report,
|
||||
config.retrieveDirectory,
|
||||
config.outputPattern,
|
||||
config.sync,
|
||||
config.configurationsToRetrieve
|
||||
)
|
||||
|
||||
private def retrieve(
|
||||
log: Logger,
|
||||
ivy: Ivy,
|
||||
report: UpdateReport,
|
||||
base: File,
|
||||
pattern: String,
|
||||
sync: Boolean,
|
||||
configurationsToRetrieve: Option[Set[Configuration]]
|
||||
): UpdateReport = {
|
||||
val configurationNames = configurationsToRetrieve match {
|
||||
case None => None
|
||||
case Some(configs) => Some(configs.map(_.name))
|
||||
}
|
||||
private def retrieve(log: Logger, ivy: Ivy, report: UpdateReport, config: RetrieveConfiguration): UpdateReport =
|
||||
retrieve(log, ivy, report, config.retrieveDirectory, config.outputPattern, config.sync, config.configurationsToRetrieve)
|
||||
|
||||
private def retrieve(log: Logger, ivy: Ivy, report: UpdateReport, base: File, pattern: String, sync: Boolean, configurationsToRetrieve: Option[Set[Configuration]]): UpdateReport =
|
||||
{
|
||||
val configurationNames = configurationsToRetrieve match {
|
||||
case None => None
|
||||
case Some(configs) => Some(configs.map(_.name))
|
||||
val existingFiles = PathFinder(base).allPaths.get filterNot { _.isDirectory }
|
||||
val toCopy = new collection.mutable.HashSet[(File, File)]
|
||||
val retReport = report retrieve { (conf, mid, art, cached) =>
|
||||
configurationNames match {
|
||||
case None => performRetrieve(conf, mid, art, base, pattern, cached, toCopy)
|
||||
case Some(names) if names(conf) =>
|
||||
performRetrieve(conf, mid, art, base, pattern, cached, toCopy)
|
||||
case _ => cached
|
||||
}
|
||||
val existingFiles = PathFinder(base).allPaths.get filterNot { _.isDirectory }
|
||||
val toCopy = new collection.mutable.HashSet[(File, File)]
|
||||
val retReport = report retrieve { (conf, mid, art, cached) =>
|
||||
configurationNames match {
|
||||
case None => performRetrieve(conf, mid, art, base, pattern, cached, toCopy)
|
||||
case Some(names) if names(conf) => performRetrieve(conf, mid, art, base, pattern, cached, toCopy)
|
||||
case _ => cached
|
||||
}
|
||||
}
|
||||
IO.copy(toCopy)
|
||||
val resolvedFiles = toCopy.map(_._2)
|
||||
if (sync) {
|
||||
val filesToDelete = existingFiles.filterNot(resolvedFiles.contains)
|
||||
filesToDelete foreach { f =>
|
||||
log.info(s"Deleting old dependency: ${f.getAbsolutePath}")
|
||||
f.delete()
|
||||
}
|
||||
IO.copy(toCopy)
|
||||
val resolvedFiles = toCopy.map(_._2)
|
||||
if (sync) {
|
||||
val filesToDelete = existingFiles.filterNot(resolvedFiles.contains)
|
||||
filesToDelete foreach { f =>
|
||||
log.info(s"Deleting old dependency: ${f.getAbsolutePath}")
|
||||
f.delete()
|
||||
}
|
||||
}
|
||||
|
||||
retReport
|
||||
}
|
||||
|
||||
private def performRetrieve(conf: String, mid: ModuleID, art: Artifact, base: File, pattern: String, cached: File, toCopy: collection.mutable.HashSet[(File, File)]): File = {
|
||||
retReport
|
||||
}
|
||||
|
||||
private def performRetrieve(
|
||||
conf: String,
|
||||
mid: ModuleID,
|
||||
art: Artifact,
|
||||
base: File,
|
||||
pattern: String,
|
||||
cached: File,
|
||||
toCopy: collection.mutable.HashSet[(File, File)]
|
||||
): File = {
|
||||
val to = retrieveTarget(conf, mid, art, base, pattern)
|
||||
toCopy += ((cached, to))
|
||||
to
|
||||
}
|
||||
|
||||
private def retrieveTarget(conf: String, mid: ModuleID, art: Artifact, base: File, pattern: String): File =
|
||||
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.branchName.orNull, mid.revision, art.name, art.`type`, art.extension, conf, null, 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.branchName.orNull,
|
||||
mid.revision,
|
||||
art.name,
|
||||
art.`type`,
|
||||
art.extension,
|
||||
conf,
|
||||
null,
|
||||
mextra,
|
||||
aextra
|
||||
)
|
||||
}
|
||||
|
||||
import UpdateLogging.{ Quiet, Full, DownloadOnly, Default }
|
||||
import LogOptions.{ LOG_QUIET, LOG_DEFAULT, LOG_DOWNLOAD_ONLY }
|
||||
|
|
@ -398,46 +632,57 @@ object IvyActions {
|
|||
case Default => LOG_DOWNLOAD_ONLY
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
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)]): Unit = {
|
||||
val missing = artifacts filter { case (a, file) => !file.exists }
|
||||
if (missing.nonEmpty)
|
||||
sys.error("Missing files for publishing:\n\t" + missing.map(_._2.getAbsolutePath).mkString("\n\t"))
|
||||
sys.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],
|
||||
val failedPaths: Map[ModuleID, Seq[ModuleID]]
|
||||
val messages: Seq[String],
|
||||
val failed: Seq[ModuleID],
|
||||
val failedPaths: Map[ModuleID, Seq[ModuleID]]
|
||||
) extends RuntimeException(messages.mkString("\n")) {
|
||||
def this(messages: Seq[String], failed: Seq[ModuleID]) =
|
||||
this(messages, failed, Map(failed map { m => m -> Nil }: _*))
|
||||
this(messages, failed, Map(failed map { m =>
|
||||
m -> Nil
|
||||
}: _*))
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents unresolved dependency warning, which displays reconstructed dependency tree
|
||||
* along with source position of each node.
|
||||
*/
|
||||
final class UnresolvedWarning private[sbt] (
|
||||
val resolveException: ResolveException,
|
||||
val failedPaths: Seq[Seq[(ModuleID, Option[SourcePosition])]]
|
||||
val resolveException: ResolveException,
|
||||
val failedPaths: Seq[Seq[(ModuleID, Option[SourcePosition])]]
|
||||
)
|
||||
object UnresolvedWarning {
|
||||
private[sbt] def apply(err: ResolveException, config: UnresolvedWarningConfiguration): UnresolvedWarning = {
|
||||
private[sbt] def apply(
|
||||
err: ResolveException,
|
||||
config: UnresolvedWarningConfiguration
|
||||
): UnresolvedWarning = {
|
||||
def modulePosition(m0: ModuleID): Option[SourcePosition] =
|
||||
config.modulePositions.find {
|
||||
case (m, p) =>
|
||||
|
|
@ -454,20 +699,25 @@ object UnresolvedWarning {
|
|||
}
|
||||
apply(err, failedPaths)
|
||||
}
|
||||
private[sbt] def apply(err: ResolveException, failedPaths: Seq[Seq[(ModuleID, Option[SourcePosition])]]): UnresolvedWarning =
|
||||
private[sbt] def apply(
|
||||
err: ResolveException,
|
||||
failedPaths: Seq[Seq[(ModuleID, Option[SourcePosition])]]
|
||||
): UnresolvedWarning =
|
||||
new UnresolvedWarning(err, failedPaths)
|
||||
private[sbt] def sourcePosStr(posOpt: Option[SourcePosition]): String =
|
||||
posOpt match {
|
||||
case Some(LinePosition(path, start)) => s" ($path#L$start)"
|
||||
case Some(LinePosition(path, start)) => s" ($path#L$start)"
|
||||
case Some(RangePosition(path, LineRange(start, end))) => s" ($path#L$start-$end)"
|
||||
case _ => ""
|
||||
case _ => ""
|
||||
}
|
||||
implicit val unresolvedWarningLines: ShowLines[UnresolvedWarning] = ShowLines { a =>
|
||||
val withExtra = a.resolveException.failed.filter(_.extraDependencyAttributes.nonEmpty)
|
||||
val buffer = mutable.ListBuffer[String]()
|
||||
if (withExtra.nonEmpty) {
|
||||
buffer += "\n\tNote: Some unresolved dependencies have extra attributes. Check that these dependencies exist with the requested attributes."
|
||||
withExtra foreach { id => buffer += "\t\t" + id }
|
||||
withExtra foreach { id =>
|
||||
buffer += "\t\t" + id
|
||||
}
|
||||
}
|
||||
if (a.failedPaths.nonEmpty) {
|
||||
buffer += "\n\tNote: Unresolved dependencies path:"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@ package sbt.internal.librarymanagement
|
|||
|
||||
import java.io.File
|
||||
|
||||
import org.apache.ivy.core.cache.{ ArtifactOrigin, CacheDownloadOptions, DefaultRepositoryCacheManager }
|
||||
import org.apache.ivy.core.cache.{
|
||||
ArtifactOrigin,
|
||||
CacheDownloadOptions,
|
||||
DefaultRepositoryCacheManager
|
||||
}
|
||||
import org.apache.ivy.core.module.descriptor.{ Artifact => IvyArtifact, DefaultArtifact }
|
||||
import org.apache.ivy.plugins.repository.file.{ FileRepository => IvyFileRepository, FileResource }
|
||||
import org.apache.ivy.plugins.repository.{ ArtifactResourceResolver, Resource, ResourceDownloader }
|
||||
|
|
@ -20,36 +24,46 @@ import scala.collection.mutable
|
|||
import jawn.{ SupportParser, MutableFacade }
|
||||
|
||||
class NotInCache(val id: ModuleID, cause: Throwable)
|
||||
extends RuntimeException(NotInCache(id, cause), cause) {
|
||||
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
|
||||
}
|
||||
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): Unit = {
|
||||
val artifact = defaultArtifact(moduleID)
|
||||
val resolved = new ResolvedResource(new FileResource(new IvyFileRepository, file), moduleID.revision)
|
||||
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): Unit = {
|
||||
try { withCachedJar(id, lock, log)(_.delete); () }
|
||||
catch { case e: Exception => log.debug("Error cleaning cached jar: " + e.toString) }
|
||||
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) =
|
||||
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)
|
||||
|
|
@ -57,41 +71,58 @@ class IvyCache(val ivyHome: Option[File]) {
|
|||
}
|
||||
|
||||
/** 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) }
|
||||
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)
|
||||
}
|
||||
|
||||
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, _) = basicLocalIvy(lock, log)
|
||||
ivy.withIvy(log) { ivy =>
|
||||
val cache = ivy.getSettings.getDefaultRepositoryCacheManager.asInstanceOf[DefaultRepositoryCacheManager]
|
||||
cache.setUseOrigin(false)
|
||||
f(cache)
|
||||
}
|
||||
def withDefaultCache[T](lock: Option[xsbti.GlobalLock], log: Logger)(
|
||||
f: DefaultRepositoryCacheManager => T
|
||||
): T = {
|
||||
val (ivy, _) = 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 = IvyPaths(new File("."), ivyHome)
|
||||
val conf = new InlineIvyConfiguration(paths, Vector(local), Vector.empty, Vector.empty, false, lock, IvySbt.DefaultChecksums, None, UpdateOptions(), log)
|
||||
(new IvySbt(conf), local)
|
||||
}
|
||||
private def basicLocalIvy(lock: Option[xsbti.GlobalLock], log: Logger) = {
|
||||
val local = Resolver.defaultLocal
|
||||
val paths = IvyPaths(new File("."), ivyHome)
|
||||
val conf = new InlineIvyConfiguration(
|
||||
paths,
|
||||
Vector(local),
|
||||
Vector.empty,
|
||||
Vector.empty,
|
||||
false,
|
||||
lock,
|
||||
IvySbt.DefaultChecksums,
|
||||
None,
|
||||
UpdateOptions(),
|
||||
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 {
|
||||
def download(artifact: IvyArtifact, resource: Resource, dest: File): Unit = {
|
||||
|
|
|
|||
|
|
@ -6,11 +6,15 @@ package sbt.internal.librarymanagement
|
|||
import sbt.librarymanagement._
|
||||
|
||||
abstract class InlineConfigurationFunctions {
|
||||
def configurations(explicitConfigurations: Iterable[Configuration], defaultConfiguration: Option[Configuration]) =
|
||||
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 Some(Configurations.DefaultMavenConfiguration) =>
|
||||
Configurations.defaultMavenConfigurations
|
||||
case _ => Nil
|
||||
}
|
||||
} else
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ private final class IvyLoggerInterface(logger: Logger) extends MessageLogger {
|
|||
def setShowProgress(progress: Boolean): Unit = ()
|
||||
}
|
||||
private final class SbtMessageLoggerEngine extends MessageLoggerEngine {
|
||||
|
||||
/** This is a hack to filter error messages about 'unknown resolver ...'. */
|
||||
override def error(msg: String): Unit = if (SbtIvyLogger.acceptError(msg)) super.error(msg)
|
||||
override def sumupProblems(): Unit = clearProblems()
|
||||
|
|
|
|||
|
|
@ -21,39 +21,48 @@ object IvyRetrieve {
|
|||
|
||||
def moduleReports(confReport: ConfigurationResolveReport): Vector[ModuleReport] =
|
||||
for {
|
||||
revId <- confReport.getModuleRevisionIds.toArray.toVector collect { case revId: ModuleRevisionId => revId }
|
||||
revId <- confReport.getModuleRevisionIds.toArray.toVector collect {
|
||||
case revId: ModuleRevisionId => revId
|
||||
}
|
||||
} yield moduleRevisionDetail(confReport, confReport.getDependency(revId))
|
||||
|
||||
@deprecated("Internal only. No longer in use.", "0.13.6")
|
||||
def artifactReports(mid: ModuleID, artReport: Seq[ArtifactDownloadReport]): ModuleReport =
|
||||
{
|
||||
val (resolved, missing) = artifacts(mid, artReport)
|
||||
ModuleReport(mid, resolved, missing)
|
||||
}
|
||||
def artifactReports(mid: ModuleID, artReport: Seq[ArtifactDownloadReport]): ModuleReport = {
|
||||
val (resolved, missing) = artifacts(mid, artReport)
|
||||
ModuleReport(mid, resolved, missing)
|
||||
}
|
||||
|
||||
private[sbt] def artifacts(mid: ModuleID, artReport: Seq[ArtifactDownloadReport]): (Vector[(Artifact, File)], Vector[Artifact]) =
|
||||
{
|
||||
val missing = new mutable.ListBuffer[Artifact]
|
||||
val resolved = new mutable.ListBuffer[(Artifact, File)]
|
||||
for (r <- artReport) {
|
||||
val fileOpt = Option(r.getLocalFile)
|
||||
val art = toArtifact(r.getArtifact)
|
||||
fileOpt match {
|
||||
case Some(file) => resolved += ((art, file))
|
||||
case None => missing += art
|
||||
}
|
||||
private[sbt] def artifacts(
|
||||
mid: ModuleID,
|
||||
artReport: Seq[ArtifactDownloadReport]
|
||||
): (Vector[(Artifact, File)], Vector[Artifact]) = {
|
||||
val missing = new mutable.ListBuffer[Artifact]
|
||||
val resolved = new mutable.ListBuffer[(Artifact, File)]
|
||||
for (r <- artReport) {
|
||||
val fileOpt = Option(r.getLocalFile)
|
||||
val art = toArtifact(r.getArtifact)
|
||||
fileOpt match {
|
||||
case Some(file) => resolved += ((art, file))
|
||||
case None => missing += art
|
||||
}
|
||||
(resolved.toVector, missing.toVector)
|
||||
}
|
||||
(resolved.toVector, missing.toVector)
|
||||
}
|
||||
|
||||
// We need this because current module report used as part of UpdateReport/ConfigurationReport contains
|
||||
// only the revolved modules.
|
||||
// Sometimes the entire module can be excluded via rules etc.
|
||||
private[sbt] def organizationArtifactReports(confReport: ConfigurationResolveReport): Vector[OrganizationArtifactReport] = {
|
||||
val moduleIds = confReport.getModuleIds.toArray.toVector collect { case mId: IvyModuleId => mId }
|
||||
private[sbt] def organizationArtifactReports(
|
||||
confReport: ConfigurationResolveReport
|
||||
): Vector[OrganizationArtifactReport] = {
|
||||
val moduleIds = confReport.getModuleIds.toArray.toVector collect {
|
||||
case mId: IvyModuleId => mId
|
||||
}
|
||||
def organizationArtifact(mid: IvyModuleId): OrganizationArtifactReport = {
|
||||
val deps = confReport.getNodes(mid).toArray.toVector collect { case node: IvyNode => node }
|
||||
OrganizationArtifactReport(mid.getOrganisation, mid.getName, deps map { moduleRevisionDetail(confReport, _) })
|
||||
OrganizationArtifactReport(mid.getOrganisation, mid.getName, deps map {
|
||||
moduleRevisionDetail(confReport, _)
|
||||
})
|
||||
}
|
||||
moduleIds map { organizationArtifact }
|
||||
}
|
||||
|
|
@ -65,10 +74,16 @@ object IvyRetrieve {
|
|||
case x => Some(x.trim)
|
||||
}
|
||||
|
||||
private[sbt] def moduleRevisionDetail(confReport: ConfigurationResolveReport, dep: IvyNode): ModuleReport = {
|
||||
private[sbt] def moduleRevisionDetail(
|
||||
confReport: ConfigurationResolveReport,
|
||||
dep: IvyNode
|
||||
): ModuleReport = {
|
||||
def toExtraAttributes(ea: ju.Map[_, _]): Map[String, String] =
|
||||
Map(ea.entrySet.toArray collect {
|
||||
case entry: ju.Map.Entry[_, _] if nonEmptyString(entry.getKey.toString).isDefined && nonEmptyString(entry.getValue.toString).isDefined =>
|
||||
case entry: ju.Map.Entry[_, _]
|
||||
if nonEmptyString(entry.getKey.toString).isDefined && nonEmptyString(
|
||||
entry.getValue.toString
|
||||
).isDefined =>
|
||||
(entry.getKey.toString, entry.getValue.toString)
|
||||
}: _*)
|
||||
def toCaller(caller: IvyCaller): Caller = {
|
||||
|
|
@ -80,11 +95,32 @@ object IvyRetrieve {
|
|||
val (extraAttributes, isForce, isChanging, isTransitive, isDirectlyForce) = ddOpt match {
|
||||
case Some(dd: SbtDefaultDependencyDescriptor) =>
|
||||
val mod = dd.dependencyModuleId
|
||||
(toExtraAttributes(dd.getExtraAttributes), mod.isForce, mod.isChanging, mod.isTransitive, mod.isForce)
|
||||
case Some(dd) => (toExtraAttributes(dd.getExtraAttributes), dd.isForce, dd.isChanging, dd.isTransitive, false)
|
||||
case None => (Map.empty[String, String], false, false, true, false)
|
||||
(
|
||||
toExtraAttributes(dd.getExtraAttributes),
|
||||
mod.isForce,
|
||||
mod.isChanging,
|
||||
mod.isTransitive,
|
||||
mod.isForce
|
||||
)
|
||||
case Some(dd) =>
|
||||
(
|
||||
toExtraAttributes(dd.getExtraAttributes),
|
||||
dd.isForce,
|
||||
dd.isChanging,
|
||||
dd.isTransitive,
|
||||
false
|
||||
)
|
||||
case None => (Map.empty[String, String], false, false, true, false)
|
||||
}
|
||||
Caller(m, callerConfigurations, extraAttributes, isForce, isChanging, isTransitive, isDirectlyForce)
|
||||
Caller(
|
||||
m,
|
||||
callerConfigurations,
|
||||
extraAttributes,
|
||||
isForce,
|
||||
isChanging,
|
||||
isTransitive,
|
||||
isDirectlyForce
|
||||
)
|
||||
}
|
||||
val revId = dep.getResolvedId
|
||||
val moduleId = toModuleID(revId)
|
||||
|
|
@ -106,9 +142,9 @@ object IvyRetrieve {
|
|||
val edOpt = Option(dep.getEvictedData(confReport.getConfiguration))
|
||||
edOpt match {
|
||||
case Some(ed) =>
|
||||
(true,
|
||||
nonEmptyString(Option(ed.getConflictManager) map { _.toString } getOrElse { "transitive" }),
|
||||
nonEmptyString(ed.getDetail))
|
||||
(true, nonEmptyString(Option(ed.getConflictManager) map { _.toString } getOrElse {
|
||||
"transitive"
|
||||
}), nonEmptyString(ed.getDetail))
|
||||
case None => (true, None, None)
|
||||
}
|
||||
case _ => (false, None, None)
|
||||
|
|
@ -133,40 +169,74 @@ object IvyRetrieve {
|
|||
val isDefault = Option(dep.getDescriptor) map { _.isDefault }
|
||||
val configurations = dep.getConfigurations(confReport.getConfiguration).toVector
|
||||
val licenses: Vector[(String, Option[String])] = mdOpt match {
|
||||
case Some(md) => md.getLicenses.toVector collect {
|
||||
case lic: IvyLicense if Option(lic.getName).isDefined =>
|
||||
val temporaryURL = "http://localhost"
|
||||
(lic.getName, nonEmptyString(lic.getUrl) orElse { Some(temporaryURL) })
|
||||
}
|
||||
case Some(md) =>
|
||||
md.getLicenses.toVector collect {
|
||||
case lic: IvyLicense if Option(lic.getName).isDefined =>
|
||||
val temporaryURL = "http://localhost"
|
||||
(lic.getName, nonEmptyString(lic.getUrl) orElse { Some(temporaryURL) })
|
||||
}
|
||||
case _ => Vector.empty
|
||||
}
|
||||
val callers = dep.getCallers(confReport.getConfiguration).toVector map { toCaller }
|
||||
val (resolved, missing) = artifacts(moduleId, confReport getDownloadReports revId)
|
||||
|
||||
ModuleReport(moduleId, resolved, missing, status, publicationDate, resolver, artifactResolver,
|
||||
evicted, evictedData, evictedReason, problem, homepage, extraAttributes, isDefault, branch,
|
||||
configurations, licenses, callers)
|
||||
ModuleReport(
|
||||
moduleId,
|
||||
resolved,
|
||||
missing,
|
||||
status,
|
||||
publicationDate,
|
||||
resolver,
|
||||
artifactResolver,
|
||||
evicted,
|
||||
evictedData,
|
||||
evictedReason,
|
||||
problem,
|
||||
homepage,
|
||||
extraAttributes,
|
||||
isDefault,
|
||||
branch,
|
||||
configurations,
|
||||
licenses,
|
||||
callers
|
||||
)
|
||||
}
|
||||
|
||||
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).withExtraAttributes(IvySbt.getExtraAttributes(revID))
|
||||
ModuleID(revID.getOrganisation, revID.getName, revID.getRevision)
|
||||
.withExtraAttributes(IvySbt.getExtraAttributes(revID))
|
||||
.branch(nonEmptyString(revID.getBranch))
|
||||
|
||||
def toArtifact(art: IvyArtifact): Artifact =
|
||||
{
|
||||
import art._
|
||||
Artifact(getName, getType, getExt, Option(getExtraAttribute("classifier")), getConfigurations.toVector map Configurations.config, Option(getUrl))
|
||||
}
|
||||
def toArtifact(art: IvyArtifact): Artifact = {
|
||||
import art._
|
||||
Artifact(
|
||||
getName,
|
||||
getType,
|
||||
getExt,
|
||||
Option(getExtraAttribute("classifier")),
|
||||
getConfigurations.toVector map Configurations.config,
|
||||
Option(getUrl)
|
||||
)
|
||||
}
|
||||
|
||||
def updateReport(report: ResolveReport, cachedDescriptor: File): UpdateReport =
|
||||
UpdateReport(cachedDescriptor, reports(report) map configurationReport, updateStats(report), Map.empty) recomputeStamps ()
|
||||
UpdateReport(
|
||||
cachedDescriptor,
|
||||
reports(report) map configurationReport,
|
||||
updateStats(report),
|
||||
Map.empty
|
||||
) recomputeStamps ()
|
||||
def updateStats(report: ResolveReport): UpdateStats =
|
||||
UpdateStats(report.getResolveTime, report.getDownloadTime, report.getDownloadSize, false)
|
||||
def configurationReport(confReport: ConfigurationResolveReport): ConfigurationReport =
|
||||
ConfigurationReport(confReport.getConfiguration, moduleReports(confReport), organizationArtifactReports(confReport))
|
||||
ConfigurationReport(
|
||||
confReport.getConfiguration,
|
||||
moduleReports(confReport),
|
||||
organizationArtifactReports(confReport)
|
||||
)
|
||||
|
||||
/**
|
||||
* Tries to find Ivy graph path the from node to target.
|
||||
|
|
|
|||
|
|
@ -11,36 +11,59 @@ private[sbt] object JsonUtil {
|
|||
def sbtOrgTemp = "org.scala-sbt.temp"
|
||||
def fakeCallerOrganization = "org.scala-sbt.temp-callers"
|
||||
|
||||
def parseUpdateReport(md: ModuleDescriptor, path: File, cachedDescriptor: File, log: Logger): UpdateReport =
|
||||
{
|
||||
try {
|
||||
val lite = CacheStore(path).read[UpdateReportLite]
|
||||
fromLite(lite, cachedDescriptor)
|
||||
} catch {
|
||||
case e: Throwable =>
|
||||
log.error("Unable to parse mini graph: " + path.toString)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
def writeUpdateReport(ur: UpdateReport, graphPath: File): Unit =
|
||||
{
|
||||
sbt.io.IO.createDirectory(graphPath.getParentFile)
|
||||
CacheStore(graphPath).write(toLite(ur))
|
||||
def parseUpdateReport(
|
||||
md: ModuleDescriptor,
|
||||
path: File,
|
||||
cachedDescriptor: File,
|
||||
log: Logger
|
||||
): UpdateReport = {
|
||||
try {
|
||||
val lite = CacheStore(path).read[UpdateReportLite]
|
||||
fromLite(lite, cachedDescriptor)
|
||||
} catch {
|
||||
case e: Throwable =>
|
||||
log.error("Unable to parse mini graph: " + path.toString)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
def writeUpdateReport(ur: UpdateReport, graphPath: File): Unit = {
|
||||
sbt.io.IO.createDirectory(graphPath.getParentFile)
|
||||
CacheStore(graphPath).write(toLite(ur))
|
||||
}
|
||||
def toLite(ur: UpdateReport): UpdateReportLite =
|
||||
UpdateReportLite(ur.configurations map { cr =>
|
||||
ConfigurationReportLite(cr.configuration, cr.details map { oar =>
|
||||
OrganizationArtifactReport(oar.organization, oar.name, oar.modules map { mr =>
|
||||
ModuleReport(
|
||||
mr.module, mr.artifacts, mr.missingArtifacts, mr.status,
|
||||
mr.publicationDate, mr.resolver, mr.artifactResolver,
|
||||
mr.evicted, mr.evictedData, mr.evictedReason,
|
||||
mr.problem, mr.homepage, mr.extraAttributes,
|
||||
mr.isDefault, mr.branch, mr.configurations, mr.licenses,
|
||||
filterOutArtificialCallers(mr.callers)
|
||||
)
|
||||
})
|
||||
})
|
||||
ConfigurationReportLite(
|
||||
cr.configuration,
|
||||
cr.details map {
|
||||
oar =>
|
||||
OrganizationArtifactReport(
|
||||
oar.organization,
|
||||
oar.name,
|
||||
oar.modules map { mr =>
|
||||
ModuleReport(
|
||||
mr.module,
|
||||
mr.artifacts,
|
||||
mr.missingArtifacts,
|
||||
mr.status,
|
||||
mr.publicationDate,
|
||||
mr.resolver,
|
||||
mr.artifactResolver,
|
||||
mr.evicted,
|
||||
mr.evictedData,
|
||||
mr.evictedReason,
|
||||
mr.problem,
|
||||
mr.homepage,
|
||||
mr.extraAttributes,
|
||||
mr.isDefault,
|
||||
mr.branch,
|
||||
mr.configurations,
|
||||
mr.licenses,
|
||||
filterOutArtificialCallers(mr.callers)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
// #1763/#2030. Caller takes up 97% of space, so we need to shrink it down,
|
||||
// but there are semantics associated with some of them.
|
||||
|
|
@ -49,7 +72,7 @@ private[sbt] object JsonUtil {
|
|||
else {
|
||||
val nonArtificial = callers filter { c =>
|
||||
(c.caller.organization != sbtOrgTemp) &&
|
||||
(c.caller.organization != fakeCallerOrganization)
|
||||
(c.caller.organization != fakeCallerOrganization)
|
||||
}
|
||||
val interProj = (callers find { c =>
|
||||
c.caller.organization == sbtOrgTemp
|
||||
|
|
@ -57,18 +80,17 @@ private[sbt] object JsonUtil {
|
|||
interProj ++ nonArtificial
|
||||
}
|
||||
|
||||
def fromLite(lite: UpdateReportLite, cachedDescriptor: File): UpdateReport =
|
||||
{
|
||||
val stats = UpdateStats(0L, 0L, 0L, false)
|
||||
val configReports = lite.configurations map { cr =>
|
||||
val details = cr.details
|
||||
val modules = details flatMap {
|
||||
_.modules filter { mr =>
|
||||
!mr.evicted && mr.problem.isEmpty
|
||||
}
|
||||
def fromLite(lite: UpdateReportLite, cachedDescriptor: File): UpdateReport = {
|
||||
val stats = UpdateStats(0L, 0L, 0L, false)
|
||||
val configReports = lite.configurations map { cr =>
|
||||
val details = cr.details
|
||||
val modules = details flatMap {
|
||||
_.modules filter { mr =>
|
||||
!mr.evicted && mr.problem.isEmpty
|
||||
}
|
||||
ConfigurationReport(cr.configuration, modules, details)
|
||||
}
|
||||
UpdateReport(cachedDescriptor, configReports, stats, Map.empty)
|
||||
ConfigurationReport(cr.configuration, modules, details)
|
||||
}
|
||||
UpdateReport(cachedDescriptor, configReports, stats, Map.empty)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,35 +19,121 @@ import Configurations.Optional
|
|||
|
||||
import org.apache.ivy.Ivy
|
||||
import org.apache.ivy.core.settings.IvySettings
|
||||
import org.apache.ivy.core.module.descriptor.{ DependencyArtifactDescriptor, DependencyDescriptor, License, ModuleDescriptor, ExcludeRule }
|
||||
import org.apache.ivy.core.module.descriptor.{
|
||||
DependencyArtifactDescriptor,
|
||||
DependencyDescriptor,
|
||||
License,
|
||||
ModuleDescriptor,
|
||||
ExcludeRule
|
||||
}
|
||||
import org.apache.ivy.plugins.resolver.{ ChainResolver, DependencyResolver, IBiblioResolver }
|
||||
import ivyint.CustomRemoteMavenResolver
|
||||
import sbt.io.IO
|
||||
|
||||
object MakePom {
|
||||
|
||||
/** True if the revision is an ivy-range, not a complete revision. */
|
||||
def isDependencyVersionRange(revision: String): Boolean = VersionRange.isVersionRange(revision)
|
||||
|
||||
/** Converts Ivy revision ranges to that of Maven POM */
|
||||
def makeDependencyVersion(revision: String): String = VersionRange.fromIvyToMavenVersion(revision)
|
||||
def makeDependencyVersion(revision: String): String =
|
||||
VersionRange.fromIvyToMavenVersion(revision)
|
||||
}
|
||||
class MakePom(val log: Logger) {
|
||||
import MakePom._
|
||||
@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)
|
||||
@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): Unit =
|
||||
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 =
|
||||
@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) }
|
||||
|
|
@ -65,81 +151,80 @@ class MakePom(val log: Logger) {
|
|||
{ 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>
|
||||
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 makeDeveloperInfo(moduleInfo: ModuleInfo): NodeSeq = {
|
||||
if (moduleInfo.developers.nonEmpty) {
|
||||
<developers>
|
||||
{
|
||||
moduleInfo.organizationHomepage match {
|
||||
case Some(h)=> <url>{ h }</url>
|
||||
case _ => NodeSeq.Empty
|
||||
moduleInfo.developers.map { developer: Developer =>
|
||||
<developer>
|
||||
<id>{ developer.id }</id>
|
||||
<name>{ developer.name }</name>
|
||||
<email>{ developer.email }</email>
|
||||
<url>{ developer.url }</url>
|
||||
</developer>
|
||||
}
|
||||
}
|
||||
</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 makeDeveloperInfo(moduleInfo: ModuleInfo): NodeSeq =
|
||||
{
|
||||
if (moduleInfo.developers.nonEmpty) {
|
||||
<developers>
|
||||
{
|
||||
moduleInfo.developers.map { developer: Developer =>
|
||||
<developer>
|
||||
<id>{ developer.id }</id>
|
||||
<name>{ developer.name }</name>
|
||||
<email>{ developer.email }</email>
|
||||
<url>{ developer.url }</url>
|
||||
</developer>
|
||||
}
|
||||
}
|
||||
</developers>
|
||||
} else NodeSeq.Empty
|
||||
}
|
||||
def makeProperties(module: ModuleDescriptor, dependencies: Seq[DependencyDescriptor]): NodeSeq =
|
||||
{
|
||||
val extra = IvySbt.getExtraAttributes(module)
|
||||
val depExtra = PomExtraDependencyAttributes.writeDependencyExtra(dependencies).mkString("\n")
|
||||
val allExtra = if (depExtra.isEmpty) extra else extra.updated(PomExtraDependencyAttributes.ExtraAttributesKey, depExtra)
|
||||
if (allExtra.isEmpty) NodeSeq.Empty else makeProperties(allExtra)
|
||||
}
|
||||
</developers>
|
||||
} else NodeSeq.Empty
|
||||
}
|
||||
def makeProperties(module: ModuleDescriptor, dependencies: Seq[DependencyDescriptor]): NodeSeq = {
|
||||
val extra = IvySbt.getExtraAttributes(module)
|
||||
val depExtra = PomExtraDependencyAttributes.writeDependencyExtra(dependencies).mkString("\n")
|
||||
val allExtra =
|
||||
if (depExtra.isEmpty) extra
|
||||
else extra.updated(PomExtraDependencyAttributes.ExtraAttributesKey, depExtra)
|
||||
if (allExtra.isEmpty) NodeSeq.Empty else makeProperties(allExtra)
|
||||
}
|
||||
def makeProperties(extra: Map[String, String]): NodeSeq = {
|
||||
def _extraAttributes(k: String) = if (k == PomExtraDependencyAttributes.ExtraAttributesKey) xmlSpacePreserve else scala.xml.Null
|
||||
def _extraAttributes(k: String) =
|
||||
if (k == PomExtraDependencyAttributes.ExtraAttributesKey) xmlSpacePreserve
|
||||
else scala.xml.Null
|
||||
<properties> {
|
||||
for ((key, value) <- extra) yield (<x>{ value }</x>).copy(label = key, attributes = _extraAttributes(key))
|
||||
} </properties>
|
||||
|
|
@ -152,8 +237,10 @@ class MakePom(val log: Logger) {
|
|||
*/
|
||||
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 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>
|
||||
|
|
@ -161,7 +248,8 @@ class MakePom(val log: Logger) {
|
|||
<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 revision(version: String) =
|
||||
if (version ne null) <version>{ version }</version> else NodeSeq.Empty
|
||||
def packaging(module: ModuleDescriptor) =
|
||||
module.getAllArtifacts match {
|
||||
case Array() => "pom"
|
||||
|
|
@ -177,10 +265,17 @@ class MakePom(val log: Logger) {
|
|||
val IgnoreTypes: Set[String] = Set(Artifact.SourceType, Artifact.DocType, Artifact.PomType)
|
||||
|
||||
@deprecated("Use `makeDependencies` variant which takes excludes", "0.13.9")
|
||||
def makeDependencies(dependencies: Seq[DependencyDescriptor], includeTypes: Set[String]): NodeSeq =
|
||||
def makeDependencies(
|
||||
dependencies: Seq[DependencyDescriptor],
|
||||
includeTypes: Set[String]
|
||||
): NodeSeq =
|
||||
makeDependencies(dependencies, includeTypes, Nil)
|
||||
|
||||
def makeDependencies(dependencies: Seq[DependencyDescriptor], includeTypes: Set[String], excludes: Seq[ExcludeRule]): NodeSeq =
|
||||
def makeDependencies(
|
||||
dependencies: Seq[DependencyDescriptor],
|
||||
includeTypes: Set[String],
|
||||
excludes: Seq[ExcludeRule]
|
||||
): NodeSeq =
|
||||
if (dependencies.isEmpty)
|
||||
NodeSeq.Empty
|
||||
else
|
||||
|
|
@ -192,74 +287,96 @@ class MakePom(val log: Logger) {
|
|||
def makeDependency(dependency: DependencyDescriptor, includeTypes: Set[String]): NodeSeq =
|
||||
makeDependency(dependency, includeTypes, Nil)
|
||||
|
||||
def makeDependency(dependency: DependencyDescriptor, includeTypes: Set[String], excludes: Seq[ExcludeRule]): NodeSeq =
|
||||
{
|
||||
val artifacts = dependency.getAllDependencyArtifacts
|
||||
val includeArtifacts = artifacts.filter(d => includeTypes(d.getType))
|
||||
if (artifacts.isEmpty) {
|
||||
val configs = dependency.getModuleConfigurations
|
||||
if (configs.filterNot(Set("sources", "docs")).nonEmpty) {
|
||||
val (scope, optional) = getScopeAndOptional(dependency.getModuleConfigurations)
|
||||
makeDependencyElem(dependency, scope, optional, None, None, excludes)
|
||||
} else NodeSeq.Empty
|
||||
} else if (includeArtifacts.isEmpty)
|
||||
NodeSeq.Empty
|
||||
else
|
||||
NodeSeq.fromSeq(artifacts.flatMap(a => makeDependencyElem(dependency, a, excludes)))
|
||||
}
|
||||
def makeDependency(
|
||||
dependency: DependencyDescriptor,
|
||||
includeTypes: Set[String],
|
||||
excludes: Seq[ExcludeRule]
|
||||
): NodeSeq = {
|
||||
val artifacts = dependency.getAllDependencyArtifacts
|
||||
val includeArtifacts = artifacts.filter(d => includeTypes(d.getType))
|
||||
if (artifacts.isEmpty) {
|
||||
val configs = dependency.getModuleConfigurations
|
||||
if (configs.filterNot(Set("sources", "docs")).nonEmpty) {
|
||||
val (scope, optional) = getScopeAndOptional(dependency.getModuleConfigurations)
|
||||
makeDependencyElem(dependency, scope, optional, None, None, excludes)
|
||||
} else NodeSeq.Empty
|
||||
} else if (includeArtifacts.isEmpty)
|
||||
NodeSeq.Empty
|
||||
else
|
||||
NodeSeq.fromSeq(artifacts.flatMap(a => makeDependencyElem(dependency, a, excludes)))
|
||||
}
|
||||
|
||||
@deprecated("Use `makeDependencyElem` variant which takes excludes", "0.13.9")
|
||||
def makeDependencyElem(dependency: DependencyDescriptor, artifact: DependencyArtifactDescriptor): Option[Elem] =
|
||||
def makeDependencyElem(
|
||||
dependency: DependencyDescriptor,
|
||||
artifact: DependencyArtifactDescriptor
|
||||
): Option[Elem] =
|
||||
makeDependencyElem(dependency, artifact, Nil)
|
||||
|
||||
def makeDependencyElem(dependency: DependencyDescriptor, artifact: DependencyArtifactDescriptor, excludes: Seq[ExcludeRule]): Option[Elem] =
|
||||
{
|
||||
val configs = artifact.getConfigurations.toList match {
|
||||
case Nil | "*" :: Nil => dependency.getModuleConfigurations
|
||||
case x => x.toArray
|
||||
}
|
||||
if (!configs.forall(Set("sources", "docs"))) {
|
||||
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
|
||||
}
|
||||
Some(makeDependencyElem(dependency, scope, optional, classifier, tpe, excludes))
|
||||
} else None
|
||||
def makeDependencyElem(
|
||||
dependency: DependencyDescriptor,
|
||||
artifact: DependencyArtifactDescriptor,
|
||||
excludes: Seq[ExcludeRule]
|
||||
): Option[Elem] = {
|
||||
val configs = artifact.getConfigurations.toList match {
|
||||
case Nil | "*" :: Nil => dependency.getModuleConfigurations
|
||||
case x => x.toArray
|
||||
}
|
||||
if (!configs.forall(Set("sources", "docs"))) {
|
||||
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
|
||||
}
|
||||
Some(makeDependencyElem(dependency, scope, optional, classifier, tpe, excludes))
|
||||
} else None
|
||||
}
|
||||
|
||||
@deprecated("Use `makeDependencyElem` variant which takes excludes", "0.13.9")
|
||||
def makeDependencyElem(dependency: DependencyDescriptor, scope: Option[String], optional: Boolean, classifier: Option[String], tpe: Option[String]): Elem =
|
||||
def makeDependencyElem(
|
||||
dependency: DependencyDescriptor,
|
||||
scope: Option[String],
|
||||
optional: Boolean,
|
||||
classifier: Option[String],
|
||||
tpe: Option[String]
|
||||
): Elem =
|
||||
makeDependencyElem(dependency, scope, optional, classifier, tpe, Nil)
|
||||
|
||||
def makeDependencyElem(dependency: DependencyDescriptor, scope: Option[String], optional: Boolean, classifier: Option[String], tpe: Option[String], excludes: Seq[ExcludeRule]): 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, excludes) }
|
||||
</dependency>
|
||||
}
|
||||
def makeDependencyElem(
|
||||
dependency: DependencyDescriptor,
|
||||
scope: Option[String],
|
||||
optional: Boolean,
|
||||
classifier: Option[String],
|
||||
tpe: Option[String],
|
||||
excludes: Seq[ExcludeRule]
|
||||
): 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, excludes) }
|
||||
</dependency>
|
||||
}
|
||||
|
||||
@deprecated("No longer used and will be removed.", "0.12.1")
|
||||
def classifier(dependency: DependencyDescriptor, includeTypes: Set[String]): NodeSeq =
|
||||
{
|
||||
val jarDep = dependency.getAllDependencyArtifacts.find(d => includeTypes(d.getType))
|
||||
jarDep match {
|
||||
case Some(a) => classifierElem(artifactClassifier(a))
|
||||
case None => NodeSeq.Empty
|
||||
}
|
||||
def classifier(dependency: DependencyDescriptor, includeTypes: Set[String]): NodeSeq = {
|
||||
val jarDep = dependency.getAllDependencyArtifacts.find(d => includeTypes(d.getType))
|
||||
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) }
|
||||
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>
|
||||
|
|
@ -275,11 +392,10 @@ class MakePom(val log: Logger) {
|
|||
}
|
||||
|
||||
@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 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>
|
||||
|
|
@ -287,59 +403,67 @@ class MakePom(val log: Logger) {
|
|||
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.nonEmpty)
|
||||
}
|
||||
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.nonEmpty)
|
||||
}
|
||||
|
||||
@deprecated("Use `exclusions` variant which takes excludes", "0.13.9")
|
||||
def exclusions(dependency: DependencyDescriptor): NodeSeq = exclusions(dependency, Nil)
|
||||
|
||||
def exclusions(dependency: DependencyDescriptor, excludes: Seq[ExcludeRule]): NodeSeq =
|
||||
{
|
||||
val excl = dependency.getExcludeRules(dependency.getModuleConfigurations) ++ excludes
|
||||
val (warns, excls) = IvyUtil.separate(excl.map(makeExclusion))
|
||||
if (warns.nonEmpty) log.warn(warns.mkString(IO.Newline))
|
||||
if (excls.nonEmpty) <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, excludes: Seq[ExcludeRule]): NodeSeq = {
|
||||
val excl = dependency.getExcludeRules(dependency.getModuleConfigurations) ++ excludes
|
||||
val (warns, excls) = IvyUtil.separate(excl.map(makeExclusion))
|
||||
if (warns.nonEmpty) log.warn(warns.mkString(IO.Newline))
|
||||
if (excls.nonEmpty) <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) =
|
||||
{
|
||||
val repositories = if (includeAll) allResolvers(settings) else resolvers(settings.getDefaultResolver)
|
||||
val mavenRepositories =
|
||||
repositories.flatMap {
|
||||
// TODO - Would it be ok if bintray were in the pom? We should avoid it for now.
|
||||
case m: CustomRemoteMavenResolver if m.repo.root == JCenterRepository.root => Nil
|
||||
case m: IBiblioResolver if m.isM2compatible && m.getRoot == JCenterRepository.root => Nil
|
||||
case m: CustomRemoteMavenResolver if m.repo.root != DefaultMavenRepository.root =>
|
||||
MavenRepository(m.repo.name, m.repo.root) :: Nil
|
||||
case m: IBiblioResolver if m.isM2compatible && m.getRoot != DefaultMavenRepository.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 makeRepositories(
|
||||
settings: IvySettings,
|
||||
includeAll: Boolean,
|
||||
filterRepositories: MavenRepository => Boolean
|
||||
) = {
|
||||
val repositories =
|
||||
if (includeAll) allResolvers(settings) else resolvers(settings.getDefaultResolver)
|
||||
val mavenRepositories =
|
||||
repositories.flatMap {
|
||||
// TODO - Would it be ok if bintray were in the pom? We should avoid it for now.
|
||||
case m: CustomRemoteMavenResolver if m.repo.root == JCenterRepository.root => Nil
|
||||
case m: IBiblioResolver if m.isM2compatible && m.getRoot == JCenterRepository.root => Nil
|
||||
case m: CustomRemoteMavenResolver if m.repo.root != DefaultMavenRepository.root =>
|
||||
MavenRepository(m.repo.name, m.repo.root) :: Nil
|
||||
case m: IBiblioResolver if m.isM2compatible && m.getRoot != DefaultMavenRepository.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 }
|
||||
|
||||
|
|
@ -349,7 +473,8 @@ class MakePom(val log: Logger) {
|
|||
|
||||
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
|
||||
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 =
|
||||
|
|
@ -364,18 +489,19 @@ class MakePom(val log: Logger) {
|
|||
* 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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,17 +10,28 @@ import org.apache.ivy.core.{ cache, module, report, resolve, search }
|
|||
import cache.ArtifactOrigin
|
||||
import search.{ ModuleEntry, OrganisationEntry, RevisionEntry }
|
||||
import module.id.ModuleRevisionId
|
||||
import module.descriptor.{ Artifact => IArtifact, DefaultArtifact, DependencyDescriptor, ModuleDescriptor }
|
||||
import module.descriptor.{
|
||||
Artifact => IArtifact,
|
||||
DefaultArtifact,
|
||||
DependencyDescriptor,
|
||||
ModuleDescriptor
|
||||
}
|
||||
import org.apache.ivy.plugins.namespace.Namespace
|
||||
import org.apache.ivy.plugins.resolver.ResolverSettings
|
||||
import report.{ ArtifactDownloadReport, DownloadReport, DownloadStatus, MetadataArtifactDownloadReport }
|
||||
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 {
|
||||
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(", ") + ")"
|
||||
|
|
@ -28,48 +39,47 @@ class ProjectResolver(name: String, map: Map[ModuleRevisionId, ModuleDescriptor]
|
|||
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
|
||||
}
|
||||
|
||||
private[sbt] def getModuleDescriptor(revisionId: ModuleRevisionId): Option[ModuleDescriptor] = map.get(revisionId)
|
||||
private[sbt] def getModuleDescriptor(revisionId: ModuleRevisionId): Option[ModuleDescriptor] =
|
||||
map.get(revisionId)
|
||||
|
||||
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
|
||||
}
|
||||
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 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 publish(artifact: IArtifact, src: File, overwrite: Boolean) =
|
||||
sys.error("Publish not supported by ProjectResolver")
|
||||
def beginPublishTransaction(module: ModuleRevisionId, overwrite: Boolean): Unit = ()
|
||||
def abortPublishTransaction(): Unit = ()
|
||||
def commitPublishTransaction(): Unit = ()
|
||||
|
|
@ -87,7 +97,10 @@ class ProjectResolver(name: String, map: Map[ModuleRevisionId, ModuleDescriptor]
|
|||
|
||||
def dumpSettings(): Unit = ()
|
||||
def setSettings(settings: ResolverSettings): Unit = { this.settings = Some(settings) }
|
||||
def getRepositoryCacheManager = settings match { case Some(s) => s.getDefaultRepositoryCacheManager; case None => sys.error("No settings defined for ProjectResolver") }
|
||||
def getRepositoryCacheManager = settings match {
|
||||
case Some(s) => s.getDefaultRepositoryCacheManager;
|
||||
case None => sys.error("No settings defined for ProjectResolver")
|
||||
}
|
||||
}
|
||||
|
||||
object ProjectResolver {
|
||||
|
|
|
|||
|
|
@ -12,16 +12,28 @@ import sbt.internal.util.complete.DefaultParsers._
|
|||
private[sbt] object RepositoriesParser {
|
||||
|
||||
private case class AfterPattern(artifactPattern: Option[String], flags: Int)
|
||||
final case class PredefinedRepository(override val id: xsbti.Predefined) extends xsbti.PredefinedRepository
|
||||
final case class MavenRepository(override val id: String, override val url: URL) extends xsbti.MavenRepository
|
||||
final case class IvyRepository(override val id: String, override val url: URL, override val ivyPattern: String,
|
||||
override val artifactPattern: String, override val mavenCompatible: Boolean, override val skipConsistencyCheck: Boolean,
|
||||
override val descriptorOptional: Boolean, val bootOnly: Boolean) extends xsbti.IvyRepository
|
||||
final case class PredefinedRepository(override val id: xsbti.Predefined)
|
||||
extends xsbti.PredefinedRepository
|
||||
final case class MavenRepository(override val id: String, override val url: URL)
|
||||
extends xsbti.MavenRepository
|
||||
final case class IvyRepository(
|
||||
override val id: String,
|
||||
override val url: URL,
|
||||
override val ivyPattern: String,
|
||||
override val artifactPattern: String,
|
||||
override val mavenCompatible: Boolean,
|
||||
override val skipConsistencyCheck: Boolean,
|
||||
override val descriptorOptional: Boolean,
|
||||
val bootOnly: Boolean
|
||||
) extends xsbti.IvyRepository
|
||||
|
||||
// Predefined repositories
|
||||
def local: Parser[xsbti.Repository] = "local" ^^^ new PredefinedRepository(xsbti.Predefined.Local)
|
||||
def mavenLocal: Parser[xsbti.Repository] = "maven-local" ^^^ new PredefinedRepository(xsbti.Predefined.MavenLocal)
|
||||
def mavenCentral: Parser[xsbti.Repository] = "maven-central" ^^^ new PredefinedRepository(xsbti.Predefined.MavenCentral)
|
||||
def local: Parser[xsbti.Repository] =
|
||||
"local" ^^^ new PredefinedRepository(xsbti.Predefined.Local)
|
||||
def mavenLocal: Parser[xsbti.Repository] =
|
||||
"maven-local" ^^^ new PredefinedRepository(xsbti.Predefined.MavenLocal)
|
||||
def mavenCentral: Parser[xsbti.Repository] =
|
||||
"maven-central" ^^^ new PredefinedRepository(xsbti.Predefined.MavenCentral)
|
||||
def predefinedResolver: Parser[xsbti.Repository] = local | mavenLocal | mavenCentral
|
||||
|
||||
// Options
|
||||
|
|
@ -54,7 +66,16 @@ private[sbt] object RepositoriesParser {
|
|||
// scalac complains about the recursion depth if we pattern match over `ap` directly.
|
||||
ap match {
|
||||
case Some(AfterPattern(artifactPattern, Flags(dOpt, sc, bo, mc))) =>
|
||||
new IvyRepository(name, uri.toURL, ivy, artifactPattern getOrElse ivy, mc, sc, dOpt, bo)
|
||||
new IvyRepository(
|
||||
name,
|
||||
uri.toURL,
|
||||
ivy,
|
||||
artifactPattern getOrElse ivy,
|
||||
mc,
|
||||
sc,
|
||||
dOpt,
|
||||
bo
|
||||
)
|
||||
case None =>
|
||||
new IvyRepository(name, uri.toURL, ivy, ivy, false, false, false, false)
|
||||
}
|
||||
|
|
@ -69,7 +90,8 @@ private[sbt] object RepositoriesParser {
|
|||
def apply(lines: Iterator[String]): Seq[xsbti.Repository] =
|
||||
if (lines.isEmpty) Nil
|
||||
else {
|
||||
if (lines.next != "[repositories]") throw new Exception("Repositories file must start with '[repositories]'")
|
||||
if (lines.next != "[repositories]")
|
||||
throw new Exception("Repositories file must start with '[repositories]'")
|
||||
lines.flatMap(getResolver(_)(resolver)).toList
|
||||
}
|
||||
def apply(str: String): Seq[xsbti.Repository] = apply(str.lines)
|
||||
|
|
@ -92,4 +114,4 @@ private[sbt] object RepositoriesParser {
|
|||
Some((dOpt, sc, bo, mc))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,10 +19,24 @@ import sbt.librarymanagement._
|
|||
* 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[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)
|
||||
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)
|
||||
|
|
@ -62,11 +76,16 @@ private[sbt] final class ResolutionCache(base: File, settings: IvySettings) exte
|
|||
}
|
||||
}
|
||||
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): Unit = {
|
||||
private[sbt] def cleanModule(
|
||||
mrid: ModuleRevisionId,
|
||||
resolveId: String,
|
||||
manager: ResolutionCacheManager
|
||||
): Unit = {
|
||||
val files =
|
||||
Option(manager.getResolvedIvyFileInCache(mrid)).toList :::
|
||||
Option(manager.getResolvedIvyPropertiesInCache(mrid)).toList :::
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ abstract class SbtExclusionRuleFunctions {
|
|||
|
||||
def apply(organization: String): SbtExclusionRule = apply(organization, "*")
|
||||
|
||||
implicit def groupIdToExclusionRule(organization: GroupID): SbtExclusionRule = apply(organization.groupID)
|
||||
implicit def groupIdToExclusionRule(organization: GroupID): SbtExclusionRule =
|
||||
apply(organization.groupID)
|
||||
implicit def stringToExclusionRule(organization: String): SbtExclusionRule = apply(organization)
|
||||
|
||||
implicit def groupArtifactIDToExclusionRule(gaid: GroupArtifactID): SbtExclusionRule =
|
||||
|
|
|
|||
|
|
@ -6,8 +6,12 @@ package sbt.internal.librarymanagement
|
|||
import java.util.Locale
|
||||
|
||||
object StringUtilities {
|
||||
@deprecated("Different use cases require different normalization. Use Project.normalizeModuleID or normalizeProjectID instead.", "0.13.0")
|
||||
@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): Unit = require(s.trim.length > 0, label + " cannot be empty.")
|
||||
def nonEmpty(s: String, label: String): Unit =
|
||||
require(s.trim.length > 0, label + " cannot be empty.")
|
||||
def appendable(s: String) = if (s.isEmpty) "" else "_" + s
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@ package internal
|
|||
package librarymanagement
|
||||
|
||||
object VersionRange {
|
||||
|
||||
/** True if the revision is an ivy-range, not a complete revision. */
|
||||
def isVersionRange(revision: String): Boolean = {
|
||||
(revision endsWith "+") ||
|
||||
(revision contains "[") ||
|
||||
(revision contains "]") ||
|
||||
(revision contains "(") ||
|
||||
(revision contains ")")
|
||||
(revision contains "[") ||
|
||||
(revision contains "]") ||
|
||||
(revision contains "(") ||
|
||||
(revision contains ")")
|
||||
}
|
||||
|
||||
// Assuming Ivy is used to resolve conflict, this removes the version range
|
||||
|
|
@ -50,13 +51,15 @@ object VersionRange {
|
|||
val maxDigit = 5
|
||||
try {
|
||||
revision match {
|
||||
case "+" => "[0,)"
|
||||
case DotPlusPattern(base) => plusRange(base)
|
||||
case "+" => "[0,)"
|
||||
case DotPlusPattern(base) => plusRange(base)
|
||||
// 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.
|
||||
case NumPlusPattern(tail) => (0 until maxDigit).map(plusRange(tail, _)).mkString(",")
|
||||
case DotNumPlusPattern(base, tail) => (0 until maxDigit).map(plusRange(base + "." + tail, _)).mkString(",")
|
||||
case rev if rev endsWith "+" => sys.error(s"dynamic revision '$rev' cannot be translated to POM")
|
||||
case NumPlusPattern(tail) => (0 until maxDigit).map(plusRange(tail, _)).mkString(",")
|
||||
case DotNumPlusPattern(base, tail) =>
|
||||
(0 until maxDigit).map(plusRange(base + "." + tail, _)).mkString(",")
|
||||
case rev if rev endsWith "+" =>
|
||||
sys.error(s"dynamic revision '$rev' cannot be translated to POM")
|
||||
case rev if startSym(rev(0)) && stopSym(rev(rev.length - 1)) =>
|
||||
val start = rev(0)
|
||||
val stop = rev(rev.length - 1)
|
||||
|
|
@ -79,5 +82,6 @@ object VersionRange {
|
|||
|
||||
private[this] val startSym = Set(']', '[', '(')
|
||||
private[this] val stopSym = Set(']', '[', ')')
|
||||
private[this] val MavenVersionSetPattern = """([\]\[\(])([\w\.\-]+)?(,)?([\w\.\-]+)?([\]\[\)])(,.+)?""".r
|
||||
private[this] val MavenVersionSetPattern =
|
||||
"""([\]\[\(])([\w\.\-]+)?(,)?([\w\.\-]+)?([\]\[\)])(,.+)?""".r
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,65 +12,73 @@ object CrossVersionUtil {
|
|||
val TransitionSbtVersion = "0.12"
|
||||
|
||||
def isFull(s: String): Boolean = (s == trueString) || (s == fullString)
|
||||
def isDisabled(s: String): Boolean = (s == falseString) || (s == noneString) || (s == disabledString)
|
||||
def isDisabled(s: String): Boolean =
|
||||
(s == falseString) || (s == noneString) || (s == disabledString)
|
||||
def isBinary(s: String): Boolean = (s == binaryString)
|
||||
|
||||
private lazy val intPattern = """\d{1,10}"""
|
||||
private lazy val basicVersion = """(""" + intPattern + """)\.(""" + intPattern + """)\.(""" + intPattern + """)"""
|
||||
|
||||
private[sbt] def isSbtApiCompatible(v: String): Boolean = sbtApiVersion(v).isDefined
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
private[sbt] def sbtApiVersion(v: String): Option[(Int, Int)] =
|
||||
{
|
||||
val ReleaseV = (basicVersion + """(-\d+)?""").r
|
||||
val CandidateV = (basicVersion + """(-RC\d+)""").r
|
||||
val NonReleaseV = (basicVersion + """([-\w+]*)""").r
|
||||
v match {
|
||||
case ReleaseV(x, y, z, ht) => Some((x.toInt, y.toInt))
|
||||
case CandidateV(x, y, z, ht) => Some((x.toInt, y.toInt))
|
||||
case NonReleaseV(x, y, z, ht) if z.toInt > 0 => Some((x.toInt, y.toInt))
|
||||
case _ => None
|
||||
}
|
||||
private[sbt] def sbtApiVersion(v: String): Option[(Int, Int)] = {
|
||||
val ReleaseV = (basicVersion + """(-\d+)?""").r
|
||||
val CandidateV = (basicVersion + """(-RC\d+)""").r
|
||||
val NonReleaseV = (basicVersion + """([-\w+]*)""").r
|
||||
v match {
|
||||
case ReleaseV(x, y, z, ht) => Some((x.toInt, y.toInt))
|
||||
case CandidateV(x, y, z, ht) => Some((x.toInt, y.toInt))
|
||||
case NonReleaseV(x, y, z, ht) if z.toInt > 0 => Some((x.toInt, y.toInt))
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
private[sbt] def isScalaApiCompatible(v: String): Boolean = scalaApiVersion(v).isDefined
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private[sbt] def scalaApiVersion(v: String): Option[(Int, Int)] =
|
||||
{
|
||||
val ReleaseV = (basicVersion + """(-\d+)?""").r
|
||||
val BinCompatV = (basicVersion + """-bin(-.*)?""").r
|
||||
val NonReleaseV = (basicVersion + """(-\w+)""").r
|
||||
v match {
|
||||
case ReleaseV(x, y, z, ht) => Some((x.toInt, y.toInt))
|
||||
case BinCompatV(x, y, z, ht) => Some((x.toInt, y.toInt))
|
||||
case NonReleaseV(x, y, z, ht) if z.toInt > 0 => Some((x.toInt, y.toInt))
|
||||
case _ => None
|
||||
}
|
||||
private[sbt] def scalaApiVersion(v: String): Option[(Int, Int)] = {
|
||||
val ReleaseV = (basicVersion + """(-\d+)?""").r
|
||||
val BinCompatV = (basicVersion + """-bin(-.*)?""").r
|
||||
val NonReleaseV = (basicVersion + """(-\w+)""").r
|
||||
v match {
|
||||
case ReleaseV(x, y, z, ht) => Some((x.toInt, y.toInt))
|
||||
case BinCompatV(x, y, z, ht) => Some((x.toInt, y.toInt))
|
||||
case NonReleaseV(x, y, z, ht) if z.toInt > 0 => Some((x.toInt, y.toInt))
|
||||
case _ => None
|
||||
}
|
||||
private[sbt] val PartialVersion = ("""(""" + intPattern + """)\.(""" + intPattern + """)(?:\..+)?""").r
|
||||
}
|
||||
private[sbt] val PartialVersion =
|
||||
("""(""" + intPattern + """)\.(""" + intPattern + """)(?:\..+)?""").r
|
||||
private[sbt] def partialVersion(s: String): Option[(Int, Int)] =
|
||||
s match {
|
||||
case PartialVersion(major, minor) => Some((major.toInt, minor.toInt))
|
||||
case _ => None
|
||||
}
|
||||
def binaryScalaVersion(full: String): String = binaryVersionWithApi(full, TransitionScalaVersion)(scalaApiVersion)
|
||||
def binarySbtVersion(full: String): String = binaryVersionWithApi(full, TransitionSbtVersion)(sbtApiVersion)
|
||||
private[sbt] def binaryVersion(full: String, cutoff: String): String = binaryVersionWithApi(full, cutoff)(scalaApiVersion)
|
||||
def binaryScalaVersion(full: String): String =
|
||||
binaryVersionWithApi(full, TransitionScalaVersion)(scalaApiVersion)
|
||||
def binarySbtVersion(full: String): String =
|
||||
binaryVersionWithApi(full, TransitionSbtVersion)(sbtApiVersion)
|
||||
private[sbt] def binaryVersion(full: String, cutoff: String): String =
|
||||
binaryVersionWithApi(full, cutoff)(scalaApiVersion)
|
||||
private[this] def isNewer(major: Int, minor: Int, minMajor: Int, minMinor: Int): Boolean =
|
||||
major > minMajor || (major == minMajor && minor >= minMinor)
|
||||
private[this] def binaryVersionWithApi(full: String, cutoff: String)(apiVersion: String => Option[(Int, Int)]): String =
|
||||
{
|
||||
def sub(major: Int, minor: Int) = major + "." + minor
|
||||
(apiVersion(full), partialVersion(cutoff)) match {
|
||||
case (Some((major, minor)), None) => sub(major, minor)
|
||||
case (Some((major, minor)), Some((minMajor, minMinor))) if isNewer(major, minor, minMajor, minMinor) => sub(major, minor)
|
||||
case _ => full
|
||||
}
|
||||
private[this] def binaryVersionWithApi(full: String, cutoff: String)(
|
||||
apiVersion: String => Option[(Int, Int)]
|
||||
): String = {
|
||||
def sub(major: Int, minor: Int) = major + "." + minor
|
||||
(apiVersion(full), partialVersion(cutoff)) match {
|
||||
case (Some((major, minor)), None) => sub(major, minor)
|
||||
case (Some((major, minor)), Some((minMajor, minMinor)))
|
||||
if isNewer(major, minor, minMajor, minMinor) =>
|
||||
sub(major, minor)
|
||||
case _ => full
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,15 +8,23 @@ trait UpdateOptionsFormat { self: BasicJsonProtocol =>
|
|||
|
||||
implicit lazy val UpdateOptionsFormat: JsonFormat[UpdateOptions] =
|
||||
project(
|
||||
(uo: UpdateOptions) => (
|
||||
uo.circularDependencyLevel.name,
|
||||
uo.interProjectFirst,
|
||||
uo.latestSnapshots,
|
||||
uo.consolidatedResolution,
|
||||
uo.cachedResolution
|
||||
(uo: UpdateOptions) =>
|
||||
(
|
||||
uo.circularDependencyLevel.name,
|
||||
uo.interProjectFirst,
|
||||
uo.latestSnapshots,
|
||||
uo.consolidatedResolution,
|
||||
uo.cachedResolution
|
||||
),
|
||||
(xs: (String, Boolean, Boolean, Boolean, Boolean)) =>
|
||||
new UpdateOptions(levels(xs._1), xs._2, xs._3, xs._4, xs._5, ConvertResolver.defaultConvert)
|
||||
new UpdateOptions(
|
||||
levels(xs._1),
|
||||
xs._2,
|
||||
xs._3,
|
||||
xs._4,
|
||||
xs._5,
|
||||
ConvertResolver.defaultConvert
|
||||
)
|
||||
)
|
||||
|
||||
private val levels: Map[String, CircularDependencyLevel] = Map(
|
||||
|
|
|
|||
|
|
@ -8,58 +8,51 @@ import StringUtilities.nonEmpty
|
|||
import sbt.librarymanagement._
|
||||
|
||||
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 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] (private[sbt] val groupID: String) {
|
||||
def %(artifactID: String) = groupArtifact(artifactID, Disabled())
|
||||
def %%(artifactID: String): GroupArtifactID = groupArtifact(artifactID, CrossVersion.binary)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
final class GroupArtifactID private[sbt] (
|
||||
private[sbt] val groupID: String,
|
||||
private[sbt] val artifactID: String,
|
||||
private[sbt] val crossVersion: CrossVersion
|
||||
private[sbt] val groupID: String,
|
||||
private[sbt] val artifactID: String,
|
||||
private[sbt] val crossVersion: CrossVersion
|
||||
) {
|
||||
def %(revision: String): ModuleID =
|
||||
{
|
||||
nonEmpty(revision, "Revision")
|
||||
ModuleID(groupID, artifactID, revision).cross(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)
|
||||
|
||||
def %(configurations: String): ModuleID =
|
||||
{
|
||||
nonEmpty(configurations, "Configurations")
|
||||
val c = configurations
|
||||
moduleID.withConfigurations(configurations = Some(c))
|
||||
}
|
||||
def %(configurations: String): ModuleID = {
|
||||
nonEmpty(configurations, "Configurations")
|
||||
val c = configurations
|
||||
moduleID.withConfigurations(configurations = Some(c))
|
||||
}
|
||||
}
|
||||
final class RepositoryName private[sbt] (name: String) {
|
||||
def at(location: String) =
|
||||
{
|
||||
nonEmpty(location, "Repository location")
|
||||
MavenRepository(name, location)
|
||||
}
|
||||
def at(location: String) = {
|
||||
nonEmpty(location, "Repository location")
|
||||
MavenRepository(name, location)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -5,8 +5,7 @@ import org.apache.ivy.plugins.resolver.DependencyResolver
|
|||
import sbt.librarymanagement._
|
||||
|
||||
// These are placeholder traits for sbt-aether-resolver
|
||||
trait CustomMavenResolver extends DependencyResolver {
|
||||
}
|
||||
trait CustomMavenResolver extends DependencyResolver {}
|
||||
trait CustomRemoteMavenResolver extends CustomMavenResolver {
|
||||
def repo: MavenRepository
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@ object ErrorMessageAuthenticator {
|
|||
case originalOpt => installIntoIvyImpl(originalOpt)
|
||||
} catch {
|
||||
case t: Throwable =>
|
||||
Message.debug("Error occurred while trying to install debug messages into Ivy Authentication" + t.getMessage)
|
||||
Message.debug(
|
||||
"Error occurred while trying to install debug messages into Ivy Authentication" + t.getMessage
|
||||
)
|
||||
}
|
||||
Some(ivy)
|
||||
}
|
||||
|
|
@ -57,8 +59,10 @@ object ErrorMessageAuthenticator {
|
|||
catch {
|
||||
case e: SecurityException if !securityWarningLogged =>
|
||||
securityWarningLogged = true
|
||||
Message.warn("Not enough permissions to set the ErrorMessageAuthenticator. "
|
||||
+ "Helpful debug messages disabled!");
|
||||
Message.warn(
|
||||
"Not enough permissions to set the ErrorMessageAuthenticator. "
|
||||
+ "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
|
||||
|
|
@ -73,6 +77,7 @@ object ErrorMessageAuthenticator {
|
|||
doInstallIfIvy(originalAuthenticator)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An authenticator which just delegates to a previous authenticator and issues *nice*
|
||||
* error messages on failure to find credentials.
|
||||
|
|
@ -80,7 +85,8 @@ object ErrorMessageAuthenticator {
|
|||
* 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 {
|
||||
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
|
||||
|
|
@ -104,14 +110,16 @@ private[sbt] final class ErrorMessageAuthenticator(original: Option[Authenticato
|
|||
// Grabs the authentication that would have been provided had we not been installed...
|
||||
def originalAuthentication: Option[PasswordAuthentication] = {
|
||||
Authenticator.setDefault(original.orNull)
|
||||
try Option(Authenticator.requestPasswordAuthentication(
|
||||
getRequestingHost,
|
||||
getRequestingSite,
|
||||
getRequestingPort,
|
||||
getRequestingProtocol,
|
||||
getRequestingPrompt,
|
||||
getRequestingScheme
|
||||
))
|
||||
try Option(
|
||||
Authenticator.requestPasswordAuthentication(
|
||||
getRequestingHost,
|
||||
getRequestingSite,
|
||||
getRequestingPort,
|
||||
getRequestingProtocol,
|
||||
getRequestingPrompt,
|
||||
getRequestingScheme
|
||||
)
|
||||
)
|
||||
finally Authenticator.setDefault(this)
|
||||
}
|
||||
originalAuthentication.orNull
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ import collection.JavaConverters._
|
|||
|
||||
/** A key used to store credentials in the ivy credentials store. */
|
||||
private[sbt] sealed trait CredentialKey
|
||||
|
||||
/** Represents a key in the ivy credentials store that is only specific to a host. */
|
||||
private[sbt] case class Host(name: String) extends CredentialKey
|
||||
|
||||
/** Represents a key in the ivy credentials store that is keyed to both a host and a "realm". */
|
||||
private[sbt] case class Realm(host: String, realm: String) extends CredentialKey
|
||||
|
||||
|
|
@ -61,4 +63,4 @@ private[sbt] object IvyCredentialsLookup {
|
|||
} mapValues { realms =>
|
||||
realms map (_.realm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,25 +13,25 @@ private[sbt] object MergeDescriptors {
|
|||
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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// combines the artifacts, configurations, includes, and excludes for DependencyDescriptors `a` and `b`
|
||||
// that otherwise have equal IDs
|
||||
private[sbt] final case class MergedDescriptors(a: DependencyDescriptor, b: DependencyDescriptor) extends DependencyDescriptor {
|
||||
private[sbt] final case class MergedDescriptors(a: DependencyDescriptor, b: DependencyDescriptor)
|
||||
extends DependencyDescriptor {
|
||||
def getDependencyId = a.getDependencyId
|
||||
def isForce = a.isForce
|
||||
def isChanging = a.isChanging
|
||||
|
|
@ -44,21 +44,41 @@ private[sbt] final case class MergedDescriptors(a: DependencyDescriptor, b: Depe
|
|||
def getModuleConfigurations = concat(a.getModuleConfigurations, b.getModuleConfigurations)
|
||||
|
||||
def getDependencyConfigurations(moduleConfiguration: String, requestedConfiguration: String) =
|
||||
concat(a.getDependencyConfigurations(moduleConfiguration, requestedConfiguration), b.getDependencyConfigurations(moduleConfiguration))
|
||||
concat(
|
||||
a.getDependencyConfigurations(moduleConfiguration, requestedConfiguration),
|
||||
b.getDependencyConfigurations(moduleConfiguration)
|
||||
)
|
||||
|
||||
def getDependencyConfigurations(moduleConfiguration: String) =
|
||||
concat(a.getDependencyConfigurations(moduleConfiguration), b.getDependencyConfigurations(moduleConfiguration))
|
||||
concat(
|
||||
a.getDependencyConfigurations(moduleConfiguration),
|
||||
b.getDependencyConfigurations(moduleConfiguration)
|
||||
)
|
||||
|
||||
def getDependencyConfigurations(moduleConfigurations: Array[String]) =
|
||||
concat(a.getDependencyConfigurations(moduleConfigurations), b.getDependencyConfigurations(moduleConfigurations))
|
||||
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))
|
||||
concatArtifacts(
|
||||
a,
|
||||
a.getDependencyArtifacts(moduleConfigurations),
|
||||
b,
|
||||
b.getDependencyArtifacts(moduleConfigurations)
|
||||
)
|
||||
|
||||
def getDependencyArtifacts(moduleConfigurations: Array[String]) =
|
||||
concatArtifacts(a, a.getDependencyArtifacts(moduleConfigurations), b, b.getDependencyArtifacts(moduleConfigurations))
|
||||
concatArtifacts(
|
||||
a,
|
||||
a.getDependencyArtifacts(moduleConfigurations),
|
||||
b,
|
||||
b.getDependencyArtifacts(moduleConfigurations)
|
||||
)
|
||||
|
||||
def getAllIncludeRules = concat(a.getAllIncludeRules, b.getAllIncludeRules)
|
||||
|
||||
|
|
@ -68,61 +88,99 @@ private[sbt] final case class MergedDescriptors(a: DependencyDescriptor, b: Depe
|
|||
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 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, arts: Array[DependencyArtifactDescriptor]): Array[DependencyArtifactDescriptor] =
|
||||
arts map { art => explicitConfigurations(base, art) }
|
||||
private[this] def explicitConfigurations(base: DependencyDescriptor, art: DependencyArtifactDescriptor): DependencyArtifactDescriptor =
|
||||
{
|
||||
val aConfs = Option(art.getConfigurations) map { _.toList }
|
||||
// In case configuration list is "*", we should still specify the module configuration of the DependencyDescriptor
|
||||
// otherwise the explicit specified artifacts from one dd can leak over to the other.
|
||||
// See gh-1500, gh-2002
|
||||
aConfs match {
|
||||
case None | Some(Nil) | Some(List("*")) => copyWithConfigurations(art, base.getModuleConfigurations)
|
||||
case _ => art
|
||||
}
|
||||
private[this] def explicitConfigurations(
|
||||
base: DependencyDescriptor,
|
||||
art: DependencyArtifactDescriptor
|
||||
): DependencyArtifactDescriptor = {
|
||||
val aConfs = Option(art.getConfigurations) map { _.toList }
|
||||
// In case configuration list is "*", we should still specify the module configuration of the DependencyDescriptor
|
||||
// otherwise the explicit specified artifacts from one dd can leak over to the other.
|
||||
// See gh-1500, gh-2002
|
||||
aConfs match {
|
||||
case None | Some(Nil) | Some(List("*")) =>
|
||||
copyWithConfigurations(art, base.getModuleConfigurations)
|
||||
case _ => art
|
||||
}
|
||||
private[this] def defaultArtifact(a: DependencyDescriptor): Array[DependencyArtifactDescriptor] =
|
||||
{
|
||||
val dd = new DefaultDependencyArtifactDescriptor(a, a.getDependencyRevisionId.getName, "jar", "jar", null, null)
|
||||
addConfigurations(dd, a.getModuleConfigurations)
|
||||
// If the dependency descriptor is empty, then it means that it has been created from a POM file. In this case,
|
||||
// it is correct to create a seemingly non-existent dependency artifact.
|
||||
if (a.getAllDependencyArtifacts.isEmpty) Array(dd)
|
||||
else a.getAllDependencyArtifacts filter (_ == 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 =
|
||||
}
|
||||
private[this] def defaultArtifact(a: DependencyDescriptor): Array[DependencyArtifactDescriptor] = {
|
||||
val dd = new DefaultDependencyArtifactDescriptor(
|
||||
a,
|
||||
a.getDependencyRevisionId.getName,
|
||||
"jar",
|
||||
"jar",
|
||||
null,
|
||||
null
|
||||
)
|
||||
addConfigurations(dd, a.getModuleConfigurations)
|
||||
// If the dependency descriptor is empty, then it means that it has been created from a POM file. In this case,
|
||||
// it is correct to create a seemingly non-existent dependency artifact.
|
||||
if (a.getAllDependencyArtifacts.isEmpty) Array(dd)
|
||||
else a.getAllDependencyArtifacts filter (_ == 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: reflect.ClassTag](a: Array[T], b: Array[T]): Array[T] = (a ++ b).distinct
|
||||
private[this] def concat[T: reflect.ClassTag](a: Array[T], b: Array[T]): Array[T] =
|
||||
(a ++ b).distinct
|
||||
|
||||
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 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
|
||||
|
|
|
|||
|
|
@ -7,7 +7,12 @@ import java.util.Date
|
|||
|
||||
import org.apache.ivy.core.settings.IvySettings
|
||||
import org.apache.ivy.core.{ IvyContext, LogOptions }
|
||||
import org.apache.ivy.core.module.descriptor.{ Artifact => IArtifact, DefaultModuleDescriptor, ModuleDescriptor, DependencyDescriptor }
|
||||
import org.apache.ivy.core.module.descriptor.{
|
||||
Artifact => IArtifact,
|
||||
DefaultModuleDescriptor,
|
||||
ModuleDescriptor,
|
||||
DependencyDescriptor
|
||||
}
|
||||
import org.apache.ivy.core.resolve.{ ResolvedModuleRevision, ResolveData }
|
||||
import org.apache.ivy.plugins.latest.LatestStrategy
|
||||
import org.apache.ivy.plugins.repository.file.{ FileRepository => IFileRepository, FileResource }
|
||||
|
|
@ -19,11 +24,11 @@ import sbt.util.Logger
|
|||
import sbt.librarymanagement._
|
||||
|
||||
private[sbt] case class SbtChainResolver(
|
||||
name: String,
|
||||
resolvers: Seq[DependencyResolver],
|
||||
settings: IvySettings,
|
||||
updateOptions: UpdateOptions,
|
||||
log: Logger
|
||||
name: String,
|
||||
resolvers: Seq[DependencyResolver],
|
||||
settings: IvySettings,
|
||||
updateOptions: UpdateOptions,
|
||||
log: Logger
|
||||
) extends ChainResolver {
|
||||
|
||||
override def equals(o: Any): Boolean = o match {
|
||||
|
|
@ -35,15 +40,14 @@ private[sbt] case class SbtChainResolver(
|
|||
case _ => false
|
||||
}
|
||||
|
||||
override def hashCode: Int =
|
||||
{
|
||||
var hash = 1
|
||||
hash = hash * 31 + this.name.##
|
||||
hash = hash * 31 + this.resolvers.##
|
||||
hash = hash * 31 + this.settings.##
|
||||
hash = hash * 31 + this.updateOptions.##
|
||||
hash
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
var hash = 1
|
||||
hash = hash * 31 + this.name.##
|
||||
hash = hash * 31 + this.resolvers.##
|
||||
hash = hash * 31 + this.settings.##
|
||||
hash = hash * 31 + this.updateOptions.##
|
||||
hash
|
||||
}
|
||||
|
||||
// TODO - We need to special case the project resolver so it always "wins" when resolving with inter-project dependencies.
|
||||
|
||||
|
|
@ -67,105 +71,119 @@ private[sbt] case class SbtChainResolver(
|
|||
//
|
||||
// Ideally this could just skip the lookup, but unfortunately several artifacts in practice do not follow the
|
||||
// correct behavior for packaging="pom" and so it is only skipped for source/javadoc classifiers.
|
||||
override def locate(artifact: IArtifact) = if (IvySbt.hasImplicitClassifier(artifact)) null else super.locate(artifact)
|
||||
override def locate(artifact: IArtifact) =
|
||||
if (IvySbt.hasImplicitClassifier(artifact)) null else super.locate(artifact)
|
||||
|
||||
override def getDependency(dd: DependencyDescriptor, data: ResolveData) =
|
||||
{
|
||||
if (data.getOptions.getLog != LogOptions.LOG_QUIET)
|
||||
Message.debug("Resolving " + dd.getDependencyRevisionId + " ...")
|
||||
val gd = doGetDependency(dd, data)
|
||||
val mod = IvySbt.resetArtifactResolver(gd)
|
||||
mod
|
||||
}
|
||||
override def getDependency(dd: DependencyDescriptor, data: ResolveData) = {
|
||||
if (data.getOptions.getLog != LogOptions.LOG_QUIET)
|
||||
Message.debug("Resolving " + dd.getDependencyRevisionId + " ...")
|
||||
val gd = doGetDependency(dd, data)
|
||||
val mod = IvySbt.resetArtifactResolver(gd)
|
||||
mod
|
||||
}
|
||||
// Modified implementation of ChainResolver#getDependency.
|
||||
// When the dependency is changing, it will check all resolvers on the chain
|
||||
// regardless of what the "latest strategy" is set, and look for the published date
|
||||
// or the module descriptor to sort them.
|
||||
// This implementation also skips resolution if "return first" is set to true,
|
||||
// and if a previously resolved or cached revision has been found.
|
||||
def doGetDependency(dd: DependencyDescriptor, data0: ResolveData): ResolvedModuleRevision =
|
||||
{
|
||||
// useLatest - Means we should always download the JARs from the internet, no matter what.
|
||||
// This will only be true *IF* the depenendency is dynamic/changing *and* latestSnapshots is true.
|
||||
// If you find multiple candidates,
|
||||
// - If `isReturnFirst` is true, you return the first value found
|
||||
// - If not, we will ATTEMPT to look at the publish date, which is not correctly discovered for Maven modules and
|
||||
// leads to undefined behavior.
|
||||
val useLatest = (dd.isChanging || IvySbt.isChanging(dd.getDependencyRevisionId)) && updateOptions.latestSnapshots
|
||||
if (useLatest) {
|
||||
Message.verbose(s"$getName is changing. Checking all resolvers on the chain")
|
||||
}
|
||||
val data = new ResolveData(data0, doValidate(data0))
|
||||
// Returns the value if we've already been resolved from some other branch of the resolution tree.
|
||||
val resolved = Option(data.getCurrentResolvedModuleRevision)
|
||||
// If we don't have any previously resolved date, we try to pull the value from the cache.
|
||||
val resolvedOrCached =
|
||||
resolved orElse {
|
||||
Message.verbose(getName + ": Checking cache for: " + dd)
|
||||
Option(findModuleInCache(dd, data, true)) map { mr =>
|
||||
Message.verbose(getName + ": module revision found in cache: " + mr.getId)
|
||||
forcedRevision(mr)
|
||||
}
|
||||
def doGetDependency(dd: DependencyDescriptor, data0: ResolveData): ResolvedModuleRevision = {
|
||||
// useLatest - Means we should always download the JARs from the internet, no matter what.
|
||||
// This will only be true *IF* the depenendency is dynamic/changing *and* latestSnapshots is true.
|
||||
// If you find multiple candidates,
|
||||
// - If `isReturnFirst` is true, you return the first value found
|
||||
// - If not, we will ATTEMPT to look at the publish date, which is not correctly discovered for Maven modules and
|
||||
// leads to undefined behavior.
|
||||
val useLatest = (dd.isChanging || IvySbt.isChanging(dd.getDependencyRevisionId)) && updateOptions.latestSnapshots
|
||||
if (useLatest) {
|
||||
Message.verbose(s"$getName is changing. Checking all resolvers on the chain")
|
||||
}
|
||||
val data = new ResolveData(data0, doValidate(data0))
|
||||
// Returns the value if we've already been resolved from some other branch of the resolution tree.
|
||||
val resolved = Option(data.getCurrentResolvedModuleRevision)
|
||||
// If we don't have any previously resolved date, we try to pull the value from the cache.
|
||||
val resolvedOrCached =
|
||||
resolved orElse {
|
||||
Message.verbose(getName + ": Checking cache for: " + dd)
|
||||
Option(findModuleInCache(dd, data, true)) map { mr =>
|
||||
Message.verbose(getName + ": module revision found in cache: " + mr.getId)
|
||||
forcedRevision(mr)
|
||||
}
|
||||
}
|
||||
|
||||
// Default value for resolution. We use this while we loop...
|
||||
// If useLatest is true, we want to try to download from the internet so we DO NOT start with a valid value.
|
||||
var temp: Option[ResolvedModuleRevision] =
|
||||
if (useLatest) None
|
||||
else resolvedOrCached
|
||||
// Cast resolvers to something useful. TODO - we dropping anything here?
|
||||
val resolvers = getResolvers.toArray.toVector collect { case x: DependencyResolver => x }
|
||||
val interProjResolver = resolvers find { x => x.getName == ProjectResolver.InterProject }
|
||||
// Default value for resolution. We use this while we loop...
|
||||
// If useLatest is true, we want to try to download from the internet so we DO NOT start with a valid value.
|
||||
var temp: Option[ResolvedModuleRevision] =
|
||||
if (useLatest) None
|
||||
else resolvedOrCached
|
||||
// Cast resolvers to something useful. TODO - we dropping anything here?
|
||||
val resolvers = getResolvers.toArray.toVector collect { case x: DependencyResolver => x }
|
||||
val interProjResolver = resolvers find { x =>
|
||||
x.getName == ProjectResolver.InterProject
|
||||
}
|
||||
|
||||
// Here we do an attempt to resolve the artifact from each of the resolvers in the chain.
|
||||
// - If we have a return value already, AND isReturnFirst is true AND useLatest is false, we DO NOT resolve anything
|
||||
// - If we do not, try to resolve.
|
||||
// RETURNS: Left -> Error
|
||||
// Right -> Some(resolved module) // Found in this resolver, can use this result.
|
||||
// Right -> None // Do not use this resolver
|
||||
lazy val results = resolvers map { x =>
|
||||
// if the revision is cached and isReturnFirst is set, don't bother hitting any resolvers, just return None for this guy.
|
||||
if (isReturnFirst && temp.isDefined && !useLatest) Right(None)
|
||||
else {
|
||||
// We actually do resolution.
|
||||
val resolver = x
|
||||
val oldLatest: Option[LatestStrategy] = setLatestIfRequired(resolver, Option(getLatestStrategy))
|
||||
try {
|
||||
val previouslyResolved = temp
|
||||
// if the module qualifies as changing, then resolve all resolvers
|
||||
if (useLatest) data.setCurrentResolvedModuleRevision(null)
|
||||
else data.setCurrentResolvedModuleRevision(temp.orNull)
|
||||
temp = Option(resolver.getDependency(dd, data))
|
||||
Right(
|
||||
if (temp eq previouslyResolved) None
|
||||
else if (useLatest) temp map { x =>
|
||||
(reparseModuleDescriptor(dd, data, resolver, x), resolver)
|
||||
// Here we do an attempt to resolve the artifact from each of the resolvers in the chain.
|
||||
// - If we have a return value already, AND isReturnFirst is true AND useLatest is false, we DO NOT resolve anything
|
||||
// - If we do not, try to resolve.
|
||||
// RETURNS: Left -> Error
|
||||
// Right -> Some(resolved module) // Found in this resolver, can use this result.
|
||||
// Right -> None // Do not use this resolver
|
||||
lazy val results = resolvers map { x =>
|
||||
// if the revision is cached and isReturnFirst is set, don't bother hitting any resolvers, just return None for this guy.
|
||||
if (isReturnFirst && temp.isDefined && !useLatest) Right(None)
|
||||
else {
|
||||
// We actually do resolution.
|
||||
val resolver = x
|
||||
val oldLatest: Option[LatestStrategy] =
|
||||
setLatestIfRequired(resolver, Option(getLatestStrategy))
|
||||
try {
|
||||
val previouslyResolved = temp
|
||||
// if the module qualifies as changing, then resolve all resolvers
|
||||
if (useLatest) data.setCurrentResolvedModuleRevision(null)
|
||||
else data.setCurrentResolvedModuleRevision(temp.orNull)
|
||||
temp = Option(resolver.getDependency(dd, data))
|
||||
Right(
|
||||
if (temp eq previouslyResolved) None
|
||||
else if (useLatest) temp map { x =>
|
||||
(reparseModuleDescriptor(dd, data, resolver, x), resolver)
|
||||
} else
|
||||
temp map { x =>
|
||||
(forcedRevision(x), resolver)
|
||||
}
|
||||
else temp map { x => (forcedRevision(x), resolver) }
|
||||
)
|
||||
} catch {
|
||||
case ex: Exception =>
|
||||
Message.verbose(
|
||||
"problem occurred while resolving " + dd + " with " + resolver
|
||||
+ ": " + IvyStringUtils.getStackTrace(ex)
|
||||
)
|
||||
} catch {
|
||||
case ex: Exception =>
|
||||
Message.verbose("problem occurred while resolving " + dd + " with " + resolver
|
||||
+ ": " + IvyStringUtils.getStackTrace(ex))
|
||||
Left(ex)
|
||||
} finally {
|
||||
oldLatest map { _ => doSetLatestStrategy(resolver, oldLatest) }
|
||||
checkInterrupted()
|
||||
Left(ex)
|
||||
} finally {
|
||||
oldLatest map { _ =>
|
||||
doSetLatestStrategy(resolver, oldLatest)
|
||||
}
|
||||
checkInterrupted()
|
||||
}
|
||||
}
|
||||
lazy val errors = results collect { case Left(e) => e }
|
||||
}
|
||||
lazy val errors = results collect { case Left(e) => e }
|
||||
|
||||
// If the value is arleady in cache, SORTED will be a Seq(None, None, ...) which means we'll fall over to the prevously cached or resolved version.
|
||||
val mrOpt: Option[ResolvedModuleRevision] = {
|
||||
val interProj: Option[ResolvedModuleRevision] =
|
||||
if (updateOptions.interProjectFirst) interProjResolver flatMap { x => Option(x.getDependency(dd, data)) }
|
||||
else None
|
||||
def foundRevisions: Vector[(ResolvedModuleRevision, DependencyResolver)] = results collect { case Right(Some(x)) => x }
|
||||
def sorted =
|
||||
if (useLatest) (foundRevisions.sortBy {
|
||||
// If the value is arleady in cache, SORTED will be a Seq(None, None, ...) which means we'll fall over to the prevously cached or resolved version.
|
||||
val mrOpt: Option[ResolvedModuleRevision] = {
|
||||
val interProj: Option[ResolvedModuleRevision] =
|
||||
if (updateOptions.interProjectFirst) interProjResolver flatMap { x =>
|
||||
Option(x.getDependency(dd, data))
|
||||
} else None
|
||||
def foundRevisions: Vector[(ResolvedModuleRevision, DependencyResolver)] = results collect {
|
||||
case Right(Some(x)) => x
|
||||
}
|
||||
def sorted =
|
||||
if (useLatest)(foundRevisions
|
||||
.sortBy {
|
||||
case (rmr, resolver) =>
|
||||
Message.warn(s"Sorting results from $rmr, using ${rmr.getPublicationDate} and ${rmr.getDescriptor.getPublicationDate}")
|
||||
Message.warn(
|
||||
s"Sorting results from $rmr, using ${rmr.getPublicationDate} and ${rmr.getDescriptor.getPublicationDate}"
|
||||
)
|
||||
// Just issue warning about issues with publication date, and fake one on it for now.
|
||||
Option(rmr.getPublicationDate) orElse Option(rmr.getDescriptor.getPublicationDate) match {
|
||||
case None =>
|
||||
|
|
@ -173,55 +191,75 @@ private[sbt] case class SbtChainResolver(
|
|||
case (null, _) =>
|
||||
// In this instance, the dependency is specified by a direct URL or some other sort of "non-ivy" file
|
||||
if (dd.isChanging)
|
||||
Message.warn(s"Resolving a changing dependency (${rmr.getId}) with no ivy/pom file!, resolution order is undefined!")
|
||||
Message.warn(
|
||||
s"Resolving a changing dependency (${rmr.getId}) with no ivy/pom file!, resolution order is undefined!"
|
||||
)
|
||||
0L
|
||||
case (ivf, dmd: DefaultModuleDescriptor) =>
|
||||
val lmd = new java.util.Date(ivf.getLastModified)
|
||||
Message.debug(s"Getting no publication date from resolver: ${resolver} for ${rmr.getId}, setting to: ${lmd}")
|
||||
Message.debug(
|
||||
s"Getting no publication date from resolver: ${resolver} for ${rmr.getId}, setting to: ${lmd}"
|
||||
)
|
||||
dmd.setPublicationDate(lmd)
|
||||
ivf.getLastModified
|
||||
case _ =>
|
||||
Message.warn(s"Getting null publication date from resolver: ${resolver} for ${rmr.getId}, resolution order is undefined!")
|
||||
Message.warn(
|
||||
s"Getting null publication date from resolver: ${resolver} for ${rmr.getId}, resolution order is undefined!"
|
||||
)
|
||||
0L
|
||||
}
|
||||
case Some(date) => // All other cases ok
|
||||
date.getTime
|
||||
}
|
||||
}).reverse.headOption map {
|
||||
case (rmr, resolver) =>
|
||||
Message.warn(s"Choosing $resolver for ${rmr.getId}")
|
||||
// Now that we know the real latest revision, let's force Ivy to use it
|
||||
val artifactOpt = findFirstArtifactRef(rmr.getDescriptor, dd, data, resolver)
|
||||
artifactOpt match {
|
||||
case Some(artifactRef) =>
|
||||
val systemMd = toSystem(rmr.getDescriptor)
|
||||
getRepositoryCacheManager.cacheModuleDescriptor(resolver, artifactRef,
|
||||
toSystem(dd), systemMd.getAllArtifacts.head, None.orNull, getCacheOptions(data))
|
||||
case None => // do nothing. There are modules without artifacts
|
||||
}
|
||||
rmr
|
||||
}
|
||||
else foundRevisions.reverse.headOption map { _._1 } // we have to reverse because resolvers are hit in reverse order.
|
||||
})
|
||||
.reverse
|
||||
.headOption map {
|
||||
case (rmr, resolver) =>
|
||||
Message.warn(s"Choosing $resolver for ${rmr.getId}")
|
||||
// Now that we know the real latest revision, let's force Ivy to use it
|
||||
val artifactOpt = findFirstArtifactRef(rmr.getDescriptor, dd, data, resolver)
|
||||
artifactOpt match {
|
||||
case Some(artifactRef) =>
|
||||
val systemMd = toSystem(rmr.getDescriptor)
|
||||
getRepositoryCacheManager.cacheModuleDescriptor(
|
||||
resolver,
|
||||
artifactRef,
|
||||
toSystem(dd),
|
||||
systemMd.getAllArtifacts.head,
|
||||
None.orNull,
|
||||
getCacheOptions(data)
|
||||
)
|
||||
case None => // do nothing. There are modules without artifacts
|
||||
}
|
||||
rmr
|
||||
} else
|
||||
foundRevisions.reverse.headOption map { _._1 } // we have to reverse because resolvers are hit in reverse order.
|
||||
|
||||
interProj orElse sorted orElse resolvedOrCached
|
||||
}
|
||||
mrOpt match {
|
||||
case None if errors.size == 1 =>
|
||||
errors.head match {
|
||||
case e: RuntimeException => throw e
|
||||
case e: ParseException => throw e
|
||||
case e: Throwable => throw new RuntimeException(e.toString, e)
|
||||
}
|
||||
case None if errors.size > 1 =>
|
||||
val err = (errors.toList map { IvyStringUtils.getErrorMessage }).mkString("\n\t", "\n\t", "\n")
|
||||
throw new RuntimeException(s"several problems occurred while resolving $dd:$err")
|
||||
case _ =>
|
||||
if (resolved == mrOpt) resolved.orNull
|
||||
else (mrOpt map { resolvedRevision }).orNull
|
||||
}
|
||||
interProj orElse sorted orElse resolvedOrCached
|
||||
}
|
||||
mrOpt match {
|
||||
case None if errors.size == 1 =>
|
||||
errors.head match {
|
||||
case e: RuntimeException => throw e
|
||||
case e: ParseException => throw e
|
||||
case e: Throwable => throw new RuntimeException(e.toString, e)
|
||||
}
|
||||
case None if errors.size > 1 =>
|
||||
val err =
|
||||
(errors.toList map { IvyStringUtils.getErrorMessage }).mkString("\n\t", "\n\t", "\n")
|
||||
throw new RuntimeException(s"several problems occurred while resolving $dd:$err")
|
||||
case _ =>
|
||||
if (resolved == mrOpt) resolved.orNull
|
||||
else (mrOpt map { resolvedRevision }).orNull
|
||||
}
|
||||
}
|
||||
// Ivy seem to not want to use the module descriptor found at the latest resolver
|
||||
private[this] def reparseModuleDescriptor(dd: DependencyDescriptor, data: ResolveData, resolver: DependencyResolver, rmr: ResolvedModuleRevision): ResolvedModuleRevision =
|
||||
private[this] def reparseModuleDescriptor(
|
||||
dd: DependencyDescriptor,
|
||||
data: ResolveData,
|
||||
resolver: DependencyResolver,
|
||||
rmr: ResolvedModuleRevision
|
||||
): ResolvedModuleRevision =
|
||||
// TODO - Redownloading/parsing the ivy file is not really the best way to make this correct.
|
||||
// We should figure out a better alternative, or directly attack the resolvers Ivy uses to
|
||||
// give them correct behavior around -SNAPSHOT.
|
||||
|
|
@ -238,49 +276,76 @@ private[sbt] case class SbtChainResolver(
|
|||
case _ => None
|
||||
}
|
||||
} getOrElse {
|
||||
Message.warn(s"Unable to reparse ${dd.getDependencyRevisionId} from $resolver, using ${rmr.getPublicationDate}")
|
||||
Message.warn(
|
||||
s"Unable to reparse ${dd.getDependencyRevisionId} from $resolver, using ${rmr.getPublicationDate}"
|
||||
)
|
||||
rmr
|
||||
}
|
||||
|
||||
/** Ported from BasicResolver#findFirstAirfactRef. */
|
||||
private[this] def findFirstArtifactRef(md: ModuleDescriptor, dd: DependencyDescriptor, data: ResolveData, resolver: DependencyResolver): Option[ResolvedResource] =
|
||||
{
|
||||
def artifactRef(artifact: IArtifact, date: Date): Option[ResolvedResource] =
|
||||
resolver match {
|
||||
case resolver: BasicResolver =>
|
||||
IvyContext.getContext.set(resolver.getName + ".artifact", artifact)
|
||||
try {
|
||||
Option(resolver.doFindArtifactRef(artifact, date)) orElse {
|
||||
Option(artifact.getUrl) map { url =>
|
||||
Message.verbose("\tusing url for " + artifact + ": " + url)
|
||||
val resource =
|
||||
if ("file" == url.getProtocol) new FileResource(new IFileRepository(), new File(url.getPath))
|
||||
else new URLResource(url)
|
||||
new ResolvedResource(resource, artifact.getModuleRevisionId.getRevision)
|
||||
}
|
||||
private[this] def findFirstArtifactRef(
|
||||
md: ModuleDescriptor,
|
||||
dd: DependencyDescriptor,
|
||||
data: ResolveData,
|
||||
resolver: DependencyResolver
|
||||
): Option[ResolvedResource] = {
|
||||
def artifactRef(artifact: IArtifact, date: Date): Option[ResolvedResource] =
|
||||
resolver match {
|
||||
case resolver: BasicResolver =>
|
||||
IvyContext.getContext.set(resolver.getName + ".artifact", artifact)
|
||||
try {
|
||||
Option(resolver.doFindArtifactRef(artifact, date)) orElse {
|
||||
Option(artifact.getUrl) map { url =>
|
||||
Message.verbose("\tusing url for " + artifact + ": " + url)
|
||||
val resource =
|
||||
if ("file" == url.getProtocol)
|
||||
new FileResource(new IFileRepository(), new File(url.getPath))
|
||||
else new URLResource(url)
|
||||
new ResolvedResource(resource, artifact.getModuleRevisionId.getRevision)
|
||||
}
|
||||
} finally {
|
||||
IvyContext.getContext.set(resolver.getName + ".artifact", null)
|
||||
}
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
val artifactRefs = md.getConfigurations.toIterator flatMap { conf =>
|
||||
md.getArtifacts(conf.getName).toIterator flatMap { af =>
|
||||
artifactRef(af, data.getDate).toIterator
|
||||
}
|
||||
} finally {
|
||||
IvyContext.getContext.set(resolver.getName + ".artifact", null)
|
||||
}
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
val artifactRefs = md.getConfigurations.toIterator flatMap { conf =>
|
||||
md.getArtifacts(conf.getName).toIterator flatMap { af =>
|
||||
artifactRef(af, data.getDate).toIterator
|
||||
}
|
||||
if (artifactRefs.hasNext) Some(artifactRefs.next())
|
||||
else None
|
||||
}
|
||||
if (artifactRefs.hasNext) Some(artifactRefs.next())
|
||||
else None
|
||||
}
|
||||
|
||||
/** Ported from ChainResolver#forcedRevision. */
|
||||
private[this] def forcedRevision(rmr: ResolvedModuleRevision): ResolvedModuleRevision =
|
||||
new ResolvedModuleRevision(rmr.getResolver, rmr.getArtifactResolver, rmr.getDescriptor, rmr.getReport, true)
|
||||
new ResolvedModuleRevision(
|
||||
rmr.getResolver,
|
||||
rmr.getArtifactResolver,
|
||||
rmr.getDescriptor,
|
||||
rmr.getReport,
|
||||
true
|
||||
)
|
||||
|
||||
/** Ported from ChainResolver#resolvedRevision. */
|
||||
private[this] def resolvedRevision(rmr: ResolvedModuleRevision): ResolvedModuleRevision =
|
||||
if (isDual) new ResolvedModuleRevision(rmr.getResolver, this, rmr.getDescriptor, rmr.getReport, rmr.isForce)
|
||||
if (isDual)
|
||||
new ResolvedModuleRevision(
|
||||
rmr.getResolver,
|
||||
this,
|
||||
rmr.getDescriptor,
|
||||
rmr.getReport,
|
||||
rmr.isForce
|
||||
)
|
||||
else rmr
|
||||
|
||||
/** Ported from ChainResolver#setLatestIfRequired. */
|
||||
private[this] def setLatestIfRequired(resolver: DependencyResolver, latest: Option[LatestStrategy]): Option[LatestStrategy] =
|
||||
private[this] def setLatestIfRequired(
|
||||
resolver: DependencyResolver,
|
||||
latest: Option[LatestStrategy]
|
||||
): Option[LatestStrategy] =
|
||||
latestStrategyName(resolver) match {
|
||||
case Some(latestName) if latestName != "default" =>
|
||||
val oldLatest = latestStrategy(resolver)
|
||||
|
|
@ -288,20 +353,26 @@ private[sbt] case class SbtChainResolver(
|
|||
oldLatest
|
||||
case _ => None
|
||||
}
|
||||
|
||||
/** Ported from ChainResolver#getLatestStrategyName. */
|
||||
private[this] def latestStrategyName(resolver: DependencyResolver): Option[String] =
|
||||
resolver match {
|
||||
case r: HasLatestStrategy => Some(r.getLatest)
|
||||
case _ => None
|
||||
}
|
||||
|
||||
/** Ported from ChainResolver#getLatest. */
|
||||
private[this] def latestStrategy(resolver: DependencyResolver): Option[LatestStrategy] =
|
||||
resolver match {
|
||||
case r: HasLatestStrategy => Some(r.getLatestStrategy)
|
||||
case _ => None
|
||||
}
|
||||
|
||||
/** Ported from ChainResolver#setLatest. */
|
||||
private[this] def doSetLatestStrategy(resolver: DependencyResolver, latest: Option[LatestStrategy]): Option[LatestStrategy] =
|
||||
private[this] def doSetLatestStrategy(
|
||||
resolver: DependencyResolver,
|
||||
latest: Option[LatestStrategy]
|
||||
): Option[LatestStrategy] =
|
||||
resolver match {
|
||||
case r: HasLatestStrategy =>
|
||||
val oldLatest = latestStrategy(resolver)
|
||||
|
|
|
|||
|
|
@ -25,13 +25,16 @@ object PomExtraDependencyAttributes {
|
|||
val ExtraAttributesKey = "extraDependencyAttributes"
|
||||
val SbtVersionKey = "sbtVersion"
|
||||
val ScalaVersionKey = "scalaVersion"
|
||||
|
||||
/**
|
||||
* Reads the extra dependency attributes out of a maven property.
|
||||
* @param props The properties from an Aether resolution.
|
||||
* @return
|
||||
* A map of module id to extra dependency attributes associated with dependencies on that module.
|
||||
*/
|
||||
def readFromAether(props: java.util.Map[String, AnyRef]): Map[ModuleRevisionId, Map[String, String]] = {
|
||||
def readFromAether(
|
||||
props: java.util.Map[String, AnyRef]
|
||||
): Map[ModuleRevisionId, Map[String, String]] = {
|
||||
import scala.collection.JavaConverters._
|
||||
(props.asScala get ExtraAttributesKey) match {
|
||||
case None => Map.empty
|
||||
|
|
@ -52,7 +55,10 @@ object PomExtraDependencyAttributes {
|
|||
* TODO - maybe we can just parse this directly here. Note the `readFromAether` method uses
|
||||
* whatever we set here.
|
||||
*/
|
||||
def transferDependencyExtraAttributes(from: Properties, to: java.util.Map[String, AnyRef]): Unit =
|
||||
def transferDependencyExtraAttributes(
|
||||
from: Properties,
|
||||
to: java.util.Map[String, AnyRef]
|
||||
): Unit =
|
||||
Option(from.getProperty(ExtraAttributesKey, null)) foreach (to.put(ExtraAttributesKey, _))
|
||||
|
||||
/**
|
||||
|
|
@ -72,16 +78,25 @@ object PomExtraDependencyAttributes {
|
|||
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 })
|
||||
(qualifiedExtra(item) filterKeys { k =>
|
||||
qualifiedIsExtra(k) == include
|
||||
})
|
||||
|
||||
def qualifiedIsExtra(k: String): Boolean = k.endsWith(ScalaVersionKey) || k.endsWith(SbtVersionKey)
|
||||
def qualifiedIsExtra(k: String): Boolean =
|
||||
k.endsWith(ScalaVersionKey) || k.endsWith(SbtVersionKey)
|
||||
|
||||
// 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 scala.collection.JavaConverters._
|
||||
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, filterCustomExtra(id, include = false).asJava)
|
||||
ModuleRevisionId.newInstance(
|
||||
id.getOrganisation,
|
||||
id.getName,
|
||||
id.getBranch,
|
||||
id.getRevision,
|
||||
filterCustomExtra(id, include = false).asJava
|
||||
)
|
||||
}
|
||||
|
||||
/** parses the sequence of dependencies with extra attribute information, with one dependency per line */
|
||||
|
|
|
|||
|
|
@ -16,28 +16,48 @@ abstract class ArtifactExtra {
|
|||
def extraAttributes: Map[String, String]
|
||||
|
||||
protected[this] def copy(
|
||||
name: String = name,
|
||||
`type`: String = `type`,
|
||||
extension: String = extension,
|
||||
classifier: Option[String] = classifier,
|
||||
configurations: Vector[Configuration] = configurations,
|
||||
url: Option[URL] = url,
|
||||
extraAttributes: Map[String, String] = extraAttributes
|
||||
name: String = name,
|
||||
`type`: String = `type`,
|
||||
extension: String = extension,
|
||||
classifier: Option[String] = classifier,
|
||||
configurations: Vector[Configuration] = configurations,
|
||||
url: Option[URL] = url,
|
||||
extraAttributes: Map[String, String] = extraAttributes
|
||||
): Artifact
|
||||
|
||||
def extra(attributes: (String, String)*) = copy(extraAttributes = extraAttributes ++ ModuleID.checkE(attributes))
|
||||
def extra(attributes: (String, String)*) =
|
||||
copy(extraAttributes = extraAttributes ++ ModuleID.checkE(attributes))
|
||||
}
|
||||
|
||||
import Configurations.{ Optional, Pom, Test }
|
||||
|
||||
abstract class ArtifactFunctions {
|
||||
def apply(name: String, extra: Map[String, String]): Artifact = Artifact(name, DefaultType, DefaultExtension, None, Vector.empty, None, extra)
|
||||
def apply(name: String, classifier: String): Artifact = Artifact(name, DefaultType, DefaultExtension, Some(classifier), Vector.empty, None)
|
||||
def apply(name: String, `type`: String, extension: String): Artifact = Artifact(name, `type`, extension, None, Vector.empty, None)
|
||||
def apply(name: String, `type`: String, extension: String, classifier: String): Artifact = Artifact(name, `type`, extension, Some(classifier), Vector.empty, None)
|
||||
def apply(name: String, url: URL): Artifact = Artifact(name, extract(url, DefaultType), extract(url, DefaultExtension), None, Vector.empty, Some(url))
|
||||
def apply(name: String, extra: Map[String, String]): Artifact =
|
||||
Artifact(name, DefaultType, DefaultExtension, None, Vector.empty, None, extra)
|
||||
def apply(name: String, classifier: String): Artifact =
|
||||
Artifact(name, DefaultType, DefaultExtension, Some(classifier), Vector.empty, None)
|
||||
def apply(name: String, `type`: String, extension: String): Artifact =
|
||||
Artifact(name, `type`, extension, None, Vector.empty, None)
|
||||
def apply(name: String, `type`: String, extension: String, classifier: String): Artifact =
|
||||
Artifact(name, `type`, extension, Some(classifier), Vector.empty, None)
|
||||
def apply(name: String, url: URL): Artifact =
|
||||
Artifact(
|
||||
name,
|
||||
extract(url, DefaultType),
|
||||
extract(url, DefaultExtension),
|
||||
None,
|
||||
Vector.empty,
|
||||
Some(url)
|
||||
)
|
||||
|
||||
def apply(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Vector[Configuration], url: Option[URL]): Artifact =
|
||||
def apply(
|
||||
name: String,
|
||||
`type`: String,
|
||||
extension: String,
|
||||
classifier: Option[String],
|
||||
configurations: Vector[Configuration],
|
||||
url: Option[URL]
|
||||
): Artifact =
|
||||
Artifact(name, `type`, extension, classifier, configurations, url, Map.empty[String, String])
|
||||
|
||||
val DefaultExtension = "jar"
|
||||
|
|
@ -66,29 +86,33 @@ abstract class ArtifactFunctions {
|
|||
assert(DefaultSourceTypes contains SourceType)
|
||||
|
||||
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, Vector.empty, 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(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,
|
||||
Vector.empty,
|
||||
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 classifierTypeMap = Map(SourceClassifier -> SourceType, DocClassifier -> DocType)
|
||||
@deprecated("Configuration should not be decided from the classifier.", "1.0")
|
||||
|
|
@ -97,7 +121,8 @@ abstract class ArtifactFunctions {
|
|||
Test
|
||||
else
|
||||
Optional
|
||||
def classifierType(classifier: String): String = classifierTypeMap.getOrElse(classifier.stripPrefix(TestsClassifier + "-"), DefaultType)
|
||||
def classifierType(classifier: String): String =
|
||||
classifierTypeMap.getOrElse(classifier.stripPrefix(TestsClassifier + "-"), DefaultType)
|
||||
|
||||
/**
|
||||
* Create a classified explicit artifact, to be used when trying to resolve sources|javadocs from Maven. This is
|
||||
|
|
@ -105,5 +130,12 @@ abstract class ArtifactFunctions {
|
|||
* The artifact is created under the default configuration.
|
||||
*/
|
||||
def classified(name: String, classifier: String): Artifact =
|
||||
Artifact(name, classifierType(classifier), DefaultExtension, Some(classifier), Vector.empty, None)
|
||||
Artifact(
|
||||
name,
|
||||
classifierType(classifier),
|
||||
DefaultExtension,
|
||||
Some(classifier),
|
||||
Vector.empty,
|
||||
None
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
package sbt.librarymanagement
|
||||
|
||||
import org.apache.ivy.plugins.circular.{ CircularDependencyStrategy, WarnCircularDependencyStrategy, IgnoreCircularDependencyStrategy, ErrorCircularDependencyStrategy }
|
||||
import org.apache.ivy.plugins.circular.{
|
||||
CircularDependencyStrategy,
|
||||
WarnCircularDependencyStrategy,
|
||||
IgnoreCircularDependencyStrategy,
|
||||
ErrorCircularDependencyStrategy
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around circular dependency strategy.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ package sbt.librarymanagement
|
|||
object Configurations {
|
||||
def config(name: String) = Configuration(name)
|
||||
def default: Seq[Configuration] = defaultMavenConfigurations
|
||||
def defaultMavenConfigurations: Seq[Configuration] = Seq(Compile, Runtime, Test, Provided, Optional)
|
||||
def defaultMavenConfigurations: Seq[Configuration] =
|
||||
Seq(Compile, Runtime, Test, Provided, Optional)
|
||||
def defaultInternal: Seq[Configuration] = Seq(CompileInternal, RuntimeInternal, TestInternal)
|
||||
def auxiliary: Seq[Configuration] = Seq(Pom)
|
||||
def names(cs: Seq[Configuration]) = cs.map(_.name)
|
||||
|
|
@ -24,7 +25,8 @@ object Configurations {
|
|||
case _ => c
|
||||
}
|
||||
|
||||
def internal(base: Configuration, ext: Configuration*) = config(base.name + "-internal").extend(ext: _*).hide
|
||||
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)
|
||||
|
||||
|
|
@ -44,15 +46,24 @@ object Configurations {
|
|||
|
||||
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] 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: _*
|
||||
)
|
||||
|
||||
/** Returns true if the configuration should be under the influence of scalaVersion. */
|
||||
private[sbt] def underScalaVersion(c: Configuration): Boolean =
|
||||
c match {
|
||||
case Default | Compile | IntegrationTest | Provided | Runtime | Test | Optional |
|
||||
CompilerPlugin | CompileInternal | RuntimeInternal | TestInternal => true
|
||||
CompilerPlugin | CompileInternal | RuntimeInternal | TestInternal =>
|
||||
true
|
||||
case config =>
|
||||
config.extendsConfigs exists underScalaVersion
|
||||
}
|
||||
|
|
@ -68,8 +79,10 @@ abstract class ConfigurationExtra {
|
|||
require(name != null && !name.isEmpty)
|
||||
require(description != null)
|
||||
|
||||
def describedAs(newDescription: String) = Configuration(name, newDescription, isPublic, extendsConfigs, transitive)
|
||||
def extend(configs: Configuration*) = Configuration(name, description, isPublic, configs.toVector ++ extendsConfigs, transitive)
|
||||
def describedAs(newDescription: String) =
|
||||
Configuration(name, newDescription, isPublic, extendsConfigs, transitive)
|
||||
def extend(configs: Configuration*) =
|
||||
Configuration(name, description, isPublic, configs.toVector ++ extendsConfigs, transitive)
|
||||
def notTransitive = intransitive
|
||||
def intransitive = Configuration(name, description, isPublic, extendsConfigs, false)
|
||||
def hide = Configuration(name, description, false, extendsConfigs, transitive)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@ import sbt.util.{ Logger, Level }
|
|||
* A library foo_2.10 and foo_2.11 can potentially be both included on the
|
||||
* library dependency graph by mistake, but it won't be caught by eviction.
|
||||
*/
|
||||
final case class ConflictWarning(label: String, level: Level.Value, failOnConflict: Boolean) {
|
||||
}
|
||||
final case class ConflictWarning(label: String, level: Level.Value, failOnConflict: Boolean) {}
|
||||
object ConflictWarning {
|
||||
def disable: ConflictWarning = ConflictWarning("", Level.Debug, false)
|
||||
|
||||
|
|
@ -19,10 +18,15 @@ object ConflictWarning {
|
|||
def apply(config: ConflictWarning, report: UpdateReport, log: Logger): Unit = {
|
||||
processCrossVersioned(config, report, log)
|
||||
}
|
||||
private[this] def processCrossVersioned(config: ConflictWarning, report: UpdateReport, log: Logger): Unit = {
|
||||
private[this] def processCrossVersioned(
|
||||
config: ConflictWarning,
|
||||
report: UpdateReport,
|
||||
log: Logger
|
||||
): Unit = {
|
||||
val crossMismatches = crossVersionMismatches(report)
|
||||
if (crossMismatches.nonEmpty) {
|
||||
val pre = s"Modules were resolved with conflicting cross-version suffixes in ${config.label}:\n "
|
||||
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(", ")
|
||||
|
|
@ -30,25 +34,26 @@ object ConflictWarning {
|
|||
}
|
||||
log.log(config.level, conflictMsgs.mkString(pre, "\n ", ""))
|
||||
if (config.failOnConflict) {
|
||||
val summary = crossMismatches.map { case ((org, raw), _) => idString(org, raw) }.mkString(", ")
|
||||
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]
|
||||
}
|
||||
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)
|
||||
}
|
||||
(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
|
||||
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]] =
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ object Credentials {
|
|||
/** Add the provided credentials to Ivy's credentials cache.*/
|
||||
def add(realm: String, host: String, userName: String, passwd: String): Unit =
|
||||
CredentialsStore.INSTANCE.addCredentials(realm, host, userName, passwd)
|
||||
|
||||
/** Load credentials from the given file into Ivy's credentials cache.*/
|
||||
def add(path: File, log: Logger): Unit =
|
||||
loadCredentials(path) match {
|
||||
|
|
@ -29,20 +30,26 @@ object Credentials {
|
|||
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) => sys.error(err)
|
||||
case Right(dc) => dc
|
||||
}
|
||||
case fc: FileCredentials =>
|
||||
loadCredentials(fc.path) match {
|
||||
case Left(err) => sys.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 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"))
|
||||
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")
|
||||
|
|
@ -59,16 +66,20 @@ object Credentials {
|
|||
private[this] val PasswordKeys = List("password", "pwd", "pass", "passwd")
|
||||
|
||||
import collection.JavaConverters._
|
||||
private[this] def read(from: File): Map[String, String] =
|
||||
{
|
||||
val properties = new java.util.Properties
|
||||
IO.load(properties, from)
|
||||
properties.asScala.map { case (k, v) => (k.toString, v.toString.trim) }.toMap
|
||||
}
|
||||
private[this] def read(from: File): Map[String, String] = {
|
||||
val properties = new java.util.Properties
|
||||
IO.load(properties, from)
|
||||
properties.asScala.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 + "')"
|
||||
}
|
||||
final class DirectCredentials(val realm: String, val host: String, val userName: String, val passwd: String) extends Credentials
|
||||
final class DirectCredentials(
|
||||
val realm: String,
|
||||
val host: String,
|
||||
val userName: String,
|
||||
val passwd: String
|
||||
) extends Credentials
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import sbt.internal.librarymanagement.cross.CrossVersionUtil
|
|||
final case class ScalaVersion(full: String, binary: String)
|
||||
|
||||
abstract class CrossVersionFunctions {
|
||||
|
||||
/** 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
|
||||
|
||||
|
|
@ -50,7 +51,11 @@ abstract class CrossVersionFunctions {
|
|||
* full version `fullVersion` and binary version `binaryVersion`. The behavior of the
|
||||
* constructed function is as documented for the [[sbt.librarymanagement.CrossVersion]] datatypes.
|
||||
*/
|
||||
def apply(cross: CrossVersion, fullVersion: String, binaryVersion: String): Option[String => String] =
|
||||
def apply(
|
||||
cross: CrossVersion,
|
||||
fullVersion: String,
|
||||
binaryVersion: String
|
||||
): Option[String => String] =
|
||||
cross match {
|
||||
case _: Disabled => None
|
||||
case b: Binary => append(b.prefix + binaryVersion + b.suffix)
|
||||
|
|
@ -64,10 +69,15 @@ abstract class CrossVersionFunctions {
|
|||
|
||||
/** 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) }
|
||||
is flatMap { i =>
|
||||
apply(module, i)
|
||||
}
|
||||
|
||||
/** Cross-version each `Artifact` in `artifacts` according to cross-version function `cross`. */
|
||||
def substituteCross(artifacts: Vector[Artifact], cross: Option[String => String]): Vector[Artifact] =
|
||||
def substituteCross(
|
||||
artifacts: Vector[Artifact],
|
||||
cross: Option[String => String]
|
||||
): Vector[Artifact] =
|
||||
cross match {
|
||||
case None => artifacts
|
||||
case Some(is) => substituteCrossA(artifacts, cross)
|
||||
|
|
@ -83,9 +93,14 @@ abstract class CrossVersionFunctions {
|
|||
name + "_" + cross
|
||||
|
||||
/** Cross-versions `exclude` according to its `crossVersion`. */
|
||||
private[sbt] def substituteCross(exclude: SbtExclusionRule, is: Option[IvyScala]): SbtExclusionRule = {
|
||||
private[sbt] def substituteCross(
|
||||
exclude: SbtExclusionRule,
|
||||
is: Option[IvyScala]
|
||||
): SbtExclusionRule = {
|
||||
val fopt: Option[String => String] =
|
||||
is flatMap { i => CrossVersion(exclude.crossVersion, i.scalaFullVersion, i.scalaBinaryVersion) }
|
||||
is flatMap { i =>
|
||||
CrossVersion(exclude.crossVersion, i.scalaFullVersion, i.scalaBinaryVersion)
|
||||
}
|
||||
exclude.withName(applyCross(exclude.name, fopt))
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +108,10 @@ abstract class CrossVersionFunctions {
|
|||
def substituteCross(a: Artifact, cross: Option[String => String]): Artifact =
|
||||
a.withName(applyCross(a.name, cross))
|
||||
|
||||
private[sbt] def substituteCrossA(as: Vector[Artifact], cross: Option[String => String]): Vector[Artifact] =
|
||||
private[sbt] def substituteCrossA(
|
||||
as: Vector[Artifact],
|
||||
cross: Option[String => String]
|
||||
): Vector[Artifact] =
|
||||
as.map(art => substituteCross(art, cross))
|
||||
|
||||
/**
|
||||
|
|
@ -101,14 +119,14 @@ abstract class CrossVersionFunctions {
|
|||
* 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.withName(applyCross(m.name, cross)).withExplicitArtifacts(substituteCrossA(m.explicitArtifacts, cross))
|
||||
else
|
||||
m
|
||||
}
|
||||
def apply(scalaFullVersion: String, scalaBinaryVersion: String): ModuleID => ModuleID = m => {
|
||||
val cross = apply(m.crossVersion, scalaFullVersion, scalaBinaryVersion)
|
||||
if (cross.isDefined)
|
||||
m.withName(applyCross(m.name, cross))
|
||||
.withExplicitArtifacts(substituteCrossA(m.explicitArtifacts, cross))
|
||||
else
|
||||
m
|
||||
}
|
||||
|
||||
@deprecated("Use CrossVersion.isScalaApiCompatible or CrossVersion.isSbtApiCompatible", "0.13.0")
|
||||
def isStable(v: String): Boolean = isScalaApiCompatible(v)
|
||||
|
|
@ -152,6 +170,7 @@ abstract class CrossVersionFunctions {
|
|||
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)
|
||||
def binaryVersion(full: String, cutoff: String): String =
|
||||
CrossVersionUtil.binaryVersion(full, cutoff)
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ import sbt.internal.librarymanagement._
|
|||
import sbt.util.Logger
|
||||
import sbt.io.Hash
|
||||
|
||||
class DefaultLibraryManagement(ivyConfiguration: IvyConfiguration, log: Logger) extends LibraryManagement {
|
||||
class DefaultLibraryManagement(ivyConfiguration: IvyConfiguration, log: Logger)
|
||||
extends LibraryManagement {
|
||||
private[sbt] val ivySbt: IvySbt = new IvySbt(ivyConfiguration)
|
||||
private val sbtOrgTemp = JsonUtil.sbtOrgTemp
|
||||
private val modulePrefixTemp = "temp-module-"
|
||||
|
|
@ -22,12 +23,17 @@ class DefaultLibraryManagement(ivyConfiguration: IvyConfiguration, log: Logger)
|
|||
|
||||
def getModule(moduleId: ModuleID, ivyScala: Option[IvyScala]): ivySbt.Module = {
|
||||
val sha1 = Hash.toHex(Hash(moduleId.name))
|
||||
val dummyID = ModuleID(sbtOrgTemp, modulePrefixTemp + sha1, moduleId.revision).withConfigurations(moduleId.configurations)
|
||||
val dummyID = ModuleID(sbtOrgTemp, modulePrefixTemp + sha1, moduleId.revision)
|
||||
.withConfigurations(moduleId.configurations)
|
||||
getModule(dummyID, Vector(moduleId), UpdateOptions(), ivyScala)
|
||||
}
|
||||
|
||||
def getModule(moduleId: ModuleID, deps: Vector[ModuleID],
|
||||
uo: UpdateOptions = UpdateOptions(), ivyScala: Option[IvyScala]): ivySbt.Module = {
|
||||
def getModule(
|
||||
moduleId: ModuleID,
|
||||
deps: Vector[ModuleID],
|
||||
uo: UpdateOptions = UpdateOptions(),
|
||||
ivyScala: Option[IvyScala]
|
||||
): ivySbt.Module = {
|
||||
val moduleSetting = InlineConfiguration(
|
||||
validate = false,
|
||||
ivyScala = ivyScala,
|
||||
|
|
@ -51,14 +57,29 @@ class DefaultLibraryManagement(ivyConfiguration: IvyConfiguration, log: Logger)
|
|||
s"unknown"
|
||||
}
|
||||
|
||||
def update(module: ivySbt.Module, retrieveDirectory: File)(predicate: File => Boolean): Option[Seq[File]] = {
|
||||
def update(module: ivySbt.Module, retrieveDirectory: File)(
|
||||
predicate: File => Boolean
|
||||
): Option[Seq[File]] = {
|
||||
val specialArtifactTypes = Artifact.DefaultSourceTypes union Artifact.DefaultDocTypes
|
||||
val artifactFilter = ArtifactTypeFilter.forbid(specialArtifactTypes)
|
||||
val retrieveConfiguration = RetrieveConfiguration(retrieveDirectory, Resolver.defaultRetrievePattern).withSync(false)
|
||||
val updateConfiguration = UpdateConfiguration(Some(retrieveConfiguration), true, UpdateLogging.DownloadOnly, artifactFilter)
|
||||
val retrieveConfiguration =
|
||||
RetrieveConfiguration(retrieveDirectory, Resolver.defaultRetrievePattern).withSync(false)
|
||||
val updateConfiguration = UpdateConfiguration(
|
||||
Some(retrieveConfiguration),
|
||||
true,
|
||||
UpdateLogging.DownloadOnly,
|
||||
artifactFilter
|
||||
)
|
||||
|
||||
log.debug(s"Attempting to fetch ${dependenciesNames(module)}. This operation may fail.")
|
||||
IvyActions.updateEither(module, updateConfiguration, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, log) match {
|
||||
IvyActions.updateEither(
|
||||
module,
|
||||
updateConfiguration,
|
||||
UnresolvedWarningConfiguration(),
|
||||
LogicalClock.unknown,
|
||||
None,
|
||||
log
|
||||
) match {
|
||||
case Left(unresolvedWarning) =>
|
||||
log.debug(s"Couldn't retrieve module ${dependenciesNames(module)}.")
|
||||
None
|
||||
|
|
|
|||
|
|
@ -6,13 +6,25 @@ package sbt.librarymanagement
|
|||
import sbt.io.{ AllPassFilter, NameFilter }
|
||||
|
||||
trait DependencyFilterExtra {
|
||||
def moduleFilter(organization: NameFilter = AllPassFilter, name: NameFilter = AllPassFilter, revision: NameFilter = AllPassFilter): ModuleFilter =
|
||||
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 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 =
|
||||
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 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 {
|
||||
|
|
@ -20,18 +32,32 @@ trait DependencyFilterExtra {
|
|||
}
|
||||
}
|
||||
object DependencyFilter extends DependencyFilterExtra {
|
||||
def make(configuration: ConfigurationFilter = configurationFilter(), module: ModuleFilter = moduleFilter(), artifact: ArtifactFilter = artifactFilter()): DependencyFilter =
|
||||
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(c: String, m: ModuleID, a: Artifact): Boolean =
|
||||
configuration(c) && module(m) && artifact(a)
|
||||
}
|
||||
def apply(x: DependencyFilter, y: DependencyFilter, combine: (Boolean, Boolean) => Boolean): DependencyFilter =
|
||||
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 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 {
|
||||
|
|
@ -40,23 +66,34 @@ trait DependencyFilter {
|
|||
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 =>
|
||||
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)))
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ import sbt.util.ShowLines
|
|||
import sbt.internal.librarymanagement.{ InlineConfiguration, IvySbt }
|
||||
|
||||
final class EvictionWarningOptions private[sbt] (
|
||||
val configurations: Seq[Configuration],
|
||||
val warnScalaVersionEviction: Boolean,
|
||||
val warnDirectEvictions: Boolean,
|
||||
val warnTransitiveEvictions: Boolean,
|
||||
val infoAllEvictions: Boolean,
|
||||
val showCallers: Boolean,
|
||||
val guessCompatible: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean]
|
||||
val configurations: Seq[Configuration],
|
||||
val warnScalaVersionEviction: Boolean,
|
||||
val warnDirectEvictions: Boolean,
|
||||
val warnTransitiveEvictions: Boolean,
|
||||
val infoAllEvictions: Boolean,
|
||||
val showCallers: Boolean,
|
||||
val guessCompatible: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean]
|
||||
) {
|
||||
private[sbt] def configStrings = configurations map { _.name }
|
||||
|
||||
|
|
@ -30,17 +30,20 @@ final class EvictionWarningOptions private[sbt] (
|
|||
copy(infoAllEvictions = infoAllEvictions)
|
||||
def withShowCallers(showCallers: Boolean): EvictionWarningOptions =
|
||||
copy(showCallers = showCallers)
|
||||
def withGuessCompatible(guessCompatible: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean]): EvictionWarningOptions =
|
||||
def withGuessCompatible(
|
||||
guessCompatible: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean]
|
||||
): EvictionWarningOptions =
|
||||
copy(guessCompatible = guessCompatible)
|
||||
|
||||
private[sbt] def copy(
|
||||
configurations: Seq[Configuration] = configurations,
|
||||
warnScalaVersionEviction: Boolean = warnScalaVersionEviction,
|
||||
warnDirectEvictions: Boolean = warnDirectEvictions,
|
||||
warnTransitiveEvictions: Boolean = warnTransitiveEvictions,
|
||||
infoAllEvictions: Boolean = infoAllEvictions,
|
||||
showCallers: Boolean = showCallers,
|
||||
guessCompatible: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] = guessCompatible
|
||||
configurations: Seq[Configuration] = configurations,
|
||||
warnScalaVersionEviction: Boolean = warnScalaVersionEviction,
|
||||
warnDirectEvictions: Boolean = warnDirectEvictions,
|
||||
warnTransitiveEvictions: Boolean = warnTransitiveEvictions,
|
||||
infoAllEvictions: Boolean = infoAllEvictions,
|
||||
showCallers: Boolean = showCallers,
|
||||
guessCompatible: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] =
|
||||
guessCompatible
|
||||
): EvictionWarningOptions =
|
||||
new EvictionWarningOptions(
|
||||
configurations = configurations,
|
||||
|
|
@ -63,19 +66,26 @@ object EvictionWarningOptions {
|
|||
|
||||
lazy val defaultGuess: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] =
|
||||
guessSecondSegment orElse guessSemVer orElse guessFalse
|
||||
lazy val guessSecondSegment: PartialFunction[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] = {
|
||||
case (m1, Some(m2), Some(ivyScala)) if m2.name.endsWith("_" + ivyScala.scalaFullVersion) || m2.name.endsWith("_" + ivyScala.scalaBinaryVersion) =>
|
||||
lazy val guessSecondSegment
|
||||
: PartialFunction[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] = {
|
||||
case (m1, Some(m2), Some(ivyScala))
|
||||
if m2.name.endsWith("_" + ivyScala.scalaFullVersion) || m2.name.endsWith(
|
||||
"_" + ivyScala.scalaBinaryVersion
|
||||
) =>
|
||||
(m1.revision, m2.revision) match {
|
||||
case (VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2)) =>
|
||||
VersionNumber.SecondSegment.isCompatible(VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2))
|
||||
VersionNumber.SecondSegment
|
||||
.isCompatible(VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2))
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
lazy val guessSemVer: PartialFunction[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] = {
|
||||
lazy val guessSemVer
|
||||
: PartialFunction[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] = {
|
||||
case (m1, Some(m2), _) =>
|
||||
(m1.revision, m2.revision) match {
|
||||
case (VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2)) =>
|
||||
VersionNumber.SemVer.isCompatible(VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2))
|
||||
VersionNumber.SemVer
|
||||
.isCompatible(VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2))
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
|
@ -85,12 +95,12 @@ object EvictionWarningOptions {
|
|||
}
|
||||
|
||||
final class EvictionPair private[sbt] (
|
||||
val organization: String,
|
||||
val name: String,
|
||||
val winner: Option[ModuleReport],
|
||||
val evicteds: Vector[ModuleReport],
|
||||
val includesDirect: Boolean,
|
||||
val showCallers: Boolean
|
||||
val organization: String,
|
||||
val name: String,
|
||||
val winner: Option[ModuleReport],
|
||||
val evicteds: Vector[ModuleReport],
|
||||
val includesDirect: Boolean,
|
||||
val showCallers: Boolean
|
||||
) {
|
||||
override def toString: String =
|
||||
EvictionPair.evictionPairLines.showLines(this).mkString
|
||||
|
|
@ -118,8 +128,7 @@ object EvictionPair {
|
|||
r.callers match {
|
||||
case Seq() => ""
|
||||
case cs => (cs map { _.caller.toString }).mkString(" (caller: ", ", ", ")")
|
||||
}
|
||||
else ""
|
||||
} else ""
|
||||
r.module.revision + callers
|
||||
}) map { " -> " + _ } getOrElse ""
|
||||
Seq(s"\t* ${a.organization}:${a.name}:${revsStr}$winnerRev")
|
||||
|
|
@ -127,29 +136,42 @@ object EvictionPair {
|
|||
}
|
||||
|
||||
final class EvictionWarning private[sbt] (
|
||||
val options: EvictionWarningOptions,
|
||||
val scalaEvictions: Seq[EvictionPair],
|
||||
val directEvictions: Seq[EvictionPair],
|
||||
val transitiveEvictions: Seq[EvictionPair],
|
||||
val allEvictions: Seq[EvictionPair]
|
||||
val options: EvictionWarningOptions,
|
||||
val scalaEvictions: Seq[EvictionPair],
|
||||
val directEvictions: Seq[EvictionPair],
|
||||
val transitiveEvictions: Seq[EvictionPair],
|
||||
val allEvictions: Seq[EvictionPair]
|
||||
) {
|
||||
def reportedEvictions: Seq[EvictionPair] = scalaEvictions ++ directEvictions ++ transitiveEvictions
|
||||
def reportedEvictions: Seq[EvictionPair] =
|
||||
scalaEvictions ++ directEvictions ++ transitiveEvictions
|
||||
private[sbt] def infoAllTheThings: List[String] = EvictionWarning.infoAllTheThings(this)
|
||||
}
|
||||
|
||||
object EvictionWarning {
|
||||
def apply(module: IvySbt#Module, options: EvictionWarningOptions, report: UpdateReport, log: Logger): EvictionWarning = {
|
||||
def apply(
|
||||
module: IvySbt#Module,
|
||||
options: EvictionWarningOptions,
|
||||
report: UpdateReport,
|
||||
log: Logger
|
||||
): EvictionWarning = {
|
||||
val evictions = buildEvictions(options, report)
|
||||
processEvictions(module, options, evictions)
|
||||
}
|
||||
|
||||
private[sbt] def buildEvictions(options: EvictionWarningOptions, report: UpdateReport): Seq[OrganizationArtifactReport] = {
|
||||
private[sbt] def buildEvictions(
|
||||
options: EvictionWarningOptions,
|
||||
report: UpdateReport
|
||||
): Seq[OrganizationArtifactReport] = {
|
||||
val buffer: mutable.ListBuffer[OrganizationArtifactReport] = mutable.ListBuffer()
|
||||
val confs = report.configurations filter { x => options.configStrings contains x.configuration }
|
||||
val confs = report.configurations filter { x =>
|
||||
options.configStrings contains x.configuration
|
||||
}
|
||||
confs flatMap { confReport =>
|
||||
confReport.details map { detail =>
|
||||
if ((detail.modules exists { _.evicted }) &&
|
||||
!(buffer exists { x => (x.organization == detail.organization) && (x.name == detail.name) })) {
|
||||
!(buffer exists { x =>
|
||||
(x.organization == detail.organization) && (x.name == detail.name)
|
||||
})) {
|
||||
buffer += detail
|
||||
}
|
||||
}
|
||||
|
|
@ -157,7 +179,11 @@ object EvictionWarning {
|
|||
buffer.toList.toVector
|
||||
}
|
||||
|
||||
private[sbt] def isScalaArtifact(module: IvySbt#Module, organization: String, name: String): Boolean =
|
||||
private[sbt] def isScalaArtifact(
|
||||
module: IvySbt#Module,
|
||||
organization: String,
|
||||
name: String
|
||||
): Boolean =
|
||||
module.moduleSettings.ivyScala match {
|
||||
case Some(s) =>
|
||||
organization == s.scalaOrganization &&
|
||||
|
|
@ -165,7 +191,11 @@ object EvictionWarning {
|
|||
case _ => false
|
||||
}
|
||||
|
||||
private[sbt] def processEvictions(module: IvySbt#Module, options: EvictionWarningOptions, reports: Seq[OrganizationArtifactReport]): EvictionWarning = {
|
||||
private[sbt] def processEvictions(
|
||||
module: IvySbt#Module,
|
||||
options: EvictionWarningOptions,
|
||||
reports: Seq[OrganizationArtifactReport]
|
||||
): EvictionWarning = {
|
||||
val directDependencies = module.moduleSettings match {
|
||||
case x: InlineConfiguration => x.dependencies
|
||||
case _ => Vector.empty
|
||||
|
|
@ -178,19 +208,29 @@ object EvictionWarning {
|
|||
(directDependencies exists { dep =>
|
||||
(detail.organization == dep.organization) && (detail.name == dep.name)
|
||||
})
|
||||
new EvictionPair(detail.organization, detail.name, winner, evicteds, includesDirect, options.showCallers)
|
||||
new EvictionPair(
|
||||
detail.organization,
|
||||
detail.name,
|
||||
winner,
|
||||
evicteds,
|
||||
includesDirect,
|
||||
options.showCallers
|
||||
)
|
||||
}
|
||||
val scalaEvictions: mutable.ListBuffer[EvictionPair] = mutable.ListBuffer()
|
||||
val directEvictions: mutable.ListBuffer[EvictionPair] = mutable.ListBuffer()
|
||||
val transitiveEvictions: mutable.ListBuffer[EvictionPair] = mutable.ListBuffer()
|
||||
def guessCompatible(p: EvictionPair): Boolean =
|
||||
p.evicteds forall { r =>
|
||||
options.guessCompatible((r.module, p.winner map { _.module }, module.moduleSettings.ivyScala))
|
||||
options.guessCompatible(
|
||||
(r.module, p.winner map { _.module }, module.moduleSettings.ivyScala)
|
||||
)
|
||||
}
|
||||
pairs foreach {
|
||||
case p if isScalaArtifact(module, p.organization, p.name) =>
|
||||
(module.moduleSettings.ivyScala, p.winner) match {
|
||||
case (Some(s), Some(winner)) if (s.scalaFullVersion != winner.module.revision) && options.warnScalaVersionEviction =>
|
||||
case (Some(s), Some(winner))
|
||||
if (s.scalaFullVersion != winner.module.revision) && options.warnScalaVersionEviction =>
|
||||
scalaEvictions += p
|
||||
case _ =>
|
||||
}
|
||||
|
|
@ -203,8 +243,13 @@ object EvictionWarning {
|
|||
transitiveEvictions += p
|
||||
}
|
||||
}
|
||||
new EvictionWarning(options, scalaEvictions.toList,
|
||||
directEvictions.toList, transitiveEvictions.toList, pairs)
|
||||
new EvictionWarning(
|
||||
options,
|
||||
scalaEvictions.toList,
|
||||
directEvictions.toList,
|
||||
transitiveEvictions.toList,
|
||||
pairs
|
||||
)
|
||||
}
|
||||
|
||||
implicit val evictionWarningLines: ShowLines[EvictionWarning] = ShowLines { a: EvictionWarning =>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,10 @@ abstract class ArtifactTypeFilterExtra {
|
|||
def types: Set[String]
|
||||
def inverted: Boolean
|
||||
|
||||
protected[this] def copy(types: Set[String] = types, inverted: Boolean = inverted): ArtifactTypeFilter
|
||||
protected[this] def copy(
|
||||
types: Set[String] = types,
|
||||
inverted: Boolean = inverted
|
||||
): ArtifactTypeFilter
|
||||
|
||||
def invert = copy(inverted = !inverted)
|
||||
def apply(a: descriptor.Artifact): Boolean = (types contains a.getType) ^ inverted
|
||||
|
|
@ -25,7 +28,9 @@ abstract class ArtifactTypeFilterFunctions {
|
|||
def forbid(types: Set[String]) = ArtifactTypeFilter(types, true)
|
||||
|
||||
implicit def toIvyFilter(f: ArtifactTypeFilter): IvyFilter = new IvyFilter {
|
||||
override def accept(o: Object): Boolean = Option(o) exists { case a: descriptor.Artifact => f.apply(a) }
|
||||
override def accept(o: Object): Boolean = Option(o) exists {
|
||||
case a: descriptor.Artifact => f.apply(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,10 +26,17 @@ object ScalaArtifacts {
|
|||
|
||||
def libraryDependency(version: String): ModuleID = ModuleID(Organization, LibraryID, version)
|
||||
|
||||
private[sbt] def toolDependencies(org: String, version: String, isDotty: Boolean = false): Seq[ModuleID] =
|
||||
private[sbt] def toolDependencies(
|
||||
org: String,
|
||||
version: String,
|
||||
isDotty: Boolean = false
|
||||
): Seq[ModuleID] =
|
||||
if (isDotty)
|
||||
Seq(ModuleID(org, DottyIDPrefix, version).withConfigurations(Some(Configurations.ScalaTool.name + "->default(compile)"))
|
||||
.withCrossVersion(CrossVersion.binary))
|
||||
Seq(
|
||||
ModuleID(org, DottyIDPrefix, version)
|
||||
.withConfigurations(Some(Configurations.ScalaTool.name + "->default(compile)"))
|
||||
.withCrossVersion(CrossVersion.binary)
|
||||
)
|
||||
else
|
||||
Seq(
|
||||
scalaToolDependency(org, ScalaArtifacts.CompilerID, version),
|
||||
|
|
@ -37,7 +44,9 @@ object ScalaArtifacts {
|
|||
)
|
||||
|
||||
private[this] def scalaToolDependency(org: String, id: String, version: String): ModuleID =
|
||||
ModuleID(org, id, version).withConfigurations(Some(Configurations.ScalaTool.name + "->default,optional(default)"))
|
||||
ModuleID(org, id, version).withConfigurations(
|
||||
Some(Configurations.ScalaTool.name + "->default,optional(default)")
|
||||
)
|
||||
}
|
||||
object SbtArtifacts {
|
||||
val Organization = "org.scala-sbt"
|
||||
|
|
@ -46,17 +55,39 @@ object SbtArtifacts {
|
|||
import ScalaArtifacts._
|
||||
|
||||
private[sbt] abstract class IvyScalaFunctions {
|
||||
|
||||
/** Performs checks/adds filters on Scala dependencies (if enabled in IvyScala). */
|
||||
def checkModule(module: DefaultModuleDescriptor, conf: String, scalaVersionConfigs: Vector[String], log: Logger)(check: IvyScala): Unit = {
|
||||
def checkModule(
|
||||
module: DefaultModuleDescriptor,
|
||||
conf: String,
|
||||
scalaVersionConfigs: Vector[String],
|
||||
log: Logger
|
||||
)(check: IvyScala): Unit = {
|
||||
if (check.checkExplicit)
|
||||
checkDependencies(module, check.scalaOrganization, check.scalaArtifacts, check.scalaBinaryVersion, scalaVersionConfigs, log)
|
||||
checkDependencies(
|
||||
module,
|
||||
check.scalaOrganization,
|
||||
check.scalaArtifacts,
|
||||
check.scalaBinaryVersion,
|
||||
scalaVersionConfigs,
|
||||
log
|
||||
)
|
||||
if (check.filterImplicit)
|
||||
excludeScalaJars(module, check.configurations)
|
||||
if (check.overrideScalaVersion)
|
||||
overrideScalaVersion(module, check.scalaOrganization, check.scalaFullVersion, scalaVersionConfigs)
|
||||
overrideScalaVersion(
|
||||
module,
|
||||
check.scalaOrganization,
|
||||
check.scalaFullVersion,
|
||||
scalaVersionConfigs
|
||||
)
|
||||
}
|
||||
|
||||
class OverrideScalaMediator(scalaOrganization: String, scalaVersion: String, scalaVersionConfigs0: Vector[String]) extends DependencyDescriptorMediator {
|
||||
class OverrideScalaMediator(
|
||||
scalaOrganization: String,
|
||||
scalaVersion: String,
|
||||
scalaVersionConfigs0: Vector[String]
|
||||
) extends DependencyDescriptorMediator {
|
||||
private[this] val scalaVersionConfigs = scalaVersionConfigs0.toSet
|
||||
def mediate(dd: DependencyDescriptor): DependencyDescriptor = {
|
||||
// Mediate only for the dependencies in scalaVersion configurations. https://github.com/sbt/sbt/issues/2786
|
||||
|
|
@ -79,8 +110,15 @@ private[sbt] abstract class IvyScalaFunctions {
|
|||
if (mrid == null) mrid
|
||||
else
|
||||
mrid.getName match {
|
||||
case name @ (CompilerID | LibraryID | ReflectID | ActorsID | ScalapID) if configQualifies && dependeeQualifies =>
|
||||
ModuleRevisionId.newInstance(scalaOrganization, name, mrid.getBranch, scalaVersion, mrid.getQualifiedExtraAttributes)
|
||||
case name @ (CompilerID | LibraryID | ReflectID | ActorsID | ScalapID)
|
||||
if configQualifies && dependeeQualifies =>
|
||||
ModuleRevisionId.newInstance(
|
||||
scalaOrganization,
|
||||
name,
|
||||
mrid.getBranch,
|
||||
scalaVersion,
|
||||
mrid.getQualifiedExtraAttributes
|
||||
)
|
||||
case _ => mrid
|
||||
}
|
||||
}
|
||||
|
|
@ -92,14 +130,32 @@ private[sbt] abstract class IvyScalaFunctions {
|
|||
}
|
||||
}
|
||||
|
||||
def overrideScalaVersion(module: DefaultModuleDescriptor, organization: String, version: String, scalaVersionConfigs: Vector[String]): Unit = {
|
||||
def overrideScalaVersion(
|
||||
module: DefaultModuleDescriptor,
|
||||
organization: String,
|
||||
version: String,
|
||||
scalaVersionConfigs: Vector[String]
|
||||
): Unit = {
|
||||
val mediator = new OverrideScalaMediator(organization, version, scalaVersionConfigs)
|
||||
module.addDependencyDescriptorMediator(new ModuleId(Organization, "*"), ExactPatternMatcher.INSTANCE, mediator)
|
||||
module.addDependencyDescriptorMediator(
|
||||
new ModuleId(Organization, "*"),
|
||||
ExactPatternMatcher.INSTANCE,
|
||||
mediator
|
||||
)
|
||||
if (organization != Organization)
|
||||
module.addDependencyDescriptorMediator(new ModuleId(organization, "*"), ExactPatternMatcher.INSTANCE, mediator)
|
||||
module.addDependencyDescriptorMediator(
|
||||
new ModuleId(organization, "*"),
|
||||
ExactPatternMatcher.INSTANCE,
|
||||
mediator
|
||||
)
|
||||
}
|
||||
|
||||
def overrideVersion(module: DefaultModuleDescriptor, org: String, name: String, version: String): Unit = {
|
||||
def overrideVersion(
|
||||
module: DefaultModuleDescriptor,
|
||||
org: String,
|
||||
name: String,
|
||||
version: String
|
||||
): Unit = {
|
||||
val id = new ModuleId(org, name)
|
||||
val over = new OverrideDependencyDescriptorMediator(null, version)
|
||||
module.addDependencyDescriptorMediator(id, ExactPatternMatcher.INSTANCE, over)
|
||||
|
|
@ -109,71 +165,98 @@ private[sbt] abstract class IvyScalaFunctions {
|
|||
* 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, scalaOrganization: String, scalaArtifacts: Vector[String], scalaBinaryVersion: String, scalaVersionConfigs0: Vector[String], log: Logger): Unit = {
|
||||
val scalaVersionConfigs: String => Boolean = if (scalaVersionConfigs0.isEmpty) (c: String) => false else scalaVersionConfigs0.toSet
|
||||
def binaryScalaWarning(dep: DependencyDescriptor): Option[String] =
|
||||
{
|
||||
val id = dep.getDependencyRevisionId
|
||||
val depBinaryVersion = CrossVersion.binaryScalaVersion(id.getRevision)
|
||||
def isScalaLangOrg = id.getOrganisation == scalaOrganization
|
||||
def isScalaArtifact = scalaArtifacts.contains(id.getName)
|
||||
def hasBinVerMismatch = depBinaryVersion != scalaBinaryVersion
|
||||
def matchesOneOfTheConfigs = dep.getModuleConfigurations exists { scalaVersionConfigs }
|
||||
val mismatched = isScalaLangOrg && isScalaArtifact && hasBinVerMismatch && matchesOneOfTheConfigs
|
||||
if (mismatched)
|
||||
Some("Binary version (" + depBinaryVersion + ") for dependency " + id +
|
||||
private def checkDependencies(
|
||||
module: ModuleDescriptor,
|
||||
scalaOrganization: String,
|
||||
scalaArtifacts: Vector[String],
|
||||
scalaBinaryVersion: String,
|
||||
scalaVersionConfigs0: Vector[String],
|
||||
log: Logger
|
||||
): Unit = {
|
||||
val scalaVersionConfigs: String => Boolean =
|
||||
if (scalaVersionConfigs0.isEmpty) (c: String) => false else scalaVersionConfigs0.toSet
|
||||
def binaryScalaWarning(dep: DependencyDescriptor): Option[String] = {
|
||||
val id = dep.getDependencyRevisionId
|
||||
val depBinaryVersion = CrossVersion.binaryScalaVersion(id.getRevision)
|
||||
def isScalaLangOrg = id.getOrganisation == scalaOrganization
|
||||
def isScalaArtifact = scalaArtifacts.contains(id.getName)
|
||||
def hasBinVerMismatch = depBinaryVersion != scalaBinaryVersion
|
||||
def matchesOneOfTheConfigs = dep.getModuleConfigurations exists { scalaVersionConfigs }
|
||||
val mismatched = isScalaLangOrg && isScalaArtifact && hasBinVerMismatch && matchesOneOfTheConfigs
|
||||
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) }
|
||||
" 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 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]): Unit = {
|
||||
val configurationNames =
|
||||
{
|
||||
val names = module.getConfigurationsNames
|
||||
if (configurations.isEmpty)
|
||||
names
|
||||
else {
|
||||
val configSet = configurationSet(configurations)
|
||||
configSet.intersect(HashSet(names: _*))
|
||||
configSet.toArray
|
||||
}
|
||||
private def excludeScalaJars(
|
||||
module: DefaultModuleDescriptor,
|
||||
configurations: Iterable[Configuration]
|
||||
): Unit = {
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an IncludeRule that includes artifacts with the given module organization and name for
|
||||
* the given configurations.
|
||||
*/
|
||||
private[sbt] def includeRule(organization: String, name: String, configurationNames: Iterable[String], includeTypePattern: String): IncludeRule =
|
||||
{
|
||||
val artifact = new ArtifactId(ModuleId.newInstance(organization, name), "*", includeTypePattern, "*")
|
||||
val rule = new DefaultIncludeRule(artifact, ExactPatternMatcher.INSTANCE, emptyMap[AnyRef, AnyRef])
|
||||
configurationNames.foreach(rule.addConfiguration)
|
||||
rule
|
||||
}
|
||||
private[sbt] def includeRule(
|
||||
organization: String,
|
||||
name: String,
|
||||
configurationNames: Iterable[String],
|
||||
includeTypePattern: String
|
||||
): IncludeRule = {
|
||||
val artifact =
|
||||
new ArtifactId(ModuleId.newInstance(organization, name), "*", includeTypePattern, "*")
|
||||
val rule =
|
||||
new DefaultIncludeRule(artifact, ExactPatternMatcher.INSTANCE, emptyMap[AnyRef, AnyRef])
|
||||
configurationNames.foreach(rule.addConfiguration)
|
||||
rule
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,53 +24,56 @@ abstract class ModuleIDExtra {
|
|||
def branchName: Option[String]
|
||||
|
||||
protected[this] def copy(
|
||||
organization: String = organization,
|
||||
name: String = name,
|
||||
revision: String = revision,
|
||||
configurations: Option[String] = configurations,
|
||||
isChanging: Boolean = isChanging,
|
||||
isTransitive: Boolean = isTransitive,
|
||||
isForce: Boolean = isForce,
|
||||
explicitArtifacts: Vector[Artifact] = explicitArtifacts,
|
||||
inclusions: Vector[InclusionRule] = inclusions,
|
||||
exclusions: Vector[ExclusionRule] = exclusions,
|
||||
extraAttributes: Map[String, String] = extraAttributes,
|
||||
crossVersion: CrossVersion = crossVersion,
|
||||
branchName: Option[String] = branchName
|
||||
organization: String = organization,
|
||||
name: String = name,
|
||||
revision: String = revision,
|
||||
configurations: Option[String] = configurations,
|
||||
isChanging: Boolean = isChanging,
|
||||
isTransitive: Boolean = isTransitive,
|
||||
isForce: Boolean = isForce,
|
||||
explicitArtifacts: Vector[Artifact] = explicitArtifacts,
|
||||
inclusions: Vector[InclusionRule] = inclusions,
|
||||
exclusions: Vector[ExclusionRule] = exclusions,
|
||||
extraAttributes: Map[String, String] = extraAttributes,
|
||||
crossVersion: CrossVersion = crossVersion,
|
||||
branchName: Option[String] = branchName
|
||||
): ModuleID
|
||||
|
||||
protected def toStringImpl: String =
|
||||
s"""$organization:$name:$revision""" +
|
||||
(configurations match { case Some(s) => ":" + s; case None => "" }) +
|
||||
{
|
||||
val attr = attributeString
|
||||
if (attr == "") ""
|
||||
else " " + attr
|
||||
} +
|
||||
(configurations match { case Some(s) => ":" + s; case None => "" }) + {
|
||||
val attr = attributeString
|
||||
if (attr == "") ""
|
||||
else " " + attr
|
||||
} +
|
||||
(if (extraAttributes.isEmpty) "" else " " + extraString)
|
||||
|
||||
protected def attributeString: String =
|
||||
{
|
||||
val buffer = ListBuffer.empty[String]
|
||||
if (isChanging) {
|
||||
buffer += "changing"
|
||||
}
|
||||
if (!isTransitive) {
|
||||
buffer += "intransitive"
|
||||
}
|
||||
if (isForce) {
|
||||
buffer += "force"
|
||||
}
|
||||
buffer.toList.mkString(";")
|
||||
protected def attributeString: String = {
|
||||
val buffer = ListBuffer.empty[String]
|
||||
if (isChanging) {
|
||||
buffer += "changing"
|
||||
}
|
||||
if (!isTransitive) {
|
||||
buffer += "intransitive"
|
||||
}
|
||||
if (isForce) {
|
||||
buffer += "force"
|
||||
}
|
||||
buffer.toList.mkString(";")
|
||||
}
|
||||
|
||||
/** String representation of the extra attributes, excluding any information only attributes. */
|
||||
def extraString: String = extraDependencyAttributes.map { case (k, v) => k + "=" + v } mkString ("(", ", ", ")")
|
||||
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(SbtPomExtraProperties.POM_INFO_KEY_PREFIX))
|
||||
def extraDependencyAttributes: Map[String, String] =
|
||||
extraAttributes.filterKeys(!_.startsWith(SbtPomExtraProperties.POM_INFO_KEY_PREFIX))
|
||||
|
||||
@deprecated("Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.", "0.12.0")
|
||||
@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 Disabled())
|
||||
|
||||
/** Specifies the cross-version behavior for this module. See [CrossVersion] for details.*/
|
||||
|
|
@ -111,7 +114,8 @@ abstract class ModuleIDExtra {
|
|||
* 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.toVector ++ explicitArtifacts)
|
||||
def artifacts(newArtifacts: Artifact*) =
|
||||
copy(explicitArtifacts = newArtifacts.toVector ++ explicitArtifacts)
|
||||
|
||||
/**
|
||||
* Applies the provided exclusions to dependencies of this module. Note that only exclusions that specify
|
||||
|
|
@ -120,13 +124,15 @@ abstract class ModuleIDExtra {
|
|||
def excludeAll(rules: InclExclRule*) = 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(InclExclRule().withOrganization(org).withName(name))
|
||||
def exclude(org: String, name: String) =
|
||||
excludeAll(InclExclRule().withOrganization(org).withName(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))
|
||||
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
|
||||
|
|
@ -175,7 +181,9 @@ abstract class ModuleIDExtra {
|
|||
}
|
||||
|
||||
abstract class ModuleIDFunctions {
|
||||
|
||||
/** 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)
|
||||
for ((key, value) <- attributes)
|
||||
yield if (key.startsWith("e:")) (key, value) else ("e:" + key, value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@ final class RawRepository(val resolver: DependencyResolver) extends Resolver(res
|
|||
case _ => false
|
||||
}
|
||||
|
||||
override def hashCode: Int =
|
||||
{
|
||||
var hash = 1
|
||||
hash = hash * 31 + this.name.##
|
||||
hash
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
var hash = 1
|
||||
hash = hash * 31 + this.name.##
|
||||
hash
|
||||
}
|
||||
}
|
||||
|
||||
abstract class MavenRepositoryFunctions {
|
||||
|
|
@ -37,11 +36,15 @@ abstract class PatternsFunctions {
|
|||
def apply(artifactPatterns: String*): Patterns = Patterns(true, artifactPatterns: _*)
|
||||
def apply(isMavenCompatible: Boolean, artifactPatterns: String*): Patterns = {
|
||||
val patterns = artifactPatterns.toVector
|
||||
Patterns().withIvyPatterns(patterns).withArtifactPatterns(patterns).withIsMavenCompatible(isMavenCompatible)
|
||||
Patterns()
|
||||
.withIvyPatterns(patterns)
|
||||
.withArtifactPatterns(patterns)
|
||||
.withIsMavenCompatible(isMavenCompatible)
|
||||
}
|
||||
}
|
||||
|
||||
trait SshBasedRepositoryExtra {
|
||||
|
||||
/** The object representing the configured ssh connection for this repository. */
|
||||
def connection: SshConnection
|
||||
|
||||
|
|
@ -53,11 +56,13 @@ trait SshBasedRepositoryExtra {
|
|||
/** 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]): RepositoryType = copy(PasswordAuthentication(user, password))
|
||||
def as(user: String, password: Option[String]): RepositoryType =
|
||||
copy(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: String): RepositoryType =
|
||||
as(user, keyfile, Some(password))
|
||||
|
||||
def as(user: String, keyfile: File, password: Option[String]): RepositoryType =
|
||||
copy(KeyFileAuthentication(user, keyfile, password))
|
||||
|
|
@ -80,7 +85,8 @@ trait SftpRepositoryExtra extends SshBasedRepositoryExtra {
|
|||
|
||||
type RepositoryType = SftpRepository
|
||||
|
||||
protected def copy(connection: SshConnection): SftpRepository = SftpRepository(name, connection, patterns)
|
||||
protected def copy(connection: SshConnection): SftpRepository =
|
||||
SftpRepository(name, connection, patterns)
|
||||
}
|
||||
|
||||
/** A repository that conforms to sbt launcher's interface */
|
||||
|
|
@ -96,7 +102,8 @@ trait ResolversSyntax {
|
|||
}
|
||||
|
||||
abstract class ResolverFunctions {
|
||||
private[sbt] def useSecureResolvers = sys.props.get("sbt.repository.secure") map { _.toLowerCase == "true" } getOrElse true
|
||||
private[sbt] def useSecureResolvers =
|
||||
sys.props.get("sbt.repository.secure") map { _.toLowerCase == "true" } getOrElse true
|
||||
|
||||
val TypesafeRepositoryRoot = typesafeRepositoryRoot(useSecureResolvers)
|
||||
val SbtRepositoryRoot = sbtRepositoryRoot(useSecureResolvers)
|
||||
|
|
@ -109,31 +116,49 @@ abstract class ResolverFunctions {
|
|||
val JCenterRepositoryRoot = "https://jcenter.bintray.com/"
|
||||
val DefaultMavenRepositoryRoot = "https://repo1.maven.org/maven2/"
|
||||
// TODO: This switch is only kept for backward compatibility. Hardcode to HTTPS in the future.
|
||||
private[sbt] def centralRepositoryRoot(secure: Boolean) = (if (secure) "https" else "http") + "://repo1.maven.org/maven2/"
|
||||
private[sbt] def centralRepositoryRoot(secure: Boolean) =
|
||||
(if (secure) "https" else "http") + "://repo1.maven.org/maven2/"
|
||||
// TODO: This switch is only kept for backward compatibility. Hardcode to HTTPS in the future.
|
||||
private[sbt] def javanet2RepositoryRoot(secure: Boolean) =
|
||||
if (secure) "https://maven.java.net/content/repositories/public/"
|
||||
else "http://download.java.net/maven/2"
|
||||
// TODO: This switch is only kept for backward compatibility. Hardcode to HTTPS in the future.
|
||||
private[sbt] def typesafeRepositoryRoot(secure: Boolean) = (if (secure) "https" else "http") + "://repo.typesafe.com/typesafe"
|
||||
private[sbt] def typesafeRepositoryRoot(secure: Boolean) =
|
||||
(if (secure) "https" else "http") + "://repo.typesafe.com/typesafe"
|
||||
// TODO: This switch is only kept for backward compatibility. Hardcode to HTTPS in the future.
|
||||
private[sbt] def sbtRepositoryRoot(secure: Boolean) = (if (secure) "https" else "http") + "://repo.scala-sbt.org/scalasbt"
|
||||
private[sbt] def sbtRepositoryRoot(secure: Boolean) =
|
||||
(if (secure) "https" else "http") + "://repo.scala-sbt.org/scalasbt"
|
||||
|
||||
// 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 = MavenRepository(ScalaToolsReleasesName, ScalaToolsReleasesRoot)
|
||||
private[sbt] val ScalaToolsSnapshots = MavenRepository(ScalaToolsSnapshotsName, ScalaToolsSnapshotsRoot)
|
||||
private[sbt] val ScalaToolsReleases =
|
||||
MavenRepository(ScalaToolsReleasesName, ScalaToolsReleasesRoot)
|
||||
private[sbt] val ScalaToolsSnapshots =
|
||||
MavenRepository(ScalaToolsSnapshotsName, ScalaToolsSnapshotsRoot)
|
||||
|
||||
def typesafeRepo(status: String) = MavenRepository("typesafe-" + status, TypesafeRepositoryRoot + "/" + status)
|
||||
def typesafeIvyRepo(status: String) = url("typesafe-ivy-" + status, new URL(TypesafeRepositoryRoot + "/ivy-" + status + "/"))(ivyStylePatterns)
|
||||
def sbtIvyRepo(status: String) = url(s"sbt-ivy-$status", new URL(s"$SbtRepositoryRoot/ivy-$status/"))(ivyStylePatterns)
|
||||
def sbtPluginRepo(status: String) = url("sbt-plugin-" + status, new URL(SbtRepositoryRoot + "/sbt-plugin-" + status + "/"))(ivyStylePatterns)
|
||||
def sonatypeRepo(status: String) = MavenRepository("sonatype-" + status, SonatypeRepositoryRoot + "/" + status)
|
||||
def bintrayRepo(owner: String, repo: String) = MavenRepository(s"bintray-$owner-$repo", s"https://dl.bintray.com/$owner/$repo/")
|
||||
def bintrayIvyRepo(owner: String, repo: String) = url(s"bintray-$owner-$repo", new URL(s"https://dl.bintray.com/$owner/$repo/"))(Resolver.ivyStylePatterns)
|
||||
def typesafeRepo(status: String) =
|
||||
MavenRepository("typesafe-" + status, TypesafeRepositoryRoot + "/" + status)
|
||||
def typesafeIvyRepo(status: String) =
|
||||
url("typesafe-ivy-" + status, new URL(TypesafeRepositoryRoot + "/ivy-" + status + "/"))(
|
||||
ivyStylePatterns
|
||||
)
|
||||
def sbtIvyRepo(status: String) =
|
||||
url(s"sbt-ivy-$status", new URL(s"$SbtRepositoryRoot/ivy-$status/"))(ivyStylePatterns)
|
||||
def sbtPluginRepo(status: String) =
|
||||
url("sbt-plugin-" + status, new URL(SbtRepositoryRoot + "/sbt-plugin-" + status + "/"))(
|
||||
ivyStylePatterns
|
||||
)
|
||||
def sonatypeRepo(status: String) =
|
||||
MavenRepository("sonatype-" + status, SonatypeRepositoryRoot + "/" + status)
|
||||
def bintrayRepo(owner: String, repo: String) =
|
||||
MavenRepository(s"bintray-$owner-$repo", s"https://dl.bintray.com/$owner/$repo/")
|
||||
def bintrayIvyRepo(owner: String, repo: String) =
|
||||
url(s"bintray-$owner-$repo", new URL(s"https://dl.bintray.com/$owner/$repo/"))(
|
||||
Resolver.ivyStylePatterns
|
||||
)
|
||||
def jcenterRepo = JCenterRepository
|
||||
|
||||
/** Add the local and Maven Central repositories to the user repositories. */
|
||||
|
|
@ -152,7 +177,11 @@ abstract class ResolverFunctions {
|
|||
* If `jcenter` is true, add the JCenter.
|
||||
* If `mavenCentral` is true, add the Maven Central repository.
|
||||
*/
|
||||
def withDefaultResolvers(userResolvers: Seq[Resolver], jcenter: Boolean, mavenCentral: Boolean): Seq[Resolver] =
|
||||
def withDefaultResolvers(
|
||||
userResolvers: Seq[Resolver],
|
||||
jcenter: Boolean,
|
||||
mavenCentral: Boolean
|
||||
): Seq[Resolver] =
|
||||
Seq(Resolver.defaultLocal) ++
|
||||
userResolvers ++
|
||||
single(JCenterRepository, jcenter) ++
|
||||
|
|
@ -163,7 +192,11 @@ abstract class ResolverFunctions {
|
|||
* If `jcenter` is true, add the JCenter.
|
||||
* If `mavenCentral` is true, add the Maven Central repository.
|
||||
*/
|
||||
private[sbt] def reorganizeAppResolvers(appResolvers: Seq[Resolver], jcenter: Boolean, mavenCentral: Boolean): Seq[Resolver] =
|
||||
private[sbt] def reorganizeAppResolvers(
|
||||
appResolvers: Seq[Resolver],
|
||||
jcenter: Boolean,
|
||||
mavenCentral: Boolean
|
||||
): Seq[Resolver] =
|
||||
appResolvers.partition(_ == Resolver.defaultLocal) match {
|
||||
case (locals, xs) =>
|
||||
locals ++
|
||||
|
|
@ -181,78 +214,111 @@ abstract class ResolverFunctions {
|
|||
|
||||
/** A base class for defining factories for interfaces to Ivy repositories that require a hostname , port, and patterns. */
|
||||
sealed abstract class Define[RepositoryType <: SshBasedRepository] {
|
||||
|
||||
/** Subclasses should implement this method to */
|
||||
protected def construct(name: String, connection: SshConnection, patterns: Patterns): RepositoryType
|
||||
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 =
|
||||
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 =
|
||||
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 =
|
||||
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 =
|
||||
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)
|
||||
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)
|
||||
protected def construct(name: String, connection: SshConnection, patterns: Patterns) =
|
||||
SftpRepository(name, connection, patterns)
|
||||
}
|
||||
|
||||
/** A factory to construct an interface to an Ivy filesystem 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))
|
||||
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, _))
|
||||
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 =
|
||||
private def baseRepository[T](base: String)(construct: Patterns => T)(
|
||||
implicit basePatterns: Patterns
|
||||
): T =
|
||||
construct(resolvePatterns(base, basePatterns))
|
||||
|
||||
/**
|
||||
|
|
@ -264,41 +330,53 @@ abstract class ResolverFunctions {
|
|||
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: Vector[String]) = patterns.map(p => resolvePattern(base, p))
|
||||
Patterns(resolveAll(basePatterns.ivyPatterns), resolveAll(basePatterns.artifactPatterns), basePatterns.isMavenCompatible, basePatterns.descriptorOptional, basePatterns.skipConsistencyCheck)
|
||||
}
|
||||
private[sbt] def resolvePattern(base: String, pattern: String): String =
|
||||
{
|
||||
val normBase = base.replace('\\', '/')
|
||||
if (normBase.endsWith("/") || pattern.startsWith("/")) normBase + pattern else normBase + "/" + pattern
|
||||
}
|
||||
private def resolvePatterns(base: String, basePatterns: Patterns): Patterns = {
|
||||
def resolveAll(patterns: Vector[String]) = patterns.map(p => resolvePattern(base, p))
|
||||
Patterns(
|
||||
resolveAll(basePatterns.ivyPatterns),
|
||||
resolveAll(basePatterns.artifactPatterns),
|
||||
basePatterns.isMavenCompatible,
|
||||
basePatterns.descriptorOptional,
|
||||
basePatterns.skipConsistencyCheck
|
||||
)
|
||||
}
|
||||
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().withArtifactPatterns(Vector(mavenStyleBasePattern))
|
||||
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 + "(/[branch])/[revision]/[type]s/[artifact](-[classifier]).[ext]"
|
||||
def defaultRetrievePattern = "[type]s/[organisation]/[module]/" + PluginPattern + "[artifact](-[revision])(-[classifier]).[ext]"
|
||||
def mavenStyleBasePattern =
|
||||
"[organisation]/[module](_[scalaVersion])(_[sbtVersion])/[revision]/[artifact]-[revision](-[classifier]).[ext]"
|
||||
def localBasePattern =
|
||||
"[organisation]/[module]/" + PluginPattern + "(/[branch])/[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: File = {
|
||||
def loadHomeFromSettings(f: () => File): Option[File] =
|
||||
try {
|
||||
val file = f()
|
||||
if (!file.exists) None
|
||||
else ((XML.loadFile(file) \ "localRepository").text match {
|
||||
case "" => None
|
||||
case e @ _ => Some(new File(e))
|
||||
})
|
||||
else
|
||||
((XML.loadFile(file) \ "localRepository").text match {
|
||||
case "" => None
|
||||
case e @ _ => Some(new File(e))
|
||||
})
|
||||
} catch {
|
||||
// Occurs inside File constructor when property or environment variable does not exist
|
||||
case _: NullPointerException => None
|
||||
// Occurs when File does not exist
|
||||
case _: IOException => None
|
||||
case e: SAXParseException => System.err.println(s"WARNING: Problem parsing ${f().getAbsolutePath}, ${e.getMessage}"); None
|
||||
case _: IOException => None
|
||||
case e: SAXParseException =>
|
||||
System.err.println(s"WARNING: Problem parsing ${f().getAbsolutePath}, ${e.getMessage}");
|
||||
None
|
||||
}
|
||||
loadHomeFromSettings(() => new File(sbt.io.Path.userHome, ".m2/settings.xml")) orElse
|
||||
loadHomeFromSettings(() => new File(new File(System.getenv("M2_HOME")), "conf/settings.xml")) getOrElse
|
||||
|
|
@ -309,14 +387,16 @@ abstract class ResolverFunctions {
|
|||
def mavenLocal: MavenRepository = new MavenCache("Maven2 Local", mavenLocalDir)
|
||||
def defaultLocal = defaultUserFileRepository("local")
|
||||
def defaultShared = defaultUserFileRepository("shared")
|
||||
def defaultUserFileRepository(id: String) =
|
||||
{
|
||||
val pList = Vector(s"$${ivy.home}/$id/$localBasePattern")
|
||||
FileRepository(id, defaultFileConfiguration, Patterns().withIvyPatterns(pList).withArtifactPatterns(pList).withIsMavenCompatible(false))
|
||||
}
|
||||
def defaultIvyPatterns =
|
||||
{
|
||||
val pList = Vector(localBasePattern)
|
||||
def defaultUserFileRepository(id: String) = {
|
||||
val pList = Vector(s"$${ivy.home}/$id/$localBasePattern")
|
||||
FileRepository(
|
||||
id,
|
||||
defaultFileConfiguration,
|
||||
Patterns().withIvyPatterns(pList).withArtifactPatterns(pList).withIsMavenCompatible(false)
|
||||
}
|
||||
)
|
||||
}
|
||||
def defaultIvyPatterns = {
|
||||
val pList = Vector(localBasePattern)
|
||||
Patterns().withIvyPatterns(pList).withArtifactPatterns(pList).withIsMavenCompatible(false)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,11 @@ import java.io.File
|
|||
* and for obtaining references to a selected subset of the underlying files.
|
||||
*/
|
||||
final class RichUpdateReport(report: UpdateReport) {
|
||||
private[sbt] def recomputeStamps(): UpdateReport =
|
||||
{
|
||||
val files = report.cachedDescriptor +: allFiles
|
||||
val stamps = files.map(f => (f, f.lastModified)).toMap
|
||||
UpdateReport(report.cachedDescriptor, report.configurations, report.stats, stamps)
|
||||
}
|
||||
private[sbt] def recomputeStamps(): UpdateReport = {
|
||||
val files = report.cachedDescriptor +: allFiles
|
||||
val stamps = files.map(f => (f, f.lastModified)).toMap
|
||||
UpdateReport(report.cachedDescriptor, report.configurations, report.stats, stamps)
|
||||
}
|
||||
|
||||
import DependencyFilter._
|
||||
|
||||
|
|
@ -24,12 +23,19 @@ final class RichUpdateReport(report: UpdateReport) {
|
|||
def matching(f: DependencyFilter): Vector[File] = select0(f).distinct
|
||||
|
||||
/** Obtains all successfully retrieved files matching all provided filters. */
|
||||
def select(configuration: ConfigurationFilter, module: ModuleFilter, artifact: ArtifactFilter): Vector[File] =
|
||||
def select(
|
||||
configuration: ConfigurationFilter,
|
||||
module: ModuleFilter,
|
||||
artifact: ArtifactFilter
|
||||
): Vector[File] =
|
||||
matching(DependencyFilter.make(configuration, module, artifact))
|
||||
|
||||
def select(configuration: ConfigurationFilter): Vector[File] = select(configuration, moduleFilter(), artifactFilter())
|
||||
def select(module: ModuleFilter): Vector[File] = select(configurationFilter(), module, artifactFilter())
|
||||
def select(artifact: ArtifactFilter): Vector[File] = select(configurationFilter(), moduleFilter(), artifact)
|
||||
def select(configuration: ConfigurationFilter): Vector[File] =
|
||||
select(configuration, moduleFilter(), artifactFilter())
|
||||
def select(module: ModuleFilter): Vector[File] =
|
||||
select(configurationFilter(), module, artifactFilter())
|
||||
def select(artifact: ArtifactFilter): Vector[File] =
|
||||
select(configurationFilter(), moduleFilter(), artifact)
|
||||
|
||||
private[this] def select0(f: DependencyFilter): Vector[File] =
|
||||
for {
|
||||
|
|
@ -39,7 +45,9 @@ final class RichUpdateReport(report: UpdateReport) {
|
|||
if f(cReport.configuration, mReport.module, artifact)
|
||||
} yield {
|
||||
if (file == null) {
|
||||
sys.error(s"Null file: conf=${cReport.configuration}, module=${mReport.module}, art: $artifact")
|
||||
sys.error(
|
||||
s"Null file: conf=${cReport.configuration}, module=${mReport.module}, art: $artifact"
|
||||
)
|
||||
}
|
||||
file
|
||||
}
|
||||
|
|
@ -49,14 +57,20 @@ final class RichUpdateReport(report: UpdateReport) {
|
|||
moduleReportMap { (configuration, modReport) =>
|
||||
modReport
|
||||
.withArtifacts(
|
||||
modReport.artifacts filter { case (art, file) => f(configuration, modReport.module, art) }
|
||||
modReport.artifacts filter {
|
||||
case (art, file) => f(configuration, modReport.module, art)
|
||||
}
|
||||
)
|
||||
.withMissingArtifacts(
|
||||
modReport.missingArtifacts filter { art => f(configuration, modReport.module, art) }
|
||||
modReport.missingArtifacts filter { art =>
|
||||
f(configuration, modReport.module, art)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private[sbt] def substitute(f: (String, ModuleID, Vector[(Artifact, File)]) => Vector[(Artifact, File)]): UpdateReport =
|
||||
private[sbt] def substitute(
|
||||
f: (String, ModuleID, Vector[(Artifact, File)]) => Vector[(Artifact, File)]
|
||||
): UpdateReport =
|
||||
moduleReportMap { (configuration, modReport) =>
|
||||
val newArtifacts = f(configuration, modReport.module, modReport.artifacts)
|
||||
modReport
|
||||
|
|
@ -85,13 +99,14 @@ final class RichUpdateReport(report: UpdateReport) {
|
|||
.withMissingArtifacts((modReport.missingArtifacts ++ f(modReport.module)).distinct)
|
||||
}
|
||||
|
||||
private[sbt] def moduleReportMap(f: (String, ModuleReport) => ModuleReport): UpdateReport =
|
||||
{
|
||||
val newConfigurations = report.configurations.map { confReport =>
|
||||
import confReport._
|
||||
val newModules = modules map { modReport => f(configuration, modReport) }
|
||||
ConfigurationReport(configuration, newModules, details)
|
||||
private[sbt] def moduleReportMap(f: (String, ModuleReport) => ModuleReport): UpdateReport = {
|
||||
val newConfigurations = report.configurations.map { confReport =>
|
||||
import confReport._
|
||||
val newModules = modules map { modReport =>
|
||||
f(configuration, modReport)
|
||||
}
|
||||
UpdateReport(report.cachedDescriptor, newConfigurations, report.stats, report.stamps)
|
||||
ConfigurationReport(configuration, newModules, details)
|
||||
}
|
||||
UpdateReport(report.cachedDescriptor, newConfigurations, report.stats, report.stamps)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,20 +12,22 @@ import sbt.util.Logger
|
|||
* See also UpdateConfiguration in IvyActions.scala.
|
||||
*/
|
||||
final class UpdateOptions private[sbt] (
|
||||
// If set to CircularDependencyLevel.Error, halt the dependency resolution.
|
||||
val circularDependencyLevel: CircularDependencyLevel,
|
||||
// If set to true, prioritize inter-project resolver
|
||||
val interProjectFirst: Boolean,
|
||||
// If set to true, check all resolvers for snapshots.
|
||||
val latestSnapshots: Boolean,
|
||||
// If set to true, use consolidated resolution.
|
||||
val consolidatedResolution: Boolean,
|
||||
// If set to true, use cached resolution.
|
||||
val cachedResolution: Boolean,
|
||||
// Extension point for an alternative resolver converter.
|
||||
val resolverConverter: UpdateOptions.ResolverConverter
|
||||
// If set to CircularDependencyLevel.Error, halt the dependency resolution.
|
||||
val circularDependencyLevel: CircularDependencyLevel,
|
||||
// If set to true, prioritize inter-project resolver
|
||||
val interProjectFirst: Boolean,
|
||||
// If set to true, check all resolvers for snapshots.
|
||||
val latestSnapshots: Boolean,
|
||||
// If set to true, use consolidated resolution.
|
||||
val consolidatedResolution: Boolean,
|
||||
// If set to true, use cached resolution.
|
||||
val cachedResolution: Boolean,
|
||||
// Extension point for an alternative resolver converter.
|
||||
val resolverConverter: UpdateOptions.ResolverConverter
|
||||
) {
|
||||
def withCircularDependencyLevel(circularDependencyLevel: CircularDependencyLevel): UpdateOptions =
|
||||
def withCircularDependencyLevel(
|
||||
circularDependencyLevel: CircularDependencyLevel
|
||||
): UpdateOptions =
|
||||
copy(circularDependencyLevel = circularDependencyLevel)
|
||||
def withInterProjectFirst(interProjectFirst: Boolean): UpdateOptions =
|
||||
copy(interProjectFirst = interProjectFirst)
|
||||
|
|
@ -42,17 +44,18 @@ final class UpdateOptions private[sbt] (
|
|||
cachedResolution = cachedResoluton,
|
||||
consolidatedResolution = cachedResolution
|
||||
)
|
||||
|
||||
/** Extention point for an alternative resolver converter. */
|
||||
def withResolverConverter(resolverConverter: UpdateOptions.ResolverConverter): UpdateOptions =
|
||||
copy(resolverConverter = resolverConverter)
|
||||
|
||||
private[sbt] def copy(
|
||||
circularDependencyLevel: CircularDependencyLevel = this.circularDependencyLevel,
|
||||
interProjectFirst: Boolean = this.interProjectFirst,
|
||||
latestSnapshots: Boolean = this.latestSnapshots,
|
||||
consolidatedResolution: Boolean = this.consolidatedResolution,
|
||||
cachedResolution: Boolean = this.cachedResolution,
|
||||
resolverConverter: UpdateOptions.ResolverConverter = this.resolverConverter
|
||||
circularDependencyLevel: CircularDependencyLevel = this.circularDependencyLevel,
|
||||
interProjectFirst: Boolean = this.interProjectFirst,
|
||||
latestSnapshots: Boolean = this.latestSnapshots,
|
||||
consolidatedResolution: Boolean = this.consolidatedResolution,
|
||||
cachedResolution: Boolean = this.cachedResolution,
|
||||
resolverConverter: UpdateOptions.ResolverConverter = this.resolverConverter
|
||||
): UpdateOptions =
|
||||
new UpdateOptions(
|
||||
circularDependencyLevel,
|
||||
|
|
@ -73,16 +76,15 @@ final class UpdateOptions private[sbt] (
|
|||
case _ => false
|
||||
}
|
||||
|
||||
override def hashCode: Int =
|
||||
{
|
||||
var hash = 1
|
||||
hash = hash * 31 + this.circularDependencyLevel.##
|
||||
hash = hash * 31 + this.interProjectFirst.##
|
||||
hash = hash * 31 + this.latestSnapshots.##
|
||||
hash = hash * 31 + this.cachedResolution.##
|
||||
hash = hash * 31 + this.resolverConverter.##
|
||||
hash
|
||||
}
|
||||
override def hashCode: Int = {
|
||||
var hash = 1
|
||||
hash = hash * 31 + this.circularDependencyLevel.##
|
||||
hash = hash * 31 + this.interProjectFirst.##
|
||||
hash = hash * 31 + this.latestSnapshots.##
|
||||
hash = hash * 31 + this.cachedResolution.##
|
||||
hash = hash * 31 + this.resolverConverter.##
|
||||
hash
|
||||
}
|
||||
}
|
||||
|
||||
object UpdateOptions {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ abstract class ConfigurationReportExtra {
|
|||
}
|
||||
|
||||
def retrieve(f: (String, ModuleID, Artifact, File) => File): ConfigurationReport =
|
||||
ConfigurationReport(configuration, modules map { _.retrieve((mid, art, file) => f(configuration, mid, art, file)) }, details)
|
||||
ConfigurationReport(configuration, modules map {
|
||||
_.retrieve((mid, art, file) => f(configuration, mid, art, file))
|
||||
}, details)
|
||||
}
|
||||
|
||||
abstract class ModuleReportExtra {
|
||||
|
|
@ -52,7 +54,8 @@ abstract class ModuleReportExtra {
|
|||
def licenses: Vector[(String, Option[String])]
|
||||
def callers: Vector[Caller]
|
||||
|
||||
protected[this] def arts: Vector[String] = artifacts.map(_.toString) ++ missingArtifacts.map(art => "(MISSING) " + art)
|
||||
protected[this] def arts: Vector[String] =
|
||||
artifacts.map(_.toString) ++ missingArtifacts.map(art => "(MISSING) " + art)
|
||||
|
||||
def detailReport: String =
|
||||
s"\t\t- ${module.revision}\n" +
|
||||
|
|
@ -71,48 +74,50 @@ abstract class ModuleReportExtra {
|
|||
if (extraAttributes.isEmpty) None
|
||||
else { Some(extraAttributes.toString) }
|
||||
) +
|
||||
reportStr("isDefault", isDefault map { _.toString }) +
|
||||
reportStr("branch", branch) +
|
||||
reportStr(
|
||||
"configurations",
|
||||
if (configurations.isEmpty) None
|
||||
else { Some(configurations.mkString(", ")) }
|
||||
) +
|
||||
reportStr(
|
||||
"licenses",
|
||||
if (licenses.isEmpty) None
|
||||
else { Some(licenses.mkString(", ")) }
|
||||
) +
|
||||
reportStr(
|
||||
"callers",
|
||||
if (callers.isEmpty) None
|
||||
else { Some(callers.mkString(", ")) }
|
||||
)
|
||||
reportStr("isDefault", isDefault map { _.toString }) +
|
||||
reportStr("branch", branch) +
|
||||
reportStr(
|
||||
"configurations",
|
||||
if (configurations.isEmpty) None
|
||||
else { Some(configurations.mkString(", ")) }
|
||||
) +
|
||||
reportStr(
|
||||
"licenses",
|
||||
if (licenses.isEmpty) None
|
||||
else { Some(licenses.mkString(", ")) }
|
||||
) +
|
||||
reportStr(
|
||||
"callers",
|
||||
if (callers.isEmpty) None
|
||||
else { Some(callers.mkString(", ")) }
|
||||
)
|
||||
private[sbt] def reportStr(key: String, value: Option[String]): String =
|
||||
value map { x => s"\t\t\t$key: $x\n" } getOrElse ""
|
||||
value map { x =>
|
||||
s"\t\t\t$key: $x\n"
|
||||
} getOrElse ""
|
||||
|
||||
def retrieve(f: (ModuleID, Artifact, File) => File): ModuleReport =
|
||||
copy(artifacts = artifacts.map { case (art, file) => (art, f(module, art, file)) })
|
||||
|
||||
protected[this] def copy(
|
||||
module: ModuleID = module,
|
||||
artifacts: Vector[(Artifact, File)] = artifacts,
|
||||
missingArtifacts: Vector[Artifact] = missingArtifacts,
|
||||
status: Option[String] = status,
|
||||
publicationDate: Option[ju.Calendar] = publicationDate,
|
||||
resolver: Option[String] = resolver,
|
||||
artifactResolver: Option[String] = artifactResolver,
|
||||
evicted: Boolean = evicted,
|
||||
evictedData: Option[String] = evictedData,
|
||||
evictedReason: Option[String] = evictedReason,
|
||||
problem: Option[String] = problem,
|
||||
homepage: Option[String] = homepage,
|
||||
extraAttributes: Map[String, String] = extraAttributes,
|
||||
isDefault: Option[Boolean] = isDefault,
|
||||
branch: Option[String] = branch,
|
||||
configurations: Vector[String] = configurations,
|
||||
licenses: Vector[(String, Option[String])] = licenses,
|
||||
callers: Vector[Caller] = callers
|
||||
module: ModuleID = module,
|
||||
artifacts: Vector[(Artifact, File)] = artifacts,
|
||||
missingArtifacts: Vector[Artifact] = missingArtifacts,
|
||||
status: Option[String] = status,
|
||||
publicationDate: Option[ju.Calendar] = publicationDate,
|
||||
resolver: Option[String] = resolver,
|
||||
artifactResolver: Option[String] = artifactResolver,
|
||||
evicted: Boolean = evicted,
|
||||
evictedData: Option[String] = evictedData,
|
||||
evictedReason: Option[String] = evictedReason,
|
||||
problem: Option[String] = problem,
|
||||
homepage: Option[String] = homepage,
|
||||
extraAttributes: Map[String, String] = extraAttributes,
|
||||
isDefault: Option[Boolean] = isDefault,
|
||||
branch: Option[String] = branch,
|
||||
configurations: Vector[String] = configurations,
|
||||
licenses: Vector[(String, Option[String])] = licenses,
|
||||
callers: Vector[Caller] = callers
|
||||
): ModuleReport
|
||||
}
|
||||
|
||||
|
|
@ -123,22 +128,21 @@ abstract class UpdateReportExtra {
|
|||
private[sbt] def stamps: Map[File, Long]
|
||||
|
||||
/** All resolved modules in all configurations. */
|
||||
def allModules: Vector[ModuleID] =
|
||||
{
|
||||
val key = (m: ModuleID) => (m.organization, m.name, m.revision)
|
||||
configurations.flatMap(_.allModules).groupBy(key).toVector map {
|
||||
case (k, v) =>
|
||||
v reduceLeft { (agg, x) =>
|
||||
agg.withConfigurations(
|
||||
(agg.configurations, x.configurations) match {
|
||||
case (None, _) => x.configurations
|
||||
case (Some(ac), None) => Some(ac)
|
||||
case (Some(ac), Some(xc)) => Some(s"$ac;$xc")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
def allModules: Vector[ModuleID] = {
|
||||
val key = (m: ModuleID) => (m.organization, m.name, m.revision)
|
||||
configurations.flatMap(_.allModules).groupBy(key).toVector map {
|
||||
case (k, v) =>
|
||||
v reduceLeft { (agg, x) =>
|
||||
agg.withConfigurations(
|
||||
(agg.configurations, x.configurations) match {
|
||||
case (None, _) => x.configurations
|
||||
case (Some(ac), None) => Some(ac)
|
||||
case (Some(ac), Some(xc)) => Some(s"$ac;$xc")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def retrieve(f: (String, ModuleID, Artifact, File) => File): UpdateReport =
|
||||
UpdateReport(cachedDescriptor, configurations map { _ retrieve f }, stats, stamps)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package sbt.librarymanagement
|
||||
|
||||
final class VersionNumber private[sbt] (
|
||||
val numbers: Seq[Long],
|
||||
val tags: Seq[String],
|
||||
val extras: Seq[String]
|
||||
val numbers: Seq[Long],
|
||||
val tags: Seq[String],
|
||||
val extras: Seq[String]
|
||||
) {
|
||||
def _1: Option[Long] = get(0)
|
||||
def _2: Option[Long] = get(1)
|
||||
|
|
@ -33,12 +33,14 @@ final class VersionNumber private[sbt] (
|
|||
extras.hashCode
|
||||
override def equals(o: Any): Boolean =
|
||||
o match {
|
||||
case v: VersionNumber => (this.numbers == v.numbers) && (this.tags == v.tags) && (this.extras == v.extras)
|
||||
case _ => false
|
||||
case v: VersionNumber =>
|
||||
(this.numbers == v.numbers) && (this.tags == v.tags) && (this.extras == v.extras)
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
object VersionNumber {
|
||||
|
||||
/**
|
||||
* @param numbers numbers delimited by a dot.
|
||||
* @param tags string prefixed by a dash.
|
||||
|
|
@ -74,10 +76,11 @@ object VersionNumber {
|
|||
val TaggedVersion = """(\d{1,14})([\.\d{1,14}]*)((?:-\w+)*)((?:\+.+)*)""".r
|
||||
val NonSpaceString = """(\S+)""".r
|
||||
v match {
|
||||
case TaggedVersion(m, ns, ts, es) => Some((Vector(m.toLong) ++ splitDot(ns), splitDash(ts), splitPlus(es)))
|
||||
case "" => None
|
||||
case NonSpaceString(s) => Some((Vector(), Vector(), Vector(s)))
|
||||
case _ => None
|
||||
case TaggedVersion(m, ns, ts, es) =>
|
||||
Some((Vector(m.toLong) ++ splitDot(ns), splitDash(ts), splitPlus(es)))
|
||||
case "" => None
|
||||
case NonSpaceString(s) => Some((Vector(), Vector(), Vector(s)))
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,8 +101,18 @@ object VersionNumber {
|
|||
doIsCompat(v1, v2) || doIsCompat(v2, v1)
|
||||
private[this] def doIsCompat(v1: VersionNumber, v2: VersionNumber): Boolean =
|
||||
(v1, v2) match {
|
||||
case (v1, v2) if (v1.size >= 2) && (v2.size >= 2) => // A normal version number MUST take the form X.Y.Z
|
||||
(v1._1.get, v1._2.get, v1._3.getOrElse(0L), v1.tags, v2._1.get, v2._2.get, v2._3.getOrElse(0L), v2.tags) match {
|
||||
case (v1, v2)
|
||||
if (v1.size >= 2) && (v2.size >= 2) => // A normal version number MUST take the form X.Y.Z
|
||||
(
|
||||
v1._1.get,
|
||||
v1._2.get,
|
||||
v1._3.getOrElse(0L),
|
||||
v1.tags,
|
||||
v2._1.get,
|
||||
v2._2.get,
|
||||
v2._3.getOrElse(0L),
|
||||
v2.tags
|
||||
) match {
|
||||
case (0L, _, _, _, 0L, _, _, _) =>
|
||||
// Major version zero (0.y.z) is for initial development. Anything may change at any time. The public API should not be considered stable.
|
||||
equalsIgnoreExtra(v1, v2)
|
||||
|
|
@ -107,8 +120,8 @@ object VersionNumber {
|
|||
// A pre-release version MAY be denoted by appending a hyphen and a series of dot separated identifiers
|
||||
equalsIgnoreExtra(v1, v2)
|
||||
case (x1, _, _, _, x2, _, _, _) =>
|
||||
// Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards compatible bug fixes are introduced.
|
||||
// Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backwards compatible functionality is introduced
|
||||
// Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards compatible bug fixes are introduced.
|
||||
// Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backwards compatible functionality is introduced
|
||||
x1 == x2
|
||||
case _ => equalsIgnoreExtra(v1, v2)
|
||||
}
|
||||
|
|
@ -129,13 +142,14 @@ object VersionNumber {
|
|||
doIsCompat(v1, v2) || doIsCompat(v2, v1)
|
||||
private[this] def doIsCompat(v1: VersionNumber, v2: VersionNumber): Boolean =
|
||||
(v1, v2) match {
|
||||
case (v1, v2) if (v1.size >= 3) && (v2.size >= 3) => // A normal version number MUST take the form X.Y.Z
|
||||
case (v1, v2)
|
||||
if (v1.size >= 3) && (v2.size >= 3) => // A normal version number MUST take the form X.Y.Z
|
||||
(v1._1.get, v1._2.get, v1._3.get, v1.tags, v2._1.get, v2._2.get, v2._3.get, v2.tags) match {
|
||||
case (x1, y1, 0, ts1, x2, y2, 0, ts2) if ts1.nonEmpty || ts2.nonEmpty =>
|
||||
// A pre-release version MAY be denoted by appending a hyphen and a series of dot separated identifiers
|
||||
equalsIgnoreExtra(v1, v2)
|
||||
case (x1, y1, _, _, x2, y2, _, _) =>
|
||||
// Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards compatible changes are introduced.
|
||||
// Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards compatible changes are introduced.
|
||||
(x1 == x2) && (y1 == y2)
|
||||
case _ => equalsIgnoreExtra(v1, v2)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,17 @@ trait BaseIvySpecification extends UnitSpec {
|
|||
def currentTarget: File = currentBase / "target" / "ivyhome"
|
||||
def currentManaged: File = currentBase / "target" / "lib_managed"
|
||||
def currentDependency: File = currentBase / "target" / "dependency"
|
||||
def defaultModuleId: ModuleID = ModuleID("com.example", "foo", "0.1.0").withConfigurations(Some("compile"))
|
||||
def defaultModuleId: ModuleID =
|
||||
ModuleID("com.example", "foo", "0.1.0").withConfigurations(Some("compile"))
|
||||
|
||||
lazy val log = ConsoleLogger()
|
||||
|
||||
def configurations = Vector(Compile, Test, Runtime)
|
||||
def module(moduleId: ModuleID, deps: Vector[ModuleID], scalaFullVersion: Option[String],
|
||||
uo: UpdateOptions = UpdateOptions(), overrideScalaVersion: Boolean = true): IvySbt#Module = {
|
||||
def module(moduleId: ModuleID,
|
||||
deps: Vector[ModuleID],
|
||||
scalaFullVersion: Option[String],
|
||||
uo: UpdateOptions = UpdateOptions(),
|
||||
overrideScalaVersion: Boolean = true): IvySbt#Module = {
|
||||
val ivyScala = scalaFullVersion map { fv =>
|
||||
IvyScala(
|
||||
scalaFullVersion = fv,
|
||||
|
|
@ -53,23 +57,42 @@ trait BaseIvySpecification extends UnitSpec {
|
|||
val off = false
|
||||
val check = Vector.empty
|
||||
val resCacheDir = currentTarget / "resolution-cache"
|
||||
new InlineIvyConfiguration(paths, resolvers, other, moduleConfs, off, None, check, Some(resCacheDir), uo, log)
|
||||
new InlineIvyConfiguration(paths,
|
||||
resolvers,
|
||||
other,
|
||||
moduleConfs,
|
||||
off,
|
||||
None,
|
||||
check,
|
||||
Some(resCacheDir),
|
||||
uo,
|
||||
log)
|
||||
}
|
||||
|
||||
def makeUpdateConfiguration: UpdateConfiguration = {
|
||||
val retrieveConfig = RetrieveConfiguration(currentManaged, Resolver.defaultRetrievePattern).withSync(false)
|
||||
UpdateConfiguration(Some(retrieveConfig), false, UpdateLogging.Full, ArtifactTypeFilter.forbid(Set("src", "doc")))
|
||||
val retrieveConfig =
|
||||
RetrieveConfiguration(currentManaged, Resolver.defaultRetrievePattern).withSync(false)
|
||||
UpdateConfiguration(Some(retrieveConfig),
|
||||
false,
|
||||
UpdateLogging.Full,
|
||||
ArtifactTypeFilter.forbid(Set("src", "doc")))
|
||||
}
|
||||
|
||||
def ivyUpdateEither(module: IvySbt#Module): Either[UnresolvedWarning, UpdateReport] = {
|
||||
// IO.delete(currentTarget)
|
||||
val config = makeUpdateConfiguration
|
||||
IvyActions.updateEither(module, config, UnresolvedWarningConfiguration(), LogicalClock.unknown, Some(currentDependency), log)
|
||||
IvyActions.updateEither(module,
|
||||
config,
|
||||
UnresolvedWarningConfiguration(),
|
||||
LogicalClock.unknown,
|
||||
Some(currentDependency),
|
||||
log)
|
||||
}
|
||||
|
||||
def cleanIvyCache(): Unit = IO.delete(currentTarget / "cache")
|
||||
|
||||
def cleanCachedResolutionCache(module: IvySbt#Module): Unit = IvyActions.cleanCachedResolutionCache(module, log)
|
||||
def cleanCachedResolutionCache(module: IvySbt#Module): Unit =
|
||||
IvyActions.cleanCachedResolutionCache(module, log)
|
||||
|
||||
def ivyUpdate(module: IvySbt#Module) =
|
||||
ivyUpdateEither(module) match {
|
||||
|
|
@ -78,7 +101,8 @@ trait BaseIvySpecification extends UnitSpec {
|
|||
throw w.resolveException
|
||||
}
|
||||
|
||||
def mkPublishConfiguration(resolver: Resolver, artifacts: Map[Artifact, File]): PublishConfiguration = {
|
||||
def mkPublishConfiguration(resolver: Resolver,
|
||||
artifacts: Map[Artifact, File]): PublishConfiguration = {
|
||||
new PublishConfiguration(
|
||||
ivyFile = None,
|
||||
resolverName = resolver.name,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ class CachedResolutionSpec extends BaseIvySpecification {
|
|||
cleanIvyCache()
|
||||
val m = module(
|
||||
ModuleID("com.example", "foo", "0.1.0").withConfigurations(Some("compile")),
|
||||
Vector(commonsIo13), Some("2.10.2"), UpdateOptions().withCachedResolution(true)
|
||||
Vector(commonsIo13),
|
||||
Some("2.10.2"),
|
||||
UpdateOptions().withCachedResolution(true)
|
||||
)
|
||||
val report = ivyUpdate(m)
|
||||
cleanCachedResolutionCache(m)
|
||||
|
|
@ -26,7 +28,9 @@ class CachedResolutionSpec extends BaseIvySpecification {
|
|||
// log.setLevel(Level.Debug)
|
||||
val m = module(
|
||||
ModuleID("com.example", "foo", "0.2.0").withConfigurations(Some("compile")),
|
||||
Vector(mavenCayennePlugin302), Some("2.10.2"), UpdateOptions().withCachedResolution(true)
|
||||
Vector(mavenCayennePlugin302),
|
||||
Some("2.10.2"),
|
||||
UpdateOptions().withCachedResolution(true)
|
||||
)
|
||||
ivyUpdateEither(m) match {
|
||||
case Right(_) => sys.error("this should've failed")
|
||||
|
|
@ -37,10 +41,10 @@ class CachedResolutionSpec extends BaseIvySpecification {
|
|||
case Right(_) => sys.error("this should've failed 2")
|
||||
case Left(uw) =>
|
||||
uw.lines should contain allOf ("\n\tNote: Unresolved dependencies path:",
|
||||
"\t\tfoundrylogic.vpp:vpp:2.2.1",
|
||||
"\t\t +- org.apache.cayenne:cayenne-tools:3.0.2",
|
||||
"\t\t +- org.apache.cayenne.plugins:maven-cayenne-plugin:3.0.2",
|
||||
"\t\t +- com.example:foo:0.2.0")
|
||||
"\t\tfoundrylogic.vpp:vpp:2.2.1",
|
||||
"\t\t +- org.apache.cayenne:cayenne-tools:3.0.2",
|
||||
"\t\t +- org.apache.cayenne.plugins:maven-cayenne-plugin:3.0.2",
|
||||
"\t\t +- com.example:foo:0.2.0")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +58,8 @@ class CachedResolutionSpec extends BaseIvySpecification {
|
|||
val m = module(
|
||||
ModuleID("com.example", "foo", "0.3.0").withConfigurations(Some("compile")),
|
||||
Vector(avro177, dataAvro1940, netty320),
|
||||
Some("2.10.2"), UpdateOptions().withCachedResolution(true)
|
||||
Some("2.10.2"),
|
||||
UpdateOptions().withCachedResolution(true)
|
||||
)
|
||||
// first resolution creates the minigraph
|
||||
val _ = ivyUpdate(m)
|
||||
|
|
@ -62,15 +67,23 @@ class CachedResolutionSpec extends BaseIvySpecification {
|
|||
// second resolution reads from the minigraph
|
||||
val report = ivyUpdate(m)
|
||||
val modules: Seq[String] = report.configurations.head.modules map { _.toString }
|
||||
assert(modules exists { x: String => x contains """org.jboss.netty:netty:3.2.0.Final""" })
|
||||
assert(!(modules exists { x: String => x contains """org.jboss.netty:netty:3.2.1.Final""" }))
|
||||
assert(modules exists { x: String =>
|
||||
x contains """org.jboss.netty:netty:3.2.0.Final"""
|
||||
})
|
||||
assert(!(modules exists { x: String =>
|
||||
x contains """org.jboss.netty:netty:3.2.1.Final"""
|
||||
}))
|
||||
}
|
||||
|
||||
def commonsIo13 = ModuleID("commons-io", "commons-io", "1.3").withConfigurations(Some("compile"))
|
||||
def mavenCayennePlugin302 = ModuleID("org.apache.cayenne.plugins", "maven-cayenne-plugin", "3.0.2").withConfigurations(Some("compile"))
|
||||
def mavenCayennePlugin302 =
|
||||
ModuleID("org.apache.cayenne.plugins", "maven-cayenne-plugin", "3.0.2").withConfigurations(
|
||||
Some("compile"))
|
||||
def avro177 = ModuleID("org.apache.avro", "avro", "1.7.7").withConfigurations(Some("compile"))
|
||||
def dataAvro1940 = ModuleID("com.linkedin.pegasus", "data-avro", "1.9.40").withConfigurations(Some("compile"))
|
||||
def netty320 = ModuleID("org.jboss.netty", "netty", "3.2.0.Final").withConfigurations(Some("compile"))
|
||||
def dataAvro1940 =
|
||||
ModuleID("com.linkedin.pegasus", "data-avro", "1.9.40").withConfigurations(Some("compile"))
|
||||
def netty320 =
|
||||
ModuleID("org.jboss.netty", "netty", "3.2.0.Final").withConfigurations(Some("compile"))
|
||||
|
||||
def defaultOptions = EvictionWarningOptions.default
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,11 +73,16 @@ class ComponentManagerTest extends UnitSpec {
|
|||
}
|
||||
|
||||
private def checksum(files: Iterable[File]): Seq[String] = files.map(checksum).toSeq
|
||||
private def checksum(file: File): String = if (file.exists) ChecksumHelper.computeAsString(file, "sha1") else ""
|
||||
private def defineFile(manager: ComponentManager, id: String, name: String): String = createFile(manager, id, name)(checksum)
|
||||
private def defineFiles(manager: ComponentManager, id: String, names: String*): Seq[String] = createFiles(manager, id, names: _*)(checksum)
|
||||
private def createFile[T](manager: ComponentManager, id: String, name: String)(f: File => T): T = createFiles(manager, id, name)(files => f(files.toList.head))
|
||||
private def createFiles[T](manager: ComponentManager, id: String, names: String*)(f: Seq[File] => T): T =
|
||||
private def checksum(file: File): String =
|
||||
if (file.exists) ChecksumHelper.computeAsString(file, "sha1") else ""
|
||||
private def defineFile(manager: ComponentManager, id: String, name: String): String =
|
||||
createFile(manager, id, name)(checksum)
|
||||
private def defineFiles(manager: ComponentManager, id: String, names: String*): Seq[String] =
|
||||
createFiles(manager, id, names: _*)(checksum)
|
||||
private def createFile[T](manager: ComponentManager, id: String, name: String)(f: File => T): T =
|
||||
createFiles(manager, id, name)(files => f(files.toList.head))
|
||||
private def createFiles[T](manager: ComponentManager, id: String, names: String*)(
|
||||
f: Seq[File] => T): T =
|
||||
withTemporaryDirectory { dir =>
|
||||
val files = names.map(name => new File(dir, name))
|
||||
files.foreach(writeRandomContent)
|
||||
|
|
@ -87,7 +92,9 @@ class ComponentManagerTest extends UnitSpec {
|
|||
private def writeRandomContent(file: File) = IO.write(file, randomString)
|
||||
private def randomString = "asdf"
|
||||
private def withManager[T](f: ComponentManager => T): T =
|
||||
withTemporaryDirectory { ivyHome => withManagerHome(ivyHome)(f) }
|
||||
withTemporaryDirectory { ivyHome =>
|
||||
withManagerHome(ivyHome)(f)
|
||||
}
|
||||
|
||||
private def withManagerHome[T](ivyHome: File)(f: ComponentManager => T): T =
|
||||
TestLogger { logger =>
|
||||
|
|
@ -105,19 +112,26 @@ class ComponentManagerTest extends UnitSpec {
|
|||
override def defineComponent(id: String, files: Array[File]): Unit = {
|
||||
val location = componentLocation(id)
|
||||
if (location.exists)
|
||||
throw new RuntimeException(s"Cannot redefine component. ID: $id, files: ${files.mkString(",")}")
|
||||
throw new RuntimeException(
|
||||
s"Cannot redefine component. ID: $id, files: ${files.mkString(",")}")
|
||||
else {
|
||||
IO.copy(files.map { f => f -> new java.io.File(location, f.getName) })
|
||||
IO.copy(files.map { f =>
|
||||
f -> new java.io.File(location, f.getName)
|
||||
})
|
||||
()
|
||||
}
|
||||
}
|
||||
override def addToComponent(id: String, files: Array[File]): Boolean = {
|
||||
val location = componentLocation(id)
|
||||
IO.copy(files.map { f => f -> new java.io.File(location, f.getName) })
|
||||
IO.copy(files.map { f =>
|
||||
f -> new java.io.File(location, f.getName)
|
||||
})
|
||||
true
|
||||
}
|
||||
override def component(id: String): Array[File] =
|
||||
Option(componentLocation(id).listFiles()).map(_.filter(_.isFile)).getOrElse(Array.empty)
|
||||
Option(componentLocation(id).listFiles())
|
||||
.map(_.filter(_.isFile))
|
||||
.getOrElse(Array.empty)
|
||||
}
|
||||
// A stubbed locking API.
|
||||
object locks extends xsbti.GlobalLock {
|
||||
|
|
|
|||
|
|
@ -118,22 +118,28 @@ class CrossVersionTest extends UnitSpec {
|
|||
CrossVersion.binaryScalaVersion("2.20170314093845.0-87654321") shouldBe "2.20170314093845.0-87654321"
|
||||
}
|
||||
it should "return patch Scala version for 2.11.8 as 2.11.8" in {
|
||||
CrossVersion(CrossVersion.patch, "2.11.8", "dummy").map(_("artefact")) shouldBe Some("artefact_2.11.8")
|
||||
CrossVersion(CrossVersion.patch, "2.11.8", "dummy").map(_("artefact")) shouldBe Some(
|
||||
"artefact_2.11.8")
|
||||
}
|
||||
it should "return patch Scala version for 2.11.8-M1 as 2.11.8-M1" in {
|
||||
CrossVersion(CrossVersion.patch, "2.11.8-M1", "dummy").map(_("artefact")) shouldBe Some("artefact_2.11.8-M1")
|
||||
CrossVersion(CrossVersion.patch, "2.11.8-M1", "dummy").map(_("artefact")) shouldBe Some(
|
||||
"artefact_2.11.8-M1")
|
||||
}
|
||||
it should "return patch Scala version for 2.11.8-RC1 as 2.11.8-RC1" in {
|
||||
CrossVersion(CrossVersion.patch, "2.11.8-RC1", "dummy").map(_("artefact")) shouldBe Some("artefact_2.11.8-RC1")
|
||||
CrossVersion(CrossVersion.patch, "2.11.8-RC1", "dummy").map(_("artefact")) shouldBe Some(
|
||||
"artefact_2.11.8-RC1")
|
||||
}
|
||||
it should "return patch Scala version for 2.11.8-bin-extra as 2.11.8" in {
|
||||
CrossVersion(CrossVersion.patch, "2.11.8-bin-extra", "dummy").map(_("artefact")) shouldBe Some("artefact_2.11.8")
|
||||
CrossVersion(CrossVersion.patch, "2.11.8-bin-extra", "dummy").map(_("artefact")) shouldBe Some(
|
||||
"artefact_2.11.8")
|
||||
}
|
||||
it should "return patch Scala version for 2.11.8-M1-bin-extra as 2.11.8-M1" in {
|
||||
CrossVersion(CrossVersion.patch, "2.11.8-M1-bin-extra", "dummy").map(_("artefact")) shouldBe Some("artefact_2.11.8-M1")
|
||||
CrossVersion(CrossVersion.patch, "2.11.8-M1-bin-extra", "dummy")
|
||||
.map(_("artefact")) shouldBe Some("artefact_2.11.8-M1")
|
||||
}
|
||||
it should "return patch Scala version for 2.11.8-RC1-bin-extra as 2.11.8-RC1" in {
|
||||
CrossVersion(CrossVersion.patch, "2.11.8-RC1-bin-extra", "dummy").map(_("artefact")) shouldBe Some("artefact_2.11.8-RC1")
|
||||
CrossVersion(CrossVersion.patch, "2.11.8-RC1-bin-extra", "dummy")
|
||||
.map(_("artefact")) shouldBe Some("artefact_2.11.8-RC1")
|
||||
}
|
||||
it should "return disabled cross version as equal to a copy" in {
|
||||
Disabled() shouldBe Disabled()
|
||||
|
|
|
|||
|
|
@ -15,7 +15,16 @@ class CustomPomParserTest extends UnitSpec {
|
|||
val repoUrl = getClass.getResource("/test-maven-repo")
|
||||
val local = MavenRepository("Test Repo", repoUrl.toExternalForm)
|
||||
val paths = IvyPaths(new File("."), Some(cacheDir))
|
||||
val conf = new InlineIvyConfiguration(paths, Vector(local), Vector.empty, Vector.empty, false, None, Vector("sha1", "md5"), None, UpdateOptions(), log)
|
||||
val conf = new InlineIvyConfiguration(paths,
|
||||
Vector(local),
|
||||
Vector.empty,
|
||||
Vector.empty,
|
||||
false,
|
||||
None,
|
||||
Vector("sha1", "md5"),
|
||||
None,
|
||||
UpdateOptions(),
|
||||
log)
|
||||
val ivySbt = new IvySbt(conf)
|
||||
val resolveOpts = new ResolveOptions().setConfs(Array("default"))
|
||||
val mrid = ModuleRevisionId.newInstance("com.test", "test-artifact", "1.0.0-SNAPSHOT")
|
||||
|
|
@ -26,7 +35,8 @@ class CustomPomParserTest extends UnitSpec {
|
|||
|
||||
resolveReport.hasError shouldBe false
|
||||
resolveReport.getArtifacts.size() shouldBe 1
|
||||
val artifact: IvyArtifact = resolveReport.getArtifacts.asInstanceOf[java.util.List[IvyArtifact]].get(0)
|
||||
val artifact: IvyArtifact =
|
||||
resolveReport.getArtifacts.asInstanceOf[java.util.List[IvyArtifact]].get(0)
|
||||
artifact.getModuleRevisionId shouldBe mrid
|
||||
artifact.getExt shouldBe "jar"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,11 +52,14 @@ class DMSerializationSpec extends UnitSpec {
|
|||
}
|
||||
|
||||
lazy val updateReportExample =
|
||||
UpdateReport(new File("./foo"), Vector(configurationReportExample),
|
||||
UpdateStats(0, 0, 0, false), Map(new File("./foo") -> 0))
|
||||
UpdateReport(new File("./foo"),
|
||||
Vector(configurationReportExample),
|
||||
UpdateStats(0, 0, 0, false),
|
||||
Map(new File("./foo") -> 0))
|
||||
lazy val configurationReportExample =
|
||||
ConfigurationReport("compile", Vector(moduleReportExample),
|
||||
Vector(organizationArtifactReportExample))
|
||||
ConfigurationReport("compile",
|
||||
Vector(moduleReportExample),
|
||||
Vector(organizationArtifactReportExample))
|
||||
lazy val organizationArtifactReportExample =
|
||||
OrganizationArtifactReport("org", "name", Vector(moduleReportExample))
|
||||
lazy val moduleReportExample =
|
||||
|
|
@ -68,13 +71,13 @@ class DMSerializationSpec extends UnitSpec {
|
|||
def roundtripStr[A: JsonReader: JsonWriter](a: A): Assertion =
|
||||
roundtripBuilder(a) { _.toString shouldBe _.toString }
|
||||
|
||||
def roundtripBuilder[A: JsonReader: JsonWriter](a: A)(f: (A, A) => Assertion): Assertion =
|
||||
{
|
||||
val json = isoString to (Converter toJsonUnsafe a)
|
||||
println(json)
|
||||
val obj = Converter fromJsonUnsafe[A] (isoString from json)
|
||||
f(a, obj)
|
||||
}
|
||||
def roundtripBuilder[A: JsonReader: JsonWriter](a: A)(f: (A, A) => Assertion): Assertion = {
|
||||
val json = isoString to (Converter toJsonUnsafe a)
|
||||
println(json)
|
||||
val obj = Converter fromJsonUnsafe [A] (isoString from json)
|
||||
f(a, obj)
|
||||
}
|
||||
|
||||
implicit val isoString: IsoString[JValue] = IsoString.iso(CompactPrinter.apply, FixedParser.parseUnsafe)
|
||||
implicit val isoString: IsoString[JValue] =
|
||||
IsoString.iso(CompactPrinter.apply, FixedParser.parseUnsafe)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,19 +44,29 @@ class EvictionWarningSpec extends BaseIvySpecification {
|
|||
it should "be detected if it's enabled" in scalaLibTransitiveWarn2()
|
||||
it should "print out message about the eviction if it's enabled" in scalaLibTransitiveWarn3()
|
||||
|
||||
def akkaActor214 = ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations(Some("compile")) cross CrossVersion.binary
|
||||
def akkaActor230 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("compile")) cross CrossVersion.binary
|
||||
def akkaActor234 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.4").withConfigurations(Some("compile")) cross CrossVersion.binary
|
||||
def scala2102 = ModuleID("org.scala-lang", "scala-library", "2.10.2").withConfigurations(Some("compile"))
|
||||
def scala2103 = ModuleID("org.scala-lang", "scala-library", "2.10.3").withConfigurations(Some("compile"))
|
||||
def scala2104 = ModuleID("org.scala-lang", "scala-library", "2.10.4").withConfigurations(Some("compile"))
|
||||
def akkaActor214 =
|
||||
ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations(Some("compile")) cross CrossVersion.binary
|
||||
def akkaActor230 =
|
||||
ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("compile")) cross CrossVersion.binary
|
||||
def akkaActor234 =
|
||||
ModuleID("com.typesafe.akka", "akka-actor", "2.3.4").withConfigurations(Some("compile")) cross CrossVersion.binary
|
||||
def scala2102 =
|
||||
ModuleID("org.scala-lang", "scala-library", "2.10.2").withConfigurations(Some("compile"))
|
||||
def scala2103 =
|
||||
ModuleID("org.scala-lang", "scala-library", "2.10.3").withConfigurations(Some("compile"))
|
||||
def scala2104 =
|
||||
ModuleID("org.scala-lang", "scala-library", "2.10.4").withConfigurations(Some("compile"))
|
||||
def commonsIo13 = ModuleID("commons-io", "commons-io", "1.3").withConfigurations(Some("compile"))
|
||||
def commonsIo14 = ModuleID("commons-io", "commons-io", "1.4").withConfigurations(Some("compile"))
|
||||
def commonsIo24 = ModuleID("commons-io", "commons-io", "2.4").withConfigurations(Some("compile"))
|
||||
def bnfparser10 = ModuleID("ca.gobits.bnf", "bnfparser", "1.0").withConfigurations(Some("compile")) // uses commons-io 2.4
|
||||
def unfilteredUploads080 = ModuleID("net.databinder", "unfiltered-uploads", "0.8.0").withConfigurations(Some("compile")) cross CrossVersion.binary // uses commons-io 1.4
|
||||
def bananaSesame04 = ModuleID("org.w3", "banana-sesame", "0.4").withConfigurations(Some("compile")) cross CrossVersion.binary // uses akka-actor 2.1.4
|
||||
def akkaRemote234 = ModuleID("com.typesafe.akka", "akka-remote", "2.3.4").withConfigurations(Some("compile")) cross CrossVersion.binary // uses akka-actor 2.3.4
|
||||
def bnfparser10 =
|
||||
ModuleID("ca.gobits.bnf", "bnfparser", "1.0").withConfigurations(Some("compile")) // uses commons-io 2.4
|
||||
def unfilteredUploads080 =
|
||||
ModuleID("net.databinder", "unfiltered-uploads", "0.8.0").withConfigurations(Some("compile")) cross CrossVersion.binary // uses commons-io 1.4
|
||||
def bananaSesame04 =
|
||||
ModuleID("org.w3", "banana-sesame", "0.4").withConfigurations(Some("compile")) cross CrossVersion.binary // uses akka-actor 2.1.4
|
||||
def akkaRemote234 =
|
||||
ModuleID("com.typesafe.akka", "akka-remote", "2.3.4").withConfigurations(Some("compile")) cross CrossVersion.binary // uses akka-actor 2.3.4
|
||||
|
||||
def defaultOptions = EvictionWarningOptions.default
|
||||
|
||||
|
|
@ -181,7 +191,10 @@ class EvictionWarningSpec extends BaseIvySpecification {
|
|||
def javaLibTransitiveWarn3() = {
|
||||
val m = module(defaultModuleId, javaLibTransitiveDeps, Some("2.10.3"))
|
||||
val report = ivyUpdate(m)
|
||||
EvictionWarning(m, defaultOptions.withWarnTransitiveEvictions(true).withShowCallers(true), report, log).lines shouldBe
|
||||
EvictionWarning(m,
|
||||
defaultOptions.withWarnTransitiveEvictions(true).withShowCallers(true),
|
||||
report,
|
||||
log).lines shouldBe
|
||||
List(
|
||||
"There may be incompatibilities among your library dependencies.",
|
||||
"Here are some of the libraries that were evicted:",
|
||||
|
|
@ -240,7 +253,10 @@ class EvictionWarningSpec extends BaseIvySpecification {
|
|||
def scalaLibTransitiveWarn3() = {
|
||||
val m = module(defaultModuleId, scalaLibTransitiveDeps, Some("2.10.4"))
|
||||
val report = ivyUpdate(m)
|
||||
EvictionWarning(m, defaultOptions.withWarnTransitiveEvictions(true).withShowCallers(true), report, log).lines shouldBe
|
||||
EvictionWarning(m,
|
||||
defaultOptions.withWarnTransitiveEvictions(true).withShowCallers(true),
|
||||
report,
|
||||
log).lines shouldBe
|
||||
List(
|
||||
"There may be incompatibilities among your library dependencies.",
|
||||
"Here are some of the libraries that were evicted:",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ class InconsistentDuplicateSpec extends UnitSpec {
|
|||
IvySbt.inconsistentDuplicateWarning(Seq(akkaActor230Test, akkaActor230)) shouldBe Nil
|
||||
}
|
||||
|
||||
def akkaActor214 = ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations(Some("compile")) cross CrossVersion.binary
|
||||
def akkaActor230 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("compile")) cross CrossVersion.binary
|
||||
def akkaActor230Test = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("test")) cross CrossVersion.binary
|
||||
def akkaActor214 =
|
||||
ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations(Some("compile")) cross CrossVersion.binary
|
||||
def akkaActor230 =
|
||||
ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("compile")) cross CrossVersion.binary
|
||||
def akkaActor230Test =
|
||||
ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("test")) cross CrossVersion.binary
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,4 +75,3 @@ class MakePomSpec extends UnitSpec {
|
|||
()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ class MergeDescriptorSpec extends BaseIvySpecification {
|
|||
cleanIvyCache()
|
||||
val m = module(
|
||||
ModuleID("com.example", "foo", "0.1.0").withConfigurations(Some("compile")),
|
||||
Vector(guavaTest, guavaTestTests), None, UpdateOptions()
|
||||
Vector(guavaTest, guavaTestTests),
|
||||
None,
|
||||
UpdateOptions()
|
||||
)
|
||||
m.withModule(log) {
|
||||
case (ivy, md, _) =>
|
||||
|
|
@ -27,8 +29,12 @@ class MergeDescriptorSpec extends BaseIvySpecification {
|
|||
}
|
||||
}
|
||||
}
|
||||
def guavaTest = ModuleID("com.google.guava", "guava-tests", "18.0").withConfigurations(Option("compile"))
|
||||
def guavaTestTests = ModuleID("com.google.guava", "guava-tests", "18.0").withConfigurations(Option("test")).classifier("tests")
|
||||
def guavaTest =
|
||||
ModuleID("com.google.guava", "guava-tests", "18.0").withConfigurations(Option("compile"))
|
||||
def guavaTestTests =
|
||||
ModuleID("com.google.guava", "guava-tests", "18.0")
|
||||
.withConfigurations(Option("test"))
|
||||
.classifier("tests")
|
||||
def defaultOptions = EvictionWarningOptions.default
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,14 @@ object ResolverTest extends UnitSpec {
|
|||
"Resolver url" should "propagate pattern descriptorOptional and skipConsistencyCheck." in {
|
||||
val pats = Vector("[orgPath]")
|
||||
val patsExpected = Vector("http://foo.com/test/[orgPath]")
|
||||
val patterns = Resolver.url("test", new URL("http://foo.com/test"))(Patterns(pats, pats, isMavenCompatible = false, descriptorOptional = true, skipConsistencyCheck = true)).patterns
|
||||
val patterns = Resolver
|
||||
.url("test", new URL("http://foo.com/test"))(
|
||||
Patterns(pats,
|
||||
pats,
|
||||
isMavenCompatible = false,
|
||||
descriptorOptional = true,
|
||||
skipConsistencyCheck = true))
|
||||
.patterns
|
||||
|
||||
patterns.ivyPatterns shouldBe patsExpected
|
||||
patterns.artifactPatterns shouldBe patsExpected
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@ class ScalaOverrideTest extends UnitSpec {
|
|||
val OtherOrgID = "other.org"
|
||||
|
||||
def check(org0: String, version0: String)(org1: String, name1: String, version1: String) = {
|
||||
val scalaConfigs = Configurations.default.toVector filter { Configurations.underScalaVersion } map { _.name }
|
||||
val scalaConfigs = Configurations.default.toVector filter { Configurations.underScalaVersion } map {
|
||||
_.name
|
||||
}
|
||||
val osm = new OverrideScalaMediator(org0, version0, scalaConfigs)
|
||||
|
||||
val mrid = ModuleRevisionId.newInstance(org1, name1, version1)
|
||||
|
|
@ -24,21 +26,51 @@ class ScalaOverrideTest extends UnitSpec {
|
|||
}
|
||||
|
||||
"""OverrideScalaMediator
|
||||
""" should "Override compiler version" in check(Organization, "2.11.8")(Organization, CompilerID, "2.11.9")
|
||||
it should "Override library version" in check(Organization, "2.11.8")(Organization, LibraryID, "2.11.8")
|
||||
it should "Override reflect version" in check(Organization, "2.11.8")(Organization, ReflectID, "2.11.7")
|
||||
it should "Override actors version" in check(Organization, "2.11.8")(Organization, ActorsID, "2.11.6")
|
||||
it should "Override scalap version" in check(Organization, "2.11.8")(Organization, ScalapID, "2.11.5")
|
||||
""" should "Override compiler version" in check(Organization, "2.11.8")(Organization,
|
||||
CompilerID,
|
||||
"2.11.9")
|
||||
it should "Override library version" in check(Organization, "2.11.8")(Organization,
|
||||
LibraryID,
|
||||
"2.11.8")
|
||||
it should "Override reflect version" in check(Organization, "2.11.8")(Organization,
|
||||
ReflectID,
|
||||
"2.11.7")
|
||||
it should "Override actors version" in check(Organization, "2.11.8")(Organization,
|
||||
ActorsID,
|
||||
"2.11.6")
|
||||
it should "Override scalap version" in check(Organization, "2.11.8")(Organization,
|
||||
ScalapID,
|
||||
"2.11.5")
|
||||
|
||||
it should "Override default compiler organization" in check(OtherOrgID, "2.11.8")(Organization, CompilerID, "2.11.9")
|
||||
it should "Override default library organization" in check(OtherOrgID, "2.11.8")(Organization, LibraryID, "2.11.8")
|
||||
it should "Override default reflect organization" in check(OtherOrgID, "2.11.8")(Organization, ReflectID, "2.11.7")
|
||||
it should "Override default actors organization" in check(OtherOrgID, "2.11.8")(Organization, ActorsID, "2.11.6")
|
||||
it should "Override default scalap organization" in check(OtherOrgID, "2.11.8")(Organization, ScalapID, "2.11.5")
|
||||
it should "Override default compiler organization" in check(OtherOrgID, "2.11.8")(Organization,
|
||||
CompilerID,
|
||||
"2.11.9")
|
||||
it should "Override default library organization" in check(OtherOrgID, "2.11.8")(Organization,
|
||||
LibraryID,
|
||||
"2.11.8")
|
||||
it should "Override default reflect organization" in check(OtherOrgID, "2.11.8")(Organization,
|
||||
ReflectID,
|
||||
"2.11.7")
|
||||
it should "Override default actors organization" in check(OtherOrgID, "2.11.8")(Organization,
|
||||
ActorsID,
|
||||
"2.11.6")
|
||||
it should "Override default scalap organization" in check(OtherOrgID, "2.11.8")(Organization,
|
||||
ScalapID,
|
||||
"2.11.5")
|
||||
|
||||
it should "Override custom compiler organization" in check(Organization, "2.11.8")(OtherOrgID, CompilerID, "2.11.9")
|
||||
it should "Override custom library organization" in check(Organization, "2.11.8")(OtherOrgID, LibraryID, "2.11.8")
|
||||
it should "Override custom reflect organization" in check(Organization, "2.11.8")(OtherOrgID, ReflectID, "2.11.7")
|
||||
it should "Override custom actors organization" in check(Organization, "2.11.8")(OtherOrgID, ActorsID, "2.11.6")
|
||||
it should "Override custom scalap organization" in check(Organization, "2.11.8")(OtherOrgID, ScalapID, "2.11.5")
|
||||
it should "Override custom compiler organization" in check(Organization, "2.11.8")(OtherOrgID,
|
||||
CompilerID,
|
||||
"2.11.9")
|
||||
it should "Override custom library organization" in check(Organization, "2.11.8")(OtherOrgID,
|
||||
LibraryID,
|
||||
"2.11.8")
|
||||
it should "Override custom reflect organization" in check(Organization, "2.11.8")(OtherOrgID,
|
||||
ReflectID,
|
||||
"2.11.7")
|
||||
it should "Override custom actors organization" in check(Organization, "2.11.8")(OtherOrgID,
|
||||
ActorsID,
|
||||
"2.11.6")
|
||||
it should "Override custom scalap organization" in check(Organization, "2.11.8")(OtherOrgID,
|
||||
ScalapID,
|
||||
"2.11.5")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,45 +38,72 @@ class VersionNumberSpec extends UnitSpec {
|
|||
it should "be SecSeg compat with 0.12.1" in beSecSegCompatWith("0.12.0", "0.12.1")
|
||||
it should "be SecSeg compat with 0.12.1-M1" in beSecSegCompatWith("0.12.0", "0.12.1-M1")
|
||||
|
||||
"0.1.0-SNAPSHOT" should "be parsed" in beParsedAs("0.1.0-SNAPSHOT", Seq(0, 1, 0), Seq("SNAPSHOT"), Seq())
|
||||
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-SNAPSHOT", Seq("0.1.0-SNAPSHOT", "0.1.0", "0.1"))
|
||||
it should "be SemVer compat with 0.1.0-SNAPSHOT" in beSemVerCompatWith("0.1.0-SNAPSHOT", "0.1.0-SNAPSHOT")
|
||||
"0.1.0-SNAPSHOT" should "be parsed" in beParsedAs("0.1.0-SNAPSHOT",
|
||||
Seq(0, 1, 0),
|
||||
Seq("SNAPSHOT"),
|
||||
Seq())
|
||||
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-SNAPSHOT",
|
||||
Seq("0.1.0-SNAPSHOT", "0.1.0", "0.1"))
|
||||
it should "be SemVer compat with 0.1.0-SNAPSHOT" in beSemVerCompatWith("0.1.0-SNAPSHOT",
|
||||
"0.1.0-SNAPSHOT")
|
||||
it should "not be SemVer compat with 0.1.0" in notBeSemVerCompatWith("0.1.0-SNAPSHOT", "0.1.0")
|
||||
it should "be SemVer compat with 0.1.0-SNAPSHOT+001" in beSemVerCompatWith("0.1.0-SNAPSHOT", "0.1.0-SNAPSHOT+001")
|
||||
it should "be SecSeg compat with 0.1.0-SNAPSHOT" in beSecSegCompatWith("0.1.0-SNAPSHOT", "0.1.0-SNAPSHOT")
|
||||
it should "be SemVer compat with 0.1.0-SNAPSHOT+001" in beSemVerCompatWith("0.1.0-SNAPSHOT",
|
||||
"0.1.0-SNAPSHOT+001")
|
||||
it should "be SecSeg compat with 0.1.0-SNAPSHOT" in beSecSegCompatWith("0.1.0-SNAPSHOT",
|
||||
"0.1.0-SNAPSHOT")
|
||||
it should "be not SecSeg compat with 0.1.0" in notBeSecSegCompatWith("0.1.0-SNAPSHOT", "0.1.0")
|
||||
it should "be SecSeg compat with 0.1.0-SNAPSHOT+001" in beSecSegCompatWith("0.1.0-SNAPSHOT", "0.1.0-SNAPSHOT+001")
|
||||
it should "be SecSeg compat with 0.1.0-SNAPSHOT+001" in beSecSegCompatWith("0.1.0-SNAPSHOT",
|
||||
"0.1.0-SNAPSHOT+001")
|
||||
|
||||
"0.1.0-M1" should "be parsed" in beParsedAs("0.1.0-M1", Seq(0, 1, 0), Seq("M1"), Seq())
|
||||
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-M1", Seq("0.1.0-M1", "0.1.0", "0.1"))
|
||||
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-M1",
|
||||
Seq("0.1.0-M1", "0.1.0", "0.1"))
|
||||
|
||||
"0.1.0-RC1" should "be parsed" in beParsedAs("0.1.0-RC1", Seq(0, 1, 0), Seq("RC1"), Seq())
|
||||
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-RC1", Seq("0.1.0-RC1", "0.1.0", "0.1"))
|
||||
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-RC1",
|
||||
Seq("0.1.0-RC1", "0.1.0", "0.1"))
|
||||
|
||||
"0.1.0-MSERVER-1" should "be parsed" in beParsedAs("0.1.0-MSERVER-1", Seq(0, 1, 0), Seq("MSERVER", "1"), Seq())
|
||||
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-MSERVER-1", Seq("0.1.0-MSERVER-1", "0.1.0", "0.1"))
|
||||
"0.1.0-MSERVER-1" should "be parsed" in beParsedAs("0.1.0-MSERVER-1",
|
||||
Seq(0, 1, 0),
|
||||
Seq("MSERVER", "1"),
|
||||
Seq())
|
||||
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-MSERVER-1",
|
||||
Seq("0.1.0-MSERVER-1", "0.1.0", "0.1"))
|
||||
|
||||
"2.10.4-20140115-000117-b3a-sources" should "be parsed" in {
|
||||
beParsedAs("2.10.4-20140115-000117-b3a-sources", Seq(2, 10, 4), Seq("20140115", "000117", "b3a", "sources"), Seq())
|
||||
beParsedAs("2.10.4-20140115-000117-b3a-sources",
|
||||
Seq(2, 10, 4),
|
||||
Seq("20140115", "000117", "b3a", "sources"),
|
||||
Seq())
|
||||
}
|
||||
it should "cascade" in generateCorrectCascadingNumbers("2.10.4-20140115-000117-b3a-sources", Seq("2.10.4-20140115-000117-b3a-sources", "2.10.4", "2.10"))
|
||||
it should "be SemVer compat with 2.0.0" in beSemVerCompatWith("2.10.4-20140115-000117-b3a-sources", "2.0.0")
|
||||
it should "be not SecSeg compat with 2.0.0" in notBeSecSegCompatWith("2.10.4-20140115-000117-b3a-sources", "2.0.0")
|
||||
it should "cascade" in generateCorrectCascadingNumbers(
|
||||
"2.10.4-20140115-000117-b3a-sources",
|
||||
Seq("2.10.4-20140115-000117-b3a-sources", "2.10.4", "2.10"))
|
||||
it should "be SemVer compat with 2.0.0" in beSemVerCompatWith(
|
||||
"2.10.4-20140115-000117-b3a-sources",
|
||||
"2.0.0")
|
||||
it should "be not SecSeg compat with 2.0.0" in notBeSecSegCompatWith(
|
||||
"2.10.4-20140115-000117-b3a-sources",
|
||||
"2.0.0")
|
||||
|
||||
"20140115000117-b3a-sources" should "be parsed" in {
|
||||
beParsedAs("20140115000117-b3a-sources", Seq(20140115000117L), Seq("b3a", "sources"), Seq())
|
||||
}
|
||||
it should "cascade" in generateCorrectCascadingNumbers("20140115000117-b3a-sources", Seq("20140115000117-b3a-sources"))
|
||||
it should "cascade" in generateCorrectCascadingNumbers("20140115000117-b3a-sources",
|
||||
Seq("20140115000117-b3a-sources"))
|
||||
|
||||
"1.0.0-alpha+001+002" should "be parsed" in {
|
||||
beParsedAs("1.0.0-alpha+001+002", Seq(1, 0, 0), Seq("alpha"), Seq("+001", "+002"))
|
||||
}
|
||||
it should "cascade" in generateCorrectCascadingNumbers("1.0.0-alpha+001+002", Seq("1.0.0-alpha+001+002", "1.0.0", "1.0"))
|
||||
it should "cascade" in generateCorrectCascadingNumbers(
|
||||
"1.0.0-alpha+001+002",
|
||||
Seq("1.0.0-alpha+001+002", "1.0.0", "1.0"))
|
||||
|
||||
"non.space.!?string" should "be parsed" in {
|
||||
beParsedAs("non.space.!?string", Seq(), Seq(), Seq("non.space.!?string"))
|
||||
}
|
||||
it should "cascade" in generateCorrectCascadingNumbers("non.space.!?string", Seq("non.space.!?string"))
|
||||
it should "cascade" in generateCorrectCascadingNumbers("non.space.!?string",
|
||||
Seq("non.space.!?string"))
|
||||
|
||||
"space !?string" should "be parsed as an error" in beParsedAsError("space !?string")
|
||||
"blank string" should "be parsed as an error" in beParsedAsError("")
|
||||
|
|
@ -89,8 +116,11 @@ class VersionNumberSpec extends UnitSpec {
|
|||
case VersionNumber(ns1, ts1, es1) =>
|
||||
sys.error(s"$ns1, $ts1, $es1")
|
||||
}
|
||||
def breakDownTo(s: String, major: Option[Long], minor: Option[Long] = None,
|
||||
patch: Option[Long] = None, buildNumber: Option[Long] = None) =
|
||||
def breakDownTo(s: String,
|
||||
major: Option[Long],
|
||||
minor: Option[Long] = None,
|
||||
patch: Option[Long] = None,
|
||||
buildNumber: Option[Long] = None) =
|
||||
s match {
|
||||
case VersionNumber(ns, ts, es) =>
|
||||
val v = VersionNumber(ns, ts, es)
|
||||
|
|
|
|||
|
|
@ -9,10 +9,13 @@ import sbt.librarymanagement.{ ModuleID, RawRepository, Resolver, UpdateReport }
|
|||
class FakeResolverSpecification extends BaseIvySpecification {
|
||||
import FakeResolver._
|
||||
|
||||
val myModule = ModuleID("org.example", "my-module", "0.0.1-SNAPSHOT").withConfigurations(Some("compile"))
|
||||
val myModule =
|
||||
ModuleID("org.example", "my-module", "0.0.1-SNAPSHOT").withConfigurations(Some("compile"))
|
||||
val example = ModuleID("com.example", "example", "1.0.0").withConfigurations(Some("compile"))
|
||||
val anotherExample = ModuleID("com.example", "another-example", "1.0.0").withConfigurations(Some("compile"))
|
||||
val nonExisting = ModuleID("com.example", "does-not-exist", "1.2.3").withConfigurations(Some("compile"))
|
||||
val anotherExample =
|
||||
ModuleID("com.example", "another-example", "1.0.0").withConfigurations(Some("compile"))
|
||||
val nonExisting =
|
||||
ModuleID("com.example", "does-not-exist", "1.2.3").withConfigurations(Some("compile"))
|
||||
|
||||
"The FakeResolver" should "find modules with only one artifact" in {
|
||||
val m = getModule(myModule)
|
||||
|
|
@ -53,12 +56,10 @@ class FakeResolverSpecification extends BaseIvySpecification {
|
|||
("org.example", "my-module", "0.0.1-SNAPSHOT") -> List(
|
||||
FakeArtifact("artifact1", "jar", "jar", artifact1)
|
||||
),
|
||||
|
||||
("com.example", "example", "1.0.0") -> List(
|
||||
FakeArtifact("artifact1", "jar", "jar", artifact1),
|
||||
FakeArtifact("artifact2", "txt", "txt", artifact2)
|
||||
),
|
||||
|
||||
("com.example", "another-example", "1.0.0") -> List(
|
||||
FakeArtifact("artifact1", "jar", "jar", artifact1),
|
||||
FakeArtifact("non-existing", "txt", "txt", new File("non-existing-file"))
|
||||
|
|
@ -67,7 +68,8 @@ class FakeResolverSpecification extends BaseIvySpecification {
|
|||
|
||||
private def fakeResolver = new FakeResolver("FakeResolver", new File("tmp"), modules)
|
||||
override def resolvers: Vector[Resolver] = Vector(new RawRepository(fakeResolver))
|
||||
private def getModule(myModule: ModuleID): IvySbt#Module = module(defaultModuleId, Vector(myModule), None)
|
||||
private def getModule(myModule: ModuleID): IvySbt#Module =
|
||||
module(defaultModuleId, Vector(myModule), None)
|
||||
private def getAllFiles(report: UpdateReport) =
|
||||
for {
|
||||
conf <- report.configurations
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ class IvyRepoSpec extends BaseIvySpecification with DependencyBuilders {
|
|||
|
||||
module(
|
||||
ourModuleID,
|
||||
Vector(dep), None //, UpdateOptions().withCachedResolution(true)
|
||||
Vector(dep),
|
||||
None //, UpdateOptions().withCachedResolution(true)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -59,12 +60,26 @@ class IvyRepoSpec extends BaseIvySpecification with DependencyBuilders {
|
|||
val clMod = {
|
||||
val externalModules = Vector(dep)
|
||||
// Note: need to extract ourModuleID so we can plug it in here, can't fish it back out of the IvySbt#Module (`m`)
|
||||
GetClassifiersModule(ourModuleID, externalModules, Vector(Configurations.Compile), attemptedClassifiers)
|
||||
GetClassifiersModule(ourModuleID,
|
||||
externalModules,
|
||||
Vector(Configurations.Compile),
|
||||
attemptedClassifiers)
|
||||
}
|
||||
|
||||
val gcm = GetClassifiersConfiguration(clMod, Map.empty, c.withArtifactFilter(c.artifactFilter.invert), ivyScala, srcTypes, docTypes)
|
||||
val gcm = GetClassifiersConfiguration(clMod,
|
||||
Map.empty,
|
||||
c.withArtifactFilter(c.artifactFilter.invert),
|
||||
ivyScala,
|
||||
srcTypes,
|
||||
docTypes)
|
||||
|
||||
val report2 = IvyActions.updateClassifiers(m.owner, gcm, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, Vector(), log)
|
||||
val report2 = IvyActions.updateClassifiers(m.owner,
|
||||
gcm,
|
||||
UnresolvedWarningConfiguration(),
|
||||
LogicalClock.unknown,
|
||||
None,
|
||||
Vector(),
|
||||
log)
|
||||
|
||||
import Inside._
|
||||
inside(report2.configuration("compile").map(_.modules)) {
|
||||
|
|
|
|||
|
|
@ -54,11 +54,16 @@ class RepositoriesParserSpecification extends UnitSpec {
|
|||
| ivyRepo: https://repo1.maven.org, [orgPath], bootOnly""".stripMargin
|
||||
val repos = RepositoriesParser(file)
|
||||
val expected =
|
||||
IvyRepository("ivyRepo", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]",
|
||||
IvyRepository(
|
||||
"ivyRepo",
|
||||
new URL("https://repo1.maven.org"),
|
||||
"[orgPath]",
|
||||
"[orgPath]",
|
||||
mavenCompatible = false,
|
||||
skipConsistencyCheck = false,
|
||||
descriptorOptional = false,
|
||||
bootOnly = true)
|
||||
bootOnly = true
|
||||
)
|
||||
repos.size shouldBe 1
|
||||
repos(0) shouldBe expected
|
||||
}
|
||||
|
|
@ -68,11 +73,16 @@ class RepositoriesParserSpecification extends UnitSpec {
|
|||
| ivyRepo: https://repo1.maven.org, [orgPath], mavenCompatible""".stripMargin
|
||||
val repos = RepositoriesParser(file)
|
||||
val expected =
|
||||
IvyRepository("ivyRepo", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]",
|
||||
IvyRepository(
|
||||
"ivyRepo",
|
||||
new URL("https://repo1.maven.org"),
|
||||
"[orgPath]",
|
||||
"[orgPath]",
|
||||
mavenCompatible = true,
|
||||
skipConsistencyCheck = false,
|
||||
descriptorOptional = false,
|
||||
bootOnly = false)
|
||||
bootOnly = false
|
||||
)
|
||||
repos.size shouldBe 1
|
||||
repos(0) shouldBe expected
|
||||
}
|
||||
|
|
@ -82,11 +92,16 @@ class RepositoriesParserSpecification extends UnitSpec {
|
|||
| ivyRepo: https://repo1.maven.org, [orgPath], skipConsistencyCheck""".stripMargin
|
||||
val repos = RepositoriesParser(file)
|
||||
val expected =
|
||||
IvyRepository("ivyRepo", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]",
|
||||
IvyRepository(
|
||||
"ivyRepo",
|
||||
new URL("https://repo1.maven.org"),
|
||||
"[orgPath]",
|
||||
"[orgPath]",
|
||||
mavenCompatible = false,
|
||||
skipConsistencyCheck = true,
|
||||
descriptorOptional = false,
|
||||
bootOnly = false)
|
||||
bootOnly = false
|
||||
)
|
||||
repos.size shouldBe 1
|
||||
repos(0) shouldBe expected
|
||||
}
|
||||
|
|
@ -96,41 +111,58 @@ class RepositoriesParserSpecification extends UnitSpec {
|
|||
| ivyRepo: https://repo1.maven.org, [orgPath], descriptorOptional""".stripMargin
|
||||
val repos = RepositoriesParser(file)
|
||||
val expected =
|
||||
IvyRepository("ivyRepo", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]",
|
||||
IvyRepository(
|
||||
"ivyRepo",
|
||||
new URL("https://repo1.maven.org"),
|
||||
"[orgPath]",
|
||||
"[orgPath]",
|
||||
mavenCompatible = false,
|
||||
skipConsistencyCheck = false,
|
||||
descriptorOptional = true,
|
||||
bootOnly = false)
|
||||
bootOnly = false
|
||||
)
|
||||
repos.size shouldBe 1
|
||||
repos(0) shouldBe expected
|
||||
}
|
||||
|
||||
it should "parse complex ivy repository definition" in {
|
||||
val file = """[repositories]
|
||||
val file =
|
||||
"""[repositories]
|
||||
| ivyRepo: https://repo1.maven.org, [orgPath], [artPath], descriptorOptional, skipConsistencyCheck""".stripMargin
|
||||
val repos = RepositoriesParser(file)
|
||||
val expected =
|
||||
IvyRepository("ivyRepo", new URL("https://repo1.maven.org"), "[orgPath]", "[artPath]",
|
||||
IvyRepository(
|
||||
"ivyRepo",
|
||||
new URL("https://repo1.maven.org"),
|
||||
"[orgPath]",
|
||||
"[artPath]",
|
||||
mavenCompatible = false,
|
||||
skipConsistencyCheck = true,
|
||||
descriptorOptional = true,
|
||||
bootOnly = false)
|
||||
bootOnly = false
|
||||
)
|
||||
repos.size shouldBe 1
|
||||
repos(0) shouldBe expected
|
||||
}
|
||||
|
||||
it should "parse multiple repositories defined together" in {
|
||||
val file = """[repositories]
|
||||
val file =
|
||||
"""[repositories]
|
||||
| local
|
||||
| ivyRepo: https://repo1.maven.org, [orgPath], [artPath], descriptorOptional, skipConsistencyCheck
|
||||
| mavenRepo: https://repo1.maven.org""".stripMargin
|
||||
val expected0 = PredefinedRepository(xsbti.Predefined.Local)
|
||||
val expected1 =
|
||||
IvyRepository("ivyRepo", new URL("https://repo1.maven.org"), "[orgPath]", "[artPath]",
|
||||
IvyRepository(
|
||||
"ivyRepo",
|
||||
new URL("https://repo1.maven.org"),
|
||||
"[orgPath]",
|
||||
"[artPath]",
|
||||
mavenCompatible = false,
|
||||
skipConsistencyCheck = true,
|
||||
descriptorOptional = true,
|
||||
bootOnly = false)
|
||||
bootOnly = false
|
||||
)
|
||||
val expected2 = MavenRepository("mavenRepo", new URL("https://repo1.maven.org"))
|
||||
|
||||
val repos = RepositoriesParser(file)
|
||||
|
|
|
|||
|
|
@ -6,10 +6,9 @@ import sbt.util._
|
|||
import sbt.internal.util._
|
||||
|
||||
object TestLogger {
|
||||
def apply[T](f: Logger => T): T =
|
||||
{
|
||||
val log = new BufferedLogger(ConsoleLogger())
|
||||
log.setLevel(Level.Debug)
|
||||
log.bufferQuietly(f(log))
|
||||
}
|
||||
def apply[T](f: Logger => T): T = {
|
||||
val log = new BufferedLogger(ConsoleLogger())
|
||||
log.setLevel(Level.Debug)
|
||||
log.bufferQuietly(f(log))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ object AutomateScalafmtPlugin extends AutoPlugin {
|
|||
configurations.flatMap { c =>
|
||||
inConfig(c)(
|
||||
Seq(
|
||||
compileInputs.in(compile) := {
|
||||
compileInputs.in(compile) := {
|
||||
scalafmtInc.value
|
||||
compileInputs.in(compile).value
|
||||
},
|
||||
sourceDirectories.in(scalafmtInc) := Seq(scalaSource.value),
|
||||
scalafmtInc := {
|
||||
val cache = streams.value.cacheDirectory / "scalafmt"
|
||||
val cache = streams.value.cacheDirectory / "scalafmt"
|
||||
val include = includeFilter.in(scalafmtInc).value
|
||||
val exclude = excludeFilter.in(scalafmtInc).value
|
||||
val sources =
|
||||
|
|
|
|||
|
|
@ -19,27 +19,39 @@ object DatatypeConfig {
|
|||
|
||||
/** Codecs that were manually written. */
|
||||
val myCodecs: PartialFunction[String, Type => List[String]] = {
|
||||
case "scala.xml.NodeSeq" => { _ => "sbt.internal.librarymanagement.formats.NodeSeqFormat" :: Nil }
|
||||
case "scala.xml.NodeSeq" => { _ =>
|
||||
"sbt.internal.librarymanagement.formats.NodeSeqFormat" :: Nil
|
||||
}
|
||||
|
||||
case "org.apache.ivy.plugins.resolver.DependencyResolver" =>
|
||||
{ _ => "sbt.internal.librarymanagement.formats.DependencyResolverFormat" :: Nil }
|
||||
case "org.apache.ivy.plugins.resolver.DependencyResolver" => { _ =>
|
||||
"sbt.internal.librarymanagement.formats.DependencyResolverFormat" :: Nil
|
||||
}
|
||||
|
||||
case "xsbti.GlobalLock" => { _ => "sbt.internal.librarymanagement.formats.GlobalLockFormat" :: Nil }
|
||||
case "xsbti.Logger" => { _ => "sbt.internal.librarymanagement.formats.LoggerFormat" :: Nil }
|
||||
case "xsbti.GlobalLock" => { _ =>
|
||||
"sbt.internal.librarymanagement.formats.GlobalLockFormat" :: Nil
|
||||
}
|
||||
case "xsbti.Logger" => { _ =>
|
||||
"sbt.internal.librarymanagement.formats.LoggerFormat" :: Nil
|
||||
}
|
||||
|
||||
case "sbt.librarymanagement.UpdateOptions" =>
|
||||
{ _ => "sbt.internal.librarymanagement.formats.UpdateOptionsFormat" :: Nil }
|
||||
case "sbt.librarymanagement.UpdateOptions" => { _ =>
|
||||
"sbt.internal.librarymanagement.formats.UpdateOptionsFormat" :: Nil
|
||||
}
|
||||
|
||||
// TODO: These are handled by BasicJsonProtocol, and sbt-datatype should handle them by default, imo
|
||||
case "Option" | "Set" | "scala.Vector" => { tpe => getFormats(oneArg(tpe)) }
|
||||
case "Map" | "Tuple2" | "scala.Tuple2" => { tpe => twoArgs(tpe).flatMap(getFormats) }
|
||||
case "Int" | "Long" => { _ => Nil }
|
||||
case "Option" | "Set" | "scala.Vector" => { tpe =>
|
||||
getFormats(oneArg(tpe))
|
||||
}
|
||||
case "Map" | "Tuple2" | "scala.Tuple2" => { tpe =>
|
||||
twoArgs(tpe).flatMap(getFormats)
|
||||
}
|
||||
case "Int" | "Long" => { _ =>
|
||||
Nil
|
||||
}
|
||||
}
|
||||
|
||||
/** Types for which we don't include the format -- they're just aliases to InclExclRule */
|
||||
val excluded = Set(
|
||||
"sbt.librarymanagement.InclusionRule",
|
||||
"sbt.librarymanagement.ExclusionRule")
|
||||
val excluded = Set("sbt.librarymanagement.InclusionRule", "sbt.librarymanagement.ExclusionRule")
|
||||
|
||||
/** Returns the list of formats required to encode the given `TpeRef`. */
|
||||
val getFormats: Type => List[String] =
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ object Dependencies {
|
|||
private val sbtIO = "org.scala-sbt" %% "io" % ioVersion
|
||||
|
||||
private val utilCollection = "org.scala-sbt" %% "util-collection" % utilVersion
|
||||
private val utilLogging = "org.scala-sbt" %% "util-logging" % utilVersion
|
||||
private val utilTesting = "org.scala-sbt" %% "util-testing" % utilVersion
|
||||
private val utilLogging = "org.scala-sbt" %% "util-logging" % utilVersion
|
||||
private val utilTesting = "org.scala-sbt" %% "util-testing" % utilVersion
|
||||
private val utilCompletion = "org.scala-sbt" %% "util-completion" % utilVersion
|
||||
private val utilCache = "org.scala-sbt" %% "util-cache" % utilVersion
|
||||
private val utilCache = "org.scala-sbt" %% "util-cache" % utilVersion
|
||||
|
||||
def getSbtModulePath(key: String, name: String) = {
|
||||
val localProps = new java.util.Properties()
|
||||
|
|
@ -24,21 +24,31 @@ object Dependencies {
|
|||
path
|
||||
}
|
||||
|
||||
lazy val sbtIoPath = getSbtModulePath("sbtio.path", "sbt/io")
|
||||
lazy val sbtIoPath = getSbtModulePath("sbtio.path", "sbt/io")
|
||||
lazy val sbtUtilPath = getSbtModulePath("sbtutil.path", "sbt/util")
|
||||
|
||||
def addSbtModule(p: Project, path: Option[String], projectName: String, m: ModuleID, c: Option[Configuration] = None) =
|
||||
def addSbtModule(p: Project,
|
||||
path: Option[String],
|
||||
projectName: String,
|
||||
m: ModuleID,
|
||||
c: Option[Configuration] = None) =
|
||||
path match {
|
||||
case Some(f) => p dependsOn c.fold[ClasspathDependency](ProjectRef(file(f), projectName))(ProjectRef(file(f), projectName) % _)
|
||||
case None => p settings (libraryDependencies += c.fold(m)(m % _))
|
||||
case Some(f) =>
|
||||
p dependsOn c.fold[ClasspathDependency](ProjectRef(file(f), projectName))(
|
||||
ProjectRef(file(f), projectName) % _)
|
||||
case None => p settings (libraryDependencies += c.fold(m)(m % _))
|
||||
}
|
||||
|
||||
def addSbtIO(p: Project): Project = addSbtModule(p, sbtIoPath, "io", sbtIO)
|
||||
def addSbtUtilCollection(p: Project): Project = addSbtModule(p, sbtUtilPath, "utilCollection", utilCollection)
|
||||
def addSbtUtilLogging(p: Project): Project = addSbtModule(p, sbtUtilPath, "utilLogging", utilLogging)
|
||||
def addSbtUtilTesting(p: Project): Project = addSbtModule(p, sbtUtilPath, "utilTesting", utilTesting, Some(Test))
|
||||
def addSbtUtilCompletion(p: Project): Project = addSbtModule(p, sbtUtilPath, "utilComplete", utilCompletion)
|
||||
def addSbtUtilCache(p: Project): Project = addSbtModule(p, sbtUtilPath, "utilCache", utilCache)
|
||||
def addSbtUtilCollection(p: Project): Project =
|
||||
addSbtModule(p, sbtUtilPath, "utilCollection", utilCollection)
|
||||
def addSbtUtilLogging(p: Project): Project =
|
||||
addSbtModule(p, sbtUtilPath, "utilLogging", utilLogging)
|
||||
def addSbtUtilTesting(p: Project): Project =
|
||||
addSbtModule(p, sbtUtilPath, "utilTesting", utilTesting, Some(Test))
|
||||
def addSbtUtilCompletion(p: Project): Project =
|
||||
addSbtModule(p, sbtUtilPath, "utilComplete", utilCompletion)
|
||||
def addSbtUtilCache(p: Project): Project = addSbtModule(p, sbtUtilPath, "utilCache", utilCache)
|
||||
|
||||
val launcherInterface = "org.scala-sbt" % "launcher-interface" % "1.0.0"
|
||||
val ivy = "org.scala-sbt.ivy" % "ivy" % "2.3.0-sbt-48dd0744422128446aee9ac31aa356ee203cc9f4"
|
||||
|
|
@ -52,7 +62,7 @@ object Dependencies {
|
|||
Def.setting {
|
||||
scalaVersion.value match {
|
||||
case sv if (sv startsWith "2.9.") || (sv startsWith "2.10.") => Nil
|
||||
case _ => ("org.scala-lang.modules" %% name % moduleVersion) :: Nil
|
||||
case _ => ("org.scala-lang.modules" %% name % moduleVersion) :: Nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,29 +4,31 @@ import sbt.IO
|
|||
|
||||
import java.io.File
|
||||
|
||||
|
||||
object Util {
|
||||
|
||||
def versionLine(version: String): String = "version=" + version
|
||||
def containsVersion(propFile: File, version: String): Boolean = IO.read(propFile).contains(versionLine(version))
|
||||
def lastCompilationTime(analysis: sbt.inc.Analysis): Long =
|
||||
{
|
||||
val lastCompilation = analysis.compilations.allCompilations.lastOption
|
||||
lastCompilation.map(_.startTime) getOrElse 0L
|
||||
}
|
||||
def containsVersion(propFile: File, version: String): Boolean =
|
||||
IO.read(propFile).contains(versionLine(version))
|
||||
def lastCompilationTime(analysis: sbt.inc.Analysis): Long = {
|
||||
val lastCompilation = analysis.compilations.allCompilations.lastOption
|
||||
lastCompilation.map(_.startTime) getOrElse 0L
|
||||
}
|
||||
|
||||
def generateVersionFile(version: String, dir: File, s: TaskStreams, analysis: sbt.inc.Analysis): Seq[File] =
|
||||
{
|
||||
import java.util.{ Date, TimeZone }
|
||||
val formatter = new java.text.SimpleDateFormat("yyyyMMdd'T'HHmmss")
|
||||
formatter.setTimeZone(TimeZone.getTimeZone("GMT"))
|
||||
val timestamp = formatter.format(new Date)
|
||||
val content = versionLine(version) + "\ntimestamp=" + timestamp
|
||||
val f = dir / "xsbt.version.properties"
|
||||
if (!f.exists || f.lastModified < lastCompilationTime(analysis) || !containsVersion(f, version)) {
|
||||
s.log.info("Writing version information to " + f + " :\n" + content)
|
||||
IO.write(f, content)
|
||||
}
|
||||
f :: Nil
|
||||
def generateVersionFile(version: String,
|
||||
dir: File,
|
||||
s: TaskStreams,
|
||||
analysis: sbt.inc.Analysis): Seq[File] = {
|
||||
import java.util.{ Date, TimeZone }
|
||||
val formatter = new java.text.SimpleDateFormat("yyyyMMdd'T'HHmmss")
|
||||
formatter.setTimeZone(TimeZone.getTimeZone("GMT"))
|
||||
val timestamp = formatter.format(new Date)
|
||||
val content = versionLine(version) + "\ntimestamp=" + timestamp
|
||||
val f = dir / "xsbt.version.properties"
|
||||
if (!f.exists || f.lastModified < lastCompilationTime(analysis) || !containsVersion(f,
|
||||
version)) {
|
||||
s.log.info("Writing version information to " + f + " :\n" + content)
|
||||
IO.write(f, content)
|
||||
}
|
||||
f :: Nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
addSbtPlugin("org.scala-sbt" % "sbt-houserules" % "0.3.2")
|
||||
addSbtPlugin("com.eed3si9n" % "sbt-doge" % "0.1.3")
|
||||
addSbtPlugin("com.eed3si9n" % "sbt-doge" % "0.1.3")
|
||||
addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.3.0-M4")
|
||||
addSbtPlugin("me.lessis" % "bintray-sbt" % "0.3.0")
|
||||
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "0.6.8")
|
||||
addSbtPlugin("me.lessis" % "bintray-sbt" % "0.3.0")
|
||||
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "0.6.8")
|
||||
|
||||
scalacOptions += "-language:postfixOps"
|
||||
|
|
|
|||
Loading…
Reference in New Issue