diff --git a/ivy/src/main/scala/sbt/EvictionWarning.scala b/ivy/src/main/scala/sbt/EvictionWarning.scala index bacebdee3..da121e0fa 100644 --- a/ivy/src/main/scala/sbt/EvictionWarning.scala +++ b/ivy/src/main/scala/sbt/EvictionWarning.scala @@ -112,8 +112,8 @@ object EvictionWarning { processEvictions(module, options, evictions) } - private[sbt] def buildEvictions(options: EvictionWarningOptions, report: UpdateReport): Seq[ModuleDetailReport] = { - val buffer: mutable.ListBuffer[ModuleDetailReport] = mutable.ListBuffer() + 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 } confs flatMap { confReport => confReport.details map { detail => @@ -134,7 +134,7 @@ object EvictionWarning { case _ => false } - private[sbt] def processEvictions(module: IvySbt#Module, options: EvictionWarningOptions, reports: Seq[ModuleDetailReport]): 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 _ => Seq() diff --git a/ivy/src/main/scala/sbt/IvyRetrieve.scala b/ivy/src/main/scala/sbt/IvyRetrieve.scala index b83b924a9..5f07963bd 100644 --- a/ivy/src/main/scala/sbt/IvyRetrieve.scala +++ b/ivy/src/main/scala/sbt/IvyRetrieve.scala @@ -48,14 +48,14 @@ object IvyRetrieve { // 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 details(confReport: ConfigurationResolveReport): Seq[ModuleDetailReport] = { + private[sbt] def organizationArtifactReports(confReport: ConfigurationResolveReport): Seq[OrganizationArtifactReport] = { val dependencies = confReport.getModuleRevisionIds.toArray.toVector collect { case revId: ModuleRevisionId => revId } val moduleIds = confReport.getModuleIds.toArray.toVector collect { case mId: IvyModuleId => mId } - def moduleDetail(mid: IvyModuleId): ModuleDetailReport = { + def organizationArtifact(mid: IvyModuleId): OrganizationArtifactReport = { val deps = confReport.getNodes(mid).toArray.toVector collect { case node: IvyNode => node } - new ModuleDetailReport(mid.getOrganisation, mid.getName, deps map { moduleRevisionDetail(confReport, _) }) + OrganizationArtifactReport(mid.getOrganisation, mid.getName, deps map { moduleRevisionDetail(confReport, _) }) } - moduleIds map { moduleDetail } + moduleIds map { organizationArtifact } } private[sbt] def nonEmptyString(s: String): Option[String] = @@ -68,11 +68,14 @@ object IvyRetrieve { 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[_, _] => (entry.getKey.toString, entry.getValue.toString) + 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 = { val m = toModuleID(caller.getModuleRevisionId) - val callerConfigurations = caller.getCallerConfigurations.toArray.toVector + val callerConfigurations = caller.getCallerConfigurations.toArray.toVector collect { + case x if nonEmptyString(x).isDefined => x + } val extraAttributes = toExtraAttributes(caller.getDependencyDescriptor.getExtraAttributes) new Caller(m, callerConfigurations, extraAttributes) } @@ -120,7 +123,7 @@ object IvyRetrieve { val configurations = dep.getConfigurations(confReport.getConfiguration).toArray.toList val licenses: Seq[(String, Option[String])] = mdOpt match { case Some(md) => md.getLicenses.toArray.toVector collect { - case lic: IvyLicense => + case lic: IvyLicense if Option(lic.getName).isDefined => (lic.getName, nonEmptyString(lic.getUrl)) } case _ => Nil @@ -150,7 +153,7 @@ object IvyRetrieve { def updateStats(report: ResolveReport): UpdateStats = new UpdateStats(report.getResolveTime, report.getDownloadTime, report.getDownloadSize, false) def configurationReport(confReport: ConfigurationResolveReport): ConfigurationReport = - new ConfigurationReport(confReport.getConfiguration, moduleReports(confReport), details(confReport), evicted(confReport)) + new ConfigurationReport(confReport.getConfiguration, moduleReports(confReport), organizationArtifactReports(confReport), evicted(confReport)) /** * Tries to find Ivy graph path the from node to target. diff --git a/ivy/src/main/scala/sbt/UpdateReport.scala b/ivy/src/main/scala/sbt/UpdateReport.scala index 2adc13931..7e04d5135 100644 --- a/ivy/src/main/scala/sbt/UpdateReport.scala +++ b/ivy/src/main/scala/sbt/UpdateReport.scala @@ -46,7 +46,7 @@ final class UpdateReport(val cachedDescriptor: File, val configurations: Seq[Con final class ConfigurationReport( val configuration: String, val modules: Seq[ModuleReport], - val details: Seq[ModuleDetailReport], + val details: Seq[OrganizationArtifactReport], @deprecated("Use details instead to get better eviction info.", "0.13.6") val evicted: Seq[ModuleID]) { def this(configuration: String, modules: Seq[ModuleReport], evicted: Seq[ModuleID]) = this(configuration, modules, Nil, evicted) @@ -67,17 +67,17 @@ final class ConfigurationReport( } /** - * ModuleDetailReport represents an organization+name entry in Ivy resolution report. + * OrganizationArtifactReport represents an organization+name entry in Ivy resolution report. * In sbt's terminology, "module" consists of organization, name, and version. * In Ivy's, "module" means just organization and name, and the one including version numbers * are called revisions. * - * A sequence of ModuleDetailReport called details is newly added to ConfigurationReport, replacing evicted. + * A sequence of OrganizationArtifactReport called details is newly added to ConfigurationReport, replacing evicted. * (Note old evicted was just a seq of ModuleIDs). - * ModuleDetailReport groups the ModuleReport of both winners and evicted reports by their organization and name, + * OrganizationArtifactReport groups the ModuleReport of both winners and evicted reports by their organization and name, * which can be used to calculate detailed evction warning etc. */ -final class ModuleDetailReport( +final class OrganizationArtifactReport private[sbt] ( val organization: String, val name: String, val modules: Seq[ModuleReport]) { @@ -86,6 +86,10 @@ final class ModuleDetailReport( s"\t$organization:$name\n${details.mkString}\n" } } +object OrganizationArtifactReport { + def apply(organization: String, name: String, modules: Seq[ModuleReport]): OrganizationArtifactReport = + new OrganizationArtifactReport(organization, name, modules) +} /** * Provides information about the resolution of a module. @@ -119,7 +123,7 @@ final class ModuleReport( s"\t\t$module: " + (if (arts.size <= 1) "" else "\n\t\t\t") + arts.mkString("\n\t\t\t") + "\n" } - private[sbt] def detailReport: String = + def detailReport: String = s"\t\t- ${module.revision}\n" + (if (arts.size <= 1) "" else arts.mkString("\t\t\t", "\n\t\t\t", "\n")) + reportStr("status", status) + diff --git a/main/actions/src/main/scala/sbt/CacheIvy.scala b/main/actions/src/main/scala/sbt/CacheIvy.scala index ace282948..9f168d228 100644 --- a/main/actions/src/main/scala/sbt/CacheIvy.scala +++ b/main/actions/src/main/scala/sbt/CacheIvy.scala @@ -65,8 +65,8 @@ object CacheIvy { } implicit def updateStatsFormat: Format[UpdateStats] = wrap[UpdateStats, (Long, Long, Long)](us => (us.resolveTime, us.downloadTime, us.downloadSize), { case (rt, dt, ds) => new UpdateStats(rt, dt, ds, true) }) - implicit def confReportFormat(implicit m: Format[String], mr: Format[Seq[ModuleReport]], mdr: Format[Seq[ModuleDetailReport]], mi: Format[Seq[ModuleID]]): Format[ConfigurationReport] = - wrap[ConfigurationReport, (String, Seq[ModuleReport], Seq[ModuleDetailReport], Seq[ModuleID])](r => (r.configuration, r.modules, r.details, r.evicted), { case (c, m, d, v) => new ConfigurationReport(c, m, d, v) }) + implicit def confReportFormat(implicit m: Format[String], mr: Format[Seq[ModuleReport]], oar: Format[Seq[OrganizationArtifactReport]], mi: Format[Seq[ModuleID]]): Format[ConfigurationReport] = + wrap[ConfigurationReport, (String, Seq[ModuleReport], Seq[OrganizationArtifactReport], Seq[ModuleID])](r => (r.configuration, r.modules, r.details, r.evicted), { case (c, m, d, v) => new ConfigurationReport(c, m, d, v) }) implicit def moduleReportFormat(implicit cf: Format[Seq[Caller]], ff: Format[File]): Format[ModuleReport] = { wrap[ModuleReport, (ModuleID, Seq[(Artifact, File)], Seq[Artifact], Option[String], Option[Long], Option[String], Option[String], Boolean, Option[String], Option[String], Option[String], Option[String], Map[String, String], Option[Boolean], Option[String], Seq[String], Seq[(String, Option[String])], Seq[Caller])]( m => (m.module, m.artifacts, m.missingArtifacts, m.status, m.publicationDate map { _.getTime }, m.resolver, m.artifactResolver, m.evicted, m.evictedData, m.evictedReason, m.problem, m.homepage, m.extraAttributes, m.isDefault, m.branch, m.configurations, m.licenses, m.callers), @@ -78,8 +78,8 @@ object CacheIvy { { case (n, t, x, c, cs, u, e) => Artifact(n, t, x, c, cs, u, e) } ) } - implicit def moduleDetailReportFormat(implicit sf: Format[String], bf: Format[Boolean], df: Format[Seq[ModuleReport]]): Format[ModuleDetailReport] = - wrap[ModuleDetailReport, (String, String, Seq[ModuleReport])](m => (m.organization, m.name, m.modules), { case (o, n, r) => new ModuleDetailReport(o, n, r) }) + implicit def organizationArtifactReportFormat(implicit sf: Format[String], bf: Format[Boolean], df: Format[Seq[ModuleReport]]): Format[OrganizationArtifactReport] = + wrap[OrganizationArtifactReport, (String, String, Seq[ModuleReport])](m => (m.organization, m.name, m.modules), { case (o, n, r) => OrganizationArtifactReport(o, n, r) }) implicit def callerFormat: Format[Caller] = wrap[Caller, (ModuleID, Seq[String], Map[String, String])](c => (c.caller, c.callerConfigurations, c.callerExtraAttributes), { case (c, cc, ea) => new Caller(c, cc, ea) }) implicit def exclusionRuleFormat(implicit sf: Format[String]): Format[ExclusionRule] = diff --git a/sbt/src/sbt-test/dependency-management/eviction-warning/build.sbt b/sbt/src/sbt-test/dependency-management/eviction-warning/build.sbt new file mode 100644 index 000000000..e9cd1a4f4 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/eviction-warning/build.sbt @@ -0,0 +1,18 @@ +lazy val check = taskKey[Unit]("tests update") + +def commonSettings: Seq[Def.Setting[_]] = Seq( + resolvers ++= Resolver.typesafeIvyRepo("releases") :: Resolver.typesafeRepo("releases") :: Resolver.sbtPluginRepo("releases") :: Nil, + check := { + val ur = update.value + import sbinary._, Operations._, DefaultProtocol._ + import Cache.seqFormat, CacheIvy._ + toByteArray(ur) + } + ) + +lazy val projA = project. + settings(commonSettings: _*). + settings( + addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.2"), + addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "0.7.3") + ) diff --git a/sbt/src/sbt-test/dependency-management/eviction-warning/test b/sbt/src/sbt-test/dependency-management/eviction-warning/test new file mode 100644 index 000000000..8ce9e0e25 --- /dev/null +++ b/sbt/src/sbt-test/dependency-management/eviction-warning/test @@ -0,0 +1 @@ +> projA/check diff --git a/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala b/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala index ec9303283..6403b38eb 100644 --- a/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala +++ b/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala @@ -1,7 +1,7 @@ package sbt -import java.io.{IOException, StringWriter, PrintWriter, File} -import java.net.{InetAddress} +import java.io.{ IOException, StringWriter, PrintWriter, File } +import java.net.{ InetAddress } import scala.collection.mutable.ListBuffer import scala.util.DynamicVariable