blob: 881fcf32732caf810789c254d31eb05058ca0187 [file] [log] [blame]
brian m. carlson36261e42019-08-18 20:04:03 +00001#include "cache.h"
Stephen Boydc2e86ad2011-03-22 00:51:05 -07002#include "builtin.h"
Brandon Williamsb2141fc2017-06-14 11:07:36 -07003#include "config.h"
Stephen Boyda8f68552019-04-26 16:51:57 -07004#include "diff.h"
Linus Torvaldsf9767222005-06-23 15:06:04 -07005
brian m. carlson1a876a62015-03-13 23:39:35 +00006static void flush_current_id(int patchlen, struct object_id *id, struct object_id *result)
Linus Torvaldsf9767222005-06-23 15:06:04 -07007{
René Scharfe4507ecc2019-12-07 20:16:51 +01008 if (patchlen)
9 printf("%s %s\n", oid_to_hex(result), oid_to_hex(id));
Linus Torvaldsf9767222005-06-23 15:06:04 -070010}
11
12static int remove_space(char *line)
13{
14 char *src = line;
15 char *dst = line;
16 unsigned char c;
17
18 while ((c = *src++) != '\0') {
19 if (!isspace(c))
20 *dst++ = c;
21 }
22 return dst - line;
23}
24
Paolo Bonzini580fb252010-04-19 10:46:14 +020025static int scan_hunk_header(const char *p, int *p_before, int *p_after)
26{
27 static const char digits[] = "0123456789";
28 const char *q, *r;
29 int n;
30
31 q = p + 4;
32 n = strspn(q, digits);
33 if (q[n] == ',') {
34 q += n + 1;
Jerry Zhang757e75c2022-02-01 20:19:45 -080035 *p_before = atoi(q);
Paolo Bonzini580fb252010-04-19 10:46:14 +020036 n = strspn(q, digits);
Jerry Zhang757e75c2022-02-01 20:19:45 -080037 } else {
38 *p_before = 1;
Paolo Bonzini580fb252010-04-19 10:46:14 +020039 }
Jerry Zhang757e75c2022-02-01 20:19:45 -080040
Paolo Bonzini580fb252010-04-19 10:46:14 +020041 if (n == 0 || q[n] != ' ' || q[n+1] != '+')
42 return 0;
43
44 r = q + n + 2;
45 n = strspn(r, digits);
46 if (r[n] == ',') {
47 r += n + 1;
Jerry Zhang757e75c2022-02-01 20:19:45 -080048 *p_after = atoi(r);
Paolo Bonzini580fb252010-04-19 10:46:14 +020049 n = strspn(r, digits);
Jerry Zhang757e75c2022-02-01 20:19:45 -080050 } else {
51 *p_after = 1;
Paolo Bonzini580fb252010-04-19 10:46:14 +020052 }
53 if (n == 0)
54 return 0;
55
Paolo Bonzini580fb252010-04-19 10:46:14 +020056 return 1;
57}
58
brian m. carlson1a876a62015-03-13 23:39:35 +000059static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
Michael S. Tsirkin30e12b92014-04-27 21:15:44 +030060 struct strbuf *line_buf, int stable)
Linus Torvaldsf9767222005-06-23 15:06:04 -070061{
Paolo Bonzini9ae144f2010-04-19 10:46:13 +020062 int patchlen = 0, found_next = 0;
Paolo Bonzini580fb252010-04-19 10:46:14 +020063 int before = -1, after = -1;
brian m. carlson36261e42019-08-18 20:04:03 +000064 git_hash_ctx ctx;
Michael S. Tsirkin30e12b92014-04-27 21:15:44 +030065
brian m. carlson36261e42019-08-18 20:04:03 +000066 the_hash_algo->init_fn(&ctx);
brian m. carlson1a876a62015-03-13 23:39:35 +000067 oidclr(result);
Linus Torvaldsf9767222005-06-23 15:06:04 -070068
Michael Schubertb9ab8102011-09-21 14:42:22 +020069 while (strbuf_getwholeline(line_buf, stdin, '\n') != EOF) {
70 char *line = line_buf->buf;
René Scharfe2bb73ae2016-05-28 18:20:23 +020071 const char *p = line;
Linus Torvaldsf9767222005-06-23 15:06:04 -070072 int len;
73
René Scharfe2bb73ae2016-05-28 18:20:23 +020074 if (!skip_prefix(line, "diff-tree ", &p) &&
75 !skip_prefix(line, "commit ", &p) &&
76 !skip_prefix(line, "From ", &p) &&
77 starts_with(line, "\\ ") && 12 < strlen(line))
Michael J Gruber2485eab2011-02-17 08:44:42 +010078 continue;
Linus Torvaldsf9767222005-06-23 15:06:04 -070079
brian m. carlson1a876a62015-03-13 23:39:35 +000080 if (!get_oid_hex(p, next_oid)) {
Paolo Bonzini9ae144f2010-04-19 10:46:13 +020081 found_next = 1;
82 break;
Linus Torvaldsf9767222005-06-23 15:06:04 -070083 }
84
85 /* Ignore commit comments */
René Scharfe2bb73ae2016-05-28 18:20:23 +020086 if (!patchlen && !starts_with(line, "diff "))
Linus Torvaldsf9767222005-06-23 15:06:04 -070087 continue;
88
Paolo Bonzini580fb252010-04-19 10:46:14 +020089 /* Parsing diff header? */
90 if (before == -1) {
René Scharfe2bb73ae2016-05-28 18:20:23 +020091 if (starts_with(line, "index "))
Paolo Bonzini580fb252010-04-19 10:46:14 +020092 continue;
René Scharfe2bb73ae2016-05-28 18:20:23 +020093 else if (starts_with(line, "--- "))
Paolo Bonzini580fb252010-04-19 10:46:14 +020094 before = after = 1;
95 else if (!isalpha(line[0]))
96 break;
97 }
Kai Ruemmler9fabded2005-10-09 16:52:50 -070098
Paolo Bonzini580fb252010-04-19 10:46:14 +020099 /* Looking for a valid hunk header? */
100 if (before == 0 && after == 0) {
René Scharfe2bb73ae2016-05-28 18:20:23 +0200101 if (starts_with(line, "@@ -")) {
Paolo Bonzini580fb252010-04-19 10:46:14 +0200102 /* Parse next hunk, but ignore line numbers. */
103 scan_hunk_header(line, &before, &after);
104 continue;
105 }
106
107 /* Split at the end of the patch. */
René Scharfe2bb73ae2016-05-28 18:20:23 +0200108 if (!starts_with(line, "diff "))
Paolo Bonzini580fb252010-04-19 10:46:14 +0200109 break;
110
111 /* Else we're parsing another header. */
Michael S. Tsirkin30e12b92014-04-27 21:15:44 +0300112 if (stable)
113 flush_one_hunk(result, &ctx);
Paolo Bonzini580fb252010-04-19 10:46:14 +0200114 before = after = -1;
115 }
116
117 /* If we get here, we're inside a hunk. */
118 if (line[0] == '-' || line[0] == ' ')
119 before--;
120 if (line[0] == '+' || line[0] == ' ')
121 after--;
Linus Torvaldsf9767222005-06-23 15:06:04 -0700122
123 /* Compute the sha without whitespace */
124 len = remove_space(line);
125 patchlen += len;
brian m. carlson36261e42019-08-18 20:04:03 +0000126 the_hash_algo->update_fn(&ctx, line, len);
Linus Torvaldsf9767222005-06-23 15:06:04 -0700127 }
Paolo Bonzini9ae144f2010-04-19 10:46:13 +0200128
129 if (!found_next)
brian m. carlson1a876a62015-03-13 23:39:35 +0000130 oidclr(next_oid);
Paolo Bonzini9ae144f2010-04-19 10:46:13 +0200131
Michael S. Tsirkin30e12b92014-04-27 21:15:44 +0300132 flush_one_hunk(result, &ctx);
133
Paolo Bonzini9ae144f2010-04-19 10:46:13 +0200134 return patchlen;
135}
136
Michael S. Tsirkin30e12b92014-04-27 21:15:44 +0300137static void generate_id_list(int stable)
Paolo Bonzini9ae144f2010-04-19 10:46:13 +0200138{
brian m. carlson1a876a62015-03-13 23:39:35 +0000139 struct object_id oid, n, result;
Paolo Bonzini9ae144f2010-04-19 10:46:13 +0200140 int patchlen;
Michael Schubertb9ab8102011-09-21 14:42:22 +0200141 struct strbuf line_buf = STRBUF_INIT;
Paolo Bonzini9ae144f2010-04-19 10:46:13 +0200142
brian m. carlson1a876a62015-03-13 23:39:35 +0000143 oidclr(&oid);
Paolo Bonzini9ae144f2010-04-19 10:46:13 +0200144 while (!feof(stdin)) {
brian m. carlson1a876a62015-03-13 23:39:35 +0000145 patchlen = get_one_patchid(&n, &result, &line_buf, stable);
146 flush_current_id(patchlen, &oid, &result);
147 oidcpy(&oid, &n);
Paolo Bonzini9ae144f2010-04-19 10:46:13 +0200148 }
Michael Schubertb9ab8102011-09-21 14:42:22 +0200149 strbuf_release(&line_buf);
Linus Torvaldsf9767222005-06-23 15:06:04 -0700150}
151
Junio C Hamano33e8fc82015-10-16 11:27:42 -0700152static const char patch_id_usage[] = "git patch-id [--stable | --unstable]";
Michael S. Tsirkin30e12b92014-04-27 21:15:44 +0300153
154static int git_patch_id_config(const char *var, const char *value, void *cb)
155{
156 int *stable = cb;
157
158 if (!strcmp(var, "patchid.stable")) {
159 *stable = git_config_bool(var, value);
160 return 0;
161 }
162
163 return git_default_config(var, value, cb);
164}
Linus Torvaldsf9767222005-06-23 15:06:04 -0700165
Linus Torvaldsdedc0ec2010-01-21 20:31:25 -0800166int cmd_patch_id(int argc, const char **argv, const char *prefix)
Linus Torvaldsf9767222005-06-23 15:06:04 -0700167{
Michael S. Tsirkin30e12b92014-04-27 21:15:44 +0300168 int stable = -1;
169
170 git_config(git_patch_id_config, &stable);
171
172 /* If nothing is set, default to unstable. */
173 if (stable < 0)
174 stable = 0;
175
176 if (argc == 2 && !strcmp(argv[1], "--stable"))
177 stable = 1;
178 else if (argc == 2 && !strcmp(argv[1], "--unstable"))
179 stable = 0;
180 else if (argc != 1)
Linus Torvaldsf9767222005-06-23 15:06:04 -0700181 usage(patch_id_usage);
182
Michael S. Tsirkin30e12b92014-04-27 21:15:44 +0300183 generate_id_list(stable);
Linus Torvaldsf9767222005-06-23 15:06:04 -0700184 return 0;
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700185}