refs: add a concept of a reference transaction
[git] / builtin / update-ref.c
1 #include "cache.h"
2 #include "refs.h"
3 #include "builtin.h"
4 #include "parse-options.h"
5 #include "quote.h"
6 #include "argv-array.h"
7
8 static const char * const git_update_ref_usage[] = {
9         N_("git update-ref [options] -d <refname> [<oldval>]"),
10         N_("git update-ref [options]    <refname> <newval> [<oldval>]"),
11         N_("git update-ref [options] --stdin [-z]"),
12         NULL
13 };
14
15 static int updates_alloc;
16 static int updates_count;
17 static struct ref_update **updates;
18
19 static char line_termination = '\n';
20 static int update_flags;
21
22 static struct ref_update *update_alloc(void)
23 {
24         struct ref_update *update;
25
26         /* Allocate and zero-init a struct ref_update */
27         update = xcalloc(1, sizeof(*update));
28         ALLOC_GROW(updates, updates_count + 1, updates_alloc);
29         updates[updates_count++] = update;
30
31         /* Store and reset accumulated options */
32         update->flags = update_flags;
33         update_flags = 0;
34
35         return update;
36 }
37
38 /*
39  * Parse one whitespace- or NUL-terminated, possibly C-quoted argument
40  * and append the result to arg.  Return a pointer to the terminator.
41  * Die if there is an error in how the argument is C-quoted.  This
42  * function is only used if not -z.
43  */
44 static const char *parse_arg(const char *next, struct strbuf *arg)
45 {
46         if (*next == '"') {
47                 const char *orig = next;
48
49                 if (unquote_c_style(arg, next, &next))
50                         die("badly quoted argument: %s", orig);
51                 if (*next && !isspace(*next))
52                         die("unexpected character after quoted argument: %s", orig);
53         } else {
54                 while (*next && !isspace(*next))
55                         strbuf_addch(arg, *next++);
56         }
57
58         return next;
59 }
60
61 /*
62  * Parse the reference name immediately after "command SP".  If not
63  * -z, then handle C-quoting.  Return a pointer to a newly allocated
64  * string containing the name of the reference, or NULL if there was
65  * an error.  Update *next to point at the character that terminates
66  * the argument.  Die if C-quoting is malformed or the reference name
67  * is invalid.
68  */
69 static char *parse_refname(struct strbuf *input, const char **next)
70 {
71         struct strbuf ref = STRBUF_INIT;
72
73         if (line_termination) {
74                 /* Without -z, use the next argument */
75                 *next = parse_arg(*next, &ref);
76         } else {
77                 /* With -z, use everything up to the next NUL */
78                 strbuf_addstr(&ref, *next);
79                 *next += ref.len;
80         }
81
82         if (!ref.len) {
83                 strbuf_release(&ref);
84                 return NULL;
85         }
86
87         if (check_refname_format(ref.buf, REFNAME_ALLOW_ONELEVEL))
88                 die("invalid ref format: %s", ref.buf);
89
90         return strbuf_detach(&ref, NULL);
91 }
92
93 /*
94  * The value being parsed is <oldvalue> (as opposed to <newvalue>; the
95  * difference affects which error messages are generated):
96  */
97 #define PARSE_SHA1_OLD 0x01
98
99 /*
100  * For backwards compatibility, accept an empty string for update's
101  * <newvalue> in binary mode to be equivalent to specifying zeros.
102  */
103 #define PARSE_SHA1_ALLOW_EMPTY 0x02
104
105 /*
106  * Parse an argument separator followed by the next argument, if any.
107  * If there is an argument, convert it to a SHA-1, write it to sha1,
108  * set *next to point at the character terminating the argument, and
109  * return 0.  If there is no argument at all (not even the empty
110  * string), return 1 and leave *next unchanged.  If the value is
111  * provided but cannot be converted to a SHA-1, die.  flags can
112  * include PARSE_SHA1_OLD and/or PARSE_SHA1_ALLOW_EMPTY.
113  */
114 static int parse_next_sha1(struct strbuf *input, const char **next,
115                            unsigned char *sha1,
116                            const char *command, const char *refname,
117                            int flags)
118 {
119         struct strbuf arg = STRBUF_INIT;
120         int ret = 0;
121
122         if (*next == input->buf + input->len)
123                 goto eof;
124
125         if (line_termination) {
126                 /* Without -z, consume SP and use next argument */
127                 if (!**next || **next == line_termination)
128                         return 1;
129                 if (**next != ' ')
130                         die("%s %s: expected SP but got: %s",
131                             command, refname, *next);
132                 (*next)++;
133                 *next = parse_arg(*next, &arg);
134                 if (arg.len) {
135                         if (get_sha1(arg.buf, sha1))
136                                 goto invalid;
137                 } else {
138                         /* Without -z, an empty value means all zeros: */
139                         hashclr(sha1);
140                 }
141         } else {
142                 /* With -z, read the next NUL-terminated line */
143                 if (**next)
144                         die("%s %s: expected NUL but got: %s",
145                             command, refname, *next);
146                 (*next)++;
147                 if (*next == input->buf + input->len)
148                         goto eof;
149                 strbuf_addstr(&arg, *next);
150                 *next += arg.len;
151
152                 if (arg.len) {
153                         if (get_sha1(arg.buf, sha1))
154                                 goto invalid;
155                 } else if (flags & PARSE_SHA1_ALLOW_EMPTY) {
156                         /* With -z, treat an empty value as all zeros: */
157                         warning("%s %s: missing <newvalue>, treating as zero",
158                                 command, refname);
159                         hashclr(sha1);
160                 } else {
161                         /*
162                          * With -z, an empty non-required value means
163                          * unspecified:
164                          */
165                         ret = 1;
166                 }
167         }
168
169         strbuf_release(&arg);
170
171         return ret;
172
173  invalid:
174         die(flags & PARSE_SHA1_OLD ?
175             "%s %s: invalid <oldvalue>: %s" :
176             "%s %s: invalid <newvalue>: %s",
177             command, refname, arg.buf);
178
179  eof:
180         die(flags & PARSE_SHA1_OLD ?
181             "%s %s: unexpected end of input when reading <oldvalue>" :
182             "%s %s: unexpected end of input when reading <newvalue>",
183             command, refname);
184 }
185
186
187 /*
188  * The following five parse_cmd_*() functions parse the corresponding
189  * command.  In each case, next points at the character following the
190  * command name and the following space.  They each return a pointer
191  * to the character terminating the command, and die with an
192  * explanatory message if there are any parsing problems.  All of
193  * these functions handle either text or binary format input,
194  * depending on how line_termination is set.
195  */
196
197 static const char *parse_cmd_update(struct strbuf *input, const char *next)
198 {
199         struct ref_update *update;
200
201         update = update_alloc();
202
203         update->ref_name = parse_refname(input, &next);
204         if (!update->ref_name)
205                 die("update: missing <ref>");
206
207         if (parse_next_sha1(input, &next, update->new_sha1,
208                             "update", update->ref_name,
209                             PARSE_SHA1_ALLOW_EMPTY))
210                 die("update %s: missing <newvalue>", update->ref_name);
211
212         update->have_old = !parse_next_sha1(input, &next, update->old_sha1,
213                                             "update", update->ref_name,
214                                             PARSE_SHA1_OLD);
215
216         if (*next != line_termination)
217                 die("update %s: extra input: %s", update->ref_name, next);
218
219         return next;
220 }
221
222 static const char *parse_cmd_create(struct strbuf *input, const char *next)
223 {
224         struct ref_update *update;
225
226         update = update_alloc();
227
228         update->ref_name = parse_refname(input, &next);
229         if (!update->ref_name)
230                 die("create: missing <ref>");
231
232         if (parse_next_sha1(input, &next, update->new_sha1,
233                             "create", update->ref_name, 0))
234                 die("create %s: missing <newvalue>", update->ref_name);
235
236         if (is_null_sha1(update->new_sha1))
237                 die("create %s: zero <newvalue>", update->ref_name);
238
239         if (*next != line_termination)
240                 die("create %s: extra input: %s", update->ref_name, next);
241
242         return next;
243 }
244
245 static const char *parse_cmd_delete(struct strbuf *input, const char *next)
246 {
247         struct ref_update *update;
248
249         update = update_alloc();
250
251         update->ref_name = parse_refname(input, &next);
252         if (!update->ref_name)
253                 die("delete: missing <ref>");
254
255         if (parse_next_sha1(input, &next, update->old_sha1,
256                             "delete", update->ref_name, PARSE_SHA1_OLD)) {
257                 update->have_old = 0;
258         } else {
259                 if (is_null_sha1(update->old_sha1))
260                         die("delete %s: zero <oldvalue>", update->ref_name);
261                 update->have_old = 1;
262         }
263
264         if (*next != line_termination)
265                 die("delete %s: extra input: %s", update->ref_name, next);
266
267         return next;
268 }
269
270 static const char *parse_cmd_verify(struct strbuf *input, const char *next)
271 {
272         struct ref_update *update;
273
274         update = update_alloc();
275
276         update->ref_name = parse_refname(input, &next);
277         if (!update->ref_name)
278                 die("verify: missing <ref>");
279
280         if (parse_next_sha1(input, &next, update->old_sha1,
281                             "verify", update->ref_name, PARSE_SHA1_OLD)) {
282                 update->have_old = 0;
283         } else {
284                 hashcpy(update->new_sha1, update->old_sha1);
285                 update->have_old = 1;
286         }
287
288         if (*next != line_termination)
289                 die("verify %s: extra input: %s", update->ref_name, next);
290
291         return next;
292 }
293
294 static const char *parse_cmd_option(struct strbuf *input, const char *next)
295 {
296         if (!strncmp(next, "no-deref", 8) && next[8] == line_termination)
297                 update_flags |= REF_NODEREF;
298         else
299                 die("option unknown: %s", next);
300         return next + 8;
301 }
302
303 static void update_refs_stdin(void)
304 {
305         struct strbuf input = STRBUF_INIT;
306         const char *next;
307
308         if (strbuf_read(&input, 0, 1000) < 0)
309                 die_errno("could not read from stdin");
310         next = input.buf;
311         /* Read each line dispatch its command */
312         while (next < input.buf + input.len) {
313                 if (*next == line_termination)
314                         die("empty command in input");
315                 else if (isspace(*next))
316                         die("whitespace before command: %s", next);
317                 else if (starts_with(next, "update "))
318                         next = parse_cmd_update(&input, next + 7);
319                 else if (starts_with(next, "create "))
320                         next = parse_cmd_create(&input, next + 7);
321                 else if (starts_with(next, "delete "))
322                         next = parse_cmd_delete(&input, next + 7);
323                 else if (starts_with(next, "verify "))
324                         next = parse_cmd_verify(&input, next + 7);
325                 else if (starts_with(next, "option "))
326                         next = parse_cmd_option(&input, next + 7);
327                 else
328                         die("unknown command: %s", next);
329
330                 next++;
331         }
332
333         strbuf_release(&input);
334 }
335
336 int cmd_update_ref(int argc, const char **argv, const char *prefix)
337 {
338         const char *refname, *oldval, *msg = NULL;
339         unsigned char sha1[20], oldsha1[20];
340         int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0, flags = 0;
341         struct option options[] = {
342                 OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
343                 OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
344                 OPT_BOOL( 0 , "no-deref", &no_deref,
345                                         N_("update <refname> not the one it points to")),
346                 OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")),
347                 OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")),
348                 OPT_END(),
349         };
350
351         git_config(git_default_config, NULL);
352         argc = parse_options(argc, argv, prefix, options, git_update_ref_usage,
353                              0);
354         if (msg && !*msg)
355                 die("Refusing to perform update with empty message.");
356
357         if (read_stdin) {
358                 if (delete || no_deref || argc > 0)
359                         usage_with_options(git_update_ref_usage, options);
360                 if (end_null)
361                         line_termination = '\0';
362                 update_refs_stdin();
363                 return update_refs(msg, updates, updates_count,
364                                    UPDATE_REFS_DIE_ON_ERR);
365         }
366
367         if (end_null)
368                 usage_with_options(git_update_ref_usage, options);
369
370         if (delete) {
371                 if (argc < 1 || argc > 2)
372                         usage_with_options(git_update_ref_usage, options);
373                 refname = argv[0];
374                 oldval = argv[1];
375         } else {
376                 const char *value;
377                 if (argc < 2 || argc > 3)
378                         usage_with_options(git_update_ref_usage, options);
379                 refname = argv[0];
380                 value = argv[1];
381                 oldval = argv[2];
382                 if (get_sha1(value, sha1))
383                         die("%s: not a valid SHA1", value);
384         }
385
386         hashclr(oldsha1); /* all-zero hash in case oldval is the empty string */
387         if (oldval && *oldval && get_sha1(oldval, oldsha1))
388                 die("%s: not a valid old SHA1", oldval);
389
390         if (no_deref)
391                 flags = REF_NODEREF;
392         if (delete)
393                 return delete_ref(refname, oldval ? oldsha1 : NULL, flags);
394         else
395                 return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
396                                   flags, UPDATE_REFS_DIE_ON_ERR);
397 }