forked from hubertp/xsbt
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Log API diffs using ShowAPI and java-diff-utils library.
Implement displaying API changes by using textual representation of an API (ShowAPI) and good, old textual diff algorithm. We are using java-diff-utils library that is distributed under Apache 2.0 license. Notice that we have only soft dependency on java-diff-utils. It means that we'll try to lookup java-diff-utils class through reflection and fail gracefully if none is found on the classpath. This way sbt is not getting any new dependency. If user needs to debug api diffs then it's matter of starting sbt with `-Dsbt.extraClasspath=path/to/diffutils.jar` option passed to sbt launcher.
- Loading branch information
1 parent
ad71858
commit 025eae9
Showing
2 changed files
with
102 additions
and
4 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package sbt.inc | ||
|
||
import xsbti.api.SourceAPI | ||
import xsbt.api.ShowAPI | ||
import xsbt.api.DefaultShowAPI._ | ||
import java.lang.reflect.Method | ||
import java.util.{List => JList} | ||
|
||
/** | ||
* A class which computes diffs (unified diffs) between two textual representations of an API. | ||
* | ||
* Internally, it uses java-diff-utils library but it calls it through reflection so there's | ||
* no hard dependency on java-diff-utils. | ||
* | ||
* The reflective lookup of java-diff-utils library is performed in the constructor. Exceptions | ||
* thrown by reflection are passed as-is to the caller of the constructor. | ||
* | ||
* @throws ClassNotFoundException if difflib.DiffUtils class cannot be located | ||
* @throws LinkageError | ||
* @throws ExceptionInInitializerError | ||
*/ | ||
class APIDiff { | ||
|
||
import APIDiff._ | ||
|
||
private val diffUtilsClass = Class.forName(diffUtilsClassName) | ||
// method signature: diff(List<?>, List<?>) | ||
private val diffMethod: Method = | ||
diffUtilsClass.getMethod(diffMethodName, classOf[JList[_]], classOf[JList[_]]) | ||
|
||
private val generateUnifiedDiffMethod: Method = { | ||
val patchClass = Class.forName(patchClassName) | ||
// method signature: generateUnifiedDiff(String, String, List<String>, Patch, int) | ||
diffUtilsClass.getMethod(generateUnifiedDiffMethodName, classOf[String], | ||
classOf[String], classOf[JList[String]], patchClass, classOf[Int]) | ||
} | ||
|
||
/** | ||
* Generates an unified diff between textual representations of `api1` and `api2`. | ||
*/ | ||
def generateApiDiff(fileName: String, api1: SourceAPI, api2: SourceAPI, contextSize: Int): String = { | ||
val api1Str = ShowAPI.show(api1) | ||
val api2Str = ShowAPI.show(api2) | ||
generateApiDiff(fileName, api1Str, api2Str, contextSize) | ||
} | ||
|
||
private def generateApiDiff(fileName: String, f1: String, f2: String, contextSize: Int): String = { | ||
assert((diffMethod != null) && (generateUnifiedDiffMethod != null), "APIDiff isn't properly initialized.") | ||
import scala.collection.JavaConverters._ | ||
def asJavaList[T](it: Iterator[T]): java.util.List[T] = it.toSeq.asJava | ||
val f1Lines = asJavaList(f1.lines) | ||
val f2Lines = asJavaList(f2.lines) | ||
//val diff = DiffUtils.diff(f1Lines, f2Lines) | ||
val diff /*: Patch*/ = diffMethod.invoke(null, f1Lines, f2Lines) | ||
val unifiedPatch: JList[String] = generateUnifiedDiffMethod.invoke(null, fileName, fileName, f1Lines, diff, | ||
(contextSize: java.lang.Integer)).asInstanceOf[JList[String]] | ||
unifiedPatch.asScala.mkString("\n") | ||
} | ||
|
||
} | ||
|
||
object APIDiff { | ||
private val diffUtilsClassName = "difflib.DiffUtils" | ||
private val patchClassName = "difflib.Patch" | ||
private val diffMethodName = "diff" | ||
private val generateUnifiedDiffMethodName = "generateUnifiedDiff" | ||
} |
This file contains 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