Skip to content

Commit 5a3f718

Browse files
committed
PR feedback
1 parent e50ae77 commit 5a3f718

File tree

2 files changed

+69
-20
lines changed

2 files changed

+69
-20
lines changed

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/dependencies/patches/PatcherInfo.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,23 @@
1616
import java.util.HexFormat;
1717
import java.util.function.Function;
1818

19-
public record PatcherInfo(String jarEntryName, byte[] classSha256, Function<ClassWriter, ClassVisitor> visitorFactory) {
19+
public final class PatcherInfo {
20+
private final String jarEntryName;
21+
private final byte[] classSha256;
22+
private final Function<ClassWriter, ClassVisitor> visitorFactory;
23+
24+
private PatcherInfo(String jarEntryName, byte[] classSha256, Function<ClassWriter, ClassVisitor> visitorFactory) {
25+
this.jarEntryName = jarEntryName;
26+
this.classSha256 = classSha256;
27+
this.visitorFactory = visitorFactory;
28+
}
29+
2030
/**
2131
* Creates a patcher info entry, linking a jar entry path name and its SHA256 digest to a patcher factory (a factory to create an ASM
2232
* visitor)
23-
* @param jarEntryName the jar entry path, as a string
24-
* @param classSha256 the SHA256 digest of the class bytes, as a HEX string
33+
*
34+
* @param jarEntryName the jar entry path, as a string
35+
* @param classSha256 the SHA256 digest of the class bytes, as a HEX string
2536
* @param visitorFactory the factory to create an ASM visitor from a ASM writer
2637
*/
2738
public static PatcherInfo classPatcher(String jarEntryName, String classSha256, Function<ClassWriter, ClassVisitor> visitorFactory) {
@@ -31,4 +42,16 @@ public static PatcherInfo classPatcher(String jarEntryName, String classSha256,
3142
boolean matches(byte[] otherClassSha256) {
3243
return Arrays.equals(this.classSha256, otherClassSha256);
3344
}
45+
46+
public String jarEntryName() {
47+
return jarEntryName;
48+
}
49+
50+
public byte[] classSha256() {
51+
return classSha256;
52+
}
53+
54+
public ClassVisitor createVisitor(ClassWriter classWriter) {
55+
return visitorFactory.apply(classWriter);
56+
}
3457
}

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/dependencies/patches/Utils.java

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.InputStream;
1919
import java.security.MessageDigest;
2020
import java.security.NoSuchAlgorithmException;
21+
import java.util.ArrayList;
2122
import java.util.Collection;
2223
import java.util.Enumeration;
2324
import java.util.HexFormat;
@@ -43,9 +44,26 @@ public class Utils {
4344
}
4445
}
4546

47+
private record MismatchInfo(String jarEntryName, String expectedClassSha256, String foundClassSha256) {
48+
@Override
49+
public String toString() {
50+
return "[class='"
51+
+ jarEntryName
52+
+ '\''
53+
+ ", expected='"
54+
+ expectedClassSha256
55+
+ '\''
56+
+ ", found='"
57+
+ foundClassSha256
58+
+ '\''
59+
+ ']';
60+
}
61+
}
62+
4663
/**
47-
* Patches the classes in the input JAR file, using the collection of patchers. If the patcher info specify a SHA256 digest, and
48-
* the class to patch does not match it, an IllegalArgumentException is thrown.
64+
* Patches the classes in the input JAR file, using the collection of patchers. Each patcher specifies a target class (its jar entry
65+
* name) and the SHA256 digest on the class bytes.
66+
* This digest is checked against the class bytes in the JAR, and if it does not match, an IllegalArgumentException is thrown.
4967
* If the input file does not contain all the classes to patch specified in the patcher info collection, an IllegalArgumentException
5068
* is also thrown.
5169
* @param inputFile the JAR file to patch
@@ -54,6 +72,7 @@ public class Utils {
5472
*/
5573
public static void patchJar(File inputFile, File outputFile, Collection<PatcherInfo> patchers) {
5674
var classPatchers = patchers.stream().collect(Collectors.toMap(PatcherInfo::jarEntryName, Function.identity()));
75+
var mismatchedClasses = new ArrayList<MismatchInfo>();
5776
try (JarFile jarFile = new JarFile(inputFile); JarOutputStream jos = new JarOutputStream(new FileOutputStream(outputFile))) {
5877
Enumeration<JarEntry> entries = jarFile.entries();
5978
while (entries.hasMoreElements()) {
@@ -67,27 +86,20 @@ public static void patchJar(File inputFile, File outputFile, Collection<PatcherI
6786
byte[] classToPatch = jarFile.getInputStream(entry).readAllBytes();
6887
var classSha256 = SHA_256.digest(classToPatch);
6988

70-
if (classPatcher.matches(classSha256) == false) {
71-
throw new IllegalArgumentException(
72-
String.format(
73-
Locale.ROOT,
74-
"""
75-
Error patching JAR [%s]: SHA256 digest mismatch for class [%s] (expected: [%s], \
76-
found: [%s]). This JAR was updated to a version that contains a different class, \
77-
for which this patcher was not designed for. Please check if the patcher still \
78-
applies correctly to this class, and update its SHA256 digest.""",
79-
inputFile.getName(),
89+
if (classPatcher.matches(classSha256)) {
90+
ClassReader classReader = new ClassReader(classToPatch);
91+
ClassWriter classWriter = new ClassWriter(classReader, COMPUTE_MAXS | COMPUTE_FRAMES);
92+
classReader.accept(classPatcher.createVisitor(classWriter), 0);
93+
jos.write(classWriter.toByteArray());
94+
} else {
95+
mismatchedClasses.add(
96+
new MismatchInfo(
8097
classPatcher.jarEntryName(),
8198
HexFormat.of().formatHex(classPatcher.classSha256()),
8299
HexFormat.of().formatHex(classSha256)
83100
)
84101
);
85102
}
86-
87-
ClassReader classReader = new ClassReader(classToPatch);
88-
ClassWriter classWriter = new ClassWriter(classReader, COMPUTE_MAXS | COMPUTE_FRAMES);
89-
classReader.accept(classPatcher.visitorFactory().apply(classWriter), 0);
90-
jos.write(classWriter.toByteArray());
91103
} else {
92104
// Read the entry's data and write it to the new JAR
93105
try (InputStream is = jarFile.getInputStream(entry)) {
@@ -100,6 +112,20 @@ public static void patchJar(File inputFile, File outputFile, Collection<PatcherI
100112
throw new RuntimeException(ex);
101113
}
102114

115+
if (mismatchedClasses.isEmpty() == false) {
116+
throw new IllegalArgumentException(
117+
String.format(
118+
Locale.ROOT,
119+
"""
120+
Error patching JAR [%s]: SHA256 digest mismatch (%s). This JAR was updated to a version that contains different \
121+
classes, for which this patcher was not designed. Please check if the patcher still \
122+
applies correctly, and update the SHA256 digest(s).""",
123+
inputFile.getName(),
124+
mismatchedClasses.stream().map(MismatchInfo::toString).collect(Collectors.joining())
125+
)
126+
);
127+
}
128+
103129
if (classPatchers.isEmpty() == false) {
104130
throw new IllegalArgumentException(
105131
String.format(

0 commit comments

Comments
 (0)