Merge pull request #19 from dwijnand/fport/maven-compatibility-changes

FPORT: Maven compatibility changes (intransitive warnings and "configuration not public")
This commit is contained in:
eugene yokota 2016-01-17 14:07:56 -05:00
commit 1c4e67fda7
6 changed files with 145 additions and 73 deletions

View File

@ -0,0 +1,26 @@
package sbt
private[sbt] object CompatibilityWarning {
def apply(module: IvySbt#Module, mavenStyle: Boolean, log: Logger): Unit = {
if (mavenStyle) {
processIntransitive(module, log)
}
}
def processIntransitive(module: IvySbt#Module, log: Logger): Unit = {
val directDependencies: Seq[ModuleID] = module.moduleSettings match {
case x: InlineConfiguration => x.dependencies
case x: InlineConfigurationWithExcludes => x.dependencies
case _ => Seq()
}
directDependencies foreach { m =>
if (!m.isTransitive) {
log.warn(
s"""Found intransitive dependency ($m) while publishMavenStyle is true, but Maven repositories
| do not support intransitive dependencies. Use exclusions instead so transitive dependencies
| will be correctly excluded in dependent projects.
""".stripMargin)
} else ()
}
}
}

View File

@ -238,31 +238,21 @@ 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 = {
def warnIntransitve(): Unit =
if (!dependency.isTransitive)
log.warn(
s"""Translating intransitive dependency (${dependency.getDependencyId}) into pom.xml, but maven does not support intransitive dependencies.
| Please use exclusions instead so transitive dependencies will be correctly excluded in dependent projects.
""".stripMargin
)
else ()
val artifacts = dependency.getAllDependencyArtifacts
val includeArtifacts = artifacts.filter(d => includeTypes(d.getType))
if (artifacts.isEmpty) {
val configs = dependency.getModuleConfigurations
if (!configs.forall(Set("sources", "docs"))) {
warnIntransitve()
val (scope, optional) = getScopeAndOptional(dependency.getModuleConfigurations)
makeDependencyElem(dependency, scope, optional, None, None, excludes)
} else NodeSeq.Empty
} else if (includeArtifacts.isEmpty) {
NodeSeq.Empty
} else {
warnIntransitve()
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] =

View File

@ -115,6 +115,7 @@ private[sbt] case class SbtChainResolver(
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
@ -122,7 +123,7 @@ private[sbt] case class SbtChainResolver(
// RETURNS: Left -> Error
// Right -> Some(resolved module) // Found in this resolver, can use this result.
// Right -> None // Do not use this resolver
val results = resolvers map { x =>
lazy val results = resolvers map { x =>
// if the revision is cached and isReturnFirst is set, don't bother hitting any resolvers, just return None for this guy.
if (isReturnFirst && temp.isDefined && !useLatest) Right(None)
else {
@ -153,54 +154,61 @@ private[sbt] case class SbtChainResolver(
}
}
}
val errors = results collect { case Left(e) => e }
val foundRevisions: Vector[(ResolvedModuleRevision, DependencyResolver)] = results collect { case Right(Some(x)) => x }
val sorted =
if (useLatest) (foundRevisions.sortBy {
case (rmr, resolver) =>
Message.warn(s"Sorrting 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 =>
(resolver.findIvyFileRef(dd, data), rmr.getDescriptor) match {
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!")
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}")
dmd.setPublicationDate(lmd)
ivf.getLastModified
case _ =>
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 None if resolver.getName == "inter-project" => // do nothing
case None if resolver.isInstanceOf[CustomMavenResolver] =>
// do nothing for now....
// We want to see if the maven caching is sufficient and we do not need to duplicate within the ivy cache...
case None => throw new RuntimeException(s"\t${resolver.getName}: no ivy file nor artifact found for $rmr")
case Some(artifactRef) =>
val systemMd = toSystem(rmr.getDescriptor)
getRepositoryCacheManager.cacheModuleDescriptor(resolver, artifactRef,
toSystem(dd), systemMd.getAllArtifacts.head, None.orNull, getCacheOptions(data))
}
rmr
}
else foundRevisions.reverse.headOption map { _._1 } // we have to reverse because resolvers are hit in reverse order.
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] = sorted orElse resolvedOrCached
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"Sorrting 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 =>
(resolver.findIvyFileRef(dd, data), rmr.getDescriptor) match {
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!")
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}")
dmd.setPublicationDate(lmd)
ivf.getLastModified
case _ =>
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 None if resolver.getName == "inter-project" => // do nothing
case None if resolver.isInstanceOf[CustomMavenResolver] =>
// do nothing for now....
// We want to see if the maven caching is sufficient and we do not need to duplicate within the ivy cache...
case None => throw new RuntimeException(s"\t${resolver.getName}: no ivy file nor artifact found for $rmr")
case Some(artifactRef) =>
val systemMd = toSystem(rmr.getDescriptor)
getRepositoryCacheManager.cacheModuleDescriptor(resolver, artifactRef,
toSystem(dd), systemMd.getAllArtifacts.head, None.orNull, getCacheOptions(data))
}
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 {
@ -305,4 +313,4 @@ private[sbt] case class SbtChainResolver(
oldLatest
case _ => None
}
}
}

View File

@ -15,6 +15,8 @@ import sbt.util.Logger
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.
@ -26,6 +28,8 @@ final class UpdateOptions private[sbt] (
) {
def withCircularDependencyLevel(circularDependencyLevel: CircularDependencyLevel): UpdateOptions =
copy(circularDependencyLevel = circularDependencyLevel)
def withInterProjectFirst(interProjectFirst: Boolean): UpdateOptions =
copy(interProjectFirst = interProjectFirst)
def withLatestSnapshots(latestSnapshots: Boolean): UpdateOptions =
copy(latestSnapshots = latestSnapshots)
@deprecated("Use withCachedResolution instead.", "0.13.7")
@ -45,6 +49,7 @@ final class UpdateOptions private[sbt] (
private[sbt] def copy(
circularDependencyLevel: CircularDependencyLevel = this.circularDependencyLevel,
interProjectFirst: Boolean = this.interProjectFirst,
latestSnapshots: Boolean = this.latestSnapshots,
consolidatedResolution: Boolean = this.consolidatedResolution,
cachedResolution: Boolean = this.cachedResolution,
@ -52,6 +57,7 @@ final class UpdateOptions private[sbt] (
): UpdateOptions =
new UpdateOptions(
circularDependencyLevel,
interProjectFirst,
latestSnapshots,
consolidatedResolution,
cachedResolution,
@ -61,6 +67,7 @@ final class UpdateOptions private[sbt] (
override def equals(o: Any): Boolean = o match {
case o: UpdateOptions =>
this.circularDependencyLevel == o.circularDependencyLevel &&
this.interProjectFirst == o.interProjectFirst &&
this.latestSnapshots == o.latestSnapshots &&
this.cachedResolution == o.cachedResolution &&
this.resolverConverter == o.resolverConverter
@ -71,6 +78,7 @@ final class UpdateOptions private[sbt] (
{
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.##
@ -84,6 +92,7 @@ object UpdateOptions {
def apply(): UpdateOptions =
new UpdateOptions(
circularDependencyLevel = CircularDependencyLevel.Warn,
interProjectFirst = true,
latestSnapshots = false,
consolidatedResolution = false,
cachedResolution = false,

View File

@ -0,0 +1,36 @@
lazy val check = taskKey[Unit]("Runs the check")
def commonSettings: Seq[Def.Setting[_]] =
Seq(
ivyPaths := new IvyPaths( (baseDirectory in ThisBuild).value, Some((target in LocalRootProject).value / "ivy-cache")),
scalaVersion in ThisBuild := "2.11.7",
organization in ThisBuild := "com.example",
version in ThisBuild := "0.1.0-SNAPSHOT",
autoScalaLibrary := false,
crossPaths := false
)
lazy val realCommonsIoClient = project.
settings(
commonSettings,
name := "a",
libraryDependencies := Seq(
"commons-io" % "commons-io" % "1.3"
),
fullResolvers := fullResolvers.value.filterNot(_.name == "inter-project")
)
lazy val fakeCommonsIo = project.
settings(
commonSettings,
organization := "commons-io",
name := "commons-io",
version := "1.3"
)
lazy val fakeCommonsIoClient = project.
dependsOn(fakeCommonsIo % "test->test").
settings(
commonSettings,
name := "c"
)

View File

@ -0,0 +1,3 @@
> realCommonsIoClient/update
> fakeCommonsIoClient/update