Apply formatting

This commit is contained in:
jvican 2017-04-26 22:55:38 +02:00
parent 712c83f859
commit d42ea869d0
No known key found for this signature in database
GPG Key ID: 42DAFA0F112E8050
71 changed files with 4878 additions and 2822 deletions

View File

@ -28,17 +28,19 @@ def commonSettings: Seq[Setting[_]] = Seq(
} }
) )
lazy val lmRoot = (project in file(".")). lazy val lmRoot = (project in file("."))
aggregate(lm). .aggregate(lm)
disablePlugins(com.typesafe.sbt.SbtScalariform). .disablePlugins(com.typesafe.sbt.SbtScalariform)
settings( .settings(
inThisBuild(Seq( inThisBuild(
homepage := Some(url("https://github.com/sbt/librarymanagement")), Seq(
description := "Library management module for sbt", homepage := Some(url("https://github.com/sbt/librarymanagement")),
scmInfo := Some(ScmInfo(url("https://github.com/sbt/librarymanagement"), "git@github.com:sbt/librarymanagement.git")), description := "Library management module for sbt",
bintrayPackage := "librarymanagement", scmInfo := Some(ScmInfo(url("https://github.com/sbt/librarymanagement"),
git.baseVersion := baseVersion "git@github.com:sbt/librarymanagement.git")),
)), bintrayPackage := "librarymanagement",
git.baseVersion := baseVersion
)),
commonSettings, commonSettings,
name := "LM Root", name := "LM Root",
publish := {}, publish := {},
@ -48,15 +50,24 @@ lazy val lmRoot = (project in file(".")).
customCommands customCommands
) )
lazy val lm = (project in file("librarymanagement")). lazy val lm = (project in file("librarymanagement"))
disablePlugins(com.typesafe.sbt.SbtScalariform). .disablePlugins(com.typesafe.sbt.SbtScalariform)
settings( .settings(
commonSettings, commonSettings,
name := "librarymanagement", name := "librarymanagement",
libraryDependencies ++= Seq( libraryDependencies ++= Seq(ivy,
ivy, jsch, scalaReflect.value, launcherInterface, sjsonnewScalaJson % Optional), jsch,
scalaReflect.value,
launcherInterface,
sjsonnewScalaJson % Optional),
libraryDependencies ++= scalaXml.value, 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(), mimaBinaryIssueFilters ++= Seq(),
contrabandFormatsForType in generateContrabands in Compile := DatatypeConfig.getFormats, contrabandFormatsForType in generateContrabands in Compile := DatatypeConfig.getFormats,
// WORKAROUND sbt/sbt#2205 include managed sources in packageSrc // WORKAROUND sbt/sbt#2205 include managed sources in packageSrc
@ -66,16 +77,21 @@ lazy val lm = (project in file("librarymanagement")).
val base = baseDirectory.value val base = baseDirectory.value
(((srcs --- sdirs --- base) pair (relativeTo(sdirs) | relativeTo(base) | flat)) toSeq) (((srcs --- sdirs --- base) pair (relativeTo(sdirs) | relativeTo(base) | flat)) toSeq)
} }
). )
configure(addSbtIO, addSbtUtilLogging, addSbtUtilTesting, addSbtUtilCollection, addSbtUtilCompletion, addSbtUtilCache). .configure(addSbtIO,
enablePlugins(ContrabandPlugin, JsonCodecPlugin) addSbtUtilLogging,
addSbtUtilTesting,
addSbtUtilCollection,
addSbtUtilCompletion,
addSbtUtilCache)
.enablePlugins(ContrabandPlugin, JsonCodecPlugin)
def customCommands: Seq[Setting[_]] = Seq( def customCommands: Seq[Setting[_]] = Seq(
commands += Command.command("release") { state => commands += Command.command("release") { state =>
// "clean" :: // "clean" ::
"so compile" :: "so compile" ::
"so publishSigned" :: "so publishSigned" ::
"reload" :: "reload" ::
state state
} }
) )

View File

