dependency filters, selecting/filtering UpdateReport

This commit is contained in:
Mark Harrah 2011-04-10 16:22:48 -04:00
parent 2f2e24c87d
commit 673f9923ab
6 changed files with 146 additions and 41 deletions

View File

@ -0,0 +1,66 @@
/* sbt -- Simple Build Tool
* Copyright 2011 Mark Harrah
*/
package sbt
trait DependencyFilterExtra
{
def moduleFilter(organization: NameFilter = AllPassFilter, name: NameFilter = AllPassFilter, revision: NameFilter = AllPassFilter): ModuleFilter =
new ModuleFilter {
def apply(m: ModuleID): Boolean = organization.accept(m.organization) && name.accept(m.name) && revision.accept(m.revision)
}
def artifactFilter(name: NameFilter = AllPassFilter, `type`: NameFilter = AllPassFilter, extension: NameFilter = AllPassFilter, classifier: NameFilter = AllPassFilter): ArtifactFilter =
new ArtifactFilter {
def apply(a: Artifact): Boolean = name.accept(a.name) && `type`.accept(a.`type`) && extension.accept(a.extension) && classifier.accept(a.classifier getOrElse "")
}
def configurationFilter(name: NameFilter = AllPassFilter): ConfigurationFilter =
new ConfigurationFilter {
def apply(c: String): Boolean = name.accept(c)
}
}
object DependencyFilter extends DependencyFilterExtra
{
def make(configuration: ConfigurationFilter = configurationFilter(), module: ModuleFilter = moduleFilter(), artifact: ArtifactFilter = artifactFilter()): DependencyFilter =
new DependencyFilter {
def apply(c: String, m: ModuleID, a: Artifact): Boolean = configuration(c) && module(m) && artifact(a)
}
def apply(x: DependencyFilter, y: DependencyFilter, combine: (Boolean, Boolean) => Boolean): DependencyFilter =
new DependencyFilter {
def apply(c: String, m: ModuleID, a: Artifact): Boolean = combine(x(c, m, a), y(c, m, a))
}
def allPass: DependencyFilter = configurationFilter()
implicit def fnToModuleFilter(f: ModuleID => Boolean): ModuleFilter = new ModuleFilter { def apply(m: ModuleID) = f(m) }
implicit def fnToArtifactFilter(f: Artifact => Boolean): ArtifactFilter = new ArtifactFilter { def apply(m: Artifact) = f(m) }
implicit def fnToConfigurationFilter(f: String => Boolean): ConfigurationFilter = new ConfigurationFilter { def apply(c: String) = f(c) }
}
trait DependencyFilter
{
def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean
final def &&(o: DependencyFilter) = DependencyFilter(this, o, _ && _)
final def ||(o: DependencyFilter) = DependencyFilter(this, o, _ || _)
final def -- (o: DependencyFilter) = DependencyFilter(this, o, _ && !_)
}
sealed trait SubDepFilter[Arg, Self <: SubDepFilter[Arg, Self]] extends DependencyFilter
{ self: Self =>
def apply(a: Arg): Boolean
protected def make(f: Arg => Boolean): Self
final def &(o: Self): Self = combine(o, _ && _)
final def |(o: Self): Self = combine(o, _ || _)
final def -(o: Self): Self = combine(o, _ && !_)
private[this] def combine(o: Self, f: (Boolean, Boolean) => Boolean): Self = make( (m: Arg) => f(this(m), o(m)) )
}
trait ModuleFilter extends SubDepFilter[ModuleID, ModuleFilter]
{
protected final def make(f: ModuleID => Boolean) = new ModuleFilter { def apply(m: ModuleID) = f(m) }
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean = apply(module)
}
trait ArtifactFilter extends SubDepFilter[Artifact, ArtifactFilter]
{
protected final def make(f: Artifact => Boolean) = new ArtifactFilter { def apply(m: Artifact) = f(m) }
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean = apply(artifact)
}
trait ConfigurationFilter extends SubDepFilter[String, ConfigurationFilter]
{
protected final def make(f: String => Boolean) = new ConfigurationFilter { def apply(m: String) = f(m) }
final def apply(configuration: String, module: ModuleID, artifact: Artifact): Boolean = apply(configuration)
}

View File

