Skip to content

Commit aa9403b

Browse files
committed
Show JAR manifest diff details
1 parent 7058b85 commit aa9403b

7 files changed

Lines changed: 118 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
**Added**
77
- Add `--summary-only` flag.
88
- Support diffing bytecode versions for classes.
9+
- Show JAR manifest diff details.
910

1011
**Changed**
1112
- Replace `com.jakewharton.diffuse.io.Size` with `me.saket.bytesize.ByteSize` in the APIs.

formats/api/formats.api

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,11 +280,12 @@ public final class com/jakewharton/diffuse/format/Field : com/jakewharton/diffus
280280

281281
public final class com/jakewharton/diffuse/format/Jar : com/jakewharton/diffuse/format/BinaryFormat, com/jakewharton/diffuse/format/CodeBinary {
282282
public static final field Companion Lcom/jakewharton/diffuse/format/Jar$Companion;
283-
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
283+
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
284284
public final fun getClasses ()Ljava/util/List;
285285
public fun getDeclaredMembers ()Ljava/util/List;
286286
public fun getFilename ()Ljava/lang/String;
287287
public final fun getFiles ()Lcom/jakewharton/diffuse/format/ArchiveFiles;
288+
public final fun getManifest ()Ljava/lang/String;
288289
public fun getMembers ()Ljava/util/List;
289290
public fun getReferencedMembers ()Ljava/util/List;
290291
public static final fun parse (Lcom/jakewharton/diffuse/io/Input;)Lcom/jakewharton/diffuse/format/Jar;

formats/src/main/kotlin/com/jakewharton/diffuse/format/Jar.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.jakewharton.diffuse.io.Input
88
class Jar
99
private constructor(
1010
override val filename: String?,
11+
val manifest: String,
1112
val files: ArchiveFiles,
1213
val classes: List<Class>,
1314
override val declaredMembers: List<Member>,
@@ -16,6 +17,8 @@ private constructor(
1617
override val members = declaredMembers + referencedMembers
1718

1819
companion object {
20+
private const val MANIFEST_PATH = "META-INF/MANIFEST.MF"
21+
1922
@JvmStatic
2023
@JvmName("parse")
2124
fun Input.toJar(): Jar {
@@ -30,7 +33,14 @@ private constructor(
3033
// Declared methods are likely to reference other declared members. Ensure all are removed.
3134
referencedMembers -= declaredMembers
3235

33-
return Jar(name, files, classes, declaredMembers.sorted(), referencedMembers.sorted())
36+
return Jar(
37+
filename = name,
38+
manifest = zip[MANIFEST_PATH].asInput().toUtf8(),
39+
files = files,
40+
classes = classes,
41+
declaredMembers = declaredMembers.sorted(),
42+
referencedMembers = referencedMembers.sorted(),
43+
)
3444
}
3545
}
3646
}

reports/src/main/kotlin/com/jakewharton/diffuse/diff/JarDiff.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ internal class JarDiff(
1313
) : BinaryDiff {
1414
val archive = ArchiveFilesDiff(oldJar.files, newJar.files, includeCompressed = false)
1515
val jars = JarsDiff(listOf(oldJar), oldMapping, listOf(newJar), newMapping)
16+
val manifest = JarManifestDiff(oldJar.manifest, newJar.manifest)
1617

17-
val changed = jars.changed || archive.changed
18+
val changed = jars.changed || archive.changed || manifest.changed
1819

1920
override fun toTextReport(summaryOnly: Boolean): Report = JarDiffTextReport(this, summaryOnly)
2021
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.jakewharton.diffuse.diff
2+
3+
import com.github.difflib.DiffUtils
4+
import com.github.difflib.UnifiedDiffUtils
5+
6+
internal class JarManifestDiff(oldManifest: String, newManifest: String) {
7+
val diff: List<String> =
8+
if (oldManifest == newManifest) {
9+
emptyList()
10+
} else {
11+
val oldLines = oldManifest.lines()
12+
val newLines = newManifest.lines()
13+
val diff = DiffUtils.diff(oldLines, newLines)
14+
UnifiedDiffUtils.generateUnifiedDiff(MANIFEST_PATH, MANIFEST_PATH, oldLines, diff, 1)
15+
}
16+
17+
val changed = diff.isNotEmpty()
18+
19+
internal companion object {
20+
const val MANIFEST_PATH = "META-INF/MANIFEST.MF"
21+
}
22+
}
23+
24+
internal fun JarManifestDiff.toDetailReport() = buildString {
25+
if (diff.isNotEmpty()) {
26+
appendLine()
27+
diff
28+
.drop(2) // Skip file name headers.
29+
.forEach(::appendLine)
30+
appendLine()
31+
}
32+
}

reports/src/main/kotlin/com/jakewharton/diffuse/report/text/JarDiffTextReport.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ internal class JarDiffTextReport(private val jarDiff: JarDiff, private val summa
2929
appendLine("=================")
3030
appendLine(jarDiff.archive.toDetailReport())
3131
}
32+
if (jarDiff.manifest.changed) {
33+
appendLine()
34+
appendLine("======================")
35+
appendLine("==== MANIFEST ====")
36+
appendLine("======================")
37+
appendLine(jarDiff.manifest.toDetailReport())
38+
}
3239
if (jarDiff.jars.changed) {
3340
appendLine()
3441
appendLine("=====================")
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.jakewharton.diffuse
2+
3+
import assertk.assertThat
4+
import assertk.assertions.contains
5+
import assertk.assertions.doesNotContain
6+
import com.jakewharton.diffuse.diff.JarDiff
7+
import com.jakewharton.diffuse.diff.JarManifestDiff.Companion.MANIFEST_PATH
8+
import com.jakewharton.diffuse.format.ApiMapping
9+
import com.jakewharton.diffuse.format.Jar
10+
import com.jakewharton.diffuse.format.Jar.Companion.toJar
11+
import com.jakewharton.diffuse.io.Input.Companion.asInput
12+
import java.io.ByteArrayOutputStream
13+
import java.util.jar.JarOutputStream
14+
import java.util.zip.ZipEntry
15+
import okio.ByteString.Companion.toByteString
16+
import org.junit.Test
17+
18+
class JarDiffTextReportTest {
19+
@Test
20+
fun manifestChanged() {
21+
val oldJar = jar("old.jar", "Manifest-Version: 1.0\nCreated-By: old")
22+
val newJar = jar("new.jar", "Manifest-Version: 1.0\nCreated-By: new")
23+
24+
val report =
25+
JarDiff(oldJar, ApiMapping.EMPTY, newJar, ApiMapping.EMPTY).toTextReport(false).toString()
26+
27+
assertThat(report)
28+
.contains(
29+
"""
30+
|======================
31+
|==== MANIFEST ====
32+
|======================
33+
|
34+
|@@ -1,2 +1,2 @@
35+
| Manifest-Version: 1.0
36+
|-Created-By: old
37+
|+Created-By: new
38+
"""
39+
.trimMargin()
40+
)
41+
}
42+
43+
@Test
44+
fun manifestNotChanged() {
45+
val oldJar = jar("old.jar", "Manifest-Version: 1.0\nCreated-By: same")
46+
val newJar = jar("new.jar", "Manifest-Version: 1.0\nCreated-By: same")
47+
48+
val report =
49+
JarDiff(oldJar, ApiMapping.EMPTY, newJar, ApiMapping.EMPTY).toTextReport(false).toString()
50+
51+
assertThat(report).doesNotContain("==== MANIFEST ====")
52+
}
53+
54+
private fun jar(name: String, manifestContent: String): Jar {
55+
val bytes = ByteArrayOutputStream()
56+
JarOutputStream(bytes).use { jar ->
57+
jar.putNextEntry(ZipEntry(MANIFEST_PATH))
58+
jar.write(manifestContent.toByteArray())
59+
jar.closeEntry()
60+
}
61+
return bytes.toByteArray().toByteString().asInput(name).toJar()
62+
}
63+
}

0 commit comments

Comments
 (0)