Merge pull request #1447 from sbt/wip/improve-resolve-exception

Improve resolve exception
This commit is contained in:
Josh Suereth 2014-07-14 10:05:13 -04:00
commit 4f3da04515
4 changed files with 66 additions and 12 deletions

View File

@ -146,6 +146,17 @@ object IvyActions {
withExtra foreach { id => log.warn("\t\t" + id) }
log.warn("")
}
err.failed foreach { x =>
val failedPaths = err.failedPaths(x)
if (!failedPaths.isEmpty) {
log.warn("\n\tNote: Unresolved dependencies path:")
val reverseFailedPaths = (failedPaths.toList map { _.toString }).reverse
log.warn("\t\t" + reverseFailedPaths.head)
reverseFailedPaths.tail foreach { id =>
log.warn("\t\t +- " + id)
}
}
}
}
def groupedConflicts[T](moduleFilter: ModuleFilter, grouping: ModuleID => T)(report: UpdateReport): Map[T, Set[String]] =
report.configurations.flatMap { confReport =>
@ -209,8 +220,15 @@ object IvyActions {
val err =
if (resolveReport.hasError) {
val messages = resolveReport.getAllProblemMessages.toArray.map(_.toString).distinct
val failed = resolveReport.getUnresolvedDependencies.map(node => IvyRetrieve.toModuleID(node.getId))
Some(new ResolveException(messages, failed))
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)
}
@ -269,4 +287,10 @@ object IvyActions {
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]) extends RuntimeException(messages.mkString("\n"))
final class ResolveException(
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 }: _*))
}

View File

@ -5,10 +5,10 @@ package sbt
import java.io.File
import collection.mutable
import org.apache.ivy.core.{ module, report }
import org.apache.ivy.core.{ module, report, resolve }
import module.descriptor.{ Artifact => IvyArtifact }
import module.id.ModuleRevisionId
import resolve.IvyNode
import report.{ ArtifactDownloadReport, ConfigurationResolveReport, ResolveReport }
object IvyRetrieve {
@ -51,4 +51,34 @@ object IvyRetrieve {
new UpdateStats(report.getResolveTime, report.getDownloadTime, report.getDownloadSize, false)
def configurationReport(confReport: ConfigurationResolveReport): ConfigurationReport =
new ConfigurationReport(confReport.getConfiguration, moduleReports(confReport), evicted(confReport))
/**
* Tries to find Ivy graph path the from node to target.
*/
def findPath(target: IvyNode, from: ModuleRevisionId): List[IvyNode] = {
def doFindPath(current: IvyNode, path: List[IvyNode]): List[IvyNode] = {
val callers = current.getAllRealCallers.toList
// Ivy actually returns non-direct callers here.
// that's why we have to calculate all possible paths below and pick the longest path.
val directCallers = callers filter { caller =>
val md = caller.getModuleDescriptor
val dd = md.getDependencies.toList find { dd =>
(dd.getDependencyRevisionId == current.getId) &&
(dd.getParentRevisionId == caller.getModuleRevisionId)
}
dd.isDefined
}
val directCallersRevId = (directCallers map { _.getModuleRevisionId }).distinct
val paths: List[List[IvyNode]] = ((directCallersRevId map { revId =>
val node = current.findNode(revId)
if (revId == from) node :: path
else if (node == node.getRoot) Nil
else if (path contains node) path
else doFindPath(node, node :: path)
}) sortBy { _.size }).reverse
paths.headOption getOrElse Nil
}
if (target.getId == from) List(target)
else doFindPath(target, List(target))
}
}

View File

@ -17,7 +17,7 @@ object Release extends Build {
// Add credentials if they exist.
def lameCredentialSettings: Seq[Setting[_]] =
if(CredentialsFile.exists) Seq(credentials in ThisBuild += Credentials(CredentialsFile))
if (CredentialsFile.exists) Seq(credentials in ThisBuild += Credentials(CredentialsFile))
else Nil
def releaseSettings(nonRoots: => Seq[ProjectReference], launcher: TaskKey[File]): Seq[Setting[_]] = Seq(
publishTo in ThisBuild <<= publishResolver,

View File

@ -14,7 +14,7 @@ object Sbt extends Build {
// Aggregate task for 2.11
private def lameAgregateTask(task: String): String =
s"all control/$task collections/$task io/$task completion/$task"
s"all control/$task collections/$task io/$task completion/$task"
def buildSettings = Seq(
organization := "org.scala-sbt",
version := "0.13.6-SNAPSHOT",
@ -57,15 +57,15 @@ object Sbt extends Build {
},
commands += Command.command("release-sbt-local") { state =>
"publishLocal" ::
"setupBuildScala211" ::
lameAgregateTask("publishLocal") ::
"reload" ::
state
"setupBuildScala211" ::
lameAgregateTask("publishLocal") ::
"reload" ::
state
},
commands += Command.command("release-sbt") { state =>
// TODO - Any sort of validation
"checkCredentials" ::
"publishSigned" ::
"publishSigned" ::
"publishLauncher" ::
"release-libs-211" ::
state