@ -50,30 +50,3 @@ object IvyRetrieve
def configurationReport(confReport: ConfigurationResolveReport): ConfigurationReport =
new ConfigurationReport(confReport.getConfiguration, moduleReports(confReport))
}
final class UpdateReport(val configurations: Seq[ConfigurationReport])
{
override def toString = "Update report:\n" + configurations.mkString
def allModules: Seq[ModuleID] = configurations.flatMap(_.allModules).distinct
def retrieve(f: (String, ModuleID, Artifact, File) => File): UpdateReport =
new UpdateReport(configurations map { _ retrieve f} )
def configuration(s: String) = configurations.find(_.configuration == s)
}
final class ConfigurationReport(val configuration: String, val modules: Seq[ModuleReport])
{
override def toString = "\t" + configuration + ":\n" + modules.mkString
def allModules: Seq[ModuleID] = modules.map(_.module)
def retrieve(f: (String, ModuleID, Artifact, File) => File): ConfigurationReport =
new ConfigurationReport(configuration, modules map { _.retrieve( (mid,art,file) => f(configuration, mid, art, file)) })
}
final class ModuleReport(val module: ModuleID, val artifacts: Seq[(Artifact, File)], val missingArtifacts: Seq[Artifact])
{
override def toString =
{
val arts = artifacts.map(_.toString) ++ missingArtifacts.map(art => "(MISSING) " + art)
"\t\t" + module + ": " +
(if(arts.size <= 1) "" else "\n\t\t\t") + arts.mkString("\n\t\t\t") + "\n"
}
def retrieve(f: (ModuleID, Artifact, File) => File): ModuleReport =
new ModuleReport(module, artifacts.map { case (art,file) => (art, f(module, art, file)) }, missingArtifacts)
}

68
ivy/UpdateReport.scala Normal file
View File

@ -0,0 +1,68 @@
/* sbt -- Simple Build Tool
* Copyright 2011 Mark Harrah
*/
package sbt
import java.io.File
final class UpdateReport(val configurations: Seq[ConfigurationReport])
{
override def toString = "Update report:\n" + configurations.mkString
def allModules: Seq[ModuleID] = configurations.flatMap(_.allModules).distinct
def retrieve(f: (String, ModuleID, Artifact, File) => File): UpdateReport =
new UpdateReport(configurations map { _ retrieve f} )
def configuration(s: String) = configurations.find(_.configuration == s)
}
final class ConfigurationReport(val configuration: String, val modules: Seq[ModuleReport])
{
override def toString = "\t" + configuration + ":\n" + modules.mkString
def allModules: Seq[ModuleID] = modules.map(_.module)
def retrieve(f: (String, ModuleID, Artifact, File) => File): ConfigurationReport =
new ConfigurationReport(configuration, modules map { _.retrieve( (mid,art,file) => f(configuration, mid, art, file)) })
}
final class ModuleReport(val module: ModuleID, val artifacts: Seq[(Artifact, File)], val missingArtifacts: Seq[Artifact])
{
override def toString =
{
val arts = artifacts.map(_.toString) ++ missingArtifacts.map(art => "(MISSING) " + art)
"\t\t" + module + ": " +
(if(arts.size <= 1) "" else "\n\t\t\t") + arts.mkString("\n\t\t\t") + "\n"
}
def retrieve(f: (ModuleID, Artifact, File) => File): ModuleReport =
new ModuleReport(module, artifacts.map { case (art,file) => (art, f(module, art, file)) }, missingArtifacts)
}
object UpdateReport
{
implicit def richUpdateReport(report: UpdateReport): RichUpdateReport = new RichUpdateReport(report)
final class RichUpdateReport(report: UpdateReport)
{
import DependencyFilter._
def allFiles: Seq[File] = matching(DependencyFilter.allPass)
def matching(f: DependencyFilter): Seq[File] = select0(f).distinct
def select(configuration: ConfigurationFilter = configurationFilter(), module: ModuleFilter = moduleFilter(), artifact: ArtifactFilter = artifactFilter()): Seq[File] =
matching(DependencyFilter.make(configuration, module, artifact))
private[this] def select0(f: DependencyFilter): Seq[File] =
for(cReport <- report.configurations; mReport <- cReport.modules; (artifact, file) <- mReport.artifacts if f(cReport.configuration, mReport.module, artifact)) yield {
if(file == null) error("Null file: conf=" + cReport.configuration + ", module=" + mReport.module + ", art: " + artifact)
file
}
def filter(f: DependencyFilter): UpdateReport =
{
val newConfigurations = report.configurations.map { confReport =>
import confReport._
val newModules =
modules map { modReport =>
import modReport._
val newArtifacts = artifacts filter { case (art, file) => f(configuration, module, art) }
val newMissing = missingArtifacts filter { art => f(configuration, module, art) }
new ModuleReport(module, newArtifacts, newMissing)
}
new ConfigurationReport(configuration, newModules)
}
new UpdateReport(newConfigurations)
}
}
}

