@matheusbsbs / matheus-bagliano / commits / 580fb25b7a
Fork 0

patch-id: Add support for mbox format

I have an alias that takes two arguments and compares their patch IDs. I would like to use to make sure I've tested exactly what I submit (patch by patch), like git patch-cmp origin/master.. file-being-sent However, I cannot do that because git patch-id is fooled by the "-- " trailer that git format-patch puts, or likely by the MIME boundary. This patch adds hunk parsing logic to git patch-id in order to detect an out of place "-" line and split the patch when it comes. In addition, commit ids in the "From " lines are considered and printed in the output. Signed-off-by: Paolo Bonzini <bonzini@gnu.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Paolo Bonzini committed Apr 19, 2010 at 10:46 UTC 580fb25b7a941267aad747afdc74b9b4a42e154a
2 files changed +90 -6
builtin/patch-id.c
+62 -6
@@ -28,10 +28,40 @@ static int remove_space(char *line)
28 return dst - line;
29 }
30
31 +static int scan_hunk_header(const char *p, int *p_before, int *p_after)
32 +{
33 + static const char digits[] = "0123456789";
34 + const char *q, *r;
35 + int n;
36 +
37 + q = p + 4;
38 + n = strspn(q, digits);
39 + if (q[n] == ',') {
40 + q += n + 1;
41 + n = strspn(q, digits);
42 + }
43 + if (n == 0 || q[n] != ' ' || q[n+1] != '+')
44 + return 0;
45 +
46 + r = q + n + 2;
47 + n = strspn(r, digits);
48 + if (r[n] == ',') {
49 + r += n + 1;
50 + n = strspn(r, digits);
51 + }
52 + if (n == 0)
53 + return 0;
54 +
55 + *p_before = atoi(q);
56 + *p_after = atoi(r);
57 + return 1;
58 +}
59 +
60 int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
61 {
62 static char line[1000];
63 int patchlen = 0, found_next = 0;
64 + int before = -1, after = -1;
65
66 while (fgets(line, sizeof(line), stdin) != NULL) {
67 char *p = line;
@@ -41,6 +71,8 @@ int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
71 p += 10;
72 else if (!memcmp(line, "commit ", 7))
73 p += 7;
74 + else if (!memcmp(line, "From ", 5))
75 + p += 5;
76
77 if (!get_sha1_hex(p, next_sha1)) {
78 found_next = 1;
@@ -51,13 +83,37 @@ int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
83 if (!patchlen && memcmp(line, "diff ", 5))
84 continue;
85
54 - /* Ignore git-diff index header */
55 - if (!memcmp(line, "index ", 6))
56 - continue;
86 + /* Parsing diff header? */
87 + if (before == -1) {
88 + if (!memcmp(line, "index ", 6))
89 + continue;
90 + else if (!memcmp(line, "--- ", 4))
91 + before = after = 1;
92 + else if (!isalpha(line[0]))
93 + break;
94 + }
95
58 - /* Ignore line numbers when computing the SHA1 of the patch */
59 - if (!memcmp(line, "@@ -", 4))
60 - continue;
96 + /* Looking for a valid hunk header? */
97 + if (before == 0 && after == 0) {
98 + if (!memcmp(line, "@@ -", 4)) {
99 + /* Parse next hunk, but ignore line numbers. */
100 + scan_hunk_header(line, &before, &after);
101 + continue;
102 + }
103 +
104 + /* Split at the end of the patch. */
105 + if (memcmp(line, "diff ", 5))
106 + break;
107 +
108 + /* Else we're parsing another header. */
109 + before = after = -1;
110 + }
111 +
112 + /* If we get here, we're inside a hunk. */
113 + if (line[0] == '-' || line[0] == ' ')
114 + before--;
115 + if (line[0] == '+' || line[0] == ' ')
116 + after--;
117
118 /* Compute the sha without whitespace */
119 len = remove_space(line);
t/t4204-patch-id.sh
+28
@@ -18,6 +18,11 @@ test_expect_success 'patch-id output is well-formed' '
18 grep "^[a-f0-9]\{40\} $(git rev-parse HEAD)$" output
19 '
20
21 +calc_patch_id () {
22 + git patch-id |
23 + sed "s# .*##" > patch-id_"$1"
24 +}
25 +
26 get_patch_id () {
27 git log -p -1 "$1" | git patch-id |
28 sed "s# .*##" > patch-id_"$1"
@@ -35,4 +40,27 @@ test_expect_success 'patch-id detects inequality' '
40 ! test_cmp patch-id_master patch-id_notsame
41 '
42
43 +test_expect_success 'patch-id supports git-format-patch output' '
44 + get_patch_id master &&
45 + git checkout same &&
46 + git format-patch -1 --stdout | calc_patch_id same &&
47 + test_cmp patch-id_master patch-id_same &&
48 + set `git format-patch -1 --stdout | git patch-id` &&
49 + test "$2" = `git rev-parse HEAD`
50 +'
51 +
52 +test_expect_success 'whitespace is irrelevant in footer' '
53 + get_patch_id master &&
54 + git checkout same &&
55 + git format-patch -1 --stdout | sed "s/ \$//" | calc_patch_id same &&
56 + test_cmp patch-id_master patch-id_same
57 +'
58 +
59 +test_expect_success 'patch-id supports git-format-patch MIME output' '
60 + get_patch_id master &&
61 + git checkout same &&
62 + git format-patch -1 --attach --stdout | calc_patch_id same &&
63 + test_cmp patch-id_master patch-id_same
64 +'
65 +
66 test_done