2
2
#include "refs.h"
3
3
#include "builtin.h"
4
4
#include "parse-options.h"
5
+ #include "quote.h"
6
+ #include "argv-array.h"
5
7
6
8
static const char * const git_update_ref_usage [] = {
7
9
N_ ("git update-ref [options] -d <refname> [<oldval>]" ),
8
10
N_ ("git update-ref [options] <refname> <newval> [<oldval>]" ),
11
+ N_ ("git update-ref [options] --stdin [-z]" ),
9
12
NULL
10
13
};
11
14
15
+ static int updates_alloc ;
16
+ static int updates_count ;
17
+ static const 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
+ static void update_store_ref_name (struct ref_update * update ,
39
+ const char * ref_name )
40
+ {
41
+ if (check_refname_format (ref_name , REFNAME_ALLOW_ONELEVEL ))
42
+ die ("invalid ref format: %s" , ref_name );
43
+ update -> ref_name = xstrdup (ref_name );
44
+ }
45
+
46
+ static void update_store_new_sha1 (struct ref_update * update ,
47
+ const char * newvalue )
48
+ {
49
+ if (* newvalue && get_sha1 (newvalue , update -> new_sha1 ))
50
+ die ("invalid new value for ref %s: %s" ,
51
+ update -> ref_name , newvalue );
52
+ }
53
+
54
+ static void update_store_old_sha1 (struct ref_update * update ,
55
+ const char * oldvalue )
56
+ {
57
+ if (* oldvalue && get_sha1 (oldvalue , update -> old_sha1 ))
58
+ die ("invalid old value for ref %s: %s" ,
59
+ update -> ref_name , oldvalue );
60
+
61
+ /* We have an old value if non-empty, or if empty without -z */
62
+ update -> have_old = * oldvalue || line_termination ;
63
+ }
64
+
65
+ static const char * parse_arg (const char * next , struct strbuf * arg )
66
+ {
67
+ /* Parse SP-terminated, possibly C-quoted argument */
68
+ if (* next != '"' )
69
+ while (* next && !isspace (* next ))
70
+ strbuf_addch (arg , * next ++ );
71
+ else if (unquote_c_style (arg , next , & next ))
72
+ die ("badly quoted argument: %s" , next );
73
+
74
+ /* Return position after the argument */
75
+ return next ;
76
+ }
77
+
78
+ static const char * parse_first_arg (const char * next , struct strbuf * arg )
79
+ {
80
+ /* Parse argument immediately after "command SP" */
81
+ strbuf_reset (arg );
82
+ if (line_termination ) {
83
+ /* Without -z, use the next argument */
84
+ next = parse_arg (next , arg );
85
+ } else {
86
+ /* With -z, use rest of first NUL-terminated line */
87
+ strbuf_addstr (arg , next );
88
+ next = next + arg -> len ;
89
+ }
90
+ return next ;
91
+ }
92
+
93
+ static const char * parse_next_arg (const char * next , struct strbuf * arg )
94
+ {
95
+ /* Parse next SP-terminated or NUL-terminated argument, if any */
96
+ strbuf_reset (arg );
97
+ if (line_termination ) {
98
+ /* Without -z, consume SP and use next argument */
99
+ if (!* next )
100
+ return NULL ;
101
+ if (* next != ' ' )
102
+ die ("expected SP but got: %s" , next );
103
+ next = parse_arg (next + 1 , arg );
104
+ } else {
105
+ /* With -z, read the next NUL-terminated line */
106
+ if (* next )
107
+ die ("expected NUL but got: %s" , next );
108
+ if (strbuf_getline (arg , stdin , '\0' ) == EOF )
109
+ return NULL ;
110
+ next = arg -> buf + arg -> len ;
111
+ }
112
+ return next ;
113
+ }
114
+
115
+ static void parse_cmd_update (const char * next )
116
+ {
117
+ struct strbuf ref = STRBUF_INIT ;
118
+ struct strbuf newvalue = STRBUF_INIT ;
119
+ struct strbuf oldvalue = STRBUF_INIT ;
120
+ struct ref_update * update ;
121
+
122
+ update = update_alloc ();
123
+
124
+ if ((next = parse_first_arg (next , & ref )) != NULL && ref .buf [0 ])
125
+ update_store_ref_name (update , ref .buf );
126
+ else
127
+ die ("update line missing <ref>" );
128
+
129
+ if ((next = parse_next_arg (next , & newvalue )) != NULL )
130
+ update_store_new_sha1 (update , newvalue .buf );
131
+ else
132
+ die ("update %s missing <newvalue>" , ref .buf );
133
+
134
+ if ((next = parse_next_arg (next , & oldvalue )) != NULL )
135
+ update_store_old_sha1 (update , oldvalue .buf );
136
+ else if (!line_termination )
137
+ die ("update %s missing [<oldvalue>] NUL" , ref .buf );
138
+
139
+ if (next && * next )
140
+ die ("update %s has extra input: %s" , ref .buf , next );
141
+ }
142
+
143
+ static void parse_cmd_create (const char * next )
144
+ {
145
+ struct strbuf ref = STRBUF_INIT ;
146
+ struct strbuf newvalue = STRBUF_INIT ;
147
+ struct ref_update * update ;
148
+
149
+ update = update_alloc ();
150
+
151
+ if ((next = parse_first_arg (next , & ref )) != NULL && ref .buf [0 ])
152
+ update_store_ref_name (update , ref .buf );
153
+ else
154
+ die ("create line missing <ref>" );
155
+
156
+ if ((next = parse_next_arg (next , & newvalue )) != NULL )
157
+ update_store_new_sha1 (update , newvalue .buf );
158
+ else
159
+ die ("create %s missing <newvalue>" , ref .buf );
160
+ if (is_null_sha1 (update -> new_sha1 ))
161
+ die ("create %s given zero new value" , ref .buf );
162
+
163
+ if (next && * next )
164
+ die ("create %s has extra input: %s" , ref .buf , next );
165
+ }
166
+
167
+ static void parse_cmd_delete (const char * next )
168
+ {
169
+ struct strbuf ref = STRBUF_INIT ;
170
+ struct strbuf oldvalue = STRBUF_INIT ;
171
+ struct ref_update * update ;
172
+
173
+ update = update_alloc ();
174
+
175
+ if ((next = parse_first_arg (next , & ref )) != NULL && ref .buf [0 ])
176
+ update_store_ref_name (update , ref .buf );
177
+ else
178
+ die ("delete line missing <ref>" );
179
+
180
+ if ((next = parse_next_arg (next , & oldvalue )) != NULL )
181
+ update_store_old_sha1 (update , oldvalue .buf );
182
+ else if (!line_termination )
183
+ die ("delete %s missing [<oldvalue>] NUL" , ref .buf );
184
+ if (update -> have_old && is_null_sha1 (update -> old_sha1 ))
185
+ die ("delete %s given zero old value" , ref .buf );
186
+
187
+ if (next && * next )
188
+ die ("delete %s has extra input: %s" , ref .buf , next );
189
+ }
190
+
191
+ static void parse_cmd_verify (const char * next )
192
+ {
193
+ struct strbuf ref = STRBUF_INIT ;
194
+ struct strbuf value = STRBUF_INIT ;
195
+ struct ref_update * update ;
196
+
197
+ update = update_alloc ();
198
+
199
+ if ((next = parse_first_arg (next , & ref )) != NULL && ref .buf [0 ])
200
+ update_store_ref_name (update , ref .buf );
201
+ else
202
+ die ("verify line missing <ref>" );
203
+
204
+ if ((next = parse_next_arg (next , & value )) != NULL ) {
205
+ update_store_old_sha1 (update , value .buf );
206
+ update_store_new_sha1 (update , value .buf );
207
+ } else if (!line_termination )
208
+ die ("verify %s missing [<oldvalue>] NUL" , ref .buf );
209
+
210
+ if (next && * next )
211
+ die ("verify %s has extra input: %s" , ref .buf , next );
212
+ }
213
+
214
+ static void parse_cmd_option (const char * next )
215
+ {
216
+ if (!strcmp (next , "no-deref" ))
217
+ update_flags |= REF_NODEREF ;
218
+ else
219
+ die ("option unknown: %s" , next );
220
+ }
221
+
222
+ static void update_refs_stdin (void )
223
+ {
224
+ struct strbuf cmd = STRBUF_INIT ;
225
+
226
+ /* Read each line dispatch its command */
227
+ while (strbuf_getline (& cmd , stdin , line_termination ) != EOF )
228
+ if (!cmd .buf [0 ])
229
+ die ("empty command in input" );
230
+ else if (isspace (* cmd .buf ))
231
+ die ("whitespace before command: %s" , cmd .buf );
232
+ else if (!prefixcmp (cmd .buf , "update " ))
233
+ parse_cmd_update (cmd .buf + 7 );
234
+ else if (!prefixcmp (cmd .buf , "create " ))
235
+ parse_cmd_create (cmd .buf + 7 );
236
+ else if (!prefixcmp (cmd .buf , "delete " ))
237
+ parse_cmd_delete (cmd .buf + 7 );
238
+ else if (!prefixcmp (cmd .buf , "verify " ))
239
+ parse_cmd_verify (cmd .buf + 7 );
240
+ else if (!prefixcmp (cmd .buf , "option " ))
241
+ parse_cmd_option (cmd .buf + 7 );
242
+ else
243
+ die ("unknown command: %s" , cmd .buf );
244
+
245
+ strbuf_release (& cmd );
246
+ }
247
+
12
248
int cmd_update_ref (int argc , const char * * argv , const char * prefix )
13
249
{
14
250
const char * refname , * oldval , * msg = NULL ;
15
251
unsigned char sha1 [20 ], oldsha1 [20 ];
16
- int delete = 0 , no_deref = 0 , flags = 0 ;
252
+ int delete = 0 , no_deref = 0 , read_stdin = 0 , end_null = 0 , flags = 0 ;
17
253
struct option options [] = {
18
254
OPT_STRING ( 'm' , NULL , & msg , N_ ("reason" ), N_ ("reason of the update" )),
19
255
OPT_BOOLEAN ('d' , NULL , & delete , N_ ("delete the reference" )),
256
+ OPT_BOOLEAN ('z' , NULL , & end_null , N_ ("stdin has NUL-terminated arguments" )),
20
257
OPT_BOOLEAN ( 0 , "no-deref" , & no_deref ,
21
258
N_ ("update <refname> not the one it points to" )),
259
+ OPT_BOOLEAN ( 0 , "stdin" , & read_stdin , N_ ("read updates from stdin" )),
22
260
OPT_END (),
23
261
};
24
262
@@ -28,6 +266,18 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
28
266
if (msg && !* msg )
29
267
die ("Refusing to perform update with empty message." );
30
268
269
+ if (read_stdin ) {
270
+ if (delete || no_deref || argc > 0 )
271
+ usage_with_options (git_update_ref_usage , options );
272
+ if (end_null )
273
+ line_termination = '\0' ;
274
+ update_refs_stdin ();
275
+ return update_refs (msg , updates , updates_count , DIE_ON_ERR );
276
+ }
277
+
278
+ if (end_null )
279
+ usage_with_options (git_update_ref_usage , options );
280
+
31
281
if (delete ) {
32
282
if (argc < 1 || argc > 2 )
33
283
usage_with_options (git_update_ref_usage , options );
0 commit comments