pretty: support normalization options for %(trailers)
authorJeff King <peff@peff.net>
Tue, 15 Aug 2017 10:25:27 +0000 (06:25 -0400)
committerJunio C Hamano <gitster@pobox.com>
Tue, 15 Aug 2017 18:13:58 +0000 (11:13 -0700)
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 <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/pretty-formats.txt
pretty.c
t/t4205-log-pretty-formats.sh
trailer.c

index 4d6dac5..efa67a7 100644 (file)
@@ -201,7 +201,10 @@ endif::git-rev-list[]
 - '%><(<N>)', '%><|(<N>)': similar to '% <(<N>)', '%<|(<N>)'
   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
index 33054e2..0e23fe3 100644 (file)
--- 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 */
index 83ea85e..ec5f530 100755 (executable)
@@ -543,6 +543,10 @@ Signed-off-by: A U Thor
   <author@example.com>
 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 <trailers &&
+               echo
+       } >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success '%(trailers:unfold) unfolds trailers' '
+       git log --no-walk --pretty="%(trailers:unfold)" >actual &&
+       {
+               unfold <trailers &&
+               echo
+       } >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 <trailers | unfold &&
+               echo
+       } >expect &&
+       test_cmp expect actual
+'
+
 test_done
index 07580af..6ec5505 100644 (file)
--- 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,