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

View File

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

View File

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

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
* machine.
*/
class ComponentManager(globalLock: xsbti.GlobalLock, provider: xsbti.ComponentProvider, ivyHome: Option[File], val log: Logger) {
class ComponentManager(
globalLock: xsbti.GlobalLock,
provider: xsbti.ComponentProvider,
ivyHome: Option[File],
val log: Logger
) {
private[this] val ivyCache = new IvyCache(ivyHome)
/** Get all of the files for component 'id', throwing an exception if no files exist for the component. */
def files(id: String)(ifMissing: IfMissing): Iterable[File] =
{
def fromGlobal =
lockGlobalCache {
try { update(id); getOrElse(createAndCache) }
catch { case e: NotInCache => createAndCache }
}
def getOrElse(orElse: => Iterable[File]): Iterable[File] =
{
val existing = provider.component(id)
if (existing.isEmpty) orElse else existing
}
def notFound = invalid("Could not find required component '" + id + "'")
def createAndCache =
ifMissing match {
case IfMissing.Fail => notFound
case d: IfMissing.Define =>
d()
if (d.cache) cache(id)
getOrElse(notFound)
}
lockLocalCache { getOrElse(fromGlobal) }
/** Get all of the files for component 'id', throwing an exception if no files exist for the component. */
def files(id: String)(ifMissing: IfMissing): Iterable[File] = {
def fromGlobal =
lockGlobalCache {
try { update(id); getOrElse(createAndCache) } catch {
case e: NotInCache => createAndCache
}
}
def getOrElse(orElse: => Iterable[File]): Iterable[File] = {
val existing = provider.component(id)
if (existing.isEmpty) orElse else existing
}
def notFound = invalid("Could not find required component '" + id + "'")
def createAndCache =
ifMissing match {
case IfMissing.Fail => notFound
case d: IfMissing.Define =>
d()
if (d.cache) cache(id)
getOrElse(notFound)
}
lockLocalCache { getOrElse(fromGlobal) }
}
/** This is used to lock the local cache in project/boot/. By checking the local cache first, we can avoid grabbing a global lock. */
private def lockLocalCache[T](action: => T): T = lock(provider.lockFile)(action)
/** This is used to ensure atomic access to components in the global Ivy cache.*/
private def lockGlobalCache[T](action: => T): T = lock(ivyCache.lockFile)(action)
private def lock[T](file: File)(action: => T): T = globalLock(file, new Callable[T] { def call = action })
private def lock[T](file: File)(action: => T): T =
globalLock(file, new Callable[T] { def call = action })
/** Get the file for component 'id', throwing an exception if no files or multiple files exist for the component. */
def file(id: String)(ifMissing: IfMissing): File =
files(id)(ifMissing).toList match {
case x :: Nil => x
case xs => invalid("Expected single file for component '" + id + "', found: " + xs.mkString(", "))
case xs =>
invalid("Expected single file for component '" + id + "', found: " + xs.mkString(", "))
}
private def invalid(msg: String) = throw new InvalidComponent(msg)
def define(id: String, files: Iterable[File]) = lockLocalCache { provider.defineComponent(id, files.toSeq.toArray) }
/** Retrieve the file for component 'id' from the local repository. */
private def update(id: String): Unit = ivyCache.withCachedJar(sbtModuleID(id), Some(globalLock), log)(jar => define(id, Seq(jar)))
def define(id: String, files: Iterable[File]) = lockLocalCache {
provider.defineComponent(id, files.toSeq.toArray)
}
/** Retrieve the file for component 'id' from the local repository. */
private def update(id: String): Unit =
ivyCache.withCachedJar(sbtModuleID(id), Some(globalLock), log)(jar => define(id, Seq(jar)))
private def sbtModuleID(id: String) =
ModuleID(SbtArtifacts.Organization, id, ComponentManager.stampedVersion)
private def sbtModuleID(id: String) = ModuleID(SbtArtifacts.Organization, id, ComponentManager.stampedVersion)
/** Install the files for component 'id' to the local repository. This is usually used after writing files to the directory returned by 'location'. */
def cache(id: String): Unit = ivyCache.cacheJar(sbtModuleID(id), file(id)(IfMissing.Fail), Some(globalLock), log)
def clearCache(id: String): Unit = lockGlobalCache { ivyCache.clearCachedJar(sbtModuleID(id), Some(globalLock), log) }
def cache(id: String): Unit =
ivyCache.cacheJar(sbtModuleID(id), file(id)(IfMissing.Fail), Some(globalLock), log)
def clearCache(id: String): Unit = lockGlobalCache {
ivyCache.clearCachedJar(sbtModuleID(id), Some(globalLock), log)
}
}
class InvalidComponent(msg: String, cause: Throwable) extends RuntimeException(msg, cause) {
def this(msg: String) = this(msg, null)
@ -73,16 +92,17 @@ class InvalidComponent(msg: String, cause: Throwable) extends RuntimeException(m
sealed trait IfMissing
object IfMissing {
object Fail extends IfMissing
final class Define(val cache: Boolean, define: => Unit) extends IfMissing { def apply() = define }
final class Define(val cache: Boolean, define: => Unit) extends IfMissing {
def apply() = define
}
}
object ComponentManager {
lazy val (version, timestamp) =
{
val properties = new java.util.Properties
val propertiesStream = versionResource.openStream
try { properties.load(propertiesStream) } finally { propertiesStream.close() }
(properties.getProperty("version"), properties.getProperty("timestamp"))
}
lazy val (version, timestamp) = {
val properties = new java.util.Properties
val propertiesStream = versionResource.openStream
try { properties.load(propertiesStream) } finally { propertiesStream.close() }
(properties.getProperty("version"), properties.getProperty("timestamp"))
}
lazy val stampedVersion = version + "_" + timestamp
import java.net.URL

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

View File

@ -1,32 +1,62 @@
package sbt.internal.librarymanagement
import org.apache.ivy.core.module.id.ModuleRevisionId
import org.apache.ivy.core.module.descriptor.{ DefaultArtifact, DefaultExtendsDescriptor, DefaultModuleDescriptor, ModuleDescriptor }
import org.apache.ivy.core.module.descriptor.{
DefaultArtifact,
DefaultExtendsDescriptor,
DefaultModuleDescriptor,
ModuleDescriptor
}
import org.apache.ivy.core.module.descriptor.{ DefaultDependencyDescriptor, DependencyDescriptor }
import org.apache.ivy.plugins.parser.{ ModuleDescriptorParser, ModuleDescriptorParserRegistry, ParserSettings }
import org.apache.ivy.plugins.parser.m2.{ ReplaceMavenConfigurationMappings, PomModuleDescriptorBuilder, PomModuleDescriptorParser }
import org.apache.ivy.plugins.parser.{
ModuleDescriptorParser,
ModuleDescriptorParserRegistry,
ParserSettings
}
import org.apache.ivy.plugins.parser.m2.{
ReplaceMavenConfigurationMappings,
PomModuleDescriptorBuilder,
PomModuleDescriptorParser
}
import org.apache.ivy.plugins.repository.Resource
import org.apache.ivy.plugins.namespace.NamespaceTransformer
import org.apache.ivy.util.extendable.ExtendableItem
import java.io.{ File, InputStream }
import java.net.URL
import sbt.internal.librarymanagement.mavenint.{ PomExtraDependencyAttributes, SbtPomExtraProperties }
import sbt.internal.librarymanagement.mavenint.{
PomExtraDependencyAttributes,
SbtPomExtraProperties
}
import sbt.io.Hash
// @deprecated("We now use an Aether-based pom parser.", "0.13.8")
final class CustomPomParser(delegate: ModuleDescriptorParser, transform: (ModuleDescriptorParser, ModuleDescriptor) => ModuleDescriptor) extends ModuleDescriptorParser {
override def parseDescriptor(ivySettings: ParserSettings, descriptorURL: URL, validate: Boolean) =
final class CustomPomParser(
delegate: ModuleDescriptorParser,
transform: (ModuleDescriptorParser, ModuleDescriptor) => ModuleDescriptor
) extends ModuleDescriptorParser {
override def parseDescriptor(
ivySettings: ParserSettings,
descriptorURL: URL,
validate: Boolean
) =
transform(this, delegate.parseDescriptor(ivySettings, descriptorURL, validate))
override def parseDescriptor(ivySettings: ParserSettings, descriptorURL: URL, res: Resource, validate: Boolean) =
override def parseDescriptor(
ivySettings: ParserSettings,
descriptorURL: URL,
res: Resource,
validate: Boolean
) =
transform(this, delegate.parseDescriptor(ivySettings, descriptorURL, res, validate))
override def toIvyFile(is: InputStream, res: Resource, destFile: File, md: ModuleDescriptor) = delegate.toIvyFile(is, res, destFile, md)
override def toIvyFile(is: InputStream, res: Resource, destFile: File, md: ModuleDescriptor) =
delegate.toIvyFile(is, res, destFile, md)
override def accept(res: Resource) = delegate.accept(res)
override def getType() = delegate.getType()
override def getMetadataArtifact(mrid: ModuleRevisionId, res: Resource) = delegate.getMetadataArtifact(mrid, res)
override def getMetadataArtifact(mrid: ModuleRevisionId, res: Resource) =
delegate.getMetadataArtifact(mrid, res)
}
// @deprecated("We now use an Aether-based pom parser.", "0.13.8")
object CustomPomParser {
@ -41,7 +71,8 @@ object CustomPomParser {
val SbtVersionKey = PomExtraDependencyAttributes.SbtVersionKey
val ScalaVersionKey = PomExtraDependencyAttributes.ScalaVersionKey
val ExtraAttributesKey = PomExtraDependencyAttributes.ExtraAttributesKey
private[this] val unqualifiedKeys = Set(SbtVersionKey, ScalaVersionKey, ExtraAttributesKey, ApiURLKey)
private[this] val unqualifiedKeys =
Set(SbtVersionKey, ScalaVersionKey, ExtraAttributesKey, ApiURLKey)
// packagings that should be jars, but that Ivy doesn't handle as jars
// TODO - move this elsewhere.
@ -51,7 +82,8 @@ object CustomPomParser {
private[this] val TransformedHashKey = "e:sbtTransformHash"
// A hash of the parameters transformation is based on.
// If a descriptor has a different hash, we need to retransform it.
private[this] def makeCoords(mrid: ModuleRevisionId): String = s"${mrid.getOrganisation}:${mrid.getName}:${mrid.getRevision}"
private[this] def makeCoords(mrid: ModuleRevisionId): String =
s"${mrid.getOrganisation}:${mrid.getName}:${mrid.getRevision}"
// We now include the ModuleID in a hash, to ensure that parent-pom transformations don't corrupt child poms.
private[this] def MakeTransformHash(md: ModuleDescriptor): String = {
@ -60,7 +92,8 @@ object CustomPomParser {
hash((unqualifiedKeys ++ JarPackagings ++ Set(coords)).toSeq.sorted)
}
private[this] def hash(ss: Seq[String]): String = Hash.toHex(Hash(ss.flatMap(_ getBytes "UTF-8").toArray))
private[this] def hash(ss: Seq[String]): String =
Hash.toHex(Hash(ss.flatMap(_ getBytes "UTF-8").toArray))
// Unfortunately, ModuleDescriptorParserRegistry is add-only and is a singleton instance.
lazy val registerDefault: Unit = ModuleDescriptorParserRegistry.getInstance.addParser(default)
@ -69,74 +102,93 @@ object CustomPomParser {
if (transformedByThisVersion(md)) md
else defaultTransformImpl(parser, md)
private[this] def transformedByThisVersion(md: ModuleDescriptor): Boolean =
{
val oldTransformedHashKey = "sbtTransformHash"
val extraInfo = md.getExtraInfo
val MyHash = MakeTransformHash(md)
// sbt 0.13.1 used "sbtTransformHash" instead of "e:sbtTransformHash" until #1192 so read both
Option(extraInfo).isDefined &&
((Option(extraInfo get TransformedHashKey) orElse Option(extraInfo get oldTransformedHashKey)) match {
case Some(MyHash) => true
case _ => false
})
}
private[this] def transformedByThisVersion(md: ModuleDescriptor): Boolean = {
val oldTransformedHashKey = "sbtTransformHash"
val extraInfo = md.getExtraInfo
val MyHash = MakeTransformHash(md)
// sbt 0.13.1 used "sbtTransformHash" instead of "e:sbtTransformHash" until #1192 so read both
Option(extraInfo).isDefined &&
((Option(extraInfo get TransformedHashKey) orElse Option(extraInfo get oldTransformedHashKey)) match {
case Some(MyHash) => true
case _ => false
})
}
private[this] def defaultTransformImpl(parser: ModuleDescriptorParser, md: ModuleDescriptor): ModuleDescriptor =
{
val properties = getPomProperties(md)
private[this] def defaultTransformImpl(
parser: ModuleDescriptorParser,
md: ModuleDescriptor
): ModuleDescriptor = {
val properties = getPomProperties(md)
// Extracts extra attributes (currently, sbt and Scala versions) stored in the <properties> element of the pom.
// These are attached to the module itself.
val filtered = shouldBeUnqualified(properties)
// Extracts extra attributes (currently, sbt and Scala versions) stored in the <properties> element of the pom.
// These are attached to the module itself.
val filtered = shouldBeUnqualified(properties)
// Extracts extra attributes for the dependencies.
// Because the <dependency> tag in pom.xml cannot include additional metadata,
// sbt includes extra attributes in a 'extraDependencyAttributes' property.
// This is read/written from/to a pure string (no element structure) because Ivy only
// parses the immediate text nodes of the property.
val extraDepAttributes = getDependencyExtra(filtered)
// Extracts extra attributes for the dependencies.
// Because the <dependency> tag in pom.xml cannot include additional metadata,
// sbt includes extra attributes in a 'extraDependencyAttributes' property.
// This is read/written from/to a pure string (no element structure) because Ivy only
// parses the immediate text nodes of the property.
val extraDepAttributes = getDependencyExtra(filtered)
val unqualify = toUnqualify(filtered)
val unqualify = toUnqualify(filtered)
// Here we always add extra attributes. There's a scenario where parent-pom information corrupts child-poms with "e:" namespaced xml elements
// and we have to force the every generated xml file to have the appropriate xml namespace
addExtra(unqualify, extraDepAttributes, parser, md)
}
// Here we always add extra attributes. There's a scenario where parent-pom information corrupts child-poms with "e:" namespaced xml elements
// and we have to force the every generated xml file to have the appropriate xml namespace
addExtra(unqualify, extraDepAttributes, parser, md)
}
// The <properties> element of the pom is used to store additional metadata, such as for sbt plugins or for the base URL for API docs.
// This is done because the pom XSD does not appear to allow extra metadata anywhere else.
// The extra sbt plugin metadata in pom.xml does not need to be readable by maven, but the other information may be.
// However, the pom.xml needs to be valid in all cases because other tools like repository managers may read the pom.xml.
private[sbt] def getPomProperties(md: ModuleDescriptor): Map[String, String] =
{
import collection.JavaConverters._
PomModuleDescriptorBuilder.extractPomProperties(md.getExtraInfo).asInstanceOf[java.util.Map[String, String]].asScala.toMap
}
private[sbt] def getPomProperties(md: ModuleDescriptor): Map[String, String] = {
import collection.JavaConverters._
PomModuleDescriptorBuilder
.extractPomProperties(md.getExtraInfo)
.asInstanceOf[java.util.Map[String, String]]
.asScala
.toMap
}
private[sbt] def toUnqualify(propertyAttributes: Map[String, String]): Map[String, String] =
(propertyAttributes - ExtraAttributesKey) map { case (k, v) => ("e:" + k, v) }
private[this] def shouldBeUnqualified(m: Map[String, String]): Map[String, String] = m.filterKeys(unqualifiedKeys)
private[this] def shouldBeUnqualified(m: Map[String, String]): Map[String, String] =
m.filterKeys(unqualifiedKeys)
private[this] def addExtra(properties: Map[String, String], id: ModuleRevisionId): ModuleRevisionId =
{
import collection.JavaConverters._
val oldExtra = qualifiedExtra(id)
val newExtra = (oldExtra ++ properties).asJava
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, newExtra)
}
private[this] def addExtra(
properties: Map[String, String],
id: ModuleRevisionId
): ModuleRevisionId = {
import collection.JavaConverters._
val oldExtra = qualifiedExtra(id)
val newExtra = (oldExtra ++ properties).asJava
ModuleRevisionId.newInstance(
id.getOrganisation,
id.getName,
id.getBranch,
id.getRevision,
newExtra
)
}
private[this] def getDependencyExtra(m: Map[String, String]): Map[ModuleRevisionId, Map[String, String]] =
private[this] def getDependencyExtra(
m: Map[String, String]
): Map[ModuleRevisionId, Map[String, String]] =
PomExtraDependencyAttributes.getDependencyExtra(m)
def qualifiedExtra(item: ExtendableItem): Map[String, String] = PomExtraDependencyAttributes.qualifiedExtra(item)
def qualifiedExtra(item: ExtendableItem): Map[String, String] =
PomExtraDependencyAttributes.qualifiedExtra(item)
def filterCustomExtra(item: ExtendableItem, include: Boolean): Map[String, String] =
(qualifiedExtra(item) filterKeys { k => qualifiedIsExtra(k) == include })
(qualifiedExtra(item) filterKeys { k =>
qualifiedIsExtra(k) == include
})
def writeDependencyExtra(s: Seq[DependencyDescriptor]): Seq[String] =
PomExtraDependencyAttributes.writeDependencyExtra(s)
// parses the sequence of dependencies with extra attribute information, with one dependency per line
def readDependencyExtra(s: String): Seq[ModuleRevisionId] = PomExtraDependencyAttributes.readDependencyExtra(s)
def readDependencyExtra(s: String): Seq[ModuleRevisionId] =
PomExtraDependencyAttributes.readDependencyExtra(s)
def qualifiedIsExtra(k: String): Boolean = PomExtraDependencyAttributes.qualifiedIsExtra(k)
@ -145,20 +197,33 @@ object CustomPomParser {
// with the extra attributes from the <properties> section
def simplify(id: ModuleRevisionId): ModuleRevisionId = PomExtraDependencyAttributes.simplify(id)
private[this] def addExtra(dep: DependencyDescriptor, extra: Map[ModuleRevisionId, Map[String, String]]): DependencyDescriptor =
{
val extras = if (extra.isEmpty) None else extra get simplify(dep.getDependencyRevisionId)
extras match {
case None => dep
case Some(extraAttrs) => transform(dep, revId => addExtra(extraAttrs, revId))
}
private[this] def addExtra(
dep: DependencyDescriptor,
extra: Map[ModuleRevisionId, Map[String, String]]
): DependencyDescriptor = {
val extras = if (extra.isEmpty) None else extra get simplify(dep.getDependencyRevisionId)
extras match {
case None => dep
case Some(extraAttrs) => transform(dep, revId => addExtra(extraAttrs, revId))
}
private[this] def transform(dep: DependencyDescriptor, f: ModuleRevisionId => ModuleRevisionId): DependencyDescriptor =
DefaultDependencyDescriptor.transformInstance(dep, namespaceTransformer(dep.getDependencyRevisionId, f), false)
}
private[this] def transform(
dep: DependencyDescriptor,
f: ModuleRevisionId => ModuleRevisionId
): DependencyDescriptor =
DefaultDependencyDescriptor.transformInstance(
dep,
namespaceTransformer(dep.getDependencyRevisionId, f),
false
)
private[this] def namespaceTransformer(txId: ModuleRevisionId, f: ModuleRevisionId => ModuleRevisionId): NamespaceTransformer =
private[this] def namespaceTransformer(
txId: ModuleRevisionId,
f: ModuleRevisionId => ModuleRevisionId
): NamespaceTransformer =
new NamespaceTransformer {
def transform(revId: ModuleRevisionId): ModuleRevisionId = if (revId == txId) f(revId) else revId
def transform(revId: ModuleRevisionId): ModuleRevisionId =
if (revId == txId) f(revId) else revId
def isIdentity = false
}
@ -167,53 +232,80 @@ object CustomPomParser {
VersionRange.stripMavenVersionRange(dd.getDependencyRevisionId.getRevision) match {
case Some(newVersion) =>
val id = dd.getDependencyRevisionId
val newId = ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, newVersion, id.getExtraAttributes)
val newId = ModuleRevisionId.newInstance(
id.getOrganisation,
id.getName,
id.getBranch,
newVersion,
id.getExtraAttributes
)
transform(dd, _ => newId)
case None => dd
}
private[sbt] lazy val versionRangeFlag = sys.props.get("sbt.modversionrange") map { _.toLowerCase == "true" } getOrElse true
private[sbt] lazy val versionRangeFlag = sys.props.get("sbt.modversionrange") map {
_.toLowerCase == "true"
} getOrElse true
import collection.JavaConverters._
def addExtra(properties: Map[String, String], dependencyExtra: Map[ModuleRevisionId, Map[String, String]], parser: ModuleDescriptorParser, md: ModuleDescriptor): ModuleDescriptor =
{
val dmd = new DefaultModuleDescriptor(parser, md.getResource)
def addExtra(
properties: Map[String, String],
dependencyExtra: Map[ModuleRevisionId, Map[String, String]],
parser: ModuleDescriptorParser,
md: ModuleDescriptor
): ModuleDescriptor = {
val dmd = new DefaultModuleDescriptor(parser, md.getResource)
val mrid = addExtra(properties, md.getModuleRevisionId)
val resolvedMrid = addExtra(properties, md.getResolvedModuleRevisionId)
dmd.setModuleRevisionId(mrid)
dmd.setResolvedModuleRevisionId(resolvedMrid)
val mrid = addExtra(properties, md.getModuleRevisionId)
val resolvedMrid = addExtra(properties, md.getResolvedModuleRevisionId)
dmd.setModuleRevisionId(mrid)
dmd.setResolvedModuleRevisionId(resolvedMrid)
dmd.setDefault(md.isDefault)
dmd.setHomePage(md.getHomePage)
dmd.setDescription(md.getDescription)
dmd.setLastModified(md.getLastModified)
dmd.setStatus(md.getStatus())
dmd.setPublicationDate(md.getPublicationDate())
dmd.setResolvedPublicationDate(md.getResolvedPublicationDate())
dmd.setDefault(md.isDefault)
dmd.setHomePage(md.getHomePage)
dmd.setDescription(md.getDescription)
dmd.setLastModified(md.getLastModified)
dmd.setStatus(md.getStatus())
dmd.setPublicationDate(md.getPublicationDate())
dmd.setResolvedPublicationDate(md.getResolvedPublicationDate())
for (l <- md.getLicenses) dmd.addLicense(l)
for ((key, value) <- md.getExtraInfo.asInstanceOf[java.util.Map[String, String]].asScala) dmd.addExtraInfo(key, value)
dmd.addExtraInfo(TransformedHashKey, MakeTransformHash(md)) // mark as transformed by this version, so we don't need to do it again
for ((key, value) <- md.getExtraAttributesNamespaces.asInstanceOf[java.util.Map[String, String]].asScala) dmd.addExtraAttributeNamespace(key, value)
IvySbt.addExtraNamespace(dmd)
for (l <- md.getLicenses) dmd.addLicense(l)
for ((key, value) <- md.getExtraInfo.asInstanceOf[java.util.Map[String, String]].asScala)
dmd.addExtraInfo(key, value)
dmd.addExtraInfo(TransformedHashKey, MakeTransformHash(md)) // mark as transformed by this version, so we don't need to do it again
for ((key, value) <- md.getExtraAttributesNamespaces
.asInstanceOf[java.util.Map[String, String]]
.asScala) dmd.addExtraAttributeNamespace(key, value)
IvySbt.addExtraNamespace(dmd)
val withExtra = md.getDependencies map { dd => addExtra(dd, dependencyExtra) }
val withVersionRangeMod: Seq[DependencyDescriptor] =
if (versionRangeFlag) withExtra map { stripVersionRange }
else withExtra
val unique = IvySbt.mergeDuplicateDefinitions(withVersionRangeMod)
unique foreach dmd.addDependency
for (ed <- md.getInheritedDescriptors) dmd.addInheritedDescriptor(new DefaultExtendsDescriptor(md, ed.getLocation, ed.getExtendsTypes))
for (conf <- md.getConfigurations) {
dmd.addConfiguration(conf)
for (art <- md.getArtifacts(conf.getName)) {
val ext = art.getExt
val newExt = if (JarPackagings(ext)) "jar" else ext
val nart = new DefaultArtifact(mrid, art.getPublicationDate, art.getName, art.getType, newExt, art.getUrl, art.getQualifiedExtraAttributes)
dmd.addArtifact(conf.getName, nart)
}
}
dmd
val withExtra = md.getDependencies map { dd =>
addExtra(dd, dependencyExtra)
}
val withVersionRangeMod: Seq[DependencyDescriptor] =
if (versionRangeFlag) withExtra map { stripVersionRange } else withExtra
val unique = IvySbt.mergeDuplicateDefinitions(withVersionRangeMod)
unique foreach dmd.addDependency
for (ed <- md.getInheritedDescriptors)
dmd.addInheritedDescriptor(
new DefaultExtendsDescriptor(md, ed.getLocation, ed.getExtendsTypes)
)
for (conf <- md.getConfigurations) {
dmd.addConfiguration(conf)
for (art <- md.getArtifacts(conf.getName)) {
val ext = art.getExt
val newExt = if (JarPackagings(ext)) "jar" else ext
val nart = new DefaultArtifact(
mrid,
art.getPublicationDate,
art.getName,
art.getType,
newExt,
art.getUrl,
art.getQualifiedExtraAttributes
)
dmd.addArtifact(conf.getName, nart)
}
}
dmd
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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).
* 3. Cache location includes extra attributes so that cross builds of a plugin do not overwrite each other.
*/
private[sbt] final class ResolutionCache(base: File, settings: IvySettings) extends ResolutionCacheManager {
private[sbt] final class ResolutionCache(base: File, settings: IvySettings)
extends ResolutionCacheManager {
private[this] def resolvedFileInCache(m: ModuleRevisionId, name: String, ext: String): File = {
val p = ResolvedPattern
val f = IvyPatternHelper.substitute(p, m.getOrganisation, m.getName, m.getBranch, m.getRevision, name, name, ext, null, null, m.getAttributes, null)
val f = IvyPatternHelper.substitute(
p,
m.getOrganisation,
m.getName,
m.getBranch,
m.getRevision,
name,
name,
ext,
null,
null,
m.getAttributes,
null
)
new File(base, f)
}
private[this] val reportBase: File = new File(base, ReportDirectory)
@ -62,11 +76,16 @@ private[sbt] final class ResolutionCache(base: File, settings: IvySettings) exte
}
}
private[sbt] object ResolutionCache {
/**
* Removes cached files from the resolution cache for the module with ID `mrid`
* and the resolveId (as set on `ResolveOptions`).
*/
private[sbt] def cleanModule(mrid: ModuleRevisionId, resolveId: String, manager: ResolutionCacheManager): Unit = {
private[sbt] def cleanModule(
mrid: ModuleRevisionId,
resolveId: String,
manager: ResolutionCacheManager
): Unit = {
val files =
Option(manager.getResolvedIvyFileInCache(mrid)).toList :::
Option(manager.getResolvedIvyPropertiesInCache(mrid)).toList :::

View File

@ -9,7 +9,8 @@ abstract class SbtExclusionRuleFunctions {
def apply(organization: String): SbtExclusionRule = apply(organization, "*")
implicit def groupIdToExclusionRule(organization: GroupID): SbtExclusionRule = apply(organization.groupID)
implicit def groupIdToExclusionRule(organization: GroupID): SbtExclusionRule =
apply(organization.groupID)
implicit def stringToExclusionRule(organization: String): SbtExclusionRule = apply(organization)
implicit def groupArtifactIDToExclusionRule(gaid: GroupArtifactID): SbtExclusionRule =

View File

@ -6,8 +6,12 @@ package sbt.internal.librarymanagement
import java.util.Locale
object StringUtilities {
@deprecated("Different use cases require different normalization. Use Project.normalizeModuleID or normalizeProjectID instead.", "0.13.0")
@deprecated(
"Different use cases require different normalization. Use Project.normalizeModuleID or normalizeProjectID instead.",
"0.13.0"
)
def normalize(s: String) = s.toLowerCase(Locale.ENGLISH).replaceAll("""\W+""", "-")
def nonEmpty(s: String, label: String): Unit = require(s.trim.length > 0, label + " cannot be empty.")
def nonEmpty(s: String, label: String): Unit =
require(s.trim.length > 0, label + " cannot be empty.")
def appendable(s: String) = if (s.isEmpty) "" else "_" + s
}

View File

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

View File

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

View File

@ -8,15 +8,23 @@ trait UpdateOptionsFormat { self: BasicJsonProtocol =>
implicit lazy val UpdateOptionsFormat: JsonFormat[UpdateOptions] =
project(
(uo: UpdateOptions) => (
uo.circularDependencyLevel.name,
uo.interProjectFirst,
uo.latestSnapshots,
uo.consolidatedResolution,
uo.cachedResolution
(uo: UpdateOptions) =>
(
uo.circularDependencyLevel.name,
uo.interProjectFirst,
uo.latestSnapshots,
uo.consolidatedResolution,
uo.cachedResolution
),
(xs: (String, Boolean, Boolean, Boolean, Boolean)) =>
new UpdateOptions(levels(xs._1), xs._2, xs._3, xs._4, xs._5, ConvertResolver.defaultConvert)
new UpdateOptions(
levels(xs._1),
xs._2,
xs._3,
xs._4,
xs._5,
ConvertResolver.defaultConvert
)
)
private val levels: Map[String, CircularDependencyLevel] = Map(

View File

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

View File

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

View File

@ -44,7 +44,9 @@ object ErrorMessageAuthenticator {
case originalOpt => installIntoIvyImpl(originalOpt)
} catch {
case t: Throwable =>
Message.debug("Error occurred while trying to install debug messages into Ivy Authentication" + t.getMessage)
Message.debug(
"Error occurred while trying to install debug messages into Ivy Authentication" + t.getMessage
)
}
Some(ivy)
}
@ -57,8 +59,10 @@ object ErrorMessageAuthenticator {
catch {
case e: SecurityException if !securityWarningLogged =>
securityWarningLogged = true
Message.warn("Not enough permissions to set the ErrorMessageAuthenticator. "
+ "Helpful debug messages disabled!");
Message.warn(
"Not enough permissions to set the ErrorMessageAuthenticator. "
+ "Helpful debug messages disabled!"
);
}
// We will try to use the original authenticator as backup authenticator.
// Since there is no getter available, so try to use some reflection to
@ -73,6 +77,7 @@ object ErrorMessageAuthenticator {
doInstallIfIvy(originalAuthenticator)
}
}
/**
* An authenticator which just delegates to a previous authenticator and issues *nice*
* error messages on failure to find credentials.
@ -80,7 +85,8 @@ object ErrorMessageAuthenticator {
* Since ivy installs its own credentials handler EVERY TIME it resolves or publishes, we want to
* install this one at some point and eventually ivy will capture it and use it.
*/
private[sbt] final class ErrorMessageAuthenticator(original: Option[Authenticator]) extends Authenticator {
private[sbt] final class ErrorMessageAuthenticator(original: Option[Authenticator])
extends Authenticator {
protected override def getPasswordAuthentication(): PasswordAuthentication = {
// We're guaranteed to only get here if Ivy's authentication fails
@ -104,14 +110,16 @@ private[sbt] final class ErrorMessageAuthenticator(original: Option[Authenticato
// Grabs the authentication that would have been provided had we not been installed...
def originalAuthentication: Option[PasswordAuthentication] = {
Authenticator.setDefault(original.orNull)
try Option(Authenticator.requestPasswordAuthentication(
getRequestingHost,
getRequestingSite,
getRequestingPort,
getRequestingProtocol,
getRequestingPrompt,
getRequestingScheme
))
try Option(
Authenticator.requestPasswordAuthentication(
getRequestingHost,
getRequestingSite,
getRequestingPort,
getRequestingProtocol,
getRequestingPrompt,
getRequestingScheme
)
)
finally Authenticator.setDefault(this)
}
originalAuthentication.orNull

View File

@ -6,8 +6,10 @@ import collection.JavaConverters._
/** A key used to store credentials in the ivy credentials store. */
private[sbt] sealed trait CredentialKey
/** Represents a key in the ivy credentials store that is only specific to a host. */
private[sbt] case class Host(name: String) extends CredentialKey
/** Represents a key in the ivy credentials store that is keyed to both a host and a "realm". */
private[sbt] case class Realm(host: String, realm: String) extends CredentialKey
@ -61,4 +63,4 @@ private[sbt] object IvyCredentialsLookup {
} mapValues { realms =>
realms map (_.realm)
}
}
}

View File

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

View File

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

View File

@ -25,13 +25,16 @@ object PomExtraDependencyAttributes {
val ExtraAttributesKey = "extraDependencyAttributes"
val SbtVersionKey = "sbtVersion"
val ScalaVersionKey = "scalaVersion"
/**
* Reads the extra dependency attributes out of a maven property.
* @param props The properties from an Aether resolution.
* @return
* A map of module id to extra dependency attributes associated with dependencies on that module.
*/
def readFromAether(props: java.util.Map[String, AnyRef]): Map[ModuleRevisionId, Map[String, String]] = {
def readFromAether(
props: java.util.Map[String, AnyRef]
): Map[ModuleRevisionId, Map[String, String]] = {
import scala.collection.JavaConverters._
(props.asScala get ExtraAttributesKey) match {
case None => Map.empty
@ -52,7 +55,10 @@ object PomExtraDependencyAttributes {
* TODO - maybe we can just parse this directly here. Note the `readFromAether` method uses
* whatever we set here.
*/
def transferDependencyExtraAttributes(from: Properties, to: java.util.Map[String, AnyRef]): Unit =
def transferDependencyExtraAttributes(
from: Properties,
to: java.util.Map[String, AnyRef]
): Unit =
Option(from.getProperty(ExtraAttributesKey, null)) foreach (to.put(ExtraAttributesKey, _))
/**
@ -72,16 +78,25 @@ object PomExtraDependencyAttributes {
item.getQualifiedExtraAttributes.asInstanceOf[java.util.Map[String, String]].asScala.toMap
}
def filterCustomExtra(item: ExtendableItem, include: Boolean): Map[String, String] =
(qualifiedExtra(item) filterKeys { k => qualifiedIsExtra(k) == include })
(qualifiedExtra(item) filterKeys { k =>
qualifiedIsExtra(k) == include
})
def qualifiedIsExtra(k: String): Boolean = k.endsWith(ScalaVersionKey) || k.endsWith(SbtVersionKey)
def qualifiedIsExtra(k: String): Boolean =
k.endsWith(ScalaVersionKey) || k.endsWith(SbtVersionKey)
// Reduces the id to exclude custom extra attributes
// This makes the id suitable as a key to associate a dependency parsed from a <dependency> element
// with the extra attributes from the <properties> section
def simplify(id: ModuleRevisionId): ModuleRevisionId = {
import scala.collection.JavaConverters._
ModuleRevisionId.newInstance(id.getOrganisation, id.getName, id.getBranch, id.getRevision, filterCustomExtra(id, include = false).asJava)
ModuleRevisionId.newInstance(
id.getOrganisation,
id.getName,
id.getBranch,
id.getRevision,
filterCustomExtra(id, include = false).asJava
)
}
/** parses the sequence of dependencies with extra attribute information, with one dependency per line */

View File

@ -16,28 +16,48 @@ abstract class ArtifactExtra {
def extraAttributes: Map[String, String]
protected[this] def copy(
name: String = name,
`type`: String = `type`,
extension: String = extension,
classifier: Option[String] = classifier,
configurations: Vector[Configuration] = configurations,
url: Option[URL] = url,
extraAttributes: Map[String, String] = extraAttributes
name: String = name,
`type`: String = `type`,
extension: String = extension,
classifier: Option[String] = classifier,
configurations: Vector[Configuration] = configurations,
url: Option[URL] = url,
extraAttributes: Map[String, String] = extraAttributes
): Artifact
def extra(attributes: (String, String)*) = copy(extraAttributes = extraAttributes ++ ModuleID.checkE(attributes))
def extra(attributes: (String, String)*) =
copy(extraAttributes = extraAttributes ++ ModuleID.checkE(attributes))
}
import Configurations.{ Optional, Pom, Test }
abstract class ArtifactFunctions {
def apply(name: String, extra: Map[String, String]): Artifact = Artifact(name, DefaultType, DefaultExtension, None, Vector.empty, None, extra)
def apply(name: String, classifier: String): Artifact = Artifact(name, DefaultType, DefaultExtension, Some(classifier), Vector.empty, None)
def apply(name: String, `type`: String, extension: String): Artifact = Artifact(name, `type`, extension, None, Vector.empty, None)
def apply(name: String, `type`: String, extension: String, classifier: String): Artifact = Artifact(name, `type`, extension, Some(classifier), Vector.empty, None)
def apply(name: String, url: URL): Artifact = Artifact(name, extract(url, DefaultType), extract(url, DefaultExtension), None, Vector.empty, Some(url))
def apply(name: String, extra: Map[String, String]): Artifact =
Artifact(name, DefaultType, DefaultExtension, None, Vector.empty, None, extra)
def apply(name: String, classifier: String): Artifact =
Artifact(name, DefaultType, DefaultExtension, Some(classifier), Vector.empty, None)
def apply(name: String, `type`: String, extension: String): Artifact =
Artifact(name, `type`, extension, None, Vector.empty, None)
def apply(name: String, `type`: String, extension: String, classifier: String): Artifact =
Artifact(name, `type`, extension, Some(classifier), Vector.empty, None)
def apply(name: String, url: URL): Artifact =
Artifact(
name,
extract(url, DefaultType),
extract(url, DefaultExtension),
None,
Vector.empty,
Some(url)
)
def apply(name: String, `type`: String, extension: String, classifier: Option[String], configurations: Vector[Configuration], url: Option[URL]): Artifact =
def apply(
name: String,
`type`: String,
extension: String,
classifier: Option[String],
configurations: Vector[Configuration],
url: Option[URL]
): Artifact =
Artifact(name, `type`, extension, classifier, configurations, url, Map.empty[String, String])
val DefaultExtension = "jar"
@ -66,29 +86,33 @@ abstract class ArtifactFunctions {
assert(DefaultSourceTypes contains SourceType)
def extract(url: URL, default: String): String = extract(url.toString, default)
def extract(name: String, default: String): String =
{
val i = name.lastIndexOf('.')
if (i >= 0)
name.substring(i + 1)
else
default
}
def defaultArtifact(file: File) =
{
val name = file.getName
val i = name.lastIndexOf('.')
val base = if (i >= 0) name.substring(0, i) else name
Artifact(base, extract(name, DefaultType), extract(name, DefaultExtension), None, Vector.empty, Some(file.toURI.toURL))
}
def artifactName(scalaVersion: ScalaVersion, module: ModuleID, artifact: Artifact): String =
{
import artifact._
val classifierStr = classifier match { case None => ""; case Some(c) => "-" + c }
val cross = CrossVersion(module.crossVersion, scalaVersion.full, scalaVersion.binary)
val base = CrossVersion.applyCross(artifact.name, cross)
base + "-" + module.revision + classifierStr + "." + artifact.extension
}
def extract(name: String, default: String): String = {
val i = name.lastIndexOf('.')
if (i >= 0)
name.substring(i + 1)
else
default
}
def defaultArtifact(file: File) = {
val name = file.getName
val i = name.lastIndexOf('.')
val base = if (i >= 0) name.substring(0, i) else name
Artifact(
base,
extract(name, DefaultType),
extract(name, DefaultExtension),
None,
Vector.empty,
Some(file.toURI.toURL)
)
}
def artifactName(scalaVersion: ScalaVersion, module: ModuleID, artifact: Artifact): String = {
import artifact._
val classifierStr = classifier match { case None => ""; case Some(c) => "-" + c }
val cross = CrossVersion(module.crossVersion, scalaVersion.full, scalaVersion.binary)
val base = CrossVersion.applyCross(artifact.name, cross)
base + "-" + module.revision + classifierStr + "." + artifact.extension
}
val classifierTypeMap = Map(SourceClassifier -> SourceType, DocClassifier -> DocType)
@deprecated("Configuration should not be decided from the classifier.", "1.0")
@ -97,7 +121,8 @@ abstract class ArtifactFunctions {
Test
else
Optional
def classifierType(classifier: String): String = classifierTypeMap.getOrElse(classifier.stripPrefix(TestsClassifier + "-"), DefaultType)
def classifierType(classifier: String): String =
classifierTypeMap.getOrElse(classifier.stripPrefix(TestsClassifier + "-"), DefaultType)
/**
* Create a classified explicit artifact, to be used when trying to resolve sources|javadocs from Maven. This is
@ -105,5 +130,12 @@ abstract class ArtifactFunctions {
* The artifact is created under the default configuration.
*/
def classified(name: String, classifier: String): Artifact =
Artifact(name, classifierType(classifier), DefaultExtension, Some(classifier), Vector.empty, None)
Artifact(
name,
classifierType(classifier),
DefaultExtension,
Some(classifier),
Vector.empty,
None
)
}

View File

@ -1,6 +1,11 @@
package sbt.librarymanagement
import org.apache.ivy.plugins.circular.{ CircularDependencyStrategy, WarnCircularDependencyStrategy, IgnoreCircularDependencyStrategy, ErrorCircularDependencyStrategy }
import org.apache.ivy.plugins.circular.{
CircularDependencyStrategy,
WarnCircularDependencyStrategy,
IgnoreCircularDependencyStrategy,
ErrorCircularDependencyStrategy
}
/**
* Wrapper around circular dependency strategy.

View File

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

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
* library dependency graph by mistake, but it won't be caught by eviction.
*/
final case class ConflictWarning(label: String, level: Level.Value, failOnConflict: Boolean) {
}
final case class ConflictWarning(label: String, level: Level.Value, failOnConflict: Boolean) {}
object ConflictWarning {
def disable: ConflictWarning = ConflictWarning("", Level.Debug, false)
@ -19,10 +18,15 @@ object ConflictWarning {
def apply(config: ConflictWarning, report: UpdateReport, log: Logger): Unit = {
processCrossVersioned(config, report, log)
}
private[this] def processCrossVersioned(config: ConflictWarning, report: UpdateReport, log: Logger): Unit = {
private[this] def processCrossVersioned(
config: ConflictWarning,
report: UpdateReport,
log: Logger
): Unit = {
val crossMismatches = crossVersionMismatches(report)
if (crossMismatches.nonEmpty) {
val pre = s"Modules were resolved with conflicting cross-version suffixes in ${config.label}:\n "
val pre =
s"Modules were resolved with conflicting cross-version suffixes in ${config.label}:\n "
val conflictMsgs =
for (((org, rawName), fullNames) <- crossMismatches) yield {
val suffixes = fullNames.map(getCrossSuffix).mkString(", ")
@ -30,25 +34,26 @@ object ConflictWarning {
}
log.log(config.level, conflictMsgs.mkString(pre, "\n ", ""))
if (config.failOnConflict) {
val summary = crossMismatches.map { case ((org, raw), _) => idString(org, raw) }.mkString(", ")
val summary =
crossMismatches.map { case ((org, raw), _) => idString(org, raw) }.mkString(", ")
sys.error("Conflicting cross-version suffixes in: " + summary)
}
}
}
/** Map from (organization, rawName) to set of multiple full names. */
def crossVersionMismatches(report: UpdateReport): Map[(String, String), Set[String]] =
{
val mismatches = report.configurations.flatMap { confReport =>
groupByRawName(confReport.allModules).mapValues { modules =>
val differentFullNames = modules.map(_.name).toSet
if (differentFullNames.size > 1) differentFullNames else Set.empty[String]
}
def crossVersionMismatches(report: UpdateReport): Map[(String, String), Set[String]] = {
val mismatches = report.configurations.flatMap { confReport =>
groupByRawName(confReport.allModules).mapValues { modules =>
val differentFullNames = modules.map(_.name).toSet
if (differentFullNames.size > 1) differentFullNames else Set.empty[String]
}
(Map.empty[(String, String), Set[String]] /: mismatches)(merge)
}
(Map.empty[(String, String), Set[String]] /: mismatches)(merge)
}
private[this] def merge[A, B](m: Map[A, Set[B]], b: (A, Set[B])): Map[A, Set[B]] =
if (b._2.isEmpty) m else
if (b._2.isEmpty) m
else
m.updated(b._1, m.getOrElse(b._1, Set.empty) ++ b._2)
private[this] def groupByRawName(ms: Seq[ModuleID]): Map[(String, String), Seq[ModuleID]] =

View File

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

View File

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

View File

@ -6,7 +6,8 @@ import sbt.internal.librarymanagement._
import sbt.util.Logger
import sbt.io.Hash
class DefaultLibraryManagement(ivyConfiguration: IvyConfiguration, log: Logger) extends LibraryManagement {
class DefaultLibraryManagement(ivyConfiguration: IvyConfiguration, log: Logger)
extends LibraryManagement {
private[sbt] val ivySbt: IvySbt = new IvySbt(ivyConfiguration)
private val sbtOrgTemp = JsonUtil.sbtOrgTemp
private val modulePrefixTemp = "temp-module-"
@ -22,12 +23,17 @@ class DefaultLibraryManagement(ivyConfiguration: IvyConfiguration, log: Logger)
def getModule(moduleId: ModuleID, ivyScala: Option[IvyScala]): ivySbt.Module = {
val sha1 = Hash.toHex(Hash(moduleId.name))
val dummyID = ModuleID(sbtOrgTemp, modulePrefixTemp + sha1, moduleId.revision).withConfigurations(moduleId.configurations)
val dummyID = ModuleID(sbtOrgTemp, modulePrefixTemp + sha1, moduleId.revision)
.withConfigurations(moduleId.configurations)
getModule(dummyID, Vector(moduleId), UpdateOptions(), ivyScala)
}
def getModule(moduleId: ModuleID, deps: Vector[ModuleID],
uo: UpdateOptions = UpdateOptions(), ivyScala: Option[IvyScala]): ivySbt.Module = {
def getModule(
moduleId: ModuleID,
deps: Vector[ModuleID],
uo: UpdateOptions = UpdateOptions(),
ivyScala: Option[IvyScala]
): ivySbt.Module = {
val moduleSetting = InlineConfiguration(
validate = false,
ivyScala = ivyScala,
@ -51,14 +57,29 @@ class DefaultLibraryManagement(ivyConfiguration: IvyConfiguration, log: Logger)
s"unknown"
}
def update(module: ivySbt.Module, retrieveDirectory: File)(predicate: File => Boolean): Option[Seq[File]] = {
def update(module: ivySbt.Module, retrieveDirectory: File)(
predicate: File => Boolean
): Option[Seq[File]] = {
val specialArtifactTypes = Artifact.DefaultSourceTypes union Artifact.DefaultDocTypes
val artifactFilter = ArtifactTypeFilter.forbid(specialArtifactTypes)
val retrieveConfiguration = RetrieveConfiguration(retrieveDirectory, Resolver.defaultRetrievePattern).withSync(false)
val updateConfiguration = UpdateConfiguration(Some(retrieveConfiguration), true, UpdateLogging.DownloadOnly, artifactFilter)
val retrieveConfiguration =
RetrieveConfiguration(retrieveDirectory, Resolver.defaultRetrievePattern).withSync(false)
val updateConfiguration = UpdateConfiguration(
Some(retrieveConfiguration),
true,
UpdateLogging.DownloadOnly,
artifactFilter
)
log.debug(s"Attempting to fetch ${dependenciesNames(module)}. This operation may fail.")
IvyActions.updateEither(module, updateConfiguration, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, log) match {
IvyActions.updateEither(
module,
updateConfiguration,
UnresolvedWarningConfiguration(),
LogicalClock.unknown,
None,
log
) match {
case Left(unresolvedWarning) =>
log.debug(s"Couldn't retrieve module ${dependenciesNames(module)}.")
None

View File

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

View File

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

View File

@ -14,7 +14,10 @@ abstract class ArtifactTypeFilterExtra {
def types: Set[String]
def inverted: Boolean
protected[this] def copy(types: Set[String] = types, inverted: Boolean = inverted): ArtifactTypeFilter
protected[this] def copy(
types: Set[String] = types,
inverted: Boolean = inverted
): ArtifactTypeFilter
def invert = copy(inverted = !inverted)
def apply(a: descriptor.Artifact): Boolean = (types contains a.getType) ^ inverted
@ -25,7 +28,9 @@ abstract class ArtifactTypeFilterFunctions {
def forbid(types: Set[String]) = ArtifactTypeFilter(types, true)
implicit def toIvyFilter(f: ArtifactTypeFilter): IvyFilter = new IvyFilter {
override def accept(o: Object): Boolean = Option(o) exists { case a: descriptor.Artifact => f.apply(a) }
override def accept(o: Object): Boolean = Option(o) exists {
case a: descriptor.Artifact => f.apply(a)
}
}
}

View File

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

View File

@ -24,53 +24,56 @@ abstract class ModuleIDExtra {
def branchName: Option[String]
protected[this] def copy(
organization: String = organization,
name: String = name,
revision: String = revision,
configurations: Option[String] = configurations,
isChanging: Boolean = isChanging,
isTransitive: Boolean = isTransitive,
isForce: Boolean = isForce,
explicitArtifacts: Vector[Artifact] = explicitArtifacts,
inclusions: Vector[InclusionRule] = inclusions,
exclusions: Vector[ExclusionRule] = exclusions,
extraAttributes: Map[String, String] = extraAttributes,
crossVersion: CrossVersion = crossVersion,
branchName: Option[String] = branchName
organization: String = organization,
name: String = name,
revision: String = revision,
configurations: Option[String] = configurations,
isChanging: Boolean = isChanging,
isTransitive: Boolean = isTransitive,
isForce: Boolean = isForce,
explicitArtifacts: Vector[Artifact] = explicitArtifacts,
inclusions: Vector[InclusionRule] = inclusions,
exclusions: Vector[ExclusionRule] = exclusions,
extraAttributes: Map[String, String] = extraAttributes,
crossVersion: CrossVersion = crossVersion,
branchName: Option[String] = branchName
): ModuleID
protected def toStringImpl: String =
s"""$organization:$name:$revision""" +
(configurations match { case Some(s) => ":" + s; case None => "" }) +
{
val attr = attributeString
if (attr == "") ""
else " " + attr
} +
(configurations match { case Some(s) => ":" + s; case None => "" }) + {
val attr = attributeString
if (attr == "") ""
else " " + attr
} +
(if (extraAttributes.isEmpty) "" else " " + extraString)
protected def attributeString: String =
{
val buffer = ListBuffer.empty[String]
if (isChanging) {
buffer += "changing"
}
if (!isTransitive) {
buffer += "intransitive"
}
if (isForce) {
buffer += "force"
}
buffer.toList.mkString(";")
protected def attributeString: String = {
val buffer = ListBuffer.empty[String]
if (isChanging) {
buffer += "changing"
}
if (!isTransitive) {
buffer += "intransitive"
}
if (isForce) {
buffer += "force"
}
buffer.toList.mkString(";")
}
/** String representation of the extra attributes, excluding any information only attributes. */
def extraString: String = extraDependencyAttributes.map { case (k, v) => k + "=" + v } mkString ("(", ", ", ")")
def extraString: String =
extraDependencyAttributes.map { case (k, v) => k + "=" + v } mkString ("(", ", ", ")")
/** Returns the extra attributes except for ones marked as information only (ones that typically would not be used for dependency resolution). */
def extraDependencyAttributes: Map[String, String] = extraAttributes.filterKeys(!_.startsWith(SbtPomExtraProperties.POM_INFO_KEY_PREFIX))
def extraDependencyAttributes: Map[String, String] =
extraAttributes.filterKeys(!_.startsWith(SbtPomExtraProperties.POM_INFO_KEY_PREFIX))
@deprecated("Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.", "0.12.0")
@deprecated(
"Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.",
"0.12.0"
)
def cross(v: Boolean): ModuleID = cross(if (v) CrossVersion.binary else Disabled())
/** Specifies the cross-version behavior for this module. See [CrossVersion] for details.*/
@ -111,7 +114,8 @@ abstract class ModuleIDExtra {
* Declares the explicit artifacts for this module. If this ModuleID represents a dependency,
* these artifact definitions override the information in the dependency's published metadata.
*/
def artifacts(newArtifacts: Artifact*) = copy(explicitArtifacts = newArtifacts.toVector ++ explicitArtifacts)
def artifacts(newArtifacts: Artifact*) =
copy(explicitArtifacts = newArtifacts.toVector ++ explicitArtifacts)
/**
* Applies the provided exclusions to dependencies of this module. Note that only exclusions that specify
@ -120,13 +124,15 @@ abstract class ModuleIDExtra {
def excludeAll(rules: InclExclRule*) = copy(exclusions = this.exclusions ++ rules)
/** Excludes the dependency with organization `org` and `name` from being introduced by this dependency during resolution. */
def exclude(org: String, name: String) = excludeAll(InclExclRule().withOrganization(org).withName(name))
def exclude(org: String, name: String) =
excludeAll(InclExclRule().withOrganization(org).withName(name))
/**
* Adds extra attributes for this module. All keys are prefixed with `e:` if they are not already so prefixed.
* This information will only be published in an ivy.xml and not in a pom.xml.
*/
def extra(attributes: (String, String)*) = copy(extraAttributes = this.extraAttributes ++ ModuleID.checkE(attributes))
def extra(attributes: (String, String)*) =
copy(extraAttributes = this.extraAttributes ++ ModuleID.checkE(attributes))
/**
* Not recommended for new use. This method is not deprecated, but the `update-classifiers` task is preferred
@ -175,7 +181,9 @@ abstract class ModuleIDExtra {
}
abstract class ModuleIDFunctions {
/** Prefixes all keys with `e:` if they are not already so prefixed. */
def checkE(attributes: Seq[(String, String)]) =
for ((key, value) <- attributes) yield if (key.startsWith("e:")) (key, value) else ("e:" + key, value)
for ((key, value) <- attributes)
yield if (key.startsWith("e:")) (key, value) else ("e:" + key, value)
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,9 @@
package sbt.librarymanagement
final class VersionNumber private[sbt] (
val numbers: Seq[Long],
val tags: Seq[String],
val extras: Seq[String]
val numbers: Seq[Long],
val tags: Seq[String],
val extras: Seq[String]
) {
def _1: Option[Long] = get(0)
def _2: Option[Long] = get(1)
@ -33,12 +33,14 @@ final class VersionNumber private[sbt] (
extras.hashCode
override def equals(o: Any): Boolean =
o match {
case v: VersionNumber => (this.numbers == v.numbers) && (this.tags == v.tags) && (this.extras == v.extras)
case _ => false
case v: VersionNumber =>
(this.numbers == v.numbers) && (this.tags == v.tags) && (this.extras == v.extras)
case _ => false
}
}
object VersionNumber {
/**
* @param numbers numbers delimited by a dot.
* @param tags string prefixed by a dash.
@ -74,10 +76,11 @@ object VersionNumber {
val TaggedVersion = """(\d{1,14})([\.\d{1,14}]*)((?:-\w+)*)((?:\+.+)*)""".r
val NonSpaceString = """(\S+)""".r
v match {
case TaggedVersion(m, ns, ts, es) => Some((Vector(m.toLong) ++ splitDot(ns), splitDash(ts), splitPlus(es)))
case "" => None
case NonSpaceString(s) => Some((Vector(), Vector(), Vector(s)))
case _ => None
case TaggedVersion(m, ns, ts, es) =>
Some((Vector(m.toLong) ++ splitDot(ns), splitDash(ts), splitPlus(es)))
case "" => None
case NonSpaceString(s) => Some((Vector(), Vector(), Vector(s)))
case _ => None
}
}
@ -98,8 +101,18 @@ object VersionNumber {
doIsCompat(v1, v2) || doIsCompat(v2, v1)
private[this] def doIsCompat(v1: VersionNumber, v2: VersionNumber): Boolean =
(v1, v2) match {
case (v1, v2) if (v1.size >= 2) && (v2.size >= 2) => // A normal version number MUST take the form X.Y.Z
(v1._1.get, v1._2.get, v1._3.getOrElse(0L), v1.tags, v2._1.get, v2._2.get, v2._3.getOrElse(0L), v2.tags) match {
case (v1, v2)
if (v1.size >= 2) && (v2.size >= 2) => // A normal version number MUST take the form X.Y.Z
(
v1._1.get,
v1._2.get,
v1._3.getOrElse(0L),
v1.tags,
v2._1.get,
v2._2.get,
v2._3.getOrElse(0L),
v2.tags
) match {
case (0L, _, _, _, 0L, _, _, _) =>
// Major version zero (0.y.z) is for initial development. Anything may change at any time. The public API should not be considered stable.
equalsIgnoreExtra(v1, v2)
@ -107,8 +120,8 @@ object VersionNumber {
// A pre-release version MAY be denoted by appending a hyphen and a series of dot separated identifiers
equalsIgnoreExtra(v1, v2)
case (x1, _, _, _, x2, _, _, _) =>
// Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards compatible bug fixes are introduced.
// Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backwards compatible functionality is introduced
// Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards compatible bug fixes are introduced.
// Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backwards compatible functionality is introduced
x1 == x2
case _ => equalsIgnoreExtra(v1, v2)
}
@ -129,13 +142,14 @@ object VersionNumber {
doIsCompat(v1, v2) || doIsCompat(v2, v1)
private[this] def doIsCompat(v1: VersionNumber, v2: VersionNumber): Boolean =
(v1, v2) match {
case (v1, v2) if (v1.size >= 3) && (v2.size >= 3) => // A normal version number MUST take the form X.Y.Z
case (v1, v2)
if (v1.size >= 3) && (v2.size >= 3) => // A normal version number MUST take the form X.Y.Z
(v1._1.get, v1._2.get, v1._3.get, v1.tags, v2._1.get, v2._2.get, v2._3.get, v2.tags) match {
case (x1, y1, 0, ts1, x2, y2, 0, ts2) if ts1.nonEmpty || ts2.nonEmpty =>
// A pre-release version MAY be denoted by appending a hyphen and a series of dot separated identifiers
equalsIgnoreExtra(v1, v2)
case (x1, y1, _, _, x2, y2, _, _) =>
// Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards compatible changes are introduced.
// Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards compatible changes are introduced.
(x1 == x2) && (y1 == y2)
case _ => equalsIgnoreExtra(v1, v2)
}

View File

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

View File

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

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

View File

@ -118,22 +118,28 @@ class CrossVersionTest extends UnitSpec {
CrossVersion.binaryScalaVersion("2.20170314093845.0-87654321") shouldBe "2.20170314093845.0-87654321"
}
it should "return patch Scala version for 2.11.8 as 2.11.8" in {
CrossVersion(CrossVersion.patch, "2.11.8", "dummy").map(_("artefact")) shouldBe Some("artefact_2.11.8")
CrossVersion(CrossVersion.patch, "2.11.8", "dummy").map(_("artefact")) shouldBe Some(
"artefact_2.11.8")
}
it should "return patch Scala version for 2.11.8-M1 as 2.11.8-M1" in {
CrossVersion(CrossVersion.patch, "2.11.8-M1", "dummy").map(_("artefact")) shouldBe Some("artefact_2.11.8-M1")
CrossVersion(CrossVersion.patch, "2.11.8-M1", "dummy").map(_("artefact")) shouldBe Some(
"artefact_2.11.8-M1")
}
it should "return patch Scala version for 2.11.8-RC1 as 2.11.8-RC1" in {
CrossVersion(CrossVersion.patch, "2.11.8-RC1", "dummy").map(_("artefact")) shouldBe Some("artefact_2.11.8-RC1")
CrossVersion(CrossVersion.patch, "2.11.8-RC1", "dummy").map(_("artefact")) shouldBe Some(
"artefact_2.11.8-RC1")
}
it should "return patch Scala version for 2.11.8-bin-extra as 2.11.8" in {
CrossVersion(CrossVersion.patch, "2.11.8-bin-extra", "dummy").map(_("artefact")) shouldBe Some("artefact_2.11.8")
CrossVersion(CrossVersion.patch, "2.11.8-bin-extra", "dummy").map(_("artefact")) shouldBe Some(
"artefact_2.11.8")
}
it should "return patch Scala version for 2.11.8-M1-bin-extra as 2.11.8-M1" in {
CrossVersion(CrossVersion.patch, "2.11.8-M1-bin-extra", "dummy").map(_("artefact")) shouldBe Some("artefact_2.11.8-M1")
CrossVersion(CrossVersion.patch, "2.11.8-M1-bin-extra", "dummy")
.map(_("artefact")) shouldBe Some("artefact_2.11.8-M1")
}
it should "return patch Scala version for 2.11.8-RC1-bin-extra as 2.11.8-RC1" in {
CrossVersion(CrossVersion.patch, "2.11.8-RC1-bin-extra", "dummy").map(_("artefact")) shouldBe Some("artefact_2.11.8-RC1")
CrossVersion(CrossVersion.patch, "2.11.8-RC1-bin-extra", "dummy")
.map(_("artefact")) shouldBe Some("artefact_2.11.8-RC1")
}
it should "return disabled cross version as equal to a copy" in {
Disabled() shouldBe Disabled()

View File

@ -15,7 +15,16 @@ class CustomPomParserTest extends UnitSpec {
val repoUrl = getClass.getResource("/test-maven-repo")
val local = MavenRepository("Test Repo", repoUrl.toExternalForm)
val paths = IvyPaths(new File("."), Some(cacheDir))
val conf = new InlineIvyConfiguration(paths, Vector(local), Vector.empty, Vector.empty, false, None, Vector("sha1", "md5"), None, UpdateOptions(), log)
val conf = new InlineIvyConfiguration(paths,
Vector(local),
Vector.empty,
Vector.empty,
false,
None,
Vector("sha1", "md5"),
None,
UpdateOptions(),
log)
val ivySbt = new IvySbt(conf)
val resolveOpts = new ResolveOptions().setConfs(Array("default"))
val mrid = ModuleRevisionId.newInstance("com.test", "test-artifact", "1.0.0-SNAPSHOT")
@ -26,7 +35,8 @@ class CustomPomParserTest extends UnitSpec {
resolveReport.hasError shouldBe false
resolveReport.getArtifacts.size() shouldBe 1
val artifact: IvyArtifact = resolveReport.getArtifacts.asInstanceOf[java.util.List[IvyArtifact]].get(0)
val artifact: IvyArtifact =
resolveReport.getArtifacts.asInstanceOf[java.util.List[IvyArtifact]].get(0)
artifact.getModuleRevisionId shouldBe mrid
artifact.getExt shouldBe "jar"
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,7 +9,14 @@ object ResolverTest extends UnitSpec {
"Resolver url" should "propagate pattern descriptorOptional and skipConsistencyCheck." in {
val pats = Vector("[orgPath]")
val patsExpected = Vector("http://foo.com/test/[orgPath]")
val patterns = Resolver.url("test", new URL("http://foo.com/test"))(Patterns(pats, pats, isMavenCompatible = false, descriptorOptional = true, skipConsistencyCheck = true)).patterns
val patterns = Resolver
.url("test", new URL("http://foo.com/test"))(
Patterns(pats,
pats,
isMavenCompatible = false,
descriptorOptional = true,
skipConsistencyCheck = true))
.patterns
patterns.ivyPatterns shouldBe patsExpected
patterns.artifactPatterns shouldBe patsExpected

View File

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

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

View File

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

View File

@ -15,7 +15,8 @@ class IvyRepoSpec extends BaseIvySpecification with DependencyBuilders {
module(
ourModuleID,
Vector(dep), None //, UpdateOptions().withCachedResolution(true)
Vector(dep),
None //, UpdateOptions().withCachedResolution(true)
)
}
@ -59,12 +60,26 @@ class IvyRepoSpec extends BaseIvySpecification with DependencyBuilders {
val clMod = {
val externalModules = Vector(dep)
// Note: need to extract ourModuleID so we can plug it in here, can't fish it back out of the IvySbt#Module (`m`)
GetClassifiersModule(ourModuleID, externalModules, Vector(Configurations.Compile), attemptedClassifiers)
GetClassifiersModule(ourModuleID,
externalModules,
Vector(Configurations.Compile),
attemptedClassifiers)
}
val gcm = GetClassifiersConfiguration(clMod, Map.empty, c.withArtifactFilter(c.artifactFilter.invert), ivyScala, srcTypes, docTypes)
val gcm = GetClassifiersConfiguration(clMod,
Map.empty,
c.withArtifactFilter(c.artifactFilter.invert),
ivyScala,
srcTypes,
docTypes)
val report2 = IvyActions.updateClassifiers(m.owner, gcm, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, Vector(), log)
val report2 = IvyActions.updateClassifiers(m.owner,
gcm,
UnresolvedWarningConfiguration(),
LogicalClock.unknown,
None,
Vector(),
log)
import Inside._
inside(report2.configuration("compile").map(_.modules)) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
addSbtPlugin("org.scala-sbt" % "sbt-houserules" % "0.3.2")
addSbtPlugin("com.eed3si9n" % "sbt-doge" % "0.1.3")
addSbtPlugin("com.eed3si9n" % "sbt-doge" % "0.1.3")
addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.3.0-M4")
addSbtPlugin("me.lessis" % "bintray-sbt" % "0.3.0")
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "0.6.8")
addSbtPlugin("me.lessis" % "bintray-sbt" % "0.3.0")
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "0.6.8")
scalacOptions += "-language:postfixOps"