From 8abc89800c09cda7910c2211ebbbbb95a3008b63 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 10 Aug 2017 14:03:58 -0400 Subject: trailer: put process_trailers() options into a struct We already have two options and are about to add a few more. To avoid having a huge number of boolean arguments, let's convert to an options struct which can be passed in. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- trailer.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'trailer.c') diff --git a/trailer.c b/trailer.c index 11f0b9fb40..9bcd54e813 100644 --- a/trailer.c +++ b/trailer.c @@ -967,7 +967,9 @@ static FILE *create_in_place_tempfile(const char *file) return outfile; } -void process_trailers(const char *file, int in_place, int trim_empty, struct string_list *trailers) +void process_trailers(const char *file, + const struct process_trailer_options *opts, + struct string_list *trailers) { LIST_HEAD(head); LIST_HEAD(arg_head); @@ -979,7 +981,7 @@ void process_trailers(const char *file, int in_place, int trim_empty, struct str read_input_file(&sb, file); - if (in_place) + if (opts->in_place) outfile = create_in_place_tempfile(file); /* Print the lines before the trailers */ @@ -989,14 +991,14 @@ void process_trailers(const char *file, int in_place, int trim_empty, struct str process_trailers_lists(&head, &arg_head); - print_all(outfile, &head, trim_empty); + print_all(outfile, &head, opts->trim_empty); free_all(&head); /* Print the lines after the trailers as is */ fwrite(sb.buf + trailer_end, 1, sb.len - trailer_end, outfile); - if (in_place) + if (opts->in_place) if (rename_tempfile(&trailers_tempfile, file)) die_errno(_("could not rename temporary file to %s"), file); -- cgit v1.2.3 From 56c493ed1b9c067813fb95ff7cd4f69c7c1d2e36 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 15 Aug 2017 06:23:21 -0400 Subject: interpret-trailers: add an option to show only the trailers In theory it's easy for any reader who wants to parse trailers to do so. But there are a lot of subtle corner cases around what counts as a trailer, when the trailer block begins and ends, etc. Since interpret-trailers already has our parsing logic, let's let callers ask it to just output the trailers. They still have to parse the "key: value" lines, but at least they can ignore all of the other corner cases. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- trailer.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'trailer.c') diff --git a/trailer.c b/trailer.c index 9bcd54e813..83225c6828 100644 --- a/trailer.c +++ b/trailer.c @@ -163,13 +163,15 @@ static void print_tok_val(FILE *outfile, const char *tok, const char *val) fprintf(outfile, "%s%c %s\n", tok, separators[0], val); } -static void print_all(FILE *outfile, struct list_head *head, int trim_empty) +static void print_all(FILE *outfile, struct list_head *head, + const struct process_trailer_options *opts) { struct list_head *pos; struct trailer_item *item; list_for_each(pos, head) { item = list_entry(pos, struct trailer_item, list); - if (!trim_empty || strlen(item->value) > 0) + if ((!opts->trim_empty || strlen(item->value) > 0) && + (!opts->only_trailers || item->token)) print_tok_val(outfile, item->token, item->value); } } @@ -886,7 +888,8 @@ static int ends_with_blank_line(const char *buf, size_t len) static int process_input_file(FILE *outfile, const char *str, - struct list_head *head) + struct list_head *head, + const struct process_trailer_options *opts) { struct trailer_info info; struct strbuf tok = STRBUF_INIT; @@ -896,9 +899,10 @@ static int process_input_file(FILE *outfile, trailer_info_get(&info, str); /* Print lines before the trailers as is */ - fwrite(str, 1, info.trailer_start - str, outfile); + if (!opts->only_trailers) + fwrite(str, 1, info.trailer_start - str, outfile); - if (!info.blank_line_before_trailer) + if (!opts->only_trailers && !info.blank_line_before_trailer) fprintf(outfile, "\n"); for (i = 0; i < info.trailer_nr; i++) { @@ -913,7 +917,7 @@ static int process_input_file(FILE *outfile, add_trailer_item(head, strbuf_detach(&tok, NULL), strbuf_detach(&val, NULL)); - } else { + } else if (!opts->only_trailers) { strbuf_addstr(&val, trailer); strbuf_strip_suffix(&val, "\n"); add_trailer_item(head, @@ -985,18 +989,19 @@ void process_trailers(const char *file, outfile = create_in_place_tempfile(file); /* Print the lines before the trailers */ - trailer_end = process_input_file(outfile, sb.buf, &head); + trailer_end = process_input_file(outfile, sb.buf, &head, opts); process_command_line_args(&arg_head, trailers); process_trailers_lists(&head, &arg_head); - print_all(outfile, &head, opts->trim_empty); + print_all(outfile, &head, opts); free_all(&head); /* Print the lines after the trailers as is */ - fwrite(sb.buf + trailer_end, 1, sb.len - trailer_end, outfile); + if (!opts->only_trailers) + fwrite(sb.buf + trailer_end, 1, sb.len - trailer_end, outfile); if (opts->in_place) if (rename_tempfile(&trailers_tempfile, file)) -- cgit v1.2.3 From fdbdb64f49959f9c83329554080934895f02ae59 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 15 Aug 2017 06:23:25 -0400 Subject: interpret-trailers: add an option to show only existing trailers It can be useful to invoke interpret-trailers for the primary purpose of parsing existing trailers. But in that case, we don't want to apply existing ifMissing or ifExists rules from the config. Let's add a special mode where we avoid applying those rules. Coupled with --only-trailers, this gives us a reasonable parsing tool. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- trailer.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'trailer.c') diff --git a/trailer.c b/trailer.c index 83225c6828..847417ef89 100644 --- a/trailer.c +++ b/trailer.c @@ -976,7 +976,6 @@ void process_trailers(const char *file, struct string_list *trailers) { LIST_HEAD(head); - LIST_HEAD(arg_head); struct strbuf sb = STRBUF_INIT; int trailer_end; FILE *outfile = stdout; @@ -991,9 +990,11 @@ void process_trailers(const char *file, /* Print the lines before the trailers */ trailer_end = process_input_file(outfile, sb.buf, &head, opts); - process_command_line_args(&arg_head, trailers); - - process_trailers_lists(&head, &arg_head); + if (!opts->only_input) { + LIST_HEAD(arg_head); + process_command_line_args(&arg_head, trailers); + process_trailers_lists(&head, &arg_head); + } print_all(outfile, &head, opts); -- cgit v1.2.3 From 000023961a0c02d6e21dc51ea3484ff71abf1c74 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 15 Aug 2017 06:23:29 -0400 Subject: interpret-trailers: add an option to unfold values The point of "--only-trailers" is to give a caller an output that's easy for them to parse. Getting rid of the non-trailer material helps, but we still may see more complicated syntax like whitespace continuation. Let's add an option to unfold any continuation, giving the output as a single "key: value" line per trailer. As a bonus, this could be used even without --only-trailers to clean up unusual formatting in the incoming data. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- trailer.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'trailer.c') diff --git a/trailer.c b/trailer.c index 847417ef89..e63f432947 100644 --- a/trailer.c +++ b/trailer.c @@ -886,6 +886,33 @@ static int ends_with_blank_line(const char *buf, size_t len) return is_blank_line(buf + ll); } +static void unfold_value(struct strbuf *val) +{ + struct strbuf out = STRBUF_INIT; + size_t i; + + strbuf_grow(&out, val->len); + i = 0; + while (i < val->len) { + char c = val->buf[i++]; + if (c == '\n') { + /* Collapse continuation down to a single space. */ + while (i < val->len && isspace(val->buf[i])) + i++; + strbuf_addch(&out, ' '); + } else { + strbuf_addch(&out, c); + } + } + + /* Empty lines may have left us with whitespace cruft at the edges */ + strbuf_trim(&out); + + /* output goes back to val as if we modified it in-place */ + strbuf_swap(&out, val); + strbuf_release(&out); +} + static int process_input_file(FILE *outfile, const char *str, struct list_head *head, @@ -914,6 +941,8 @@ static int process_input_file(FILE *outfile, if (separator_pos >= 1) { parse_trailer(&tok, &val, NULL, trailer, separator_pos); + if (opts->unfold) + unfold_value(&val); add_trailer_item(head, strbuf_detach(&tok, NULL), strbuf_detach(&val, NULL)); -- cgit v1.2.3 From a388b10fc17c435df32c3875225a1468edad9535 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 15 Aug 2017 06:23:56 -0400 Subject: pretty: move trailer formatting to trailer.c The next commit will add many features to the %(trailer) placeholder in pretty.c. We'll need to access some internal functions of trailer.c for that, so our options are either: 1. expose those functions publicly or 2. make an entry point into trailer.c to do the formatting Doing (2) ends up exposing less surface area, though do note that caveats in the docstring of the new function. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- trailer.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'trailer.c') diff --git a/trailer.c b/trailer.c index e63f432947..07580af9c0 100644 --- a/trailer.c +++ b/trailer.c @@ -1090,3 +1090,21 @@ void trailer_info_release(struct trailer_info *info) free(info->trailers[i]); free(info->trailers); } + +static void format_trailer_info(struct strbuf *out, + const struct trailer_info *info, + const struct process_trailer_options *opts) +{ + strbuf_add(out, info->trailer_start, + info->trailer_end - info->trailer_start); +} + +void format_trailers_from_commit(struct strbuf *out, const char *msg, + const struct process_trailer_options *opts) +{ + struct trailer_info info; + + trailer_info_get(&info, msg); + format_trailer_info(out, &info, opts); + trailer_info_release(&info); +} -- cgit v1.2.3 From 58311c66fd316dff8f2c68a634ca0cf968227870 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 15 Aug 2017 06:25:27 -0400 Subject: pretty: support normalization options for %(trailers) The interpret-trailers command recently learned some options to make its output easier to parse (for a caller whose only interested in picking out the trailer values). But it's not very efficient for asking for the trailers of many commits in a single invocation. We already have "%(trailers)" to do that, but it doesn't know about unfolding or omitting non-trailers. Let's plumb those options through, so you can have the best of both. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- trailer.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'trailer.c') diff --git a/trailer.c b/trailer.c index 07580af9c0..6ec5505dc4 100644 --- a/trailer.c +++ b/trailer.c @@ -1095,8 +1095,36 @@ static void format_trailer_info(struct strbuf *out, const struct trailer_info *info, const struct process_trailer_options *opts) { - strbuf_add(out, info->trailer_start, - info->trailer_end - info->trailer_start); + int i; + + /* If we want the whole block untouched, we can take the fast path. */ + if (!opts->only_trailers && !opts->unfold) { + strbuf_add(out, info->trailer_start, + info->trailer_end - info->trailer_start); + return; + } + + for (i = 0; i < info->trailer_nr; i++) { + char *trailer = info->trailers[i]; + int separator_pos = find_separator(trailer, separators); + + if (separator_pos >= 1) { + struct strbuf tok = STRBUF_INIT; + struct strbuf val = STRBUF_INIT; + + parse_trailer(&tok, &val, NULL, trailer, separator_pos); + if (opts->unfold) + unfold_value(&val); + + strbuf_addf(out, "%s: %s\n", tok.buf, val.buf); + strbuf_release(&tok); + strbuf_release(&val); + + } else if (!opts->only_trailers) { + strbuf_addstr(out, trailer); + } + } + } void format_trailers_from_commit(struct strbuf *out, const char *msg, -- cgit v1.2.3