8
*/
9
10
#include "cache.h"
11
+#include "alloc.h"
12
#include "config.h"
13
#include "builtin.h"
14
#include "gettext.h"
28
#include "worktree.h"
29
#include "write-or-die.h"
30
31
+static char *separator = "\n";
32
static const char * const git_notes_usage[] = {
33
N_("git notes [--ref <notes-ref>] [list [<object>]]"),
32
- N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
34
+ N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--separator=<paragraph-break>] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
35
N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"),
34
- N_("git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
36
+ N_("git notes [--ref <notes-ref>] append [--allow-empty] [--separator=<paragraph-break>] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
37
N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"),
38
N_("git notes [--ref <notes-ref>] show [<object>]"),
39
N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"),
101
static const char note_template[] =
102
N_("Write/edit the notes for the following object:");
103
104
+struct note_msg {
105
+ int stripspace;
106
+ struct strbuf buf;
107
+};
108
+
109
struct note_data {
110
int given;
111
int use_editor;
112
char *edit_path;
113
struct strbuf buf;
114
+ struct note_msg **messages;
115
+ size_t msg_nr;
116
+ size_t msg_alloc;
117
};
118
119
static void free_note_data(struct note_data *d)
123
free(d->edit_path);
124
}
125
strbuf_release(&d->buf);
126
+
127
+ while (d->msg_nr--) {
128
+ strbuf_release(&d->messages[d->msg_nr]->buf);
129
+ free(d->messages[d->msg_nr]);
130
+ }
131
+ free(d->messages);
132
}
133
134
static int list_each_note(const struct object_id *object_oid,
229
}
230
}
231
232
+static void insert_separator(struct strbuf *message, size_t pos)
233
+{
234
+ size_t sep_len = strlen(separator);
235
+ if (sep_len && separator[sep_len - 1] == '\n')
236
+ strbuf_insertstr(message, pos, separator);
237
+ else
238
+ strbuf_insertf(message, pos, "%s%s", separator, "\n");
239
+}
240
+
241
+static void concat_messages(struct note_data *d)
242
+{
243
+ struct strbuf msg = STRBUF_INIT;
244
+
245
+ size_t i;
246
+ for (i = 0; i < d->msg_nr ; i++) {
247
+ if (d->buf.len)
248
+ insert_separator(&d->buf, d->buf.len);
249
+ strbuf_add(&msg, d->messages[i]->buf.buf, d->messages[i]->buf.len);
250
+ strbuf_addbuf(&d->buf, &msg);
251
+ if (d->messages[i]->stripspace)
252
+ strbuf_stripspace(&d->buf, 0);
253
+ strbuf_reset(&msg);
254
+ }
255
+ strbuf_release(&msg);
256
+}
257
+
258
static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
259
{
260
struct note_data *d = opt->value;
261
+ struct note_msg *msg = xmalloc(sizeof(*msg));
262
263
BUG_ON_OPT_NEG(unset);
264
222
- if (d->buf.len)
223
- strbuf_addch(&d->buf, '\n');
224
- strbuf_addstr(&d->buf, arg);
225
- strbuf_stripspace(&d->buf, 0);
226
-
227
- d->given = 1;
265
+ strbuf_init(&msg->buf, strlen(arg));
266
+ strbuf_addstr(&msg->buf, arg);
267
+ ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
268
+ d->messages[d->msg_nr - 1] = msg;
269
+ msg->stripspace = 1;
270
return 0;
271
}
272
273
static int parse_file_arg(const struct option *opt, const char *arg, int unset)
274
{
275
struct note_data *d = opt->value;
276
+ struct note_msg *msg = xmalloc(sizeof(*msg));
277
278
BUG_ON_OPT_NEG(unset);
279
237
- if (d->buf.len)
238
- strbuf_addch(&d->buf, '\n');
280
+ strbuf_init(&msg->buf , 0);
281
if (!strcmp(arg, "-")) {
240
- if (strbuf_read(&d->buf, 0, 1024) < 0)
282
+ if (strbuf_read(&msg->buf, 0, 1024) < 0)
283
die_errno(_("cannot read '%s'"), arg);
242
- } else if (strbuf_read_file(&d->buf, arg, 1024) < 0)
284
+ } else if (strbuf_read_file(&msg->buf, arg, 1024) < 0)
285
die_errno(_("could not open or read '%s'"), arg);
244
- strbuf_stripspace(&d->buf, 0);
286
246
- d->given = 1;
287
+ ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
288
+ d->messages[d->msg_nr - 1] = msg;
289
+ msg->stripspace = 1;
290
return 0;
291
}
292
293
static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
294
{
295
struct note_data *d = opt->value;
253
- char *buf;
296
+ struct note_msg *msg = xmalloc(sizeof(*msg));
297
+ char *value;
298
struct object_id object;
299
enum object_type type;
300
unsigned long len;
301
302
BUG_ON_OPT_NEG(unset);
303
260
- if (d->buf.len)
261
- strbuf_addch(&d->buf, '\n');
262
-
304
+ strbuf_init(&msg->buf, 0);
305
if (repo_get_oid(the_repository, arg, &object))
306
die(_("failed to resolve '%s' as a valid ref."), arg);
265
- if (!(buf = repo_read_object_file(the_repository, &object, &type, &len)))
307
+ if (!(value = repo_read_object_file(the_repository, &object, &type, &len)))
308
die(_("failed to read object '%s'."), arg);
309
if (type != OBJ_BLOB) {
268
- free(buf);
310
+ strbuf_release(&msg->buf);
311
+ free(value);
312
+ free(msg);
313
die(_("cannot read note data from non-blob object '%s'."), arg);
314
}
271
- strbuf_add(&d->buf, buf, len);
272
- free(buf);
315
274
- d->given = 1;
316
+ strbuf_add(&msg->buf, value, len);
317
+ free(value);
318
+
319
+ msg->buf.len = len;
320
+ ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
321
+ d->messages[d->msg_nr - 1] = msg;
322
+ msg->stripspace = 0;
323
return 0;
324
}
325
454
struct object_id object, new_note;
455
const struct object_id *note;
456
struct note_data d = { .buf = STRBUF_INIT };
457
+
458
struct option options[] = {
459
OPT_CALLBACK_F('m', "message", &d, N_("message"),
460
N_("note contents as a string"), PARSE_OPT_NONEG,
471
OPT_BOOL(0, "allow-empty", &allow_empty,
472
N_("allow storing empty note")),
473
OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE),
474
+ OPT_STRING(0, "separator", &separator, N_("separator"),
475
+ N_("insert <paragraph-break> between paragraphs")),
476
OPT_END()
477
};
478
484
usage_with_options(git_notes_add_usage, options);
485
}
486
487
+ if (d.msg_nr)
488
+ concat_messages(&d);
489
+ d.given = !!d.buf.len;
490
+
491
object_ref = argc > 1 ? argv[1] : "HEAD";
492
493
if (repo_get_oid(the_repository, object_ref, &object))
642
parse_reuse_arg),
643
OPT_BOOL(0, "allow-empty", &allow_empty,
644
N_("allow storing empty note")),
645
+ OPT_STRING(0, "separator", &separator, N_("separator"),
646
+ N_("insert <paragraph-break> between paragraphs")),
647
OPT_END()
648
};
649
int edit = !strcmp(argv[0], "edit");
657
usage_with_options(usage, options);
658
}
659
660
+ if (d.msg_nr)
661
+ concat_messages(&d);
662
+ d.given = !!d.buf.len;
663
+
664
if (d.given && edit)
665
fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated "
666
"for the 'edit' subcommand.\n"
684
&type, &size);
685
686
if (d.buf.len && prev_buf && size)
626
- strbuf_insertstr(&d.buf, 0, "\n");
687
+ insert_separator(&d.buf, 0);
688
if (prev_buf && size)
689
strbuf_insert(&d.buf, 0, prev_buf, size);
690
free(prev_buf);