mirror of https://github.com/sbt/sbt.git
Output better `sbt.ModuleReport`s
This commit is contained in:
parent
ebd97b8340
commit
d33ab9da26
|
|
@ -76,7 +76,10 @@ case class Project(
|
|||
|
||||
// Ivy-specific
|
||||
// First String is configuration
|
||||
publications: Seq[(String, Publication)]
|
||||
publications: Seq[(String, Publication)],
|
||||
|
||||
// Extra infos, not used during resolution
|
||||
info: Info
|
||||
) {
|
||||
def moduleVersion = (module, version)
|
||||
|
||||
|
|
@ -85,6 +88,25 @@ case class Project(
|
|||
Orders.allConfigurations(configurations)
|
||||
}
|
||||
|
||||
/** Extra project info, not used during resolution */
|
||||
case class Info(
|
||||
description: String,
|
||||
homePage: String,
|
||||
licenses: Seq[(String, Option[String])],
|
||||
developers: Seq[Info.Developer],
|
||||
publication: Option[Versions.DateTime]
|
||||
)
|
||||
|
||||
object Info {
|
||||
case class Developer(
|
||||
id: String,
|
||||
name: String,
|
||||
url: String
|
||||
)
|
||||
|
||||
val empty = Info("", "", Nil, Nil, None)
|
||||
}
|
||||
|
||||
// Maven-specific
|
||||
case class Activation(properties: Seq[(String, Option[String])])
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,25 @@ object IvyXml {
|
|||
|
||||
publicationsOpt = publicationsNodeOpt.map(publications)
|
||||
|
||||
} yield
|
||||
} yield {
|
||||
|
||||
val description = infoNode.children
|
||||
.find(_.label == "description")
|
||||
.map(_.textContent.trim)
|
||||
.getOrElse("")
|
||||
|
||||
val licenses = infoNode.children
|
||||
.filter(_.label == "license")
|
||||
.flatMap { n =>
|
||||
n.attribute("name").toOption.map { name =>
|
||||
(name, n.attribute("url").toOption)
|
||||
}.toSeq
|
||||
}
|
||||
|
||||
val publicationDate = infoNode.attribute("publication")
|
||||
.toOption
|
||||
.flatMap(parseDateTime)
|
||||
|
||||
Project(
|
||||
module,
|
||||
version,
|
||||
|
|
@ -128,7 +146,15 @@ object IvyXml {
|
|||
configurations0.flatMap { case (conf, _) =>
|
||||
(publicationsOpt.flatMap(_.get(conf)).getOrElse(Nil) ++ inAllConfs).map(conf -> _)
|
||||
}
|
||||
}
|
||||
},
|
||||
Info(
|
||||
description,
|
||||
"",
|
||||
licenses,
|
||||
Nil,
|
||||
publicationDate
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -177,39 +177,73 @@ object Pom {
|
|||
(mod.copy(attributes = Map.empty), ver) -> mod.attributes
|
||||
}.toMap
|
||||
|
||||
} yield Project(
|
||||
projModule.copy(organization = groupId),
|
||||
version,
|
||||
deps.map {
|
||||
case (config, dep0) =>
|
||||
val dep = extraAttrsMap.get(dep0.moduleVersion).fold(dep0)(attrs =>
|
||||
dep0.copy(module = dep0.module.copy(attributes = attrs))
|
||||
)
|
||||
config -> dep
|
||||
},
|
||||
Map.empty,
|
||||
parentModuleOpt.map((_, parentVersionOpt.getOrElse(""))),
|
||||
depMgmts,
|
||||
properties.toMap,
|
||||
profiles,
|
||||
None,
|
||||
None,
|
||||
Nil
|
||||
)
|
||||
}
|
||||
} yield {
|
||||
|
||||
def parseDateTime(s: String): Option[Versions.DateTime] =
|
||||
if (s.length == 14 && s.forall(_.isDigit))
|
||||
Some(Versions.DateTime(
|
||||
s.substring(0, 4).toInt,
|
||||
s.substring(4, 6).toInt,
|
||||
s.substring(6, 8).toInt,
|
||||
s.substring(8, 10).toInt,
|
||||
s.substring(10, 12).toInt,
|
||||
s.substring(12, 14).toInt
|
||||
))
|
||||
else
|
||||
None
|
||||
val description = pom.children
|
||||
.find(_.label == "description")
|
||||
.map(_.textContent)
|
||||
.getOrElse("")
|
||||
|
||||
val homePage = pom.children
|
||||
.find(_.label == "url")
|
||||
.map(_.textContent)
|
||||
.getOrElse("")
|
||||
|
||||
val licenses = pom.children
|
||||
.find(_.label == "licenses")
|
||||
.toSeq
|
||||
.flatMap(_.children)
|
||||
.filter(_.label == "license")
|
||||
.flatMap { n =>
|
||||
n.attribute("name").toOption.map { name =>
|
||||
(name, n.attribute("url").toOption)
|
||||
}.toSeq
|
||||
}
|
||||
|
||||
val developers = pom.children
|
||||
.find(_.label == "developers")
|
||||
.toSeq
|
||||
.flatMap(_.children)
|
||||
.filter(_.label == "developer")
|
||||
.map { n =>
|
||||
for {
|
||||
id <- n.attribute("id")
|
||||
name <- n.attribute("name")
|
||||
url <- n.attribute("url")
|
||||
} yield Info.Developer(id, name, url)
|
||||
}
|
||||
.collect {
|
||||
case \/-(d) => d
|
||||
}
|
||||
|
||||
Project(
|
||||
projModule.copy(organization = groupId),
|
||||
version,
|
||||
deps.map {
|
||||
case (config, dep0) =>
|
||||
val dep = extraAttrsMap.get(dep0.moduleVersion).fold(dep0)(attrs =>
|
||||
dep0.copy(module = dep0.module.copy(attributes = attrs))
|
||||
)
|
||||
config -> dep
|
||||
},
|
||||
Map.empty,
|
||||
parentModuleOpt.map((_, parentVersionOpt.getOrElse(""))),
|
||||
depMgmts,
|
||||
properties.toMap,
|
||||
profiles,
|
||||
None,
|
||||
None,
|
||||
Nil,
|
||||
Info(
|
||||
description,
|
||||
homePage,
|
||||
licenses,
|
||||
developers,
|
||||
None
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
def versions(node: Node): String \/ Versions = {
|
||||
import Scalaz._
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ package object coursier {
|
|||
type Project = core.Project
|
||||
val Project = core.Project
|
||||
|
||||
type Info = core.Info
|
||||
val Info = core.Info
|
||||
|
||||
type Profile = core.Profile
|
||||
val Profile = core.Profile
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package coursier.util
|
||||
|
||||
import coursier.core.Versions
|
||||
|
||||
import scalaz.{\/-, -\/, \/, Scalaz}
|
||||
|
||||
object Xml {
|
||||
|
|
@ -55,4 +57,17 @@ object Xml {
|
|||
.toRightDisjunction(s"$description not found")
|
||||
}
|
||||
|
||||
def parseDateTime(s: String): Option[Versions.DateTime] =
|
||||
if (s.length == 14 && s.forall(_.isDigit))
|
||||
Some(Versions.DateTime(
|
||||
s.substring(0, 4).toInt,
|
||||
s.substring(4, 6).toInt,
|
||||
s.substring(6, 8).toInt,
|
||||
s.substring(8, 10).toInt,
|
||||
s.substring(10, 12).toInt,
|
||||
s.substring(12, 14).toInt
|
||||
))
|
||||
else
|
||||
None
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,8 @@ object FromSbt {
|
|||
Nil,
|
||||
None,
|
||||
None,
|
||||
Nil
|
||||
Nil,
|
||||
Info.empty
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package coursier
|
||||
|
||||
import java.util.GregorianCalendar
|
||||
|
||||
import sbt._
|
||||
|
||||
object ToSbt {
|
||||
|
|
@ -24,33 +26,61 @@ object ToSbt {
|
|||
Map.empty
|
||||
)
|
||||
|
||||
def moduleReport(dependency: Dependency, artifacts: Seq[(Artifact, Option[File])]): sbt.ModuleReport =
|
||||
def moduleReport(
|
||||
dependency: Dependency,
|
||||
dependees: Seq[(Dependency, Project)],
|
||||
project: Project,
|
||||
artifacts: Seq[(Artifact, Option[File])]
|
||||
): sbt.ModuleReport = {
|
||||
|
||||
val sbtArtifacts = artifacts.collect {
|
||||
case (artifact, Some(file)) =>
|
||||
(ToSbt.artifact(dependency.module, artifact), file)
|
||||
}
|
||||
val sbtMissingArtifacts = artifacts.collect {
|
||||
case (artifact, None) =>
|
||||
ToSbt.artifact(dependency.module, artifact)
|
||||
}
|
||||
|
||||
val publicationDate = project.info.publication.map { dt =>
|
||||
new GregorianCalendar(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second).getTime
|
||||
}
|
||||
|
||||
val callers = dependees.map {
|
||||
case (dependee, dependeeProj) =>
|
||||
new Caller(
|
||||
ToSbt.moduleId(dependee),
|
||||
dependeeProj.configurations.keys.toVector,
|
||||
dependee.module.attributes ++ dependeeProj.properties,
|
||||
// FIXME Set better values here
|
||||
isForceDependency = false,
|
||||
isChangingDependency = false,
|
||||
isTransitiveDependency = false,
|
||||
isDirectlyForceDependency = false
|
||||
)
|
||||
}
|
||||
|
||||
new sbt.ModuleReport(
|
||||
ToSbt.moduleId(dependency),
|
||||
artifacts.collect {
|
||||
case (artifact, Some(file)) =>
|
||||
(ToSbt.artifact(dependency.module, artifact), file)
|
||||
},
|
||||
artifacts.collect {
|
||||
case (artifact, None) =>
|
||||
ToSbt.artifact(dependency.module, artifact)
|
||||
},
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Map.empty,
|
||||
None,
|
||||
None,
|
||||
Nil,
|
||||
Nil,
|
||||
Nil
|
||||
module = ToSbt.moduleId(dependency),
|
||||
artifacts = sbtArtifacts,
|
||||
missingArtifacts = sbtMissingArtifacts,
|
||||
status = None,
|
||||
publicationDate = publicationDate,
|
||||
resolver = None,
|
||||
artifactResolver = None,
|
||||
evicted = false,
|
||||
evictedData = None,
|
||||
evictedReason = None,
|
||||
problem = None,
|
||||
homepage = Some(project.info.homePage).filter(_.nonEmpty),
|
||||
extraAttributes = dependency.module.attributes ++ project.properties,
|
||||
isDefault = None,
|
||||
branch = None,
|
||||
configurations = project.configurations.keys.toVector,
|
||||
licenses = project.info.licenses,
|
||||
callers = callers
|
||||
)
|
||||
}
|
||||
|
||||
private def grouped[K, V](map: Seq[(K, V)]): Map[K, Seq[V]] =
|
||||
map.groupBy { case (k, _) => k }.map {
|
||||
|
|
@ -71,9 +101,47 @@ object ToSbt {
|
|||
|
||||
val groupedDepArtifacts = grouped(depArtifacts)
|
||||
|
||||
val versions = res.dependencies.toVector.map { dep =>
|
||||
dep.module -> dep.version
|
||||
}.toMap
|
||||
|
||||
def clean(dep: Dependency): Dependency =
|
||||
dep.copy(configuration = "", exclusions = Set.empty, optional = false)
|
||||
|
||||
val reverseDependencies = res.reverseDependencies
|
||||
.toVector
|
||||
.map { case (k, v) =>
|
||||
clean(k) -> v.map(clean)
|
||||
}
|
||||
.groupBy { case (k, v) => k }
|
||||
.mapValues { v =>
|
||||
v.flatMap {
|
||||
case (_, l) => l
|
||||
}
|
||||
}
|
||||
.toVector
|
||||
.toMap
|
||||
|
||||
groupedDepArtifacts.map {
|
||||
case (dep, artifacts) =>
|
||||
ToSbt.moduleReport(dep, artifacts.map(a => a -> artifactFileOpt(a)))
|
||||
val (_, proj) = res.projectCache(dep.moduleVersion)
|
||||
|
||||
// FIXME Likely flaky...
|
||||
val dependees = reverseDependencies
|
||||
.getOrElse(clean(dep.copy(version = "")), Vector.empty)
|
||||
.map { dependee0 =>
|
||||
val version = versions(dependee0.module)
|
||||
val dependee = dependee0.copy(version = version)
|
||||
val (_, dependeeProj) = res.projectCache(dependee.moduleVersion)
|
||||
(dependee, dependeeProj)
|
||||
}
|
||||
|
||||
ToSbt.moduleReport(
|
||||
dep,
|
||||
dependees,
|
||||
proj,
|
||||
artifacts.map(a => a -> artifactFileOpt(a))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ package object test {
|
|||
profiles,
|
||||
versions,
|
||||
snapshotVersioning,
|
||||
publications
|
||||
publications,
|
||||
Info.empty
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue