interpret-trailers: add an option to show only the trailers
authorJeff King <peff@peff.net>
Tue, 15 Aug 2017 10:23:21 +0000 (06:23 -0400)
committerJunio C Hamano <gitster@pobox.com>
Tue, 15 Aug 2017 18:13:58 +0000 (11:13 -0700)
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 <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-interpret-trailers.txt
builtin/interpret-trailers.c
t/t7513-interpret-trailers.sh
trailer.c
trailer.h
index 31cdeaecdfde8fb358c35c3a9a2e3c4279d440d0..295dffbd2104ba7b471b69bc1300deb002318e53 100644 (file)
@@ -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
 -----------------------
 
index bb0d7b937a9e2610ae35e5ae52a3ac7fffc6d134..afb12c11bc9966c7786f6602e3940ea0ffaa39be 100644 (file)
@@ -24,6 +24,7 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
        struct option options[] = {
                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_STRING_LIST(0, "trailer", &trailers, N_("trailer"),
                                N_("trailer(s) to add")),
                OPT_END()
index 0c6f91c4338cce131b3d6066e590f177f7e739d1..90d30037b7b38397123a080c8d70df4de894066f 100755 (executable)
@@ -1275,4 +1275,43 @@ test_expect_success 'with cut line' '
        test_cmp expected actual
 '
 
+test_expect_success 'only trailers' '
+       git config trailer.sign.command "echo config-value" &&
+       cat >expected <<-\EOF &&
+               existing: existing-value
+               sign: config-value
+               added: added-value
+       EOF
+       git interpret-trailers \
+               --trailer added:added-value \
+               --only-trailers >actual <<-\EOF &&
+               my subject
+
+               my body
+
+               existing: existing-value
+       EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'only-trailers omits non-trailer in middle of block' '
+       git config trailer.sign.command "echo config-value" &&
+       cat >expected <<-\EOF &&
+               Signed-off-by: nobody <nobody@nowhere>
+               Signed-off-by: somebody <somebody@somewhere>
+               sign: config-value
+       EOF
+       git interpret-trailers --only-trailers >actual <<-\EOF &&
+               subject
+
+               it is important that the trailers below are signed-off-by
+               so that they meet the "25% trailers Git knows about" heuristic
+
+               Signed-off-by: nobody <nobody@nowhere>
+               this is not a trailer
+               Signed-off-by: somebody <somebody@somewhere>
+       EOF
+       test_cmp expected actual
+'
+
 test_done
index 9bcd54e813d94e02d08de9ab18cdee467a2e6729..83225c6828b30d893a641142c8c7c2684ac4f6a4 100644 (file)
--- 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))
index 9da00bedecdbfe2f7c69f7be5a88a61225c0a3fe..3cf35ced00ffbc57de93b6d8a005085836b23ed5 100644 (file)
--- a/trailer.h
+++ b/trailer.h
@@ -25,6 +25,7 @@ struct trailer_info {
 struct process_trailer_options {
        int in_place;
        int trim_empty;
+       int only_trailers;
 };
 
 #define PROCESS_TRAILER_OPTIONS_INIT {0}