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 <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Aug 15, 2017 at 06:23 UTC 000023961a0c02d6e21dc51ea3484ff71abf1c74
5 files changed +56
Documentation/git-interpret-trailers.txt
+4
@@ -88,6 +88,10 @@ OPTIONS
88 from the command-line or by following configured `trailer.*`
89 rules.
90
91 +--unfold::
92 + Remove any whitespace-continuation in trailers, so that each
93 + trailer appears on a line by itself with its full content.
94 +
95 CONFIGURATION VARIABLES
96 -----------------------
97
builtin/interpret-trailers.c
+1
@@ -26,6 +26,7 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
26 OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")),
27 OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")),
28 OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply config rules")),
29 + OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")),
30 OPT_STRING_LIST(0, "trailer", &trailers, N_("trailer"),
31 N_("trailer(s) to add")),
32 OPT_END()
t/t7513-interpret-trailers.sh
+21
@@ -1330,4 +1330,25 @@ test_expect_success 'only input' '
1330 test_cmp expected actual
1331 '
1332
1333 +test_expect_success 'unfold' '
1334 + cat >expected <<-\EOF &&
1335 + foo: continued across several lines
1336 + EOF
1337 + # pass through tr to make leading and trailing whitespace more obvious
1338 + tr _ " " <<-\EOF |
1339 + my subject
1340 +
1341 + my body
1342 +
1343 + foo:_
1344 + __continued
1345 + ___across
1346 + ____several
1347 + _____lines
1348 + ___
1349 + EOF
1350 + git interpret-trailers --only-trailers --only-input --unfold >actual &&
1351 + test_cmp expected actual
1352 +'
1353 +
1354 test_done
trailer.c
+29
@@ -886,6 +886,33 @@ static int ends_with_blank_line(const char *buf, size_t len)
886 return is_blank_line(buf + ll);
887 }
888
889 +static void unfold_value(struct strbuf *val)
890 +{
891 + struct strbuf out = STRBUF_INIT;
892 + size_t i;
893 +
894 + strbuf_grow(&out, val->len);
895 + i = 0;
896 + while (i < val->len) {
897 + char c = val->buf[i++];
898 + if (c == '\n') {
899 + /* Collapse continuation down to a single space. */
900 + while (i < val->len && isspace(val->buf[i]))
901 + i++;
902 + strbuf_addch(&out, ' ');
903 + } else {
904 + strbuf_addch(&out, c);
905 + }
906 + }
907 +
908 + /* Empty lines may have left us with whitespace cruft at the edges */
909 + strbuf_trim(&out);
910 +
911 + /* output goes back to val as if we modified it in-place */
912 + strbuf_swap(&out, val);
913 + strbuf_release(&out);
914 +}
915 +
916 static int process_input_file(FILE *outfile,
917 const char *str,
918 struct list_head *head,
@@ -914,6 +941,8 @@ static int process_input_file(FILE *outfile,
941 if (separator_pos >= 1) {
942 parse_trailer(&tok, &val, NULL, trailer,
943 separator_pos);
944 + if (opts->unfold)
945 + unfold_value(&val);
946 add_trailer_item(head,
947 strbuf_detach(&tok, NULL),
948 strbuf_detach(&val, NULL));
trailer.h
+1
@@ -27,6 +27,7 @@ struct process_trailer_options {
27 int trim_empty;
28 int only_trailers;
29 int only_input;
30 + int unfold;
31 };
32
33 #define PROCESS_TRAILER_OPTIONS_INIT {0}