Permalink
Browse files

mima-binary-issue-filters key to specify bin compat issues to ignore

Provide a canned filter ProblemFilters.exclude[ProblemType]("name")

For each binary issue reported, show the syntax to ignore it.

Fixes #3
  • Loading branch information...
1 parent 73e2cbb commit 34d8b4fa933948c3fe23c8443e217e5f67e1edea @havocp committed Jun 5, 2012
@@ -0,0 +1,17 @@
+package com.typesafe.tools.mima.core
+
+object ProblemFilters {
+
+ private case class ExcludeByName[P <: ProblemRef: ClassManifest](name: String) extends ProblemFilter {
+ override def apply(problem: Problem): Boolean = {
+ !(implicitly[ClassManifest[P]].erasure.isAssignableFrom(problem.getClass) &&
+ Some(name) == problem.matchName)
+ }
+
+ override def toString(): String = """ExcludeByName[%s]("%s")""".format(implicitly[ClassManifest[P]].erasure.getSimpleName, name)
+ }
+
+ def exclude[P <: ProblemRef: ClassManifest](name: String): ProblemFilter = {
+ ExcludeByName[P](name)
+ }
+}
@@ -12,6 +12,14 @@ trait ProblemRef {
def ref: Ref
def fileName: String
def referredMember: String
+
+ // name that can be used to write a matching filter
+ def matchName: Option[String] = None
+
+ // description of how to make a filter rule
+ def howToFilter: Option[String] = matchName map { name =>
+ """ProblemFilters.exclude[%s]("%s")""".format(this.getClass.getSimpleName, name)
+ }
}
trait TemplateRef extends ProblemRef {
@@ -31,9 +39,13 @@ sealed abstract class Problem extends ProblemRef {
def description: String
}
-abstract class TemplateProblem(override val ref: ClassInfo) extends Problem with TemplateRef
+abstract class TemplateProblem(override val ref: ClassInfo) extends Problem with TemplateRef {
+ override def matchName = Some(ref.fullName)
+}
-abstract class MemberProblem(override val ref: MemberInfo) extends Problem with MemberRef
+abstract class MemberProblem(override val ref: MemberInfo) extends Problem with MemberRef {
+ override def matchName = Some(referredMember)
+}
case class MissingFieldProblem(oldfld: MemberInfo) extends MemberProblem(oldfld) {
def description = oldfld.fieldString + " does not have a correspondent in " + affectedVersion + " version"
@@ -119,4 +131,4 @@ case class InaccessibleMethodProblem(newmeth: MemberInfo) extends MemberProblem(
case class InaccessibleClassProblem(newclazz: ClassInfo) extends TemplateProblem(newclazz) {
def description = newclazz.classString + " was public; is inaccessible in " + affectedVersion + " version"
-}
+}
@@ -0,0 +1,5 @@
+package com.typesafe.tools.mima
+
+package object core {
+ type ProblemFilter = (Problem) => Boolean
+}
@@ -12,5 +12,5 @@ object MimaKeys {
// TODO - Create a task to make a MiMaLib, is that a good idea?
val findBinaryIssues = TaskKey[List[core.Problem]]("mima-find-binary-issues", "A list of all binary incompatibilities between two files.")
val reportBinaryIssues = TaskKey[Unit]("mima-report-binary-issues", "Logs all binary incompatibilities to the sbt console/logs.")
-
+ val binaryIssueFilters = SettingKey[Seq[core.ProblemFilter]]("mima-binary-issue-filters", "A list of filters to apply to binary issues found.")
}
@@ -9,6 +9,7 @@ object MimaPlugin extends Plugin {
import MimaKeys._
/** Just configures MiMa to compare previous/current classfiles.*/
def mimaReportSettings: Seq[Setting[_]] = Seq(
+ binaryIssueFilters := Nil,
findBinaryIssues <<= (previousClassfiles, currentClassfiles,
fullClasspath in findBinaryIssues, streams, name) map { (prevOption, curr, cp, s, name) =>
prevOption match {
@@ -19,7 +20,7 @@ object MimaPlugin extends Plugin {
Nil
}
},
- reportBinaryIssues <<= (findBinaryIssues, failOnProblem, streams, name) map SbtMima.reportErrors)
+ reportBinaryIssues <<= (findBinaryIssues, failOnProblem, binaryIssueFilters, streams, name) map SbtMima.reportErrors)
/** Setup mima with default settings, applicable for most projects. */
def mimaDefaultSettings: Seq[Setting[_]] = Seq(
failOnProblem := true,
@@ -34,10 +34,29 @@ object SbtMima {
/** Reports binary compatibility errors.
* @param failOnProblem if true, fails the build on binary compatibility errors.
*/
- def reportErrors(errors: List[core.Problem], failOnProblem: Boolean, s: TaskStreams, projectName: String): Unit = {
+ def reportErrors(found: List[core.Problem], failOnProblem: Boolean, filters: Seq[core.ProblemFilter], s: TaskStreams, projectName: String): Unit = {
+ // filters * found is n-squared, it's fixable in principle by special-casing known
+ // filter types or something, not worth it most likely...
+
+ def isReported(problem: core.Problem) = filters forall { f =>
+ if (f(problem)) {
+ true
+ } else {
+ s.log.debug(projectName + ": filtered out: " + problem.description + "\n filtered by: " + f)
+ false
+ }
+ }
+
+ val errors = found filter isReported
+
+ val filteredCount = found.size - errors.size
+ val filteredNote = if (filteredCount > 0) " (filtered " + filteredCount + ")" else ""
+
// TODO - Line wrapping an other magikz
- def prettyPrint(p: core.Problem): String = " * " + p.description
- s.log.info(projectName + ": found " + errors.size + " potential binary incompatibilities")
+ def prettyPrint(p: core.Problem): String = {
+ " * " + p.description + p.howToFilter.map("\n filter with: " + _).getOrElse("")
+ }
+ s.log.info(projectName + ": found " + errors.size + " potential binary incompatibilities" + filteredNote)
errors map prettyPrint foreach { p =>
if (failOnProblem) s.log.error(p)
else s.log.warn(p)

0 comments on commit 34d8b4f

Please sign in to comment.