Merge branch 'jk/trailers-parse'
"git interpret-trailers" has been taught a "--parse" and a few other options to make it easier for scripts to grab existing trailer lines from a commit log message. * jk/trailers-parse: doc/interpret-trailers: fix "the this" typo pretty: support normalization options for %(trailers) t4205: refactor %(trailers) tests pretty: move trailer formatting to trailer.c interpret-trailers: add --parse convenience option interpret-trailers: add an option to unfold values interpret-trailers: add an option to show only existing trailers interpret-trailers: add an option to show only the trailers trailer: put process_trailers() options into a struct
This commit is contained in:
commit
06cf4f2d87
@ -3,24 +3,27 @@ git-interpret-trailers(1)
|
|||||||
|
|
||||||
NAME
|
NAME
|
||||||
----
|
----
|
||||||
git-interpret-trailers - help add structured information into commit messages
|
git-interpret-trailers - add or parse structured information in commit messages
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git interpret-trailers' [--in-place] [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]
|
'git interpret-trailers' [options] [(--trailer <token>[(=|:)<value>])...] [<file>...]
|
||||||
|
'git interpret-trailers' [options] [--parse] [<file>...]
|
||||||
|
|
||||||
DESCRIPTION
|
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
|
headers, at the end of the otherwise free-form part of a commit
|
||||||
message.
|
message.
|
||||||
|
|
||||||
This command reads some patches or commit messages from either the
|
This command reads some patches or commit messages from either the
|
||||||
<file> arguments or the standard input if no <file> is specified. Then
|
<file> arguments or the standard input if no <file> is specified. If
|
||||||
this command applies the arguments passed using the `--trailer`
|
`--parse` is specified, the output consists of the parsed trailers.
|
||||||
option, if any, to the commit message part of each input file. The
|
|
||||||
result is emitted on the standard output.
|
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.
|
||||||
|
|
||||||
Some configuration variables control the way the `--trailer` arguments
|
Some configuration variables control the way the `--trailer` arguments
|
||||||
are applied to each commit message and the way any existing trailer in
|
are applied to each commit message and the way any existing trailer in
|
||||||
@ -103,6 +106,22 @@ OPTIONS
|
|||||||
and applies to all '--trailer' options until the next occurrence of
|
and applies to all '--trailer' options until the next occurrence of
|
||||||
'--if-missing' or '--no-if-missing'.
|
'--if-missing' or '--no-if-missing'.
|
||||||
|
|
||||||
|
--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.
|
||||||
|
|
||||||
|
--unfold::
|
||||||
|
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
|
CONFIGURATION VARIABLES
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
@ -205,7 +205,10 @@ endif::git-rev-list[]
|
|||||||
- '%><(<N>)', '%><|(<N>)': similar to '% <(<N>)', '%<|(<N>)'
|
- '%><(<N>)', '%><|(<N>)': similar to '% <(<N>)', '%<|(<N>)'
|
||||||
respectively, but padding both sides (i.e. the text is centered)
|
respectively, but padding both sides (i.e. the text is centered)
|
||||||
- %(trailers): display the trailers of the body as interpreted by
|
- %(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
|
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
|
||||||
|
@ -73,15 +73,24 @@ static int option_parse_trailer(const struct option *opt,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int in_place = 0;
|
struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
|
||||||
int trim_empty = 0;
|
|
||||||
LIST_HEAD(trailers);
|
LIST_HEAD(trailers);
|
||||||
|
|
||||||
struct option options[] = {
|
struct option options[] = {
|
||||||
OPT_BOOL(0, "in-place", &in_place, N_("edit files in place")),
|
OPT_BOOL(0, "in-place", &opts.in_place, N_("edit files in place")),
|
||||||
OPT_BOOL(0, "trim-empty", &trim_empty, N_("trim empty trailers")),
|
OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")),
|
||||||
|
|
||||||
OPT_CALLBACK(0, "where", NULL, N_("action"),
|
OPT_CALLBACK(0, "where", NULL, N_("action"),
|
||||||
N_("where to place the new trailer"), option_parse_where),
|
N_("where to place the new trailer"), option_parse_where),
|
||||||
@ -90,6 +99,11 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
|
|||||||
OPT_CALLBACK(0, "if-missing", NULL, N_("action"),
|
OPT_CALLBACK(0, "if-missing", NULL, N_("action"),
|
||||||
N_("action if trailer is missing"), option_parse_if_missing),
|
N_("action if trailer is missing"), option_parse_if_missing),
|
||||||
|
|
||||||
|
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_CALLBACK(0, "trailer", &trailers, N_("trailer"),
|
OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"),
|
||||||
N_("trailer(s) to add"), option_parse_trailer),
|
N_("trailer(s) to add"), option_parse_trailer),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
@ -98,14 +112,20 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
|
|||||||
argc = parse_options(argc, argv, prefix, options,
|
argc = parse_options(argc, argv, prefix, options,
|
||||||
git_interpret_trailers_usage, 0);
|
git_interpret_trailers_usage, 0);
|
||||||
|
|
||||||
|
if (opts.only_input && !list_empty(&trailers))
|
||||||
|
usage_msg_opt(
|
||||||
|
_("--trailer with --only-input does not make sense"),
|
||||||
|
git_interpret_trailers_usage,
|
||||||
|
options);
|
||||||
|
|
||||||
if (argc) {
|
if (argc) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
process_trailers(argv[i], in_place, trim_empty, &trailers);
|
process_trailers(argv[i], &opts, &trailers);
|
||||||
} else {
|
} else {
|
||||||
if (in_place)
|
if (opts.in_place)
|
||||||
die(_("no input file given for in-place editing"));
|
die(_("no input file given for in-place editing"));
|
||||||
process_trailers(NULL, in_place, trim_empty, &trailers);
|
process_trailers(NULL, &opts, &trailers);
|
||||||
}
|
}
|
||||||
|
|
||||||
new_trailers_clear(&trailers);
|
new_trailers_clear(&trailers);
|
||||||
|
26
pretty.c
26
pretty.c
@ -871,16 +871,6 @@ const char *format_subject(struct strbuf *sb, const char *msg,
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void format_trailers(struct strbuf *sb, const char *msg)
|
|
||||||
{
|
|
||||||
struct trailer_info info;
|
|
||||||
|
|
||||||
trailer_info_get(&info, msg);
|
|
||||||
strbuf_add(sb, info.trailer_start,
|
|
||||||
info.trailer_end - info.trailer_start);
|
|
||||||
trailer_info_release(&info);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_commit_message(struct format_commit_context *c)
|
static void parse_commit_message(struct format_commit_context *c)
|
||||||
{
|
{
|
||||||
const char *msg = c->message + c->message_off;
|
const char *msg = c->message + c->message_off;
|
||||||
@ -1074,6 +1064,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
|
|||||||
const struct commit *commit = c->commit;
|
const struct commit *commit = c->commit;
|
||||||
const char *msg = c->message;
|
const char *msg = c->message;
|
||||||
struct commit_list *p;
|
struct commit_list *p;
|
||||||
|
const char *arg;
|
||||||
int ch;
|
int ch;
|
||||||
|
|
||||||
/* these are independent of the commit */
|
/* these are independent of the commit */
|
||||||
@ -1292,9 +1283,18 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (starts_with(placeholder, "(trailers)")) {
|
if (skip_prefix(placeholder, "(trailers", &arg)) {
|
||||||
format_trailers(sb, msg + c->subject_off);
|
struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
|
||||||
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 */
|
return 0; /* unknown placeholder */
|
||||||
|
@ -539,25 +539,62 @@ cat >trailers <<EOF
|
|||||||
Signed-off-by: A U Thor <author@example.com>
|
Signed-off-by: A U Thor <author@example.com>
|
||||||
Acked-by: A U Thor <author@example.com>
|
Acked-by: A U Thor <author@example.com>
|
||||||
[ v2 updated patch description ]
|
[ v2 updated patch description ]
|
||||||
Signed-off-by: A U Thor <author@example.com>
|
Signed-off-by: A U Thor
|
||||||
|
<author@example.com>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
test_expect_success 'pretty format %(trailers) shows trailers' '
|
unfold () {
|
||||||
|
perl -0pe 's/\n\s+/ /'
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expect_success 'set up trailer tests' '
|
||||||
echo "Some contents" >trailerfile &&
|
echo "Some contents" >trailerfile &&
|
||||||
git add trailerfile &&
|
git add trailerfile &&
|
||||||
git commit -F - <<-EOF &&
|
git commit -F - <<-EOF
|
||||||
trailers: this commit message has trailers
|
trailers: this commit message has trailers
|
||||||
|
|
||||||
This commit is a test commit with trailers at the end. We parse this
|
This commit is a test commit with trailers at the end. We parse this
|
||||||
message and display the trailers using %bT
|
message and display the trailers using %(trailers).
|
||||||
|
|
||||||
$(cat trailers)
|
$(cat trailers)
|
||||||
EOF
|
EOF
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pretty format %(trailers) shows trailers' '
|
||||||
git log --no-walk --pretty="%(trailers)" >actual &&
|
git log --no-walk --pretty="%(trailers)" >actual &&
|
||||||
cat >expect <<-EOF &&
|
{
|
||||||
$(cat trailers)
|
cat trailers &&
|
||||||
|
echo
|
||||||
|
} >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
EOF
|
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_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -1341,4 +1341,80 @@ test_expect_success 'with cut line' '
|
|||||||
test_cmp expected actual
|
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_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_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
|
test_done
|
||||||
|
114
trailer.c
114
trailer.c
@ -159,13 +159,15 @@ static void print_tok_val(FILE *outfile, const char *tok, const char *val)
|
|||||||
fprintf(outfile, "%s%c %s\n", tok, separators[0], 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 list_head *pos;
|
||||||
struct trailer_item *item;
|
struct trailer_item *item;
|
||||||
list_for_each(pos, head) {
|
list_for_each(pos, head) {
|
||||||
item = list_entry(pos, struct trailer_item, list);
|
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);
|
print_tok_val(outfile, item->token, item->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -910,9 +912,37 @@ static int ends_with_blank_line(const char *buf, size_t len)
|
|||||||
return is_blank_line(buf + ll);
|
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,
|
static int process_input_file(FILE *outfile,
|
||||||
const char *str,
|
const char *str,
|
||||||
struct list_head *head)
|
struct list_head *head,
|
||||||
|
const struct process_trailer_options *opts)
|
||||||
{
|
{
|
||||||
struct trailer_info info;
|
struct trailer_info info;
|
||||||
struct strbuf tok = STRBUF_INIT;
|
struct strbuf tok = STRBUF_INIT;
|
||||||
@ -922,9 +952,10 @@ static int process_input_file(FILE *outfile,
|
|||||||
trailer_info_get(&info, str);
|
trailer_info_get(&info, str);
|
||||||
|
|
||||||
/* Print lines before the trailers as is */
|
/* 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");
|
fprintf(outfile, "\n");
|
||||||
|
|
||||||
for (i = 0; i < info.trailer_nr; i++) {
|
for (i = 0; i < info.trailer_nr; i++) {
|
||||||
@ -936,10 +967,12 @@ static int process_input_file(FILE *outfile,
|
|||||||
if (separator_pos >= 1) {
|
if (separator_pos >= 1) {
|
||||||
parse_trailer(&tok, &val, NULL, trailer,
|
parse_trailer(&tok, &val, NULL, trailer,
|
||||||
separator_pos);
|
separator_pos);
|
||||||
|
if (opts->unfold)
|
||||||
|
unfold_value(&val);
|
||||||
add_trailer_item(head,
|
add_trailer_item(head,
|
||||||
strbuf_detach(&tok, NULL),
|
strbuf_detach(&tok, NULL),
|
||||||
strbuf_detach(&val, NULL));
|
strbuf_detach(&val, NULL));
|
||||||
} else {
|
} else if (!opts->only_trailers) {
|
||||||
strbuf_addstr(&val, trailer);
|
strbuf_addstr(&val, trailer);
|
||||||
strbuf_strip_suffix(&val, "\n");
|
strbuf_strip_suffix(&val, "\n");
|
||||||
add_trailer_item(head,
|
add_trailer_item(head,
|
||||||
@ -993,11 +1026,11 @@ static FILE *create_in_place_tempfile(const char *file)
|
|||||||
return outfile;
|
return outfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_trailers(const char *file, int in_place, int trim_empty,
|
void process_trailers(const char *file,
|
||||||
|
const struct process_trailer_options *opts,
|
||||||
struct list_head *new_trailer_head)
|
struct list_head *new_trailer_head)
|
||||||
{
|
{
|
||||||
LIST_HEAD(head);
|
LIST_HEAD(head);
|
||||||
LIST_HEAD(arg_head);
|
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
int trailer_end;
|
int trailer_end;
|
||||||
FILE *outfile = stdout;
|
FILE *outfile = stdout;
|
||||||
@ -1006,24 +1039,27 @@ void process_trailers(const char *file, int in_place, int trim_empty,
|
|||||||
|
|
||||||
read_input_file(&sb, file);
|
read_input_file(&sb, file);
|
||||||
|
|
||||||
if (in_place)
|
if (opts->in_place)
|
||||||
outfile = create_in_place_tempfile(file);
|
outfile = create_in_place_tempfile(file);
|
||||||
|
|
||||||
/* Print the lines before the trailers */
|
/* 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, new_trailer_head);
|
if (!opts->only_input) {
|
||||||
|
LIST_HEAD(arg_head);
|
||||||
|
process_command_line_args(&arg_head, new_trailer_head);
|
||||||
|
process_trailers_lists(&head, &arg_head);
|
||||||
|
}
|
||||||
|
|
||||||
process_trailers_lists(&head, &arg_head);
|
print_all(outfile, &head, opts);
|
||||||
|
|
||||||
print_all(outfile, &head, trim_empty);
|
|
||||||
|
|
||||||
free_all(&head);
|
free_all(&head);
|
||||||
|
|
||||||
/* Print the lines after the trailers as is */
|
/* 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 (in_place)
|
if (opts->in_place)
|
||||||
if (rename_tempfile(&trailers_tempfile, file))
|
if (rename_tempfile(&trailers_tempfile, file))
|
||||||
die_errno(_("could not rename temporary file to %s"), file);
|
die_errno(_("could not rename temporary file to %s"), file);
|
||||||
|
|
||||||
@ -1080,3 +1116,49 @@ void trailer_info_release(struct trailer_info *info)
|
|||||||
free(info->trailers[i]);
|
free(info->trailers[i]);
|
||||||
free(info->trailers);
|
free(info->trailers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void format_trailer_info(struct strbuf *out,
|
||||||
|
const struct trailer_info *info,
|
||||||
|
const struct process_trailer_options *opts)
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
const struct process_trailer_options *opts)
|
||||||
|
{
|
||||||
|
struct trailer_info info;
|
||||||
|
|
||||||
|
trailer_info_get(&info, msg);
|
||||||
|
format_trailer_info(out, &info, opts);
|
||||||
|
trailer_info_release(&info);
|
||||||
|
}
|
||||||
|
27
trailer.h
27
trailer.h
@ -63,11 +63,36 @@ struct new_trailer_item {
|
|||||||
enum trailer_if_missing if_missing;
|
enum trailer_if_missing if_missing;
|
||||||
};
|
};
|
||||||
|
|
||||||
void process_trailers(const char *file, int in_place, int trim_empty,
|
struct process_trailer_options {
|
||||||
|
int in_place;
|
||||||
|
int trim_empty;
|
||||||
|
int only_trailers;
|
||||||
|
int only_input;
|
||||||
|
int unfold;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PROCESS_TRAILER_OPTIONS_INIT {0}
|
||||||
|
|
||||||
|
void process_trailers(const char *file,
|
||||||
|
const struct process_trailer_options *opts,
|
||||||
struct list_head *new_trailer_head);
|
struct list_head *new_trailer_head);
|
||||||
|
|
||||||
void trailer_info_get(struct trailer_info *info, const char *str);
|
void trailer_info_get(struct trailer_info *info, const char *str);
|
||||||
|
|
||||||
void trailer_info_release(struct trailer_info *info);
|
void trailer_info_release(struct trailer_info *info);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format the trailers from the commit msg "msg" into the strbuf "out".
|
||||||
|
* Note two caveats about "opts":
|
||||||
|
*
|
||||||
|
* - this is primarily a helper for pretty.c, and not
|
||||||
|
* all of the flags are supported.
|
||||||
|
*
|
||||||
|
* - this differs from process_trailers slightly in that we always format
|
||||||
|
* only the trailer block itself, even if the "only_trailers" option is not
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
void format_trailers_from_commit(struct strbuf *out, const char *msg,
|
||||||
|
const struct process_trailer_options *opts);
|
||||||
|
|
||||||
#endif /* TRAILER_H */
|
#endif /* TRAILER_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user