pretty format %(trailers): add a "key_value_separator"
Add a "key_value_separator" option to the "%(trailers)" pretty format, to go along with the existing "separator" argument. In combination these two options make it trivial to produce machine-readable (e.g. \0 and \0\0-delimited) format output. As elaborated on in a previous commit which added "keyonly" it was needlessly tedious to extract structured data from "%(trailers)" before the addition of this "key_value_separator" option. As seen by the test being added here extracting this data now becomes trivial. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
9d87d5ae02
commit
058761f1c1
@ -284,6 +284,10 @@ option is given with no value, it's enabled.
|
|||||||
`%(trailers:only,unfold=true)` unfolds and shows all trailer lines.
|
`%(trailers:only,unfold=true)` unfolds and shows all trailer lines.
|
||||||
** 'keyonly[=<BOOL>]': only show the key part of the trailer.
|
** 'keyonly[=<BOOL>]': only show the key part of the trailer.
|
||||||
** 'valueonly[=<BOOL>]': only show the value part of the trailer.
|
** 'valueonly[=<BOOL>]': only show the value part of the trailer.
|
||||||
|
** 'key_value_separator=<SEP>': specify a separator inserted between
|
||||||
|
trailer lines. When this option is not given each trailer key-value
|
||||||
|
pair is separated by ": ". Otherwise it shares the same semantics
|
||||||
|
as 'separator=<SEP>' above.
|
||||||
|
|
||||||
NOTE: Some placeholders may depend on other options given to the
|
NOTE: Some placeholders may depend on other options given to the
|
||||||
revision traversal engine. For example, the `%g*` reflog options will
|
revision traversal engine. For example, the `%g*` reflog options will
|
||||||
|
9
pretty.c
9
pretty.c
@ -1418,6 +1418,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
|
|||||||
struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
|
struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
|
||||||
struct string_list filter_list = STRING_LIST_INIT_NODUP;
|
struct string_list filter_list = STRING_LIST_INIT_NODUP;
|
||||||
struct strbuf sepbuf = STRBUF_INIT;
|
struct strbuf sepbuf = STRBUF_INIT;
|
||||||
|
struct strbuf kvsepbuf = STRBUF_INIT;
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
|
|
||||||
opts.no_divider = 1;
|
opts.no_divider = 1;
|
||||||
@ -1449,6 +1450,14 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
|
|||||||
strbuf_expand(&sepbuf, fmt, strbuf_expand_literal_cb, NULL);
|
strbuf_expand(&sepbuf, fmt, strbuf_expand_literal_cb, NULL);
|
||||||
free(fmt);
|
free(fmt);
|
||||||
opts.separator = &sepbuf;
|
opts.separator = &sepbuf;
|
||||||
|
} else if (match_placeholder_arg_value(arg, "key_value_separator", &arg, &argval, &arglen)) {
|
||||||
|
char *fmt;
|
||||||
|
|
||||||
|
strbuf_reset(&kvsepbuf);
|
||||||
|
fmt = xstrndup(argval, arglen);
|
||||||
|
strbuf_expand(&kvsepbuf, fmt, strbuf_expand_literal_cb, NULL);
|
||||||
|
free(fmt);
|
||||||
|
opts.key_value_separator = &kvsepbuf;
|
||||||
} else if (!match_placeholder_bool_arg(arg, "only", &arg, &opts.only_trailers) &&
|
} else if (!match_placeholder_bool_arg(arg, "only", &arg, &opts.only_trailers) &&
|
||||||
!match_placeholder_bool_arg(arg, "unfold", &arg, &opts.unfold) &&
|
!match_placeholder_bool_arg(arg, "unfold", &arg, &opts.unfold) &&
|
||||||
!match_placeholder_bool_arg(arg, "keyonly", &arg, &opts.key_only) &&
|
!match_placeholder_bool_arg(arg, "keyonly", &arg, &opts.key_only) &&
|
||||||
|
@ -776,6 +776,39 @@ test_expect_success 'pretty format %(trailers:separator=X,unfold) changes separa
|
|||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pretty format %(trailers:key_value_separator) changes key-value separator' '
|
||||||
|
git log --no-walk --pretty=format:"X%(trailers:key_value_separator=%x00)X" >actual &&
|
||||||
|
(
|
||||||
|
printf "XSigned-off-by\0A U Thor <author@example.com>\n" &&
|
||||||
|
printf "Acked-by\0A U Thor <author@example.com>\n" &&
|
||||||
|
printf "[ v2 updated patch description ]\n" &&
|
||||||
|
printf "Signed-off-by\0A U Thor\n <author@example.com>\nX"
|
||||||
|
) >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pretty format %(trailers:key_value_separator,unfold) changes key-value separator' '
|
||||||
|
git log --no-walk --pretty=format:"X%(trailers:key_value_separator=%x00,unfold)X" >actual &&
|
||||||
|
(
|
||||||
|
printf "XSigned-off-by\0A U Thor <author@example.com>\n" &&
|
||||||
|
printf "Acked-by\0A U Thor <author@example.com>\n" &&
|
||||||
|
printf "[ v2 updated patch description ]\n" &&
|
||||||
|
printf "Signed-off-by\0A U Thor <author@example.com>\nX"
|
||||||
|
) >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pretty format %(trailers:separator,key_value_separator) changes both separators' '
|
||||||
|
git log --no-walk --pretty=format:"%(trailers:separator=%x00,key_value_separator=%x00%x00,unfold)" >actual &&
|
||||||
|
(
|
||||||
|
printf "Signed-off-by\0\0A U Thor <author@example.com>\0" &&
|
||||||
|
printf "Acked-by\0\0A U Thor <author@example.com>\0" &&
|
||||||
|
printf "[ v2 updated patch description ]\0" &&
|
||||||
|
printf "Signed-off-by\0\0A U Thor <author@example.com>"
|
||||||
|
) >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'pretty format %(trailers) combining separator/key/keyonly/valueonly' '
|
test_expect_success 'pretty format %(trailers) combining separator/key/keyonly/valueonly' '
|
||||||
git commit --allow-empty -F - <<-\EOF &&
|
git commit --allow-empty -F - <<-\EOF &&
|
||||||
Important fix
|
Important fix
|
||||||
|
11
trailer.c
11
trailer.c
@ -1132,7 +1132,8 @@ static void format_trailer_info(struct strbuf *out,
|
|||||||
|
|
||||||
/* If we want the whole block untouched, we can take the fast path. */
|
/* If we want the whole block untouched, we can take the fast path. */
|
||||||
if (!opts->only_trailers && !opts->unfold && !opts->filter &&
|
if (!opts->only_trailers && !opts->unfold && !opts->filter &&
|
||||||
!opts->separator && !opts->key_only && !opts->value_only) {
|
!opts->separator && !opts->key_only && !opts->value_only &&
|
||||||
|
!opts->key_value_separator) {
|
||||||
strbuf_add(out, info->trailer_start,
|
strbuf_add(out, info->trailer_start,
|
||||||
info->trailer_end - info->trailer_start);
|
info->trailer_end - info->trailer_start);
|
||||||
return;
|
return;
|
||||||
@ -1155,8 +1156,12 @@ static void format_trailer_info(struct strbuf *out,
|
|||||||
strbuf_addbuf(out, opts->separator);
|
strbuf_addbuf(out, opts->separator);
|
||||||
if (!opts->value_only)
|
if (!opts->value_only)
|
||||||
strbuf_addbuf(out, &tok);
|
strbuf_addbuf(out, &tok);
|
||||||
if (!opts->key_only && !opts->value_only)
|
if (!opts->key_only && !opts->value_only) {
|
||||||
strbuf_addstr(out, ": ");
|
if (opts->key_value_separator)
|
||||||
|
strbuf_addbuf(out, opts->key_value_separator);
|
||||||
|
else
|
||||||
|
strbuf_addstr(out, ": ");
|
||||||
|
}
|
||||||
if (!opts->key_only)
|
if (!opts->key_only)
|
||||||
strbuf_addbuf(out, &val);
|
strbuf_addbuf(out, &val);
|
||||||
if (!opts->separator)
|
if (!opts->separator)
|
||||||
|
@ -74,6 +74,7 @@ struct process_trailer_options {
|
|||||||
int key_only;
|
int key_only;
|
||||||
int value_only;
|
int value_only;
|
||||||
const struct strbuf *separator;
|
const struct strbuf *separator;
|
||||||
|
const struct strbuf *key_value_separator;
|
||||||
int (*filter)(const struct strbuf *, void *);
|
int (*filter)(const struct strbuf *, void *);
|
||||||
void *filter_data;
|
void *filter_data;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user