From 482bdc1b77b3fdbff6454ae3f919c532535361d3 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Fri, 15 Aug 2014 01:52:31 -0400 Subject: [PATCH 1/3] scalariform changes --- testing/src/main/scala/sbt/JUnitXmlTestsListener.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From 074fbdb9e682fd2a68c37335ff8130f3ceb97ca4 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Fri, 15 Aug 2014 01:57:21 -0400 Subject: [PATCH 2/3] ModuleDetailReport => OrganizationArtifactReport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ModuleDetailReport hasn’t been released yet, so this rename is safe. --- ivy/src/main/scala/sbt/EvictionWarning.scala | 6 +++--- ivy/src/main/scala/sbt/IvyRetrieve.scala | 10 +++++----- ivy/src/main/scala/sbt/UpdateReport.scala | 14 +++++++++----- main/actions/src/main/scala/sbt/CacheIvy.scala | 8 ++++---- 4 files changed, 21 insertions(+), 17 deletions(-) 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..ed252e43b 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] = @@ -150,7 +150,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..d32bbe9a9 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. 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] = From e1d60b6de02b311c35c448d2e80e048652416a7a Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Fri, 15 Aug 2014 02:57:17 -0400 Subject: [PATCH 3/3] Fixes #1484. Fixes another variant of update NPE Ivy gives an array that contains null for caller configurations. sbinary barfs when it sees null. Curiously two of the sbt plugins that hit this bug happens to be from Typesafe: addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.2") addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "0.7.3") --- ivy/src/main/scala/sbt/IvyRetrieve.scala | 9 ++++++--- ivy/src/main/scala/sbt/UpdateReport.scala | 2 +- .../eviction-warning/build.sbt | 18 ++++++++++++++++++ .../eviction-warning/test | 1 + 4 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 sbt/src/sbt-test/dependency-management/eviction-warning/build.sbt create mode 100644 sbt/src/sbt-test/dependency-management/eviction-warning/test diff --git a/ivy/src/main/scala/sbt/IvyRetrieve.scala b/ivy/src/main/scala/sbt/IvyRetrieve.scala index ed252e43b..5f07963bd 100644 --- a/ivy/src/main/scala/sbt/IvyRetrieve.scala +++ b/ivy/src/main/scala/sbt/IvyRetrieve.scala @@ -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 diff --git a/ivy/src/main/scala/sbt/UpdateReport.scala b/ivy/src/main/scala/sbt/UpdateReport.scala index d32bbe9a9..7e04d5135 100644 --- a/ivy/src/main/scala/sbt/UpdateReport.scala +++ b/ivy/src/main/scala/sbt/UpdateReport.scala @@ -123,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/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