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 --- Documentation/git-interpret-trailers.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt index 31cdeaecdf..295dffbd21 100644 --- a/Documentation/git-interpret-trailers.txt +++ b/Documentation/git-interpret-trailers.txt @@ -80,6 +80,9 @@ OPTIONS trailer to the input messages. See the description of this command. +--only-trailers:: + Output only the trailers, not any other parts of the input. + CONFIGURATION VARIABLES ----------------------- -- cgit v1.3-5-g9baa 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 --- Documentation/git-interpret-trailers.txt | 5 +++++ builtin/interpret-trailers.c | 7 +++++++ t/t7513-interpret-trailers.sh | 16 ++++++++++++++++ trailer.c | 9 +++++---- trailer.h | 1 + 5 files changed, 34 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt index 295dffbd21..7cc43b0e3e 100644 --- a/Documentation/git-interpret-trailers.txt +++ b/Documentation/git-interpret-trailers.txt @@ -83,6 +83,11 @@ OPTIONS --only-trailers:: Output only the trailers, not any other parts of the input. +--only-input:: + Output only trailers that exist in the input; do not add any + from the command-line or by following configured `trailer.*` + rules. + CONFIGURATION VARIABLES ----------------------- diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c index afb12c11bc..2d90e0e480 100644 --- a/builtin/interpret-trailers.c +++ b/builtin/interpret-trailers.c @@ -25,6 +25,7 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "in-place", &opts.in_place, N_("edit files in place")), OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")), OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")), + OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply config rules")), OPT_STRING_LIST(0, "trailer", &trailers, N_("trailer"), N_("trailer(s) to add")), OPT_END() @@ -33,6 +34,12 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, git_interpret_trailers_usage, 0); + if (opts.only_input && trailers.nr) + usage_msg_opt( + _("--trailer with --only-input does not make sense"), + git_interpret_trailers_usage, + options); + if (argc) { int i; for (i = 0; i < argc; i++) diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh index 90d30037b7..94b6c52473 100755 --- a/t/t7513-interpret-trailers.sh +++ b/t/t7513-interpret-trailers.sh @@ -1314,4 +1314,20 @@ test_expect_success 'only-trailers omits non-trailer in middle of block' ' test_cmp expected actual ' +test_expect_success 'only input' ' + git config trailer.sign.command "echo config-value" && + cat >expected <<-\EOF && + existing: existing-value + EOF + git interpret-trailers \ + --only-trailers --only-input >actual <<-\EOF && + my subject + + my body + + existing: existing-value + EOF + test_cmp expected actual +' + test_done 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); diff --git a/trailer.h b/trailer.h index 3cf35ced00..76c3b571bf 100644 --- a/trailer.h +++ b/trailer.h @@ -26,6 +26,7 @@ struct process_trailer_options { int in_place; int trim_empty; int only_trailers; + int only_input; }; #define PROCESS_TRAILER_OPTIONS_INIT {0} -- cgit v1.3-5-g9baa 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 --- Documentation/git-interpret-trailers.txt | 4 ++++ builtin/interpret-trailers.c | 1 + t/t7513-interpret-trailers.sh | 21 +++++++++++++++++++++ trailer.c | 29 +++++++++++++++++++++++++++++ trailer.h | 1 + 5 files changed, 56 insertions(+) (limited to 'Documentation') diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt index 7cc43b0e3e..be948e8028 100644 --- a/Documentation/git-interpret-trailers.txt +++ b/Documentation/git-interpret-trailers.txt @@ -88,6 +88,10 @@ OPTIONS from the command-line or by following configured `trailer.*` rules. +--unfold:: + Remove any whitespace-continuation in trailers, so that each + trailer appears on a line by itself with its full content. + CONFIGURATION VARIABLES ----------------------- diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c index 2d90e0e480..922c3bad63 100644 --- a/builtin/interpret-trailers.c +++ b/builtin/interpret-trailers.c @@ -26,6 +26,7 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")), OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")), OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply config rules")), + OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")), OPT_STRING_LIST(0, "trailer", &trailers, N_("trailer"), N_("trailer(s) to add")), OPT_END() diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh index 94b6c52473..baf2feba98 100755 --- a/t/t7513-interpret-trailers.sh +++ b/t/t7513-interpret-trailers.sh @@ -1330,4 +1330,25 @@ test_expect_success 'only input' ' test_cmp expected actual ' +test_expect_success 'unfold' ' + cat >expected <<-\EOF && + foo: continued across several lines + EOF + # pass through tr to make leading and trailing whitespace more obvious + tr _ " " <<-\EOF | + my subject + + my body + + foo:_ + __continued + ___across + ____several + _____lines + ___ + EOF + git interpret-trailers --only-trailers --only-input --unfold >actual && + test_cmp expected actual +' + test_done 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)); diff --git a/trailer.h b/trailer.h index 76c3b571bf..194f85a102 100644 --- a/trailer.h +++ b/trailer.h @@ -27,6 +27,7 @@ struct process_trailer_options { int trim_empty; int only_trailers; int only_input; + int unfold; }; #define PROCESS_TRAILER_OPTIONS_INIT {0} -- cgit v1.3-5-g9baa From 99e09dafd7b7bcac4d8189b41dc6038bf36334f5 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 15 Aug 2017 06:23:34 -0400 Subject: interpret-trailers: add --parse convenience option The last few commits have added command line options that can turn interpret-trailers into a parsing tool. Since they'd most often be used together, let's provide a convenient single option for callers to invoke this mode. This is implemented as a callback rather than a boolean so that its effect is applied immediately, as if those options had been specified. Later options can then override them. E.g.: git interpret-trailers --parse --no-unfold would work. Let's also update the documentation to make clear that this parsing mode behaves quite differently than the normal "add trailers to the input" mode. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Documentation/git-interpret-trailers.txt | 21 ++++++++++++++------- builtin/interpret-trailers.c | 12 ++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt index be948e8028..1df8aabf51 100644 --- a/Documentation/git-interpret-trailers.txt +++ b/Documentation/git-interpret-trailers.txt @@ -3,24 +3,27 @@ git-interpret-trailers(1) NAME ---- -git-interpret-trailers - help add structured information into commit messages +git-interpret-trailers - add or parse structured information in commit messages SYNOPSIS -------- [verse] -'git interpret-trailers' [--in-place] [--trim-empty] [(--trailer [(=|:)])...] [...] +'git interpret-trailers' [options] [(--trailer [(=|:)])...] [...] +'git interpret-trailers' [options] [--parse] [...] DESCRIPTION ----------- -Help adding 'trailers' lines, that look similar to RFC 822 e-mail +Help parsing or adding 'trailers' lines, that look similar to RFC 822 e-mail headers, at the end of the otherwise free-form part of a commit message. This command reads some patches or commit messages from either the - arguments or the standard input if no is specified. Then -this command applies the arguments passed using the `--trailer` -option, if any, to the commit message part of each input file. The -result is emitted on the standard output. + arguments or the standard input if no is specified. If +`--parse` is specified, the output consists of the parsed trailers. + +Otherwise, the this command applies the arguments passed using the +`--trailer` option, if any, to the commit message part of each input +file. The result is emitted on the standard output. Some configuration variables control the way the `--trailer` arguments are applied to each commit message and the way any existing trailer in @@ -92,6 +95,10 @@ OPTIONS Remove any whitespace-continuation in trailers, so that each trailer appears on a line by itself with its full content. +--parse:: + A convenience alias for `--only-trailers --only-input + --unfold`. + CONFIGURATION VARIABLES ----------------------- diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c index 922c3bad63..555111a078 100644 --- a/builtin/interpret-trailers.c +++ b/builtin/interpret-trailers.c @@ -16,6 +16,16 @@ static const char * const git_interpret_trailers_usage[] = { NULL }; +static int parse_opt_parse(const struct option *opt, const char *arg, + int unset) +{ + struct process_trailer_options *v = opt->value; + v->only_trailers = 1; + v->only_input = 1; + v->unfold = 1; + return 0; +} + int cmd_interpret_trailers(int argc, const char **argv, const char *prefix) { struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT; @@ -27,6 +37,8 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")), OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply config rules")), OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")), + { OPTION_CALLBACK, 0, "parse", &opts, NULL, N_("set parsing options"), + PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse }, OPT_STRING_LIST(0, "trailer", &trailers, N_("trailer"), N_("trailer(s) to add")), OPT_END() -- cgit v1.3-5-g9baa 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 --- Documentation/pretty-formats.txt | 5 ++++- pretty.c | 15 ++++++++++++--- t/t4205-log-pretty-formats.sh | 33 +++++++++++++++++++++++++++++++++ trailer.c | 32 ++++++++++++++++++++++++++++++-- 4 files changed, 79 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index 4d6dac5770..efa67a716e 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -201,7 +201,10 @@ endif::git-rev-list[] - '%><()', '%><|()': similar to '% <()', '%<|()' respectively, but padding both sides (i.e. the text is centered) - %(trailers): display the trailers of the body as interpreted by - linkgit:git-interpret-trailers[1] + linkgit:git-interpret-trailers[1]. If the `:only` option is given, + omit non-trailer lines from the trailer block. If the `:unfold` + option is given, behave as if interpret-trailer's `--unfold` option + was given. E.g., `%(trailers:only:unfold)` to do both. NOTE: Some placeholders may depend on other options given to the revision traversal engine. For example, the `%g*` reflog options will diff --git a/pretty.c b/pretty.c index 33054e22cd..0e23fe3c05 100644 --- a/pretty.c +++ b/pretty.c @@ -1044,6 +1044,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ const struct commit *commit = c->commit; const char *msg = c->message; struct commit_list *p; + const char *arg; int ch; /* these are independent of the commit */ @@ -1262,10 +1263,18 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ return 1; } - if (starts_with(placeholder, "(trailers)")) { + if (skip_prefix(placeholder, "(trailers", &arg)) { struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT; - format_trailers_from_commit(sb, msg + c->subject_off, &opts); - return strlen("(trailers)"); + while (*arg == ':') { + if (skip_prefix(arg, ":only", &arg)) + opts.only_trailers = 1; + else if (skip_prefix(arg, ":unfold", &arg)) + opts.unfold = 1; + } + if (*arg == ')') { + format_trailers_from_commit(sb, msg + c->subject_off, &opts); + return arg - placeholder + 1; + } } return 0; /* unknown placeholder */ diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index 83ea85eb45..ec5f530102 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -543,6 +543,10 @@ Signed-off-by: A U Thor EOF +unfold () { + perl -0pe 's/\n\s+/ /' +} + test_expect_success 'set up trailer tests' ' echo "Some contents" >trailerfile && git add trailerfile && @@ -565,4 +569,33 @@ test_expect_success 'pretty format %(trailers) shows trailers' ' test_cmp expect actual ' +test_expect_success '%(trailers:only) shows only "key: value" trailers' ' + git log --no-walk --pretty="%(trailers:only)" >actual && + { + grep -v patch.description expect && + test_cmp expect actual +' + +test_expect_success '%(trailers:unfold) unfolds trailers' ' + git log --no-walk --pretty="%(trailers:unfold)" >actual && + { + unfold expect && + test_cmp expect actual +' + +test_expect_success ':only and :unfold work together' ' + git log --no-walk --pretty="%(trailers:only:unfold)" >actual && + git log --no-walk --pretty="%(trailers:unfold:only)" >reverse && + test_cmp actual reverse && + { + grep -v patch.description expect && + test_cmp expect actual +' + test_done 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.3-5-g9baa From 5a0d0c037cc187a6eee6329206b9f6a48746a054 Mon Sep 17 00:00:00 2001 From: Martin Ă…gren Date: Sun, 20 Aug 2017 05:40:09 -0400 Subject: doc/interpret-trailers: fix "the this" typo Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Documentation/git-interpret-trailers.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt index 1df8aabf51..2e22210734 100644 --- a/Documentation/git-interpret-trailers.txt +++ b/Documentation/git-interpret-trailers.txt @@ -21,7 +21,7 @@ This command reads some patches or commit messages from either the arguments or the standard input if no is specified. If `--parse` is specified, the output consists of the parsed trailers. -Otherwise, the this command applies the arguments passed using the +Otherwise, this command applies the arguments passed using the `--trailer` option, if any, to the commit message part of each input file. The result is emitted on the standard output. -- cgit v1.3-5-g9baa