@ -37,68 +37,83 @@ object ReplaceMavenConfigurationMappings {
// NOTE - This code is copied from org.apache.ivy.plugins.parser.m2.PomModuleDescriptorBuilder // NOTE - This code is copied from org.apache.ivy.plugins.parser.m2.PomModuleDescriptorBuilder
// except with altered default configurations... // except with altered default configurations...
REPLACEMENT_MAPPINGS.put("compile", new PomModuleDescriptorBuilder.ConfMapper { REPLACEMENT_MAPPINGS.put(
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = { "compile",
if (isOptional) { new PomModuleDescriptorBuilder.ConfMapper {
dd.addDependencyConfiguration("optional", "compile(*)") 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. if (isOptional) {
dd.addDependencyConfiguration("optional", "master(compile)") dd.addDependencyConfiguration("optional", "compile(*)")
} else { // FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
dd.addDependencyConfiguration("compile", "compile(*)") dd.addDependencyConfiguration("optional", "master(compile)")
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there. } else {
dd.addDependencyConfiguration("compile", "master(compile)") dd.addDependencyConfiguration("compile", "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("compile", "master(compile)")
dd.addDependencyConfiguration("runtime", "runtime(*)")
}
} }
} }
}) )
REPLACEMENT_MAPPINGS.put("provided", new PomModuleDescriptorBuilder.ConfMapper { REPLACEMENT_MAPPINGS.put(
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = { "provided",
if (isOptional) { new PomModuleDescriptorBuilder.ConfMapper {
dd.addDependencyConfiguration("optional", "compile(*)") def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
dd.addDependencyConfiguration("optional", "provided(*)") if (isOptional) {
dd.addDependencyConfiguration("optional", "runtime(*)") 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", "provided(*)")
dd.addDependencyConfiguration("optional", "master(compile)") dd.addDependencyConfiguration("optional", "runtime(*)")
} else { // FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
dd.addDependencyConfiguration("provided", "compile(*)") dd.addDependencyConfiguration("optional", "master(compile)")
dd.addDependencyConfiguration("provided", "provided(*)") } else {
dd.addDependencyConfiguration("provided", "runtime(*)") dd.addDependencyConfiguration("provided", "compile(*)")
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there. dd.addDependencyConfiguration("provided", "provided(*)")
dd.addDependencyConfiguration("provided", "master(compile)") 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 { REPLACEMENT_MAPPINGS.put(
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = { "runtime",
if (isOptional) { new PomModuleDescriptorBuilder.ConfMapper {
dd.addDependencyConfiguration("optional", "compile(*)") def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
dd.addDependencyConfiguration("optional", "provided(*)") if (isOptional) {
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there. dd.addDependencyConfiguration("optional", "compile(*)")
dd.addDependencyConfiguration("optional", "master(compile)") dd.addDependencyConfiguration("optional", "provided(*)")
} else { // FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there.
dd.addDependencyConfiguration("runtime", "compile(*)") dd.addDependencyConfiguration("optional", "master(compile)")
dd.addDependencyConfiguration("runtime", "runtime(*)") } else {
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there. dd.addDependencyConfiguration("runtime", "compile(*)")
dd.addDependencyConfiguration("runtime", "master(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 { REPLACEMENT_MAPPINGS.put(
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = { "test",
dd.addDependencyConfiguration("test", "runtime(*)") new PomModuleDescriptorBuilder.ConfMapper {
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there. def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = {
dd.addDependencyConfiguration("test", "master(compile)") 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 { REPLACEMENT_MAPPINGS.put(
def addMappingConfs(dd: DefaultDependencyDescriptor, isOptional: Boolean): Unit = { "system",
// FIX - Here we take a mroe conservative approach of depending on the compile configuration if master isn't there. new PomModuleDescriptorBuilder.ConfMapper {
dd.addDependencyConfiguration("system", "master(compile)") 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 REPLACEMENT_MAPPINGS
} }
@ -106,13 +121,17 @@ object ReplaceMavenConfigurationMappings {
def init(): Unit = { def init(): Unit = {
// Here we mutate a static final field, because we have to AND because it's evil. // Here we mutate a static final field, because we have to AND because it's evil.
try { 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.clear()
map.putAll(REPLACEMENT_MAVEN_MAPPINGS) map.putAll(REPLACEMENT_MAVEN_MAPPINGS)
} catch { } catch {
case e: Exception => case e: Exception =>
// TODO - Log that Ivy may not be configured correctly and you could have maven/ivy issues. // 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
)
} }
} }
} }

View File

@ -6,16 +6,16 @@ import sbt.util.{ Level, Logger }
import Configurations._ import Configurations._
final class CompatibilityWarningOptions private[sbt] ( final class CompatibilityWarningOptions private[sbt] (
val configurations: Seq[Configuration], val configurations: Seq[Configuration],
val level: Level.Value val level: Level.Value
) )
object CompatibilityWarningOptions { object CompatibilityWarningOptions {
def default: CompatibilityWarningOptions = def default: CompatibilityWarningOptions =
apply(configurations = List(Compile, Runtime), level = Level.Warn) apply(configurations = List(Compile, Runtime), level = Level.Warn)
def apply( def apply(
configurations: List[Configuration], configurations: List[Configuration],
level: Level.Value level: Level.Value
): CompatibilityWarningOptions = ): CompatibilityWarningOptions =
new CompatibilityWarningOptions( new CompatibilityWarningOptions(
configurations = configurations, configurations = configurations,
@ -24,12 +24,21 @@ object CompatibilityWarningOptions {
} }
private[sbt] object CompatibilityWarning { 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) { if (mavenStyle) {
processIntransitive(config, module, log) 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 monitoredConfigsStr: Set[String] = (config.configurations map { _.name }).toSet
val directDependencies: Seq[ModuleID] = module.moduleSettings match { val directDependencies: Seq[ModuleID] = module.moduleSettings match {
case x: InlineConfiguration => x.dependencies case x: InlineConfiguration => x.dependencies

View File

@ -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 * This is used for compiled source jars so that the compilation need not be repeated for other projects on the same
* machine. * 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) 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. */ /** 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) 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.*/ /** 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 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. */ /** 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 = def file(id: String)(ifMissing: IfMissing): File =
files(id)(ifMissing).toList match { files(id)(ifMissing).toList match {
case x :: Nil => x 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) private def invalid(msg: String) = throw new InvalidComponent(msg)
def define(id: String, files: Iterable[File]) = lockLocalCache { provider.defineComponent(id, files.toSeq.toArray) } def define(id: String, files: Iterable[File]) = lockLocalCache {
/** Retrieve the file for component 'id' from the local repository. */ provider.defineComponent(id, files.toSeq.toArray)
private def update(id: String): Unit = ivyCache.withCachedJar(sbtModuleID(id), Some(globalLock), log)(jar => define(id, Seq(jar))) }
/** 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'. */ /** 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 cache(id: String): Unit =
def clearCache(id: String): Unit = lockGlobalCache { ivyCache.clearCachedJar(sbtModuleID(id), Some(globalLock), log) } 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) { class InvalidComponent(msg: String, cause: Throwable) extends RuntimeException(msg, cause) {
def this(msg: String) = this(msg, null) def this(msg: String) = this(msg, null)
@ -73,16 +92,17 @@ class InvalidComponent(msg: String, cause: Throwable) extends RuntimeException(m
sealed trait IfMissing sealed trait IfMissing
object IfMissing { object IfMissing {
object Fail extends 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 { object ComponentManager {
lazy val (version, timestamp) = lazy val (version, timestamp) = {
{ val properties = new java.util.Properties
val properties = new java.util.Properties val propertiesStream = versionResource.openStream
val propertiesStream = versionResource.openStream try { properties.load(propertiesStream) } finally { propertiesStream.close() }
try { properties.load(propertiesStream) } finally { propertiesStream.close() } (properties.getProperty("version"), properties.getProperty("timestamp"))
(properties.getProperty("version"), properties.getProperty("timestamp")) }
}
lazy val stampedVersion = version + "_" + timestamp lazy val stampedVersion = version + "_" + timestamp
import java.net.URL import java.net.URL

View File

@ -9,8 +9,20 @@ import org.apache.ivy.core.module.descriptor.DependencyDescriptor
import org.apache.ivy.core.resolve.ResolveData import org.apache.ivy.core.resolve.ResolveData
import org.apache.ivy.core.settings.IvySettings import org.apache.ivy.core.settings.IvySettings
import org.apache.ivy.plugins.repository.{ RepositoryCopyProgressListener, TransferEvent } import org.apache.ivy.plugins.repository.{ RepositoryCopyProgressListener, TransferEvent }
import org.apache.ivy.plugins.resolver.{ BasicResolver, DependencyResolver, IBiblioResolver, RepositoryResolver } import org.apache.ivy.plugins.resolver.{
import org.apache.ivy.plugins.resolver.{ AbstractPatternsBasedResolver, AbstractSshBasedResolver, FileSystemResolver, SFTPResolver, SshResolver, URLResolver } 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.url.{ URLRepository => URLRepo }
import org.apache.ivy.plugins.repository.file.{ FileRepository => FileRepo, FileResource } import org.apache.ivy.plugins.repository.file.{ FileRepository => FileRepo, FileResource }
import java.io.{ IOException, File } import java.io.{ IOException, File }
@ -41,25 +53,35 @@ private[sbt] object ConvertResolver {
thing.setAccessible(true) thing.setAccessible(true)
Some(thing) Some(thing)
} catch { } catch {
case (_: java.lang.NoSuchFieldException) | case (_: java.lang.NoSuchFieldException) | (_: java.lang.SecurityException) |
(_: java.lang.SecurityException) | (_: java.lang.NoSuchMethodException) =>
(_: java.lang.NoSuchMethodException) => None None
} }
private val signerNameField: Option[java.lang.reflect.Field] = private val signerNameField: Option[java.lang.reflect.Field] =
reflectiveLookup(_.getDeclaredField("signerName")) reflectiveLookup(_.getDeclaredField("signerName"))
private val putChecksumMethod: Option[java.lang.reflect.Method] = private val putChecksumMethod: Option[java.lang.reflect.Method] =
reflectiveLookup(_.getDeclaredMethod( reflectiveLookup(
"putChecksum", _.getDeclaredMethod(
classOf[IArtifact], classOf[File], classOf[String], "putChecksum",
classOf[Boolean], classOf[String] classOf[IArtifact],
)) classOf[File],
classOf[String],
classOf[Boolean],
classOf[String]
)
)
private val putSignatureMethod: Option[java.lang.reflect.Method] = private val putSignatureMethod: Option[java.lang.reflect.Method] =
reflectiveLookup(_.getDeclaredMethod( reflectiveLookup(
"putSignature", _.getDeclaredMethod(
classOf[IArtifact], classOf[File], classOf[String], "putSignature",
classOf[Boolean] classOf[IArtifact],
)) classOf[File],
classOf[String],
classOf[Boolean]
)
)
} }
/** /**
* The default behavior of ivy's overwrite flags ignores the fact that a lot of repositories * 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 * 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 Some(field) => field.get(this).asInstanceOf[String]
case None => null 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! // verify the checksum algorithms before uploading artifacts!
val checksums = getChecksumAlgorithms() val checksums = getChecksumAlgorithms()
val repository = getRepository() val repository = getRepository()
@ -89,8 +116,9 @@ private[sbt] object ConvertResolver {
// we need to overwrite what it has. // we need to overwrite what it has.
for (checksum <- checksums) { for (checksum <- checksums) {
putChecksumMethod match { putChecksumMethod match {
case Some(method) => method.invoke(this, artifact, src, dest, true: java.lang.Boolean, checksum) case Some(method) =>
case None => // TODO - issue warning? method.invoke(this, artifact, src, dest, true: java.lang.Boolean, checksum)
case None => // TODO - issue warning?
} }
} }
if (signerName != null) { if (signerName != null) {
@ -108,77 +136,84 @@ private[sbt] object ConvertResolver {
apply(r, settings, UpdateOptions(), log) apply(r, settings, UpdateOptions(), log)
/** Converts the given sbt resolver into an Ivy resolver. */ /** 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)) (updateOptions.resolverConverter orElse defaultConvert)((r, settings, log))
/** The default implementation of converter. */ /** The default implementation of converter. */
lazy val defaultConvert: ResolverConverter = { lazy val defaultConvert: ResolverConverter = {
case (r, settings, log) => case (r, settings, log) =>
r match { r match {
case repo: MavenRepository => case repo: MavenRepository => {
{ val pattern = Collections.singletonList(
val pattern = Collections.singletonList(Resolver.resolvePattern(repo.root, Resolver.mavenStyleBasePattern)) Resolver.resolvePattern(repo.root, Resolver.mavenStyleBasePattern)
final class PluginCapableResolver extends IBiblioResolver with ChecksumFriendlyURLResolver with DescriptorRequired { )
def setPatterns(): Unit = { final class PluginCapableResolver
// done this way for access to protected methods. extends IBiblioResolver
setArtifactPatterns(pattern) with ChecksumFriendlyURLResolver
setIvyPatterns(pattern) 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 PluginCapableResolver
{ if (repo.localIfFile) resolver.setRepository(new LocalIfFileRepo)
val resolver = new SshResolver with DescriptorRequired initializeMavenStyle(resolver, repo.name, repo.root)
initializeSSHResolver(resolver, repo, settings) resolver
repo.publishPermissions.foreach(perm => resolver.setPublishPermissions(perm)) .setPatterns() // has to be done after initializeMavenStyle, which calls methods that overwrite the patterns
resolver 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 => resolver.setName(repo.name)
{ initializePatterns(resolver, repo.patterns, settings)
val resolver = new SFTPResolver import repo.configuration.{ isLocal, isTransactional }
initializeSSHResolver(resolver, repo, settings) resolver.setLocal(isLocal)
resolver isTransactional.foreach(value => resolver.setTransactional(value.toString))
} resolver
case repo: FileRepository => }
{ case repo: URLRepository => {
val resolver = new FileSystemResolver with DescriptorRequired { val resolver = new URLResolver with ChecksumFriendlyURLResolver with DescriptorRequired
// Workaround for #1156 resolver.setName(repo.name)
// Temporarily in sbt 0.13.x we deprecate overwriting initializePatterns(resolver, repo.patterns, settings)
// in local files for non-changing revisions. resolver
// This will be fully enforced in sbt 1.0. }
setRepository(new WarnOnOverwriteFileRepo()) case repo: ChainedResolver =>
} IvySbt.resolverChain(repo.name, repo.resolvers, false, settings, log)
resolver.setName(repo.name) case repo: RawRepository => repo.resolver
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 { private sealed trait DescriptorRequired extends BasicResolver {
override def getDependency(dd: DependencyDescriptor, data: ResolveData) = override def getDependency(dd: DependencyDescriptor, data: ResolveData) = {
{ val prev = descriptorString(isAllownomd)
val prev = descriptorString(isAllownomd) setDescriptor(descriptorString(hasExplicitURL(dd)))
setDescriptor(descriptorString(hasExplicitURL(dd))) try super.getDependency(dd, data)
try super.getDependency(dd, data) finally setDescriptor(prev) finally setDescriptor(prev)
} }
def descriptorString(optional: Boolean) = def descriptorString(optional: Boolean) =
if (optional) BasicResolver.DESCRIPTOR_OPTIONAL else BasicResolver.DESCRIPTOR_REQUIRED if (optional) BasicResolver.DESCRIPTOR_OPTIONAL else BasicResolver.DESCRIPTOR_REQUIRED
def hasExplicitURL(dd: DependencyDescriptor): Boolean = def hasExplicitURL(dd: DependencyDescriptor): Boolean =
@ -189,35 +224,49 @@ private[sbt] object ConvertResolver {
resolver.setM2compatible(true) resolver.setM2compatible(true)
resolver.setRoot(root) 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.setName(repo.name)
resolver.setPassfile(null) resolver.setPassfile(null)
initializePatterns(resolver, repo.patterns, settings) initializePatterns(resolver, repo.patterns, settings)
initializeConnection(resolver, repo.connection) initializeConnection(resolver, repo.connection)
} }
private def initializeConnection(resolver: AbstractSshBasedResolver, connection: SshConnection): Unit = { private def initializeConnection(
resolver: AbstractSshBasedResolver,
connection: SshConnection
): Unit = {
import resolver._ import resolver._
import connection._ import connection._
hostname.foreach(setHost) hostname.foreach(setHost)
port.foreach(setPort) port.foreach(setPort)
authentication foreach authentication foreach {
{ case pa: PasswordAuthentication =>
case pa: PasswordAuthentication => setUser(pa.user)
setUser(pa.user) pa.password.foreach(setUserPassword)
pa.password.foreach(setUserPassword) case kfa: KeyFileAuthentication =>
case kfa: KeyFileAuthentication => setKeyFile(kfa.keyfile)
setKeyFile(kfa.keyfile) kfa.password.foreach(setKeyFilePassword)
kfa.password.foreach(setKeyFilePassword) setUser(kfa.user)
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.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) resolver.setCheckconsistency(!patterns.skipConsistencyCheck)
patterns.ivyPatterns.foreach(p => resolver.addIvyPattern(settings substitute p)) patterns.ivyPatterns.foreach(p => resolver.addIvyPattern(settings substitute p))
patterns.artifactPatterns.foreach(p => resolver.addArtifactPattern(settings substitute p)) patterns.artifactPatterns.foreach(p => resolver.addArtifactPattern(settings substitute p))
} }
/** /**
* A custom Ivy URLRepository that returns FileResources for file URLs. * 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. * 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 { catch {
case e: java.io.IOException if e.getMessage.contains("destination already exists") => case e: java.io.IOException if e.getMessage.contains("destination already exists") =>
import org.apache.ivy.util.Message 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) super.put(source, destination, true)
} }
} }

View File

@ -1,32 +1,62 @@
package sbt.internal.librarymanagement package sbt.internal.librarymanagement
import org.apache.ivy.core.module.id.ModuleRevisionId 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.core.module.descriptor.{ DefaultDependencyDescriptor, DependencyDescriptor }
import org.apache.ivy.plugins.parser.{ ModuleDescriptorParser, ModuleDescriptorParserRegistry, ParserSettings } import org.apache.ivy.plugins.parser.{
import org.apache.ivy.plugins.parser.m2.{ ReplaceMavenConfigurationMappings, PomModuleDescriptorBuilder, PomModuleDescriptorParser } 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.repository.Resource
import org.apache.ivy.plugins.namespace.NamespaceTransformer import org.apache.ivy.plugins.namespace.NamespaceTransformer
import org.apache.ivy.util.extendable.ExtendableItem import org.apache.ivy.util.extendable.ExtendableItem
import java.io.{ File, InputStream } import java.io.{ File, InputStream }
import java.net.URL import java.net.URL
import sbt.internal.librarymanagement.mavenint.{ PomExtraDependencyAttributes, SbtPomExtraProperties } import sbt.internal.librarymanagement.mavenint.{
PomExtraDependencyAttributes,
SbtPomExtraProperties
}
import sbt.io.Hash import sbt.io.Hash
// @deprecated("We now use an Aether-based pom parser.", "0.13.8") // @deprecated("We now use an Aether-based pom parser.", "0.13.8")
final class CustomPomParser(delegate: ModuleDescriptorParser, transform: (ModuleDescriptorParser, ModuleDescriptor) => ModuleDescriptor) extends ModuleDescriptorParser { final class CustomPomParser(
override def parseDescriptor(ivySettings: ParserSettings, descriptorURL: URL, validate: Boolean) = delegate: ModuleDescriptorParser,
transform: (ModuleDescriptorParser, ModuleDescriptor) => ModuleDescriptor
) extends ModuleDescriptorParser {
override def parseDescriptor(
ivySettings: ParserSettings,
descriptorURL: URL,
validate: Boolean
) =
transform(this, delegate.parseDescriptor(ivySettings, descriptorURL, validate)) 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)) 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 accept(res: Resource) = delegate.accept(res)
override def getType() = delegate.getType() 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") // @deprecated("We now use an Aether-based pom parser.", "0.13.8")
object CustomPomParser { object CustomPomParser {
@ -41,7 +71,8 @@ object CustomPomParser {
val SbtVersionKey = PomExtraDependencyAttributes.SbtVersionKey val SbtVersionKey = PomExtraDependencyAttributes.SbtVersionKey
val ScalaVersionKey = PomExtraDependencyAttributes.ScalaVersionKey val ScalaVersionKey = PomExtraDependencyAttributes.ScalaVersionKey
val ExtraAttributesKey = PomExtraDependencyAttributes.ExtraAttributesKey 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 // packagings that should be jars, but that Ivy doesn't handle as jars
// TODO - move this elsewhere. // TODO - move this elsewhere.
@ -51,7 +82,8 @@ object CustomPomParser {
private[this] val TransformedHashKey = "e:sbtTransformHash" private[this] val TransformedHashKey = "e:sbtTransformHash"
// A hash of the parameters transformation is based on. // A hash of the parameters transformation is based on.
// If a descriptor has a different hash, we need to retransform it. // 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. // 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 = { private[this] def MakeTransformHash(md: ModuleDescriptor): String = {
@ -60,7 +92,8 @@ object CustomPomParser {
hash((unqualifiedKeys ++ JarPackagings ++ Set(coords)).toSeq.sorted) 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. // Unfortunately, ModuleDescriptorParserRegistry is add-only and is a singleton instance.
lazy val registerDefault: Unit = ModuleDescriptorParserRegistry.getInstance.addParser(default) lazy val registerDefault: Unit = ModuleDescriptorParserRegistry.getInstance.addParser(default)
@ -69,74 +102,93 @@ object CustomPomParser {
if (transformedByThisVersion(md)) md if (transformedByThisVersion(md)) md
else defaultTransformImpl(parser, md) else defaultTransformImpl(parser, md)
private[this] def transformedByThisVersion(md: ModuleDescriptor): Boolean = private[this] def transformedByThisVersion(md: ModuleDescriptor): Boolean = {
{ val oldTransformedHashKey = "sbtTransformHash"
val oldTransformedHashKey = "sbtTransformHash" val extraInfo = md.getExtraInfo
val extraInfo = md.getExtraInfo val MyHash = MakeTransformHash(md)
val MyHash = MakeTransformHash(md) // sbt 0.13.1 used "sbtTransformHash" instead of "e:sbtTransformHash" until #1192 so read both
// sbt 0.13.1 used "sbtTransformHash" instead of "e:sbtTransformHash" until #1192 so read both Option(extraInfo).isDefined &&
Option(extraInfo).isDefined && ((Option(extraInfo get TransformedHashKey) orElse Option(extraInfo get oldTransformedHashKey)) match {
((Option(extraInfo get TransformedHashKey) orElse Option(extraInfo get oldTransformedHashKey)) match { case Some(MyHash) => true
case Some(MyHash) => true case _ => false
case _ => false })
}) }
}
private[this] def defaultTransformImpl(parser: ModuleDescriptorParser, md: ModuleDescriptor): ModuleDescriptor = private[this] def defaultTransformImpl(
{ parser: ModuleDescriptorParser,
val properties = getPomProperties(md) md: ModuleDescriptor
): ModuleDescriptor = {
val properties = getPomProperties(md)
// Extracts extra attributes (currently, sbt and Scala versions) stored in the <properties> element of the pom. // Extracts extra attributes (currently, sbt and Scala versions) stored in the <properties> element of the pom.
// These are attached to the module itself. // These are attached to the module itself.
val filtered = shouldBeUnqualified(properties) val filtered = shouldBeUnqualified(properties)
// Extracts extra attributes for the dependencies. // Extracts extra attributes for the dependencies.
// Because the <dependency> tag in pom.xml cannot include additional metadata, // Because the <dependency> tag in pom.xml cannot include additional metadata,
// sbt includes extra attributes in a 'extraDependencyAttributes' property. // sbt includes extra attributes in a 'extraDependencyAttributes' property.
// This is read/written from/to a pure string (no element structure) because Ivy only // This is read/written from/to a pure string (no element structure) because Ivy only
// parses the immediate text nodes of the property. // parses the immediate text nodes of the property.
val extraDepAttributes = getDependencyExtra(filtered) 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 // 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 // and we have to force the every generated xml file to have the appropriate xml namespace
addExtra(unqualify, extraDepAttributes, parser, md) 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. // 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. // 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. // 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. // 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] = private[sbt] def getPomProperties(md: ModuleDescriptor): Map[String, String] = {
{ import collection.JavaConverters._
import collection.JavaConverters._ PomModuleDescriptorBuilder
PomModuleDescriptorBuilder.extractPomProperties(md.getExtraInfo).asInstanceOf[java.util.Map[String, String]].asScala.toMap .extractPomProperties(md.getExtraInfo)
} .asInstanceOf[java.util.Map[String, String]]
.asScala
.toMap
}
private[sbt] def toUnqualify(propertyAttributes: Map[String, String]): Map[String, String] = private[sbt] def toUnqualify(propertyAttributes: Map[String, String]): Map[String, String] =
(propertyAttributes - ExtraAttributesKey) map { case (k, v) => ("e:" + k, v) } (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 = private[this] def addExtra(
{ properties: Map[String, String],
import collection.JavaConverters._ id: ModuleRevisionId
val oldExtra = qualifiedExtra(id) ): ModuleRevisionId = {
val newExtra = (oldExtra ++ properties).asJava import collection.JavaConverters._
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, newExtra) 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) 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] = 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] = def writeDependencyExtra(s: Seq[DependencyDescriptor]): Seq[String] =
PomExtraDependencyAttributes.writeDependencyExtra(s) PomExtraDependencyAttributes.writeDependencyExtra(s)
// parses the sequence of dependencies with extra attribute information, with one dependency per line // 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) def qualifiedIsExtra(k: String): Boolean = PomExtraDependencyAttributes.qualifiedIsExtra(k)
@ -145,20 +197,33 @@ object CustomPomParser {
// with the extra attributes from the <properties> section // with the extra attributes from the <properties> section
def simplify(id: ModuleRevisionId): ModuleRevisionId = PomExtraDependencyAttributes.simplify(id) def simplify(id: ModuleRevisionId): ModuleRevisionId = PomExtraDependencyAttributes.simplify(id)
private[this] def addExtra(dep: DependencyDescriptor, extra: Map[ModuleRevisionId, Map[String, String]]): DependencyDescriptor = private[this] def addExtra(
{ dep: DependencyDescriptor,
val extras = if (extra.isEmpty) None else extra get simplify(dep.getDependencyRevisionId) extra: Map[ModuleRevisionId, Map[String, String]]
extras match { ): DependencyDescriptor = {
case None => dep val extras = if (extra.isEmpty) None else extra get simplify(dep.getDependencyRevisionId)
case Some(extraAttrs) => transform(dep, revId => addExtra(extraAttrs, revId)) 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 { 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 def isIdentity = false
} }
@ -167,53 +232,80 @@ object CustomPomParser {
VersionRange.stripMavenVersionRange(dd.getDependencyRevisionId.getRevision) match { VersionRange.stripMavenVersionRange(dd.getDependencyRevisionId.getRevision) match {
case Some(newVersion) => case Some(newVersion) =>
val id = dd.getDependencyRevisionId 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) transform(dd, _ => newId)
case None => dd 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._ import collection.JavaConverters._
def addExtra(properties: Map[String, String], dependencyExtra: Map[ModuleRevisionId, Map[String, String]], parser: ModuleDescriptorParser, md: ModuleDescriptor): ModuleDescriptor = def addExtra(
{ properties: Map[String, String],
val dmd = new DefaultModuleDescriptor(parser, md.getResource) 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 mrid = addExtra(properties, md.getModuleRevisionId)
val resolvedMrid = addExtra(properties, md.getResolvedModuleRevisionId) val resolvedMrid = addExtra(properties, md.getResolvedModuleRevisionId)
dmd.setModuleRevisionId(mrid) dmd.setModuleRevisionId(mrid)
dmd.setResolvedModuleRevisionId(resolvedMrid) dmd.setResolvedModuleRevisionId(resolvedMrid)
dmd.setDefault(md.isDefault) dmd.setDefault(md.isDefault)
dmd.setHomePage(md.getHomePage) dmd.setHomePage(md.getHomePage)
dmd.setDescription(md.getDescription) dmd.setDescription(md.getDescription)
dmd.setLastModified(md.getLastModified) dmd.setLastModified(md.getLastModified)
dmd.setStatus(md.getStatus()) dmd.setStatus(md.getStatus())
dmd.setPublicationDate(md.getPublicationDate()) dmd.setPublicationDate(md.getPublicationDate())
dmd.setResolvedPublicationDate(md.getResolvedPublicationDate()) dmd.setResolvedPublicationDate(md.getResolvedPublicationDate())
for (l <- md.getLicenses) dmd.addLicense(l) for (l <- md.getLicenses) dmd.addLicense(l)
for ((key, value) <- md.getExtraInfo.asInstanceOf[java.util.Map[String, String]].asScala) dmd.addExtraInfo(key, value) for ((key, value) <- md.getExtraInfo.asInstanceOf[java.util.Map[String, String]].asScala)
dmd.addExtraInfo(TransformedHashKey, MakeTransformHash(md)) // mark as transformed by this version, so we don't need to do it again dmd.addExtraInfo(key, value)
for ((key, value) <- md.getExtraAttributesNamespaces.asInstanceOf[java.util.Map[String, String]].asScala) dmd.addExtraAttributeNamespace(key, value) dmd.addExtraInfo(TransformedHashKey, MakeTransformHash(md)) // mark as transformed by this version, so we don't need to do it again
IvySbt.addExtraNamespace(dmd) 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 withExtra = md.getDependencies map { dd =>
val withVersionRangeMod: Seq[DependencyDescriptor] = addExtra(dd, dependencyExtra)
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 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
}
} }

View File

@ -6,7 +6,10 @@ package sbt.internal.librarymanagement
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.net.URL 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.core.settings.IvySettings
import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser
import org.apache.ivy.plugins.repository.Resource 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.*/ /** Subclasses the default Ivy file parser in order to provide access to protected methods.*/
private[sbt] object CustomXmlParser extends XmlModuleDescriptorParser { private[sbt] object CustomXmlParser extends XmlModuleDescriptorParser {
import XmlModuleDescriptorParser.Parser import XmlModuleDescriptorParser.Parser
class CustomParser(settings: IvySettings, defaultConfig: Option[String]) extends Parser(CustomXmlParser, settings) { class CustomParser(settings: IvySettings, defaultConfig: Option[String])
def setSource(url: URL) = extends Parser(CustomXmlParser, settings) {
{ def setSource(url: URL) = {
super.setResource(new URLResource(url)) super.setResource(new URLResource(url))
super.setInput(url) super.setInput(url)
} }
def setInput(bytes: Array[Byte]): Unit = setInput(new ByteArrayInputStream(bytes)) def setInput(bytes: Array[Byte]): Unit = setInput(new ByteArrayInputStream(bytes))
/** Overridden because the super implementation overwrites the module descriptor.*/ /** Overridden because the super implementation overwrites the module descriptor.*/
override def setResource(res: Resource): Unit = () override def setResource(res: Resource): Unit = ()
override def setMd(md: DefaultModuleDescriptor) = override def setMd(md: DefaultModuleDescriptor) = {
{ super.setMd(md)
super.setMd(md) if (defaultConfig.isDefined) setDefaultConfMapping("*->default(compile)")
if (defaultConfig.isDefined) setDefaultConfMapping("*->default(compile)") }
} override def parseDepsConfs(confs: String, dd: DefaultDependencyDescriptor) =
override def parseDepsConfs(confs: String, dd: DefaultDependencyDescriptor) = super.parseDepsConfs(confs, dd) super.parseDepsConfs(confs, dd)
override def getDefaultConf = defaultConfig.getOrElse(super.getDefaultConf) override def getDefaultConf = defaultConfig.getOrElse(super.getDefaultConf)
} }
} }

View File

@ -5,7 +5,14 @@ import java.net.URL
import org.apache.ivy.core.cache.ArtifactOrigin import org.apache.ivy.core.cache.ArtifactOrigin
import org.apache.ivy.core.cache.{ DefaultRepositoryCacheManager, RepositoryCacheManager } 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.module.id.ModuleRevisionId
import org.apache.ivy.core.report.ArtifactDownloadReport import org.apache.ivy.core.report.ArtifactDownloadReport
import org.apache.ivy.core.report.{ DownloadReport, DownloadStatus } import org.apache.ivy.core.report.{ DownloadReport, DownloadStatus }
@ -22,7 +29,8 @@ import FakeResolver._
/** /**
* A fake `DependencyResolver` that statically serves predefined artifacts. * 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 { private object Artifact {
def unapply(art: IvyArtifact): Some[(String, String, String)] = { 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 = override def commitPublishTransaction(): Unit =
throw new UnsupportedOperationException("This resolver doesn't support publishing.") 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 report = new ArtifactDownloadReport(artifact.getArtifact)
val path = new URL(artifact.getLocation).toURI.getPath 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 mrid = dd.getDependencyRevisionId()
val artifact = modules get ((organisation, name, revision)) map { arts => val artifact = modules get ((organisation, name, revision)) map { arts =>
val artifacts: Array[DependencyArtifactDescriptor] = arts.toArray map (_ artifactOf dd) val artifacts: Array[DependencyArtifactDescriptor] = arts.toArray map (_ artifactOf dd)
val moduleDescriptor = DefaultModuleDescriptor.newDefaultInstance(mrid, artifacts) val moduleDescriptor = DefaultModuleDescriptor.newDefaultInstance(mrid, artifacts)
val defaultArtifact = arts.headOption match { val defaultArtifact = arts.headOption match {
case Some(FakeArtifact(name, tpe, ext, _)) => new DefaultArtifact(mrid, new java.util.Date, name, tpe, ext) case Some(FakeArtifact(name, tpe, ext, _)) =>
case None => null new DefaultArtifact(mrid, new java.util.Date, name, tpe, ext)
case None => null
} }
val metadataReport = new MetadataArtifactDownloadReport(defaultArtifact) val metadataReport = new MetadataArtifactDownloadReport(defaultArtifact)
metadataReport.setDownloadStatus(DownloadStatus.SUCCESSFUL) metadataReport.setDownloadStatus(DownloadStatus.SUCCESSFUL)
@ -147,10 +158,16 @@ private[sbt] class FakeResolver(private var name: String, cacheDir: File, module
new RevisionEntry(module, v) new RevisionEntry(module, v)
}.toArray }.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 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 Array.empty
override def locate(art: IvyArtifact): ArtifactOrigin = { override def locate(art: IvyArtifact): ArtifactOrigin = {
@ -158,7 +175,8 @@ private[sbt] class FakeResolver(private var name: String, cacheDir: File, module
val artifact = val artifact =
for { for {
artifacts <- modules get ((moduleOrganisation, moduleName, moduleRevision)) 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) } yield new ArtifactOrigin(art, /* isLocal = */ true, artifact.file.toURI.toURL.toString)
artifact.orNull artifact.orNull
@ -183,6 +201,13 @@ private[sbt] object FakeResolver {
final case class FakeArtifact(name: String, tpe: String, ext: String, file: File) { final case class FakeArtifact(name: String, tpe: String, ext: String, file: File) {
def artifactOf(dd: DependencyDescriptor): DependencyArtifactDescriptor = 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
)
} }
} }

View File

@ -12,7 +12,12 @@ import org.apache.ivy.Ivy
import org.apache.ivy.core.{ IvyPatternHelper, LogOptions } import org.apache.ivy.core.{ IvyPatternHelper, LogOptions }
import org.apache.ivy.core.deliver.DeliverOptions import org.apache.ivy.core.deliver.DeliverOptions
import org.apache.ivy.core.install.InstallOptions 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.report.ResolveReport
import org.apache.ivy.core.resolve.ResolveOptions import org.apache.ivy.core.resolve.ResolveOptions
import org.apache.ivy.plugins.resolver.{ BasicResolver, DependencyResolver } 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.internal.util.{ SourcePosition, LinePosition, RangePosition, LineRange }
import sbt.librarymanagement._, syntax._ import sbt.librarymanagement._, syntax._
final class DeliverConfiguration(val deliverIvyPattern: String, val status: String, val configurations: Option[Vector[Configuration]], val logging: UpdateLogging) final class DeliverConfiguration(
final class PublishConfiguration(val ivyFile: Option[File], val resolverName: String, val artifacts: Map[Artifact, File], val checksums: Vector[String], val logging: UpdateLogging, val deliverIvyPattern: String,
val overwrite: Boolean) { val status: String,
def this(ivyFile: Option[File], resolverName: String, artifacts: Map[Artifact, File], checksums: Vector[String], logging: UpdateLogging) = 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) 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 */ /** @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 GetClassifiersConfiguration(
final case class GetClassifiersModule(id: ModuleID, modules: Vector[ModuleID], configurations: Vector[Configuration], classifiers: Vector[String]) 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] ( final class UnresolvedWarningConfiguration private[sbt] (
val modulePositions: Map[ModuleID, SourcePosition] val modulePositions: Map[ModuleID, SourcePosition]
) )
object UnresolvedWarningConfiguration { object UnresolvedWarningConfiguration {
def apply(): UnresolvedWarningConfiguration = apply(Map()) def apply(): UnresolvedWarningConfiguration = apply(Map())
@ -43,6 +87,7 @@ object UnresolvedWarningConfiguration {
} }
object IvyActions { object IvyActions {
/** Installs the dependencies of the given 'module' from the resolver named 'from' to the resolver named 'to'.*/ /** 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 = { def install(module: IvySbt#Module, from: String, to: String, log: Logger): Unit = {
module.withModule(log) { (ivy, md, default) => module.withModule(log) { (ivy, md, default) =>
@ -73,27 +118,48 @@ object IvyActions {
/** Creates a Maven pom from the given Ivy configuration*/ /** Creates a Maven pom from the given Ivy configuration*/
def makePom(module: IvySbt#Module, configuration: MakePomConfiguration, log: Logger): Unit = { 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) => 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) log.info("Wrote " + file.getAbsolutePath)
} }
} }
def deliver(module: IvySbt#Module, configuration: DeliverConfiguration, log: Logger): File = def deliver(module: IvySbt#Module, configuration: DeliverConfiguration, log: Logger): File = {
{ import configuration._
import configuration._ module.withModule(log) {
module.withModule(log) { case (ivy, md, default) =>
case (ivy, md, default) => val revID = md.getModuleRevisionId
val revID = md.getModuleRevisionId val options = DeliverOptions.newInstance(ivy.getSettings).setStatus(status)
val options = DeliverOptions.newInstance(ivy.getSettings).setStatus(status) options.setConfs(IvySbt.getConfigurations(md, configurations))
options.setConfs(IvySbt.getConfigurations(md, configurations)) ivy.deliver(revID, revID.getRevision, deliverIvyPattern, options)
ivy.deliver(revID, revID.getRevision, deliverIvyPattern, options) deliveredFile(ivy, deliverIvyPattern, md)
deliveredFile(ivy, deliverIvyPattern, md)
}
} }
}
def deliveredFile(ivy: Ivy, pattern: String, md: ModuleDescriptor): File = 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 = { def publish(module: IvySbt#Module, configuration: PublishConfiguration, log: Logger): Unit = {
import configuration._ import configuration._
@ -101,40 +167,59 @@ object IvyActions {
case (ivy, md, default) => case (ivy, md, default) =>
val resolver = ivy.getSettings.getResolver(resolverName) val resolver = ivy.getSettings.getResolver(resolverName)
if (resolver eq null) sys.error("Undefined resolver '" + 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 cross = crossVersionMap(module.moduleSettings)
val as = mapArtifacts(md, cross, artifacts) ++ ivyArtifact.toList val as = mapArtifacts(md, cross, artifacts) ++ ivyArtifact.toList
withChecksums(resolver, checksums) { publish(md, as, resolver, overwrite = overwrite) } 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 } resolver match { case br: BasicResolver => withChecksums(br, checksums)(act); case _ => act }
private[this] def withChecksums[T](resolver: BasicResolver, checksums: Vector[String])(act: => T): T = private[this] def withChecksums[T](resolver: BasicResolver, checksums: Vector[String])(
{ act: => T
val previous = resolver.getChecksumAlgorithms ): T = {
resolver.setChecksums(checksums mkString ",") val previous = resolver.getChecksumAlgorithms
try { act } resolver.setChecksums(checksums mkString ",")
finally { resolver.setChecksums(previous mkString ",") } try { act } finally { resolver.setChecksums(previous mkString ",") }
} }
private def crossVersionMap(moduleSettings: ModuleSettings): Option[String => String] = private def crossVersionMap(moduleSettings: ModuleSettings): Option[String => String] =
moduleSettings match { moduleSettings match {
case i: InlineConfiguration => CrossVersion(i.module, i.ivyScala) case i: InlineConfiguration => CrossVersion(i.module, i.ivyScala)
case _ => None case _ => None
} }
def mapArtifacts(module: ModuleDescriptor, cross: Option[String => String], artifacts: Map[Artifact, File]): Vector[(IArtifact, File)] = def mapArtifacts(
{ module: ModuleDescriptor,
val rawa = artifacts.keys.toVector cross: Option[String => String],
val seqa = CrossVersion.substituteCross(rawa, cross) artifacts: Map[Artifact, File]
val zipped = rawa zip IvySbt.mapArtifacts(module, seqa) ): Vector[(IArtifact, File)] = {
zipped map { case (a, ivyA) => (ivyA, artifacts(a)) } 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. * Resolves and retrieves dependencies. 'ivyConfig' is used to produce an Ivy file and configuration.
* 'updateConfig' configures the actual resolution and retrieval process. * 'updateConfig' configures the actual resolution and retrieval process.
*/ */
@deprecated("This is no longer public.", "0.13.6") @deprecated("This is no longer public.", "0.13.6")
def update(module: IvySbt#Module, configuration: UpdateConfiguration, log: Logger): UpdateReport = def update(
updateEither(module, configuration, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, log) match { module: IvySbt#Module,
configuration: UpdateConfiguration,
log: Logger
): UpdateReport =
updateEither(
module,
configuration,
UnresolvedWarningConfiguration(),
LogicalClock.unknown,
None,
log
) match {
case Right(r) => r case Right(r) => r
case Left(w) => case Left(w) =>
throw w.resolveException throw w.resolveException
@ -144,10 +229,17 @@ object IvyActions {
* Resolves and retrieves dependencies. 'ivyConfig' is used to produce an Ivy file and configuration. * Resolves and retrieves dependencies. 'ivyConfig' is used to produce an Ivy file and configuration.
* 'updateConfig' configures the actual resolution and retrieval process. * 'updateConfig' configures the actual resolution and retrieval process.
*/ */
private[sbt] def updateEither(module: IvySbt#Module, configuration: UpdateConfiguration, private[sbt] def updateEither(
uwconfig: UnresolvedWarningConfiguration, logicalClock: LogicalClock, depDir: Option[File], log: Logger): Either[UnresolvedWarning, UpdateReport] = module: IvySbt#Module,
configuration: UpdateConfiguration,
uwconfig: UnresolvedWarningConfiguration,
logicalClock: LogicalClock,
depDir: Option[File],
log: Logger
): Either[UnresolvedWarning, UpdateReport] =
module.withModule(log) { 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 { ivy.getResolveEngine match {
case x: CachedResolutionResolveEngine => case x: CachedResolutionResolveEngine =>
val iw = IvySbt.inconsistentDuplicateWarning(md) val iw = IvySbt.inconsistentDuplicateWarning(md)
@ -157,7 +249,16 @@ object IvyActions {
resolveOptions.setResolveId(resolveId) resolveOptions.setResolveId(resolveId)
resolveOptions.setArtifactFilter(configuration.artifactFilter) resolveOptions.setArtifactFilter(configuration.artifactFilter)
resolveOptions.setLog(ivyLogLevel(configuration.logging)) 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) => case Left(x) =>
Left(UnresolvedWarning(x, uwconfig)) Left(UnresolvedWarning(x, uwconfig))
case Right(uReport) => case Right(uReport) =>
@ -170,12 +271,14 @@ object IvyActions {
case (ivy, md, default) => case (ivy, md, default) =>
val iw = IvySbt.inconsistentDuplicateWarning(md) val iw = IvySbt.inconsistentDuplicateWarning(md)
iw foreach { log.warn(_) } 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 { err match {
case Some(x) if !configuration.missingOk => case Some(x) if !configuration.missingOk =>
Left(UnresolvedWarning(x, uwconfig)) Left(UnresolvedWarning(x, uwconfig))
case _ => case _ =>
val cachedDescriptor = ivy.getSettings.getResolutionCacheManager.getResolvedIvyFileInCache(md.getModuleRevisionId) val cachedDescriptor = ivy.getSettings.getResolutionCacheManager
.getResolvedIvyFileInCache(md.getModuleRevisionId)
val uReport = IvyRetrieve.updateReport(report, cachedDescriptor) val uReport = IvyRetrieve.updateReport(report, cachedDescriptor)
configuration.retrieve match { configuration.retrieve match {
case Some(rConf) => Right(retrieve(log, ivy, uReport, rConf)) case Some(rConf) => Right(retrieve(log, ivy, uReport, rConf))
@ -185,11 +288,14 @@ object IvyActions {
} }
@deprecated("No longer used.", "0.13.6") @deprecated("No longer used.", "0.13.6")
def processUnresolved(err: ResolveException, log: Logger): Unit = () 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 => report.configurations.flatMap { confReport =>
val evicted = confReport.evicted.filter(moduleFilter) val evicted = confReport.evicted.filter(moduleFilter)
val evictedSet = evicted.map(m => (m.organization, m.name)).toSet 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) grouped(grouping)(conflicted ++ evicted)
}.toMap }.toMap
@ -197,27 +303,59 @@ object IvyActions {
mods groupBy (grouping) mapValues (_.map(_.revision).toSet) mods groupBy (grouping) mapValues (_.map(_.revision).toSet)
@deprecated("This is no longer public.", "0.13.6") @deprecated("This is no longer public.", "0.13.6")
def transitiveScratch(ivySbt: IvySbt, label: String, config: GetClassifiersConfiguration, log: Logger): UpdateReport = def transitiveScratch(
transitiveScratch(ivySbt, label, config, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, log) 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, private[sbt] def transitiveScratch(
uwconfig: UnresolvedWarningConfiguration, logicalClock: LogicalClock, depDir: Option[File], log: Logger): UpdateReport = ivySbt: IvySbt,
{ label: String,
import config.{ configuration => c, ivyScala, module => mod } config: GetClassifiersConfiguration,
import mod.{ id, modules => deps } uwconfig: UnresolvedWarningConfiguration,
val base = restrictedCopy(id, true).withName(id.name + "$" + label) logicalClock: LogicalClock,
val module = new ivySbt.Module(InlineConfiguration(false, ivyScala, base, ModuleInfo(base.name), deps)) depDir: Option[File],
val report = updateEither(module, c, uwconfig, logicalClock, depDir, log) match { log: Logger
case Right(r) => r ): UpdateReport = {
case Left(w) => import config.{ configuration => c, ivyScala, module => mod }
throw w.resolveException import mod.{ id, modules => deps }
} val base = restrictedCopy(id, true).withName(id.name + "$" + label)
val newConfig = config.copy(module = mod.copy(modules = report.allModules)) val module =
updateClassifiers(ivySbt, newConfig, uwconfig, logicalClock, depDir, Vector(), log) 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") @deprecated("This is no longer public.", "0.13.6")
def updateClassifiers(ivySbt: IvySbt, config: GetClassifiersConfiguration, log: Logger): UpdateReport = def updateClassifiers(
updateClassifiers(ivySbt, config, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, Vector(), log) 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 * 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 * @param config important to set `config.configuration.types` to only allow artifact types that can correspond to
* "classified" artifacts (sources and javadocs). * "classified" artifacts (sources and javadocs).
*/ */
private[sbt] def updateClassifiers(ivySbt: IvySbt, config: GetClassifiersConfiguration, private[sbt] def updateClassifiers(
uwconfig: UnresolvedWarningConfiguration, logicalClock: LogicalClock, depDir: Option[File], ivySbt: IvySbt,
artifacts: Vector[(String, ModuleID, Artifact, File)], config: GetClassifiersConfiguration,
log: Logger): UpdateReport = uwconfig: UnresolvedWarningConfiguration,
{ logicalClock: LogicalClock,
import config.{ configuration => c, module => mod, _ } depDir: Option[File],
import mod.{ configurations => confs, _ } artifacts: Vector[(String, ModuleID, Artifact, File)],
assert(classifiers.nonEmpty, "classifiers cannot be empty") log: Logger
assert(c.artifactFilter.types.nonEmpty, "UpdateConfiguration must filter on some types") ): UpdateReport = {
val baseModules = modules map { m => restrictedCopy(m, true) } import config.{ configuration => c, module => mod, _ }
// Adding list of explicit artifacts here. import mod.{ configurations => confs, _ }
val deps = baseModules.distinct flatMap classifiedArtifacts(classifiers, exclude, artifacts) assert(classifiers.nonEmpty, "classifiers cannot be empty")
val base = restrictedCopy(id, true).withName(id.name + classifiers.mkString("$", "_", "")) assert(c.artifactFilter.types.nonEmpty, "UpdateConfiguration must filter on some types")
val module = new ivySbt.Module(InlineConfiguration(false, ivyScala, base, ModuleInfo(base.name), deps).withConfigurations(confs)) val baseModules = modules map { m =>
// c.copy ensures c.types is preserved too restrictedCopy(m, true)
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
}
} }
// 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 // This version adds explicit artifact
private[sbt] def classifiedArtifacts( private[sbt] def classifiedArtifacts(
classifiers: Vector[String], classifiers: Vector[String],
exclude: Map[ModuleID, Set[String]], exclude: Map[ModuleID, Set[String]],
artifacts: Vector[(String, ModuleID, Artifact, File)] artifacts: Vector[(String, ModuleID, Artifact, File)]
)(m: ModuleID): Option[ModuleID] = { )(m: ModuleID): Option[ModuleID] = {
def sameModule(m1: ModuleID, m2: ModuleID): Boolean = m1.organization == m2.organization && m1.name == m2.name && m1.revision == m2.revision def sameModule(m1: ModuleID, m2: ModuleID): Boolean =
def explicitArtifacts = 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 val arts = (artifacts collect {
if (arts.isEmpty) None case (_, x, art, _) if sameModule(m, x) && art.classifier.isDefined => art
else Some(intransitiveModuleWithExplicitArts(m, arts)) }).distinct
} if (arts.isEmpty) None
else Some(intransitiveModuleWithExplicitArts(m, arts))
}
def hardcodedArtifacts = classifiedArtifacts(classifiers, exclude)(m) def hardcodedArtifacts = classifiedArtifacts(classifiers, exclude)(m)
explicitArtifacts orElse hardcodedArtifacts explicitArtifacts orElse hardcodedArtifacts
} }
private def classifiedArtifacts(classifiers: Vector[String], exclude: Map[ModuleID, Set[String]])(m: ModuleID): Option[ModuleID] = private def classifiedArtifacts(
{ classifiers: Vector[String],
val excluded = exclude getOrElse (restrictedCopy(m, false), Set.empty) exclude: Map[ModuleID, Set[String]]
val included = classifiers filterNot excluded )(m: ModuleID): Option[ModuleID] = {
if (included.isEmpty) None else { val excluded = exclude getOrElse (restrictedCopy(m, false), Set.empty)
Some(intransitiveModuleWithExplicitArts(module = m, arts = classifiedArtifacts(m.name, included))) 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, * 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. * `usage.getDependencyIncludesSet` returns null if there are no (explicit) include rules.
*/ */
private def intransitiveModuleWithExplicitArts(module: ModuleID, arts: Vector[Artifact]): ModuleID = private def intransitiveModuleWithExplicitArts(
module.withIsTransitive(false).withExplicitArtifacts(arts).withInclusions(Vector(InclExclRule.everything)) 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 = def addExcluded(
report.addMissing { id => classifiedArtifacts(id.name, classifiers filter getExcluded(id, exclude)) } 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] = 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] = private[this] def getExcluded(id: ModuleID, exclude: Map[ModuleID, Set[String]]): Set[String] =
exclude.getOrElse(restrictedCopy(id, false), Set.empty[String]) exclude.getOrElse(restrictedCopy(id, false), Set.empty[String])
def extractExcludes(report: UpdateReport): Map[ModuleID, Set[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) = 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) .branch(m.branchName)
private[this] def resolve(logging: UpdateLogging)(ivy: Ivy, module: DefaultModuleDescriptor, defaultConf: String, filter: ArtifactTypeFilter): (ResolveReport, Option[ResolveException]) = private[this] def resolve(logging: UpdateLogging)(
{ ivy: Ivy,
val resolveOptions = new ResolveOptions module: DefaultModuleDescriptor,
val resolveId = ResolveOptions.getDefaultResolveId(module) defaultConf: String,
resolveOptions.setResolveId(resolveId) filter: ArtifactTypeFilter
resolveOptions.setArtifactFilter(filter) ): (ResolveReport, Option[ResolveException]) = {
resolveOptions.setLog(ivyLogLevel(logging)) val resolveOptions = new ResolveOptions
ResolutionCache.cleanModule(module.getModuleRevisionId, resolveId, ivy.getSettings.getResolutionCacheManager) val resolveId = ResolveOptions.getDefaultResolveId(module)
val resolveReport = ivy.resolve(module, resolveOptions) resolveOptions.setResolveId(resolveId)
val err = resolveOptions.setArtifactFilter(filter)
if (resolveReport.hasError) { resolveOptions.setLog(ivyLogLevel(logging))
val messages = resolveReport.getAllProblemMessages.toArray.map(_.toString).distinct ResolutionCache.cleanModule(
val failedPaths = Map(resolveReport.getUnresolvedDependencies map { node => module.getModuleRevisionId,
val m = IvyRetrieve.toModuleID(node.getId) resolveId,
val path = IvyRetrieve.findPath(node, module.getModuleRevisionId) map { x => ivy.getSettings.getResolutionCacheManager
IvyRetrieve.toModuleID(x.getId) )
} val resolveReport = ivy.resolve(module, resolveOptions)
m -> path val err =
}: _*) if (resolveReport.hasError) {
val failed = failedPaths.keys.toSeq val messages = resolveReport.getAllProblemMessages.toArray.map(_.toString).distinct
Some(new ResolveException(messages, failed, failedPaths)) val failedPaths = Map(resolveReport.getUnresolvedDependencies map { node =>
} else None val m = IvyRetrieve.toModuleID(node.getId)
(resolveReport, err) 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 = val existingFiles = PathFinder(base).allPaths.get filterNot { _.isDirectory }
retrieve(log, ivy, report, config.retrieveDirectory, config.outputPattern, config.sync, config.configurationsToRetrieve) val toCopy = new collection.mutable.HashSet[(File, File)]
val retReport = report retrieve { (conf, mid, art, cached) =>
private def retrieve(log: Logger, ivy: Ivy, report: UpdateReport, base: File, pattern: String, sync: Boolean, configurationsToRetrieve: Option[Set[Configuration]]): UpdateReport = configurationNames match {
{ case None => performRetrieve(conf, mid, art, base, pattern, cached, toCopy)
val configurationNames = configurationsToRetrieve match { case Some(names) if names(conf) =>
case None => None performRetrieve(conf, mid, art, base, pattern, cached, toCopy)
case Some(configs) => Some(configs.map(_.name)) case _ => cached
} }
val existingFiles = PathFinder(base).allPaths.get filterNot { _.isDirectory } }
val toCopy = new collection.mutable.HashSet[(File, File)] IO.copy(toCopy)
val retReport = report retrieve { (conf, mid, art, cached) => val resolvedFiles = toCopy.map(_._2)
configurationNames match { if (sync) {
case None => performRetrieve(conf, mid, art, base, pattern, cached, toCopy) val filesToDelete = existingFiles.filterNot(resolvedFiles.contains)
case Some(names) if names(conf) => performRetrieve(conf, mid, art, base, pattern, cached, toCopy) filesToDelete foreach { f =>
case _ => cached 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) val to = retrieveTarget(conf, mid, art, base, pattern)
toCopy += ((cached, to)) toCopy += ((cached, to))
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)) new File(base, substitute(conf, mid, art, pattern))
private def substitute(conf: String, mid: ModuleID, art: Artifact, pattern: String): String = private def substitute(conf: String, mid: ModuleID, art: Artifact, pattern: String): String = {
{ val mextra = IvySbt.javaMap(mid.extraAttributes, true)
val mextra = IvySbt.javaMap(mid.extraAttributes, true) val aextra = IvySbt.extra(art, true)
val aextra = IvySbt.extra(art, true) IvyPatternHelper.substitute(
IvyPatternHelper.substitute(pattern, mid.organization, mid.name, mid.branchName.orNull, mid.revision, art.name, art.`type`, art.extension, conf, null, mextra, aextra) 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 UpdateLogging.{ Quiet, Full, DownloadOnly, Default }
import LogOptions.{ LOG_QUIET, LOG_DEFAULT, LOG_DOWNLOAD_ONLY } import LogOptions.{ LOG_QUIET, LOG_DEFAULT, LOG_DOWNLOAD_ONLY }
@ -398,46 +632,57 @@ object IvyActions {
case Default => LOG_DOWNLOAD_ONLY case Default => LOG_DOWNLOAD_ONLY
} }
def publish(module: ModuleDescriptor, artifacts: Seq[(IArtifact, File)], resolver: DependencyResolver, overwrite: Boolean): Unit = def publish(
{ module: ModuleDescriptor,
if (artifacts.nonEmpty) { artifacts: Seq[(IArtifact, File)],
checkFilesPresent(artifacts) resolver: DependencyResolver,
try { overwrite: Boolean
resolver.beginPublishTransaction(module.getModuleRevisionId(), overwrite); ): Unit = {
for ((artifact, file) <- artifacts) if (artifacts.nonEmpty) {
resolver.publish(artifact, file, overwrite) checkFilesPresent(artifacts)
resolver.commitPublishTransaction() try {
} catch { resolver.beginPublishTransaction(module.getModuleRevisionId(), overwrite);
case e: Throwable => for ((artifact, file) <- artifacts)
try { resolver.abortPublishTransaction() } resolver.publish(artifact, file, overwrite)
finally { throw e } resolver.commitPublishTransaction()
} } catch {
case e: Throwable =>
try { resolver.abortPublishTransaction() } finally { throw e }
} }
} }
}
private[this] def checkFilesPresent(artifacts: Seq[(IArtifact, File)]): Unit = { private[this] def checkFilesPresent(artifacts: Seq[(IArtifact, File)]): Unit = {
val missing = artifacts filter { case (a, file) => !file.exists } val missing = artifacts filter { case (a, file) => !file.exists }
if (missing.nonEmpty) 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( final class ResolveException(
val messages: Seq[String], val messages: Seq[String],
val failed: Seq[ModuleID], val failed: Seq[ModuleID],
val failedPaths: Map[ModuleID, Seq[ModuleID]] val failedPaths: Map[ModuleID, Seq[ModuleID]]
) extends RuntimeException(messages.mkString("\n")) { ) extends RuntimeException(messages.mkString("\n")) {
def this(messages: Seq[String], failed: Seq[ModuleID]) = 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 * Represents unresolved dependency warning, which displays reconstructed dependency tree
* along with source position of each node. * along with source position of each node.
*/ */
final class UnresolvedWarning private[sbt] ( final class UnresolvedWarning private[sbt] (
val resolveException: ResolveException, val resolveException: ResolveException,
val failedPaths: Seq[Seq[(ModuleID, Option[SourcePosition])]] val failedPaths: Seq[Seq[(ModuleID, Option[SourcePosition])]]
) )
object UnresolvedWarning { 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] = def modulePosition(m0: ModuleID): Option[SourcePosition] =
config.modulePositions.find { config.modulePositions.find {
case (m, p) => case (m, p) =>
@ -454,20 +699,25 @@ object UnresolvedWarning {
} }
apply(err, failedPaths) 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) new UnresolvedWarning(err, failedPaths)
private[sbt] def sourcePosStr(posOpt: Option[SourcePosition]): String = private[sbt] def sourcePosStr(posOpt: Option[SourcePosition]): String =
posOpt match { 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 Some(RangePosition(path, LineRange(start, end))) => s" ($path#L$start-$end)"
case _ => "" case _ => ""
} }
implicit val unresolvedWarningLines: ShowLines[UnresolvedWarning] = ShowLines { a => implicit val unresolvedWarningLines: ShowLines[UnresolvedWarning] = ShowLines { a =>
val withExtra = a.resolveException.failed.filter(_.extraDependencyAttributes.nonEmpty) val withExtra = a.resolveException.failed.filter(_.extraDependencyAttributes.nonEmpty)
val buffer = mutable.ListBuffer[String]() val buffer = mutable.ListBuffer[String]()
if (withExtra.nonEmpty) { if (withExtra.nonEmpty) {
buffer += "\n\tNote: Some unresolved dependencies have extra attributes. Check that these dependencies exist with the requested attributes." 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) { if (a.failedPaths.nonEmpty) {
buffer += "\n\tNote: Unresolved dependencies path:" buffer += "\n\tNote: Unresolved dependencies path:"

View File

@ -5,7 +5,11 @@ package sbt.internal.librarymanagement
import java.io.File 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.core.module.descriptor.{ Artifact => IvyArtifact, DefaultArtifact }
import org.apache.ivy.plugins.repository.file.{ FileRepository => IvyFileRepository, FileResource } import org.apache.ivy.plugins.repository.file.{ FileRepository => IvyFileRepository, FileResource }
import org.apache.ivy.plugins.repository.{ ArtifactResourceResolver, Resource, ResourceDownloader } import org.apache.ivy.plugins.repository.{ ArtifactResourceResolver, Resource, ResourceDownloader }
@ -20,36 +24,46 @@ import scala.collection.mutable
import jawn.{ SupportParser, MutableFacade } import jawn.{ SupportParser, MutableFacade }
class NotInCache(val id: ModuleID, cause: Throwable) 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) def this(id: ModuleID) = this(id, null)
} }
private object NotInCache { private object NotInCache {
def apply(id: ModuleID, cause: Throwable) = def apply(id: ModuleID, cause: Throwable) = {
{ val postfix = if (cause == null) "" else (": " + cause.toString)
val postfix = if (cause == null) "" else (": " + cause.toString) "File for " + id + " not in cache" + postfix
"File for " + id + " not in cache" + postfix }
}
} }
/** Provides methods for working at the level of a single jar file with the default Ivy cache.*/ /** Provides methods for working at the level of a single jar file with the default Ivy cache.*/
class IvyCache(val ivyHome: Option[File]) { class IvyCache(val ivyHome: Option[File]) {
def lockFile = new File(ivyHome getOrElse Path.userHome, ".sbt.cache.lock") 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.*/ /** 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 = { def cacheJar(moduleID: ModuleID, file: File, lock: Option[xsbti.GlobalLock], log: Logger): Unit = {
val artifact = defaultArtifact(moduleID) 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 => withDefaultCache(lock, log) { cache =>
val resolver = new ArtifactResourceResolver { def resolve(artifact: IvyArtifact) = resolved } val resolver = new ArtifactResourceResolver { def resolve(artifact: IvyArtifact) = resolved }
cache.download(artifact, resolver, new FileDownloader, new CacheDownloadOptions) cache.download(artifact, resolver, new FileDownloader, new CacheDownloadOptions)
() ()
} }
} }
/** Clears the cache of the jar for the given ID.*/ /** Clears the cache of the jar for the given ID.*/
def clearCachedJar(id: ModuleID, lock: Option[xsbti.GlobalLock], log: Logger): Unit = { def clearCachedJar(id: ModuleID, lock: Option[xsbti.GlobalLock], log: Logger): Unit = {
try { withCachedJar(id, lock, log)(_.delete); () } try { withCachedJar(id, lock, log)(_.delete); () } catch {
catch { case e: Exception => log.debug("Error cleaning cached jar: " + e.toString) } 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.*/ /** 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 => withCachedJar(id, lock, log) { cachedFile =>
val copyTo = new File(toDirectory, cachedFile.getName) val copyTo = new File(toDirectory, cachedFile.getName)
FileUtil.copy(cachedFile, copyTo, null) 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 .*/ /** 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 = def withCachedJar[T](id: ModuleID, lock: Option[xsbti.GlobalLock], log: Logger)(
{ f: File => T
val cachedFile = ): T = {
try { val cachedFile =
withDefaultCache(lock, log) { cache => try {
val artifact = defaultArtifact(id) withDefaultCache(lock, log) { cache =>
cache.getArchiveFileInCache(artifact, unknownOrigin(artifact)) val artifact = defaultArtifact(id)
} cache.getArchiveFileInCache(artifact, unknownOrigin(artifact))
} catch { case e: Exception => throw new NotInCache(id, e) } }
} 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.*/ /** Calls the given function with the default Ivy cache.*/
def withDefaultCache[T](lock: Option[xsbti.GlobalLock], log: Logger)(f: DefaultRepositoryCacheManager => T): T = def withDefaultCache[T](lock: Option[xsbti.GlobalLock], log: Logger)(
{ f: DefaultRepositoryCacheManager => T
val (ivy, _) = basicLocalIvy(lock, log) ): T = {
ivy.withIvy(log) { ivy => val (ivy, _) = basicLocalIvy(lock, log)
val cache = ivy.getSettings.getDefaultRepositoryCacheManager.asInstanceOf[DefaultRepositoryCacheManager] ivy.withIvy(log) { ivy =>
cache.setUseOrigin(false) val cache = ivy.getSettings.getDefaultRepositoryCacheManager
f(cache) .asInstanceOf[DefaultRepositoryCacheManager]
} cache.setUseOrigin(false)
f(cache)
} }
}
private def unknownOrigin(artifact: IvyArtifact) = ArtifactOrigin.unkwnown(artifact) 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.*/ /** 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) = private def basicLocalIvy(lock: Option[xsbti.GlobalLock], log: Logger) = {
{ val local = Resolver.defaultLocal
val local = Resolver.defaultLocal val paths = IvyPaths(new File("."), ivyHome)
val paths = IvyPaths(new File("."), ivyHome) val conf = new InlineIvyConfiguration(
val conf = new InlineIvyConfiguration(paths, Vector(local), Vector.empty, Vector.empty, false, lock, IvySbt.DefaultChecksums, None, UpdateOptions(), log) paths,
(new IvySbt(conf), local) 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.*/ /** Creates a default jar artifact based on the given ID.*/
private def defaultArtifact(moduleID: ModuleID): IvyArtifact = private def defaultArtifact(moduleID: ModuleID): IvyArtifact =
new DefaultArtifact(IvySbt.toID(moduleID), null, moduleID.name, "jar", "jar") new DefaultArtifact(IvySbt.toID(moduleID), null, moduleID.name, "jar", "jar")
} }
/** Required by Ivy for copying to the cache.*/ /** Required by Ivy for copying to the cache.*/
private class FileDownloader extends ResourceDownloader { private class FileDownloader extends ResourceDownloader {
def download(artifact: IvyArtifact, resource: Resource, dest: File): Unit = { def download(artifact: IvyArtifact, resource: Resource, dest: File): Unit = {

View File

@ -6,11 +6,15 @@ package sbt.internal.librarymanagement
import sbt.librarymanagement._ import sbt.librarymanagement._
abstract class InlineConfigurationFunctions { abstract class InlineConfigurationFunctions {
def configurations(explicitConfigurations: Iterable[Configuration], defaultConfiguration: Option[Configuration]) = def configurations(
explicitConfigurations: Iterable[Configuration],
defaultConfiguration: Option[Configuration]
) =
if (explicitConfigurations.isEmpty) { if (explicitConfigurations.isEmpty) {
defaultConfiguration match { defaultConfiguration match {
case Some(Configurations.DefaultIvyConfiguration) => Configurations.Default :: Nil case Some(Configurations.DefaultIvyConfiguration) => Configurations.Default :: Nil
case Some(Configurations.DefaultMavenConfiguration) => Configurations.defaultMavenConfigurations case Some(Configurations.DefaultMavenConfiguration) =>
Configurations.defaultMavenConfigurations
case _ => Nil case _ => Nil
} }
} else } else

View File

@ -44,6 +44,7 @@ private final class IvyLoggerInterface(logger: Logger) extends MessageLogger {
def setShowProgress(progress: Boolean): Unit = () def setShowProgress(progress: Boolean): Unit = ()
} }
private final class SbtMessageLoggerEngine extends MessageLoggerEngine { private final class SbtMessageLoggerEngine extends MessageLoggerEngine {
/** This is a hack to filter error messages about 'unknown resolver ...'. */ /** 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 error(msg: String): Unit = if (SbtIvyLogger.acceptError(msg)) super.error(msg)
override def sumupProblems(): Unit = clearProblems() override def sumupProblems(): Unit = clearProblems()

View File

@ -21,39 +21,48 @@ object IvyRetrieve {
def moduleReports(confReport: ConfigurationResolveReport): Vector[ModuleReport] = def moduleReports(confReport: ConfigurationResolveReport): Vector[ModuleReport] =
for { 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)) } yield moduleRevisionDetail(confReport, confReport.getDependency(revId))
@deprecated("Internal only. No longer in use.", "0.13.6") @deprecated("Internal only. No longer in use.", "0.13.6")
def artifactReports(mid: ModuleID, artReport: Seq[ArtifactDownloadReport]): ModuleReport = def artifactReports(mid: ModuleID, artReport: Seq[ArtifactDownloadReport]): ModuleReport = {
{ val (resolved, missing) = artifacts(mid, artReport)
val (resolved, missing) = artifacts(mid, artReport) ModuleReport(mid, resolved, missing)
ModuleReport(mid, resolved, missing) }
}
private[sbt] def artifacts(mid: ModuleID, artReport: Seq[ArtifactDownloadReport]): (Vector[(Artifact, File)], Vector[Artifact]) = private[sbt] def artifacts(
{ mid: ModuleID,
val missing = new mutable.ListBuffer[Artifact] artReport: Seq[ArtifactDownloadReport]
val resolved = new mutable.ListBuffer[(Artifact, File)] ): (Vector[(Artifact, File)], Vector[Artifact]) = {
for (r <- artReport) { val missing = new mutable.ListBuffer[Artifact]
val fileOpt = Option(r.getLocalFile) val resolved = new mutable.ListBuffer[(Artifact, File)]
val art = toArtifact(r.getArtifact) for (r <- artReport) {
fileOpt match { val fileOpt = Option(r.getLocalFile)
case Some(file) => resolved += ((art, file)) val art = toArtifact(r.getArtifact)
case None => missing += art 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 // We need this because current module report used as part of UpdateReport/ConfigurationReport contains
// only the revolved modules. // only the revolved modules.
// Sometimes the entire module can be excluded via rules etc. // Sometimes the entire module can be excluded via rules etc.
private[sbt] def organizationArtifactReports(confReport: ConfigurationResolveReport): Vector[OrganizationArtifactReport] = { private[sbt] def organizationArtifactReports(
val moduleIds = confReport.getModuleIds.toArray.toVector collect { case mId: IvyModuleId => mId } confReport: ConfigurationResolveReport
): Vector[OrganizationArtifactReport] = {
val moduleIds = confReport.getModuleIds.toArray.toVector collect {
case mId: IvyModuleId => mId
}
def organizationArtifact(mid: IvyModuleId): OrganizationArtifactReport = { def organizationArtifact(mid: IvyModuleId): OrganizationArtifactReport = {
val deps = confReport.getNodes(mid).toArray.toVector collect { case node: IvyNode => node } 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 } moduleIds map { organizationArtifact }
} }
@ -65,10 +74,16 @@ object IvyRetrieve {
case x => Some(x.trim) 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] = def toExtraAttributes(ea: ju.Map[_, _]): Map[String, String] =
Map(ea.entrySet.toArray collect { 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) (entry.getKey.toString, entry.getValue.toString)
}: _*) }: _*)
def toCaller(caller: IvyCaller): Caller = { def toCaller(caller: IvyCaller): Caller = {
@ -80,11 +95,32 @@ object IvyRetrieve {
val (extraAttributes, isForce, isChanging, isTransitive, isDirectlyForce) = ddOpt match { val (extraAttributes, isForce, isChanging, isTransitive, isDirectlyForce) = ddOpt match {
case Some(dd: SbtDefaultDependencyDescriptor) => case Some(dd: SbtDefaultDependencyDescriptor) =>
val mod = dd.dependencyModuleId 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) toExtraAttributes(dd.getExtraAttributes),
case None => (Map.empty[String, String], false, false, true, false) 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 revId = dep.getResolvedId
val moduleId = toModuleID(revId) val moduleId = toModuleID(revId)
@ -106,9 +142,9 @@ object IvyRetrieve {
val edOpt = Option(dep.getEvictedData(confReport.getConfiguration)) val edOpt = Option(dep.getEvictedData(confReport.getConfiguration))
edOpt match { edOpt match {
case Some(ed) => case Some(ed) =>
(true, (true, nonEmptyString(Option(ed.getConflictManager) map { _.toString } getOrElse {
nonEmptyString(Option(ed.getConflictManager) map { _.toString } getOrElse { "transitive" }), "transitive"
nonEmptyString(ed.getDetail)) }), nonEmptyString(ed.getDetail))
case None => (true, None, None) case None => (true, None, None)
} }
case _ => (false, None, None) case _ => (false, None, None)
@ -133,40 +169,74 @@ object IvyRetrieve {
val isDefault = Option(dep.getDescriptor) map { _.isDefault } val isDefault = Option(dep.getDescriptor) map { _.isDefault }
val configurations = dep.getConfigurations(confReport.getConfiguration).toVector val configurations = dep.getConfigurations(confReport.getConfiguration).toVector
val licenses: Vector[(String, Option[String])] = mdOpt match { val licenses: Vector[(String, Option[String])] = mdOpt match {
case Some(md) => md.getLicenses.toVector collect { case Some(md) =>
case lic: IvyLicense if Option(lic.getName).isDefined => md.getLicenses.toVector collect {
val temporaryURL = "http://localhost" case lic: IvyLicense if Option(lic.getName).isDefined =>
(lic.getName, nonEmptyString(lic.getUrl) orElse { Some(temporaryURL) }) val temporaryURL = "http://localhost"
} (lic.getName, nonEmptyString(lic.getUrl) orElse { Some(temporaryURL) })
}
case _ => Vector.empty case _ => Vector.empty
} }
val callers = dep.getCallers(confReport.getConfiguration).toVector map { toCaller } val callers = dep.getCallers(confReport.getConfiguration).toVector map { toCaller }
val (resolved, missing) = artifacts(moduleId, confReport getDownloadReports revId) val (resolved, missing) = artifacts(moduleId, confReport getDownloadReports revId)
ModuleReport(moduleId, resolved, missing, status, publicationDate, resolver, artifactResolver, ModuleReport(
evicted, evictedData, evictedReason, problem, homepage, extraAttributes, isDefault, branch, moduleId,
configurations, licenses, callers) resolved,
missing,
status,
publicationDate,
resolver,
artifactResolver,
evicted,
evictedData,
evictedReason,
problem,
homepage,
extraAttributes,
isDefault,
branch,
configurations,
licenses,
callers
)
} }
def evicted(confReport: ConfigurationResolveReport): Seq[ModuleID] = def evicted(confReport: ConfigurationResolveReport): Seq[ModuleID] =
confReport.getEvictedNodes.map(node => toModuleID(node.getId)) confReport.getEvictedNodes.map(node => toModuleID(node.getId))
def toModuleID(revID: ModuleRevisionId): ModuleID = 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)) .branch(nonEmptyString(revID.getBranch))
def toArtifact(art: IvyArtifact): Artifact = def toArtifact(art: IvyArtifact): Artifact = {
{ import art._
import art._ Artifact(
Artifact(getName, getType, getExt, Option(getExtraAttribute("classifier")), getConfigurations.toVector map Configurations.config, Option(getUrl)) getName,
} getType,
getExt,
Option(getExtraAttribute("classifier")),
getConfigurations.toVector map Configurations.config,
Option(getUrl)
)
}
def updateReport(report: ResolveReport, cachedDescriptor: File): UpdateReport = 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 = def updateStats(report: ResolveReport): UpdateStats =
UpdateStats(report.getResolveTime, report.getDownloadTime, report.getDownloadSize, false) UpdateStats(report.getResolveTime, report.getDownloadTime, report.getDownloadSize, false)
def configurationReport(confReport: ConfigurationResolveReport): ConfigurationReport = 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. * Tries to find Ivy graph path the from node to target.

View File

@ -11,36 +11,59 @@ private[sbt] object JsonUtil {
def sbtOrgTemp = "org.scala-sbt.temp" def sbtOrgTemp = "org.scala-sbt.temp"
def fakeCallerOrganization = "org.scala-sbt.temp-callers" def fakeCallerOrganization = "org.scala-sbt.temp-callers"
def parseUpdateReport(md: ModuleDescriptor, path: File, cachedDescriptor: File, log: Logger): UpdateReport = def parseUpdateReport(
{ md: ModuleDescriptor,
try { path: File,
val lite = CacheStore(path).read[UpdateReportLite] cachedDescriptor: File,
fromLite(lite, cachedDescriptor) log: Logger
} catch { ): UpdateReport = {
case e: Throwable => try {
log.error("Unable to parse mini graph: " + path.toString) val lite = CacheStore(path).read[UpdateReportLite]
throw e fromLite(lite, cachedDescriptor)
} } catch {
} case e: Throwable =>
def writeUpdateReport(ur: UpdateReport, graphPath: File): Unit = log.error("Unable to parse mini graph: " + path.toString)
{ throw e
sbt.io.IO.createDirectory(graphPath.getParentFile)
CacheStore(graphPath).write(toLite(ur))
} }
}
def writeUpdateReport(ur: UpdateReport, graphPath: File): Unit = {
sbt.io.IO.createDirectory(graphPath.getParentFile)
CacheStore(graphPath).write(toLite(ur))
}
def toLite(ur: UpdateReport): UpdateReportLite = def toLite(ur: UpdateReport): UpdateReportLite =
UpdateReportLite(ur.configurations map { cr => UpdateReportLite(ur.configurations map { cr =>
ConfigurationReportLite(cr.configuration, cr.details map { oar => ConfigurationReportLite(
OrganizationArtifactReport(oar.organization, oar.name, oar.modules map { mr => cr.configuration,
ModuleReport( cr.details map {
mr.module, mr.artifacts, mr.missingArtifacts, mr.status, oar =>
mr.publicationDate, mr.resolver, mr.artifactResolver, OrganizationArtifactReport(
mr.evicted, mr.evictedData, mr.evictedReason, oar.organization,
mr.problem, mr.homepage, mr.extraAttributes, oar.name,
mr.isDefault, mr.branch, mr.configurations, mr.licenses, oar.modules map { mr =>
filterOutArtificialCallers(mr.callers) 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, // #1763/#2030. Caller takes up 97% of space, so we need to shrink it down,
// but there are semantics associated with some of them. // but there are semantics associated with some of them.
@ -49,7 +72,7 @@ private[sbt] object JsonUtil {
else { else {
val nonArtificial = callers filter { c => val nonArtificial = callers filter { c =>
(c.caller.organization != sbtOrgTemp) && (c.caller.organization != sbtOrgTemp) &&
(c.caller.organization != fakeCallerOrganization) (c.caller.organization != fakeCallerOrganization)
} }
val interProj = (callers find { c => val interProj = (callers find { c =>
c.caller.organization == sbtOrgTemp c.caller.organization == sbtOrgTemp
@ -57,18 +80,17 @@ private[sbt] object JsonUtil {
interProj ++ nonArtificial interProj ++ nonArtificial
} }
def fromLite(lite: UpdateReportLite, cachedDescriptor: File): UpdateReport = def fromLite(lite: UpdateReportLite, cachedDescriptor: File): UpdateReport = {
{ val stats = UpdateStats(0L, 0L, 0L, false)
val stats = UpdateStats(0L, 0L, 0L, false) val configReports = lite.configurations map { cr =>
val configReports = lite.configurations map { cr => val details = cr.details
val details = cr.details val modules = details flatMap {
val modules = details flatMap { _.modules filter { mr =>
_.modules filter { mr => !mr.evicted && mr.problem.isEmpty
!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)
}
} }

View File

@ -19,35 +19,121 @@ import Configurations.Optional
import org.apache.ivy.Ivy import org.apache.ivy.Ivy
import org.apache.ivy.core.settings.IvySettings 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 org.apache.ivy.plugins.resolver.{ ChainResolver, DependencyResolver, IBiblioResolver }
import ivyint.CustomRemoteMavenResolver import ivyint.CustomRemoteMavenResolver
import sbt.io.IO import sbt.io.IO
object MakePom { object MakePom {
/** True if the revision is an ivy-range, not a complete revision. */ /** True if the revision is an ivy-range, not a complete revision. */
def isDependencyVersionRange(revision: String): Boolean = VersionRange.isVersionRange(revision) def isDependencyVersionRange(revision: String): Boolean = VersionRange.isVersionRange(revision)
/** Converts Ivy revision ranges to that of Maven POM */ /** 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) { class MakePom(val log: Logger) {
import MakePom._ import MakePom._
@deprecated("Use `write(Ivy, ModuleDescriptor, ModuleInfo, Option[Iterable[Configuration]], Set[String], NodeSeq, XNode => XNode, MavenRepository => Boolean, Boolean, File)` instead", "0.11.2") @deprecated(
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 = "Use `write(Ivy, ModuleDescriptor, ModuleInfo, Option[Iterable[Configuration]], Set[String], NodeSeq, XNode => XNode, MavenRepository => Boolean, Boolean, File)` instead",
write(ivy, module, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], Set(Artifact.DefaultType), extra, process, filterRepositories, allRepositories, output) "0.11.2"
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) 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 // 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(node: XNode, output: File): Unit = write(toString(node), output, "\n")
def write(xmlString: String, output: File, newline: String): Unit = def write(xmlString: String, output: File, newline: String): Unit =
IO.write(output, "<?xml version='1.0' encoding='" + IO.utf8.name + "'?>" + newline + xmlString) IO.write(output, "<?xml version='1.0' encoding='" + IO.utf8.name + "'?>" + newline + xmlString)
def toString(node: XNode): String = new PrettyPrinter(1000, 4).format(node) 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") @deprecated(
def toPom(ivy: Ivy, module: ModuleDescriptor, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], extra: NodeSeq, filterRepositories: MavenRepository => Boolean, allRepositories: Boolean): XNode = "Use `toPom(Ivy, ModuleDescriptor, ModuleInfo, Option[Iterable[Configuration]], Set[String], NodeSeq, MavenRepository => Boolean, Boolean)` instead",
toPom(ivy, module, moduleInfo, configurations, Set(Artifact.DefaultType), extra, filterRepositories, allRepositories) "0.11.2"
def toPom(ivy: Ivy, module: ModuleDescriptor, moduleInfo: ModuleInfo, configurations: Option[Iterable[Configuration]], includeTypes: Set[String], extra: NodeSeq, filterRepositories: MavenRepository => Boolean, allRepositories: Boolean): XNode = )
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"> (<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> <modelVersion>4.0.0</modelVersion>
{ makeModuleID(module) } { makeModuleID(module) }
@ -65,81 +151,80 @@ class MakePom(val log: Logger) {
{ makeRepositories(ivy.getSettings, allRepositories, filterRepositories) } { makeRepositories(ivy.getSettings, allRepositories, filterRepositories) }
</project>) </project>)
def makeModuleID(module: ModuleDescriptor): NodeSeq = def makeModuleID(module: ModuleDescriptor): NodeSeq = {
{ val mrid = moduleDescriptor(module)
val mrid = moduleDescriptor(module) val a: NodeSeq =
val a: NodeSeq = (<groupId>{ mrid.getOrganisation }</groupId>
(<groupId>{ mrid.getOrganisation }</groupId> <artifactId>{ mrid.getName }</artifactId>
<artifactId>{ mrid.getName }</artifactId> <packaging>{ packaging(module) }</packaging>)
<packaging>{ packaging(module) }</packaging>) val b: NodeSeq =
val b: NodeSeq = ((description(module.getDescription) ++
((description(module.getDescription) ++ homePage(module.getHomePage) ++
homePage(module.getHomePage) ++ revision(mrid.getRevision) ++
revision(mrid.getRevision) ++ licenses(module.getLicenses)): NodeSeq)
licenses(module.getLicenses)): NodeSeq) a ++ b
a ++ b }
}
def makeStartYear(moduleInfo: ModuleInfo): NodeSeq = def makeStartYear(moduleInfo: ModuleInfo): NodeSeq =
moduleInfo.startYear match { moduleInfo.startYear match {
case Some(y) => <inceptionYear>{ y }</inceptionYear> case Some(y) => <inceptionYear>{ y }</inceptionYear>
case _ => NodeSeq.Empty case _ => NodeSeq.Empty
} }
def makeOrganization(moduleInfo: ModuleInfo): NodeSeq = def makeOrganization(moduleInfo: ModuleInfo): NodeSeq = {
{ <organization>
<organization> <name>{ moduleInfo.organizationName }</name>
<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 { moduleInfo.developers.map { developer: Developer =>
case Some(h)=> <url>{ h }</url> <developer>
case _ => NodeSeq.Empty <id>{ developer.id }</id>
<name>{ developer.name }</name>
<email>{ developer.email }</email>
<url>{ developer.url }</url>
</developer>
} }
} }
</organization> </developers>
} } else NodeSeq.Empty
def makeScmInfo(moduleInfo: ModuleInfo): NodeSeq = }
{ def makeProperties(module: ModuleDescriptor, dependencies: Seq[DependencyDescriptor]): NodeSeq = {
moduleInfo.scmInfo match { val extra = IvySbt.getExtraAttributes(module)
case Some(s) => val depExtra = PomExtraDependencyAttributes.writeDependencyExtra(dependencies).mkString("\n")
<scm> val allExtra =
<url>{ s.browseUrl }</url> if (depExtra.isEmpty) extra
<connection>{ s.connection }</connection> else extra.updated(PomExtraDependencyAttributes.ExtraAttributesKey, depExtra)
{ if (allExtra.isEmpty) NodeSeq.Empty else makeProperties(allExtra)
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)
}
def makeProperties(extra: Map[String, String]): NodeSeq = { 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> { <properties> {
for ((key, value) <- extra) yield (<x>{ value }</x>).copy(label = key, attributes = _extraAttributes(key)) for ((key, value) <- extra) yield (<x>{ value }</x>).copy(label = key, attributes = _extraAttributes(key))
} </properties> } </properties>
@ -152,8 +237,10 @@ class MakePom(val log: Logger) {
*/ */
def xmlSpacePreserve = new PrefixedAttribute("xml", "space", "preserve", scala.xml.Null) 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 description(d: String) =
def licenses(ls: Array[License]) = if (ls == null || ls.isEmpty) NodeSeq.Empty else <licenses>{ ls.map(license) }</licenses> 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) = def license(l: License) =
<license> <license>
<name>{ l.getName }</name> <name>{ l.getName }</name>
@ -161,7 +248,8 @@ class MakePom(val log: Logger) {
<distribution>repo</distribution> <distribution>repo</distribution>
</license> </license>
def homePage(homePage: String) = if (homePage eq null) NodeSeq.Empty else <url>{ homePage }</url> 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) = def packaging(module: ModuleDescriptor) =
module.getAllArtifacts match { module.getAllArtifacts match {
case Array() => "pom" case Array() => "pom"
@ -177,10 +265,17 @@ class MakePom(val log: Logger) {
val IgnoreTypes: Set[String] = Set(Artifact.SourceType, Artifact.DocType, Artifact.PomType) val IgnoreTypes: Set[String] = Set(Artifact.SourceType, Artifact.DocType, Artifact.PomType)
@deprecated("Use `makeDependencies` variant which takes excludes", "0.13.9") @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) 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) if (dependencies.isEmpty)
NodeSeq.Empty NodeSeq.Empty
else else
@ -192,74 +287,96 @@ class MakePom(val log: Logger) {
def makeDependency(dependency: DependencyDescriptor, includeTypes: Set[String]): NodeSeq = def makeDependency(dependency: DependencyDescriptor, includeTypes: Set[String]): NodeSeq =
makeDependency(dependency, includeTypes, Nil) makeDependency(dependency, includeTypes, Nil)
def makeDependency(dependency: DependencyDescriptor, includeTypes: Set[String], excludes: Seq[ExcludeRule]): NodeSeq = def makeDependency(
{ dependency: DependencyDescriptor,
val artifacts = dependency.getAllDependencyArtifacts includeTypes: Set[String],
val includeArtifacts = artifacts.filter(d => includeTypes(d.getType)) excludes: Seq[ExcludeRule]
if (artifacts.isEmpty) { ): NodeSeq = {
val configs = dependency.getModuleConfigurations val artifacts = dependency.getAllDependencyArtifacts
if (configs.filterNot(Set("sources", "docs")).nonEmpty) { val includeArtifacts = artifacts.filter(d => includeTypes(d.getType))
val (scope, optional) = getScopeAndOptional(dependency.getModuleConfigurations) if (artifacts.isEmpty) {
makeDependencyElem(dependency, scope, optional, None, None, excludes) val configs = dependency.getModuleConfigurations
} else NodeSeq.Empty if (configs.filterNot(Set("sources", "docs")).nonEmpty) {
} else if (includeArtifacts.isEmpty) val (scope, optional) = getScopeAndOptional(dependency.getModuleConfigurations)
NodeSeq.Empty makeDependencyElem(dependency, scope, optional, None, None, excludes)
else } else NodeSeq.Empty
NodeSeq.fromSeq(artifacts.flatMap(a => makeDependencyElem(dependency, a, excludes))) } 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") @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) makeDependencyElem(dependency, artifact, Nil)
def makeDependencyElem(dependency: DependencyDescriptor, artifact: DependencyArtifactDescriptor, excludes: Seq[ExcludeRule]): Option[Elem] = def makeDependencyElem(
{ dependency: DependencyDescriptor,
val configs = artifact.getConfigurations.toList match { artifact: DependencyArtifactDescriptor,
case Nil | "*" :: Nil => dependency.getModuleConfigurations excludes: Seq[ExcludeRule]
case x => x.toArray ): Option[Elem] = {
} val configs = artifact.getConfigurations.toList match {
if (!configs.forall(Set("sources", "docs"))) { case Nil | "*" :: Nil => dependency.getModuleConfigurations
val (scope, optional) = getScopeAndOptional(configs) case x => x.toArray
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
} }
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") @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) 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 = def makeDependencyElem(
{ dependency: DependencyDescriptor,
val mrid = dependency.getDependencyRevisionId scope: Option[String],
<dependency> optional: Boolean,
<groupId>{ mrid.getOrganisation }</groupId> classifier: Option[String],
<artifactId>{ mrid.getName }</artifactId> tpe: Option[String],
<version>{ makeDependencyVersion(mrid.getRevision) }</version> excludes: Seq[ExcludeRule]
{ scopeElem(scope) } ): Elem = {
{ optionalElem(optional) } val mrid = dependency.getDependencyRevisionId
{ classifierElem(classifier) } <dependency>
{ typeElem(tpe) } <groupId>{ mrid.getOrganisation }</groupId>
{ exclusions(dependency, excludes) } <artifactId>{ mrid.getName }</artifactId>
</dependency> <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") @deprecated("No longer used and will be removed.", "0.12.1")
def classifier(dependency: DependencyDescriptor, includeTypes: Set[String]): NodeSeq = def classifier(dependency: DependencyDescriptor, includeTypes: Set[String]): NodeSeq = {
{ val jarDep = dependency.getAllDependencyArtifacts.find(d => includeTypes(d.getType))
val jarDep = dependency.getAllDependencyArtifacts.find(d => includeTypes(d.getType)) jarDep match {
jarDep match { case Some(a) => classifierElem(artifactClassifier(a))
case Some(a) => classifierElem(artifactClassifier(a)) case None => NodeSeq.Empty
case None => NodeSeq.Empty
}
} }
}
def artifactType(artifact: DependencyArtifactDescriptor): Option[String] = 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 = def typeElem(tpe: Option[String]): NodeSeq =
tpe match { tpe match {
case Some(t) => <type>{ t }</type> 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") @deprecated("No longer used and will be removed.", "0.12.1")
def scopeAndOptional(dependency: DependencyDescriptor): NodeSeq = def scopeAndOptional(dependency: DependencyDescriptor): NodeSeq = {
{ val (scope, opt) = getScopeAndOptional(dependency.getModuleConfigurations)
val (scope, opt) = getScopeAndOptional(dependency.getModuleConfigurations) scopeElem(scope) ++ optionalElem(opt)
scopeElem(scope) ++ optionalElem(opt) }
}
def scopeElem(scope: Option[String]): NodeSeq = scope match { def scopeElem(scope: Option[String]): NodeSeq = scope match {
case None | Some(Configurations.Compile.name) => NodeSeq.Empty case None | Some(Configurations.Compile.name) => NodeSeq.Empty
case Some(s) => <scope>{ s }</scope> 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 optionalElem(opt: Boolean) = if (opt) <optional>true</optional> else NodeSeq.Empty
def moduleDescriptor(module: ModuleDescriptor) = module.getModuleRevisionId def moduleDescriptor(module: ModuleDescriptor) = module.getModuleRevisionId
def getScopeAndOptional(confs: Array[String]): (Option[String], Boolean) = def getScopeAndOptional(confs: Array[String]): (Option[String], Boolean) = {
{ val (opt, notOptional) = confs.partition(_ == Optional.name)
val (opt, notOptional) = confs.partition(_ == Optional.name) val defaultNotOptional =
val defaultNotOptional = Configurations.defaultMavenConfigurations.find(notOptional contains _.name) Configurations.defaultMavenConfigurations.find(notOptional contains _.name)
val scope = defaultNotOptional.map(_.name) val scope = defaultNotOptional.map(_.name)
(scope, opt.nonEmpty) (scope, opt.nonEmpty)
} }
@deprecated("Use `exclusions` variant which takes excludes", "0.13.9") @deprecated("Use `exclusions` variant which takes excludes", "0.13.9")
def exclusions(dependency: DependencyDescriptor): NodeSeq = exclusions(dependency, Nil) def exclusions(dependency: DependencyDescriptor): NodeSeq = exclusions(dependency, Nil)
def exclusions(dependency: DependencyDescriptor, excludes: Seq[ExcludeRule]): NodeSeq = def exclusions(dependency: DependencyDescriptor, excludes: Seq[ExcludeRule]): NodeSeq = {
{ val excl = dependency.getExcludeRules(dependency.getModuleConfigurations) ++ excludes
val excl = dependency.getExcludeRules(dependency.getModuleConfigurations) ++ excludes val (warns, excls) = IvyUtil.separate(excl.map(makeExclusion))
val (warns, excls) = IvyUtil.separate(excl.map(makeExclusion)) if (warns.nonEmpty) log.warn(warns.mkString(IO.Newline))
if (warns.nonEmpty) log.warn(warns.mkString(IO.Newline)) if (excls.nonEmpty) <exclusions>{ excls }</exclusions>
if (excls.nonEmpty) <exclusions>{ excls }</exclusions> else NodeSeq.Empty
else NodeSeq.Empty }
} def makeExclusion(exclRule: ExcludeRule): Either[String, NodeSeq] = {
def makeExclusion(exclRule: ExcludeRule): Either[String, NodeSeq] = val m = exclRule.getId.getModuleId
{ val (g, a) = (m.getOrganisation, m.getName)
val m = exclRule.getId.getModuleId if (g == null || g.isEmpty || g == "*" || a.isEmpty || a == "*")
val (g, a) = (m.getOrganisation, m.getName) Left(
if (g == null || g.isEmpty || g == "*" || a.isEmpty || a == "*") "Skipped generating '<exclusion/>' for %s. Dependency exclusion should have both 'org' and 'module' to comply with Maven POM's schema."
Left("Skipped generating '<exclusion/>' for %s. Dependency exclusion should have both 'org' and 'module' to comply with Maven POM's schema.".format(m)) .format(m)
else )
Right( else
<exclusion> Right(
<groupId>{ g }</groupId> <exclusion>
<artifactId>{ a }</artifactId> <groupId>{ g }</groupId>
</exclusion> <artifactId>{ a }</artifactId>
) </exclusion>
} )
}
def makeRepositories(settings: IvySettings, includeAll: Boolean, filterRepositories: MavenRepository => Boolean) = def makeRepositories(
{ settings: IvySettings,
val repositories = if (includeAll) allResolvers(settings) else resolvers(settings.getDefaultResolver) includeAll: Boolean,
val mavenRepositories = filterRepositories: MavenRepository => Boolean
repositories.flatMap { ) = {
// TODO - Would it be ok if bintray were in the pom? We should avoid it for now. val repositories =
case m: CustomRemoteMavenResolver if m.repo.root == JCenterRepository.root => Nil if (includeAll) allResolvers(settings) else resolvers(settings.getDefaultResolver)
case m: IBiblioResolver if m.isM2compatible && m.getRoot == JCenterRepository.root => Nil val mavenRepositories =
case m: CustomRemoteMavenResolver if m.repo.root != DefaultMavenRepository.root => repositories.flatMap {
MavenRepository(m.repo.name, m.repo.root) :: Nil // TODO - Would it be ok if bintray were in the pom? We should avoid it for now.
case m: IBiblioResolver if m.isM2compatible && m.getRoot != DefaultMavenRepository.root => case m: CustomRemoteMavenResolver if m.repo.root == JCenterRepository.root => Nil
MavenRepository(m.getName, m.getRoot) :: Nil case m: IBiblioResolver if m.isM2compatible && m.getRoot == JCenterRepository.root => Nil
case _ => Nil case m: CustomRemoteMavenResolver if m.repo.root != DefaultMavenRepository.root =>
} MavenRepository(m.repo.name, m.repo.root) :: Nil
val repositoryElements = mavenRepositories.filter(filterRepositories).map(mavenRepository) case m: IBiblioResolver if m.isM2compatible && m.getRoot != DefaultMavenRepository.root =>
if (repositoryElements.isEmpty) repositoryElements else <repositories>{ repositoryElements }</repositories> MavenRepository(m.getName, m.getRoot) :: Nil
} case _ => Nil
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) 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] = def resolvers(r: DependencyResolver): Seq[DependencyResolver] =
r match { case c: ChainResolver => flatten(castResolvers(c.getResolvers)); case _ => r :: Nil } 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 toID(name: String) = checkID(name.filter(isValidIDCharacter).mkString, name)
def isValidIDCharacter(c: Char) = c.isLetterOrDigit 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 = def mavenRepository(repo: MavenRepository): XNode =
mavenRepository(toID(repo.name), repo.name, repo.root) mavenRepository(toID(repo.name), repo.name, repo.root)
def mavenRepository(id: String, name: String, root: String): XNode = 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. * 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 * This currently only preserves the information required by makePom
*/ */
private def depsInConfs(module: ModuleDescriptor, configurations: Option[Iterable[Configuration]]): Seq[DependencyDescriptor] = private def depsInConfs(
{ module: ModuleDescriptor,
val keepConfigurations = IvySbt.getConfigurations(module, configurations) configurations: Option[Iterable[Configuration]]
val keepSet = Set(keepConfigurations.toSeq: _*) ): Seq[DependencyDescriptor] = {
def translate(dependency: DependencyDescriptor) = val keepConfigurations = IvySbt.getConfigurations(module, configurations)
{ val keepSet = Set(keepConfigurations.toSeq: _*)
val keep = dependency.getModuleConfigurations.filter(keepSet.contains) def translate(dependency: DependencyDescriptor) = {
if (keep.isEmpty) val keep = dependency.getModuleConfigurations.filter(keepSet.contains)
None if (keep.isEmpty)
else // TODO: translate the dependency to contain only configurations to keep None
Some(dependency) else // TODO: translate the dependency to contain only configurations to keep
} Some(dependency)
module.getDependencies flatMap translate
} }
module.getDependencies flatMap translate
}
} }

View File

@ -10,17 +10,28 @@ import org.apache.ivy.core.{ cache, module, report, resolve, search }
import cache.ArtifactOrigin import cache.ArtifactOrigin
import search.{ ModuleEntry, OrganisationEntry, RevisionEntry } import search.{ ModuleEntry, OrganisationEntry, RevisionEntry }
import module.id.ModuleRevisionId 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.namespace.Namespace
import org.apache.ivy.plugins.resolver.ResolverSettings import org.apache.ivy.plugins.resolver.ResolverSettings
import report.{ ArtifactDownloadReport, DownloadReport, DownloadStatus, MetadataArtifactDownloadReport } import report.{
ArtifactDownloadReport,
DownloadReport,
DownloadStatus,
MetadataArtifactDownloadReport
}
import resolve.{ DownloadOptions, ResolveData, ResolvedModuleRevision } import resolve.{ DownloadOptions, ResolveData, ResolvedModuleRevision }
/** /**
* A Resolver that uses a predefined mapping from module ids to in-memory descriptors. * A Resolver that uses a predefined mapping from module ids to in-memory descriptors.
* It does not handle artifacts. * 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 getName = name
def setName(name: String) = sys.error("Setting name not supported by ProjectResolver") def setName(name: String) = sys.error("Setting name not supported by ProjectResolver")
override def toString = "ProjectResolver(" + name + ", mapped: " + map.keys.mkString(", ") + ")" 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 = def getDependency(dd: DependencyDescriptor, data: ResolveData): ResolvedModuleRevision =
getDependency(dd.getDependencyRevisionId).orNull getDependency(dd.getDependencyRevisionId).orNull
private[this] def getDependency(revisionId: ModuleRevisionId): Option[ResolvedModuleRevision] = private[this] def getDependency(revisionId: ModuleRevisionId): Option[ResolvedModuleRevision] = {
{ def constructResult(descriptor: ModuleDescriptor) =
def constructResult(descriptor: ModuleDescriptor) = new ResolvedModuleRevision(this, this, descriptor, report(revisionId), true) new ResolvedModuleRevision(this, this, descriptor, report(revisionId), true)
map get revisionId map constructResult 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 = def report(revisionId: ModuleRevisionId): MetadataArtifactDownloadReport = {
{ val artifact = DefaultArtifact.newIvyArtifact(revisionId, new Date)
val artifact = DefaultArtifact.newIvyArtifact(revisionId, new Date) val r = new MetadataArtifactDownloadReport(artifact)
val r = new MetadataArtifactDownloadReport(artifact) r.setSearched(false)
r.setSearched(false) r.setDownloadStatus(DownloadStatus.FAILED)
r.setDownloadStatus(DownloadStatus.FAILED) r
r }
}
// this resolver nevers locates artifacts, only resolves dependencies // this resolver nevers locates artifacts, only resolves dependencies
def exists(artifact: IArtifact) = false def exists(artifact: IArtifact) = false
def locate(artifact: IArtifact) = null def locate(artifact: IArtifact) = null
def download(artifacts: Array[IArtifact], options: DownloadOptions): DownloadReport = def download(artifacts: Array[IArtifact], options: DownloadOptions): DownloadReport = {
{ val r = new DownloadReport
val r = new DownloadReport for (artifact <- artifacts)
for (artifact <- artifacts) if (getDependency(artifact.getModuleRevisionId).isEmpty)
if (getDependency(artifact.getModuleRevisionId).isEmpty) r.addArtifactReport(notDownloaded(artifact))
r.addArtifactReport(notDownloaded(artifact)) r
r }
}
def download(artifact: ArtifactOrigin, options: DownloadOptions): ArtifactDownloadReport = def download(artifact: ArtifactOrigin, options: DownloadOptions): ArtifactDownloadReport =
notDownloaded(artifact.getArtifact) notDownloaded(artifact.getArtifact)
def findIvyFileRef(dd: DependencyDescriptor, data: ResolveData) = null def findIvyFileRef(dd: DependencyDescriptor, data: ResolveData) = null
def notDownloaded(artifact: IArtifact): ArtifactDownloadReport = def notDownloaded(artifact: IArtifact): ArtifactDownloadReport = {
{ val r = new ArtifactDownloadReport(artifact)
val r = new ArtifactDownloadReport(artifact) r.setDownloadStatus(DownloadStatus.FAILED)
r.setDownloadStatus(DownloadStatus.FAILED) r
r }
}
// doesn't support publishing // 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 beginPublishTransaction(module: ModuleRevisionId, overwrite: Boolean): Unit = ()
def abortPublishTransaction(): Unit = () def abortPublishTransaction(): Unit = ()
def commitPublishTransaction(): Unit = () def commitPublishTransaction(): Unit = ()
@ -87,7 +97,10 @@ class ProjectResolver(name: String, map: Map[ModuleRevisionId, ModuleDescriptor]
def dumpSettings(): Unit = () def dumpSettings(): Unit = ()
def setSettings(settings: ResolverSettings): Unit = { this.settings = Some(settings) } 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 { object ProjectResolver {

View File

@ -12,16 +12,28 @@ import sbt.internal.util.complete.DefaultParsers._
private[sbt] object RepositoriesParser { private[sbt] object RepositoriesParser {
private case class AfterPattern(artifactPattern: Option[String], flags: Int) private case class AfterPattern(artifactPattern: Option[String], flags: Int)
final case class PredefinedRepository(override val id: xsbti.Predefined) extends xsbti.PredefinedRepository final case class PredefinedRepository(override val id: xsbti.Predefined)
final case class MavenRepository(override val id: String, override val url: URL) extends xsbti.MavenRepository extends xsbti.PredefinedRepository
final case class IvyRepository(override val id: String, override val url: URL, override val ivyPattern: String, final case class MavenRepository(override val id: String, override val url: URL)
override val artifactPattern: String, override val mavenCompatible: Boolean, override val skipConsistencyCheck: Boolean, extends xsbti.MavenRepository
override val descriptorOptional: Boolean, val bootOnly: Boolean) extends xsbti.IvyRepository 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 // Predefined repositories
def local: Parser[xsbti.Repository] = "local" ^^^ new PredefinedRepository(xsbti.Predefined.Local) def local: Parser[xsbti.Repository] =
def mavenLocal: Parser[xsbti.Repository] = "maven-local" ^^^ new PredefinedRepository(xsbti.Predefined.MavenLocal) "local" ^^^ new PredefinedRepository(xsbti.Predefined.Local)
def mavenCentral: Parser[xsbti.Repository] = "maven-central" ^^^ new PredefinedRepository(xsbti.Predefined.MavenCentral) 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 def predefinedResolver: Parser[xsbti.Repository] = local | mavenLocal | mavenCentral
// Options // Options
@ -54,7 +66,16 @@ private[sbt] object RepositoriesParser {
// scalac complains about the recursion depth if we pattern match over `ap` directly. // scalac complains about the recursion depth if we pattern match over `ap` directly.
ap match { ap match {
case Some(AfterPattern(artifactPattern, Flags(dOpt, sc, bo, mc))) => 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 => case None =>
new IvyRepository(name, uri.toURL, ivy, ivy, false, false, false, false) 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] = def apply(lines: Iterator[String]): Seq[xsbti.Repository] =
if (lines.isEmpty) Nil if (lines.isEmpty) Nil
else { 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 lines.flatMap(getResolver(_)(resolver)).toList
} }
def apply(str: String): Seq[xsbti.Repository] = apply(str.lines) def apply(str: String): Seq[xsbti.Repository] = apply(str.lines)

View File

@ -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). * 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. * 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 = { private[this] def resolvedFileInCache(m: ModuleRevisionId, name: String, ext: String): File = {
val p = ResolvedPattern 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) new File(base, f)
} }
private[this] val reportBase: File = new File(base, ReportDirectory) 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 { private[sbt] object ResolutionCache {
/** /**
* Removes cached files from the resolution cache for the module with ID `mrid` * Removes cached files from the resolution cache for the module with ID `mrid`
* and the resolveId (as set on `ResolveOptions`). * 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 = val files =
Option(manager.getResolvedIvyFileInCache(mrid)).toList ::: Option(manager.getResolvedIvyFileInCache(mrid)).toList :::
Option(manager.getResolvedIvyPropertiesInCache(mrid)).toList ::: Option(manager.getResolvedIvyPropertiesInCache(mrid)).toList :::

View File

@ -9,7 +9,8 @@ abstract class SbtExclusionRuleFunctions {
def apply(organization: String): SbtExclusionRule = apply(organization, "*") 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 stringToExclusionRule(organization: String): SbtExclusionRule = apply(organization)
implicit def groupArtifactIDToExclusionRule(gaid: GroupArtifactID): SbtExclusionRule = implicit def groupArtifactIDToExclusionRule(gaid: GroupArtifactID): SbtExclusionRule =

View File

@ -6,8 +6,12 @@ package sbt.internal.librarymanagement
import java.util.Locale import java.util.Locale
object StringUtilities { 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 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 def appendable(s: String) = if (s.isEmpty) "" else "_" + s
} }

View File

@ -3,13 +3,14 @@ package internal
package librarymanagement package librarymanagement
object VersionRange { object VersionRange {
/** True if the revision is an ivy-range, not a complete revision. */ /** True if the revision is an ivy-range, not a complete revision. */
def isVersionRange(revision: String): Boolean = { def isVersionRange(revision: String): Boolean = {
(revision endsWith "+") || (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 // Assuming Ivy is used to resolve conflict, this removes the version range
@ -50,13 +51,15 @@ object VersionRange {
val maxDigit = 5 val maxDigit = 5
try { try {
revision match { revision match {
case "+" => "[0,)" case "+" => "[0,)"
case DotPlusPattern(base) => plusRange(base) case DotPlusPattern(base) => plusRange(base)
// This is a heuristic. Maven just doesn't support Ivy's notions of 1+, so // 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. // we assume version ranges never go beyond 5 siginificant digits.
case NumPlusPattern(tail) => (0 until maxDigit).map(plusRange(tail, _)).mkString(",") case NumPlusPattern(tail) => (0 until maxDigit).map(plusRange(tail, _)).mkString(",")
case DotNumPlusPattern(base, tail) => (0 until maxDigit).map(plusRange(base + "." + tail, _)).mkString(",") case DotNumPlusPattern(base, tail) =>
case rev if rev endsWith "+" => sys.error(s"dynamic revision '$rev' cannot be translated to POM") (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)) => case rev if startSym(rev(0)) && stopSym(rev(rev.length - 1)) =>
val start = rev(0) val start = rev(0)
val stop = rev(rev.length - 1) val stop = rev(rev.length - 1)
@ -79,5 +82,6 @@ object VersionRange {
private[this] val startSym = Set(']', '[', '(') private[this] val startSym = Set(']', '[', '(')
private[this] val stopSym = Set(']', '[', ')') private[this] val stopSym = Set(']', '[', ')')
private[this] val MavenVersionSetPattern = """([\]\[\(])([\w\.\-]+)?(,)?([\w\.\-]+)?([\]\[\)])(,.+)?""".r private[this] val MavenVersionSetPattern =
"""([\]\[\(])([\w\.\-]+)?(,)?([\w\.\-]+)?([\]\[\)])(,.+)?""".r
} }

View File

@ -12,65 +12,73 @@ object CrossVersionUtil {
val TransitionSbtVersion = "0.12" val TransitionSbtVersion = "0.12"
def isFull(s: String): Boolean = (s == trueString) || (s == fullString) 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) def isBinary(s: String): Boolean = (s == binaryString)
private lazy val intPattern = """\d{1,10}""" private lazy val intPattern = """\d{1,10}"""
private lazy val basicVersion = """(""" + intPattern + """)\.(""" + intPattern + """)\.(""" + intPattern + """)""" private lazy val basicVersion = """(""" + intPattern + """)\.(""" + intPattern + """)\.(""" + intPattern + """)"""
private[sbt] def isSbtApiCompatible(v: String): Boolean = sbtApiVersion(v).isDefined private[sbt] def isSbtApiCompatible(v: String): Boolean = sbtApiVersion(v).isDefined
/** /**
* Returns sbt binary interface x.y API compatible with the given version string v. * Returns sbt binary interface x.y API compatible with the given version string v.
* RCs for x.y.0 are considered API compatible. * 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). * 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)] = private[sbt] def sbtApiVersion(v: String): Option[(Int, Int)] = {
{ val ReleaseV = (basicVersion + """(-\d+)?""").r
val ReleaseV = (basicVersion + """(-\d+)?""").r val CandidateV = (basicVersion + """(-RC\d+)""").r
val CandidateV = (basicVersion + """(-RC\d+)""").r val NonReleaseV = (basicVersion + """([-\w+]*)""").r
val NonReleaseV = (basicVersion + """([-\w+]*)""").r v match {
v match { case ReleaseV(x, y, z, ht) => Some((x.toInt, y.toInt))
case ReleaseV(x, y, z, ht) => Some((x.toInt, y.toInt)) case CandidateV(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 NonReleaseV(x, y, z, ht) if z.toInt > 0 => Some((x.toInt, y.toInt)) case _ => None
case _ => None
}
} }
}
private[sbt] def isScalaApiCompatible(v: String): Boolean = scalaApiVersion(v).isDefined private[sbt] def isScalaApiCompatible(v: String): Boolean = scalaApiVersion(v).isDefined
/** /**
* Returns Scala binary interface x.y API compatible with the given version string v. * Returns Scala binary interface x.y API compatible with the given version string v.
* Compatibile versions include 2.10.0-1 and 2.10.1-M1 for Some(2, 10), but not 2.10.0-RC1. * 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)] = private[sbt] def scalaApiVersion(v: String): Option[(Int, Int)] = {
{ val ReleaseV = (basicVersion + """(-\d+)?""").r
val ReleaseV = (basicVersion + """(-\d+)?""").r val BinCompatV = (basicVersion + """-bin(-.*)?""").r
val BinCompatV = (basicVersion + """-bin(-.*)?""").r val NonReleaseV = (basicVersion + """(-\w+)""").r
val NonReleaseV = (basicVersion + """(-\w+)""").r v match {
v match { case ReleaseV(x, y, z, ht) => Some((x.toInt, y.toInt))
case ReleaseV(x, y, z, ht) => Some((x.toInt, y.toInt)) case BinCompatV(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 NonReleaseV(x, y, z, ht) if z.toInt > 0 => Some((x.toInt, y.toInt)) case _ => None
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)] = private[sbt] def partialVersion(s: String): Option[(Int, Int)] =
s match { s match {
case PartialVersion(major, minor) => Some((major.toInt, minor.toInt)) case PartialVersion(major, minor) => Some((major.toInt, minor.toInt))
case _ => None case _ => None
} }
def binaryScalaVersion(full: String): String = binaryVersionWithApi(full, TransitionScalaVersion)(scalaApiVersion) def binaryScalaVersion(full: String): String =
def binarySbtVersion(full: String): String = binaryVersionWithApi(full, TransitionSbtVersion)(sbtApiVersion) binaryVersionWithApi(full, TransitionScalaVersion)(scalaApiVersion)
private[sbt] def binaryVersion(full: String, cutoff: String): String = binaryVersionWithApi(full, cutoff)(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 = private[this] def isNewer(major: Int, minor: Int, minMajor: Int, minMinor: Int): Boolean =
major > minMajor || (major == minMajor && minor >= minMinor) major > minMajor || (major == minMajor && minor >= minMinor)
private[this] def binaryVersionWithApi(full: String, cutoff: String)(apiVersion: String => Option[(Int, Int)]): String = private[this] def binaryVersionWithApi(full: String, cutoff: String)(
{ apiVersion: String => Option[(Int, Int)]
def sub(major: Int, minor: Int) = major + "." + minor ): String = {
(apiVersion(full), partialVersion(cutoff)) match { def sub(major: Int, minor: Int) = major + "." + minor
case (Some((major, minor)), None) => sub(major, minor) (apiVersion(full), partialVersion(cutoff)) match {
case (Some((major, minor)), Some((minMajor, minMinor))) if isNewer(major, minor, minMajor, minMinor) => sub(major, minor) case (Some((major, minor)), None) => sub(major, minor)
case _ => full case (Some((major, minor)), Some((minMajor, minMinor)))
} if isNewer(major, minor, minMajor, minMinor) =>
sub(major, minor)
case _ => full
} }
}
} }

View File

@ -8,15 +8,23 @@ trait UpdateOptionsFormat { self: BasicJsonProtocol =>
implicit lazy val UpdateOptionsFormat: JsonFormat[UpdateOptions] = implicit lazy val UpdateOptionsFormat: JsonFormat[UpdateOptions] =
project( project(
(uo: UpdateOptions) => ( (uo: UpdateOptions) =>
uo.circularDependencyLevel.name, (
uo.interProjectFirst, uo.circularDependencyLevel.name,
uo.latestSnapshots, uo.interProjectFirst,
uo.consolidatedResolution, uo.latestSnapshots,
uo.cachedResolution uo.consolidatedResolution,
uo.cachedResolution
), ),
(xs: (String, Boolean, Boolean, Boolean, Boolean)) => (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( private val levels: Map[String, CircularDependencyLevel] = Map(

View File

@ -8,58 +8,51 @@ import StringUtilities.nonEmpty
import sbt.librarymanagement._ import sbt.librarymanagement._
trait DependencyBuilders { trait DependencyBuilders {
final implicit def toGroupID(groupID: String): GroupID = final implicit def toGroupID(groupID: String): GroupID = {
{ nonEmpty(groupID, "Group ID")
nonEmpty(groupID, "Group ID") new GroupID(groupID)
new GroupID(groupID) }
} final implicit def toRepositoryName(name: String): RepositoryName = {
final implicit def toRepositoryName(name: String): RepositoryName = nonEmpty(name, "Repository name")
{ new RepositoryName(name)
nonEmpty(name, "Repository name") }
new RepositoryName(name) final implicit def moduleIDConfigurable(m: ModuleID): ModuleIDConfigurable = {
} require(m.configurations.isEmpty, "Configurations already specified for module " + m)
final implicit def moduleIDConfigurable(m: ModuleID): ModuleIDConfigurable = new ModuleIDConfigurable(m)
{ }
require(m.configurations.isEmpty, "Configurations already specified for module " + m)
new ModuleIDConfigurable(m)
}
} }
final class GroupID private[sbt] (private[sbt] val groupID: String) { final class GroupID private[sbt] (private[sbt] val groupID: String) {
def %(artifactID: String) = groupArtifact(artifactID, Disabled()) def %(artifactID: String) = groupArtifact(artifactID, Disabled())
def %%(artifactID: String): GroupArtifactID = groupArtifact(artifactID, CrossVersion.binary) def %%(artifactID: String): GroupArtifactID = groupArtifact(artifactID, CrossVersion.binary)
private def groupArtifact(artifactID: String, cross: CrossVersion) = private def groupArtifact(artifactID: String, cross: CrossVersion) = {
{ nonEmpty(artifactID, "Artifact ID")
nonEmpty(artifactID, "Artifact ID") new GroupArtifactID(groupID, artifactID, cross)
new GroupArtifactID(groupID, artifactID, cross) }
}
} }
final class GroupArtifactID private[sbt] ( final class GroupArtifactID private[sbt] (
private[sbt] val groupID: String, private[sbt] val groupID: String,
private[sbt] val artifactID: String, private[sbt] val artifactID: String,
private[sbt] val crossVersion: CrossVersion private[sbt] val crossVersion: CrossVersion
) { ) {
def %(revision: String): ModuleID = def %(revision: String): ModuleID = {
{ nonEmpty(revision, "Revision")
nonEmpty(revision, "Revision") ModuleID(groupID, artifactID, revision).cross(crossVersion)
ModuleID(groupID, artifactID, revision).cross(crossVersion) }
}
} }
final class ModuleIDConfigurable private[sbt] (moduleID: ModuleID) { final class ModuleIDConfigurable private[sbt] (moduleID: ModuleID) {
def %(configuration: Configuration): ModuleID = %(configuration.name) def %(configuration: Configuration): ModuleID = %(configuration.name)
def %(configurations: String): ModuleID = def %(configurations: String): ModuleID = {
{ nonEmpty(configurations, "Configurations")
nonEmpty(configurations, "Configurations") val c = configurations
val c = configurations moduleID.withConfigurations(configurations = Some(c))
moduleID.withConfigurations(configurations = Some(c)) }
}
} }
final class RepositoryName private[sbt] (name: String) { final class RepositoryName private[sbt] (name: String) {
def at(location: String) = def at(location: String) = {
{ nonEmpty(location, "Repository location")
nonEmpty(location, "Repository location") MavenRepository(name, location)
MavenRepository(name, location) }
}
} }

View File

@ -5,8 +5,7 @@ import org.apache.ivy.plugins.resolver.DependencyResolver
import sbt.librarymanagement._ import sbt.librarymanagement._
// These are placeholder traits for sbt-aether-resolver // These are placeholder traits for sbt-aether-resolver
trait CustomMavenResolver extends DependencyResolver { trait CustomMavenResolver extends DependencyResolver {}
}
trait CustomRemoteMavenResolver extends CustomMavenResolver { trait CustomRemoteMavenResolver extends CustomMavenResolver {
def repo: MavenRepository def repo: MavenRepository
} }

View File

@ -44,7 +44,9 @@ object ErrorMessageAuthenticator {
case originalOpt => installIntoIvyImpl(originalOpt) case originalOpt => installIntoIvyImpl(originalOpt)
} catch { } catch {
case t: Throwable => 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) Some(ivy)
} }
@ -57,8 +59,10 @@ object ErrorMessageAuthenticator {
catch { catch {
case e: SecurityException if !securityWarningLogged => case e: SecurityException if !securityWarningLogged =>
securityWarningLogged = true securityWarningLogged = true
Message.warn("Not enough permissions to set the ErrorMessageAuthenticator. " Message.warn(
+ "Helpful debug messages disabled!"); "Not enough permissions to set the ErrorMessageAuthenticator. "
+ "Helpful debug messages disabled!"
);
} }
// We will try to use the original authenticator as backup authenticator. // We will try to use the original authenticator as backup authenticator.
// Since there is no getter available, so try to use some reflection to // Since there is no getter available, so try to use some reflection to
@ -73,6 +77,7 @@ object ErrorMessageAuthenticator {
doInstallIfIvy(originalAuthenticator) doInstallIfIvy(originalAuthenticator)
} }
} }
/** /**
* An authenticator which just delegates to a previous authenticator and issues *nice* * An authenticator which just delegates to a previous authenticator and issues *nice*
* error messages on failure to find credentials. * 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 * 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. * 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 = { protected override def getPasswordAuthentication(): PasswordAuthentication = {
// We're guaranteed to only get here if Ivy's authentication fails // 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... // Grabs the authentication that would have been provided had we not been installed...
def originalAuthentication: Option[PasswordAuthentication] = { def originalAuthentication: Option[PasswordAuthentication] = {
Authenticator.setDefault(original.orNull) Authenticator.setDefault(original.orNull)
try Option(Authenticator.requestPasswordAuthentication( try Option(
getRequestingHost, Authenticator.requestPasswordAuthentication(
getRequestingSite, getRequestingHost,
getRequestingPort, getRequestingSite,
getRequestingProtocol, getRequestingPort,
getRequestingPrompt, getRequestingProtocol,
getRequestingScheme getRequestingPrompt,
)) getRequestingScheme
)
)
finally Authenticator.setDefault(this) finally Authenticator.setDefault(this)
} }
originalAuthentication.orNull originalAuthentication.orNull

View File

@ -6,8 +6,10 @@ import collection.JavaConverters._
/** A key used to store credentials in the ivy credentials store. */ /** A key used to store credentials in the ivy credentials store. */
private[sbt] sealed trait CredentialKey private[sbt] sealed trait CredentialKey
/** Represents a key in the ivy credentials store that is only specific to a host. */ /** Represents a key in the ivy credentials store that is only specific to a host. */
private[sbt] case class Host(name: String) extends CredentialKey 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". */ /** 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 private[sbt] case class Realm(host: String, realm: String) extends CredentialKey

View File

@ -13,25 +13,25 @@ private[sbt] object MergeDescriptors {
a.isTransitive == b.isTransitive && a.isTransitive == b.isTransitive &&
a.getParentRevisionId == b.getParentRevisionId && a.getParentRevisionId == b.getParentRevisionId &&
a.getNamespace == b.getNamespace && { a.getNamespace == b.getNamespace && {
val amrid = a.getDependencyRevisionId val amrid = a.getDependencyRevisionId
val bmrid = b.getDependencyRevisionId val bmrid = b.getDependencyRevisionId
amrid == bmrid amrid == bmrid
} && { } && {
val adyn = a.getDynamicConstraintDependencyRevisionId val adyn = a.getDynamicConstraintDependencyRevisionId
val bdyn = b.getDynamicConstraintDependencyRevisionId val bdyn = b.getDynamicConstraintDependencyRevisionId
adyn == bdyn adyn == bdyn
}
def apply(a: DependencyDescriptor, b: DependencyDescriptor): DependencyDescriptor =
{
assert(mergeable(a, b))
new MergedDescriptors(a, b)
} }
def apply(a: DependencyDescriptor, b: DependencyDescriptor): DependencyDescriptor = {
assert(mergeable(a, b))
new MergedDescriptors(a, b)
}
} }
// combines the artifacts, configurations, includes, and excludes for DependencyDescriptors `a` and `b` // combines the artifacts, configurations, includes, and excludes for DependencyDescriptors `a` and `b`
// that otherwise have equal IDs // 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 getDependencyId = a.getDependencyId
def isForce = a.isForce def isForce = a.isForce
def isChanging = a.isChanging 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 getModuleConfigurations = concat(a.getModuleConfigurations, b.getModuleConfigurations)
def getDependencyConfigurations(moduleConfiguration: String, requestedConfiguration: String) = 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) = def getDependencyConfigurations(moduleConfiguration: String) =
concat(a.getDependencyConfigurations(moduleConfiguration), b.getDependencyConfigurations(moduleConfiguration)) concat(
a.getDependencyConfigurations(moduleConfiguration),
b.getDependencyConfigurations(moduleConfiguration)
)
def getDependencyConfigurations(moduleConfigurations: Array[String]) = 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) = 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]) = 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) 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]) = def getIncludeRules(moduleConfigurations: Array[String]) =
concat(a.getIncludeRules(moduleConfigurations), b.getIncludeRules(moduleConfigurations)) concat(a.getIncludeRules(moduleConfigurations), b.getIncludeRules(moduleConfigurations))
private[this] def concatArtifacts(a: DependencyDescriptor, as: Array[DependencyArtifactDescriptor], b: DependencyDescriptor, bs: Array[DependencyArtifactDescriptor]) = private[this] def concatArtifacts(
{ a: DependencyDescriptor,
if (as.isEmpty) as: Array[DependencyArtifactDescriptor],
if (bs.isEmpty) as b: DependencyDescriptor,
else defaultArtifact(a) ++ explicitConfigurations(b, bs) bs: Array[DependencyArtifactDescriptor]
else if (bs.isEmpty) explicitConfigurations(a, as) ++ defaultArtifact(b) ) = {
else concat(explicitConfigurations(a, as), explicitConfigurations(b, bs)) 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] = private[this] def explicitConfigurations(
arts map { art => explicitConfigurations(base, art) } base: DependencyDescriptor,
private[this] def explicitConfigurations(base: DependencyDescriptor, art: DependencyArtifactDescriptor): DependencyArtifactDescriptor = art: DependencyArtifactDescriptor
{ ): DependencyArtifactDescriptor = {
val aConfs = Option(art.getConfigurations) map { _.toList } val aConfs = Option(art.getConfigurations) map { _.toList }
// In case configuration list is "*", we should still specify the module configuration of the DependencyDescriptor // 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. // otherwise the explicit specified artifacts from one dd can leak over to the other.
// See gh-1500, gh-2002 // See gh-1500, gh-2002
aConfs match { aConfs match {
case None | Some(Nil) | Some(List("*")) => copyWithConfigurations(art, base.getModuleConfigurations) case None | Some(Nil) | Some(List("*")) =>
case _ => art copyWithConfigurations(art, base.getModuleConfigurations)
} case _ => art
} }
private[this] def defaultArtifact(a: DependencyDescriptor): Array[DependencyArtifactDescriptor] = }
{ private[this] def defaultArtifact(a: DependencyDescriptor): Array[DependencyArtifactDescriptor] = {
val dd = new DefaultDependencyArtifactDescriptor(a, a.getDependencyRevisionId.getName, "jar", "jar", null, null) val dd = new DefaultDependencyArtifactDescriptor(
addConfigurations(dd, a.getModuleConfigurations) a,
// If the dependency descriptor is empty, then it means that it has been created from a POM file. In this case, a.getDependencyRevisionId.getName,
// it is correct to create a seemingly non-existent dependency artifact. "jar",
if (a.getAllDependencyArtifacts.isEmpty) Array(dd) "jar",
else a.getAllDependencyArtifacts filter (_ == dd) null,
} null
private[this] def copyWithConfigurations(dd: DependencyArtifactDescriptor, confs: Seq[String]): DependencyArtifactDescriptor = )
{ addConfigurations(dd, a.getModuleConfigurations)
val dextra = dd.getQualifiedExtraAttributes // If the dependency descriptor is empty, then it means that it has been created from a POM file. In this case,
val newd = new DefaultDependencyArtifactDescriptor(dd.getDependencyDescriptor, dd.getName, dd.getType, dd.getExt, dd.getUrl, dextra) // it is correct to create a seemingly non-existent dependency artifact.
addConfigurations(newd, confs) if (a.getAllDependencyArtifacts.isEmpty) Array(dd)
newd else a.getAllDependencyArtifacts filter (_ == dd)
} }
private[this] def addConfigurations(dd: DefaultDependencyArtifactDescriptor, confs: Seq[String]): Unit = 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 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 getAllExcludeRules = concat(a.getAllExcludeRules, b.getAllExcludeRules)
def getExcludeRules(moduleConfigurations: String) = concat(a.getExcludeRules(moduleConfigurations), b.getExcludeRules(moduleConfigurations)) def getExcludeRules(moduleConfigurations: String) =
concat(a.getExcludeRules(moduleConfigurations), b.getExcludeRules(moduleConfigurations))
def getExcludeRules(moduleConfigurations: Array[String]) = concat(a.getExcludeRules(moduleConfigurations), b.getExcludeRules(moduleConfigurations)) def getExcludeRules(moduleConfigurations: Array[String]) =
concat(a.getExcludeRules(moduleConfigurations), b.getExcludeRules(moduleConfigurations))
def doesExclude(moduleConfigurations: Array[String], artifactId: ArtifactId) = a.doesExclude(moduleConfigurations, artifactId) || b.doesExclude(moduleConfigurations, artifactId) def doesExclude(moduleConfigurations: Array[String], artifactId: ArtifactId) =
a.doesExclude(moduleConfigurations, artifactId) || b.doesExclude(
moduleConfigurations,
artifactId
)
def canExclude = a.canExclude || b.canExclude def canExclude = a.canExclude || b.canExclude
def asSystem = this def asSystem = this
def clone(revision: ModuleRevisionId) = new MergedDescriptors(a.clone(revision), b.clone(revision)) def clone(revision: ModuleRevisionId) =
new MergedDescriptors(a.clone(revision), b.clone(revision))
def getAttribute(name: String): String = a.getAttribute(name) def getAttribute(name: String): String = a.getAttribute(name)
def getAttributes = a.getAttributes def getAttributes = a.getAttributes

View File

@ -7,7 +7,12 @@ import java.util.Date
import org.apache.ivy.core.settings.IvySettings import org.apache.ivy.core.settings.IvySettings
import org.apache.ivy.core.{ IvyContext, LogOptions } 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.core.resolve.{ ResolvedModuleRevision, ResolveData }
import org.apache.ivy.plugins.latest.LatestStrategy import org.apache.ivy.plugins.latest.LatestStrategy
import org.apache.ivy.plugins.repository.file.{ FileRepository => IFileRepository, FileResource } import org.apache.ivy.plugins.repository.file.{ FileRepository => IFileRepository, FileResource }
@ -19,11 +24,11 @@ import sbt.util.Logger
import sbt.librarymanagement._ import sbt.librarymanagement._
private[sbt] case class SbtChainResolver( private[sbt] case class SbtChainResolver(
name: String, name: String,
resolvers: Seq[DependencyResolver], resolvers: Seq[DependencyResolver],
settings: IvySettings, settings: IvySettings,
updateOptions: UpdateOptions, updateOptions: UpdateOptions,
log: Logger log: Logger
) extends ChainResolver { ) extends ChainResolver {
override def equals(o: Any): Boolean = o match { override def equals(o: Any): Boolean = o match {
@ -35,15 +40,14 @@ private[sbt] case class SbtChainResolver(
case _ => false case _ => false
} }
override def hashCode: Int = override def hashCode: Int = {
{ var hash = 1
var hash = 1 hash = hash * 31 + this.name.##
hash = hash * 31 + this.name.## hash = hash * 31 + this.resolvers.##
hash = hash * 31 + this.resolvers.## hash = hash * 31 + this.settings.##
hash = hash * 31 + this.settings.## hash = hash * 31 + this.updateOptions.##
hash = hash * 31 + this.updateOptions.## hash
hash }
}
// TODO - We need to special case the project resolver so it always "wins" when resolving with inter-project dependencies. // 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 // 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. // 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) = override def getDependency(dd: DependencyDescriptor, data: ResolveData) = {
{ if (data.getOptions.getLog != LogOptions.LOG_QUIET)
if (data.getOptions.getLog != LogOptions.LOG_QUIET) Message.debug("Resolving " + dd.getDependencyRevisionId + " ...")
Message.debug("Resolving " + dd.getDependencyRevisionId + " ...") val gd = doGetDependency(dd, data)
val gd = doGetDependency(dd, data) val mod = IvySbt.resetArtifactResolver(gd)
val mod = IvySbt.resetArtifactResolver(gd) mod
mod }
}
// Modified implementation of ChainResolver#getDependency. // Modified implementation of ChainResolver#getDependency.
// When the dependency is changing, it will check all resolvers on the chain // 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 // regardless of what the "latest strategy" is set, and look for the published date
// or the module descriptor to sort them. // or the module descriptor to sort them.
// This implementation also skips resolution if "return first" is set to true, // This implementation also skips resolution if "return first" is set to true,
// and if a previously resolved or cached revision has been found. // and if a previously resolved or cached revision has been found.
def doGetDependency(dd: DependencyDescriptor, data0: ResolveData): ResolvedModuleRevision = def doGetDependency(dd: DependencyDescriptor, data0: ResolveData): ResolvedModuleRevision = {
{ // useLatest - Means we should always download the JARs from the internet, no matter what.
// 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.
// This will only be true *IF* the depenendency is dynamic/changing *and* latestSnapshots is true. // If you find multiple candidates,
// If you find multiple candidates, // - If `isReturnFirst` is true, you return the first value found
// - 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
// - If not, we will ATTEMPT to look at the publish date, which is not correctly discovered for Maven modules and // leads to undefined behavior.
// leads to undefined behavior. val useLatest = (dd.isChanging || IvySbt.isChanging(dd.getDependencyRevisionId)) && updateOptions.latestSnapshots
val useLatest = (dd.isChanging || IvySbt.isChanging(dd.getDependencyRevisionId)) && updateOptions.latestSnapshots if (useLatest) {
if (useLatest) { Message.verbose(s"$getName is changing. Checking all resolvers on the chain")
Message.verbose(s"$getName is changing. Checking all resolvers on the chain") }
} val data = new ResolveData(data0, doValidate(data0))
val data = new ResolveData(data0, doValidate(data0)) // Returns the value if we've already been resolved from some other branch of the resolution tree.
// Returns the value if we've already been resolved from some other branch of the resolution tree. val resolved = Option(data.getCurrentResolvedModuleRevision)
val resolved = Option(data.getCurrentResolvedModuleRevision) // If we don't have any previously resolved date, we try to pull the value from the cache.
// If we don't have any previously resolved date, we try to pull the value from the cache. val resolvedOrCached =
val resolvedOrCached = resolved orElse {
resolved orElse { Message.verbose(getName + ": Checking cache for: " + dd)
Message.verbose(getName + ": Checking cache for: " + dd) Option(findModuleInCache(dd, data, true)) map { mr =>
Option(findModuleInCache(dd, data, true)) map { mr => Message.verbose(getName + ": module revision found in cache: " + mr.getId)
Message.verbose(getName + ": module revision found in cache: " + mr.getId) forcedRevision(mr)
forcedRevision(mr)
}
} }
}
// Default value for resolution. We use this while we loop... // 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. // 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] = var temp: Option[ResolvedModuleRevision] =
if (useLatest) None if (useLatest) None
else resolvedOrCached else resolvedOrCached
// Cast resolvers to something useful. TODO - we dropping anything here? // Cast resolvers to something useful. TODO - we dropping anything here?
val resolvers = getResolvers.toArray.toVector collect { case x: DependencyResolver => x } val resolvers = getResolvers.toArray.toVector collect { case x: DependencyResolver => x }
val interProjResolver = resolvers find { x => x.getName == ProjectResolver.InterProject } 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. // 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 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. // - If we do not, try to resolve.
// RETURNS: Left -> Error // RETURNS: Left -> Error
// Right -> Some(resolved module) // Found in this resolver, can use this result. // Right -> Some(resolved module) // Found in this resolver, can use this result.
// Right -> None // Do not use this resolver // Right -> None // Do not use this resolver
lazy val results = resolvers map { x => 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 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) if (isReturnFirst && temp.isDefined && !useLatest) Right(None)
else { else {
// We actually do resolution. // We actually do resolution.
val resolver = x val resolver = x
val oldLatest: Option[LatestStrategy] = setLatestIfRequired(resolver, Option(getLatestStrategy)) val oldLatest: Option[LatestStrategy] =
try { setLatestIfRequired(resolver, Option(getLatestStrategy))
val previouslyResolved = temp try {
// if the module qualifies as changing, then resolve all resolvers val previouslyResolved = temp
if (useLatest) data.setCurrentResolvedModuleRevision(null) // if the module qualifies as changing, then resolve all resolvers
else data.setCurrentResolvedModuleRevision(temp.orNull) if (useLatest) data.setCurrentResolvedModuleRevision(null)
temp = Option(resolver.getDependency(dd, data)) else data.setCurrentResolvedModuleRevision(temp.orNull)
Right( temp = Option(resolver.getDependency(dd, data))
if (temp eq previouslyResolved) None Right(
else if (useLatest) temp map { x => if (temp eq previouslyResolved) None
(reparseModuleDescriptor(dd, data, resolver, x), resolver) 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 { Left(ex)
case ex: Exception => } finally {
Message.verbose("problem occurred while resolving " + dd + " with " + resolver oldLatest map { _ =>
+ ": " + IvyStringUtils.getStackTrace(ex)) doSetLatestStrategy(resolver, oldLatest)
Left(ex)
} finally {
oldLatest map { _ => doSetLatestStrategy(resolver, oldLatest) }
checkInterrupted()
} }
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. // 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 mrOpt: Option[ResolvedModuleRevision] = {
val interProj: Option[ResolvedModuleRevision] = val interProj: Option[ResolvedModuleRevision] =
if (updateOptions.interProjectFirst) interProjResolver flatMap { x => Option(x.getDependency(dd, data)) } if (updateOptions.interProjectFirst) interProjResolver flatMap { x =>
else None Option(x.getDependency(dd, data))
def foundRevisions: Vector[(ResolvedModuleRevision, DependencyResolver)] = results collect { case Right(Some(x)) => x } } else None
def sorted = def foundRevisions: Vector[(ResolvedModuleRevision, DependencyResolver)] = results collect {
if (useLatest) (foundRevisions.sortBy { case Right(Some(x)) => x
}
def sorted =
if (useLatest)(foundRevisions
.sortBy {
case (rmr, resolver) => 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. // Just issue warning about issues with publication date, and fake one on it for now.
Option(rmr.getPublicationDate) orElse Option(rmr.getDescriptor.getPublicationDate) match { Option(rmr.getPublicationDate) orElse Option(rmr.getDescriptor.getPublicationDate) match {
case None => case None =>
@ -173,55 +191,75 @@ private[sbt] case class SbtChainResolver(
case (null, _) => case (null, _) =>
// In this instance, the dependency is specified by a direct URL or some other sort of "non-ivy" file // In this instance, the dependency is specified by a direct URL or some other sort of "non-ivy" file
if (dd.isChanging) 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 0L
case (ivf, dmd: DefaultModuleDescriptor) => case (ivf, dmd: DefaultModuleDescriptor) =>
val lmd = new java.util.Date(ivf.getLastModified) 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) dmd.setPublicationDate(lmd)
ivf.getLastModified ivf.getLastModified
case _ => 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 0L
} }
case Some(date) => // All other cases ok case Some(date) => // All other cases ok
date.getTime date.getTime
} }
}).reverse.headOption map { })
case (rmr, resolver) => .reverse
Message.warn(s"Choosing $resolver for ${rmr.getId}") .headOption map {
// Now that we know the real latest revision, let's force Ivy to use it case (rmr, resolver) =>
val artifactOpt = findFirstArtifactRef(rmr.getDescriptor, dd, data, resolver) Message.warn(s"Choosing $resolver for ${rmr.getId}")
artifactOpt match { // Now that we know the real latest revision, let's force Ivy to use it
case Some(artifactRef) => val artifactOpt = findFirstArtifactRef(rmr.getDescriptor, dd, data, resolver)
val systemMd = toSystem(rmr.getDescriptor) artifactOpt match {
getRepositoryCacheManager.cacheModuleDescriptor(resolver, artifactRef, case Some(artifactRef) =>
toSystem(dd), systemMd.getAllArtifacts.head, None.orNull, getCacheOptions(data)) val systemMd = toSystem(rmr.getDescriptor)
case None => // do nothing. There are modules without artifacts getRepositoryCacheManager.cacheModuleDescriptor(
} resolver,
rmr artifactRef,
} toSystem(dd),
else foundRevisions.reverse.headOption map { _._1 } // we have to reverse because resolvers are hit in reverse order. 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 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
}
} }
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 // 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. // 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 // We should figure out a better alternative, or directly attack the resolvers Ivy uses to
// give them correct behavior around -SNAPSHOT. // give them correct behavior around -SNAPSHOT.
@ -238,49 +276,76 @@ private[sbt] case class SbtChainResolver(
case _ => None case _ => None
} }
} getOrElse { } 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 rmr
} }
/** Ported from BasicResolver#findFirstAirfactRef. */ /** Ported from BasicResolver#findFirstAirfactRef. */
private[this] def findFirstArtifactRef(md: ModuleDescriptor, dd: DependencyDescriptor, data: ResolveData, resolver: DependencyResolver): Option[ResolvedResource] = private[this] def findFirstArtifactRef(
{ md: ModuleDescriptor,
def artifactRef(artifact: IArtifact, date: Date): Option[ResolvedResource] = dd: DependencyDescriptor,
resolver match { data: ResolveData,
case resolver: BasicResolver => resolver: DependencyResolver
IvyContext.getContext.set(resolver.getName + ".artifact", artifact) ): Option[ResolvedResource] = {
try { def artifactRef(artifact: IArtifact, date: Date): Option[ResolvedResource] =
Option(resolver.doFindArtifactRef(artifact, date)) orElse { resolver match {
Option(artifact.getUrl) map { url => case resolver: BasicResolver =>
Message.verbose("\tusing url for " + artifact + ": " + url) IvyContext.getContext.set(resolver.getName + ".artifact", artifact)
val resource = try {
if ("file" == url.getProtocol) new FileResource(new IFileRepository(), new File(url.getPath)) Option(resolver.doFindArtifactRef(artifact, date)) orElse {
else new URLResource(url) Option(artifact.getUrl) map { url =>
new ResolvedResource(resource, artifact.getModuleRevisionId.getRevision) 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 _ => } finally {
None IvyContext.getContext.set(resolver.getName + ".artifact", null)
} }
val artifactRefs = md.getConfigurations.toIterator flatMap { conf => case _ =>
md.getArtifacts(conf.getName).toIterator flatMap { af => None
artifactRef(af, data.getDate).toIterator }
} 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. */ /** Ported from ChainResolver#forcedRevision. */
private[this] def forcedRevision(rmr: ResolvedModuleRevision): ResolvedModuleRevision = 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. */ /** Ported from ChainResolver#resolvedRevision. */
private[this] def resolvedRevision(rmr: ResolvedModuleRevision): ResolvedModuleRevision = 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 else rmr
/** Ported from ChainResolver#setLatestIfRequired. */ /** 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 { latestStrategyName(resolver) match {
case Some(latestName) if latestName != "default" => case Some(latestName) if latestName != "default" =>
val oldLatest = latestStrategy(resolver) val oldLatest = latestStrategy(resolver)
@ -288,20 +353,26 @@ private[sbt] case class SbtChainResolver(
oldLatest oldLatest
case _ => None case _ => None
} }
/** Ported from ChainResolver#getLatestStrategyName. */ /** Ported from ChainResolver#getLatestStrategyName. */
private[this] def latestStrategyName(resolver: DependencyResolver): Option[String] = private[this] def latestStrategyName(resolver: DependencyResolver): Option[String] =
resolver match { resolver match {
case r: HasLatestStrategy => Some(r.getLatest) case r: HasLatestStrategy => Some(r.getLatest)
case _ => None case _ => None
} }
/** Ported from ChainResolver#getLatest. */ /** Ported from ChainResolver#getLatest. */
private[this] def latestStrategy(resolver: DependencyResolver): Option[LatestStrategy] = private[this] def latestStrategy(resolver: DependencyResolver): Option[LatestStrategy] =
resolver match { resolver match {
case r: HasLatestStrategy => Some(r.getLatestStrategy) case r: HasLatestStrategy => Some(r.getLatestStrategy)
case _ => None case _ => None
} }
/** Ported from ChainResolver#setLatest. */ /** 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 { resolver match {
case r: HasLatestStrategy => case r: HasLatestStrategy =>
val oldLatest = latestStrategy(resolver) val oldLatest = latestStrategy(resolver)

View File

@ -25,13 +25,16 @@ object PomExtraDependencyAttributes {
val ExtraAttributesKey = "extraDependencyAttributes" val ExtraAttributesKey = "extraDependencyAttributes"
val SbtVersionKey = "sbtVersion" val SbtVersionKey = "sbtVersion"
val ScalaVersionKey = "scalaVersion" val ScalaVersionKey = "scalaVersion"
/** /**
* Reads the extra dependency attributes out of a maven property. * Reads the extra dependency attributes out of a maven property.
* @param props The properties from an Aether resolution. * @param props The properties from an Aether resolution.
* @return * @return
* A map of module id to extra dependency attributes associated with dependencies on that module. * 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._ import scala.collection.JavaConverters._
(props.asScala get ExtraAttributesKey) match { (props.asScala get ExtraAttributesKey) match {
case None => Map.empty case None => Map.empty
@ -52,7 +55,10 @@ object PomExtraDependencyAttributes {
* TODO - maybe we can just parse this directly here. Note the `readFromAether` method uses * TODO - maybe we can just parse this directly here. Note the `readFromAether` method uses
* whatever we set here. * 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, _)) 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 item.getQualifiedExtraAttributes.asInstanceOf[java.util.Map[String, String]].asScala.toMap
} }
def filterCustomExtra(item: ExtendableItem, include: Boolean): Map[String, String] = 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 // 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 // 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 // with the extra attributes from the <properties> section
def simplify(id: ModuleRevisionId): ModuleRevisionId = { def simplify(id: ModuleRevisionId): ModuleRevisionId = {
import scala.collection.JavaConverters._ 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 */ /** parses the sequence of dependencies with extra attribute information, with one dependency per line */

View File

@ -16,28 +16,48 @@ abstract class ArtifactExtra {
def extraAttributes: Map[String, String] def extraAttributes: Map[String, String]
protected[this] def copy( protected[this] def copy(
name: String = name, name: String = name,
`type`: String = `type`, `type`: String = `type`,
extension: String = extension, extension: String = extension,
classifier: Option[String] = classifier, classifier: Option[String] = classifier,
configurations: Vector[Configuration] = configurations, configurations: Vector[Configuration] = configurations,
url: Option[URL] = url, url: Option[URL] = url,
extraAttributes: Map[String, String] = extraAttributes extraAttributes: Map[String, String] = extraAttributes
): Artifact ): 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 } import Configurations.{ Optional, Pom, Test }
abstract class ArtifactFunctions { 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, extra: Map[String, String]): Artifact =
def apply(name: String, classifier: String): Artifact = Artifact(name, DefaultType, DefaultExtension, Some(classifier), Vector.empty, None) Artifact(name, DefaultType, DefaultExtension, None, Vector.empty, None, extra)
def apply(name: String, `type`: String, extension: String): Artifact = Artifact(name, `type`, extension, None, Vector.empty, None) def apply(name: String, classifier: String): Artifact =
def apply(name: String, `type`: String, extension: String, classifier: String): Artifact = Artifact(name, `type`, extension, Some(classifier), Vector.empty, None) Artifact(name, DefaultType, DefaultExtension, 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): 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]) Artifact(name, `type`, extension, classifier, configurations, url, Map.empty[String, String])
val DefaultExtension = "jar" val DefaultExtension = "jar"
@ -66,29 +86,33 @@ abstract class ArtifactFunctions {
assert(DefaultSourceTypes contains SourceType) assert(DefaultSourceTypes contains SourceType)
def extract(url: URL, default: String): String = extract(url.toString, default) def extract(url: URL, default: String): String = extract(url.toString, default)
def extract(name: String, default: String): String = def extract(name: String, default: String): String = {
{ val i = name.lastIndexOf('.')
val i = name.lastIndexOf('.') if (i >= 0)
if (i >= 0) name.substring(i + 1)
name.substring(i + 1) else
else default
default }
} def defaultArtifact(file: File) = {
def defaultArtifact(file: File) = val name = file.getName
{ val i = name.lastIndexOf('.')
val name = file.getName val base = if (i >= 0) name.substring(0, i) else name
val i = name.lastIndexOf('.') Artifact(
val base = if (i >= 0) name.substring(0, i) else name base,
Artifact(base, extract(name, DefaultType), extract(name, DefaultExtension), None, Vector.empty, Some(file.toURI.toURL)) extract(name, DefaultType),
} extract(name, DefaultExtension),
def artifactName(scalaVersion: ScalaVersion, module: ModuleID, artifact: Artifact): String = None,
{ Vector.empty,
import artifact._ Some(file.toURI.toURL)
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) def artifactName(scalaVersion: ScalaVersion, module: ModuleID, artifact: Artifact): String = {
base + "-" + module.revision + classifierStr + "." + artifact.extension 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) val classifierTypeMap = Map(SourceClassifier -> SourceType, DocClassifier -> DocType)
@deprecated("Configuration should not be decided from the classifier.", "1.0") @deprecated("Configuration should not be decided from the classifier.", "1.0")
@ -97,7 +121,8 @@ abstract class ArtifactFunctions {
Test Test
else else
Optional 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 * 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. * The artifact is created under the default configuration.
*/ */
def classified(name: String, classifier: String): Artifact = 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
)
} }

View File

@ -1,6 +1,11 @@
package sbt.librarymanagement 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. * Wrapper around circular dependency strategy.

View File

@ -6,7 +6,8 @@ package sbt.librarymanagement
object Configurations { object Configurations {
def config(name: String) = Configuration(name) def config(name: String) = Configuration(name)
def default: Seq[Configuration] = defaultMavenConfigurations 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 defaultInternal: Seq[Configuration] = Seq(CompileInternal, RuntimeInternal, TestInternal)
def auxiliary: Seq[Configuration] = Seq(Pom) def auxiliary: Seq[Configuration] = Seq(Pom)
def names(cs: Seq[Configuration]) = cs.map(_.name) def names(cs: Seq[Configuration]) = cs.map(_.name)
@ -24,7 +25,8 @@ object Configurations {
case _ => c 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 fullInternal(base: Configuration): Configuration = internal(base, base, Optional, Provided)
def optionalInternal(base: Configuration): Configuration = internal(base, base, Optional) def optionalInternal(base: Configuration): Configuration = internal(base, base, Optional)
@ -44,15 +46,24 @@ object Configurations {
private[sbt] val DefaultMavenConfiguration = defaultConfiguration(true) private[sbt] val DefaultMavenConfiguration = defaultConfiguration(true)
private[sbt] val DefaultIvyConfiguration = defaultConfiguration(false) private[sbt] val DefaultIvyConfiguration = defaultConfiguration(false)
private[sbt] def DefaultConfiguration(mavenStyle: Boolean) = if (mavenStyle) DefaultMavenConfiguration else DefaultIvyConfiguration private[sbt] def DefaultConfiguration(mavenStyle: Boolean) =
private[sbt] def defaultConfiguration(mavenStyle: Boolean) = if (mavenStyle) Configurations.Compile else Configurations.Default if (mavenStyle) DefaultMavenConfiguration else DefaultIvyConfiguration
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) 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. */ /** Returns true if the configuration should be under the influence of scalaVersion. */
private[sbt] def underScalaVersion(c: Configuration): Boolean = private[sbt] def underScalaVersion(c: Configuration): Boolean =
c match { c match {
case Default | Compile | IntegrationTest | Provided | Runtime | Test | Optional | case Default | Compile | IntegrationTest | Provided | Runtime | Test | Optional |
CompilerPlugin | CompileInternal | RuntimeInternal | TestInternal => true CompilerPlugin | CompileInternal | RuntimeInternal | TestInternal =>
true
case config => case config =>
config.extendsConfigs exists underScalaVersion config.extendsConfigs exists underScalaVersion
} }
@ -68,8 +79,10 @@ abstract class ConfigurationExtra {
require(name != null && !name.isEmpty) require(name != null && !name.isEmpty)
require(description != null) require(description != null)
def describedAs(newDescription: String) = Configuration(name, newDescription, isPublic, extendsConfigs, transitive) def describedAs(newDescription: String) =
def extend(configs: Configuration*) = Configuration(name, description, isPublic, configs.toVector ++ extendsConfigs, transitive) Configuration(name, newDescription, isPublic, extendsConfigs, transitive)
def extend(configs: Configuration*) =
Configuration(name, description, isPublic, configs.toVector ++ extendsConfigs, transitive)
def notTransitive = intransitive def notTransitive = intransitive
def intransitive = Configuration(name, description, isPublic, extendsConfigs, false) def intransitive = Configuration(name, description, isPublic, extendsConfigs, false)
def hide = Configuration(name, description, false, extendsConfigs, transitive) def hide = Configuration(name, description, false, extendsConfigs, transitive)

View File

@ -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 * 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. * 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 { object ConflictWarning {
def disable: ConflictWarning = ConflictWarning("", Level.Debug, false) def disable: ConflictWarning = ConflictWarning("", Level.Debug, false)
@ -19,10 +18,15 @@ object ConflictWarning {
def apply(config: ConflictWarning, report: UpdateReport, log: Logger): Unit = { def apply(config: ConflictWarning, report: UpdateReport, log: Logger): Unit = {
processCrossVersioned(config, report, log) 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) val crossMismatches = crossVersionMismatches(report)
if (crossMismatches.nonEmpty) { 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 = val conflictMsgs =
for (((org, rawName), fullNames) <- crossMismatches) yield { for (((org, rawName), fullNames) <- crossMismatches) yield {
val suffixes = fullNames.map(getCrossSuffix).mkString(", ") val suffixes = fullNames.map(getCrossSuffix).mkString(", ")
@ -30,25 +34,26 @@ object ConflictWarning {
} }
log.log(config.level, conflictMsgs.mkString(pre, "\n ", "")) log.log(config.level, conflictMsgs.mkString(pre, "\n ", ""))
if (config.failOnConflict) { 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) sys.error("Conflicting cross-version suffixes in: " + summary)
} }
} }
} }
/** Map from (organization, rawName) to set of multiple full names. */ /** Map from (organization, rawName) to set of multiple full names. */
def crossVersionMismatches(report: UpdateReport): Map[(String, String), Set[String]] = def crossVersionMismatches(report: UpdateReport): Map[(String, String), Set[String]] = {
{ val mismatches = report.configurations.flatMap { confReport =>
val mismatches = report.configurations.flatMap { confReport => groupByRawName(confReport.allModules).mapValues { modules =>
groupByRawName(confReport.allModules).mapValues { modules => val differentFullNames = modules.map(_.name).toSet
val differentFullNames = modules.map(_.name).toSet if (differentFullNames.size > 1) differentFullNames else Set.empty[String]
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]] = 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) m.updated(b._1, m.getOrElse(b._1, Set.empty) ++ b._2)
private[this] def groupByRawName(ms: Seq[ModuleID]): Map[(String, String), Seq[ModuleID]] = private[this] def groupByRawName(ms: Seq[ModuleID]): Map[(String, String), Seq[ModuleID]] =

View File

@ -18,6 +18,7 @@ object Credentials {
/** Add the provided credentials to Ivy's credentials cache.*/ /** Add the provided credentials to Ivy's credentials cache.*/
def add(realm: String, host: String, userName: String, passwd: String): Unit = def add(realm: String, host: String, userName: String, passwd: String): Unit =
CredentialsStore.INSTANCE.addCredentials(realm, host, userName, passwd) CredentialsStore.INSTANCE.addCredentials(realm, host, userName, passwd)
/** Load credentials from the given file into Ivy's credentials cache.*/ /** Load credentials from the given file into Ivy's credentials cache.*/
def add(path: File, log: Logger): Unit = def add(path: File, log: Logger): Unit =
loadCredentials(path) match { loadCredentials(path) match {
@ -29,20 +30,26 @@ object Credentials {
def allDirect(sc: Seq[Credentials]): Seq[DirectCredentials] = sc map toDirect def allDirect(sc: Seq[Credentials]): Seq[DirectCredentials] = sc map toDirect
def toDirect(c: Credentials): DirectCredentials = c match { def toDirect(c: Credentials): DirectCredentials = c match {
case dc: DirectCredentials => dc case dc: DirectCredentials => dc
case fc: FileCredentials => loadCredentials(fc.path) match { case fc: FileCredentials =>
case Left(err) => sys.error(err) loadCredentials(fc.path) match {
case Right(dc) => dc case Left(err) => sys.error(err)
} case Right(dc) => dc
}
} }
def loadCredentials(path: File): Either[String, DirectCredentials] = def loadCredentials(path: File): Either[String, DirectCredentials] =
if (path.exists) { if (path.exists) {
val properties = read(path) 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 { 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 (Nil, List(realm, host, user, pass)) =>
case (errors, _) => Left(errors.mkString("\n")) Right(new DirectCredentials(realm, host, user, pass))
case (errors, _) => Left(errors.mkString("\n"))
} }
} else } else
Left("Credentials file " + path + " does not exist") Left("Credentials file " + path + " does not exist")
@ -59,16 +66,20 @@ object Credentials {
private[this] val PasswordKeys = List("password", "pwd", "pass", "passwd") private[this] val PasswordKeys = List("password", "pwd", "pass", "passwd")
import collection.JavaConverters._ import collection.JavaConverters._
private[this] def read(from: File): Map[String, String] = private[this] def read(from: File): Map[String, String] = {
{ val properties = new java.util.Properties
val properties = new java.util.Properties IO.load(properties, from)
IO.load(properties, from) properties.asScala.map { case (k, v) => (k.toString, v.toString.trim) }.toMap
properties.asScala.map { case (k, v) => (k.toString, v.toString.trim) }.toMap }
}
} }
sealed trait Credentials sealed trait Credentials
final class FileCredentials(val path: File) extends Credentials { final class FileCredentials(val path: File) extends Credentials {
override def toString = "FileCredentials('" + path + "')" override def toString = "FileCredentials('" + path + "')"
} }
final class DirectCredentials(val realm: String, val host: String, val userName: String, val passwd: String) extends Credentials final class DirectCredentials(
val realm: String,
val host: String,
val userName: String,
val passwd: String
) extends Credentials

View File

@ -6,6 +6,7 @@ import sbt.internal.librarymanagement.cross.CrossVersionUtil
final case class ScalaVersion(full: String, binary: String) final case class ScalaVersion(full: String, binary: String)
abstract class CrossVersionFunctions { 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. */ /** 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 val TransitionScalaVersion = CrossVersionUtil.TransitionScalaVersion
@ -50,7 +51,11 @@ abstract class CrossVersionFunctions {
* full version `fullVersion` and binary version `binaryVersion`. The behavior of the * full version `fullVersion` and binary version `binaryVersion`. The behavior of the
* constructed function is as documented for the [[sbt.librarymanagement.CrossVersion]] datatypes. * 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 { cross match {
case _: Disabled => None case _: Disabled => None
case b: Binary => append(b.prefix + binaryVersion + b.suffix) 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. */ /** Constructs the cross-version function defined by `module` and `is`, if one is configured. */
def apply(module: ModuleID, is: Option[IvyScala]): Option[String => String] = 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`. */ /** 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 { cross match {
case None => artifacts case None => artifacts
case Some(is) => substituteCrossA(artifacts, cross) case Some(is) => substituteCrossA(artifacts, cross)
@ -83,9 +93,14 @@ abstract class CrossVersionFunctions {
name + "_" + cross name + "_" + cross
/** Cross-versions `exclude` according to its `crossVersion`. */ /** 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] = 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)) exclude.withName(applyCross(exclude.name, fopt))
} }
@ -93,7 +108,10 @@ abstract class CrossVersionFunctions {
def substituteCross(a: Artifact, cross: Option[String => String]): Artifact = def substituteCross(a: Artifact, cross: Option[String => String]): Artifact =
a.withName(applyCross(a.name, cross)) 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)) as.map(art => substituteCross(art, cross))
/** /**
@ -101,14 +119,14 @@ abstract class CrossVersionFunctions {
* for the given full and binary Scala versions `scalaFullVersion` and `scalaBinaryVersion` * for the given full and binary Scala versions `scalaFullVersion` and `scalaBinaryVersion`
* according to the ModuleID's cross-versioning setting. * according to the ModuleID's cross-versioning setting.
*/ */
def apply(scalaFullVersion: String, scalaBinaryVersion: String): ModuleID => ModuleID = m => def apply(scalaFullVersion: String, scalaBinaryVersion: String): ModuleID => ModuleID = m => {
{ val cross = apply(m.crossVersion, scalaFullVersion, scalaBinaryVersion)
val cross = apply(m.crossVersion, scalaFullVersion, scalaBinaryVersion) if (cross.isDefined)
if (cross.isDefined) m.withName(applyCross(m.name, cross))
m.withName(applyCross(m.name, cross)).withExplicitArtifacts(substituteCrossA(m.explicitArtifacts, cross)) .withExplicitArtifacts(substituteCrossA(m.explicitArtifacts, cross))
else else
m m
} }
@deprecated("Use CrossVersion.isScalaApiCompatible or CrossVersion.isSbtApiCompatible", "0.13.0") @deprecated("Use CrossVersion.isScalaApiCompatible or CrossVersion.isSbtApiCompatible", "0.13.0")
def isStable(v: String): Boolean = isScalaApiCompatible(v) def isStable(v: String): Boolean = isScalaApiCompatible(v)
@ -152,6 +170,7 @@ abstract class CrossVersionFunctions {
def binarySbtVersion(full: String): String = CrossVersionUtil.binarySbtVersion(full) def binarySbtVersion(full: String): String = CrossVersionUtil.binarySbtVersion(full)
@deprecated("Use CrossVersion.scalaApiVersion or CrossVersion.sbtApiVersion", "0.13.0") @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)
} }

View File

@ -6,7 +6,8 @@ import sbt.internal.librarymanagement._
import sbt.util.Logger import sbt.util.Logger
import sbt.io.Hash 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[sbt] val ivySbt: IvySbt = new IvySbt(ivyConfiguration)
private val sbtOrgTemp = JsonUtil.sbtOrgTemp private val sbtOrgTemp = JsonUtil.sbtOrgTemp
private val modulePrefixTemp = "temp-module-" private val modulePrefixTemp = "temp-module-"
@ -22,12 +23,17 @@ class DefaultLibraryManagement(ivyConfiguration: IvyConfiguration, log: Logger)
def getModule(moduleId: ModuleID, ivyScala: Option[IvyScala]): ivySbt.Module = { def getModule(moduleId: ModuleID, ivyScala: Option[IvyScala]): ivySbt.Module = {
val sha1 = Hash.toHex(Hash(moduleId.name)) 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) getModule(dummyID, Vector(moduleId), UpdateOptions(), ivyScala)
} }
def getModule(moduleId: ModuleID, deps: Vector[ModuleID], def getModule(
uo: UpdateOptions = UpdateOptions(), ivyScala: Option[IvyScala]): ivySbt.Module = { moduleId: ModuleID,
deps: Vector[ModuleID],
uo: UpdateOptions = UpdateOptions(),
ivyScala: Option[IvyScala]
): ivySbt.Module = {
val moduleSetting = InlineConfiguration( val moduleSetting = InlineConfiguration(
validate = false, validate = false,
ivyScala = ivyScala, ivyScala = ivyScala,
@ -51,14 +57,29 @@ class DefaultLibraryManagement(ivyConfiguration: IvyConfiguration, log: Logger)
s"unknown" 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 specialArtifactTypes = Artifact.DefaultSourceTypes union Artifact.DefaultDocTypes
val artifactFilter = ArtifactTypeFilter.forbid(specialArtifactTypes) val artifactFilter = ArtifactTypeFilter.forbid(specialArtifactTypes)
val retrieveConfiguration = RetrieveConfiguration(retrieveDirectory, Resolver.defaultRetrievePattern).withSync(false) val retrieveConfiguration =
val updateConfiguration = UpdateConfiguration(Some(retrieveConfiguration), true, UpdateLogging.DownloadOnly, artifactFilter) 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.") 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) => case Left(unresolvedWarning) =>
log.debug(s"Couldn't retrieve module ${dependenciesNames(module)}.") log.debug(s"Couldn't retrieve module ${dependenciesNames(module)}.")
None None

View File

@ -6,13 +6,25 @@ package sbt.librarymanagement
import sbt.io.{ AllPassFilter, NameFilter } import sbt.io.{ AllPassFilter, NameFilter }
trait DependencyFilterExtra { 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 { 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 { 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 = def configurationFilter(name: NameFilter = AllPassFilter): ConfigurationFilter =
new ConfigurationFilter { new ConfigurationFilter {
@ -20,18 +32,32 @@ trait DependencyFilterExtra {
} }
} }
object DependencyFilter extends 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 { 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 { new DependencyFilter {
def apply(c: String, m: ModuleID, a: Artifact): Boolean = combine(x(c, m, a), y(c, m, a)) def apply(c: String, m: ModuleID, a: Artifact): Boolean = combine(x(c, m, a), y(c, m, a))
} }
def allPass: DependencyFilter = configurationFilter() def allPass: DependencyFilter = configurationFilter()
implicit def fnToModuleFilter(f: ModuleID => Boolean): ModuleFilter = new ModuleFilter { def apply(m: ModuleID) = f(m) } implicit def fnToModuleFilter(f: ModuleID => Boolean): ModuleFilter = new ModuleFilter {
implicit def fnToArtifactFilter(f: Artifact => Boolean): ArtifactFilter = new ArtifactFilter { def apply(m: Artifact) = f(m) } def apply(m: ModuleID) = f(m)
implicit def fnToConfigurationFilter(f: String => Boolean): ConfigurationFilter = new ConfigurationFilter { def apply(c: String) = f(c) } }
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 _ implicit def subDepFilterToFn[Arg](f: SubDepFilter[Arg, _]): Arg => Boolean = f apply _
} }
trait DependencyFilter { trait DependencyFilter {
@ -40,23 +66,34 @@ trait DependencyFilter {
final def ||(o: DependencyFilter) = DependencyFilter(this, o, _ || _) final def ||(o: DependencyFilter) = DependencyFilter(this, o, _ || _)
final def --(o: DependencyFilter) = DependencyFilter(this, o, _ && !_) final def --(o: DependencyFilter) = DependencyFilter(this, o, _ && !_)
} }
sealed trait SubDepFilter[Arg, Self <: SubDepFilter[Arg, Self]] extends DependencyFilter { self: Self => sealed trait SubDepFilter[Arg, Self <: SubDepFilter[Arg, Self]] extends DependencyFilter {
self: Self =>
def apply(a: Arg): Boolean def apply(a: Arg): Boolean
protected def make(f: Arg => Boolean): Self 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, _ || _) 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] { trait ModuleFilter extends SubDepFilter[ModuleID, ModuleFilter] {
protected final def make(f: ModuleID => Boolean) = new ModuleFilter { def apply(m: ModuleID) = f(m) } protected final def make(f: ModuleID => Boolean) = new ModuleFilter {
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean = apply(module) def apply(m: ModuleID) = f(m)
}
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean =
apply(module)
} }
trait ArtifactFilter extends SubDepFilter[Artifact, ArtifactFilter] { trait ArtifactFilter extends SubDepFilter[Artifact, ArtifactFilter] {
protected final def make(f: Artifact => Boolean) = new ArtifactFilter { def apply(m: Artifact) = f(m) } protected final def make(f: Artifact => Boolean) = new ArtifactFilter {
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean = apply(artifact) def apply(m: Artifact) = f(m)
}
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean =
apply(artifact)
} }
trait ConfigurationFilter extends SubDepFilter[String, ConfigurationFilter] { trait ConfigurationFilter extends SubDepFilter[String, ConfigurationFilter] {
protected final def make(f: String => Boolean) = new ConfigurationFilter { def apply(m: String) = f(m) } protected final def make(f: String => Boolean) = new ConfigurationFilter {
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean = apply(configuration) def apply(m: String) = f(m)
}
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean =
apply(configuration)
} }

View File

@ -8,13 +8,13 @@ import sbt.util.ShowLines
import sbt.internal.librarymanagement.{ InlineConfiguration, IvySbt } import sbt.internal.librarymanagement.{ InlineConfiguration, IvySbt }
final class EvictionWarningOptions private[sbt] ( final class EvictionWarningOptions private[sbt] (
val configurations: Seq[Configuration], val configurations: Seq[Configuration],
val warnScalaVersionEviction: Boolean, val warnScalaVersionEviction: Boolean,
val warnDirectEvictions: Boolean, val warnDirectEvictions: Boolean,
val warnTransitiveEvictions: Boolean, val warnTransitiveEvictions: Boolean,
val infoAllEvictions: Boolean, val infoAllEvictions: Boolean,
val showCallers: Boolean, val showCallers: Boolean,
val guessCompatible: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] val guessCompatible: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean]
) { ) {
private[sbt] def configStrings = configurations map { _.name } private[sbt] def configStrings = configurations map { _.name }
@ -30,17 +30,20 @@ final class EvictionWarningOptions private[sbt] (
copy(infoAllEvictions = infoAllEvictions) copy(infoAllEvictions = infoAllEvictions)
def withShowCallers(showCallers: Boolean): EvictionWarningOptions = def withShowCallers(showCallers: Boolean): EvictionWarningOptions =
copy(showCallers = showCallers) 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) copy(guessCompatible = guessCompatible)
private[sbt] def copy( private[sbt] def copy(
configurations: Seq[Configuration] = configurations, configurations: Seq[Configuration] = configurations,
warnScalaVersionEviction: Boolean = warnScalaVersionEviction, warnScalaVersionEviction: Boolean = warnScalaVersionEviction,
warnDirectEvictions: Boolean = warnDirectEvictions, warnDirectEvictions: Boolean = warnDirectEvictions,
warnTransitiveEvictions: Boolean = warnTransitiveEvictions, warnTransitiveEvictions: Boolean = warnTransitiveEvictions,
infoAllEvictions: Boolean = infoAllEvictions, infoAllEvictions: Boolean = infoAllEvictions,
showCallers: Boolean = showCallers, showCallers: Boolean = showCallers,
guessCompatible: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] = guessCompatible guessCompatible: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] =
guessCompatible
): EvictionWarningOptions = ): EvictionWarningOptions =
new EvictionWarningOptions( new EvictionWarningOptions(
configurations = configurations, configurations = configurations,
@ -63,19 +66,26 @@ object EvictionWarningOptions {
lazy val defaultGuess: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] = lazy val defaultGuess: Function1[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] =
guessSecondSegment orElse guessSemVer orElse guessFalse guessSecondSegment orElse guessSemVer orElse guessFalse
lazy val guessSecondSegment: PartialFunction[(ModuleID, Option[ModuleID], Option[IvyScala]), Boolean] = { lazy val guessSecondSegment
case (m1, Some(m2), Some(ivyScala)) if m2.name.endsWith("_" + ivyScala.scalaFullVersion) || m2.name.endsWith("_" + ivyScala.scalaBinaryVersion) => : 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 { (m1.revision, m2.revision) match {
case (VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2)) => 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 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), _) => case (m1, Some(m2), _) =>
(m1.revision, m2.revision) match { (m1.revision, m2.revision) match {
case (VersionNumber(ns1, ts1, es1), VersionNumber(ns2, ts2, es2)) => 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 case _ => false
} }
} }
@ -85,12 +95,12 @@ object EvictionWarningOptions {
} }
final class EvictionPair private[sbt] ( final class EvictionPair private[sbt] (
val organization: String, val organization: String,
val name: String, val name: String,
val winner: Option[ModuleReport], val winner: Option[ModuleReport],
val evicteds: Vector[ModuleReport], val evicteds: Vector[ModuleReport],
val includesDirect: Boolean, val includesDirect: Boolean,
val showCallers: Boolean val showCallers: Boolean
) { ) {
override def toString: String = override def toString: String =
EvictionPair.evictionPairLines.showLines(this).mkString EvictionPair.evictionPairLines.showLines(this).mkString
@ -118,8 +128,7 @@ object EvictionPair {
r.callers match { r.callers match {
case Seq() => "" case Seq() => ""
case cs => (cs map { _.caller.toString }).mkString(" (caller: ", ", ", ")") case cs => (cs map { _.caller.toString }).mkString(" (caller: ", ", ", ")")
} } else ""
else ""
r.module.revision + callers r.module.revision + callers
}) map { " -> " + _ } getOrElse "" }) map { " -> " + _ } getOrElse ""
Seq(s"\t* ${a.organization}:${a.name}:${revsStr}$winnerRev") Seq(s"\t* ${a.organization}:${a.name}:${revsStr}$winnerRev")
@ -127,29 +136,42 @@ object EvictionPair {
} }
final class EvictionWarning private[sbt] ( final class EvictionWarning private[sbt] (
val options: EvictionWarningOptions, val options: EvictionWarningOptions,
val scalaEvictions: Seq[EvictionPair], val scalaEvictions: Seq[EvictionPair],
val directEvictions: Seq[EvictionPair], val directEvictions: Seq[EvictionPair],
val transitiveEvictions: Seq[EvictionPair], val transitiveEvictions: Seq[EvictionPair],
val allEvictions: 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) private[sbt] def infoAllTheThings: List[String] = EvictionWarning.infoAllTheThings(this)
} }
object EvictionWarning { 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) val evictions = buildEvictions(options, report)
processEvictions(module, options, evictions) 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 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 => confs flatMap { confReport =>
confReport.details map { detail => confReport.details map { detail =>
if ((detail.modules exists { _.evicted }) && 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 buffer += detail
} }
} }
@ -157,7 +179,11 @@ object EvictionWarning {
buffer.toList.toVector 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 { module.moduleSettings.ivyScala match {
case Some(s) => case Some(s) =>
organization == s.scalaOrganization && organization == s.scalaOrganization &&
@ -165,7 +191,11 @@ object EvictionWarning {
case _ => false 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 { val directDependencies = module.moduleSettings match {
case x: InlineConfiguration => x.dependencies case x: InlineConfiguration => x.dependencies
case _ => Vector.empty case _ => Vector.empty
@ -178,19 +208,29 @@ object EvictionWarning {
(directDependencies exists { dep => (directDependencies exists { dep =>
(detail.organization == dep.organization) && (detail.name == dep.name) (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 scalaEvictions: mutable.ListBuffer[EvictionPair] = mutable.ListBuffer()
val directEvictions: mutable.ListBuffer[EvictionPair] = mutable.ListBuffer() val directEvictions: mutable.ListBuffer[EvictionPair] = mutable.ListBuffer()
val transitiveEvictions: mutable.ListBuffer[EvictionPair] = mutable.ListBuffer() val transitiveEvictions: mutable.ListBuffer[EvictionPair] = mutable.ListBuffer()
def guessCompatible(p: EvictionPair): Boolean = def guessCompatible(p: EvictionPair): Boolean =
p.evicteds forall { r => 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 { pairs foreach {
case p if isScalaArtifact(module, p.organization, p.name) => case p if isScalaArtifact(module, p.organization, p.name) =>
(module.moduleSettings.ivyScala, p.winner) match { (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 scalaEvictions += p
case _ => case _ =>
} }
@ -203,8 +243,13 @@ object EvictionWarning {
transitiveEvictions += p transitiveEvictions += p
} }
} }
new EvictionWarning(options, scalaEvictions.toList, new EvictionWarning(
directEvictions.toList, transitiveEvictions.toList, pairs) options,
scalaEvictions.toList,
directEvictions.toList,
transitiveEvictions.toList,
pairs
)
} }
implicit val evictionWarningLines: ShowLines[EvictionWarning] = ShowLines { a: EvictionWarning => implicit val evictionWarningLines: ShowLines[EvictionWarning] = ShowLines { a: EvictionWarning =>

View File

@ -14,7 +14,10 @@ abstract class ArtifactTypeFilterExtra {
def types: Set[String] def types: Set[String]
def inverted: Boolean 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 invert = copy(inverted = !inverted)
def apply(a: descriptor.Artifact): Boolean = (types contains a.getType) ^ 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) def forbid(types: Set[String]) = ArtifactTypeFilter(types, true)
implicit def toIvyFilter(f: ArtifactTypeFilter): IvyFilter = new IvyFilter { 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)
}
} }
} }

View File

@ -26,10 +26,17 @@ object ScalaArtifacts {
def libraryDependency(version: String): ModuleID = ModuleID(Organization, LibraryID, version) 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) if (isDotty)
Seq(ModuleID(org, DottyIDPrefix, version).withConfigurations(Some(Configurations.ScalaTool.name + "->default(compile)")) Seq(
.withCrossVersion(CrossVersion.binary)) ModuleID(org, DottyIDPrefix, version)
.withConfigurations(Some(Configurations.ScalaTool.name + "->default(compile)"))
.withCrossVersion(CrossVersion.binary)
)
else else
Seq( Seq(
scalaToolDependency(org, ScalaArtifacts.CompilerID, version), scalaToolDependency(org, ScalaArtifacts.CompilerID, version),
@ -37,7 +44,9 @@ object ScalaArtifacts {
) )
private[this] def scalaToolDependency(org: String, id: String, version: String): ModuleID = 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 { object SbtArtifacts {
val Organization = "org.scala-sbt" val Organization = "org.scala-sbt"
@ -46,17 +55,39 @@ object SbtArtifacts {
import ScalaArtifacts._ import ScalaArtifacts._
private[sbt] abstract class IvyScalaFunctions { private[sbt] abstract class IvyScalaFunctions {
/** Performs checks/adds filters on Scala dependencies (if enabled in IvyScala). */ /** 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) 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) if (check.filterImplicit)
excludeScalaJars(module, check.configurations) excludeScalaJars(module, check.configurations)
if (check.overrideScalaVersion) 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 private[this] val scalaVersionConfigs = scalaVersionConfigs0.toSet
def mediate(dd: DependencyDescriptor): DependencyDescriptor = { def mediate(dd: DependencyDescriptor): DependencyDescriptor = {
// Mediate only for the dependencies in scalaVersion configurations. https://github.com/sbt/sbt/issues/2786 // 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 if (mrid == null) mrid
else else
mrid.getName match { mrid.getName match {
case name @ (CompilerID | LibraryID | ReflectID | ActorsID | ScalapID) if configQualifies && dependeeQualifies => case name @ (CompilerID | LibraryID | ReflectID | ActorsID | ScalapID)
ModuleRevisionId.newInstance(scalaOrganization, name, mrid.getBranch, scalaVersion, mrid.getQualifiedExtraAttributes) if configQualifies && dependeeQualifies =>
ModuleRevisionId.newInstance(
scalaOrganization,
name,
mrid.getBranch,
scalaVersion,
mrid.getQualifiedExtraAttributes
)
case _ => mrid 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) 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) 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 id = new ModuleId(org, name)
val over = new OverrideDependencyDescriptorMediator(null, version) val over = new OverrideDependencyDescriptorMediator(null, version)
module.addDependencyDescriptorMediator(id, ExactPatternMatcher.INSTANCE, over) 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 * Checks the immediate dependencies of module for dependencies on scala jars and verifies that the version on the
* dependencies matches scalaVersion. * dependencies matches scalaVersion.
*/ */
private def checkDependencies(module: ModuleDescriptor, scalaOrganization: String, scalaArtifacts: Vector[String], scalaBinaryVersion: String, scalaVersionConfigs0: Vector[String], log: Logger): Unit = { private def checkDependencies(
val scalaVersionConfigs: String => Boolean = if (scalaVersionConfigs0.isEmpty) (c: String) => false else scalaVersionConfigs0.toSet module: ModuleDescriptor,
def binaryScalaWarning(dep: DependencyDescriptor): Option[String] = scalaOrganization: String,
{ scalaArtifacts: Vector[String],
val id = dep.getDependencyRevisionId scalaBinaryVersion: String,
val depBinaryVersion = CrossVersion.binaryScalaVersion(id.getRevision) scalaVersionConfigs0: Vector[String],
def isScalaLangOrg = id.getOrganisation == scalaOrganization log: Logger
def isScalaArtifact = scalaArtifacts.contains(id.getName) ): Unit = {
def hasBinVerMismatch = depBinaryVersion != scalaBinaryVersion val scalaVersionConfigs: String => Boolean =
def matchesOneOfTheConfigs = dep.getModuleConfigurations exists { scalaVersionConfigs } if (scalaVersionConfigs0.isEmpty) (c: String) => false else scalaVersionConfigs0.toSet
val mismatched = isScalaLangOrg && isScalaArtifact && hasBinVerMismatch && matchesOneOfTheConfigs def binaryScalaWarning(dep: DependencyDescriptor): Option[String] = {
if (mismatched) val id = dep.getDependencyRevisionId
Some("Binary version (" + depBinaryVersion + ") for dependency " + id + 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 + "\n\tin " + module.getModuleRevisionId +
" differs from Scala binary version in project (" + scalaBinaryVersion + ").") " differs from Scala binary version in project (" + scalaBinaryVersion + ")."
else )
None else
} None
module.getDependencies.toList.flatMap(binaryScalaWarning).toSet foreach { (s: String) => log.warn(s) } }
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 * 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 * 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. * is done by setting scalaVersion in the project definition.
*/ */
private def excludeScalaJars(module: DefaultModuleDescriptor, configurations: Iterable[Configuration]): Unit = { private def excludeScalaJars(
val configurationNames = module: DefaultModuleDescriptor,
{ configurations: Iterable[Configuration]
val names = module.getConfigurationsNames ): Unit = {
if (configurations.isEmpty) val configurationNames = {
names val names = module.getConfigurationsNames
else { if (configurations.isEmpty)
val configSet = configurationSet(configurations) names
configSet.intersect(HashSet(names: _*)) else {
configSet.toArray val configSet = configurationSet(configurations)
} configSet.intersect(HashSet(names: _*))
configSet.toArray
} }
}
def excludeScalaJar(name: String): Unit = def excludeScalaJar(name: String): Unit =
module.addExcludeRule(excludeRule(Organization, name, configurationNames, "jar")) module.addExcludeRule(excludeRule(Organization, name, configurationNames, "jar"))
excludeScalaJar(LibraryID) excludeScalaJar(LibraryID)
excludeScalaJar(CompilerID) excludeScalaJar(CompilerID)
} }
/** /**
* Creates an ExcludeRule that excludes artifacts with the given module organization and name for * Creates an ExcludeRule that excludes artifacts with the given module organization and name for
* the given configurations. * the given configurations.
*/ */
private[sbt] def excludeRule(organization: String, name: String, configurationNames: Iterable[String], excludeTypePattern: String): ExcludeRule = private[sbt] def excludeRule(
{ organization: String,
val artifact = new ArtifactId(ModuleId.newInstance(organization, name), "*", excludeTypePattern, "*") name: String,
val rule = new DefaultExcludeRule(artifact, ExactPatternMatcher.INSTANCE, emptyMap[AnyRef, AnyRef]) configurationNames: Iterable[String],
configurationNames.foreach(rule.addConfiguration) excludeTypePattern: String
rule ): 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 * Creates an IncludeRule that includes artifacts with the given module organization and name for
* the given configurations. * the given configurations.
*/ */
private[sbt] def includeRule(organization: String, name: String, configurationNames: Iterable[String], includeTypePattern: String): IncludeRule = private[sbt] def includeRule(
{ organization: String,
val artifact = new ArtifactId(ModuleId.newInstance(organization, name), "*", includeTypePattern, "*") name: String,
val rule = new DefaultIncludeRule(artifact, ExactPatternMatcher.INSTANCE, emptyMap[AnyRef, AnyRef]) configurationNames: Iterable[String],
configurationNames.foreach(rule.addConfiguration) includeTypePattern: String
rule ): 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
}
} }

View File

@ -24,53 +24,56 @@ abstract class ModuleIDExtra {
def branchName: Option[String] def branchName: Option[String]
protected[this] def copy( protected[this] def copy(
organization: String = organization, organization: String = organization,
name: String = name, name: String = name,
revision: String = revision, revision: String = revision,
configurations: Option[String] = configurations, configurations: Option[String] = configurations,
isChanging: Boolean = isChanging, isChanging: Boolean = isChanging,
isTransitive: Boolean = isTransitive, isTransitive: Boolean = isTransitive,
isForce: Boolean = isForce, isForce: Boolean = isForce,
explicitArtifacts: Vector[Artifact] = explicitArtifacts, explicitArtifacts: Vector[Artifact] = explicitArtifacts,
inclusions: Vector[InclusionRule] = inclusions, inclusions: Vector[InclusionRule] = inclusions,
exclusions: Vector[ExclusionRule] = exclusions, exclusions: Vector[ExclusionRule] = exclusions,
extraAttributes: Map[String, String] = extraAttributes, extraAttributes: Map[String, String] = extraAttributes,
crossVersion: CrossVersion = crossVersion, crossVersion: CrossVersion = crossVersion,
branchName: Option[String] = branchName branchName: Option[String] = branchName
): ModuleID ): ModuleID
protected def toStringImpl: String = protected def toStringImpl: String =
s"""$organization:$name:$revision""" + s"""$organization:$name:$revision""" +
(configurations match { case Some(s) => ":" + s; case None => "" }) + (configurations match { case Some(s) => ":" + s; case None => "" }) + {
{ val attr = attributeString
val attr = attributeString if (attr == "") ""
if (attr == "") "" else " " + attr
else " " + attr } +
} +
(if (extraAttributes.isEmpty) "" else " " + extraString) (if (extraAttributes.isEmpty) "" else " " + extraString)
protected def attributeString: String = protected def attributeString: String = {
{ val buffer = ListBuffer.empty[String]
val buffer = ListBuffer.empty[String] if (isChanging) {
if (isChanging) { buffer += "changing"
buffer += "changing"
}
if (!isTransitive) {
buffer += "intransitive"
}
if (isForce) {
buffer += "force"
}
buffer.toList.mkString(";")
} }
if (!isTransitive) {
buffer += "intransitive"
}
if (isForce) {
buffer += "force"
}
buffer.toList.mkString(";")
}
/** String representation of the extra attributes, excluding any information only attributes. */ /** 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). */ /** 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()) def cross(v: Boolean): ModuleID = cross(if (v) CrossVersion.binary else Disabled())
/** Specifies the cross-version behavior for this module. See [CrossVersion] for details.*/ /** 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, * 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. * 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 * 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) 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. */ /** 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. * 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. * 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 * 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 { abstract class ModuleIDFunctions {
/** Prefixes all keys with `e:` if they are not already so prefixed. */ /** Prefixes all keys with `e:` if they are not already so prefixed. */
def checkE(attributes: Seq[(String, String)]) = 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)
} }

View File

@ -18,12 +18,11 @@ final class RawRepository(val resolver: DependencyResolver) extends Resolver(res
case _ => false case _ => false
} }
override def hashCode: Int = override def hashCode: Int = {
{ var hash = 1
var hash = 1 hash = hash * 31 + this.name.##
hash = hash * 31 + this.name.## hash
hash }
}
} }
abstract class MavenRepositoryFunctions { abstract class MavenRepositoryFunctions {
@ -37,11 +36,15 @@ abstract class PatternsFunctions {
def apply(artifactPatterns: String*): Patterns = Patterns(true, artifactPatterns: _*) def apply(artifactPatterns: String*): Patterns = Patterns(true, artifactPatterns: _*)
def apply(isMavenCompatible: Boolean, artifactPatterns: String*): Patterns = { def apply(isMavenCompatible: Boolean, artifactPatterns: String*): Patterns = {
val patterns = artifactPatterns.toVector val patterns = artifactPatterns.toVector
Patterns().withIvyPatterns(patterns).withArtifactPatterns(patterns).withIsMavenCompatible(isMavenCompatible) Patterns()
.withIvyPatterns(patterns)
.withArtifactPatterns(patterns)
.withIsMavenCompatible(isMavenCompatible)
} }
} }
trait SshBasedRepositoryExtra { trait SshBasedRepositoryExtra {
/** The object representing the configured ssh connection for this repository. */ /** The object representing the configured ssh connection for this repository. */
def connection: SshConnection 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. */ /** 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, password: String): RepositoryType = as(user, Some(password))
def as(user: String): RepositoryType = as(user, None) 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. */ /** 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): 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 = def as(user: String, keyfile: File, password: Option[String]): RepositoryType =
copy(KeyFileAuthentication(user, keyfile, password)) copy(KeyFileAuthentication(user, keyfile, password))
@ -80,7 +85,8 @@ trait SftpRepositoryExtra extends SshBasedRepositoryExtra {
type RepositoryType = SftpRepository 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 */ /** A repository that conforms to sbt launcher's interface */
@ -96,7 +102,8 @@ trait ResolversSyntax {
} }
abstract class ResolverFunctions { 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 TypesafeRepositoryRoot = typesafeRepositoryRoot(useSecureResolvers)
val SbtRepositoryRoot = sbtRepositoryRoot(useSecureResolvers) val SbtRepositoryRoot = sbtRepositoryRoot(useSecureResolvers)
@ -109,31 +116,49 @@ abstract class ResolverFunctions {
val JCenterRepositoryRoot = "https://jcenter.bintray.com/" val JCenterRepositoryRoot = "https://jcenter.bintray.com/"
val DefaultMavenRepositoryRoot = "https://repo1.maven.org/maven2/" val DefaultMavenRepositoryRoot = "https://repo1.maven.org/maven2/"
// TODO: This switch is only kept for backward compatibility. Hardcode to HTTPS in the future. // 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. // TODO: This switch is only kept for backward compatibility. Hardcode to HTTPS in the future.
private[sbt] def javanet2RepositoryRoot(secure: Boolean) = private[sbt] def javanet2RepositoryRoot(secure: Boolean) =
if (secure) "https://maven.java.net/content/repositories/public/" if (secure) "https://maven.java.net/content/repositories/public/"
else "http://download.java.net/maven/2" else "http://download.java.net/maven/2"
// TODO: This switch is only kept for backward compatibility. Hardcode to HTTPS in the future. // 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. // 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 // obsolete: kept only for launcher compatibility
private[sbt] val ScalaToolsReleasesName = "Sonatype OSS Releases" private[sbt] val ScalaToolsReleasesName = "Sonatype OSS Releases"
private[sbt] val ScalaToolsSnapshotsName = "Sonatype OSS Snapshots" private[sbt] val ScalaToolsSnapshotsName = "Sonatype OSS Snapshots"
private[sbt] val ScalaToolsReleasesRoot = SonatypeRepositoryRoot + "/releases" private[sbt] val ScalaToolsReleasesRoot = SonatypeRepositoryRoot + "/releases"
private[sbt] val ScalaToolsSnapshotsRoot = SonatypeRepositoryRoot + "/snapshots" private[sbt] val ScalaToolsSnapshotsRoot = SonatypeRepositoryRoot + "/snapshots"
private[sbt] val ScalaToolsReleases = MavenRepository(ScalaToolsReleasesName, ScalaToolsReleasesRoot) private[sbt] val ScalaToolsReleases =
private[sbt] val ScalaToolsSnapshots = MavenRepository(ScalaToolsSnapshotsName, ScalaToolsSnapshotsRoot) MavenRepository(ScalaToolsReleasesName, ScalaToolsReleasesRoot)
private[sbt] val ScalaToolsSnapshots =
MavenRepository(ScalaToolsSnapshotsName, ScalaToolsSnapshotsRoot)
def typesafeRepo(status: String) = MavenRepository("typesafe-" + status, TypesafeRepositoryRoot + "/" + status) def typesafeRepo(status: String) =
def typesafeIvyRepo(status: String) = url("typesafe-ivy-" + status, new URL(TypesafeRepositoryRoot + "/ivy-" + status + "/"))(ivyStylePatterns) MavenRepository("typesafe-" + status, TypesafeRepositoryRoot + "/" + status)
def sbtIvyRepo(status: String) = url(s"sbt-ivy-$status", new URL(s"$SbtRepositoryRoot/ivy-$status/"))(ivyStylePatterns) def typesafeIvyRepo(status: String) =
def sbtPluginRepo(status: String) = url("sbt-plugin-" + status, new URL(SbtRepositoryRoot + "/sbt-plugin-" + status + "/"))(ivyStylePatterns) url("typesafe-ivy-" + status, new URL(TypesafeRepositoryRoot + "/ivy-" + status + "/"))(
def sonatypeRepo(status: String) = MavenRepository("sonatype-" + status, SonatypeRepositoryRoot + "/" + status) ivyStylePatterns
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 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 def jcenterRepo = JCenterRepository
/** Add the local and Maven Central repositories to the user repositories. */ /** 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 `jcenter` is true, add the JCenter.
* If `mavenCentral` is true, add the Maven Central repository. * 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) ++ Seq(Resolver.defaultLocal) ++
userResolvers ++ userResolvers ++
single(JCenterRepository, jcenter) ++ single(JCenterRepository, jcenter) ++
@ -163,7 +192,11 @@ abstract class ResolverFunctions {
* If `jcenter` is true, add the JCenter. * If `jcenter` is true, add the JCenter.
* If `mavenCentral` is true, add the Maven Central repository. * 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 { appResolvers.partition(_ == Resolver.defaultLocal) match {
case (locals, xs) => case (locals, xs) =>
locals ++ 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. */ /** A base class for defining factories for interfaces to Ivy repositories that require a hostname , port, and patterns. */
sealed abstract class Define[RepositoryType <: SshBasedRepository] { sealed abstract class Define[RepositoryType <: SshBasedRepository] {
/** Subclasses should implement this method to */ /** 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 * 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. * 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 = def apply(name: String)(implicit basePatterns: Patterns): RepositoryType =
apply(name, None, None, None) apply(name, None, None, None)
/** /**
* Constructs this repository type with the given `name` and `hostname`. `basePatterns` are the initial patterns to use. * 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. * 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 = def apply(name: String, hostname: String)(implicit basePatterns: Patterns): RepositoryType =
apply(name, Some(hostname), None, None) apply(name, Some(hostname), None, None)
/** /**
* Constructs this repository type with the given `name`, `hostname`, and the `basePath` against which the initial * 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. * 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. * 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)) 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. * 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. * 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) apply(name, Some(hostname), Some(port), None)
/** /**
* Constructs this repository type with the given `name`, `hostname`, `port`, and the `basePath` against which the initial * 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. * 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. * 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)) 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 * 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). * 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. * 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)) construct(name, SshConnection(None, hostname, port), resolvePatterns(basePath, basePatterns))
} }
/** A factory to construct an interface to an Ivy SSH resolver.*/ /** A factory to construct an interface to an Ivy SSH resolver.*/
object ssh extends Define[SshRepository] { 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.*/ /** A factory to construct an interface to an Ivy SFTP resolver.*/
object sftp extends Define[SftpRepository] { 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. */ /** A factory to construct an interface to an Ivy filesystem resolver. */
object file { object file {
/** /**
* Constructs a file resolver with the given name. The patterns to use must be explicitly specified * 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. * 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. */ /** Constructs a file resolver with the given name and base directory. */
def apply(name: String, baseDirectory: File)(implicit basePatterns: Patterns): FileRepository = 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 { object url {
/** /**
* Constructs a URL resolver with the given name. The patterns to use must be explicitly specified * 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. * using the `ivys` or `artifacts` methods on the constructed resolver object.
*/ */
def apply(name: String): URLRepository = URLRepository(name, Patterns(false)) def apply(name: String): URLRepository = URLRepository(name, Patterns(false))
/** Constructs a file resolver with the given name and base directory. */ /** Constructs a file resolver with the given name and base directory. */
def apply(name: String, baseURL: URL)(implicit basePatterns: Patterns): URLRepository = def apply(name: String, baseURL: URL)(implicit basePatterns: Patterns): URLRepository =
baseRepository(baseURL.toURI.normalize.toString)(URLRepository(name, _)) 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)) construct(resolvePatterns(base, basePatterns))
/** /**
@ -264,41 +330,53 @@ abstract class ResolverFunctions {
case Some(path) => resolvePatterns(path, patterns) case Some(path) => resolvePatterns(path, patterns)
case None => patterns case None => patterns
} }
/** Resolves the ivy file and artifact patterns in `patterns` against the given base. */ /** Resolves the ivy file and artifact patterns in `patterns` against the given base. */
private def resolvePatterns(base: String, basePatterns: Patterns): Patterns = private def resolvePatterns(base: String, basePatterns: Patterns): Patterns = {
{ def resolveAll(patterns: Vector[String]) = patterns.map(p => resolvePattern(base, p))
def resolveAll(patterns: Vector[String]) = patterns.map(p => resolvePattern(base, p)) Patterns(
Patterns(resolveAll(basePatterns.ivyPatterns), resolveAll(basePatterns.artifactPatterns), basePatterns.isMavenCompatible, basePatterns.descriptorOptional, basePatterns.skipConsistencyCheck) resolveAll(basePatterns.ivyPatterns),
} resolveAll(basePatterns.artifactPatterns),
private[sbt] def resolvePattern(base: String, pattern: String): String = basePatterns.isMavenCompatible,
{ basePatterns.descriptorOptional,
val normBase = base.replace('\\', '/') basePatterns.skipConsistencyCheck
if (normBase.endsWith("/") || pattern.startsWith("/")) normBase + pattern else normBase + "/" + pattern )
} }
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 defaultFileConfiguration = FileConfiguration(true, None)
def mavenStylePatterns = Patterns().withArtifactPatterns(Vector(mavenStyleBasePattern)) def mavenStylePatterns = Patterns().withArtifactPatterns(Vector(mavenStyleBasePattern))
def ivyStylePatterns = defaultIvyPatterns //Patterns(Nil, Nil, false) def ivyStylePatterns = defaultIvyPatterns //Patterns(Nil, Nil, false)
def defaultPatterns = mavenStylePatterns def defaultPatterns = mavenStylePatterns
def mavenStyleBasePattern = "[organisation]/[module](_[scalaVersion])(_[sbtVersion])/[revision]/[artifact]-[revision](-[classifier]).[ext]" def mavenStyleBasePattern =
def localBasePattern = "[organisation]/[module]/" + PluginPattern + "(/[branch])/[revision]/[type]s/[artifact](-[classifier]).[ext]" "[organisation]/[module](_[scalaVersion])(_[sbtVersion])/[revision]/[artifact]-[revision](-[classifier]).[ext]"
def defaultRetrievePattern = "[type]s/[organisation]/[module]/" + PluginPattern + "[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]/)" final val PluginPattern = "(scala_[scalaVersion]/)(sbt_[sbtVersion]/)"
private[this] def mavenLocalDir: File = { private[this] def mavenLocalDir: File = {
def loadHomeFromSettings(f: () => File): Option[File] = def loadHomeFromSettings(f: () => File): Option[File] =
try { try {
val file = f() val file = f()
if (!file.exists) None if (!file.exists) None
else ((XML.loadFile(file) \ "localRepository").text match { else
case "" => None ((XML.loadFile(file) \ "localRepository").text match {
case e @ _ => Some(new File(e)) case "" => None
}) case e @ _ => Some(new File(e))
})
} catch { } catch {
// Occurs inside File constructor when property or environment variable does not exist // Occurs inside File constructor when property or environment variable does not exist
case _: NullPointerException => None case _: NullPointerException => None
// Occurs when File does not exist // Occurs when File does not exist
case _: IOException => None case _: IOException => None
case e: SAXParseException => System.err.println(s"WARNING: Problem parsing ${f().getAbsolutePath}, ${e.getMessage}"); 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(sbt.io.Path.userHome, ".m2/settings.xml")) orElse
loadHomeFromSettings(() => new File(new File(System.getenv("M2_HOME")), "conf/settings.xml")) getOrElse 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 mavenLocal: MavenRepository = new MavenCache("Maven2 Local", mavenLocalDir)
def defaultLocal = defaultUserFileRepository("local") def defaultLocal = defaultUserFileRepository("local")
def defaultShared = defaultUserFileRepository("shared") def defaultShared = defaultUserFileRepository("shared")
def defaultUserFileRepository(id: String) = def defaultUserFileRepository(id: String) = {
{ val pList = Vector(s"$${ivy.home}/$id/$localBasePattern")
val pList = Vector(s"$${ivy.home}/$id/$localBasePattern") FileRepository(
FileRepository(id, defaultFileConfiguration, Patterns().withIvyPatterns(pList).withArtifactPatterns(pList).withIsMavenCompatible(false)) id,
} defaultFileConfiguration,
def defaultIvyPatterns =
{
val pList = Vector(localBasePattern)
Patterns().withIvyPatterns(pList).withArtifactPatterns(pList).withIsMavenCompatible(false) Patterns().withIvyPatterns(pList).withArtifactPatterns(pList).withIsMavenCompatible(false)
} )
}
def defaultIvyPatterns = {
val pList = Vector(localBasePattern)
Patterns().withIvyPatterns(pList).withArtifactPatterns(pList).withIsMavenCompatible(false)
}
} }

View File

@ -8,12 +8,11 @@ import java.io.File
* and for obtaining references to a selected subset of the underlying files. * and for obtaining references to a selected subset of the underlying files.
*/ */
final class RichUpdateReport(report: UpdateReport) { final class RichUpdateReport(report: UpdateReport) {
private[sbt] def recomputeStamps(): UpdateReport = private[sbt] def recomputeStamps(): UpdateReport = {
{ val files = report.cachedDescriptor +: allFiles
val files = report.cachedDescriptor +: allFiles val stamps = files.map(f => (f, f.lastModified)).toMap
val stamps = files.map(f => (f, f.lastModified)).toMap UpdateReport(report.cachedDescriptor, report.configurations, report.stats, stamps)
UpdateReport(report.cachedDescriptor, report.configurations, report.stats, stamps) }
}
import DependencyFilter._ import DependencyFilter._
@ -24,12 +23,19 @@ final class RichUpdateReport(report: UpdateReport) {
def matching(f: DependencyFilter): Vector[File] = select0(f).distinct def matching(f: DependencyFilter): Vector[File] = select0(f).distinct
/** Obtains all successfully retrieved files matching all provided filters. */ /** 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)) matching(DependencyFilter.make(configuration, module, artifact))
def select(configuration: ConfigurationFilter): Vector[File] = select(configuration, moduleFilter(), artifactFilter()) def select(configuration: ConfigurationFilter): Vector[File] =
def select(module: ModuleFilter): Vector[File] = select(configurationFilter(), module, artifactFilter()) select(configuration, moduleFilter(), artifactFilter())
def select(artifact: ArtifactFilter): Vector[File] = select(configurationFilter(), moduleFilter(), artifact) 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] = private[this] def select0(f: DependencyFilter): Vector[File] =
for { for {
@ -39,7 +45,9 @@ final class RichUpdateReport(report: UpdateReport) {
if f(cReport.configuration, mReport.module, artifact) if f(cReport.configuration, mReport.module, artifact)
} yield { } yield {
if (file == null) { 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 file
} }
@ -49,14 +57,20 @@ final class RichUpdateReport(report: UpdateReport) {
moduleReportMap { (configuration, modReport) => moduleReportMap { (configuration, modReport) =>
modReport modReport
.withArtifacts( .withArtifacts(
modReport.artifacts filter { case (art, file) => f(configuration, modReport.module, art) } modReport.artifacts filter {
case (art, file) => f(configuration, modReport.module, art)
}
) )
.withMissingArtifacts( .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) => moduleReportMap { (configuration, modReport) =>
val newArtifacts = f(configuration, modReport.module, modReport.artifacts) val newArtifacts = f(configuration, modReport.module, modReport.artifacts)
modReport modReport
@ -85,13 +99,14 @@ final class RichUpdateReport(report: UpdateReport) {
.withMissingArtifacts((modReport.missingArtifacts ++ f(modReport.module)).distinct) .withMissingArtifacts((modReport.missingArtifacts ++ f(modReport.module)).distinct)
} }
private[sbt] def moduleReportMap(f: (String, ModuleReport) => ModuleReport): UpdateReport = private[sbt] def moduleReportMap(f: (String, ModuleReport) => ModuleReport): UpdateReport = {
{ val newConfigurations = report.configurations.map { confReport =>
val newConfigurations = report.configurations.map { confReport => import confReport._
import confReport._ val newModules = modules map { modReport =>
val newModules = modules map { modReport => f(configuration, modReport) } f(configuration, modReport)
ConfigurationReport(configuration, newModules, details)
} }
UpdateReport(report.cachedDescriptor, newConfigurations, report.stats, report.stamps) ConfigurationReport(configuration, newModules, details)
} }
UpdateReport(report.cachedDescriptor, newConfigurations, report.stats, report.stamps)
}
} }

View File

@ -12,20 +12,22 @@ import sbt.util.Logger
* See also UpdateConfiguration in IvyActions.scala. * See also UpdateConfiguration in IvyActions.scala.
*/ */
final class UpdateOptions private[sbt] ( final class UpdateOptions private[sbt] (
// If set to CircularDependencyLevel.Error, halt the dependency resolution. // If set to CircularDependencyLevel.Error, halt the dependency resolution.
val circularDependencyLevel: CircularDependencyLevel, val circularDependencyLevel: CircularDependencyLevel,
// If set to true, prioritize inter-project resolver // If set to true, prioritize inter-project resolver
val interProjectFirst: Boolean, val interProjectFirst: Boolean,
// If set to true, check all resolvers for snapshots. // If set to true, check all resolvers for snapshots.
val latestSnapshots: Boolean, val latestSnapshots: Boolean,
// If set to true, use consolidated resolution. // If set to true, use consolidated resolution.
val consolidatedResolution: Boolean, val consolidatedResolution: Boolean,
// If set to true, use cached resolution. // If set to true, use cached resolution.
val cachedResolution: Boolean, val cachedResolution: Boolean,
// Extension point for an alternative resolver converter. // Extension point for an alternative resolver converter.
val resolverConverter: UpdateOptions.ResolverConverter val resolverConverter: UpdateOptions.ResolverConverter
) { ) {
def withCircularDependencyLevel(circularDependencyLevel: CircularDependencyLevel): UpdateOptions = def withCircularDependencyLevel(
circularDependencyLevel: CircularDependencyLevel
): UpdateOptions =
copy(circularDependencyLevel = circularDependencyLevel) copy(circularDependencyLevel = circularDependencyLevel)
def withInterProjectFirst(interProjectFirst: Boolean): UpdateOptions = def withInterProjectFirst(interProjectFirst: Boolean): UpdateOptions =
copy(interProjectFirst = interProjectFirst) copy(interProjectFirst = interProjectFirst)
@ -42,17 +44,18 @@ final class UpdateOptions private[sbt] (
cachedResolution = cachedResoluton, cachedResolution = cachedResoluton,
consolidatedResolution = cachedResolution consolidatedResolution = cachedResolution
) )
/** Extention point for an alternative resolver converter. */ /** Extention point for an alternative resolver converter. */
def withResolverConverter(resolverConverter: UpdateOptions.ResolverConverter): UpdateOptions = def withResolverConverter(resolverConverter: UpdateOptions.ResolverConverter): UpdateOptions =
copy(resolverConverter = resolverConverter) copy(resolverConverter = resolverConverter)
private[sbt] def copy( private[sbt] def copy(
circularDependencyLevel: CircularDependencyLevel = this.circularDependencyLevel, circularDependencyLevel: CircularDependencyLevel = this.circularDependencyLevel,
interProjectFirst: Boolean = this.interProjectFirst, interProjectFirst: Boolean = this.interProjectFirst,
latestSnapshots: Boolean = this.latestSnapshots, latestSnapshots: Boolean = this.latestSnapshots,
consolidatedResolution: Boolean = this.consolidatedResolution, consolidatedResolution: Boolean = this.consolidatedResolution,
cachedResolution: Boolean = this.cachedResolution, cachedResolution: Boolean = this.cachedResolution,
resolverConverter: UpdateOptions.ResolverConverter = this.resolverConverter resolverConverter: UpdateOptions.ResolverConverter = this.resolverConverter
): UpdateOptions = ): UpdateOptions =
new UpdateOptions( new UpdateOptions(
circularDependencyLevel, circularDependencyLevel,
@ -73,16 +76,15 @@ final class UpdateOptions private[sbt] (
case _ => false case _ => false
} }
override def hashCode: Int = override def hashCode: Int = {
{ var hash = 1
var hash = 1 hash = hash * 31 + this.circularDependencyLevel.##
hash = hash * 31 + this.circularDependencyLevel.## hash = hash * 31 + this.interProjectFirst.##
hash = hash * 31 + this.interProjectFirst.## hash = hash * 31 + this.latestSnapshots.##
hash = hash * 31 + this.latestSnapshots.## hash = hash * 31 + this.cachedResolution.##
hash = hash * 31 + this.cachedResolution.## hash = hash * 31 + this.resolverConverter.##
hash = hash * 31 + this.resolverConverter.## hash
hash }
}
} }
object UpdateOptions { object UpdateOptions {

View File

@ -29,7 +29,9 @@ abstract class ConfigurationReportExtra {
} }
def retrieve(f: (String, ModuleID, Artifact, File) => File): ConfigurationReport = 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 { abstract class ModuleReportExtra {
@ -52,7 +54,8 @@ abstract class ModuleReportExtra {
def licenses: Vector[(String, Option[String])] def licenses: Vector[(String, Option[String])]
def callers: Vector[Caller] 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 = def detailReport: String =
s"\t\t- ${module.revision}\n" + s"\t\t- ${module.revision}\n" +
@ -71,48 +74,50 @@ abstract class ModuleReportExtra {
if (extraAttributes.isEmpty) None if (extraAttributes.isEmpty) None
else { Some(extraAttributes.toString) } else { Some(extraAttributes.toString) }
) + ) +
reportStr("isDefault", isDefault map { _.toString }) + reportStr("isDefault", isDefault map { _.toString }) +
reportStr("branch", branch) + reportStr("branch", branch) +
reportStr( reportStr(
"configurations", "configurations",
if (configurations.isEmpty) None if (configurations.isEmpty) None
else { Some(configurations.mkString(", ")) } else { Some(configurations.mkString(", ")) }
) + ) +
reportStr( reportStr(
"licenses", "licenses",
if (licenses.isEmpty) None if (licenses.isEmpty) None
else { Some(licenses.mkString(", ")) } else { Some(licenses.mkString(", ")) }
) + ) +
reportStr( reportStr(
"callers", "callers",
if (callers.isEmpty) None if (callers.isEmpty) None
else { Some(callers.mkString(", ")) } else { Some(callers.mkString(", ")) }
) )
private[sbt] def reportStr(key: String, value: Option[String]): String = 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 = def retrieve(f: (ModuleID, Artifact, File) => File): ModuleReport =
copy(artifacts = artifacts.map { case (art, file) => (art, f(module, art, file)) }) copy(artifacts = artifacts.map { case (art, file) => (art, f(module, art, file)) })
protected[this] def copy( protected[this] def copy(
module: ModuleID = module, module: ModuleID = module,
artifacts: Vector[(Artifact, File)] = artifacts, artifacts: Vector[(Artifact, File)] = artifacts,
missingArtifacts: Vector[Artifact] = missingArtifacts, missingArtifacts: Vector[Artifact] = missingArtifacts,
status: Option[String] = status, status: Option[String] = status,
publicationDate: Option[ju.Calendar] = publicationDate, publicationDate: Option[ju.Calendar] = publicationDate,
resolver: Option[String] = resolver, resolver: Option[String] = resolver,
artifactResolver: Option[String] = artifactResolver, artifactResolver: Option[String] = artifactResolver,
evicted: Boolean = evicted, evicted: Boolean = evicted,
evictedData: Option[String] = evictedData, evictedData: Option[String] = evictedData,
evictedReason: Option[String] = evictedReason, evictedReason: Option[String] = evictedReason,
problem: Option[String] = problem, problem: Option[String] = problem,
homepage: Option[String] = homepage, homepage: Option[String] = homepage,
extraAttributes: Map[String, String] = extraAttributes, extraAttributes: Map[String, String] = extraAttributes,
isDefault: Option[Boolean] = isDefault, isDefault: Option[Boolean] = isDefault,
branch: Option[String] = branch, branch: Option[String] = branch,
configurations: Vector[String] = configurations, configurations: Vector[String] = configurations,
licenses: Vector[(String, Option[String])] = licenses, licenses: Vector[(String, Option[String])] = licenses,
callers: Vector[Caller] = callers callers: Vector[Caller] = callers
): ModuleReport ): ModuleReport
} }
@ -123,22 +128,21 @@ abstract class UpdateReportExtra {
private[sbt] def stamps: Map[File, Long] private[sbt] def stamps: Map[File, Long]
/** All resolved modules in all configurations. */ /** All resolved modules in all configurations. */
def allModules: Vector[ModuleID] = def allModules: Vector[ModuleID] = {
{ val key = (m: ModuleID) => (m.organization, m.name, m.revision)
val key = (m: ModuleID) => (m.organization, m.name, m.revision) configurations.flatMap(_.allModules).groupBy(key).toVector map {
configurations.flatMap(_.allModules).groupBy(key).toVector map { case (k, v) =>
case (k, v) => v reduceLeft { (agg, x) =>
v reduceLeft { (agg, x) => agg.withConfigurations(
agg.withConfigurations( (agg.configurations, x.configurations) match {
(agg.configurations, x.configurations) match { case (None, _) => x.configurations
case (None, _) => x.configurations case (Some(ac), None) => Some(ac)
case (Some(ac), None) => Some(ac) case (Some(ac), Some(xc)) => Some(s"$ac;$xc")
case (Some(ac), Some(xc)) => Some(s"$ac;$xc") }
} )
) }
}
}
} }
}
def retrieve(f: (String, ModuleID, Artifact, File) => File): UpdateReport = def retrieve(f: (String, ModuleID, Artifact, File) => File): UpdateReport =
UpdateReport(cachedDescriptor, configurations map { _ retrieve f }, stats, stamps) UpdateReport(cachedDescriptor, configurations map { _ retrieve f }, stats, stamps)

View File

@ -1,9 +1,9 @@
package sbt.librarymanagement package sbt.librarymanagement
final class VersionNumber private[sbt] ( final class VersionNumber private[sbt] (
val numbers: Seq[Long], val numbers: Seq[Long],
val tags: Seq[String], val tags: Seq[String],
val extras: Seq[String] val extras: Seq[String]
) { ) {
def _1: Option[Long] = get(0) def _1: Option[Long] = get(0)
def _2: Option[Long] = get(1) def _2: Option[Long] = get(1)
@ -33,12 +33,14 @@ final class VersionNumber private[sbt] (
extras.hashCode extras.hashCode
override def equals(o: Any): Boolean = override def equals(o: Any): Boolean =
o match { o match {
case v: VersionNumber => (this.numbers == v.numbers) && (this.tags == v.tags) && (this.extras == v.extras) case v: VersionNumber =>
case _ => false (this.numbers == v.numbers) && (this.tags == v.tags) && (this.extras == v.extras)
case _ => false
} }
} }
object VersionNumber { object VersionNumber {
/** /**
* @param numbers numbers delimited by a dot. * @param numbers numbers delimited by a dot.
* @param tags string prefixed by a dash. * @param tags string prefixed by a dash.
@ -74,10 +76,11 @@ object VersionNumber {
val TaggedVersion = """(\d{1,14})([\.\d{1,14}]*)((?:-\w+)*)((?:\+.+)*)""".r val TaggedVersion = """(\d{1,14})([\.\d{1,14}]*)((?:-\w+)*)((?:\+.+)*)""".r
val NonSpaceString = """(\S+)""".r val NonSpaceString = """(\S+)""".r
v match { v match {
case TaggedVersion(m, ns, ts, es) => Some((Vector(m.toLong) ++ splitDot(ns), splitDash(ts), splitPlus(es))) case TaggedVersion(m, ns, ts, es) =>
case "" => None Some((Vector(m.toLong) ++ splitDot(ns), splitDash(ts), splitPlus(es)))
case NonSpaceString(s) => Some((Vector(), Vector(), Vector(s))) case "" => None
case _ => None case NonSpaceString(s) => Some((Vector(), Vector(), Vector(s)))
case _ => None
} }
} }
@ -98,8 +101,18 @@ object VersionNumber {
doIsCompat(v1, v2) || doIsCompat(v2, v1) doIsCompat(v1, v2) || doIsCompat(v2, v1)
private[this] def doIsCompat(v1: VersionNumber, v2: VersionNumber): Boolean = private[this] def doIsCompat(v1: VersionNumber, v2: VersionNumber): Boolean =
(v1, v2) match { (v1, v2) match {
case (v1, v2) if (v1.size >= 2) && (v2.size >= 2) => // A normal version number MUST take the form X.Y.Z case (v1, v2)
(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 { 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, _, _, _) => 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. // 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) equalsIgnoreExtra(v1, v2)
@ -129,7 +142,8 @@ object VersionNumber {
doIsCompat(v1, v2) || doIsCompat(v2, v1) doIsCompat(v1, v2) || doIsCompat(v2, v1)
private[this] def doIsCompat(v1: VersionNumber, v2: VersionNumber): Boolean = private[this] def doIsCompat(v1: VersionNumber, v2: VersionNumber): Boolean =
(v1, v2) match { (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 { (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 => 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 // A pre-release version MAY be denoted by appending a hyphen and a series of dot separated identifiers

View File

@ -13,13 +13,17 @@ trait BaseIvySpecification extends UnitSpec {
def currentTarget: File = currentBase / "target" / "ivyhome" def currentTarget: File = currentBase / "target" / "ivyhome"
def currentManaged: File = currentBase / "target" / "lib_managed" def currentManaged: File = currentBase / "target" / "lib_managed"
def currentDependency: File = currentBase / "target" / "dependency" 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() lazy val log = ConsoleLogger()
def configurations = Vector(Compile, Test, Runtime) def configurations = Vector(Compile, Test, Runtime)
def module(moduleId: ModuleID, deps: Vector[ModuleID], scalaFullVersion: Option[String], def module(moduleId: ModuleID,
uo: UpdateOptions = UpdateOptions(), overrideScalaVersion: Boolean = true): IvySbt#Module = { deps: Vector[ModuleID],
scalaFullVersion: Option[String],
uo: UpdateOptions = UpdateOptions(),
overrideScalaVersion: Boolean = true): IvySbt#Module = {
val ivyScala = scalaFullVersion map { fv => val ivyScala = scalaFullVersion map { fv =>
IvyScala( IvyScala(
scalaFullVersion = fv, scalaFullVersion = fv,
@ -53,23 +57,42 @@ trait BaseIvySpecification extends UnitSpec {
val off = false val off = false
val check = Vector.empty val check = Vector.empty
val resCacheDir = currentTarget / "resolution-cache" 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 = { def makeUpdateConfiguration: UpdateConfiguration = {
val retrieveConfig = RetrieveConfiguration(currentManaged, Resolver.defaultRetrievePattern).withSync(false) val retrieveConfig =
UpdateConfiguration(Some(retrieveConfig), false, UpdateLogging.Full, ArtifactTypeFilter.forbid(Set("src", "doc"))) 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] = { def ivyUpdateEither(module: IvySbt#Module): Either[UnresolvedWarning, UpdateReport] = {
// IO.delete(currentTarget) // IO.delete(currentTarget)
val config = makeUpdateConfiguration 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 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) = def ivyUpdate(module: IvySbt#Module) =
ivyUpdateEither(module) match { ivyUpdateEither(module) match {
@ -78,7 +101,8 @@ trait BaseIvySpecification extends UnitSpec {
throw w.resolveException throw w.resolveException
} }
def mkPublishConfiguration(resolver: Resolver, artifacts: Map[Artifact, File]): PublishConfiguration = { def mkPublishConfiguration(resolver: Resolver,
artifacts: Map[Artifact, File]): PublishConfiguration = {
new PublishConfiguration( new PublishConfiguration(
ivyFile = None, ivyFile = None,
resolverName = resolver.name, resolverName = resolver.name,

View File

@ -10,7 +10,9 @@ class CachedResolutionSpec extends BaseIvySpecification {
cleanIvyCache() cleanIvyCache()
val m = module( val m = module(
ModuleID("com.example", "foo", "0.1.0").withConfigurations(Some("compile")), 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) val report = ivyUpdate(m)
cleanCachedResolutionCache(m) cleanCachedResolutionCache(m)
@ -26,7 +28,9 @@ class CachedResolutionSpec extends BaseIvySpecification {
// log.setLevel(Level.Debug) // log.setLevel(Level.Debug)
val m = module( val m = module(
ModuleID("com.example", "foo", "0.2.0").withConfigurations(Some("compile")), 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 { ivyUpdateEither(m) match {
case Right(_) => sys.error("this should've failed") 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 Right(_) => sys.error("this should've failed 2")
case Left(uw) => case Left(uw) =>
uw.lines should contain allOf ("\n\tNote: Unresolved dependencies path:", uw.lines should contain allOf ("\n\tNote: Unresolved dependencies path:",
"\t\tfoundrylogic.vpp:vpp:2.2.1", "\t\tfoundrylogic.vpp:vpp:2.2.1",
"\t\t +- org.apache.cayenne:cayenne-tools:3.0.2", "\t\t +- org.apache.cayenne:cayenne-tools:3.0.2",
"\t\t +- org.apache.cayenne.plugins:maven-cayenne-plugin:3.0.2", "\t\t +- org.apache.cayenne.plugins:maven-cayenne-plugin:3.0.2",
"\t\t +- com.example:foo:0.2.0") "\t\t +- com.example:foo:0.2.0")
} }
} }
@ -54,7 +58,8 @@ class CachedResolutionSpec extends BaseIvySpecification {
val m = module( val m = module(
ModuleID("com.example", "foo", "0.3.0").withConfigurations(Some("compile")), ModuleID("com.example", "foo", "0.3.0").withConfigurations(Some("compile")),
Vector(avro177, dataAvro1940, netty320), Vector(avro177, dataAvro1940, netty320),
Some("2.10.2"), UpdateOptions().withCachedResolution(true) Some("2.10.2"),
UpdateOptions().withCachedResolution(true)
) )
// first resolution creates the minigraph // first resolution creates the minigraph
val _ = ivyUpdate(m) val _ = ivyUpdate(m)
@ -62,15 +67,23 @@ class CachedResolutionSpec extends BaseIvySpecification {
// second resolution reads from the minigraph // second resolution reads from the minigraph
val report = ivyUpdate(m) val report = ivyUpdate(m)
val modules: Seq[String] = report.configurations.head.modules map { _.toString } 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 =>
assert(!(modules exists { x: String => x contains """org.jboss.netty:netty:3.2.1.Final""" })) 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 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 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 dataAvro1940 =
def netty320 = ModuleID("org.jboss.netty", "netty", "3.2.0.Final").withConfigurations(Some("compile")) 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 def defaultOptions = EvictionWarningOptions.default
} }

View File

@ -73,11 +73,16 @@ class ComponentManagerTest extends UnitSpec {
} }
private def checksum(files: Iterable[File]): Seq[String] = files.map(checksum).toSeq 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 checksum(file: File): String =
private def defineFile(manager: ComponentManager, id: String, name: String): String = createFile(manager, id, name)(checksum) if (file.exists) ChecksumHelper.computeAsString(file, "sha1") else ""
private def defineFiles(manager: ComponentManager, id: String, names: String*): Seq[String] = createFiles(manager, id, names: _*)(checksum) private def defineFile(manager: ComponentManager, id: String, name: String): String =
private def createFile[T](manager: ComponentManager, id: String, name: String)(f: File => T): T = createFiles(manager, id, name)(files => f(files.toList.head)) createFile(manager, id, name)(checksum)
private def createFiles[T](manager: ComponentManager, id: String, names: String*)(f: Seq[File] => T): T = 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 => withTemporaryDirectory { dir =>
val files = names.map(name => new File(dir, name)) val files = names.map(name => new File(dir, name))
files.foreach(writeRandomContent) files.foreach(writeRandomContent)
@ -87,7 +92,9 @@ class ComponentManagerTest extends UnitSpec {
private def writeRandomContent(file: File) = IO.write(file, randomString) private def writeRandomContent(file: File) = IO.write(file, randomString)
private def randomString = "asdf" private def randomString = "asdf"
private def withManager[T](f: ComponentManager => T): T = 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 = private def withManagerHome[T](ivyHome: File)(f: ComponentManager => T): T =
TestLogger { logger => TestLogger { logger =>
@ -105,19 +112,26 @@ class ComponentManagerTest extends UnitSpec {
override def defineComponent(id: String, files: Array[File]): Unit = { override def defineComponent(id: String, files: Array[File]): Unit = {
val location = componentLocation(id) val location = componentLocation(id)
if (location.exists) 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 { 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 = { override def addToComponent(id: String, files: Array[File]): Boolean = {
val location = componentLocation(id) 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 true
} }
override def component(id: String): Array[File] = 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. // A stubbed locking API.
object locks extends xsbti.GlobalLock { object locks extends xsbti.GlobalLock {

View File

@ -118,22 +118,28 @@ class CrossVersionTest extends UnitSpec {
CrossVersion.binaryScalaVersion("2.20170314093845.0-87654321") shouldBe "2.20170314093845.0-87654321" 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 { 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 { 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 { 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 { 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 { 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 { 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 { it should "return disabled cross version as equal to a copy" in {
Disabled() shouldBe Disabled() Disabled() shouldBe Disabled()

View File

@ -15,7 +15,16 @@ class CustomPomParserTest extends UnitSpec {
val repoUrl = getClass.getResource("/test-maven-repo") val repoUrl = getClass.getResource("/test-maven-repo")
val local = MavenRepository("Test Repo", repoUrl.toExternalForm) val local = MavenRepository("Test Repo", repoUrl.toExternalForm)
val paths = IvyPaths(new File("."), Some(cacheDir)) 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 ivySbt = new IvySbt(conf)
val resolveOpts = new ResolveOptions().setConfs(Array("default")) val resolveOpts = new ResolveOptions().setConfs(Array("default"))
val mrid = ModuleRevisionId.newInstance("com.test", "test-artifact", "1.0.0-SNAPSHOT") 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.hasError shouldBe false
resolveReport.getArtifacts.size() shouldBe 1 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.getModuleRevisionId shouldBe mrid
artifact.getExt shouldBe "jar" artifact.getExt shouldBe "jar"
} }

View File

@ -52,11 +52,14 @@ class DMSerializationSpec extends UnitSpec {
} }
lazy val updateReportExample = lazy val updateReportExample =
UpdateReport(new File("./foo"), Vector(configurationReportExample), UpdateReport(new File("./foo"),
UpdateStats(0, 0, 0, false), Map(new File("./foo") -> 0)) Vector(configurationReportExample),
UpdateStats(0, 0, 0, false),
Map(new File("./foo") -> 0))
lazy val configurationReportExample = lazy val configurationReportExample =
ConfigurationReport("compile", Vector(moduleReportExample), ConfigurationReport("compile",
Vector(organizationArtifactReportExample)) Vector(moduleReportExample),
Vector(organizationArtifactReportExample))
lazy val organizationArtifactReportExample = lazy val organizationArtifactReportExample =
OrganizationArtifactReport("org", "name", Vector(moduleReportExample)) OrganizationArtifactReport("org", "name", Vector(moduleReportExample))
lazy val moduleReportExample = lazy val moduleReportExample =
@ -68,13 +71,13 @@ class DMSerializationSpec extends UnitSpec {
def roundtripStr[A: JsonReader: JsonWriter](a: A): Assertion = def roundtripStr[A: JsonReader: JsonWriter](a: A): Assertion =
roundtripBuilder(a) { _.toString shouldBe _.toString } roundtripBuilder(a) { _.toString shouldBe _.toString }
def roundtripBuilder[A: JsonReader: JsonWriter](a: A)(f: (A, A) => Assertion): Assertion = def roundtripBuilder[A: JsonReader: JsonWriter](a: A)(f: (A, A) => Assertion): Assertion = {
{ val json = isoString to (Converter toJsonUnsafe a)
val json = isoString to (Converter toJsonUnsafe a) println(json)
println(json) val obj = Converter fromJsonUnsafe [A] (isoString from json)
val obj = Converter fromJsonUnsafe[A] (isoString from json) f(a, obj)
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)
} }

View File

@ -44,19 +44,29 @@ class EvictionWarningSpec extends BaseIvySpecification {
it should "be detected if it's enabled" in scalaLibTransitiveWarn2() it should "be detected if it's enabled" in scalaLibTransitiveWarn2()
it should "print out message about the eviction if it's enabled" in scalaLibTransitiveWarn3() 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 akkaActor214 =
def akkaActor230 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("compile")) cross CrossVersion.binary ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations(Some("compile")) cross CrossVersion.binary
def akkaActor234 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.4").withConfigurations(Some("compile")) cross CrossVersion.binary def akkaActor230 =
def scala2102 = ModuleID("org.scala-lang", "scala-library", "2.10.2").withConfigurations(Some("compile")) ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("compile")) cross CrossVersion.binary
def scala2103 = ModuleID("org.scala-lang", "scala-library", "2.10.3").withConfigurations(Some("compile")) def akkaActor234 =
def scala2104 = ModuleID("org.scala-lang", "scala-library", "2.10.4").withConfigurations(Some("compile")) 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 commonsIo13 = ModuleID("commons-io", "commons-io", "1.3").withConfigurations(Some("compile"))
def commonsIo14 = ModuleID("commons-io", "commons-io", "1.4").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 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 bnfparser10 =
def unfilteredUploads080 = ModuleID("net.databinder", "unfiltered-uploads", "0.8.0").withConfigurations(Some("compile")) cross CrossVersion.binary // uses commons-io 1.4 ModuleID("ca.gobits.bnf", "bnfparser", "1.0").withConfigurations(Some("compile")) // uses commons-io 2.4
def bananaSesame04 = ModuleID("org.w3", "banana-sesame", "0.4").withConfigurations(Some("compile")) cross CrossVersion.binary // uses akka-actor 2.1.4 def unfilteredUploads080 =
def akkaRemote234 = ModuleID("com.typesafe.akka", "akka-remote", "2.3.4").withConfigurations(Some("compile")) cross CrossVersion.binary // uses akka-actor 2.3.4 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 def defaultOptions = EvictionWarningOptions.default
@ -181,7 +191,10 @@ class EvictionWarningSpec extends BaseIvySpecification {
def javaLibTransitiveWarn3() = { def javaLibTransitiveWarn3() = {
val m = module(defaultModuleId, javaLibTransitiveDeps, Some("2.10.3")) val m = module(defaultModuleId, javaLibTransitiveDeps, Some("2.10.3"))
val report = ivyUpdate(m) 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( List(
"There may be incompatibilities among your library dependencies.", "There may be incompatibilities among your library dependencies.",
"Here are some of the libraries that were evicted:", "Here are some of the libraries that were evicted:",
@ -240,7 +253,10 @@ class EvictionWarningSpec extends BaseIvySpecification {
def scalaLibTransitiveWarn3() = { def scalaLibTransitiveWarn3() = {
val m = module(defaultModuleId, scalaLibTransitiveDeps, Some("2.10.4")) val m = module(defaultModuleId, scalaLibTransitiveDeps, Some("2.10.4"))
val report = ivyUpdate(m) 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( List(
"There may be incompatibilities among your library dependencies.", "There may be incompatibilities among your library dependencies.",
"Here are some of the libraries that were evicted:", "Here are some of the libraries that were evicted:",

View File

@ -20,7 +20,10 @@ class InconsistentDuplicateSpec extends UnitSpec {
IvySbt.inconsistentDuplicateWarning(Seq(akkaActor230Test, akkaActor230)) shouldBe Nil 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 akkaActor214 =
def akkaActor230 = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("compile")) cross CrossVersion.binary ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations(Some("compile")) cross CrossVersion.binary
def akkaActor230Test = ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("test")) 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
} }

View File

@ -75,4 +75,3 @@ class MakePomSpec extends UnitSpec {
() ()
} }
} }

View File

@ -9,7 +9,9 @@ class MergeDescriptorSpec extends BaseIvySpecification {
cleanIvyCache() cleanIvyCache()
val m = module( val m = module(
ModuleID("com.example", "foo", "0.1.0").withConfigurations(Some("compile")), ModuleID("com.example", "foo", "0.1.0").withConfigurations(Some("compile")),
Vector(guavaTest, guavaTestTests), None, UpdateOptions() Vector(guavaTest, guavaTestTests),
None,
UpdateOptions()
) )
m.withModule(log) { m.withModule(log) {
case (ivy, md, _) => 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 guavaTest =
def guavaTestTests = ModuleID("com.google.guava", "guava-tests", "18.0").withConfigurations(Option("test")).classifier("tests") 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 def defaultOptions = EvictionWarningOptions.default
} }

View File

@ -9,7 +9,14 @@ object ResolverTest extends UnitSpec {
"Resolver url" should "propagate pattern descriptorOptional and skipConsistencyCheck." in { "Resolver url" should "propagate pattern descriptorOptional and skipConsistencyCheck." in {
val pats = Vector("[orgPath]") val pats = Vector("[orgPath]")
val patsExpected = Vector("http://foo.com/test/[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.ivyPatterns shouldBe patsExpected
patterns.artifactPatterns shouldBe patsExpected patterns.artifactPatterns shouldBe patsExpected

View File

@ -12,7 +12,9 @@ class ScalaOverrideTest extends UnitSpec {
val OtherOrgID = "other.org" val OtherOrgID = "other.org"
def check(org0: String, version0: String)(org1: String, name1: String, version1: String) = { 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 osm = new OverrideScalaMediator(org0, version0, scalaConfigs)
val mrid = ModuleRevisionId.newInstance(org1, name1, version1) val mrid = ModuleRevisionId.newInstance(org1, name1, version1)
@ -24,21 +26,51 @@ class ScalaOverrideTest extends UnitSpec {
} }
"""OverrideScalaMediator """OverrideScalaMediator
""" should "Override compiler version" in check(Organization, "2.11.8")(Organization, CompilerID, "2.11.9") """ should "Override compiler version" in check(Organization, "2.11.8")(Organization,
it should "Override library version" in check(Organization, "2.11.8")(Organization, LibraryID, "2.11.8") CompilerID,
it should "Override reflect version" in check(Organization, "2.11.8")(Organization, ReflectID, "2.11.7") "2.11.9")
it should "Override actors version" in check(Organization, "2.11.8")(Organization, ActorsID, "2.11.6") it should "Override library version" in check(Organization, "2.11.8")(Organization,
it should "Override scalap version" in check(Organization, "2.11.8")(Organization, ScalapID, "2.11.5") 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 compiler organization" in check(OtherOrgID, "2.11.8")(Organization,
it should "Override default library organization" in check(OtherOrgID, "2.11.8")(Organization, LibraryID, "2.11.8") CompilerID,
it should "Override default reflect organization" in check(OtherOrgID, "2.11.8")(Organization, ReflectID, "2.11.7") "2.11.9")
it should "Override default actors organization" in check(OtherOrgID, "2.11.8")(Organization, ActorsID, "2.11.6") it should "Override default library organization" in check(OtherOrgID, "2.11.8")(Organization,
it should "Override default scalap organization" in check(OtherOrgID, "2.11.8")(Organization, ScalapID, "2.11.5") 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 compiler organization" in check(Organization, "2.11.8")(OtherOrgID,
it should "Override custom library organization" in check(Organization, "2.11.8")(OtherOrgID, LibraryID, "2.11.8") CompilerID,
it should "Override custom reflect organization" in check(Organization, "2.11.8")(OtherOrgID, ReflectID, "2.11.7") "2.11.9")
it should "Override custom actors organization" in check(Organization, "2.11.8")(OtherOrgID, ActorsID, "2.11.6") it should "Override custom library organization" in check(Organization, "2.11.8")(OtherOrgID,
it should "Override custom scalap organization" in check(Organization, "2.11.8")(OtherOrgID, ScalapID, "2.11.5") 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")
} }

View File

@ -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" 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") 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()) "0.1.0-SNAPSHOT" should "be parsed" in beParsedAs("0.1.0-SNAPSHOT",
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-SNAPSHOT", Seq("0.1.0-SNAPSHOT", "0.1.0", "0.1")) Seq(0, 1, 0),
it should "be SemVer compat with 0.1.0-SNAPSHOT" in beSemVerCompatWith("0.1.0-SNAPSHOT", "0.1.0-SNAPSHOT") 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 "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 SemVer compat with 0.1.0-SNAPSHOT+001" in beSemVerCompatWith("0.1.0-SNAPSHOT",
it should "be SecSeg compat with 0.1.0-SNAPSHOT" in beSecSegCompatWith("0.1.0-SNAPSHOT", "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 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()) "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()) "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()) "0.1.0-MSERVER-1" should "be parsed" in beParsedAs("0.1.0-MSERVER-1",
it should "cascade" in generateCorrectCascadingNumbers("0.1.0-MSERVER-1", Seq("0.1.0-MSERVER-1", "0.1.0", "0.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 { "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 "cascade" in generateCorrectCascadingNumbers(
it should "be SemVer compat with 2.0.0" in beSemVerCompatWith("2.10.4-20140115-000117-b3a-sources", "2.0.0") "2.10.4-20140115-000117-b3a-sources",
it should "be not SecSeg compat with 2.0.0" in notBeSecSegCompatWith("2.10.4-20140115-000117-b3a-sources", "2.0.0") 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 { "20140115000117-b3a-sources" should "be parsed" in {
beParsedAs("20140115000117-b3a-sources", Seq(20140115000117L), Seq("b3a", "sources"), Seq()) 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 { "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")) 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 { "non.space.!?string" should "be parsed" in {
beParsedAs("non.space.!?string", Seq(), Seq(), Seq("non.space.!?string")) 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") "space !?string" should "be parsed as an error" in beParsedAsError("space !?string")
"blank string" should "be parsed as an error" in beParsedAsError("") "blank string" should "be parsed as an error" in beParsedAsError("")
@ -89,8 +116,11 @@ class VersionNumberSpec extends UnitSpec {
case VersionNumber(ns1, ts1, es1) => case VersionNumber(ns1, ts1, es1) =>
sys.error(s"$ns1, $ts1, $es1") sys.error(s"$ns1, $ts1, $es1")
} }
def breakDownTo(s: String, major: Option[Long], minor: Option[Long] = None, def breakDownTo(s: String,
patch: Option[Long] = None, buildNumber: Option[Long] = None) = major: Option[Long],
minor: Option[Long] = None,
patch: Option[Long] = None,
buildNumber: Option[Long] = None) =
s match { s match {
case VersionNumber(ns, ts, es) => case VersionNumber(ns, ts, es) =>
val v = VersionNumber(ns, ts, es) val v = VersionNumber(ns, ts, es)

View File

@ -9,10 +9,13 @@ import sbt.librarymanagement.{ ModuleID, RawRepository, Resolver, UpdateReport }
class FakeResolverSpecification extends BaseIvySpecification { class FakeResolverSpecification extends BaseIvySpecification {
import FakeResolver._ 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 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 anotherExample =
val nonExisting = ModuleID("com.example", "does-not-exist", "1.2.3").withConfigurations(Some("compile")) 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 { "The FakeResolver" should "find modules with only one artifact" in {
val m = getModule(myModule) val m = getModule(myModule)
@ -53,12 +56,10 @@ class FakeResolverSpecification extends BaseIvySpecification {
("org.example", "my-module", "0.0.1-SNAPSHOT") -> List( ("org.example", "my-module", "0.0.1-SNAPSHOT") -> List(
FakeArtifact("artifact1", "jar", "jar", artifact1) FakeArtifact("artifact1", "jar", "jar", artifact1)
), ),
("com.example", "example", "1.0.0") -> List( ("com.example", "example", "1.0.0") -> List(
FakeArtifact("artifact1", "jar", "jar", artifact1), FakeArtifact("artifact1", "jar", "jar", artifact1),
FakeArtifact("artifact2", "txt", "txt", artifact2) FakeArtifact("artifact2", "txt", "txt", artifact2)
), ),
("com.example", "another-example", "1.0.0") -> List( ("com.example", "another-example", "1.0.0") -> List(
FakeArtifact("artifact1", "jar", "jar", artifact1), FakeArtifact("artifact1", "jar", "jar", artifact1),
FakeArtifact("non-existing", "txt", "txt", new File("non-existing-file")) 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) private def fakeResolver = new FakeResolver("FakeResolver", new File("tmp"), modules)
override def resolvers: Vector[Resolver] = Vector(new RawRepository(fakeResolver)) 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) = private def getAllFiles(report: UpdateReport) =
for { for {
conf <- report.configurations conf <- report.configurations

View File

@ -15,7 +15,8 @@ class IvyRepoSpec extends BaseIvySpecification with DependencyBuilders {
module( module(
ourModuleID, 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 clMod = {
val externalModules = Vector(dep) 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`) // 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._ import Inside._
inside(report2.configuration("compile").map(_.modules)) { inside(report2.configuration("compile").map(_.modules)) {

View File

@ -54,11 +54,16 @@ class RepositoriesParserSpecification extends UnitSpec {
| ivyRepo: https://repo1.maven.org, [orgPath], bootOnly""".stripMargin | ivyRepo: https://repo1.maven.org, [orgPath], bootOnly""".stripMargin
val repos = RepositoriesParser(file) val repos = RepositoriesParser(file)
val expected = val expected =
IvyRepository("ivyRepo", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]", IvyRepository(
"ivyRepo",
new URL("https://repo1.maven.org"),
"[orgPath]",
"[orgPath]",
mavenCompatible = false, mavenCompatible = false,
skipConsistencyCheck = false, skipConsistencyCheck = false,
descriptorOptional = false, descriptorOptional = false,
bootOnly = true) bootOnly = true
)
repos.size shouldBe 1 repos.size shouldBe 1
repos(0) shouldBe expected repos(0) shouldBe expected
} }
@ -68,11 +73,16 @@ class RepositoriesParserSpecification extends UnitSpec {
| ivyRepo: https://repo1.maven.org, [orgPath], mavenCompatible""".stripMargin | ivyRepo: https://repo1.maven.org, [orgPath], mavenCompatible""".stripMargin
val repos = RepositoriesParser(file) val repos = RepositoriesParser(file)
val expected = val expected =
IvyRepository("ivyRepo", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]", IvyRepository(
"ivyRepo",
new URL("https://repo1.maven.org"),
"[orgPath]",
"[orgPath]",
mavenCompatible = true, mavenCompatible = true,
skipConsistencyCheck = false, skipConsistencyCheck = false,
descriptorOptional = false, descriptorOptional = false,
bootOnly = false) bootOnly = false
)
repos.size shouldBe 1 repos.size shouldBe 1
repos(0) shouldBe expected repos(0) shouldBe expected
} }
@ -82,11 +92,16 @@ class RepositoriesParserSpecification extends UnitSpec {
| ivyRepo: https://repo1.maven.org, [orgPath], skipConsistencyCheck""".stripMargin | ivyRepo: https://repo1.maven.org, [orgPath], skipConsistencyCheck""".stripMargin
val repos = RepositoriesParser(file) val repos = RepositoriesParser(file)
val expected = val expected =
IvyRepository("ivyRepo", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]", IvyRepository(
"ivyRepo",
new URL("https://repo1.maven.org"),
"[orgPath]",
"[orgPath]",
mavenCompatible = false, mavenCompatible = false,
skipConsistencyCheck = true, skipConsistencyCheck = true,
descriptorOptional = false, descriptorOptional = false,
bootOnly = false) bootOnly = false
)
repos.size shouldBe 1 repos.size shouldBe 1
repos(0) shouldBe expected repos(0) shouldBe expected
} }
@ -96,41 +111,58 @@ class RepositoriesParserSpecification extends UnitSpec {
| ivyRepo: https://repo1.maven.org, [orgPath], descriptorOptional""".stripMargin | ivyRepo: https://repo1.maven.org, [orgPath], descriptorOptional""".stripMargin
val repos = RepositoriesParser(file) val repos = RepositoriesParser(file)
val expected = val expected =
IvyRepository("ivyRepo", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]", IvyRepository(
"ivyRepo",
new URL("https://repo1.maven.org"),
"[orgPath]",
"[orgPath]",
mavenCompatible = false, mavenCompatible = false,
skipConsistencyCheck = false, skipConsistencyCheck = false,
descriptorOptional = true, descriptorOptional = true,
bootOnly = false) bootOnly = false
)
repos.size shouldBe 1 repos.size shouldBe 1
repos(0) shouldBe expected repos(0) shouldBe expected
} }
it should "parse complex ivy repository definition" in { it should "parse complex ivy repository definition" in {
val file = """[repositories] val file =
"""[repositories]
| ivyRepo: https://repo1.maven.org, [orgPath], [artPath], descriptorOptional, skipConsistencyCheck""".stripMargin | ivyRepo: https://repo1.maven.org, [orgPath], [artPath], descriptorOptional, skipConsistencyCheck""".stripMargin
val repos = RepositoriesParser(file) val repos = RepositoriesParser(file)
val expected = val expected =
IvyRepository("ivyRepo", new URL("https://repo1.maven.org"), "[orgPath]", "[artPath]", IvyRepository(
"ivyRepo",
new URL("https://repo1.maven.org"),
"[orgPath]",
"[artPath]",
mavenCompatible = false, mavenCompatible = false,
skipConsistencyCheck = true, skipConsistencyCheck = true,
descriptorOptional = true, descriptorOptional = true,
bootOnly = false) bootOnly = false
)
repos.size shouldBe 1 repos.size shouldBe 1
repos(0) shouldBe expected repos(0) shouldBe expected
} }
it should "parse multiple repositories defined together" in { it should "parse multiple repositories defined together" in {
val file = """[repositories] val file =
"""[repositories]
| local | local
| ivyRepo: https://repo1.maven.org, [orgPath], [artPath], descriptorOptional, skipConsistencyCheck | ivyRepo: https://repo1.maven.org, [orgPath], [artPath], descriptorOptional, skipConsistencyCheck
| mavenRepo: https://repo1.maven.org""".stripMargin | mavenRepo: https://repo1.maven.org""".stripMargin
val expected0 = PredefinedRepository(xsbti.Predefined.Local) val expected0 = PredefinedRepository(xsbti.Predefined.Local)
val expected1 = val expected1 =
IvyRepository("ivyRepo", new URL("https://repo1.maven.org"), "[orgPath]", "[artPath]", IvyRepository(
"ivyRepo",
new URL("https://repo1.maven.org"),
"[orgPath]",
"[artPath]",
mavenCompatible = false, mavenCompatible = false,
skipConsistencyCheck = true, skipConsistencyCheck = true,
descriptorOptional = true, descriptorOptional = true,
bootOnly = false) bootOnly = false
)
val expected2 = MavenRepository("mavenRepo", new URL("https://repo1.maven.org")) val expected2 = MavenRepository("mavenRepo", new URL("https://repo1.maven.org"))
val repos = RepositoriesParser(file) val repos = RepositoriesParser(file)

View File

@ -6,10 +6,9 @@ import sbt.util._
import sbt.internal.util._ import sbt.internal.util._
object TestLogger { object TestLogger {
def apply[T](f: Logger => T): T = def apply[T](f: Logger => T): T = {
{ val log = new BufferedLogger(ConsoleLogger())
val log = new BufferedLogger(ConsoleLogger()) log.setLevel(Level.Debug)
log.setLevel(Level.Debug) log.bufferQuietly(f(log))
log.bufferQuietly(f(log)) }
}
} }

View File

@ -11,13 +11,13 @@ object AutomateScalafmtPlugin extends AutoPlugin {
configurations.flatMap { c => configurations.flatMap { c =>
inConfig(c)( inConfig(c)(
Seq( Seq(
compileInputs.in(compile) := { compileInputs.in(compile) := {
scalafmtInc.value scalafmtInc.value
compileInputs.in(compile).value compileInputs.in(compile).value
}, },
sourceDirectories.in(scalafmtInc) := Seq(scalaSource.value), sourceDirectories.in(scalafmtInc) := Seq(scalaSource.value),
scalafmtInc := { scalafmtInc := {
val cache = streams.value.cacheDirectory / "scalafmt" val cache = streams.value.cacheDirectory / "scalafmt"
val include = includeFilter.in(scalafmtInc).value val include = includeFilter.in(scalafmtInc).value
val exclude = excludeFilter.in(scalafmtInc).value val exclude = excludeFilter.in(scalafmtInc).value
val sources = val sources =

View File

@ -19,27 +19,39 @@ object DatatypeConfig {
/** Codecs that were manually written. */ /** Codecs that were manually written. */
val myCodecs: PartialFunction[String, Type => List[String]] = { 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" => case "org.apache.ivy.plugins.resolver.DependencyResolver" => { _ =>
{ _ => "sbt.internal.librarymanagement.formats.DependencyResolverFormat" :: Nil } "sbt.internal.librarymanagement.formats.DependencyResolverFormat" :: Nil
}
case "xsbti.GlobalLock" => { _ => "sbt.internal.librarymanagement.formats.GlobalLockFormat" :: Nil } case "xsbti.GlobalLock" => { _ =>
case "xsbti.Logger" => { _ => "sbt.internal.librarymanagement.formats.LoggerFormat" :: Nil } "sbt.internal.librarymanagement.formats.GlobalLockFormat" :: Nil
}
case "xsbti.Logger" => { _ =>
"sbt.internal.librarymanagement.formats.LoggerFormat" :: Nil
}
case "sbt.librarymanagement.UpdateOptions" => case "sbt.librarymanagement.UpdateOptions" => { _ =>
{ _ => "sbt.internal.librarymanagement.formats.UpdateOptionsFormat" :: Nil } "sbt.internal.librarymanagement.formats.UpdateOptionsFormat" :: Nil
}
// TODO: These are handled by BasicJsonProtocol, and sbt-datatype should handle them by default, imo // 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 "Option" | "Set" | "scala.Vector" => { tpe =>
case "Map" | "Tuple2" | "scala.Tuple2" => { tpe => twoArgs(tpe).flatMap(getFormats) } getFormats(oneArg(tpe))
case "Int" | "Long" => { _ => Nil } }
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 */ /** Types for which we don't include the format -- they're just aliases to InclExclRule */
val excluded = Set( val excluded = Set("sbt.librarymanagement.InclusionRule", "sbt.librarymanagement.ExclusionRule")
"sbt.librarymanagement.InclusionRule",
"sbt.librarymanagement.ExclusionRule")
/** Returns the list of formats required to encode the given `TpeRef`. */ /** Returns the list of formats required to encode the given `TpeRef`. */
val getFormats: Type => List[String] = val getFormats: Type => List[String] =

View File

@ -11,10 +11,10 @@ object Dependencies {
private val sbtIO = "org.scala-sbt" %% "io" % ioVersion private val sbtIO = "org.scala-sbt" %% "io" % ioVersion
private val utilCollection = "org.scala-sbt" %% "util-collection" % utilVersion private val utilCollection = "org.scala-sbt" %% "util-collection" % utilVersion
private val utilLogging = "org.scala-sbt" %% "util-logging" % utilVersion private val utilLogging = "org.scala-sbt" %% "util-logging" % utilVersion
private val utilTesting = "org.scala-sbt" %% "util-testing" % utilVersion private val utilTesting = "org.scala-sbt" %% "util-testing" % utilVersion
private val utilCompletion = "org.scala-sbt" %% "util-completion" % 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) = { def getSbtModulePath(key: String, name: String) = {
val localProps = new java.util.Properties() val localProps = new java.util.Properties()
@ -24,21 +24,31 @@ object Dependencies {
path 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") 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 { path match {
case Some(f) => p dependsOn c.fold[ClasspathDependency](ProjectRef(file(f), projectName))(ProjectRef(file(f), projectName) % _) case Some(f) =>
case None => p settings (libraryDependencies += c.fold(m)(m % _)) 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 addSbtIO(p: Project): Project = addSbtModule(p, sbtIoPath, "io", sbtIO)
def addSbtUtilCollection(p: Project): Project = addSbtModule(p, sbtUtilPath, "utilCollection", utilCollection) def addSbtUtilCollection(p: Project): Project =
def addSbtUtilLogging(p: Project): Project = addSbtModule(p, sbtUtilPath, "utilLogging", utilLogging) addSbtModule(p, sbtUtilPath, "utilCollection", utilCollection)
def addSbtUtilTesting(p: Project): Project = addSbtModule(p, sbtUtilPath, "utilTesting", utilTesting, Some(Test)) def addSbtUtilLogging(p: Project): Project =
def addSbtUtilCompletion(p: Project): Project = addSbtModule(p, sbtUtilPath, "utilComplete", utilCompletion) addSbtModule(p, sbtUtilPath, "utilLogging", utilLogging)
def addSbtUtilCache(p: Project): Project = addSbtModule(p, sbtUtilPath, "utilCache", utilCache) 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 launcherInterface = "org.scala-sbt" % "launcher-interface" % "1.0.0"
val ivy = "org.scala-sbt.ivy" % "ivy" % "2.3.0-sbt-48dd0744422128446aee9ac31aa356ee203cc9f4" val ivy = "org.scala-sbt.ivy" % "ivy" % "2.3.0-sbt-48dd0744422128446aee9ac31aa356ee203cc9f4"
@ -52,7 +62,7 @@ object Dependencies {
Def.setting { Def.setting {
scalaVersion.value match { scalaVersion.value match {
case sv if (sv startsWith "2.9.") || (sv startsWith "2.10.") => Nil 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
} }
} }
} }

View File

@ -4,29 +4,31 @@ import sbt.IO
import java.io.File import java.io.File
object Util { object Util {
def versionLine(version: String): String = "version=" + version def versionLine(version: String): String = "version=" + version
def containsVersion(propFile: File, version: String): Boolean = IO.read(propFile).contains(versionLine(version)) def containsVersion(propFile: File, version: String): Boolean =
def lastCompilationTime(analysis: sbt.inc.Analysis): Long = IO.read(propFile).contains(versionLine(version))
{ def lastCompilationTime(analysis: sbt.inc.Analysis): Long = {
val lastCompilation = analysis.compilations.allCompilations.lastOption val lastCompilation = analysis.compilations.allCompilations.lastOption
lastCompilation.map(_.startTime) getOrElse 0L lastCompilation.map(_.startTime) getOrElse 0L
} }
def generateVersionFile(version: String, dir: File, s: TaskStreams, analysis: sbt.inc.Analysis): Seq[File] = def generateVersionFile(version: String,
{ dir: File,
import java.util.{ Date, TimeZone } s: TaskStreams,
val formatter = new java.text.SimpleDateFormat("yyyyMMdd'T'HHmmss") analysis: sbt.inc.Analysis): Seq[File] = {
formatter.setTimeZone(TimeZone.getTimeZone("GMT")) import java.util.{ Date, TimeZone }
val timestamp = formatter.format(new Date) val formatter = new java.text.SimpleDateFormat("yyyyMMdd'T'HHmmss")
val content = versionLine(version) + "\ntimestamp=" + timestamp formatter.setTimeZone(TimeZone.getTimeZone("GMT"))
val f = dir / "xsbt.version.properties" val timestamp = formatter.format(new Date)
if (!f.exists || f.lastModified < lastCompilationTime(analysis) || !containsVersion(f, version)) { val content = versionLine(version) + "\ntimestamp=" + timestamp
s.log.info("Writing version information to " + f + " :\n" + content) val f = dir / "xsbt.version.properties"
IO.write(f, content) if (!f.exists || f.lastModified < lastCompilationTime(analysis) || !containsVersion(f,
} version)) {
f :: Nil s.log.info("Writing version information to " + f + " :\n" + content)
IO.write(f, content)
} }
f :: Nil
}
} }

View File

@ -1,7 +1,7 @@
addSbtPlugin("org.scala-sbt" % "sbt-houserules" % "0.3.2") 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("org.scala-sbt" % "sbt-contraband" % "0.3.0-M4")
addSbtPlugin("me.lessis" % "bintray-sbt" % "0.3.0") addSbtPlugin("me.lessis" % "bintray-sbt" % "0.3.0")
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "0.6.8") addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "0.6.8")
scalacOptions += "-language:postfixOps" scalacOptions += "-language:postfixOps"