builtin-notes: Refactor handling of -F option to allow combining -m and -F
By moving the -F option handling into a separate function (parse_file_arg), we can start allowing several -F options, and mixed usage of -m and -F options. Each -m/-F given appends to the note message, in the order they are given on the command-line. The patch includes tests verifying correct behaviour of the new functionality. Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Johan Herland committed
Feb 13, 2010 at 22:28 UTC
348f199b2d9250a82453323c90b7e8d3d9462220
2 files changed
+73
-44
builtin-notes.c
+51
-43
@@ -34,6 +34,11 @@ static const char note_template[] =
34
"# Write/edit the notes for the following object:\n"
35
"#\n";
36
37
+struct msg_arg {
38
+ int given;
39
+ struct strbuf buf;
40
+};
41
+
42
static int list_each_note(const unsigned char *object_sha1,
43
const unsigned char *note_sha1, char *note_path,
44
void *cb_data)
@@ -93,15 +98,13 @@ static void write_commented_object(int fd, const unsigned char *object)
98
sha1_to_hex(object));
99
}
100
96
-static void create_note(const unsigned char *object,
97
- struct strbuf *buf,
98
- int skip_editor, int append_only,
99
- const unsigned char *prev,
101
+static void create_note(const unsigned char *object, struct msg_arg *msg,
102
+ int append_only, const unsigned char *prev,
103
unsigned char *result)
104
{
105
char *path = NULL;
106
104
- if (!skip_editor) {
107
+ if (!msg->given) {
108
int fd;
109
110
/* write the template message before editing: */
@@ -118,34 +121,33 @@ static void create_note(const unsigned char *object,
121
122
close(fd);
123
121
- if (launch_editor(path, buf, NULL)) {
124
+ if (launch_editor(path, &(msg->buf), NULL)) {
125
die("Please supply the note contents using either -m" \
126
" or -F option");
127
}
128
+ stripspace(&(msg->buf), 1);
129
}
130
127
- stripspace(buf, 1);
128
-
131
if (prev && append_only) {
132
/* Append buf to previous note contents */
133
unsigned long size;
134
enum object_type type;
135
char *prev_buf = read_sha1_file(prev, &type, &size);
136
135
- strbuf_grow(buf, size + 1);
136
- if (buf->len && prev_buf && size)
137
- strbuf_insert(buf, 0, "\n", 1);
137
+ strbuf_grow(&(msg->buf), size + 1);
138
+ if (msg->buf.len && prev_buf && size)
139
+ strbuf_insert(&(msg->buf), 0, "\n", 1);
140
if (prev_buf && size)
139
- strbuf_insert(buf, 0, prev_buf, size);
141
+ strbuf_insert(&(msg->buf), 0, prev_buf, size);
142
free(prev_buf);
143
}
144
143
- if (!buf->len) {
145
+ if (!msg->buf.len) {
146
fprintf(stderr, "Removing note for object %s\n",
147
sha1_to_hex(object));
148
hashclr(result);
149
} else {
148
- if (write_sha1_file(buf->buf, buf->len, blob_type, result)) {
150
+ if (write_sha1_file(msg->buf.buf, msg->buf.len, blob_type, result)) {
151
error("unable to write note object");
152
if (path)
153
error("The note contents has been left in %s",
@@ -160,20 +162,39 @@ static void create_note(const unsigned char *object,
162
}
163
}
164
163
-struct msg_arg {
164
- int given;
165
- struct strbuf buf;
166
-};
167
-
165
static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
166
{
167
struct msg_arg *msg = opt->value;
168
169
if (!arg)
170
return -1;
171
+
172
+ strbuf_grow(&(msg->buf), strlen(arg) + 2);
173
if (msg->buf.len)
175
- strbuf_addstr(&(msg->buf), "\n\n");
174
+ strbuf_addstr(&(msg->buf), "\n");
175
strbuf_addstr(&(msg->buf), arg);
176
+ stripspace(&(msg->buf), 0);
177
+
178
+ msg->given = 1;
179
+ return 0;
180
+}
181
+
182
+static int parse_file_arg(const struct option *opt, const char *arg, int unset)
183
+{
184
+ struct msg_arg *msg = opt->value;
185
+
186
+ if (!arg)
187
+ return -1;
188
+
189
+ if (msg->buf.len)
190
+ strbuf_addstr(&(msg->buf), "\n");
191
+ if (!strcmp(arg, "-")) {
192
+ if (strbuf_read(&(msg->buf), 0, 1024) < 0)
193
+ die_errno("cannot read '%s'", arg);
194
+ } else if (strbuf_read_file(&(msg->buf), arg, 1024) < 0)
195
+ die_errno("could not open or read '%s'", arg);
196
+ stripspace(&(msg->buf), 0);
197
+
198
msg->given = 1;
199
return 0;
200
}
@@ -220,7 +241,6 @@ int commit_notes(struct notes_tree *t, const char *msg)
241
242
int cmd_notes(int argc, const char **argv, const char *prefix)
243
{
223
- struct strbuf buf = STRBUF_INIT;
244
struct notes_tree *t;
245
unsigned char object[20], new_note[20];
246
const unsigned char *note;
@@ -230,13 +250,13 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
250
int list = 0, add = 0, append = 0, edit = 0, show = 0, remove = 0,
251
prune = 0, force = 0;
252
int given_object;
233
- const char *msgfile = NULL;
253
struct msg_arg msg = { 0, STRBUF_INIT };
254
struct option options[] = {
255
OPT_GROUP("Notes options"),
237
- OPT_CALLBACK('m', "message", &msg, "msg",
256
+ OPT_CALLBACK('m', "message", &msg, "MSG",
257
"note contents as a string", parse_msg_arg),
239
- OPT_FILENAME('F', "file", &msgfile, "note contents in a file"),
258
+ OPT_CALLBACK('F', "file", &msg, "FILE",
259
+ "note contents in a file", parse_file_arg),
260
OPT_BOOLEAN('f', "force", &force, "replace existing notes"),
261
OPT_END()
262
};
@@ -265,21 +285,17 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
285
if (list + add + append + edit + show + remove + prune != 1)
286
usage_with_options(git_notes_usage, options);
287
268
- if ((msg.given || msgfile) && !(add || append || edit)) {
288
+ if (msg.given && !(add || append || edit)) {
289
error("cannot use -m/-F options with %s subcommand.", argv[0]);
290
usage_with_options(git_notes_usage, options);
291
}
292
273
- if ((msg.given || msgfile) && edit) {
293
+ if (msg.given && edit) {
294
fprintf(stderr, "The -m and -F options has been deprecated for"
295
" the 'edit' subcommand.\n"
296
"Please use 'git notes add -f -m/-F' instead.\n");
297
}
298
279
- if (msg.given && msgfile) {
280
- error("mixing -m and -F options is not allowed.");
281
- usage_with_options(git_notes_usage, options);
282
- }
299
300
if (force && !add) {
301
error("cannot use -f option with %s subcommand.", argv[0]);
@@ -341,24 +357,16 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
357
}
358
}
359
344
- if (remove)
345
- strbuf_reset(&buf);
346
- else if (msg.given)
347
- strbuf_addbuf(&buf, &(msg.buf));
348
- else if (msgfile) {
349
- if (!strcmp(msgfile, "-")) {
350
- if (strbuf_read(&buf, 0, 1024) < 0)
351
- die_errno("cannot read '%s'", msgfile);
352
- } else if (strbuf_read_file(&buf, msgfile, 1024) < 0)
353
- die_errno("could not open or read '%s'", msgfile);
360
+ if (remove) {
361
+ msg.given = 1;
362
+ strbuf_reset(&(msg.buf));
363
}
364
365
if (prune) {
366
hashclr(new_note);
367
prune_notes(t);
368
} else {
360
- create_note(object, &buf, msg.given || msgfile || remove,
361
- append, note, new_note);
369
+ create_note(object, &msg, append, note, new_note);
370
if (is_null_sha1(new_note))
371
remove_note(t, object);
372
else
@@ -369,6 +377,6 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
377
commit_notes(t, logmsg);
378
379
free_notes(t);
372
- strbuf_release(&buf);
380
+ strbuf_release(&(msg.buf));
381
return 0;
382
}
t/t3301-notes.sh
+22
-1
@@ -284,8 +284,29 @@ test_expect_success 'verify non-creation of note with -m ""' '
284
! git notes show
285
'
286
287
+cat > expect-combine_m_and_F << EOF
288
+foo
289
+
290
+xyzzy
291
+
292
+bar
293
+
294
+zyxxy
295
+
296
+baz
297
+EOF
298
+
299
+test_expect_success 'create note with combination of -m and -F' '
300
+ echo "xyzzy" > note_a &&
301
+ echo "zyxxy" > note_b &&
302
+ git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" &&
303
+ git notes show > output &&
304
+ test_cmp expect-combine_m_and_F output
305
+'
306
+
307
test_expect_success 'remove note with "git notes remove" (setup)' '
288
- git notes remove HEAD^
308
+ git notes remove HEAD^ &&
309
+ git notes remove
310
'
311
312
cat > expect-rm-remove << EOF