Created
June 5, 2012 22:15
-
-
Save havocp/2878457 to your computer and use it in GitHub Desktop.
Patch to support filtering mima issues
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/core/src/main/scala/com/typesafe/tools/mima/core/Filters.scala b/core/src/main/scala/com/typesafe/tools/mima/core/Filters.scala | |
new file mode 100644 | |
index 0000000..fc8b98c | |
--- /dev/null | |
+++ b/core/src/main/scala/com/typesafe/tools/mima/core/Filters.scala | |
@@ -0,0 +1,17 @@ | |
+package com.typesafe.tools.mima.core | |
+ | |
+object ProblemFilters { | |
+ | |
+ private case class ExcludeByName[P <: ProblemRef: ClassManifest](val 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) | |
+ } | |
+} | |
diff --git a/core/src/main/scala/com/typesafe/tools/mima/core/Problems.scala b/core/src/main/scala/com/typesafe/tools/mima/core/Problems.scala | |
index e8ed5e4..07b2018 100644 | |
--- a/core/src/main/scala/com/typesafe/tools/mima/core/Problems.scala | |
+++ b/core/src/main/scala/com/typesafe/tools/mima/core/Problems.scala | |
@@ -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" | |
-} | |
\ No newline at end of file | |
+} | |
diff --git a/core/src/main/scala/com/typesafe/tools/mima/core/package.scala b/core/src/main/scala/com/typesafe/tools/mima/core/package.scala | |
new file mode 100644 | |
index 0000000..481dcb0 | |
--- /dev/null | |
+++ b/core/src/main/scala/com/typesafe/tools/mima/core/package.scala | |
@@ -0,0 +1,5 @@ | |
+package com.typesafe.tools.mima | |
+ | |
+package object core { | |
+ type ProblemFilter = (Problem) => Boolean | |
+} | |
diff --git a/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/Keys.scala b/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/Keys.scala | |
index 3e7f1e7..89d3d5d 100644 | |
--- a/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/Keys.scala | |
+++ b/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/Keys.scala | |
@@ -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.") | |
} | |
diff --git a/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/MimaPlugin.scala b/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/MimaPlugin.scala | |
index 88b362e..c844c78 100644 | |
--- a/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/MimaPlugin.scala | |
+++ b/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/MimaPlugin.scala | |
@@ -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, | |
diff --git a/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/SbtMima.scala b/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/SbtMima.scala | |
index f019771..81cd504 100644 | |
--- a/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/SbtMima.scala | |
+++ b/sbtplugin/src/main/scala/com/typesafe/tools/mima/plugin/SbtMima.scala | |
@@ -34,10 +34,26 @@ 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 = { | |
+ // this is sort of n-squared, it's fixable in principle by special-casing known | |
+ // filter types or something, not worth it most likely... | |
+ val errors = found filter { problem => | |
+ filters.foldLeft(true)({ (sofar, f) => | |
+ val keep = sofar && f(problem) | |
+ if (sofar && !keep) | |
+ s.log.debug(projectName + ": filtered out: " + problem.description + "\n filtered by: " + f) | |
+ keep | |
+ }) | |
+ } | |
+ | |
+ 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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Any reason for using the foldLeft instead of just finding the first filter with something like 'exists' or using a for expression?
i.e.