View File

@ -482,7 +482,7 @@ object Classpaths
moduleID :== normalizedName,
defaultConfiguration in GlobalScope :== Some(Configurations.Compile),
defaultConfigurationMapping in GlobalScope <<= defaultConfiguration{ case Some(d) => "*->" + d.name; case None => "*->*" },
ivyPaths <<= (baseDirectory, appConfiguration) { (base, app) => new IvyPaths(base, Option(app.provider.scalaProvider.launcher.ivyHome)) },
ivyPaths <<= (baseDirectory, appConfiguration) { (base, app) => new IvyPaths(base, Option(app.provider.scalaProvider.launcher.ivyHome).map(_ / "cache")) },
otherResolvers <<= publishTo(_.toList),
projectResolver <<= projectResolverTask,
projectDependencies <<= projectDependenciesTask,
@ -565,7 +565,7 @@ object Classpaths
val f =
Tracked.inputChanged(cacheFile / "inputs") { (inChanged: Boolean, in: In) =>
val outCache = Tracked.lastOutput[In, UpdateReport](cacheFile / "output") {
case (_, Some(out)) if !inChanged && allFiles(out).forall(_.exists) => out
case (_, Some(out)) if !inChanged && out.allFiles.forall(_.exists) => out
case _ => work(in)
}
outCache(in)
@ -726,16 +726,8 @@ object Classpaths
flatten(defaultConfiguration in p get data) getOrElse Configurations.Default
def flatten[T](o: Option[Option[T]]): Option[T] = o flatMap identity
def managedJars(config: Configuration, jarTypes: Set[String], up: UpdateReport): Classpath = managedFiles(config, up)(isJar(jarTypes))
def allFiles(up: UpdateReport): Seq[File] = data( up.configurations flatMap { cr => allJars(cr)(_ => true) }).distinct
def managedFiles(config: Configuration, up: UpdateReport)(pred: Artifact => Boolean): Classpath =
allJars( confReport(config.name, up) )(pred)
def confReport(config: String, up: UpdateReport): ConfigurationReport =
up.configuration(config) getOrElse error("Configuration '" + config + "' unresolved by 'update'.")
def allJars(cr: ConfigurationReport)(pred: Artifact => Boolean): Seq[File] = cr.modules.flatMap(mr => allJars(mr.artifacts)(pred))
def allJars(as: Seq[(Artifact,File)])(pred: Artifact => Boolean): Seq[File] = as collect { case (a, f) if pred(a) => f }
def isJar(jarTypes: Set[String])(a: Artifact): Boolean =
jarTypes contains a.`type`
lazy val dbResolver = Resolver.url("sbt-db", new URL("http://databinder.net/repo/"))(Resolver.ivyStylePatterns)
import DependencyFilter._
def managedJars(config: Configuration, jarTypes: Set[String], up: UpdateReport): Classpath = up.select( configuration = configurationFilter(config.name), artifact = artifactFilter(`type` = jarTypes) )
}

View File

@ -1,7 +1,7 @@
/* sbt -- Simple Build Tool
* Copyright 2010, 2011 Mark Harrah
*/
package object sbt extends sbt.std.TaskExtra with sbt.Types with sbt.ProcessExtra with sbt.impl.DependencyBuilders with sbt.PathExtra with sbt.ProjectExtra
package object sbt extends sbt.std.TaskExtra with sbt.Types with sbt.ProcessExtra with sbt.impl.DependencyBuilders with sbt.PathExtra with sbt.ProjectExtra with sbt.DependencyFilterExtra
{
type Setting[T] = Project.Setting[T]
type ScopedKey[T] = Project.ScopedKey[T]

View File

@ -56,6 +56,12 @@ object NothingFilter extends NameFilter
def accept(name: String) = false
}
object NameFilter
{
implicit def fnToNameFilter(f: String => Boolean): NameFilter = new NameFilter {
def accept(name: String) = f(name)
}
}
object GlobFilter
{
implicit def apply(expression: String): NameFilter =