|
| 1 | +import com.github.difflib.DiffUtils; |
| 2 | +import com.github.difflib.UnifiedDiffUtils; |
| 3 | +import com.github.difflib.patch.Patch; |
| 4 | +import com.github.difflib.patch.PatchFailedException; |
1 | 5 | import java.io.*; |
2 | 6 | import java.nio.file.*; |
| 7 | +import java.util.*; |
3 | 8 | import java.util.zip.*; |
4 | 9 |
|
5 | 10 | public class Patcher { |
6 | 11 |
|
7 | 12 | public static void apply(File dir, File patch) throws Exception { |
8 | 13 | if (!patch.exists()) return; |
9 | 14 |
|
10 | | - Utils.run(dir, "patch", "-p1", "-i", patch.getAbsolutePath()); |
| 15 | + for (var e : parse(patch).entrySet()) { |
| 16 | + File f = new File(dir, e.getKey()); |
| 17 | + if (!f.exists()) throw new RuntimeException("File not found: " + e.getKey()); |
| 18 | + |
| 19 | + List<String> orig = Files.readAllLines(f.toPath()); |
| 20 | + Patch<String> p = UnifiedDiffUtils.parseUnifiedDiff(e.getValue()); |
| 21 | + |
| 22 | + try { |
| 23 | + Files.write(f.toPath(), DiffUtils.patch(orig, p)); |
| 24 | + } catch (PatchFailedException ex) { |
| 25 | + throw new RuntimeException("Patch failed for " + e.getKey() + ": " + ex.getMessage()); |
| 26 | + } |
| 27 | + } |
11 | 28 | } |
12 | 29 |
|
13 | 30 | public static void unapply(File dir, File patch) throws Exception { |
14 | 31 | if (!patch.exists()) return; |
15 | 32 |
|
16 | | - Utils.run(dir, "patch", "-R", "-p1", "-i", patch.getAbsolutePath()); |
| 33 | + for (var e : parse(patch).entrySet()) { |
| 34 | + File f = new File(dir, e.getKey()); |
| 35 | + if (!f.exists()) throw new RuntimeException("File not found: " + e.getKey()); |
| 36 | + |
| 37 | + List<String> cur = Files.readAllLines(f.toPath()); |
| 38 | + Patch<String> p = UnifiedDiffUtils.parseUnifiedDiff(e.getValue()); |
| 39 | + List<String> result = DiffUtils.unpatch(cur, p); |
| 40 | + |
| 41 | + try { |
| 42 | + List<String> check = DiffUtils.patch(result, p); |
| 43 | + if (!check.equals(cur)) |
| 44 | + throw new RuntimeException("Revert failed for " + e.getKey() + ": mismatch"); |
| 45 | + } catch (PatchFailedException ex) { |
| 46 | + throw new RuntimeException("Revert failed for " + e.getKey() + ": " + ex.getMessage()); |
| 47 | + } |
| 48 | + |
| 49 | + Files.write(f.toPath(), result); |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + private static Map<String, List<String>> parse(File patch) throws IOException { |
| 54 | + Map<String, List<String>> m = new LinkedHashMap<>(); |
| 55 | + List<String> lines = Files.readAllLines(patch.toPath()); |
| 56 | + List<String> cur = null; |
| 57 | + String file = null; |
| 58 | + |
| 59 | + for (String line : lines) { |
| 60 | + if (line.startsWith("--- a/")) { |
| 61 | + if (cur != null && file != null) m.put(file, cur); |
| 62 | + file = line.substring(6).split("\t")[0]; |
| 63 | + |
| 64 | + cur = new ArrayList<>(); |
| 65 | + cur.add(line); |
| 66 | + } else if (cur != null) { |
| 67 | + cur.add(line); |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + if (cur != null && file != null) m.put(file, cur); |
| 72 | + |
| 73 | + return m; |
17 | 74 | } |
18 | 75 |
|
19 | 76 | public static void snap(File src, File dest) throws IOException { |
@@ -43,22 +100,32 @@ public static void diff(File base, File cur, File out, boolean isZip) throws Exc |
43 | 100 |
|
44 | 101 | StringBuilder sb = new StringBuilder(); |
45 | 102 | for (String pkg : new String[]{"com", "net"}) { |
46 | | - Path pkgPath = tmp.resolve(pkg); |
47 | | - if (!Files.exists(pkgPath)) continue; |
| 103 | + Path d = tmp.resolve(pkg); |
| 104 | + if (!Files.exists(d)) continue; |
48 | 105 |
|
49 | | - Files.walk(pkgPath).filter(p -> p.toString().endsWith(".java")).forEach(p -> { |
| 106 | + Files.walk(d).filter(p -> p.toString().endsWith(".java")).forEach(p -> { |
50 | 107 | String rel = tmp.relativize(p).toString(); |
51 | | - File curFile = new File(cur, rel); |
52 | | - if (!curFile.exists()) return; |
| 108 | + File f = new File(cur, rel); |
| 109 | + if (!f.exists()) return; |
53 | 110 |
|
54 | 111 | try { |
55 | | - String d = Utils.runOut(tmp.toFile(), "diff", "-u", rel, curFile.getAbsolutePath()); |
56 | | - if (!d.isEmpty()) { |
57 | | - d = d.replaceFirst("--- " + rel, "--- a/" + rel); |
58 | | - d = d.replaceFirst("\\+\\+\\+ .*", "+++ b/" + rel); |
59 | | - sb.append(d); |
| 112 | + List<String> a = Files.readAllLines(p); |
| 113 | + List<String> b = Files.readAllLines(f.toPath()); |
| 114 | + Patch<String> patch = DiffUtils.diff(a, b); |
| 115 | + |
| 116 | + if (!patch.getDeltas().isEmpty()) { |
| 117 | + List<String> u = UnifiedDiffUtils.generateUnifiedDiff(rel, rel, a, patch, 3); |
| 118 | + for (int i = 0; i < u.size(); i++) { |
| 119 | + String line = u.get(i); |
| 120 | + if (line.startsWith("--- ")) u.set(i, "--- a/" + rel); |
| 121 | + else if (line.startsWith("+++ ")) u.set(i, "+++ b/" + rel); |
| 122 | + } |
| 123 | + |
| 124 | + for (String line : u) sb.append(line).append("\n"); |
60 | 125 | } |
61 | | - } catch (Exception e) {} |
| 126 | + } catch (IOException e) { |
| 127 | + throw new UncheckedIOException(e); |
| 128 | + } |
62 | 129 | }); |
63 | 130 | } |
64 | 131 |
|
|
0 commit comments