From d42ea869d064a28c692df7d93c506b698dd6937c Mon Sep 17 00:00:00 2001 From: jvican Date: Wed, 26 Apr 2017 22:55:38 +0200 Subject: [PATCH] Apply formatting --- build.sbt | 62 +- .../ReplaceMavenConfigurationMappings.scala | 125 +- .../CompatibilityWarning.scala | 21 +- .../librarymanagement/ComponentManager.scala | 96 +- .../librarymanagement/ConvertResolver.scala | 233 +-- .../librarymanagement/CustomPomParser.scala | 318 ++-- .../librarymanagement/CustomXmlParser.scala | 30 +- .../librarymanagement/FakeResolver.scala | 45 +- .../sbt/internal/librarymanagement/Ivy.scala | 967 +++++++----- .../librarymanagement/IvyActions.scala | 666 ++++++--- .../internal/librarymanagement/IvyCache.scala | 105 +- .../librarymanagement/IvyConfigurations.scala | 8 +- .../librarymanagement/IvyLogger.scala | 1 + .../librarymanagement/IvyRetrieve.scala | 162 +- .../internal/librarymanagement/JsonUtil.scala | 100 +- .../internal/librarymanagement/MakePom.scala | 526 ++++--- .../librarymanagement/ProjectResolver.scala | 79 +- .../RepositoriesParser.scala | 44 +- .../librarymanagement/ResolutionCache.scala | 25 +- .../SbtExclusionRuleExtra.scala | 3 +- .../librarymanagement/StringUtilities.scala | 8 +- .../librarymanagement/VersionRange.scala | 24 +- .../cross/CrossVersionUtil.scala | 78 +- .../formats/UpdateOptionsFormat.scala | 22 +- .../impl/DependencyBuilders.scala | 71 +- .../CachedResolutionResolveEngine.scala | 1332 ++++++++++------- .../ivyint/CustomMavenResolver.scala | 3 +- .../ivyint/ErrorMessageAuthenticator.scala | 32 +- .../ivyint/IvyCredentialsLookup.scala | 4 +- .../ivyint/MergeDescriptors.scala | 180 ++- .../ivyint/SbtChainResolver.scala | 397 +++-- .../PomExtraDependencyAttributes.scala | 25 +- .../sbt/librarymanagement/ArtifactExtra.scala | 112 +- .../CircularDependencyLevel.scala | 7 +- .../ConfigurationExtra.scala | 29 +- .../librarymanagement/ConflictWarning.scala | 33 +- .../sbt/librarymanagement/Credentials.scala | 39 +- .../librarymanagement/CrossVersionExtra.scala | 49 +- .../DefaultLibraryManagement.scala | 37 +- .../librarymanagement/DependencyFilter.scala | 73 +- .../librarymanagement/EvictionWarning.scala | 135 +- .../sbt/librarymanagement/IvyInterface.scala | 9 +- .../sbt/librarymanagement/IvyScalaExtra.scala | 199 ++- .../sbt/librarymanagement/ModuleIDExtra.scala | 86 +- .../sbt/librarymanagement/ResolverExtra.scala | 208 ++- .../librarymanagement/RichUpdateReport.scala | 57 +- .../sbt/librarymanagement/UpdateOptions.scala | 60 +- .../librarymanagement/UpdateReportExtra.scala | 110 +- .../sbt/librarymanagement/VersionNumber.scala | 44 +- .../src/test/scala/BaseIvySpecification.scala | 42 +- .../src/test/scala/CachedResolutionSpec.scala | 37 +- .../src/test/scala/ComponentManagerTest.scala | 34 +- .../src/test/scala/CrossVersionTest.scala | 18 +- .../src/test/scala/CustomPomParserTest.scala | 14 +- .../src/test/scala/DMSerializationSpec.scala | 27 +- .../src/test/scala/EvictionWarningSpec.scala | 40 +- .../scala/InconsistentDuplicateSpec.scala | 9 +- .../src/test/scala/MakePomSpec.scala | 1 - .../src/test/scala/MergeDescriptorSpec.scala | 12 +- .../src/test/scala/ResolverTest.scala | 9 +- .../src/test/scala/ScalaOverrideTest.scala | 68 +- .../src/test/scala/VersionNumberSpec.scala | 68 +- .../FakeResolverSpecification.scala | 14 +- .../librarymanagement/IvyRepoSpec.scala | 25 +- .../RepositoriesParserSpecification.scala | 60 +- .../librarymanagement/TestLogger.scala | 11 +- project/AutomateScalafmtPlugin.scala | 4 +- project/DatatypeConfig.scala | 38 +- project/Dependencies.scala | 36 +- project/Util.scala | 42 +- project/plugins.sbt | 6 +- 71 files changed, 4875 insertions(+), 2819 deletions(-) diff --git a/build.sbt b/build.sbt index 1571c04b..aed7152a 100644 --- a/build.sbt +++ b/build.sbt @@ -28,17 +28,19 @@ def commonSettings: Seq[Setting[_]] = Seq( } ) -lazy val lmRoot = (project in file(".")). - aggregate(lm). - disablePlugins(com.typesafe.sbt.SbtScalariform). - settings( - inThisBuild(Seq( - homepage := Some(url("https://github.com/sbt/librarymanagement")), - description := "Library management module for sbt", - scmInfo := Some(ScmInfo(url("https://github.com/sbt/librarymanagement"), "git@github.com:sbt/librarymanagement.git")), - bintrayPackage := "librarymanagement", - git.baseVersion := baseVersion - )), +lazy val lmRoot = (project in file(".")) + .aggregate(lm) + .disablePlugins(com.typesafe.sbt.SbtScalariform) + .settings( + inThisBuild( + Seq( + homepage := Some(url("https://github.com/sbt/librarymanagement")), + description := "Library management module for sbt", + scmInfo := Some(ScmInfo(url("https://github.com/sbt/librarymanagement"), + "git@github.com:sbt/librarymanagement.git")), + bintrayPackage := "librarymanagement", + git.baseVersion := baseVersion + )), commonSettings, name := "LM Root", publish := {}, @@ -48,15 +50,24 @@ lazy val lmRoot = (project in file(".")). customCommands ) -lazy val lm = (project in file("librarymanagement")). - disablePlugins(com.typesafe.sbt.SbtScalariform). - settings( +lazy val lm = (project in file("librarymanagement")) + .disablePlugins(com.typesafe.sbt.SbtScalariform) + .settings( commonSettings, name := "librarymanagement", - libraryDependencies ++= Seq( - ivy, jsch, scalaReflect.value, launcherInterface, sjsonnewScalaJson % Optional), + libraryDependencies ++= Seq(ivy, + jsch, + scalaReflect.value, + launcherInterface, + sjsonnewScalaJson % Optional), libraryDependencies ++= scalaXml.value, - resourceGenerators in Compile += Def.task(Util.generateVersionFile(version.value, resourceManaged.value, streams.value, (compile in Compile).value)).taskValue, + resourceGenerators in Compile += Def + .task( + Util.generateVersionFile(version.value, + resourceManaged.value, + streams.value, + (compile in Compile).value)) + .taskValue, mimaBinaryIssueFilters ++= Seq(), contrabandFormatsForType in generateContrabands in Compile := DatatypeConfig.getFormats, // WORKAROUND sbt/sbt#2205 include managed sources in packageSrc @@ -66,16 +77,21 @@ lazy val lm = (project in file("librarymanagement")). val base = baseDirectory.value (((srcs --- sdirs --- base) pair (relativeTo(sdirs) | relativeTo(base) | flat)) toSeq) } - ). - configure(addSbtIO, addSbtUtilLogging, addSbtUtilTesting, addSbtUtilCollection, addSbtUtilCompletion, addSbtUtilCache). - enablePlugins(ContrabandPlugin, JsonCodecPlugin) + ) + .configure(addSbtIO, + addSbtUtilLogging, + addSbtUtilTesting, + addSbtUtilCollection, + addSbtUtilCompletion, + addSbtUtilCache) + .enablePlugins(ContrabandPlugin, JsonCodecPlugin) def customCommands: Seq[Setting[_]] = Seq( commands += Command.command("release") { state => // "clean" :: "so compile" :: - "so publishSigned" :: - "reload" :: - state + "so publishSigned" :: + "reload" :: + state } ) diff --git a/librarymanagement/src/main/scala/org/apache/ivy/plugins/parser/m2/ReplaceMavenConfigurationMappings.scala b/librarymanagement/src/main/scala/org/apache/ivy/plugins/parser/m2/ReplaceMavenConfigurationMappings.scala index e59bd174..410bdcfb 100644 --- a/librarymanagement/src/main/scala/org/apache/ivy/plugins/parser/m2/ReplaceMavenConfigurationMappings.scala +++ b/librarymanagement/src/main/scala/org/apache/ivy/plugins/parser/m2/ReplaceMavenConfigurationMappings.scala @@ -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 + ) } } } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/CompatibilityWarning.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/CompatibilityWarning.scala index 0a4f9feb..42d3e6ca 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/CompatibilityWarning.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/CompatibilityWarning.scala @@ -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 diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ComponentManager.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ComponentManager.scala index 480912e7..244d86c6 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ComponentManager.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ComponentManager.scala @@ -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) + def files(id: String)(ifMissing: IfMissing): Iterable[File] = { + def fromGlobal = + lockGlobalCache { + try { update(id); getOrElse(createAndCache) } catch { + case e: NotInCache => createAndCache } - - lockLocalCache { getOrElse(fromGlobal) } + } + 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) } + 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 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 diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala index a1d67b99..c90ece75 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala @@ -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 - } - 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 + 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: 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) } } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/CustomPomParser.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/CustomPomParser.scala index a8336662..c906fc81 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/CustomPomParser.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/CustomPomParser.scala @@ -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 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 element of the pom. + // These are attached to the module itself. + val filtered = shouldBeUnqualified(properties) - // Extracts extra attributes for the dependencies. - // Because the 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 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 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 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 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 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 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 namespaceTransformer(txId: ModuleRevisionId, f: ModuleRevisionId => ModuleRevisionId): NamespaceTransformer = + } + 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 = 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) - - 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()) - - 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) - } + 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) + + 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) + + 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 } + dmd + } } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/CustomXmlParser.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/CustomXmlParser.scala index d8100ddc..0498828b 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/CustomXmlParser.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/CustomXmlParser.scala @@ -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) } } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/FakeResolver.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/FakeResolver.scala index 58ef9f63..b8e493ee 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/FakeResolver.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/FakeResolver.scala @@ -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 + ) } } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/Ivy.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/Ivy.scala index 44c53d82..b5084ffb 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/Ivy.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/Ivy.scala @@ -11,8 +11,19 @@ import org.apache.ivy.Ivy import org.apache.ivy.core.IvyPatternHelper import org.apache.ivy.core.cache.{ CacheMetadataOptions, DefaultRepositoryCacheManager } import org.apache.ivy.core.event.EventManager -import org.apache.ivy.core.module.descriptor.{ Artifact => IArtifact, DefaultArtifact, DefaultDependencyArtifactDescriptor, MDArtifact } -import org.apache.ivy.core.module.descriptor.{ DefaultDependencyDescriptor, DefaultModuleDescriptor, DependencyDescriptor, ModuleDescriptor, License } +import org.apache.ivy.core.module.descriptor.{ + Artifact => IArtifact, + DefaultArtifact, + DefaultDependencyArtifactDescriptor, + MDArtifact +} +import org.apache.ivy.core.module.descriptor.{ + DefaultDependencyDescriptor, + DefaultModuleDescriptor, + DependencyDescriptor, + ModuleDescriptor, + License +} import org.apache.ivy.core.module.descriptor.OverrideDependencyDescriptorMediator import org.apache.ivy.core.module.id.{ ModuleId, ModuleRevisionId } import org.apache.ivy.core.resolve._ @@ -29,7 +40,11 @@ import scala.collection.mutable import sbt.util.Logger import sbt.librarymanagement._ import Resolver.PluginPattern -import ivyint.{ CachedResolutionResolveEngine, CachedResolutionResolveCache, SbtDefaultDependencyDescriptor } +import ivyint.{ + CachedResolutionResolveEngine, + CachedResolutionResolveCache, + SbtDefaultDependencyDescriptor +} final class IvySbt(val configuration: IvyConfiguration) { self => import configuration.baseDirectory @@ -41,72 +56,82 @@ final class IvySbt(val configuration: IvyConfiguration) { self => * saving some time. This is necessary because Ivy has global state (IvyContext, Message, DocumentBuilder, ...). */ - private def withDefaultLogger[T](logger: MessageLogger)(f: => T): T = - { - def action() = - IvySbt.synchronized { - val originalLogger = Message.getDefaultLogger - Message.setDefaultLogger(logger) - try { f } - finally { Message.setDefaultLogger(originalLogger) } - } - // Ivy is not thread-safe nor can the cache be used concurrently. - // If provided a GlobalLock, we can use that to ensure safe access to the cache. - // Otherwise, we can at least synchronize within the JVM. - // For thread-safety in particular, Ivy uses a static DocumentBuilder, which is not thread-safe. - configuration.lock match { - case Some(lock) => lock(ivyLockFile, new Callable[T] { def call = action() }) - case None => action() + private def withDefaultLogger[T](logger: MessageLogger)(f: => T): T = { + def action() = + IvySbt.synchronized { + val originalLogger = Message.getDefaultLogger + Message.setDefaultLogger(logger) + try { f } finally { Message.setDefaultLogger(originalLogger) } } + // Ivy is not thread-safe nor can the cache be used concurrently. + // If provided a GlobalLock, we can use that to ensure safe access to the cache. + // Otherwise, we can at least synchronize within the JVM. + // For thread-safety in particular, Ivy uses a static DocumentBuilder, which is not thread-safe. + configuration.lock match { + case Some(lock) => lock(ivyLockFile, new Callable[T] { def call = action() }) + case None => action() } - private lazy val settings: IvySettings = - { - val is = new IvySettings - - is.setBaseDir(baseDirectory) - is.setCircularDependencyStrategy(configuration.updateOptions.circularDependencyLevel.ivyStrategy) - CustomPomParser.registerDefault - - configuration match { - case e: ExternalIvyConfiguration => - IvySbt.addResolvers(e.extraResolvers, is, configuration.log) - IvySbt.loadURI(is, e.uri) - case i: InlineIvyConfiguration => - is.setVariable("ivy.checksums", i.checksums mkString ",") - i.paths.ivyHome foreach is.setDefaultIvyUserDir - IvySbt.configureCache(is, i.localOnly, i.resolutionCacheDir) - IvySbt.setResolvers(is, i.resolvers, i.otherResolvers, i.localOnly, configuration.updateOptions, configuration.log) - IvySbt.setModuleConfigurations(is, i.moduleConfigurations, configuration.log) - } - is - } - private[sbt] def mkIvy: Ivy = - { - val i = new Ivy() { - private val loggerEngine = new SbtMessageLoggerEngine - override def getLoggerEngine = loggerEngine - override def bind(): Unit = { - val prOpt = Option(getSettings.getResolver(ProjectResolver.InterProject)) map { case pr: ProjectResolver => pr } - // We inject the deps we need before we can hook our resolve engine. - setSortEngine(new SortEngine(getSettings)) - setEventManager(new EventManager()) - if (configuration.updateOptions.cachedResolution) { - setResolveEngine(new ResolveEngine(getSettings, getEventManager, getSortEngine) with CachedResolutionResolveEngine { + } + private lazy val settings: IvySettings = { + val is = new IvySettings + + is.setBaseDir(baseDirectory) + is.setCircularDependencyStrategy( + configuration.updateOptions.circularDependencyLevel.ivyStrategy + ) + CustomPomParser.registerDefault + + configuration match { + case e: ExternalIvyConfiguration => + IvySbt.addResolvers(e.extraResolvers, is, configuration.log) + IvySbt.loadURI(is, e.uri) + case i: InlineIvyConfiguration => + is.setVariable("ivy.checksums", i.checksums mkString ",") + i.paths.ivyHome foreach is.setDefaultIvyUserDir + IvySbt.configureCache(is, i.localOnly, i.resolutionCacheDir) + IvySbt.setResolvers( + is, + i.resolvers, + i.otherResolvers, + i.localOnly, + configuration.updateOptions, + configuration.log + ) + IvySbt.setModuleConfigurations(is, i.moduleConfigurations, configuration.log) + } + is + } + private[sbt] def mkIvy: Ivy = { + val i = new Ivy() { + private val loggerEngine = new SbtMessageLoggerEngine + override def getLoggerEngine = loggerEngine + override def bind(): Unit = { + val prOpt = Option(getSettings.getResolver(ProjectResolver.InterProject)) map { + case pr: ProjectResolver => pr + } + // We inject the deps we need before we can hook our resolve engine. + setSortEngine(new SortEngine(getSettings)) + setEventManager(new EventManager()) + if (configuration.updateOptions.cachedResolution) { + setResolveEngine( + new ResolveEngine(getSettings, getEventManager, getSortEngine) + with CachedResolutionResolveEngine { val cachedResolutionResolveCache = IvySbt.cachedResolutionResolveCache val projectResolver = prOpt def makeInstance = mkIvy - }) - } else setResolveEngine(new ResolveEngine(getSettings, getEventManager, getSortEngine)) - super.bind() - } + } + ) + } else setResolveEngine(new ResolveEngine(getSettings, getEventManager, getSortEngine)) + super.bind() } - - i.setSettings(settings) - i.bind() - i.getLoggerEngine.pushLogger(new IvyLoggerInterface(configuration.log)) - i } + i.setSettings(settings) + i.bind() + i.getLoggerEngine.pushLogger(new IvyLoggerInterface(configuration.log)) + i + } + private lazy val ivy: Ivy = mkIvy // Must be the same file as is used in Update in the launcher private lazy val ivyLockFile = new File(settings.getDefaultIvyUserDir, ".sbt.ivy.lock") @@ -123,8 +148,7 @@ final class IvySbt(val configuration: IvyConfiguration) { self => ivyint.ErrorMessageAuthenticator.install() ivy.pushContext() ivy.getLoggerEngine.pushLogger(log) - try { f(ivy) } - finally { + try { f(ivy) } finally { ivy.getLoggerEngine.popLogger() ivy.popContext() } @@ -137,7 +161,9 @@ final class IvySbt(val configuration: IvyConfiguration) { self => */ private[sbt] def cleanCachedResolutionCache(md: ModuleDescriptor, log: Logger): Unit = withIvy(log) { i => - val prOpt = Option(i.getSettings.getResolver(ProjectResolver.InterProject)) map { case pr: ProjectResolver => pr } + val prOpt = Option(i.getSettings.getResolver(ProjectResolver.InterProject)) map { + case pr: ProjectResolver => pr + } if (configuration.updateOptions.cachedResolution) { IvySbt.cachedResolutionResolveCache.clean(md, prOpt) } @@ -147,98 +173,124 @@ final class IvySbt(val configuration: IvyConfiguration) { self => val moduleSettings: ModuleSettings = IvySbt.substituteCross(rawModuleSettings) def owner = IvySbt.this def withModule[T](log: Logger)(f: (Ivy, DefaultModuleDescriptor, String) => T): T = - withIvy[T](log) { ivy => f(ivy, moduleDescriptor0, defaultConfig0) } + withIvy[T](log) { ivy => + f(ivy, moduleDescriptor0, defaultConfig0) + } def moduleDescriptor(log: Logger): DefaultModuleDescriptor = withModule(log)((_, md, _) => md) - def dependencyMapping(log: Logger): (ModuleRevisionId, ModuleDescriptor) = - { - val md = moduleDescriptor(log) - (md.getModuleRevisionId, md) - } + def dependencyMapping(log: Logger): (ModuleRevisionId, ModuleDescriptor) = { + val md = moduleDescriptor(log) + (md.getModuleRevisionId, md) + } def defaultConfig(log: Logger): String = withModule(log)((_, _, dc) => dc) // these should only be referenced by withModule because lazy vals synchronize on this object // withIvy explicitly locks the IvySbt object, so they have to be done in the right order to avoid deadlock - private[this] lazy val (moduleDescriptor0: DefaultModuleDescriptor, defaultConfig0: String) = - { - val (baseModule, baseConfiguration) = - moduleSettings match { - case ic: InlineConfiguration => configureInline(ic, configuration.log) - case pc: PomConfiguration => configurePom(pc) - case ifc: IvyFileConfiguration => configureIvyFile(ifc) - } + private[this] lazy val (moduleDescriptor0: DefaultModuleDescriptor, defaultConfig0: String) = { + val (baseModule, baseConfiguration) = + moduleSettings match { + case ic: InlineConfiguration => configureInline(ic, configuration.log) + case pc: PomConfiguration => configurePom(pc) + case ifc: IvyFileConfiguration => configureIvyFile(ifc) + } - val configs = - moduleSettings match { - case ic: InlineConfiguration => ic.configurations - case pc: PomConfiguration => Configurations.default ++ Configurations.defaultInternal - case ifc: IvyFileConfiguration => Configurations.default ++ Configurations.defaultInternal - } - moduleSettings.ivyScala match { - case Some(is) => - val svc = configs.toVector filter Configurations.underScalaVersion map { _.name } - IvyScala.checkModule(baseModule, baseConfiguration, svc, configuration.log)(is) - case _ => // do nothing + val configs = + moduleSettings match { + case ic: InlineConfiguration => ic.configurations + case pc: PomConfiguration => Configurations.default ++ Configurations.defaultInternal + case ifc: IvyFileConfiguration => + Configurations.default ++ Configurations.defaultInternal } - IvySbt.addExtraNamespace(baseModule) - (baseModule, baseConfiguration) + moduleSettings.ivyScala match { + case Some(is) => + val svc = configs.toVector filter Configurations.underScalaVersion map { _.name } + IvyScala.checkModule(baseModule, baseConfiguration, svc, configuration.log)(is) + case _ => // do nothing } - private def configureInline(ic: InlineConfiguration, log: Logger) = - { - import ic._ - val moduleID = newConfiguredModuleID(module, moduleInfo, configurations) - IvySbt.setConflictManager(moduleID, conflictManager, ivy.getSettings) - val defaultConf = defaultConfiguration getOrElse Configurations.config(ModuleDescriptor.DEFAULT_CONFIGURATION) - log.debug("Using inline dependencies specified in Scala" + (if (ivyXML.isEmpty) "." else " and XML.")) - - val parser = IvySbt.parseIvyXML(ivy.getSettings, IvySbt.wrapped(module, ivyXML), moduleID, defaultConf.name, validate) - IvySbt.addMainArtifact(moduleID) - IvySbt.addOverrides(moduleID, overrides, ivy.getSettings.getMatcher(PatternMatcher.EXACT)) - IvySbt.addExcludes(moduleID, excludes, ivyScala) - val transformedDeps = IvySbt.overrideDirect(dependencies, overrides) - IvySbt.addDependencies(moduleID, transformedDeps, parser) - (moduleID, parser.getDefaultConf) + IvySbt.addExtraNamespace(baseModule) + (baseModule, baseConfiguration) + } + private def configureInline(ic: InlineConfiguration, log: Logger) = { + import ic._ + val moduleID = newConfiguredModuleID(module, moduleInfo, configurations) + IvySbt.setConflictManager(moduleID, conflictManager, ivy.getSettings) + val defaultConf = defaultConfiguration getOrElse Configurations.config( + ModuleDescriptor.DEFAULT_CONFIGURATION + ) + log.debug( + "Using inline dependencies specified in Scala" + (if (ivyXML.isEmpty) "." + else " and XML.") + ) + + val parser = IvySbt.parseIvyXML( + ivy.getSettings, + IvySbt.wrapped(module, ivyXML), + moduleID, + defaultConf.name, + validate + ) + IvySbt.addMainArtifact(moduleID) + IvySbt.addOverrides(moduleID, overrides, ivy.getSettings.getMatcher(PatternMatcher.EXACT)) + IvySbt.addExcludes(moduleID, excludes, ivyScala) + val transformedDeps = IvySbt.overrideDirect(dependencies, overrides) + IvySbt.addDependencies(moduleID, transformedDeps, parser) + (moduleID, parser.getDefaultConf) + } + private def newConfiguredModuleID( + module: ModuleID, + moduleInfo: ModuleInfo, + configurations: Iterable[Configuration] + ) = { + val mod = new DefaultModuleDescriptor(IvySbt.toID(module), "release", null, false) + mod.setLastModified(System.currentTimeMillis) + mod.setDescription(moduleInfo.description) + moduleInfo.homepage foreach { h => + mod.setHomePage(h.toString) } - private def newConfiguredModuleID(module: ModuleID, moduleInfo: ModuleInfo, configurations: Iterable[Configuration]) = - { - val mod = new DefaultModuleDescriptor(IvySbt.toID(module), "release", null, false) - mod.setLastModified(System.currentTimeMillis) - mod.setDescription(moduleInfo.description) - moduleInfo.homepage foreach { h => mod.setHomePage(h.toString) } - moduleInfo.licenses foreach { l => mod.addLicense(new License(l._1, l._2.toString)) } - IvySbt.addConfigurations(mod, configurations) - IvySbt.addArtifacts(mod, module.explicitArtifacts) - mod + moduleInfo.licenses foreach { l => + mod.addLicense(new License(l._1, l._2.toString)) } + IvySbt.addConfigurations(mod, configurations) + IvySbt.addArtifacts(mod, module.explicitArtifacts) + mod + } /** Parses the Maven pom 'pomFile' from the given `PomConfiguration`.*/ - private def configurePom(pc: PomConfiguration) = - { - val md = CustomPomParser.default.parseDescriptor(settings, toURL(pc.file), pc.validate) - val dmd = IvySbt.toDefaultModuleDescriptor(md) - IvySbt.addConfigurations(dmd, Configurations.defaultInternal) - val defaultConf = Configurations.DefaultMavenConfiguration.name - for (is <- pc.ivyScala) if (pc.autoScalaTools) { - val confParser = new CustomXmlParser.CustomParser(settings, Some(defaultConf)) - confParser.setMd(dmd) - addScalaToolDependencies(dmd, confParser, is) - } - (dmd, defaultConf) + private def configurePom(pc: PomConfiguration) = { + val md = CustomPomParser.default.parseDescriptor(settings, toURL(pc.file), pc.validate) + val dmd = IvySbt.toDefaultModuleDescriptor(md) + IvySbt.addConfigurations(dmd, Configurations.defaultInternal) + val defaultConf = Configurations.DefaultMavenConfiguration.name + for (is <- pc.ivyScala) if (pc.autoScalaTools) { + val confParser = new CustomXmlParser.CustomParser(settings, Some(defaultConf)) + confParser.setMd(dmd) + addScalaToolDependencies(dmd, confParser, is) } + (dmd, defaultConf) + } + /** Parses the Ivy file 'ivyFile' from the given `IvyFileConfiguration`.*/ - private def configureIvyFile(ifc: IvyFileConfiguration) = - { - val parser = new CustomXmlParser.CustomParser(settings, None) - parser.setValidate(ifc.validate) - parser.setSource(toURL(ifc.file)) - parser.parse() - val dmd = IvySbt.toDefaultModuleDescriptor(parser.getModuleDescriptor()) - for (is <- ifc.ivyScala) if (ifc.autoScalaTools) + private def configureIvyFile(ifc: IvyFileConfiguration) = { + val parser = new CustomXmlParser.CustomParser(settings, None) + parser.setValidate(ifc.validate) + parser.setSource(toURL(ifc.file)) + parser.parse() + val dmd = IvySbt.toDefaultModuleDescriptor(parser.getModuleDescriptor()) + for (is <- ifc.ivyScala) + if (ifc.autoScalaTools) addScalaToolDependencies(dmd, parser, is) - (dmd, parser.getDefaultConf) - } - private def addScalaToolDependencies(dmd: DefaultModuleDescriptor, parser: CustomXmlParser.CustomParser, is: IvyScala): Unit = { + (dmd, parser.getDefaultConf) + } + private def addScalaToolDependencies( + dmd: DefaultModuleDescriptor, + parser: CustomXmlParser.CustomParser, + is: IvyScala + ): Unit = { IvySbt.addConfigurations(dmd, Configurations.ScalaTool :: Nil) - IvySbt.addDependencies(dmd, ScalaArtifacts.toolDependencies(is.scalaOrganization, is.scalaFullVersion), parser) + IvySbt.addDependencies( + dmd, + ScalaArtifacts.toolDependencies(is.scalaOrganization, is.scalaFullVersion), + parser + ) } private def toURL(file: File) = file.toURI.toURL } @@ -249,7 +301,8 @@ private[sbt] object IvySbt { val DefaultIvyFilename = "ivy.xml" val DefaultMavenFilename = "pom.xml" val DefaultChecksums = Vector("sha1", "md5") - private[sbt] def cachedResolutionResolveCache: CachedResolutionResolveCache = new CachedResolutionResolveCache + private[sbt] def cachedResolutionResolveCache: CachedResolutionResolveCache = + new CachedResolutionResolveCache def defaultIvyFile(project: File) = new File(project, DefaultIvyFilename) def defaultIvyConfiguration(project: File) = new File(project, DefaultIvyConfigFilename) @@ -266,7 +319,14 @@ private[sbt] object IvySbt { * Sets the resolvers for 'settings' to 'resolvers'. This is done by creating a new chain and making it the default. * 'other' is for resolvers that should be in a different chain. These are typically used for publishing or other actions. */ - private def setResolvers(settings: IvySettings, resolvers: Seq[Resolver], other: Seq[Resolver], localOnly: Boolean, updateOptions: UpdateOptions, log: Logger): Unit = { + private def setResolvers( + settings: IvySettings, + resolvers: Seq[Resolver], + other: Seq[Resolver], + localOnly: Boolean, + updateOptions: UpdateOptions, + log: Logger + ): Unit = { def makeChain(label: String, name: String, rs: Seq[Resolver]) = { log.debug(label + " repositories:") val chain = resolverChain(name, rs, localOnly, settings, updateOptions, log) @@ -283,15 +343,36 @@ private[sbt] object IvySbt { module.revision endsWith "-SNAPSHOT" private[sbt] def isChanging(mrid: ModuleRevisionId): Boolean = mrid.getRevision endsWith "-SNAPSHOT" - def resolverChain(name: String, resolvers: Seq[Resolver], localOnly: Boolean, settings: IvySettings, log: Logger): DependencyResolver = + def resolverChain( + name: String, + resolvers: Seq[Resolver], + localOnly: Boolean, + settings: IvySettings, + log: Logger + ): DependencyResolver = resolverChain(name, resolvers, localOnly, settings, UpdateOptions(), log) - def resolverChain(name: String, resolvers: Seq[Resolver], localOnly: Boolean, settings: IvySettings, updateOptions: UpdateOptions, log: Logger): DependencyResolver = { - def mapResolvers(rs: Seq[Resolver]) = rs.map(r => ConvertResolver(r, settings, updateOptions, log)) + def resolverChain( + name: String, + resolvers: Seq[Resolver], + localOnly: Boolean, + settings: IvySettings, + updateOptions: UpdateOptions, + log: Logger + ): DependencyResolver = { + def mapResolvers(rs: Seq[Resolver]) = + rs.map(r => ConvertResolver(r, settings, updateOptions, log)) val (projectResolvers, rest) = resolvers.partition(_.name == "inter-project") - if (projectResolvers.isEmpty) new ivyint.SbtChainResolver(name, mapResolvers(rest), settings, updateOptions, log) + if (projectResolvers.isEmpty) + new ivyint.SbtChainResolver(name, mapResolvers(rest), settings, updateOptions, log) else { // Here we set up a "first repo wins" chain resolver - val delegate = new ivyint.SbtChainResolver(name + "-delegate", mapResolvers(rest), settings, updateOptions, log) + val delegate = new ivyint.SbtChainResolver( + name + "-delegate", + mapResolvers(rest), + settings, + updateOptions, + log + ) val prs = mapResolvers(projectResolvers) // Here we construct a chain resolver which will FORCE looking at the project resolver first. new ivyint.SbtChainResolver( @@ -310,17 +391,22 @@ private[sbt] object IvySbt { settings.addResolver(ConvertResolver(r, settings, UpdateOptions(), log)) } } + /** * A hack to detect if the given artifact is an automatically generated request for a classifier, * as opposed to a user-initiated declaration. It relies on Ivy prefixing classifier with m:, while sbt uses e:. * Clearly, it would be better to have an explicit option in Ivy to control this. */ - def hasImplicitClassifier(artifact: IArtifact): Boolean = - { - import scala.collection.JavaConverters._ - artifact.getQualifiedExtraAttributes.asScala.keys.exists(_.asInstanceOf[String] startsWith "m:") - } - private def setModuleConfigurations(settings: IvySettings, moduleConfigurations: Seq[ModuleConfiguration], log: Logger): Unit = { + def hasImplicitClassifier(artifact: IArtifact): Boolean = { + import scala.collection.JavaConverters._ + artifact.getQualifiedExtraAttributes.asScala.keys + .exists(_.asInstanceOf[String] startsWith "m:") + } + private def setModuleConfigurations( + settings: IvySettings, + moduleConfigurations: Seq[ModuleConfiguration], + log: Logger + ): Unit = { val existing = settings.getResolverNames for (moduleConf <- moduleConfigurations) { import moduleConf._ @@ -328,15 +414,32 @@ private[sbt] object IvySbt { import PatternMatcher._ if (!existing.contains(resolver.name)) settings.addResolver(ConvertResolver(resolver, settings, UpdateOptions(), log)) - val attributes = javaMap(Map(MODULE_KEY -> name, ORGANISATION_KEY -> organization, REVISION_KEY -> revision)) - settings.addModuleConfiguration(attributes, settings.getMatcher(EXACT_OR_REGEXP), resolver.name, null, null, null) + val attributes = javaMap( + Map(MODULE_KEY -> name, ORGANISATION_KEY -> organization, REVISION_KEY -> revision) + ) + settings.addModuleConfiguration( + attributes, + settings.getMatcher(EXACT_OR_REGEXP), + resolver.name, + null, + null, + null + ) } } - private def configureCache(settings: IvySettings, localOnly: Boolean, resCacheDir: Option[File]): Unit = { + private def configureCache( + settings: IvySettings, + localOnly: Boolean, + resCacheDir: Option[File] + ): Unit = { configureResolutionCache(settings, localOnly, resCacheDir) configureRepositoryCache(settings, localOnly) } - private[this] def configureResolutionCache(settings: IvySettings, localOnly: Boolean, resCacheDir: Option[File]): Unit = { + private[this] def configureResolutionCache( + settings: IvySettings, + localOnly: Boolean, + resCacheDir: Option[File] + ): Unit = { val base = resCacheDir getOrElse settings.getDefaultResolutionCacheBasedir settings.setResolutionCacheManager(new ResolutionCache(base, settings)) } @@ -346,19 +449,32 @@ private[sbt] object IvySbt { // if there are problems with this, a less aggressive fix might be to only reset the artifact resolver when it is a ProjectResolver // a possible problem is that fetching artifacts is slower, due to the full chain being the artifact resolver instead of the specific resolver // This also fixes #760, which occurs when metadata exists in a repository, but the artifact doesn't. - private[sbt] def resetArtifactResolver(resolved: ResolvedModuleRevision): ResolvedModuleRevision = + private[sbt] def resetArtifactResolver( + resolved: ResolvedModuleRevision + ): ResolvedModuleRevision = if (resolved eq null) null else { val desc = resolved.getDescriptor val updatedDescriptor = CustomPomParser.defaultTransform(desc.getParser, desc) - new ResolvedModuleRevision(resolved.getResolver, resolved.getResolver, updatedDescriptor, resolved.getReport, resolved.isForce) + new ResolvedModuleRevision( + resolved.getResolver, + resolved.getResolver, + updatedDescriptor, + resolved.getReport, + resolved.isForce + ) } private[this] def configureRepositoryCache(settings: IvySettings, localOnly: Boolean): Unit = { val cacheDir = settings.getDefaultRepositoryCacheBasedir() val manager = new DefaultRepositoryCacheManager("default-cache", settings, cacheDir) { - override def findModuleInCache(dd: DependencyDescriptor, revId: ModuleRevisionId, options: CacheMetadataOptions, r: String) = { + override def findModuleInCache( + dd: DependencyDescriptor, + revId: ModuleRevisionId, + options: CacheMetadataOptions, + r: String + ) = { // ignore and reset the resolver- not ideal, but avoids thrashing. val resolved = resetArtifactResolver(super.findModuleInCache(dd, revId, options, null)) // invalidate the cache if the artifact was removed from the local repository @@ -384,7 +500,11 @@ private[sbt] object IvySbt { case _ => false } // ignore the original resolver wherever possible to avoid issues like #704 - override def saveResolvers(descriptor: ModuleDescriptor, metadataResolverName: String, artifactResolverName: String): Unit = () + override def saveResolvers( + descriptor: ModuleDescriptor, + metadataResolverName: String, + artifactResolverName: String + ): Unit = () } manager.setArtifactPattern(PluginPattern + manager.getArtifactPattern) manager.setDataFilePattern(PluginPattern + manager.getDataFilePattern) @@ -399,23 +519,36 @@ private[sbt] object IvySbt { settings.addRepositoryCacheManager(manager) settings.setDefaultRepositoryCacheManager(manager) } - def toIvyConfiguration(configuration: Configuration) = - { - import org.apache.ivy.core.module.descriptor.{ Configuration => IvyConfig } - import IvyConfig.Visibility._ - import configuration._ - new IvyConfig(name, if (isPublic) PUBLIC else PRIVATE, description, extendsConfigs.map(_.name).toArray, transitive, null) - } + def toIvyConfiguration(configuration: Configuration) = { + import org.apache.ivy.core.module.descriptor.{ Configuration => IvyConfig } + import IvyConfig.Visibility._ + import configuration._ + new IvyConfig( + name, + if (isPublic) PUBLIC else PRIVATE, + description, + extendsConfigs.map(_.name).toArray, + transitive, + null + ) + } def addExtraNamespace(dmd: DefaultModuleDescriptor): Unit = dmd.addExtraAttributeNamespace("e", "http://ant.apache.org/ivy/extra") /** Adds the ivy.xml main artifact. */ private def addMainArtifact(moduleID: DefaultModuleDescriptor): Unit = { - val artifact = DefaultArtifact.newIvyArtifact(moduleID.getResolvedModuleRevisionId, moduleID.getPublicationDate) + val artifact = DefaultArtifact.newIvyArtifact( + moduleID.getResolvedModuleRevisionId, + moduleID.getPublicationDate + ) moduleID.setModuleArtifact(artifact) moduleID.check() } - private def setConflictManager(moduleID: DefaultModuleDescriptor, conflict: ConflictManager, is: IvySettings): Unit = { + private def setConflictManager( + moduleID: DefaultModuleDescriptor, + conflict: ConflictManager, + is: IvySettings + ): Unit = { val mid = ModuleId.newInstance(conflict.organization, conflict.module) val matcher = is.getMatcher(PatternMatcher.EXACT_OR_REGEXP) val manager = is.getConflictManager(conflict.name) @@ -423,143 +556,189 @@ private[sbt] object IvySbt { } /** Converts the given sbt module id into an Ivy ModuleRevisionId.*/ - def toID(m: ModuleID) = - { - import m._ - ModuleRevisionId.newInstance(organization, name, branchName.orNull, revision, javaMap(extraAttributes)) - } + def toID(m: ModuleID) = { + import m._ + ModuleRevisionId.newInstance( + organization, + name, + branchName.orNull, + revision, + javaMap(extraAttributes) + ) + } private def substituteCross(m: ModuleSettings): ModuleSettings = m.ivyScala match { case None => m case Some(is) => substituteCross(m, is.scalaFullVersion, is.scalaBinaryVersion) } - private def substituteCross(m: ModuleSettings, scalaFullVersion: String, scalaBinaryVersion: String): ModuleSettings = - { - val sub = CrossVersion(scalaFullVersion, scalaBinaryVersion) - m match { - case ic: InlineConfiguration => ic.withModule(sub(ic.module)).withDependencies(ic.dependencies map sub).withOverrides(ic.overrides map sub) - case _ => m - } + private def substituteCross( + m: ModuleSettings, + scalaFullVersion: String, + scalaBinaryVersion: String + ): ModuleSettings = { + val sub = CrossVersion(scalaFullVersion, scalaBinaryVersion) + m match { + case ic: InlineConfiguration => + ic.withModule(sub(ic.module)) + .withDependencies(ic.dependencies map sub) + .withOverrides(ic.overrides map sub) + case _ => m } + } - private def toIvyArtifact(moduleID: ModuleDescriptor, a: Artifact, allConfigurations: Iterable[String]): MDArtifact = - { - val artifact = new MDArtifact(moduleID, a.name, a.`type`, a.extension, null, extra(a, false)) - copyConfigurations(a, artifact.addConfiguration, allConfigurations) - artifact - } - def getExtraAttributes(revID: ExtendableItem): Map[String, String] = - { - import scala.collection.JavaConverters._ - revID.getExtraAttributes.asInstanceOf[java.util.Map[String, String]].asScala.toMap - } - private[sbt] def extra(artifact: Artifact, unqualify: Boolean = false): java.util.Map[String, String] = - { - val ea = artifact.classifier match { case Some(c) => artifact.extra("e:classifier" -> c); case None => artifact } - javaMap(ea.extraAttributes, unqualify) - } - private[sbt] def javaMap(m: Map[String, String], unqualify: Boolean = false) = - { - import scala.collection.JavaConverters._ - val map = if (unqualify) m map { case (k, v) => (k.stripPrefix("e:"), v) } else m - if (map.isEmpty) null else map.asJava - } + private def toIvyArtifact( + moduleID: ModuleDescriptor, + a: Artifact, + allConfigurations: Iterable[String] + ): MDArtifact = { + val artifact = new MDArtifact(moduleID, a.name, a.`type`, a.extension, null, extra(a, false)) + copyConfigurations(a, artifact.addConfiguration, allConfigurations) + artifact + } + def getExtraAttributes(revID: ExtendableItem): Map[String, String] = { + import scala.collection.JavaConverters._ + revID.getExtraAttributes.asInstanceOf[java.util.Map[String, String]].asScala.toMap + } + private[sbt] def extra( + artifact: Artifact, + unqualify: Boolean = false + ): java.util.Map[String, String] = { + val ea = artifact.classifier match { + case Some(c) => artifact.extra("e:classifier" -> c); case None => artifact + } + javaMap(ea.extraAttributes, unqualify) + } + private[sbt] def javaMap(m: Map[String, String], unqualify: Boolean = false) = { + import scala.collection.JavaConverters._ + val map = if (unqualify) m map { case (k, v) => (k.stripPrefix("e:"), v) } else m + if (map.isEmpty) null else map.asJava + } /** Creates a full ivy file for 'module' using the 'dependencies' XML as the part after the <info>...</info> section. */ - private def wrapped(module: ModuleID, dependencies: NodeSeq) = - { - - { - if (hasInfo(module, dependencies)) - NodeSeq.Empty - else - addExtraAttributes(defaultInfo(module), module.extraAttributes) - } - { dependencies } - { - // this is because Ivy adds a default artifact if none are specified. - if ((dependencies \\ "publications").isEmpty) else NodeSeq.Empty - } - - } + private def wrapped(module: ModuleID, dependencies: NodeSeq) = { + + { + if (hasInfo(module, dependencies)) + NodeSeq.Empty + else + addExtraAttributes(defaultInfo(module), module.extraAttributes) + } + { dependencies } + { + // this is because Ivy adds a default artifact if none are specified. + if ((dependencies \\ "publications").isEmpty) else NodeSeq.Empty + } + + } private[this] def defaultInfo(module: ModuleID): scala.xml.Elem = { import module._ val base = - branchName.fold(base) { br => base % new scala.xml.UnprefixedAttribute("branch", br, scala.xml.Null) } - } - private[this] def addExtraAttributes(elem: scala.xml.Elem, extra: Map[String, String]): scala.xml.Elem = - (elem /: extra) { case (e, (key, value)) => e % new scala.xml.UnprefixedAttribute(key, value, scala.xml.Null) } - private def hasInfo(module: ModuleID, x: scala.xml.NodeSeq) = - { - val info = { x } \ "info" - if (info.nonEmpty) { - def check(found: NodeSeq, expected: String, label: String) = - if (found.isEmpty) - sys.error("Missing " + label + " in inline Ivy XML.") - else { - val str = found.text - if (str != expected) sys.error("Inconsistent " + label + " in inline Ivy XML. Expected '" + expected + "', got '" + str + "'") - } - check(info \ "@organisation", module.organization, "organisation") - check(info \ "@module", module.name, "name") - check(info \ "@revision", module.revision, "version") - } - info.nonEmpty + branchName.fold(base) { br => + base % new scala.xml.UnprefixedAttribute("branch", br, scala.xml.Null) } + } + private[this] def addExtraAttributes( + elem: scala.xml.Elem, + extra: Map[String, String] + ): scala.xml.Elem = + (elem /: extra) { + case (e, (key, value)) => e % new scala.xml.UnprefixedAttribute(key, value, scala.xml.Null) + } + private def hasInfo(module: ModuleID, x: scala.xml.NodeSeq) = { + val info = { x } \ "info" + if (info.nonEmpty) { + def check(found: NodeSeq, expected: String, label: String) = + if (found.isEmpty) + sys.error("Missing " + label + " in inline Ivy XML.") + else { + val str = found.text + if (str != expected) + sys.error( + "Inconsistent " + label + " in inline Ivy XML. Expected '" + expected + "', got '" + str + "'" + ) + } + check(info \ "@organisation", module.organization, "organisation") + check(info \ "@module", module.name, "name") + check(info \ "@revision", module.revision, "version") + } + info.nonEmpty + } + /** Parses the given in-memory Ivy file 'xml', using the existing 'moduleID' and specifying the given 'defaultConfiguration'. */ - private def parseIvyXML(settings: IvySettings, xml: scala.xml.NodeSeq, moduleID: DefaultModuleDescriptor, defaultConfiguration: String, validate: Boolean): CustomXmlParser.CustomParser = + private def parseIvyXML( + settings: IvySettings, + xml: scala.xml.NodeSeq, + moduleID: DefaultModuleDescriptor, + defaultConfiguration: String, + validate: Boolean + ): CustomXmlParser.CustomParser = parseIvyXML(settings, xml.toString, moduleID, defaultConfiguration, validate) + /** Parses the given in-memory Ivy file 'xml', using the existing 'moduleID' and specifying the given 'defaultConfiguration'. */ - private def parseIvyXML(settings: IvySettings, xml: String, moduleID: DefaultModuleDescriptor, defaultConfiguration: String, validate: Boolean): CustomXmlParser.CustomParser = - { - val parser = new CustomXmlParser.CustomParser(settings, Some(defaultConfiguration)) - parser.setMd(moduleID) - parser.setValidate(validate) - parser.setInput(xml.getBytes) - parser.parse() - parser + private def parseIvyXML( + settings: IvySettings, + xml: String, + moduleID: DefaultModuleDescriptor, + defaultConfiguration: String, + validate: Boolean + ): CustomXmlParser.CustomParser = { + val parser = new CustomXmlParser.CustomParser(settings, Some(defaultConfiguration)) + parser.setMd(moduleID) + parser.setValidate(validate) + parser.setInput(xml.getBytes) + parser.parse() + parser + } + + def inconsistentDuplicateWarning(moduleID: DefaultModuleDescriptor): List[String] = { + import IvyRetrieve.toModuleID + val dds = moduleID.getDependencies + val deps = dds flatMap { dd => + val module = toModuleID(dd.getDependencyRevisionId) + dd.getModuleConfigurations map (c => module.withConfigurations(Some(c))) } + inconsistentDuplicateWarning(deps) + } - def inconsistentDuplicateWarning(moduleID: DefaultModuleDescriptor): List[String] = - { - import IvyRetrieve.toModuleID - val dds = moduleID.getDependencies - val deps = dds flatMap { dd => - val module = toModuleID(dd.getDependencyRevisionId) - dd.getModuleConfigurations map (c => module.withConfigurations(Some(c))) - } - inconsistentDuplicateWarning(deps) - } - - def inconsistentDuplicateWarning(dependencies: Seq[ModuleID]): List[String] = - { - val warningHeader = "Multiple dependencies with the same organization/name but different versions. To avoid conflict, pick one version:" - val out: mutable.ListBuffer[String] = mutable.ListBuffer() - (dependencies groupBy { dep => (dep.organization, dep.name, dep.configurations) }) foreach { - case (k, vs) if vs.size > 1 => - val v0 = vs.head - (vs find { _.revision != v0.revision }) foreach { v => - out += s" * ${v0.organization}:${v0.name}:(" + (vs map { _.revision }).mkString(", ") + ")" - } - case _ => () - } - if (out.isEmpty) Nil - else warningHeader :: out.toList + def inconsistentDuplicateWarning(dependencies: Seq[ModuleID]): List[String] = { + val warningHeader = + "Multiple dependencies with the same organization/name but different versions. To avoid conflict, pick one version:" + val out: mutable.ListBuffer[String] = mutable.ListBuffer() + (dependencies groupBy { dep => + (dep.organization, dep.name, dep.configurations) + }) foreach { + case (k, vs) if vs.size > 1 => + val v0 = vs.head + (vs find { _.revision != v0.revision }) foreach { v => + out += s" * ${v0.organization}:${v0.name}:(" + (vs map { _.revision }) + .mkString(", ") + ")" + } + case _ => () } + if (out.isEmpty) Nil + else warningHeader :: out.toList + } /** This method is used to add inline dependencies to the provided module. */ - def addDependencies(moduleID: DefaultModuleDescriptor, dependencies: Seq[ModuleID], parser: CustomXmlParser.CustomParser): Unit = { - val converted = dependencies map { dependency => convertDependency(moduleID, dependency, parser) } - val unique = if (hasDuplicateDependencies(converted)) mergeDuplicateDefinitions(converted) else converted + def addDependencies( + moduleID: DefaultModuleDescriptor, + dependencies: Seq[ModuleID], + parser: CustomXmlParser.CustomParser + ): Unit = { + val converted = dependencies map { dependency => + convertDependency(moduleID, dependency, parser) + } + val unique = + if (hasDuplicateDependencies(converted)) mergeDuplicateDefinitions(converted) else converted unique foreach moduleID.addDependency } + /** Determines if there are multiple dependency definitions for the same dependency ID. */ - def hasDuplicateDependencies(dependencies: Seq[DependencyDescriptor]): Boolean = - { - val ids = dependencies.map(_.getDependencyRevisionId) - ids.toSet.size != ids.size - } + def hasDuplicateDependencies(dependencies: Seq[DependencyDescriptor]): Boolean = { + val ids = dependencies.map(_.getDependencyRevisionId) + ids.toSet.size != ids.size + } /** * Combines the artifacts, includes, and excludes of duplicate dependency definitions. @@ -571,119 +750,170 @@ private[sbt] object IvySbt { * as well as basic multi-classifier handling: #285, #419, #480. * Multiple dependency definitions should otherwise be avoided as much as possible. */ - def mergeDuplicateDefinitions(dependencies: Seq[DependencyDescriptor]): Seq[DependencyDescriptor] = - { - // need to preserve basic order of dependencies: can't use dependencies.groupBy - val deps = new java.util.LinkedHashMap[ModuleRevisionId, List[DependencyDescriptor]] - for (dd <- dependencies) { - val id = dd.getDependencyRevisionId - val updated = deps get id match { - case null => dd :: Nil - case v => dd :: v - } - deps.put(id, updated) + def mergeDuplicateDefinitions( + dependencies: Seq[DependencyDescriptor] + ): Seq[DependencyDescriptor] = { + // need to preserve basic order of dependencies: can't use dependencies.groupBy + val deps = new java.util.LinkedHashMap[ModuleRevisionId, List[DependencyDescriptor]] + for (dd <- dependencies) { + val id = dd.getDependencyRevisionId + val updated = deps get id match { + case null => dd :: Nil + case v => dd :: v } + deps.put(id, updated) + } - import scala.collection.JavaConverters._ - deps.values.asScala.toSeq.flatMap { dds => - val mergeable = (dds, dds.tail).zipped.forall(ivyint.MergeDescriptors.mergeable _) - if (mergeable) dds.reverse.reduceLeft(ivyint.MergeDescriptors.apply _) :: Nil else dds - } + import scala.collection.JavaConverters._ + deps.values.asScala.toSeq.flatMap { dds => + val mergeable = (dds, dds.tail).zipped.forall(ivyint.MergeDescriptors.mergeable _) + if (mergeable) dds.reverse.reduceLeft(ivyint.MergeDescriptors.apply _) :: Nil else dds } + } /** Transforms an sbt ModuleID into an Ivy DefaultDependencyDescriptor.*/ - def convertDependency(moduleID: DefaultModuleDescriptor, dependency: ModuleID, parser: CustomXmlParser.CustomParser): DefaultDependencyDescriptor = - { - val dependencyDescriptor = new DefaultDependencyDescriptor(moduleID, toID(dependency), dependency.isForce, dependency.isChanging, dependency.isTransitive) with SbtDefaultDependencyDescriptor { - def dependencyModuleId = dependency - } - dependency.configurations match { - case None => // The configuration for this dependency was not explicitly specified, so use the default - parser.parseDepsConfs(parser.getDefaultConf, dependencyDescriptor) - case Some(confs) => // The configuration mapping (looks like: test->default) was specified for this dependency - parser.parseDepsConfs(confs, dependencyDescriptor) - } - for (artifact <- dependency.explicitArtifacts) { - import artifact.{ name, `type`, extension, url } - val extraMap = extra(artifact) - val ivyArtifact = new DefaultDependencyArtifactDescriptor(dependencyDescriptor, name, `type`, extension, url.orNull, extraMap) - copyConfigurations(artifact, ivyArtifact.addConfiguration) - for (conf <- dependencyDescriptor.getModuleConfigurations) - dependencyDescriptor.addDependencyArtifact(conf, ivyArtifact) - } - for (excls <- dependency.exclusions) { - for (conf <- dependencyDescriptor.getModuleConfigurations) { - dependencyDescriptor.addExcludeRule(conf, IvyScala.excludeRule(excls.organization, excls.name, excls.configurations, excls.artifact)) - } + def convertDependency( + moduleID: DefaultModuleDescriptor, + dependency: ModuleID, + parser: CustomXmlParser.CustomParser + ): DefaultDependencyDescriptor = { + val dependencyDescriptor = new DefaultDependencyDescriptor( + moduleID, + toID(dependency), + dependency.isForce, + dependency.isChanging, + dependency.isTransitive + ) with SbtDefaultDependencyDescriptor { + def dependencyModuleId = dependency + } + dependency.configurations match { + case None => // The configuration for this dependency was not explicitly specified, so use the default + parser.parseDepsConfs(parser.getDefaultConf, dependencyDescriptor) + case Some(confs) => // The configuration mapping (looks like: test->default) was specified for this dependency + parser.parseDepsConfs(confs, dependencyDescriptor) + } + for (artifact <- dependency.explicitArtifacts) { + import artifact.{ name, `type`, extension, url } + val extraMap = extra(artifact) + val ivyArtifact = new DefaultDependencyArtifactDescriptor( + dependencyDescriptor, + name, + `type`, + extension, + url.orNull, + extraMap + ) + copyConfigurations(artifact, ivyArtifact.addConfiguration) + for (conf <- dependencyDescriptor.getModuleConfigurations) + dependencyDescriptor.addDependencyArtifact(conf, ivyArtifact) + } + for (excls <- dependency.exclusions) { + for (conf <- dependencyDescriptor.getModuleConfigurations) { + dependencyDescriptor.addExcludeRule( + conf, + IvyScala.excludeRule( + excls.organization, + excls.name, + excls.configurations, + excls.artifact + ) + ) } - for (incls <- dependency.inclusions) { - for (conf <- dependencyDescriptor.getModuleConfigurations) { - dependencyDescriptor.addIncludeRule(conf, IvyScala.includeRule(incls.organization, incls.name, incls.configurations, incls.artifact)) - } + } + for (incls <- dependency.inclusions) { + for (conf <- dependencyDescriptor.getModuleConfigurations) { + dependencyDescriptor.addIncludeRule( + conf, + IvyScala.includeRule( + incls.organization, + incls.name, + incls.configurations, + incls.artifact + ) + ) } - - dependencyDescriptor } + + dependencyDescriptor + } def copyConfigurations(artifact: Artifact, addConfiguration: String => Unit): Unit = copyConfigurations(artifact, addConfiguration, "*" :: Nil) - private[this] def copyConfigurations(artifact: Artifact, addConfiguration: String => Unit, allConfigurations: Iterable[String]): Unit = - { - val confs = if (artifact.configurations.isEmpty) allConfigurations else artifact.configurations.map(_.name) - confs foreach addConfiguration - } + private[this] def copyConfigurations( + artifact: Artifact, + addConfiguration: String => Unit, + allConfigurations: Iterable[String] + ): Unit = { + val confs = + if (artifact.configurations.isEmpty) allConfigurations + else artifact.configurations.map(_.name) + confs foreach addConfiguration + } - def addExcludes(moduleID: DefaultModuleDescriptor, excludes: Seq[SbtExclusionRule], ivyScala: Option[IvyScala]): Unit = + def addExcludes( + moduleID: DefaultModuleDescriptor, + excludes: Seq[SbtExclusionRule], + ivyScala: Option[IvyScala] + ): Unit = excludes foreach addExclude(moduleID, ivyScala) - def addExclude(moduleID: DefaultModuleDescriptor, ivyScala: Option[IvyScala])(exclude0: SbtExclusionRule): Unit = - { - // this adds _2.11 postfix - val exclude = CrossVersion.substituteCross(exclude0, ivyScala) - val confs = - if (exclude.configurations.isEmpty) moduleID.getConfigurationsNames.toList - else exclude.configurations - val excludeRule = IvyScala.excludeRule(exclude.organization, exclude.name, confs, exclude.artifact) - moduleID.addExcludeRule(excludeRule) - } - - def addOverrides(moduleID: DefaultModuleDescriptor, overrides: Set[ModuleID], matcher: PatternMatcher): Unit = + def addExclude(moduleID: DefaultModuleDescriptor, ivyScala: Option[IvyScala])( + exclude0: SbtExclusionRule + ): Unit = { + // this adds _2.11 postfix + val exclude = CrossVersion.substituteCross(exclude0, ivyScala) + val confs = + if (exclude.configurations.isEmpty) moduleID.getConfigurationsNames.toList + else exclude.configurations + val excludeRule = + IvyScala.excludeRule(exclude.organization, exclude.name, confs, exclude.artifact) + moduleID.addExcludeRule(excludeRule) + } + + def addOverrides( + moduleID: DefaultModuleDescriptor, + overrides: Set[ModuleID], + matcher: PatternMatcher + ): Unit = overrides foreach addOverride(moduleID, matcher) - def addOverride(moduleID: DefaultModuleDescriptor, matcher: PatternMatcher)(overrideDef: ModuleID): Unit = - { - val overrideID = new ModuleId(overrideDef.organization, overrideDef.name) - val overrideWith = new OverrideDependencyDescriptorMediator(null, overrideDef.revision) - moduleID.addDependencyDescriptorMediator(overrideID, matcher, overrideWith) - } + def addOverride(moduleID: DefaultModuleDescriptor, matcher: PatternMatcher)( + overrideDef: ModuleID + ): Unit = { + val overrideID = new ModuleId(overrideDef.organization, overrideDef.name) + val overrideWith = new OverrideDependencyDescriptorMediator(null, overrideDef.revision) + moduleID.addDependencyDescriptorMediator(overrideID, matcher, overrideWith) + } + /** * It is necessary to explicitly modify direct dependencies because Ivy gives * "IllegalStateException: impossible to get artifacts when data has not been loaded." * when a direct dependency is overridden with a newer version." */ - def overrideDirect(dependencies: Seq[ModuleID], overrides: Set[ModuleID]): Seq[ModuleID] = - { - def key(id: ModuleID) = (id.organization, id.name) - val overridden = overrides.map(id => (key(id), id.revision)).toMap - dependencies map { dep => - overridden get key(dep) match { - case Some(rev) => dep.withRevision(rev) - case None => dep - } + def overrideDirect(dependencies: Seq[ModuleID], overrides: Set[ModuleID]): Seq[ModuleID] = { + def key(id: ModuleID) = (id.organization, id.name) + val overridden = overrides.map(id => (key(id), id.revision)).toMap + dependencies map { dep => + overridden get key(dep) match { + case Some(rev) => dep.withRevision(rev) + case None => dep } } + } /** This method is used to add inline artifacts to the provided module. */ def addArtifacts(moduleID: DefaultModuleDescriptor, artifacts: Iterable[Artifact]): Unit = for (art <- mapArtifacts(moduleID, artifacts.toSeq); c <- art.getConfigurations) moduleID.addArtifact(c, art) - def addConfigurations(mod: DefaultModuleDescriptor, configurations: Iterable[Configuration]): Unit = + def addConfigurations( + mod: DefaultModuleDescriptor, + configurations: Iterable[Configuration] + ): Unit = configurations.foreach(config => mod.addConfiguration(toIvyConfiguration(config))) - def mapArtifacts(moduleID: ModuleDescriptor, artifacts: Seq[Artifact]): Seq[IArtifact] = - { - lazy val allConfigurations = moduleID.getPublicConfigurationsNames - for (artifact <- artifacts) yield toIvyArtifact(moduleID, artifact, allConfigurations) - } + def mapArtifacts(moduleID: ModuleDescriptor, artifacts: Seq[Artifact]): Seq[IArtifact] = { + lazy val allConfigurations = moduleID.getPublicConfigurationsNames + for (artifact <- artifacts) yield toIvyArtifact(moduleID, artifact, allConfigurations) + } /** * This code converts the given ModuleDescriptor to a DefaultModuleDescriptor by casting or generating an error. @@ -694,7 +924,10 @@ private[sbt] object IvySbt { case dmd: DefaultModuleDescriptor => dmd case _ => sys.error("Unknown ModuleDescriptor type.") } - def getConfigurations(module: ModuleDescriptor, configurations: Option[Iterable[Configuration]]) = + def getConfigurations( + module: ModuleDescriptor, + configurations: Option[Iterable[Configuration]] + ) = configurations match { case Some(confs) => confs.map(_.name).toList.toArray case None => module.getPublicConfigurationsNames diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyActions.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyActions.scala index cc1a2eda..aad711ff 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyActions.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyActions.scala @@ -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) - - 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) + 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) + } @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 - } + 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 - } + } + 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:" diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyCache.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyCache.scala index ae7d0127..c697b639 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyCache.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyCache.scala @@ -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 = { diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyConfigurations.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyConfigurations.scala index 74bdde75..71c52732 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyConfigurations.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyConfigurations.scala @@ -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 diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyLogger.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyLogger.scala index 02830669..f178a95f 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyLogger.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyLogger.scala @@ -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() diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyRetrieve.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyRetrieve.scala index fa55c51e..d76f7556 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyRetrieve.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/IvyRetrieve.scala @@ -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. diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/JsonUtil.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/JsonUtil.scala index 55d7dbd6..19c83539 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/JsonUtil.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/JsonUtil.scala @@ -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) + } } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/MakePom.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/MakePom.scala index 5544d0d5..3e30bf85 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/MakePom.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/MakePom.scala @@ -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, "" + 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 = ( 4.0.0 { makeModuleID(module) } @@ -65,81 +151,80 @@ class MakePom(val log: Logger) { { makeRepositories(ivy.getSettings, allRepositories, filterRepositories) } ) - def makeModuleID(module: ModuleDescriptor): NodeSeq = - { - val mrid = moduleDescriptor(module) - val a: NodeSeq = - ({ mrid.getOrganisation } - { mrid.getName } - { packaging(module) }) - 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 = + ({ mrid.getOrganisation } + { mrid.getName } + { packaging(module) }) + 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) => { y } case _ => NodeSeq.Empty } - def makeOrganization(moduleInfo: ModuleInfo): NodeSeq = - { - - { moduleInfo.organizationName } - { - moduleInfo.organizationHomepage match { - case Some(h)=> { h } - case _ => NodeSeq.Empty - } + def makeOrganization(moduleInfo: ModuleInfo): NodeSeq = { + + { moduleInfo.organizationName } + { + moduleInfo.organizationHomepage match { + case Some(h)=> { h } + case _ => NodeSeq.Empty } - - } - def makeScmInfo(moduleInfo: ModuleInfo): NodeSeq = - { - moduleInfo.scmInfo match { - case Some(s) => - - { s.browseUrl } - { s.connection } - { - s.devConnection match { - case Some(d)=> { d } - case _=> NodeSeq.Empty - } - } - - case _ => NodeSeq.Empty } - } - def makeDeveloperInfo(moduleInfo: ModuleInfo): NodeSeq = - { - if (moduleInfo.developers.nonEmpty) { - + + } + def makeScmInfo(moduleInfo: ModuleInfo): NodeSeq = { + moduleInfo.scmInfo match { + case Some(s) => + + { s.browseUrl } + { s.connection } { - moduleInfo.developers.map { developer: Developer => - - { developer.id } - { developer.name } - { developer.email } - { developer.url } - + s.devConnection match { + case Some(d)=> { d } + case _=> NodeSeq.Empty } } - - } 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) + + case _ => NodeSeq.Empty } + } + def makeDeveloperInfo(moduleInfo: ModuleInfo): NodeSeq = { + if (moduleInfo.developers.nonEmpty) { + + { + moduleInfo.developers.map { developer: Developer => + + { developer.id } + { developer.name } + { developer.email } + { developer.url } + + } + } + + } 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 { for ((key, value) <- extra) yield ({ value }).copy(label = key, attributes = _extraAttributes(key)) } @@ -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 { d } - def licenses(ls: Array[License]) = if (ls == null || ls.isEmpty) NodeSeq.Empty else { ls.map(license) } + def description(d: String) = + if ((d eq null) || d.isEmpty) NodeSeq.Empty else { d } + def licenses(ls: Array[License]) = + if (ls == null || ls.isEmpty) NodeSeq.Empty else { ls.map(license) } def license(l: License) = { l.getName } @@ -161,7 +248,8 @@ class MakePom(val log: Logger) { repo def homePage(homePage: String) = if (homePage eq null) NodeSeq.Empty else { homePage } - def revision(version: String) = if (version ne null) { version } else NodeSeq.Empty + def revision(version: String) = + if (version ne null) { 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 - - { mrid.getOrganisation } - { mrid.getName } - { makeDependencyVersion(mrid.getRevision) } - { scopeElem(scope) } - { optionalElem(optional) } - { classifierElem(classifier) } - { typeElem(tpe) } - { exclusions(dependency, excludes) } - - } + def makeDependencyElem( + dependency: DependencyDescriptor, + scope: Option[String], + optional: Boolean, + classifier: Option[String], + tpe: Option[String], + excludes: Seq[ExcludeRule] + ): Elem = { + val mrid = dependency.getDependencyRevisionId + + { mrid.getOrganisation } + { mrid.getName } + { makeDependencyVersion(mrid.getRevision) } + { scopeElem(scope) } + { optionalElem(optional) } + { classifierElem(classifier) } + { typeElem(tpe) } + { exclusions(dependency, excludes) } + + } @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) => { t } @@ -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) => { s } @@ -287,59 +403,67 @@ class MakePom(val log: Logger) { def optionalElem(opt: Boolean) = if (opt) true 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) { excls } - 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 '' for %s. Dependency exclusion should have both 'org' and 'module' to comply with Maven POM's schema.".format(m)) - else - Right( - - { g } - { a } - - ) - } + 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) { excls } + 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 '' for %s. Dependency exclusion should have both 'org' and 'module' to comply with Maven POM's schema." + .format(m) + ) + else + Right( + + { g } + { a } + + ) + } - 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 { repositoryElements } - } - 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 { repositoryElements } + } + 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 + } } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ProjectResolver.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ProjectResolver.scala index caca5a9e..912f77bd 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ProjectResolver.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ProjectResolver.scala @@ -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 { diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/RepositoriesParser.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/RepositoriesParser.scala index 1f56dbb6..a10741b6 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/RepositoriesParser.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/RepositoriesParser.scala @@ -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)) } } -} \ No newline at end of file +} diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ResolutionCache.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ResolutionCache.scala index 25103ba8..c6d3da44 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ResolutionCache.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ResolutionCache.scala @@ -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 ::: diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/SbtExclusionRuleExtra.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/SbtExclusionRuleExtra.scala index ec144cfe..6c5c0124 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/SbtExclusionRuleExtra.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/SbtExclusionRuleExtra.scala @@ -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 = diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/StringUtilities.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/StringUtilities.scala index 00541d44..37c26418 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/StringUtilities.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/StringUtilities.scala @@ -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 } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/VersionRange.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/VersionRange.scala index bb73c882..38c5661b 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/VersionRange.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/VersionRange.scala @@ -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 } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/cross/CrossVersionUtil.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/cross/CrossVersionUtil.scala index 7524f085..4ebc79ca 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/cross/CrossVersionUtil.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/cross/CrossVersionUtil.scala @@ -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 } + } } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/UpdateOptionsFormat.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/UpdateOptionsFormat.scala index e5e8b6e6..0770fee8 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/UpdateOptionsFormat.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/formats/UpdateOptionsFormat.scala @@ -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( diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/impl/DependencyBuilders.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/impl/DependencyBuilders.scala index c5e117c7..a37a4f38 100755 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/impl/DependencyBuilders.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/impl/DependencyBuilders.scala @@ -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) + } } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala index 8b9cb507..0b4e2b92 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala @@ -12,8 +12,19 @@ import org.apache.ivy.core import core.resolve._ import core.module.id.{ ModuleRevisionId, ModuleId => IvyModuleId } import core.report.ResolveReport -import core.module.descriptor.{ DefaultModuleDescriptor, ModuleDescriptor, DefaultDependencyDescriptor, DependencyDescriptor, Configuration => IvyConfiguration, ExcludeRule, IncludeRule } -import core.module.descriptor.{ OverrideDependencyDescriptorMediator, DependencyArtifactDescriptor } +import core.module.descriptor.{ + DefaultModuleDescriptor, + ModuleDescriptor, + DefaultDependencyDescriptor, + DependencyDescriptor, + Configuration => IvyConfiguration, + ExcludeRule, + IncludeRule +} +import core.module.descriptor.{ + OverrideDependencyDescriptorMediator, + DependencyArtifactDescriptor +} import core.IvyPatternHelper import org.apache.ivy.util.{ Message, MessageLogger } import org.apache.ivy.plugins.latest.{ ArtifactInfo => IvyArtifactInfo } @@ -39,12 +50,17 @@ private[sbt] object CachedResolutionResolveCache { private[sbt] class CachedResolutionResolveCache { import CachedResolutionResolveCache._ - val updateReportCache: concurrent.Map[ModuleRevisionId, Either[ResolveException, UpdateReport]] = concurrent.TrieMap() + val updateReportCache: concurrent.Map[ModuleRevisionId, Either[ResolveException, UpdateReport]] = + concurrent.TrieMap() // Used for subproject - val projectReportCache: concurrent.Map[(ModuleRevisionId, LogicalClock), Either[ResolveException, UpdateReport]] = concurrent.TrieMap() + val projectReportCache + : concurrent.Map[(ModuleRevisionId, LogicalClock), Either[ResolveException, UpdateReport]] = + concurrent.TrieMap() val resolveReportCache: concurrent.Map[ModuleRevisionId, ResolveReport] = concurrent.TrieMap() val resolvePropertiesCache: concurrent.Map[ModuleRevisionId, String] = concurrent.TrieMap() - val conflictCache: concurrent.Map[(ModuleID, ModuleID), (Vector[ModuleID], Vector[ModuleID], String)] = concurrent.TrieMap() + val conflictCache + : concurrent.Map[(ModuleID, ModuleID), (Vector[ModuleID], Vector[ModuleID], String)] = + concurrent.TrieMap() val maxConflictCacheSize: Int = 1024 val maxUpdateReportCacheSize: Int = 1024 @@ -54,191 +70,235 @@ private[sbt] class CachedResolutionResolveCache { def directDependencies(md0: ModuleDescriptor): Vector[DependencyDescriptor] = md0.getDependencies.toVector // Returns a vector of (module descriptor, changing, dd) - def buildArtificialModuleDescriptors(md0: ModuleDescriptor, data: ResolveData, prOpt: Option[ProjectResolver], log: Logger): Vector[(DefaultModuleDescriptor, Boolean, DependencyDescriptor)] = - { - log.debug(s":: building artificial module descriptors from ${md0.getModuleRevisionId}") - // val expanded = expandInternalDependencies(md0, data, prOpt, log) - val rootModuleConfigs = md0.getConfigurations.toVector - directDependencies(md0) map { dd => - val arts = dd.getAllDependencyArtifacts.toVector map { x => s"""${x.getName}:${x.getType}:${x.getExt}:${x.getExtraAttributes}""" } - log.debug(s"::: dd: $dd (artifacts: ${arts.mkString(",")})") - buildArtificialModuleDescriptor(dd, rootModuleConfigs, md0, prOpt, log) + def buildArtificialModuleDescriptors( + md0: ModuleDescriptor, + data: ResolveData, + prOpt: Option[ProjectResolver], + log: Logger + ): Vector[(DefaultModuleDescriptor, Boolean, DependencyDescriptor)] = { + log.debug(s":: building artificial module descriptors from ${md0.getModuleRevisionId}") + // val expanded = expandInternalDependencies(md0, data, prOpt, log) + val rootModuleConfigs = md0.getConfigurations.toVector + directDependencies(md0) map { dd => + val arts = dd.getAllDependencyArtifacts.toVector map { x => + s"""${x.getName}:${x.getType}:${x.getExt}:${x.getExtraAttributes}""" } + log.debug(s"::: dd: $dd (artifacts: ${arts.mkString(",")})") + buildArtificialModuleDescriptor(dd, rootModuleConfigs, md0, prOpt, log) } - def internalDependency(dd: DependencyDescriptor, prOpt: Option[ProjectResolver]): Option[ModuleDescriptor] = + } + def internalDependency( + dd: DependencyDescriptor, + prOpt: Option[ProjectResolver] + ): Option[ModuleDescriptor] = prOpt match { case Some(pr) => pr.getModuleDescriptor(dd.getDependencyRevisionId) case _ => None } - def buildArtificialModuleDescriptor(dd: DependencyDescriptor, rootModuleConfigs: Vector[IvyConfiguration], - parent: ModuleDescriptor, prOpt: Option[ProjectResolver], log: Logger): (DefaultModuleDescriptor, Boolean, DependencyDescriptor) = - { - def excludeRuleString(rule: ExcludeRule): String = - s"""Exclude(${rule.getId},${rule.getConfigurations.mkString(",")},${rule.getMatcher})""" - def includeRuleString(rule: IncludeRule): String = - s"""Include(${rule.getId},${rule.getConfigurations.mkString(",")},${rule.getMatcher})""" - def artifactString(dad: DependencyArtifactDescriptor): String = - s"""Artifact(${dad.getName},${dad.getType},${dad.getExt},${dad.getUrl},${dad.getConfigurations.mkString(",")},${dad.getExtraAttributes})""" - val mrid = dd.getDependencyRevisionId - val confMap = (dd.getModuleConfigurations map { conf => - conf + "->(" + dd.getDependencyConfigurations(conf).mkString(",") + ")" - }) - val exclusions = (dd.getModuleConfigurations.toVector flatMap { conf => - dd.getExcludeRules(conf).toVector match { - case Vector() => None - case rules => Some(conf + "->(" + (rules map excludeRuleString).mkString(",") + ")") - } - }) - val inclusions = (dd.getModuleConfigurations.toVector flatMap { conf => - dd.getIncludeRules(conf).toVector match { - case Vector() => None - case rules => Some(conf + "->(" + (rules map includeRuleString).mkString(",") + ")") - } - }) - val explicitArtifacts = dd.getAllDependencyArtifacts.toVector map { artifactString } - val mes = parent.getAllExcludeRules.toVector - val mesStr = (mes map excludeRuleString).mkString(",") - val os = extractOverrides(parent) - val moduleLevel = s"""dependencyOverrides=${os.mkString(",")};moduleExclusions=$mesStr""" - val depsString = s"""$mrid;${confMap.mkString(",")};isForce=${dd.isForce};isChanging=${dd.isChanging};isTransitive=${dd.isTransitive};""" + - s"""exclusions=${exclusions.mkString(",")};inclusions=${inclusions.mkString(",")};explicitArtifacts=${explicitArtifacts.mkString(",")};$moduleLevel;""" - val sha1 = Hash.toHex(Hash(s"""graphVersion=${CachedResolutionResolveCache.graphVersion};$depsString""")) - val md1 = new DefaultModuleDescriptor(createID(sbtOrgTemp, "temp-resolve-" + sha1, "1.0"), "release", null, false) with ArtificialModuleDescriptor { - def targetModuleRevisionId: ModuleRevisionId = mrid + def buildArtificialModuleDescriptor( + dd: DependencyDescriptor, + rootModuleConfigs: Vector[IvyConfiguration], + parent: ModuleDescriptor, + prOpt: Option[ProjectResolver], + log: Logger + ): (DefaultModuleDescriptor, Boolean, DependencyDescriptor) = { + def excludeRuleString(rule: ExcludeRule): String = + s"""Exclude(${rule.getId},${rule.getConfigurations.mkString(",")},${rule.getMatcher})""" + def includeRuleString(rule: IncludeRule): String = + s"""Include(${rule.getId},${rule.getConfigurations.mkString(",")},${rule.getMatcher})""" + def artifactString(dad: DependencyArtifactDescriptor): String = + s"""Artifact(${dad.getName},${dad.getType},${dad.getExt},${dad.getUrl},${dad.getConfigurations + .mkString(",")},${dad.getExtraAttributes})""" + val mrid = dd.getDependencyRevisionId + val confMap = (dd.getModuleConfigurations map { conf => + conf + "->(" + dd.getDependencyConfigurations(conf).mkString(",") + ")" + }) + val exclusions = (dd.getModuleConfigurations.toVector flatMap { conf => + dd.getExcludeRules(conf).toVector match { + case Vector() => None + case rules => Some(conf + "->(" + (rules map excludeRuleString).mkString(",") + ")") } - for { - conf <- rootModuleConfigs - } yield md1.addConfiguration(conf) - md1.addDependency(dd) - os foreach { ovr => - md1.addDependencyDescriptorMediator(ovr.moduleId, ovr.pm, ovr.ddm) + }) + val inclusions = (dd.getModuleConfigurations.toVector flatMap { conf => + dd.getIncludeRules(conf).toVector match { + case Vector() => None + case rules => Some(conf + "->(" + (rules map includeRuleString).mkString(",") + ")") } - mes foreach { exclude => - md1.addExcludeRule(exclude) - } - (md1, IvySbt.isChanging(dd) || internalDependency(dd, prOpt).isDefined, dd) + }) + val explicitArtifacts = dd.getAllDependencyArtifacts.toVector map { artifactString } + val mes = parent.getAllExcludeRules.toVector + val mesStr = (mes map excludeRuleString).mkString(",") + val os = extractOverrides(parent) + val moduleLevel = s"""dependencyOverrides=${os.mkString(",")};moduleExclusions=$mesStr""" + val depsString = s"""$mrid;${confMap.mkString(",")};isForce=${dd.isForce};isChanging=${dd.isChanging};isTransitive=${dd.isTransitive};""" + + s"""exclusions=${exclusions.mkString(",")};inclusions=${inclusions.mkString(",")};explicitArtifacts=${explicitArtifacts + .mkString(",")};$moduleLevel;""" + val sha1 = Hash.toHex( + Hash(s"""graphVersion=${CachedResolutionResolveCache.graphVersion};$depsString""") + ) + val md1 = new DefaultModuleDescriptor( + createID(sbtOrgTemp, "temp-resolve-" + sha1, "1.0"), + "release", + null, + false + ) with ArtificialModuleDescriptor { + def targetModuleRevisionId: ModuleRevisionId = mrid } - def extractOverrides(md0: ModuleDescriptor): Vector[IvyOverride] = - { - import scala.collection.JavaConverters._ - md0.getAllDependencyDescriptorMediators.getAllRules.asScala.toSeq.toVector sortBy { - case (k, v) => - k.toString - } collect { - case (k: MapMatcher, v: OverrideDependencyDescriptorMediator) => - val attr: Map[Any, Any] = k.getAttributes.asScala.toMap - val module = IvyModuleId.newInstance(attr(IvyPatternHelper.ORGANISATION_KEY).toString, attr(IvyPatternHelper.MODULE_KEY).toString) - val pm = k.getPatternMatcher - IvyOverride(module, pm, v) - } + for { + conf <- rootModuleConfigs + } yield md1.addConfiguration(conf) + md1.addDependency(dd) + os foreach { ovr => + md1.addDependencyDescriptorMediator(ovr.moduleId, ovr.pm, ovr.ddm) } - def getOrElseUpdateMiniGraph(md: ModuleDescriptor, changing0: Boolean, logicalClock: LogicalClock, miniGraphPath: File, cachedDescriptor: File, log: Logger)(f: => Either[ResolveException, UpdateReport]): Either[ResolveException, UpdateReport] = - { - import sbt.io.syntax._ - val mrid = md.getResolvedModuleRevisionId - val (pathOrg, pathName, pathRevision) = md match { - case x: ArtificialModuleDescriptor => - val tmrid = x.targetModuleRevisionId - (tmrid.getOrganisation, tmrid.getName, tmrid.getRevision + "_" + mrid.getName) - case _ => - (mrid.getOrganisation, mrid.getName, mrid.getRevision) + mes foreach { exclude => + md1.addExcludeRule(exclude) + } + (md1, IvySbt.isChanging(dd) || internalDependency(dd, prOpt).isDefined, dd) + } + def extractOverrides(md0: ModuleDescriptor): Vector[IvyOverride] = { + import scala.collection.JavaConverters._ + md0.getAllDependencyDescriptorMediators.getAllRules.asScala.toSeq.toVector sortBy { + case (k, v) => + k.toString + } collect { + case (k: MapMatcher, v: OverrideDependencyDescriptorMediator) => + val attr: Map[Any, Any] = k.getAttributes.asScala.toMap + val module = IvyModuleId.newInstance( + attr(IvyPatternHelper.ORGANISATION_KEY).toString, + attr(IvyPatternHelper.MODULE_KEY).toString + ) + val pm = k.getPatternMatcher + IvyOverride(module, pm, v) + } + } + def getOrElseUpdateMiniGraph( + md: ModuleDescriptor, + changing0: Boolean, + logicalClock: LogicalClock, + miniGraphPath: File, + cachedDescriptor: File, + log: Logger + )( + f: => Either[ResolveException, UpdateReport] + ): Either[ResolveException, UpdateReport] = { + import sbt.io.syntax._ + val mrid = md.getResolvedModuleRevisionId + val (pathOrg, pathName, pathRevision) = md match { + case x: ArtificialModuleDescriptor => + val tmrid = x.targetModuleRevisionId + (tmrid.getOrganisation, tmrid.getName, tmrid.getRevision + "_" + mrid.getName) + case _ => + (mrid.getOrganisation, mrid.getName, mrid.getRevision) + } + val staticGraphDirectory = miniGraphPath / "static" + val dynamicGraphDirectory = miniGraphPath / "dynamic" + val staticGraphPath = staticGraphDirectory / pathOrg / pathName / pathRevision / "graphs" / "graph.json" + val dynamicGraphPath = dynamicGraphDirectory / todayStr / logicalClock.toString / pathOrg / pathName / pathRevision / "graphs" / "graph.json" + def cleanDynamicGraph(): Unit = { + val list = IO.listFiles(dynamicGraphDirectory, DirectoryFilter).toList + list filterNot { d => + (d.getName == todayStr) || (d.getName == tomorrowStr) || (d.getName == yesterdayStr) + } foreach { d => + log.debug(s"deleting old graphs $d...") + IO.delete(d) } - val staticGraphDirectory = miniGraphPath / "static" - val dynamicGraphDirectory = miniGraphPath / "dynamic" - val staticGraphPath = staticGraphDirectory / pathOrg / pathName / pathRevision / "graphs" / "graph.json" - val dynamicGraphPath = dynamicGraphDirectory / todayStr / logicalClock.toString / pathOrg / pathName / pathRevision / "graphs" / "graph.json" - def cleanDynamicGraph(): Unit = - { - val list = IO.listFiles(dynamicGraphDirectory, DirectoryFilter).toList - list filterNot { d => - (d.getName == todayStr) || (d.getName == tomorrowStr) || (d.getName == yesterdayStr) - } foreach { d => - log.debug(s"deleting old graphs $d...") - IO.delete(d) + } + def loadMiniGraphFromFile: Option[Either[ResolveException, UpdateReport]] = + (if (staticGraphPath.exists) Some(staticGraphPath) + else if (dynamicGraphPath.exists) Some(dynamicGraphPath) + else None) match { + case Some(path) => + log.debug(s"parsing ${path.getAbsolutePath.toString}") + val ur = JsonUtil.parseUpdateReport(md, path, cachedDescriptor, log) + if (ur.allFiles forall { _.exists }) { + updateReportCache(md.getModuleRevisionId) = Right(ur) + Some(Right(ur)) + } else { + log.debug(s"some files are missing from the cache, so invalidating the minigraph") + IO.delete(path) + None } + case _ => None + } + (updateReportCache.get(mrid) orElse loadMiniGraphFromFile) match { + case Some(result) => + result match { + case Right(ur) => Right(ur.withStats(ur.stats.withCached(true))) + case x => x } - def loadMiniGraphFromFile: Option[Either[ResolveException, UpdateReport]] = - (if (staticGraphPath.exists) Some(staticGraphPath) - else if (dynamicGraphPath.exists) Some(dynamicGraphPath) - else None) match { - case Some(path) => - log.debug(s"parsing ${path.getAbsolutePath.toString}") - val ur = JsonUtil.parseUpdateReport(md, path, cachedDescriptor, log) - if (ur.allFiles forall { _.exists }) { + case None => + f match { + case Right(ur) => + val changing = changing0 || (ur.configurations exists { cr => + cr.details exists { oar => + oar.modules exists { mr => + IvySbt.isChanging(mr.module) || (mr.callers exists { _.isChangingDependency }) + } + } + }) + IO.createDirectory(miniGraphPath) + val gp = + if (changing) dynamicGraphPath + else staticGraphPath + log.debug(s"saving minigraph to $gp") + if (changing) { + cleanDynamicGraph() + } + JsonUtil.writeUpdateReport(ur, gp) + // limit the update cache size + if (updateReportCache.size > maxUpdateReportCacheSize) { + updateReportCache.remove(updateReportCache.head._1) + } + // don't cache dynamic graphs in memory. + if (!changing) { updateReportCache(md.getModuleRevisionId) = Right(ur) - Some(Right(ur)) - } else { - log.debug(s"some files are missing from the cache, so invalidating the minigraph") - IO.delete(path) - None } - case _ => None + Right(ur) + case Left(re) => + if (!changing0) { + updateReportCache(md.getModuleRevisionId) = Left(re) + } + Left(re) } - (updateReportCache.get(mrid) orElse loadMiniGraphFromFile) match { - case Some(result) => - result match { - case Right(ur) => Right(ur.withStats(ur.stats.withCached(true))) - case x => x - } - case None => - f match { - case Right(ur) => - val changing = changing0 || (ur.configurations exists { cr => - cr.details exists { oar => - oar.modules exists { mr => - IvySbt.isChanging(mr.module) || (mr.callers exists { _.isChangingDependency }) - } - } - }) - IO.createDirectory(miniGraphPath) - val gp = if (changing) dynamicGraphPath - else staticGraphPath - log.debug(s"saving minigraph to $gp") - if (changing) { - cleanDynamicGraph() - } - JsonUtil.writeUpdateReport(ur, gp) - // limit the update cache size - if (updateReportCache.size > maxUpdateReportCacheSize) { - updateReportCache.remove(updateReportCache.head._1) - } - // don't cache dynamic graphs in memory. - if (!changing) { - updateReportCache(md.getModuleRevisionId) = Right(ur) - } - Right(ur) - case Left(re) => - if (!changing0) { - updateReportCache(md.getModuleRevisionId) = Left(re) - } - Left(re) - } - } } + } - def getOrElseUpdateConflict(cf0: ModuleID, cf1: ModuleID, conflicts: Vector[ModuleReport])(f: => (Vector[ModuleReport], Vector[ModuleReport], String)): (Vector[ModuleReport], Vector[ModuleReport]) = - { - def reconstructReports(surviving: Vector[ModuleID], evicted: Vector[ModuleID], mgr: String): (Vector[ModuleReport], Vector[ModuleReport]) = { - val moduleIdMap = Map(conflicts map { x => x.module -> x }: _*) - (surviving map moduleIdMap, evicted map moduleIdMap map { _.withEvicted(true).withEvictedReason(Some(mgr.toString)) }) - } - (conflictCache get ((cf0, cf1))) match { - case Some((surviving, evicted, mgr)) => reconstructReports(surviving, evicted, mgr) - case _ => - (conflictCache get ((cf1, cf0))) match { - case Some((surviving, evicted, mgr)) => reconstructReports(surviving, evicted, mgr) - case _ => - val (surviving, evicted, mgr) = f - if (conflictCache.size > maxConflictCacheSize) { - conflictCache.remove(conflictCache.head._1) - } - conflictCache((cf0, cf1)) = (surviving map { _.module }, evicted map { _.module }, mgr) - (surviving, evicted) - } - } + def getOrElseUpdateConflict(cf0: ModuleID, cf1: ModuleID, conflicts: Vector[ModuleReport])( + f: => (Vector[ModuleReport], Vector[ModuleReport], String) + ): (Vector[ModuleReport], Vector[ModuleReport]) = { + def reconstructReports( + surviving: Vector[ModuleID], + evicted: Vector[ModuleID], + mgr: String + ): (Vector[ModuleReport], Vector[ModuleReport]) = { + val moduleIdMap = Map(conflicts map { x => + x.module -> x + }: _*) + (surviving map moduleIdMap, evicted map moduleIdMap map { + _.withEvicted(true).withEvictedReason(Some(mgr.toString)) + }) } - def getOrElseUpdateProjectReport(mrid: ModuleRevisionId, logicalClock: LogicalClock)(f: => Either[ResolveException, UpdateReport]): Either[ResolveException, UpdateReport] = - if (projectReportCache contains (mrid -> logicalClock)) projectReportCache((mrid, logicalClock)) + (conflictCache get ((cf0, cf1))) match { + case Some((surviving, evicted, mgr)) => reconstructReports(surviving, evicted, mgr) + case _ => + (conflictCache get ((cf1, cf0))) match { + case Some((surviving, evicted, mgr)) => reconstructReports(surviving, evicted, mgr) + case _ => + val (surviving, evicted, mgr) = f + if (conflictCache.size > maxConflictCacheSize) { + conflictCache.remove(conflictCache.head._1) + } + conflictCache((cf0, cf1)) = (surviving map { _.module }, evicted map { _.module }, mgr) + (surviving, evicted) + } + } + } + def getOrElseUpdateProjectReport(mrid: ModuleRevisionId, logicalClock: LogicalClock)( + f: => Either[ResolveException, UpdateReport] + ): Either[ResolveException, UpdateReport] = + if (projectReportCache contains (mrid -> logicalClock)) + projectReportCache((mrid, logicalClock)) else { val oldKeys = projectReportCache.keys filter { case (x, clk) => clk != logicalClock } projectReportCache --= oldKeys @@ -263,86 +323,107 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { val ivy = makeInstance ivy.pushContext() ivy.getLoggerEngine.pushLogger(log) - try { f(ivy) } - finally { + try { f(ivy) } finally { ivy.getLoggerEngine.popLogger() ivy.popContext() } } - def withDefaultLogger[A](log: MessageLogger)(f: => A): A = - { - val originalLogger = Message.getDefaultLogger - Message.setDefaultLogger(log) - try { f } - finally { Message.setDefaultLogger(originalLogger) } - } + def withDefaultLogger[A](log: MessageLogger)(f: => A): A = { + val originalLogger = Message.getDefaultLogger + Message.setDefaultLogger(log) + try { f } finally { Message.setDefaultLogger(originalLogger) } + } /** * This returns sbt's UpdateReport structure. * missingOk allows sbt to call this with classifiers that may or may not exist, and grab the JARs. */ - def customResolve(md0: ModuleDescriptor, missingOk: Boolean, logicalClock: LogicalClock, options0: ResolveOptions, depDir: File, log: Logger): Either[ResolveException, UpdateReport] = - cachedResolutionResolveCache.getOrElseUpdateProjectReport(md0.getModuleRevisionId, logicalClock) { + def customResolve( + md0: ModuleDescriptor, + missingOk: Boolean, + logicalClock: LogicalClock, + options0: ResolveOptions, + depDir: File, + log: Logger + ): Either[ResolveException, UpdateReport] = + cachedResolutionResolveCache.getOrElseUpdateProjectReport( + md0.getModuleRevisionId, + logicalClock + ) { import sbt.io.syntax._ val start = System.currentTimeMillis val miniGraphPath = depDir / "module" - val cachedDescriptor = getSettings.getResolutionCacheManager.getResolvedIvyFileInCache(md0.getModuleRevisionId) + val cachedDescriptor = + getSettings.getResolutionCacheManager.getResolvedIvyFileInCache(md0.getModuleRevisionId) val cache = cachedResolutionResolveCache val os = cache.extractOverrides(md0) val options1 = new ResolveOptions(options0) val data = new ResolveData(this, options1) val mds = cache.buildArtificialModuleDescriptors(md0, data, projectResolver, log) - def doWork(md: ModuleDescriptor, dd: DependencyDescriptor): Either[ResolveException, UpdateReport] = + def doWork( + md: ModuleDescriptor, + dd: DependencyDescriptor + ): Either[ResolveException, UpdateReport] = cache.internalDependency(dd, projectResolver) match { case Some(md1) => log.debug(s":: call customResolve recursively: $dd") customResolve(md1, missingOk, logicalClock, options0, depDir, log) match { - case Right(ur) => Right(remapInternalProject(new IvyNode(data, md1), ur, md0, dd, os, log)) - case Left(e) => Left(e) + case Right(ur) => + Right(remapInternalProject(new IvyNode(data, md1), ur, md0, dd, os, log)) + case Left(e) => Left(e) } case None => log.debug(s":: call ivy resolution: $dd") doWorkUsingIvy(md) } - def doWorkUsingIvy(md: ModuleDescriptor): Either[ResolveException, UpdateReport] = - { - val options1 = new ResolveOptions(options0) - val rr = withIvy(log) { ivy => - ivy.resolve(md, options1) - } - if (!rr.hasError || missingOk) Right(IvyRetrieve.updateReport(rr, cachedDescriptor)) - else { - val messages = rr.getAllProblemMessages.toArray.map(_.toString).distinct - val failedPaths = ListMap(rr.getUnresolvedDependencies map { node => - val m = IvyRetrieve.toModuleID(node.getId) - val path = IvyRetrieve.findPath(node, md.getModuleRevisionId) map { x => - IvyRetrieve.toModuleID(x.getId) - } - log.debug("- Unresolved path " + path.toString) - m -> path - }: _*) - val failed = failedPaths.keys.toSeq - Left(new ResolveException(messages, failed, failedPaths)) - } + def doWorkUsingIvy(md: ModuleDescriptor): Either[ResolveException, UpdateReport] = { + val options1 = new ResolveOptions(options0) + val rr = withIvy(log) { ivy => + ivy.resolve(md, options1) } - val (internal, external) = mds.partition { case (_, _, dd) => cache.internalDependency(dd, projectResolver).isDefined } + if (!rr.hasError || missingOk) Right(IvyRetrieve.updateReport(rr, cachedDescriptor)) + else { + val messages = rr.getAllProblemMessages.toArray.map(_.toString).distinct + val failedPaths = ListMap(rr.getUnresolvedDependencies map { node => + val m = IvyRetrieve.toModuleID(node.getId) + val path = IvyRetrieve.findPath(node, md.getModuleRevisionId) map { x => + IvyRetrieve.toModuleID(x.getId) + } + log.debug("- Unresolved path " + path.toString) + m -> path + }: _*) + val failed = failedPaths.keys.toSeq + Left(new ResolveException(messages, failed, failedPaths)) + } + } + val (internal, external) = mds.partition { + case (_, _, dd) => cache.internalDependency(dd, projectResolver).isDefined + } val internalResults = internal map { case (md, changing, dd) => - cache.getOrElseUpdateMiniGraph(md, changing, logicalClock, miniGraphPath, cachedDescriptor, log) { + cache.getOrElseUpdateMiniGraph( + md, + changing, + logicalClock, + miniGraphPath, + cachedDescriptor, + log + ) { doWork(md, dd) } } val externalResults = external map { case (md0, changing, dd) => val configurationsInInternal = internalResults flatMap { - case Right(ur) => ur.allModules.flatMap { - case md => - val sameName = md.name == dd.getDependencyId.getName - val sameOrg = md.organization == dd.getDependencyId.getOrganisation - if (sameName && sameOrg) md.configurations - else None - } + case Right(ur) => + ur.allModules.flatMap { + case md => + val sameName = md.name == dd.getDependencyId.getName + val sameOrg = md.organization == dd.getDependencyId.getOrganisation + if (sameName && sameOrg) md.configurations + else None + } case _ => Nil } @@ -359,291 +440,388 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { case _ => () } - cache.getOrElseUpdateMiniGraph(md0, changing, logicalClock, miniGraphPath, cachedDescriptor, log) { + cache.getOrElseUpdateMiniGraph( + md0, + changing, + logicalClock, + miniGraphPath, + cachedDescriptor, + log + ) { doWork(md0, dd) } } val results = internalResults ++ externalResults - val uReport = mergeResults(md0, results, missingOk, System.currentTimeMillis - start, os, log) + val uReport = + mergeResults(md0, results, missingOk, System.currentTimeMillis - start, os, log) val cacheManager = getSettings.getResolutionCacheManager cacheManager.saveResolvedModuleDescriptor(md0) val prop0 = "" - val ivyPropertiesInCache0 = cacheManager.getResolvedIvyPropertiesInCache(md0.getResolvedModuleRevisionId) + val ivyPropertiesInCache0 = + cacheManager.getResolvedIvyPropertiesInCache(md0.getResolvedModuleRevisionId) IO.write(ivyPropertiesInCache0, prop0) uReport } - def mergeResults(md0: ModuleDescriptor, results: Vector[Either[ResolveException, UpdateReport]], missingOk: Boolean, resolveTime: Long, - os: Vector[IvyOverride], log: Logger): Either[ResolveException, UpdateReport] = - if (!missingOk && (results exists { _.isLeft })) Left(mergeErrors(md0, results collect { case Left(re) => re }, log)) + def mergeResults( + md0: ModuleDescriptor, + results: Vector[Either[ResolveException, UpdateReport]], + missingOk: Boolean, + resolveTime: Long, + os: Vector[IvyOverride], + log: Logger + ): Either[ResolveException, UpdateReport] = + if (!missingOk && (results exists { _.isLeft })) Left(mergeErrors(md0, results collect { + case Left(re) => re + }, log)) else Right(mergeReports(md0, results collect { case Right(ur) => ur }, resolveTime, os, log)) - def mergeErrors(md0: ModuleDescriptor, errors: Vector[ResolveException], log: Logger): ResolveException = - { - val messages = errors flatMap { _.messages } - val failed = errors flatMap { _.failed } - val failedPaths = errors flatMap { - _.failedPaths.toList map { - case (failed, paths) => - if (paths.isEmpty) (failed, paths) - else (failed, List(IvyRetrieve.toModuleID(md0.getResolvedModuleRevisionId)) ::: paths.toList.tail) - } + def mergeErrors( + md0: ModuleDescriptor, + errors: Vector[ResolveException], + log: Logger + ): ResolveException = { + val messages = errors flatMap { _.messages } + val failed = errors flatMap { _.failed } + val failedPaths = errors flatMap { + _.failedPaths.toList map { + case (failed, paths) => + if (paths.isEmpty) (failed, paths) + else + (failed, + List(IvyRetrieve.toModuleID(md0.getResolvedModuleRevisionId)) ::: paths.toList.tail) } - new ResolveException(messages, failed, ListMap(failedPaths: _*)) } - def mergeReports(md0: ModuleDescriptor, reports: Vector[UpdateReport], resolveTime: Long, os: Vector[IvyOverride], log: Logger): UpdateReport = - { - log.debug(s":: merging update reports") - val cachedDescriptor = getSettings.getResolutionCacheManager.getResolvedIvyFileInCache(md0.getModuleRevisionId) - val rootModuleConfigs = md0.getConfigurations.toVector - val cachedReports = reports filter { !_.stats.cached } - val stats = UpdateStats(resolveTime, (cachedReports map { _.stats.downloadTime }).sum, (cachedReports map { _.stats.downloadSize }).sum, false) - val configReports = rootModuleConfigs map { conf => - log.debug("::: -----------") - val crs = reports flatMap { _.configurations filter { _.configuration == conf.getName } } - mergeConfigurationReports(conf.getName, crs, os, log) - } - UpdateReport(cachedDescriptor, configReports, stats, Map.empty) + new ResolveException(messages, failed, ListMap(failedPaths: _*)) + } + def mergeReports( + md0: ModuleDescriptor, + reports: Vector[UpdateReport], + resolveTime: Long, + os: Vector[IvyOverride], + log: Logger + ): UpdateReport = { + log.debug(s":: merging update reports") + val cachedDescriptor = + getSettings.getResolutionCacheManager.getResolvedIvyFileInCache(md0.getModuleRevisionId) + val rootModuleConfigs = md0.getConfigurations.toVector + val cachedReports = reports filter { !_.stats.cached } + val stats = UpdateStats( + resolveTime, + (cachedReports map { _.stats.downloadTime }).sum, + (cachedReports map { _.stats.downloadSize }).sum, + false + ) + val configReports = rootModuleConfigs map { conf => + log.debug("::: -----------") + val crs = reports flatMap { _.configurations filter { _.configuration == conf.getName } } + mergeConfigurationReports(conf.getName, crs, os, log) } + UpdateReport(cachedDescriptor, configReports, stats, Map.empty) + } // memory usage 62%, of which 58% is in mergeOrganizationArtifactReports - def mergeConfigurationReports(rootModuleConf: String, reports: Vector[ConfigurationReport], os: Vector[IvyOverride], log: Logger): ConfigurationReport = - { - // get the details right, and the rest could be derived - val details = mergeOrganizationArtifactReports(rootModuleConf, reports flatMap { _.details }, os, log) - val modules = details flatMap { - _.modules filter { mr => - !mr.evicted && mr.problem.isEmpty - } + def mergeConfigurationReports( + rootModuleConf: String, + reports: Vector[ConfigurationReport], + os: Vector[IvyOverride], + log: Logger + ): ConfigurationReport = { + // get the details right, and the rest could be derived + val details = + mergeOrganizationArtifactReports(rootModuleConf, reports flatMap { _.details }, os, log) + val modules = details flatMap { + _.modules filter { mr => + !mr.evicted && mr.problem.isEmpty } - ConfigurationReport(rootModuleConf, modules, details) } + ConfigurationReport(rootModuleConf, modules, details) + } + /** * Returns a tuple of (merged org + name combo, newly evicted modules) */ - def mergeOrganizationArtifactReports(rootModuleConf: String, reports0: Vector[OrganizationArtifactReport], os: Vector[IvyOverride], log: Logger): Vector[OrganizationArtifactReport] = - { - // filter out evicted modules from further logic - def filterReports(report0: OrganizationArtifactReport): Option[OrganizationArtifactReport] = - report0.modules.toVector flatMap { mr => - if (mr.evicted || mr.problem.nonEmpty) None - else - // https://github.com/sbt/sbt/issues/1763 - Some(mr.withCallers(JsonUtil.filterOutArtificialCallers(mr.callers))) - } match { - case Vector() => None - case ms => Some(OrganizationArtifactReport(report0.organization, report0.name, ms)) - } + def mergeOrganizationArtifactReports( + rootModuleConf: String, + reports0: Vector[OrganizationArtifactReport], + os: Vector[IvyOverride], + log: Logger + ): Vector[OrganizationArtifactReport] = { + // filter out evicted modules from further logic + def filterReports(report0: OrganizationArtifactReport): Option[OrganizationArtifactReport] = + report0.modules.toVector flatMap { mr => + if (mr.evicted || mr.problem.nonEmpty) None + else + // https://github.com/sbt/sbt/issues/1763 + Some(mr.withCallers(JsonUtil.filterOutArtificialCallers(mr.callers))) + } match { + case Vector() => None + case ms => Some(OrganizationArtifactReport(report0.organization, report0.name, ms)) + } - // group by takes up too much memory. trading space with time. - val orgNamePairs: Vector[(String, String)] = (reports0 map { oar => (oar.organization, oar.name) }).distinct - // this might take up some memory, but it's limited to a single - val reports1 = reports0 flatMap { filterReports } - val allModules0: Map[(String, String), Vector[OrganizationArtifactReport]] = - Map(orgNamePairs map { - case (organization, name) => - val xs = reports1 filter { oar => oar.organization == organization && oar.name == name } - ((organization, name), xs) - }: _*) - // this returns a List of Lists of (org, name). should be deterministic - def detectLoops(allModules: Map[(String, String), Vector[OrganizationArtifactReport]]): List[List[(String, String)]] = - { - val loopSets: mutable.Set[Set[(String, String)]] = mutable.Set.empty - val loopLists: mutable.ListBuffer[List[(String, String)]] = mutable.ListBuffer.empty - def testLoop(m: (String, String), current: (String, String), history: List[(String, String)]): Unit = - { - val callers = + // group by takes up too much memory. trading space with time. + val orgNamePairs: Vector[(String, String)] = (reports0 map { oar => + (oar.organization, oar.name) + }).distinct + // this might take up some memory, but it's limited to a single + val reports1 = reports0 flatMap { filterReports } + val allModules0: Map[(String, String), Vector[OrganizationArtifactReport]] = + Map(orgNamePairs map { + case (organization, name) => + val xs = reports1 filter { oar => + oar.organization == organization && oar.name == name + } + ((organization, name), xs) + }: _*) + // this returns a List of Lists of (org, name). should be deterministic + def detectLoops(allModules: Map[(String, String), Vector[OrganizationArtifactReport]]) + : List[List[(String, String)]] = { + val loopSets: mutable.Set[Set[(String, String)]] = mutable.Set.empty + val loopLists: mutable.ListBuffer[List[(String, String)]] = mutable.ListBuffer.empty + def testLoop( + m: (String, String), + current: (String, String), + history: List[(String, String)] + ): Unit = { + val callers = + (for { + oar <- allModules.getOrElse(current, Vector()) + mr <- oar.modules + c <- mr.callers + } yield (c.caller.organization, c.caller.name)).distinct + callers foreach { c => + if (history contains c) { + val loop = (c :: history.takeWhile(_ != c)) ::: List(c) + if (!loopSets(loop.toSet)) { + loopSets += loop.toSet + loopLists += loop + val loopStr = (loop map { case (o, n) => s"$o:$n" }).mkString("->") + log.warn(s"""avoid circular dependency while using cached resolution: $loopStr""") + } + } else testLoop(m, c, c :: history) + } + } + orgNamePairs map { orgname => + testLoop(orgname, orgname, List(orgname)) + } + loopLists.toList + } + val allModules2: mutable.Map[(String, String), Vector[OrganizationArtifactReport]] = + mutable.Map(allModules0.toSeq: _*) + @tailrec def breakLoops(loops: List[List[(String, String)]]): Unit = + loops match { + case Nil => () + case loop :: rest => + loop match { + case Nil => + breakLoops(rest) + case loop => + val sortedLoop = loop sortBy { x => (for { - oar <- allModules.getOrElse(current, Vector()) + oar <- allModules0(x) mr <- oar.modules c <- mr.callers - } yield (c.caller.organization, c.caller.name)).distinct - callers foreach { c => - if (history contains c) { - val loop = (c :: history.takeWhile(_ != c)) ::: List(c) - if (!loopSets(loop.toSet)) { - loopSets += loop.toSet - loopLists += loop - val loopStr = (loop map { case (o, n) => s"$o:$n" }).mkString("->") - log.warn(s"""avoid circular dependency while using cached resolution: $loopStr""") - } - } else testLoop(m, c, c :: history) + } yield c).size } - } - orgNamePairs map { orgname => - testLoop(orgname, orgname, List(orgname)) - } - loopLists.toList - } - val allModules2: mutable.Map[(String, String), Vector[OrganizationArtifactReport]] = - mutable.Map(allModules0.toSeq: _*) - @tailrec def breakLoops(loops: List[List[(String, String)]]): Unit = - loops match { - case Nil => () - case loop :: rest => - loop match { - case Nil => - breakLoops(rest) - case loop => - val sortedLoop = loop sortBy { x => - (for { - oar <- allModules0(x) - mr <- oar.modules - c <- mr.callers - } yield c).size - } - val moduleWithMostCallers = sortedLoop.reverse.head - val next: (String, String) = loop(loop.indexOf(moduleWithMostCallers) + 1) - // remove the module with most callers as the caller of next. - // so, A -> C, B -> C, and C -> A. C has the most callers, and C -> A will be removed. - allModules2 foreach { - case (k: (String, String), oars0) if k == next => - val oars: Vector[OrganizationArtifactReport] = oars0 map { oar => - val mrs = oar.modules map { mr => - val callers0 = mr.callers - val callers = callers0 filterNot { c => (c.caller.organization, c.caller.name) == moduleWithMostCallers } - if (callers.size == callers0.size) mr - else { - log.debug(s":: $rootModuleConf: removing caller $moduleWithMostCallers -> $next for sorting") - mr.withCallers(callers) - } + val moduleWithMostCallers = sortedLoop.reverse.head + val next: (String, String) = loop(loop.indexOf(moduleWithMostCallers) + 1) + // remove the module with most callers as the caller of next. + // so, A -> C, B -> C, and C -> A. C has the most callers, and C -> A will be removed. + allModules2 foreach { + case (k: (String, String), oars0) if k == next => + val oars: Vector[OrganizationArtifactReport] = oars0 map { oar => + val mrs = oar.modules map { mr => + val callers0 = mr.callers + val callers = callers0 filterNot { c => + (c.caller.organization, c.caller.name) == moduleWithMostCallers + } + if (callers.size == callers0.size) mr + else { + log.debug( + s":: $rootModuleConf: removing caller $moduleWithMostCallers -> $next for sorting" + ) + mr.withCallers(callers) } - OrganizationArtifactReport(oar.organization, oar.name, mrs) } - allModules2(k) = oars - case (k, v) => // do nothing - } + OrganizationArtifactReport(oar.organization, oar.name, mrs) + } + allModules2(k) = oars + case (k, v) => // do nothing + } - breakLoops(rest) - } - } - val loop = detectLoops(allModules0) - log.debug(s":: $rootModuleConf: loop: $loop") - breakLoops(loop) + breakLoops(rest) + } + } + val loop = detectLoops(allModules0) + log.debug(s":: $rootModuleConf: loop: $loop") + breakLoops(loop) - // sort the all modules such that less called modules comes earlier - @tailrec def sortModules( + // sort the all modules such that less called modules comes earlier + @tailrec + def sortModules( cs: Vector[(String, String)], - acc: Vector[(String, String)], extra: Vector[(String, String)], - n: Int, guard: Int - ): Vector[(String, String)] = - { - // println(s"sortModules: $n / $guard") - val keys = cs.toSet - val (called, notCalled) = cs partition { k => - val reports = allModules2(k) - reports exists { - _.modules.exists { - _.callers exists { caller => - val m = caller.caller - keys((m.organization, m.name)) - } - } + acc: Vector[(String, String)], + extra: Vector[(String, String)], + n: Int, + guard: Int + ): Vector[(String, String)] = { + // println(s"sortModules: $n / $guard") + val keys = cs.toSet + val (called, notCalled) = cs partition { k => + val reports = allModules2(k) + reports exists { + _.modules.exists { + _.callers exists { caller => + val m = caller.caller + keys((m.organization, m.name)) } } - lazy val result0 = acc ++ notCalled ++ called ++ extra - def warnCircular(): Unit = { - log.warn(s"""unexpected circular dependency while using cached resolution: ${cs.mkString(",")}""") - } - (if (n > guard) { - warnCircular - result0 - } else if (called.isEmpty) result0 - else if (notCalled.isEmpty) { - warnCircular - sortModules(cs.tail, acc, extra :+ cs.head, n + 1, guard) - } else sortModules(called, acc ++ notCalled, extra, 0, called.size * called.size + 1)) } - def resolveConflicts( + } + lazy val result0 = acc ++ notCalled ++ called ++ extra + def warnCircular(): Unit = { + log.warn( + s"""unexpected circular dependency while using cached resolution: ${cs.mkString(",")}""" + ) + } + (if (n > guard) { + warnCircular + result0 + } else if (called.isEmpty) result0 + else if (notCalled.isEmpty) { + warnCircular + sortModules(cs.tail, acc, extra :+ cs.head, n + 1, guard) + } else sortModules(called, acc ++ notCalled, extra, 0, called.size * called.size + 1)) + } + def resolveConflicts( cs: List[(String, String)], allModules: Map[(String, String), Vector[OrganizationArtifactReport]] - ): List[OrganizationArtifactReport] = - cs match { - case Nil => Nil - case (organization, name) :: rest => - val reports = allModules((organization, name)) - reports match { - case Vector() => resolveConflicts(rest, allModules) - case Vector(oa) if (oa.modules.isEmpty) => resolveConflicts(rest, allModules) - case Vector(oa) if (oa.modules.size == 1 && !oa.modules.head.evicted) => - log.debug(s":: no conflict $rootModuleConf: ${oa.organization}:${oa.name}") - oa :: resolveConflicts(rest, allModules) - case oas => - (mergeModuleReports(rootModuleConf, oas flatMap { _.modules }, os, log) match { - case (survivor, newlyEvicted) => - val evicted = (survivor ++ newlyEvicted) filter { m => m.evicted } - val notEvicted = (survivor ++ newlyEvicted) filter { m => !m.evicted } - log.debug("::: adds " + (notEvicted map { _.module }).mkString(", ")) - log.debug("::: evicted " + (evicted map { _.module }).mkString(", ")) - val x = OrganizationArtifactReport(organization, name, survivor ++ newlyEvicted) - val nextModules = transitivelyEvict(rootModuleConf, rest, allModules, evicted, log) - x :: resolveConflicts(rest, nextModules) - }) - } - } - val guard0 = (orgNamePairs.size * orgNamePairs.size) + 1 - val sorted: Vector[(String, String)] = sortModules(orgNamePairs, Vector(), Vector(), 0, guard0) - val sortedStr = (sorted map { case (o, n) => s"$o:$n" }).mkString(", ") - log.debug(s":: sort result: $sortedStr") - val result = resolveConflicts(sorted.toList, allModules0) - result.toVector - } + ): List[OrganizationArtifactReport] = + cs match { + case Nil => Nil + case (organization, name) :: rest => + val reports = allModules((organization, name)) + reports match { + case Vector() => resolveConflicts(rest, allModules) + case Vector(oa) if (oa.modules.isEmpty) => resolveConflicts(rest, allModules) + case Vector(oa) if (oa.modules.size == 1 && !oa.modules.head.evicted) => + log.debug(s":: no conflict $rootModuleConf: ${oa.organization}:${oa.name}") + oa :: resolveConflicts(rest, allModules) + case oas => + (mergeModuleReports(rootModuleConf, oas flatMap { _.modules }, os, log) match { + case (survivor, newlyEvicted) => + val evicted = (survivor ++ newlyEvicted) filter { m => + m.evicted + } + val notEvicted = (survivor ++ newlyEvicted) filter { m => + !m.evicted + } + log.debug("::: adds " + (notEvicted map { _.module }).mkString(", ")) + log.debug("::: evicted " + (evicted map { _.module }).mkString(", ")) + val x = OrganizationArtifactReport(organization, name, survivor ++ newlyEvicted) + val nextModules = + transitivelyEvict(rootModuleConf, rest, allModules, evicted, log) + x :: resolveConflicts(rest, nextModules) + }) + } + } + val guard0 = (orgNamePairs.size * orgNamePairs.size) + 1 + val sorted: Vector[(String, String)] = sortModules(orgNamePairs, Vector(), Vector(), 0, guard0) + val sortedStr = (sorted map { case (o, n) => s"$o:$n" }).mkString(", ") + log.debug(s":: sort result: $sortedStr") + val result = resolveConflicts(sorted.toList, allModules0) + result.toVector + } + /** * Merges ModuleReports, which represents orgnization, name, and version. * Returns a touple of (surviving modules ++ non-conflicting modules, newly evicted modules). */ - def mergeModuleReports(rootModuleConf: String, modules: Vector[ModuleReport], os: Vector[IvyOverride], log: Logger): (Vector[ModuleReport], Vector[ModuleReport]) = - { - if (modules.nonEmpty) { - log.debug(s":: merging module reports for $rootModuleConf: ${modules.head.module.organization}:${modules.head.module.name}") - } - def mergeModuleReports(org: String, name: String, version: String, xs: Vector[ModuleReport]): ModuleReport = { - val completelyEvicted = xs forall { _.evicted } - val allCallers = xs flatMap { _.callers } - // Caller info is often repeated across the subprojects. We only need ModuleID info for later, so xs.head is ok. - val distinctByModuleId = allCallers.groupBy({ _.caller }).toVector map { case (k, xs) => xs.head } - val allArtifacts = (xs flatMap { _.artifacts }).distinct - xs.head.withArtifacts(allArtifacts).withEvicted(completelyEvicted).withCallers(distinctByModuleId) - } - val merged = (modules groupBy { m => (m.module.organization, m.module.name, m.module.revision) }).toSeq.toVector flatMap { - case ((org, name, version), xs) => - if (xs.size < 2) xs - else Vector(mergeModuleReports(org, name, version, xs)) + def mergeModuleReports( + rootModuleConf: String, + modules: Vector[ModuleReport], + os: Vector[IvyOverride], + log: Logger + ): (Vector[ModuleReport], Vector[ModuleReport]) = { + if (modules.nonEmpty) { + log.debug( + s":: merging module reports for $rootModuleConf: ${modules.head.module.organization}:${modules.head.module.name}" + ) + } + def mergeModuleReports( + org: String, + name: String, + version: String, + xs: Vector[ModuleReport] + ): ModuleReport = { + val completelyEvicted = xs forall { _.evicted } + val allCallers = xs flatMap { _.callers } + // Caller info is often repeated across the subprojects. We only need ModuleID info for later, so xs.head is ok. + val distinctByModuleId = allCallers.groupBy({ _.caller }).toVector map { + case (k, xs) => xs.head } - val conflicts = merged filter { m => !m.evicted && m.problem.isEmpty } - if (conflicts.size < 2) (merged, Vector()) - else resolveConflict(rootModuleConf, conflicts, os, log) match { + val allArtifacts = (xs flatMap { _.artifacts }).distinct + xs.head + .withArtifacts(allArtifacts) + .withEvicted(completelyEvicted) + .withCallers(distinctByModuleId) + } + val merged = (modules groupBy { m => + (m.module.organization, m.module.name, m.module.revision) + }).toSeq.toVector flatMap { + case ((org, name, version), xs) => + if (xs.size < 2) xs + else Vector(mergeModuleReports(org, name, version, xs)) + } + val conflicts = merged filter { m => + !m.evicted && m.problem.isEmpty + } + if (conflicts.size < 2) (merged, Vector()) + else + resolveConflict(rootModuleConf, conflicts, os, log) match { case (survivor, evicted) => - (survivor ++ (merged filter { m => m.evicted || m.problem.isDefined }), evicted) + (survivor ++ (merged filter { m => + m.evicted || m.problem.isDefined + }), evicted) } - } + } + /** * This transitively evicts any non-evicted modules whose only callers are newly evicted. */ - def transitivelyEvict(rootModuleConf: String, pairs: List[(String, String)], - reports0: Map[(String, String), Vector[OrganizationArtifactReport]], - evicted0: Vector[ModuleReport], log: Logger): Map[(String, String), Vector[OrganizationArtifactReport]] = - { - val em = (evicted0 map { _.module }).toSet - def isTransitivelyEvicted(mr: ModuleReport): Boolean = - mr.callers forall { c => em(c.caller) } - val reports: Seq[((String, String), Vector[OrganizationArtifactReport])] = reports0.toSeq flatMap { - case (k, v) if !(pairs contains k) => Seq() - case ((organization, name), oars0) => - val oars = oars0 map { oar => - val (affected, unaffected) = oar.modules partition { mr => - val x = !mr.evicted && mr.problem.isEmpty && isTransitivelyEvicted(mr) - if (x) { - log.debug(s""":::: transitively evicted $rootModuleConf: ${mr.module}""") - } - x + def transitivelyEvict( + rootModuleConf: String, + pairs: List[(String, String)], + reports0: Map[(String, String), Vector[OrganizationArtifactReport]], + evicted0: Vector[ModuleReport], + log: Logger + ): Map[(String, String), Vector[OrganizationArtifactReport]] = { + val em = (evicted0 map { _.module }).toSet + def isTransitivelyEvicted(mr: ModuleReport): Boolean = + mr.callers forall { c => + em(c.caller) + } + val reports + : Seq[((String, String), Vector[OrganizationArtifactReport])] = reports0.toSeq flatMap { + case (k, v) if !(pairs contains k) => Seq() + case ((organization, name), oars0) => + val oars = oars0 map { oar => + val (affected, unaffected) = oar.modules partition { mr => + val x = !mr.evicted && mr.problem.isEmpty && isTransitivelyEvicted(mr) + if (x) { + log.debug(s""":::: transitively evicted $rootModuleConf: ${mr.module}""") } - val newlyEvicted = affected map { _.withEvicted(true).withEvictedReason(Some("transitive-evict")) } - if (affected.isEmpty) oar - else OrganizationArtifactReport(organization, name, unaffected ++ newlyEvicted) + x } - Seq(((organization, name), oars)) - } - Map(reports: _*) + val newlyEvicted = affected map { + _.withEvicted(true).withEvictedReason(Some("transitive-evict")) + } + if (affected.isEmpty) oar + else OrganizationArtifactReport(organization, name, unaffected ++ newlyEvicted) + } + Seq(((organization, name), oars)) } + Map(reports: _*) + } + /** * resolves dependency resolution conflicts in which multiple candidates are found for organization+name combos. * The main input is conflicts, which is a Vector of ModuleReport, which contains full info on the modulerevision, including its callers. @@ -655,116 +833,162 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine { * Note transitively forced dependencies are not respected. This seems to be the case for stock Ivy's behavior as well, * which may be because Ivy makes all Maven dependencies as forced="true". */ - def resolveConflict(rootModuleConf: String, conflicts: Vector[ModuleReport], os: Vector[IvyOverride], log: Logger): (Vector[ModuleReport], Vector[ModuleReport]) = - { - import org.apache.ivy.plugins.conflict.{ NoConflictManager, StrictConflictManager, LatestConflictManager } - val head = conflicts.head - val organization = head.module.organization - val name = head.module.name - log.debug(s"::: resolving conflict in $rootModuleConf:$organization:$name " + (conflicts map { _.module }).mkString("(", ", ", ")")) - def useLatest(lcm: LatestConflictManager): (Vector[ModuleReport], Vector[ModuleReport], String) = - (conflicts find { m => - m.callers.exists { _.isDirectlyForceDependency } - }) match { - case Some(m) => - log.debug(s"- directly forced dependency: $m ${m.callers}") - (Vector(m), conflicts filterNot { _ == m } map { _.withEvicted(true).withEvictedReason(Some("direct-force")) }, "direct-force") - case None => - (conflicts find { m => - m.callers.exists { _.isForceDependency } - }) match { - // Ivy translates pom.xml dependencies to forced="true", so transitive force is broken. - case Some(m) if !ignoreTransitiveForce => - log.debug(s"- transitively forced dependency: $m ${m.callers}") - (Vector(m), conflicts filterNot { _ == m } map { _.withEvicted(true).withEvictedReason(Some("transitive-force")) }, "transitive-force") - case _ => - val strategy = lcm.getStrategy - val infos = conflicts map { ModuleReportArtifactInfo(_) } - log.debug(s"- Using $strategy with $infos") - Option(strategy.findLatest(infos.toArray, None.orNull)) match { - case Some(ModuleReportArtifactInfo(m)) => - (Vector(m), conflicts filterNot { _ == m } map { _.withEvicted(true).withEvictedReason(Some(lcm.toString)) }, lcm.toString) - case _ => (conflicts, Vector(), lcm.toString) - } - } - } - def doResolveConflict: (Vector[ModuleReport], Vector[ModuleReport], String) = - os find { ovr => ovr.moduleId.getOrganisation == organization && ovr.moduleId.getName == name } match { - case Some(ovr) if Option(ovr.ddm.getVersion).isDefined => - val ovrVersion = ovr.ddm.getVersion - conflicts find { mr => - mr.module.revision == ovrVersion - } match { - case Some(m) => - (Vector(m), conflicts filterNot { _ == m } map { _.withEvicted(true).withEvictedReason(Some("override")) }, "override") - case None => - sys.error(s"override dependency specifies $ovrVersion but no candidates were found: " + (conflicts map { _.module }).mkString("(", ", ", ")")) - } - case None => - getSettings.getConflictManager(IvyModuleId.newInstance(organization, name)) match { - case ncm: NoConflictManager => (conflicts, Vector(), ncm.toString) - case _: StrictConflictManager => sys.error((s"conflict was found in $rootModuleConf:$organization:$name " + (conflicts map { _.module }).mkString("(", ", ", ")"))) - case lcm: LatestConflictManager => useLatest(lcm) - case conflictManager => sys.error(s"Unsupported conflict manager $conflictManager") - } - } - if (conflicts.size == 2 && os.isEmpty) { - val (cf0, cf1) = (conflicts(0).module, conflicts(1).module) - val cache = cachedResolutionResolveCache - val (surviving, evicted) = cache.getOrElseUpdateConflict(cf0, cf1, conflicts) { doResolveConflict } - (surviving, evicted) - } else { - val (surviving, evicted, _) = doResolveConflict - (surviving, evicted) - } + def resolveConflict( + rootModuleConf: String, + conflicts: Vector[ModuleReport], + os: Vector[IvyOverride], + log: Logger + ): (Vector[ModuleReport], Vector[ModuleReport]) = { + import org.apache.ivy.plugins.conflict.{ + NoConflictManager, + StrictConflictManager, + LatestConflictManager } - def remapInternalProject(node: IvyNode, ur: UpdateReport, - md0: ModuleDescriptor, dd: DependencyDescriptor, - os: Vector[IvyOverride], log: Logger): UpdateReport = - { - def parentConfigs(c: String): Vector[String] = - Option(md0.getConfiguration(c)) match { - case Some(config) => - config.getExtends.toVector ++ - (config.getExtends.toVector flatMap parentConfigs) - case None => Vector() - } - // These are the configurations from the original project we want to resolve. - val rootModuleConfs = md0.getConfigurations.toVector - val configurations0 = ur.configurations.toVector - // This is how md looks from md0 via dd's mapping. - val remappedConfigs0: Map[String, Vector[String]] = Map(rootModuleConfs map { conf0 => - val remapped: Vector[String] = dd.getDependencyConfigurations(conf0.getName).toVector flatMap { conf => - node.getRealConfs(conf).toVector - } - conf0.getName -> remapped - }: _*) - // This emulates test-internal extending test configuration etc. - val remappedConfigs: Map[String, Vector[String]] = - (remappedConfigs0 /: rootModuleConfs) { (acc0, c) => - val ps = parentConfigs(c.getName) - (acc0 /: ps) { (acc, parent) => - val vs0 = acc.getOrElse(c.getName, Vector()) - val vs = acc.getOrElse(parent, Vector()) - acc.updated(c.getName, (vs0 ++ vs).distinct) + val head = conflicts.head + val organization = head.module.organization + val name = head.module.name + log.debug(s"::: resolving conflict in $rootModuleConf:$organization:$name " + (conflicts map { + _.module + }).mkString("(", ", ", ")")) + def useLatest( + lcm: LatestConflictManager + ): (Vector[ModuleReport], Vector[ModuleReport], String) = + (conflicts find { m => + m.callers.exists { _.isDirectlyForceDependency } + }) match { + case Some(m) => + log.debug(s"- directly forced dependency: $m ${m.callers}") + (Vector(m), conflicts filterNot { _ == m } map { + _.withEvicted(true).withEvictedReason(Some("direct-force")) + }, "direct-force") + case None => + (conflicts find { m => + m.callers.exists { _.isForceDependency } + }) match { + // Ivy translates pom.xml dependencies to forced="true", so transitive force is broken. + case Some(m) if !ignoreTransitiveForce => + log.debug(s"- transitively forced dependency: $m ${m.callers}") + (Vector(m), conflicts filterNot { _ == m } map { + _.withEvicted(true).withEvictedReason(Some("transitive-force")) + }, "transitive-force") + case _ => + val strategy = lcm.getStrategy + val infos = conflicts map { ModuleReportArtifactInfo(_) } + log.debug(s"- Using $strategy with $infos") + Option(strategy.findLatest(infos.toArray, None.orNull)) match { + case Some(ModuleReportArtifactInfo(m)) => + (Vector(m), conflicts filterNot { _ == m } map { + _.withEvicted(true).withEvictedReason(Some(lcm.toString)) + }, lcm.toString) + case _ => (conflicts, Vector(), lcm.toString) + } } + } + def doResolveConflict: (Vector[ModuleReport], Vector[ModuleReport], String) = + os find { ovr => + ovr.moduleId.getOrganisation == organization && ovr.moduleId.getName == name + } match { + case Some(ovr) if Option(ovr.ddm.getVersion).isDefined => + val ovrVersion = ovr.ddm.getVersion + conflicts find { mr => + mr.module.revision == ovrVersion + } match { + case Some(m) => + (Vector(m), conflicts filterNot { _ == m } map { + _.withEvicted(true).withEvictedReason(Some("override")) + }, "override") + case None => + sys.error( + s"override dependency specifies $ovrVersion but no candidates were found: " + (conflicts map { + _.module + }).mkString("(", ", ", ")") + ) + } + case None => + getSettings.getConflictManager(IvyModuleId.newInstance(organization, name)) match { + case ncm: NoConflictManager => (conflicts, Vector(), ncm.toString) + case _: StrictConflictManager => + sys.error( + (s"conflict was found in $rootModuleConf:$organization:$name " + (conflicts map { + _.module + }).mkString("(", ", ", ")")) + ) + case lcm: LatestConflictManager => useLatest(lcm) + case conflictManager => sys.error(s"Unsupported conflict manager $conflictManager") + } + } + if (conflicts.size == 2 && os.isEmpty) { + val (cf0, cf1) = (conflicts(0).module, conflicts(1).module) + val cache = cachedResolutionResolveCache + val (surviving, evicted) = cache.getOrElseUpdateConflict(cf0, cf1, conflicts) { + doResolveConflict + } + (surviving, evicted) + } else { + val (surviving, evicted, _) = doResolveConflict + (surviving, evicted) + } + } + def remapInternalProject( + node: IvyNode, + ur: UpdateReport, + md0: ModuleDescriptor, + dd: DependencyDescriptor, + os: Vector[IvyOverride], + log: Logger + ): UpdateReport = { + def parentConfigs(c: String): Vector[String] = + Option(md0.getConfiguration(c)) match { + case Some(config) => + config.getExtends.toVector ++ + (config.getExtends.toVector flatMap parentConfigs) + case None => Vector() + } + // These are the configurations from the original project we want to resolve. + val rootModuleConfs = md0.getConfigurations.toVector + val configurations0 = ur.configurations.toVector + // This is how md looks from md0 via dd's mapping. + val remappedConfigs0: Map[String, Vector[String]] = Map(rootModuleConfs map { conf0 => + val remapped + : Vector[String] = dd.getDependencyConfigurations(conf0.getName).toVector flatMap { conf => + node.getRealConfs(conf).toVector + } + conf0.getName -> remapped + }: _*) + // This emulates test-internal extending test configuration etc. + val remappedConfigs: Map[String, Vector[String]] = + (remappedConfigs0 /: rootModuleConfs) { (acc0, c) => + val ps = parentConfigs(c.getName) + (acc0 /: ps) { (acc, parent) => + val vs0 = acc.getOrElse(c.getName, Vector()) + val vs = acc.getOrElse(parent, Vector()) + acc.updated(c.getName, (vs0 ++ vs).distinct) } - log.debug(s"::: remapped configs $remappedConfigs") - val configurations = rootModuleConfs map { conf0 => - val remappedCRs = configurations0 filter { cr => - remappedConfigs(conf0.getName) contains cr.configuration - } - mergeConfigurationReports(conf0.getName, remappedCRs, os, log) } - UpdateReport(ur.cachedDescriptor, configurations, ur.stats, ur.stamps) + log.debug(s"::: remapped configs $remappedConfigs") + val configurations = rootModuleConfs map { conf0 => + val remappedCRs = configurations0 filter { cr => + remappedConfigs(conf0.getName) contains cr.configuration + } + mergeConfigurationReports(conf0.getName, remappedCRs, os, log) } + UpdateReport(ur.cachedDescriptor, configurations, ur.stats, ur.stamps) + } } -private[sbt] case class ModuleReportArtifactInfo(moduleReport: ModuleReport) extends IvyArtifactInfo { - override def getLastModified: Long = moduleReport.publicationDate map { _.getTimeInMillis } getOrElse 0L +private[sbt] case class ModuleReportArtifactInfo(moduleReport: ModuleReport) + extends IvyArtifactInfo { + override def getLastModified: Long = + moduleReport.publicationDate map { _.getTimeInMillis } getOrElse 0L override def getRevision: String = moduleReport.module.revision - override def toString: String = s"ModuleReportArtifactInfo(${moduleReport.module}, $getRevision, $getLastModified)" + override def toString: String = + s"ModuleReportArtifactInfo(${moduleReport.module}, $getRevision, $getLastModified)" } -private[sbt] case class IvyOverride(moduleId: IvyModuleId, pm: PatternMatcher, ddm: OverrideDependencyDescriptorMediator) { - override def toString: String = s"""IvyOverride($moduleId,$pm,${ddm.getVersion},${ddm.getBranch})""" +private[sbt] case class IvyOverride( + moduleId: IvyModuleId, + pm: PatternMatcher, + ddm: OverrideDependencyDescriptorMediator +) { + override def toString: String = + s"""IvyOverride($moduleId,$pm,${ddm.getVersion},${ddm.getBranch})""" } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/CustomMavenResolver.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/CustomMavenResolver.scala index 3fc19aed..788b8f1e 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/CustomMavenResolver.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/CustomMavenResolver.scala @@ -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 } diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala index 48cb3bb8..9a19ac6c 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/ErrorMessageAuthenticator.scala @@ -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 diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/IvyCredentialsLookup.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/IvyCredentialsLookup.scala index 88a23791..e2e11912 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/IvyCredentialsLookup.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/IvyCredentialsLookup.scala @@ -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) } -} \ No newline at end of file +} diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/MergeDescriptors.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/MergeDescriptors.scala index 1f9cfa15..5f361ea5 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/MergeDescriptors.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/MergeDescriptors.scala @@ -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 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 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 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 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 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 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 diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/SbtChainResolver.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/SbtChainResolver.scala index afc5bda1..0c7f2c62 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/SbtChainResolver.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/ivyint/SbtChainResolver.scala @@ -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) diff --git a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/mavenint/PomExtraDependencyAttributes.scala b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/mavenint/PomExtraDependencyAttributes.scala index 8ae8b8ef..c198f046 100644 --- a/librarymanagement/src/main/scala/sbt/internal/librarymanagement/mavenint/PomExtraDependencyAttributes.scala +++ b/librarymanagement/src/main/scala/sbt/internal/librarymanagement/mavenint/PomExtraDependencyAttributes.scala @@ -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 element // with the extra attributes from the 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 */ diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/ArtifactExtra.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/ArtifactExtra.scala index fe662ca7..989ef8ce 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/ArtifactExtra.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/ArtifactExtra.scala @@ -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, `type`: String, extension: String, classifier: Option[String], configurations: Vector[Configuration], url: Option[URL]): Artifact = + 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 = 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 + ) } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/CircularDependencyLevel.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/CircularDependencyLevel.scala index 0fc32c01..4f1b5320 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/CircularDependencyLevel.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/CircularDependencyLevel.scala @@ -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. diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/ConfigurationExtra.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/ConfigurationExtra.scala index 8e30e5c6..9795ff70 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/ConfigurationExtra.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/ConfigurationExtra.scala @@ -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) diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/ConflictWarning.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/ConflictWarning.scala index 98d9fe46..02355408 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/ConflictWarning.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/ConflictWarning.scala @@ -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]] = diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/Credentials.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/Credentials.scala index 55dffa36..4044dfd3 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/Credentials.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/Credentials.scala @@ -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 diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala index e4d172b7..7e90f8c5 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/CrossVersionExtra.scala @@ -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) } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/DefaultLibraryManagement.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/DefaultLibraryManagement.scala index 4dddcab7..43bf8b23 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/DefaultLibraryManagement.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/DefaultLibraryManagement.scala @@ -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 diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/DependencyFilter.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/DependencyFilter.scala index 644e4357..27900061 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/DependencyFilter.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/DependencyFilter.scala @@ -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) } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/EvictionWarning.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/EvictionWarning.scala index 853efa33..eff181a2 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/EvictionWarning.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/EvictionWarning.scala @@ -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 => diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/IvyInterface.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/IvyInterface.scala index 7f7e1dc9..82ddace8 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/IvyInterface.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/IvyInterface.scala @@ -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) + } } } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/IvyScalaExtra.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/IvyScalaExtra.scala index 5a630043..9d18c9da 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/IvyScalaExtra.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/IvyScalaExtra.scala @@ -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 + } } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala index 572fd194..7fbb5f34 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/ModuleIDExtra.scala @@ -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) } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/ResolverExtra.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/ResolverExtra.scala index b772e084..077c3ae1 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/ResolverExtra.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/ResolverExtra.scala @@ -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) - - 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) + 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 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) + } } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/RichUpdateReport.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/RichUpdateReport.scala index 1d6e6c47..6d7e1c58 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/RichUpdateReport.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/RichUpdateReport.scala @@ -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) + } } diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/UpdateOptions.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/UpdateOptions.scala index 626d3137..0ebcee17 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/UpdateOptions.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/UpdateOptions.scala @@ -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 { diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/UpdateReportExtra.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/UpdateReportExtra.scala index 594588b4..7f2c39fa 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/UpdateReportExtra.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/UpdateReportExtra.scala @@ -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) diff --git a/librarymanagement/src/main/scala/sbt/librarymanagement/VersionNumber.scala b/librarymanagement/src/main/scala/sbt/librarymanagement/VersionNumber.scala index 674ffc36..2f82a361 100644 --- a/librarymanagement/src/main/scala/sbt/librarymanagement/VersionNumber.scala +++ b/librarymanagement/src/main/scala/sbt/librarymanagement/VersionNumber.scala @@ -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) } diff --git a/librarymanagement/src/test/scala/BaseIvySpecification.scala b/librarymanagement/src/test/scala/BaseIvySpecification.scala index 1400db7a..50a7f1f9 100644 --- a/librarymanagement/src/test/scala/BaseIvySpecification.scala +++ b/librarymanagement/src/test/scala/BaseIvySpecification.scala @@ -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, diff --git a/librarymanagement/src/test/scala/CachedResolutionSpec.scala b/librarymanagement/src/test/scala/CachedResolutionSpec.scala index 066286f4..f00787fd 100644 --- a/librarymanagement/src/test/scala/CachedResolutionSpec.scala +++ b/librarymanagement/src/test/scala/CachedResolutionSpec.scala @@ -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 } diff --git a/librarymanagement/src/test/scala/ComponentManagerTest.scala b/librarymanagement/src/test/scala/ComponentManagerTest.scala index ff429aee..4cc45275 100644 --- a/librarymanagement/src/test/scala/ComponentManagerTest.scala +++ b/librarymanagement/src/test/scala/ComponentManagerTest.scala @@ -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 { diff --git a/librarymanagement/src/test/scala/CrossVersionTest.scala b/librarymanagement/src/test/scala/CrossVersionTest.scala index fb4dfacf..d6e245dc 100644 --- a/librarymanagement/src/test/scala/CrossVersionTest.scala +++ b/librarymanagement/src/test/scala/CrossVersionTest.scala @@ -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() diff --git a/librarymanagement/src/test/scala/CustomPomParserTest.scala b/librarymanagement/src/test/scala/CustomPomParserTest.scala index e4077132..ea011359 100644 --- a/librarymanagement/src/test/scala/CustomPomParserTest.scala +++ b/librarymanagement/src/test/scala/CustomPomParserTest.scala @@ -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" } diff --git a/librarymanagement/src/test/scala/DMSerializationSpec.scala b/librarymanagement/src/test/scala/DMSerializationSpec.scala index 5c6a89db..3fb9ae8e 100644 --- a/librarymanagement/src/test/scala/DMSerializationSpec.scala +++ b/librarymanagement/src/test/scala/DMSerializationSpec.scala @@ -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) } diff --git a/librarymanagement/src/test/scala/EvictionWarningSpec.scala b/librarymanagement/src/test/scala/EvictionWarningSpec.scala index ce834ac7..8daf2277 100644 --- a/librarymanagement/src/test/scala/EvictionWarningSpec.scala +++ b/librarymanagement/src/test/scala/EvictionWarningSpec.scala @@ -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:", diff --git a/librarymanagement/src/test/scala/InconsistentDuplicateSpec.scala b/librarymanagement/src/test/scala/InconsistentDuplicateSpec.scala index 4e0866d6..8ba69022 100644 --- a/librarymanagement/src/test/scala/InconsistentDuplicateSpec.scala +++ b/librarymanagement/src/test/scala/InconsistentDuplicateSpec.scala @@ -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 } diff --git a/librarymanagement/src/test/scala/MakePomSpec.scala b/librarymanagement/src/test/scala/MakePomSpec.scala index fb2c5500..eb9c353c 100644 --- a/librarymanagement/src/test/scala/MakePomSpec.scala +++ b/librarymanagement/src/test/scala/MakePomSpec.scala @@ -75,4 +75,3 @@ class MakePomSpec extends UnitSpec { () } } - diff --git a/librarymanagement/src/test/scala/MergeDescriptorSpec.scala b/librarymanagement/src/test/scala/MergeDescriptorSpec.scala index 65749a28..dddeadfd 100644 --- a/librarymanagement/src/test/scala/MergeDescriptorSpec.scala +++ b/librarymanagement/src/test/scala/MergeDescriptorSpec.scala @@ -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 } diff --git a/librarymanagement/src/test/scala/ResolverTest.scala b/librarymanagement/src/test/scala/ResolverTest.scala index d2090c50..2682797f 100644 --- a/librarymanagement/src/test/scala/ResolverTest.scala +++ b/librarymanagement/src/test/scala/ResolverTest.scala @@ -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 diff --git a/librarymanagement/src/test/scala/ScalaOverrideTest.scala b/librarymanagement/src/test/scala/ScalaOverrideTest.scala index f14a2d6c..2417db78 100644 --- a/librarymanagement/src/test/scala/ScalaOverrideTest.scala +++ b/librarymanagement/src/test/scala/ScalaOverrideTest.scala @@ -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") - - 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") + """ 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 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") } diff --git a/librarymanagement/src/test/scala/VersionNumberSpec.scala b/librarymanagement/src/test/scala/VersionNumberSpec.scala index 5e59cada..66fd96f6 100644 --- a/librarymanagement/src/test/scala/VersionNumberSpec.scala +++ b/librarymanagement/src/test/scala/VersionNumberSpec.scala @@ -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) diff --git a/librarymanagement/src/test/scala/sbt/internal/librarymanagement/FakeResolverSpecification.scala b/librarymanagement/src/test/scala/sbt/internal/librarymanagement/FakeResolverSpecification.scala index 27936225..07962f60 100644 --- a/librarymanagement/src/test/scala/sbt/internal/librarymanagement/FakeResolverSpecification.scala +++ b/librarymanagement/src/test/scala/sbt/internal/librarymanagement/FakeResolverSpecification.scala @@ -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 diff --git a/librarymanagement/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala b/librarymanagement/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala index b6238b3d..61c9aa27 100644 --- a/librarymanagement/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala +++ b/librarymanagement/src/test/scala/sbt/internal/librarymanagement/IvyRepoSpec.scala @@ -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 report2 = IvyActions.updateClassifiers(m.owner, gcm, UnresolvedWarningConfiguration(), LogicalClock.unknown, None, Vector(), log) + 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) import Inside._ inside(report2.configuration("compile").map(_.modules)) { diff --git a/librarymanagement/src/test/scala/sbt/internal/librarymanagement/RepositoriesParserSpecification.scala b/librarymanagement/src/test/scala/sbt/internal/librarymanagement/RepositoriesParserSpecification.scala index 707bbcff..0aec79d3 100644 --- a/librarymanagement/src/test/scala/sbt/internal/librarymanagement/RepositoriesParserSpecification.scala +++ b/librarymanagement/src/test/scala/sbt/internal/librarymanagement/RepositoriesParserSpecification.scala @@ -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) diff --git a/librarymanagement/src/test/scala/sbt/internal/librarymanagement/TestLogger.scala b/librarymanagement/src/test/scala/sbt/internal/librarymanagement/TestLogger.scala index 4dace213..e3cd17d3 100644 --- a/librarymanagement/src/test/scala/sbt/internal/librarymanagement/TestLogger.scala +++ b/librarymanagement/src/test/scala/sbt/internal/librarymanagement/TestLogger.scala @@ -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)) + } } diff --git a/project/AutomateScalafmtPlugin.scala b/project/AutomateScalafmtPlugin.scala index f066d056..28e0c04d 100644 --- a/project/AutomateScalafmtPlugin.scala +++ b/project/AutomateScalafmtPlugin.scala @@ -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 = diff --git a/project/DatatypeConfig.scala b/project/DatatypeConfig.scala index 4b39d3ca..cc95f3ff 100644 --- a/project/DatatypeConfig.scala +++ b/project/DatatypeConfig.scala @@ -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] = diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 8777d53e..b8a07cd1 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -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 } } } diff --git a/project/Util.scala b/project/Util.scala index 26533a73..2b8dccaf 100644 --- a/project/Util.scala +++ b/project/Util.scala @@ -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 + } } diff --git a/project/plugins.sbt b/project/plugins.sbt index 6d069c96..1392d888 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -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"