Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
**Added**
- Add `--summary-only` flag.
- Support diffing bytecode versions for classes.
- Show JAR manifest diff details.

**Changed**
- Replace `com.jakewharton.diffuse.io.Size` with `me.saket.bytesize.ByteSize` in the APIs.
Expand Down
3 changes: 2 additions & 1 deletion formats/api/formats.api
Original file line number Diff line number Diff line change
Expand Up @@ -280,11 +280,12 @@ public final class com/jakewharton/diffuse/format/Field : com/jakewharton/diffus

public final class com/jakewharton/diffuse/format/Jar : com/jakewharton/diffuse/format/BinaryFormat, com/jakewharton/diffuse/format/CodeBinary {
public static final field Companion Lcom/jakewharton/diffuse/format/Jar$Companion;
public synthetic fun <init> (Ljava/lang/String;Lcom/jakewharton/diffuse/format/ArchiveFiles;Ljava/util/List;Ljava/util/List;Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Lcom/jakewharton/diffuse/format/ArchiveFiles;Ljava/util/List;Ljava/util/List;Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getClasses ()Ljava/util/List;
public fun getDeclaredMembers ()Ljava/util/List;
public fun getFilename ()Ljava/lang/String;
public final fun getFiles ()Lcom/jakewharton/diffuse/format/ArchiveFiles;
public final fun getManifest ()Ljava/lang/String;
public fun getMembers ()Ljava/util/List;
public fun getReferencedMembers ()Ljava/util/List;
public static final fun parse (Lcom/jakewharton/diffuse/io/Input;)Lcom/jakewharton/diffuse/format/Jar;
Expand Down
12 changes: 11 additions & 1 deletion formats/src/main/kotlin/com/jakewharton/diffuse/format/Jar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.jakewharton.diffuse.io.Input
class Jar
private constructor(
override val filename: String?,
val manifest: String,
val files: ArchiveFiles,
val classes: List<Class>,
override val declaredMembers: List<Member>,
Expand All @@ -16,6 +17,8 @@ private constructor(
override val members = declaredMembers + referencedMembers

companion object {
private const val MANIFEST_PATH = "META-INF/MANIFEST.MF"

@JvmStatic
@JvmName("parse")
fun Input.toJar(): Jar {
Expand All @@ -30,7 +33,14 @@ private constructor(
// Declared methods are likely to reference other declared members. Ensure all are removed.
referencedMembers -= declaredMembers

return Jar(name, files, classes, declaredMembers.sorted(), referencedMembers.sorted())
return Jar(
filename = name,
manifest = zip[MANIFEST_PATH].asInput().toUtf8(),
files = files,
classes = classes,
declaredMembers = declaredMembers.sorted(),
referencedMembers = referencedMembers.sorted(),
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ internal class JarDiff(
) : BinaryDiff {
val archive = ArchiveFilesDiff(oldJar.files, newJar.files, includeCompressed = false)
val jars = JarsDiff(listOf(oldJar), oldMapping, listOf(newJar), newMapping)
val manifest = JarManifestDiff(oldJar.manifest, newJar.manifest)

val changed = jars.changed || archive.changed
val changed = jars.changed || archive.changed || manifest.changed

override fun toTextReport(summaryOnly: Boolean): Report = JarDiffTextReport(this, summaryOnly)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.jakewharton.diffuse.diff

import com.github.difflib.DiffUtils
import com.github.difflib.UnifiedDiffUtils

internal class JarManifestDiff(oldManifest: String, newManifest: String) {
val diff: List<String> =
if (oldManifest == newManifest) {
emptyList()
} else {
val oldLines = oldManifest.lines()
val newLines = newManifest.lines()
val diff = DiffUtils.diff(oldLines, newLines)
UnifiedDiffUtils.generateUnifiedDiff(MANIFEST_PATH, MANIFEST_PATH, oldLines, diff, 1)
}

val changed = diff.isNotEmpty()

internal companion object {
const val MANIFEST_PATH = "META-INF/MANIFEST.MF"
}
}

internal fun JarManifestDiff.toDetailReport() = buildString {
if (diff.isNotEmpty()) {
appendLine()
diff
.drop(2) // Skip file name headers.
.forEach(::appendLine)
appendLine()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ internal class JarDiffTextReport(private val jarDiff: JarDiff, private val summa
appendLine("=================")
appendLine(jarDiff.archive.toDetailReport())
}
if (jarDiff.manifest.changed) {
appendLine()
appendLine("======================")
appendLine("==== MANIFEST ====")
appendLine("======================")
appendLine(jarDiff.manifest.toDetailReport())
}
if (jarDiff.jars.changed) {
appendLine()
appendLine("=====================")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.jakewharton.diffuse

import assertk.assertThat
import assertk.assertions.contains
import assertk.assertions.doesNotContain
import com.jakewharton.diffuse.diff.JarDiff
import com.jakewharton.diffuse.diff.JarManifestDiff.Companion.MANIFEST_PATH
import com.jakewharton.diffuse.format.ApiMapping
import com.jakewharton.diffuse.format.Jar
import com.jakewharton.diffuse.format.Jar.Companion.toJar
import com.jakewharton.diffuse.io.Input.Companion.asInput
import java.io.ByteArrayOutputStream
import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry
import okio.ByteString.Companion.toByteString
import org.junit.Test

class JarDiffTextReportTest {
@Test
fun manifestChanged() {
val oldJar = jar("old.jar", "Manifest-Version: 1.0\nCreated-By: old")
val newJar = jar("new.jar", "Manifest-Version: 1.0\nCreated-By: new")

val report =
JarDiff(oldJar, ApiMapping.EMPTY, newJar, ApiMapping.EMPTY).toTextReport(false).toString()

assertThat(report)
.contains(
"""
|======================
|==== MANIFEST ====
|======================
|
|@@ -1,2 +1,2 @@
| Manifest-Version: 1.0
|-Created-By: old
|+Created-By: new
"""
.trimMargin()
)
}

@Test
fun manifestNotChanged() {
val oldJar = jar("old.jar", "Manifest-Version: 1.0\nCreated-By: same")
val newJar = jar("new.jar", "Manifest-Version: 1.0\nCreated-By: same")

val report =
JarDiff(oldJar, ApiMapping.EMPTY, newJar, ApiMapping.EMPTY).toTextReport(false).toString()

assertThat(report).doesNotContain("==== MANIFEST ====")
}

private fun jar(name: String, manifestContent: String): Jar {
val bytes = ByteArrayOutputStream()
JarOutputStream(bytes).use { jar ->
jar.putNextEntry(ZipEntry(MANIFEST_PATH))
jar.write(manifestContent.toByteArray())
jar.closeEntry()
}
return bytes.toByteArray().toByteString().asInput(name).toJar()
}
}