mirror of
https://github.com/git/git.git
synced 2024-09-08 03:50:44 +02:00
Merge branch 'la/hide-trailer-info'
The trailer API has been reshuffled a bit. * la/hide-trailer-info: trailer unit tests: inspect iterator contents trailer: document parse_trailers() usage trailer: retire trailer_info_get() from API trailer: make trailer_info struct private trailer: make parse_trailers() return trailer_info pointer interpret-trailers: access trailer_info with new helpers sequencer: use the trailer iterator trailer: teach iterator about non-trailer lines trailer: add unit tests for trailer iterator Makefile: sort UNIT_TEST_PROGRAMS
This commit is contained in:
commit
7593d66928
5
Makefile
5
Makefile
@ -1334,10 +1334,11 @@ THIRD_PARTY_SOURCES += compat/regex/%
|
||||
THIRD_PARTY_SOURCES += sha1collisiondetection/%
|
||||
THIRD_PARTY_SOURCES += sha1dc/%
|
||||
|
||||
UNIT_TEST_PROGRAMS += t-mem-pool
|
||||
UNIT_TEST_PROGRAMS += t-strbuf
|
||||
UNIT_TEST_PROGRAMS += t-ctype
|
||||
UNIT_TEST_PROGRAMS += t-mem-pool
|
||||
UNIT_TEST_PROGRAMS += t-prio-queue
|
||||
UNIT_TEST_PROGRAMS += t-strbuf
|
||||
UNIT_TEST_PROGRAMS += t-trailer
|
||||
UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS))
|
||||
UNIT_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
|
||||
UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
|
||||
|
@ -141,7 +141,7 @@ static void interpret_trailers(const struct process_trailer_options *opts,
|
||||
LIST_HEAD(head);
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
struct strbuf trailer_block = STRBUF_INIT;
|
||||
struct trailer_info info;
|
||||
struct trailer_info *info;
|
||||
FILE *outfile = stdout;
|
||||
|
||||
trailer_config_init();
|
||||
@ -151,13 +151,13 @@ static void interpret_trailers(const struct process_trailer_options *opts,
|
||||
if (opts->in_place)
|
||||
outfile = create_in_place_tempfile(file);
|
||||
|
||||
parse_trailers(opts, &info, sb.buf, &head);
|
||||
info = parse_trailers(opts, sb.buf, &head);
|
||||
|
||||
/* Print the lines before the trailers */
|
||||
if (!opts->only_trailers)
|
||||
fwrite(sb.buf, 1, info.trailer_block_start, outfile);
|
||||
fwrite(sb.buf, 1, trailer_block_start(info), outfile);
|
||||
|
||||
if (!opts->only_trailers && !info.blank_line_before_trailer)
|
||||
if (!opts->only_trailers && !blank_line_before_trailer_block(info))
|
||||
fprintf(outfile, "\n");
|
||||
|
||||
|
||||
@ -178,8 +178,8 @@ static void interpret_trailers(const struct process_trailer_options *opts,
|
||||
|
||||
/* Print the lines after the trailers as is */
|
||||
if (!opts->only_trailers)
|
||||
fwrite(sb.buf + info.trailer_block_end, 1, sb.len - info.trailer_block_end, outfile);
|
||||
trailer_info_release(&info);
|
||||
fwrite(sb.buf + trailer_block_end(info), 1, sb.len - trailer_block_end(info), outfile);
|
||||
trailer_info_release(info);
|
||||
|
||||
if (opts->in_place)
|
||||
if (rename_tempfile(&trailers_tempfile, file))
|
||||
|
27
sequencer.c
27
sequencer.c
@ -359,35 +359,32 @@ static const char *get_todo_path(const struct replay_opts *opts)
|
||||
static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,
|
||||
size_t ignore_footer)
|
||||
{
|
||||
struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
|
||||
struct trailer_info info;
|
||||
size_t i;
|
||||
struct trailer_iterator iter;
|
||||
size_t i = 0;
|
||||
int found_sob = 0, found_sob_last = 0;
|
||||
char saved_char;
|
||||
|
||||
opts.no_divider = 1;
|
||||
|
||||
if (ignore_footer) {
|
||||
saved_char = sb->buf[sb->len - ignore_footer];
|
||||
sb->buf[sb->len - ignore_footer] = '\0';
|
||||
}
|
||||
|
||||
trailer_info_get(&opts, sb->buf, &info);
|
||||
trailer_iterator_init(&iter, sb->buf);
|
||||
|
||||
if (ignore_footer)
|
||||
sb->buf[sb->len - ignore_footer] = saved_char;
|
||||
|
||||
if (info.trailer_block_start == info.trailer_block_end)
|
||||
while (trailer_iterator_advance(&iter)) {
|
||||
i++;
|
||||
if (sob && !strncmp(iter.raw, sob->buf, sob->len))
|
||||
found_sob = i;
|
||||
}
|
||||
trailer_iterator_release(&iter);
|
||||
|
||||
if (!i)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < info.trailer_nr; i++)
|
||||
if (sob && !strncmp(info.trailers[i], sob->buf, sob->len)) {
|
||||
found_sob = 1;
|
||||
if (i == info.trailer_nr - 1)
|
||||
found_sob_last = 1;
|
||||
}
|
||||
|
||||
trailer_info_release(&info);
|
||||
found_sob_last = (int)i == found_sob;
|
||||
|
||||
if (found_sob_last)
|
||||
return 3;
|
||||
|
315
t/unit-tests/t-trailer.c
Normal file
315
t/unit-tests/t-trailer.c
Normal file
@ -0,0 +1,315 @@
|
||||
#include "test-lib.h"
|
||||
#include "trailer.h"
|
||||
|
||||
struct contents {
|
||||
const char *raw;
|
||||
const char *key;
|
||||
const char *val;
|
||||
};
|
||||
|
||||
static void t_trailer_iterator(const char *msg, size_t num_expected,
|
||||
struct contents *contents)
|
||||
{
|
||||
struct trailer_iterator iter;
|
||||
size_t i = 0;
|
||||
|
||||
trailer_iterator_init(&iter, msg);
|
||||
while (trailer_iterator_advance(&iter)) {
|
||||
if (num_expected) {
|
||||
check_str(iter.raw, contents[i].raw);
|
||||
check_str(iter.key.buf, contents[i].key);
|
||||
check_str(iter.val.buf, contents[i].val);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
trailer_iterator_release(&iter);
|
||||
|
||||
check_uint(i, ==, num_expected);
|
||||
}
|
||||
|
||||
static void run_t_trailer_iterator(void)
|
||||
{
|
||||
|
||||
static struct test_cases {
|
||||
const char *name;
|
||||
const char *msg;
|
||||
size_t num_expected;
|
||||
struct contents contents[10];
|
||||
} tc[] = {
|
||||
{
|
||||
"empty input",
|
||||
"",
|
||||
0,
|
||||
{{0}},
|
||||
},
|
||||
{
|
||||
"no newline at beginning",
|
||||
"Fixes: x\n"
|
||||
"Acked-by: x\n"
|
||||
"Reviewed-by: x\n",
|
||||
0,
|
||||
{{0}},
|
||||
},
|
||||
{
|
||||
"newline at beginning",
|
||||
"\n"
|
||||
"Fixes: x\n"
|
||||
"Acked-by: x\n"
|
||||
"Reviewed-by: x\n",
|
||||
3,
|
||||
{
|
||||
{
|
||||
.raw = "Fixes: x\n",
|
||||
.key = "Fixes",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
.raw = "Acked-by: x\n",
|
||||
.key = "Acked-by",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
.raw = "Reviewed-by: x\n",
|
||||
.key = "Reviewed-by",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"without body text",
|
||||
"subject: foo bar\n"
|
||||
"\n"
|
||||
"Fixes: x\n"
|
||||
"Acked-by: x\n"
|
||||
"Reviewed-by: x\n",
|
||||
3,
|
||||
{
|
||||
{
|
||||
.raw = "Fixes: x\n",
|
||||
.key = "Fixes",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
.raw = "Acked-by: x\n",
|
||||
.key = "Acked-by",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
.raw = "Reviewed-by: x\n",
|
||||
.key = "Reviewed-by",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"with body text, without divider",
|
||||
"my subject\n"
|
||||
"\n"
|
||||
"my body which is long\n"
|
||||
"and contains some special\n"
|
||||
"chars like : = ? !\n"
|
||||
"hello\n"
|
||||
"\n"
|
||||
"Fixes: x\n"
|
||||
"Acked-by: x\n"
|
||||
"Reviewed-by: x\n"
|
||||
"Signed-off-by: x\n",
|
||||
4,
|
||||
{
|
||||
{
|
||||
.raw = "Fixes: x\n",
|
||||
.key = "Fixes",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
.raw = "Acked-by: x\n",
|
||||
.key = "Acked-by",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
.raw = "Reviewed-by: x\n",
|
||||
.key = "Reviewed-by",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
.raw = "Signed-off-by: x\n",
|
||||
.key = "Signed-off-by",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"with body text, without divider (second trailer block)",
|
||||
"my subject\n"
|
||||
"\n"
|
||||
"my body which is long\n"
|
||||
"and contains some special\n"
|
||||
"chars like : = ? !\n"
|
||||
"hello\n"
|
||||
"\n"
|
||||
"Fixes: x\n"
|
||||
"Acked-by: x\n"
|
||||
"Reviewed-by: x\n"
|
||||
"Signed-off-by: x\n"
|
||||
"\n"
|
||||
/*
|
||||
* Because this is the last trailer block, it takes
|
||||
* precedence over the first one encountered above.
|
||||
*/
|
||||
"Helped-by: x\n"
|
||||
"Signed-off-by: x\n",
|
||||
2,
|
||||
{
|
||||
{
|
||||
.raw = "Helped-by: x\n",
|
||||
.key = "Helped-by",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
.raw = "Signed-off-by: x\n",
|
||||
.key = "Signed-off-by",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"with body text, with divider",
|
||||
"my subject\n"
|
||||
"\n"
|
||||
"my body which is long\n"
|
||||
"and contains some special\n"
|
||||
"chars like : = ? !\n"
|
||||
"hello\n"
|
||||
"\n"
|
||||
"---\n"
|
||||
"\n"
|
||||
/*
|
||||
* This trailer still counts because the iterator
|
||||
* always ignores the divider.
|
||||
*/
|
||||
"Signed-off-by: x\n",
|
||||
1,
|
||||
{
|
||||
{
|
||||
.raw = "Signed-off-by: x\n",
|
||||
.key = "Signed-off-by",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"with non-trailer lines in trailer block",
|
||||
"subject: foo bar\n"
|
||||
"\n"
|
||||
/*
|
||||
* Even though this trailer block has a non-trailer line
|
||||
* in it, it's still a valid trailer block because it's
|
||||
* at least 25% trailers and is Git-generated (see
|
||||
* git_generated_prefixes[] in trailer.c).
|
||||
*/
|
||||
"not a trailer line\n"
|
||||
"not a trailer line\n"
|
||||
"not a trailer line\n"
|
||||
"Signed-off-by: x\n",
|
||||
/*
|
||||
* Even though there is only really 1 real "trailer"
|
||||
* (Signed-off-by), we still have 4 trailer objects
|
||||
* because we still want to iterate through the entire
|
||||
* block.
|
||||
*/
|
||||
4,
|
||||
{
|
||||
{
|
||||
.raw = "not a trailer line\n",
|
||||
.key = "not a trailer line",
|
||||
.val = "",
|
||||
},
|
||||
{
|
||||
.raw = "not a trailer line\n",
|
||||
.key = "not a trailer line",
|
||||
.val = "",
|
||||
},
|
||||
{
|
||||
.raw = "not a trailer line\n",
|
||||
.key = "not a trailer line",
|
||||
.val = "",
|
||||
},
|
||||
{
|
||||
.raw = "Signed-off-by: x\n",
|
||||
.key = "Signed-off-by",
|
||||
.val = "x",
|
||||
},
|
||||
{
|
||||
0
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"with non-trailer lines (one too many) in trailer block",
|
||||
"subject: foo bar\n"
|
||||
"\n"
|
||||
/*
|
||||
* This block has only 20% trailers, so it's below the
|
||||
* 25% threshold.
|
||||
*/
|
||||
"not a trailer line\n"
|
||||
"not a trailer line\n"
|
||||
"not a trailer line\n"
|
||||
"not a trailer line\n"
|
||||
"Signed-off-by: x\n",
|
||||
0,
|
||||
{{0}},
|
||||
},
|
||||
{
|
||||
"with non-trailer lines (only 1) in trailer block, but no Git-generated trailers",
|
||||
"subject: foo bar\n"
|
||||
"\n"
|
||||
/*
|
||||
* This block has only 1 non-trailer out of 10 (IOW, 90%
|
||||
* trailers) but is not considered a trailer block
|
||||
* because the 25% threshold only applies to cases where
|
||||
* there was a Git-generated trailer.
|
||||
*/
|
||||
"Reviewed-by: x\n"
|
||||
"Reviewed-by: x\n"
|
||||
"Reviewed-by: x\n"
|
||||
"Helped-by: x\n"
|
||||
"Helped-by: x\n"
|
||||
"Helped-by: x\n"
|
||||
"Acked-by: x\n"
|
||||
"Acked-by: x\n"
|
||||
"Acked-by: x\n"
|
||||
"not a trailer line\n",
|
||||
0,
|
||||
{{0}},
|
||||
},
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(tc) / sizeof(tc[0]); i++) {
|
||||
TEST(t_trailer_iterator(tc[i].msg,
|
||||
tc[i].num_expected,
|
||||
tc[i].contents),
|
||||
"%s", tc[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
int cmd_main(int argc, const char **argv)
|
||||
{
|
||||
run_t_trailer_iterator();
|
||||
return test_done();
|
||||
}
|
169
trailer.c
169
trailer.c
@ -11,6 +11,27 @@
|
||||
* Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
|
||||
*/
|
||||
|
||||
struct trailer_info {
|
||||
/*
|
||||
* True if there is a blank line before the location pointed to by
|
||||
* trailer_block_start.
|
||||
*/
|
||||
int blank_line_before_trailer;
|
||||
|
||||
/*
|
||||
* Offsets to the trailer block start and end positions in the input
|
||||
* string. If no trailer block is found, these are both set to the
|
||||
* "true" end of the input (find_end_of_log_message()).
|
||||
*/
|
||||
size_t trailer_block_start, trailer_block_end;
|
||||
|
||||
/*
|
||||
* Array of trailers found.
|
||||
*/
|
||||
char **trailers;
|
||||
size_t trailer_nr;
|
||||
};
|
||||
|
||||
struct conf_info {
|
||||
char *name;
|
||||
char *key;
|
||||
@ -952,58 +973,16 @@ static void unfold_value(struct strbuf *val)
|
||||
strbuf_release(&out);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse trailers in "str", populating the trailer info and "head"
|
||||
* linked list structure.
|
||||
*/
|
||||
void parse_trailers(const struct process_trailer_options *opts,
|
||||
struct trailer_info *info,
|
||||
const char *str,
|
||||
struct list_head *head)
|
||||
static struct trailer_info *trailer_info_new(void)
|
||||
{
|
||||
struct strbuf tok = STRBUF_INIT;
|
||||
struct strbuf val = STRBUF_INIT;
|
||||
size_t i;
|
||||
|
||||
trailer_info_get(opts, str, info);
|
||||
|
||||
for (i = 0; i < info->trailer_nr; i++) {
|
||||
int separator_pos;
|
||||
char *trailer = info->trailers[i];
|
||||
if (starts_with(trailer, comment_line_str))
|
||||
continue;
|
||||
separator_pos = find_separator(trailer, separators);
|
||||
if (separator_pos >= 1) {
|
||||
parse_trailer(&tok, &val, NULL, trailer,
|
||||
separator_pos);
|
||||
if (opts->unfold)
|
||||
unfold_value(&val);
|
||||
add_trailer_item(head,
|
||||
strbuf_detach(&tok, NULL),
|
||||
strbuf_detach(&val, NULL));
|
||||
} else if (!opts->only_trailers) {
|
||||
strbuf_addstr(&val, trailer);
|
||||
strbuf_strip_suffix(&val, "\n");
|
||||
add_trailer_item(head,
|
||||
NULL,
|
||||
strbuf_detach(&val, NULL));
|
||||
}
|
||||
}
|
||||
struct trailer_info *info = xcalloc(1, sizeof(*info));
|
||||
return info;
|
||||
}
|
||||
|
||||
void free_trailers(struct list_head *trailers)
|
||||
{
|
||||
struct list_head *pos, *p;
|
||||
list_for_each_safe(pos, p, trailers) {
|
||||
list_del(pos);
|
||||
free_trailer_item(list_entry(pos, struct trailer_item, list));
|
||||
}
|
||||
}
|
||||
|
||||
void trailer_info_get(const struct process_trailer_options *opts,
|
||||
const char *str,
|
||||
struct trailer_info *info)
|
||||
static struct trailer_info *trailer_info_get(const struct process_trailer_options *opts,
|
||||
const char *str)
|
||||
{
|
||||
struct trailer_info *info = trailer_info_new();
|
||||
size_t end_of_log_message = 0, trailer_block_start = 0;
|
||||
struct strbuf **trailer_lines, **ptr;
|
||||
char **trailer_strings = NULL;
|
||||
@ -1042,6 +1021,73 @@ void trailer_info_get(const struct process_trailer_options *opts,
|
||||
info->trailer_block_end = end_of_log_message;
|
||||
info->trailers = trailer_strings;
|
||||
info->trailer_nr = nr;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse trailers in "str", populating the trailer info and "trailer_objects"
|
||||
* linked list structure.
|
||||
*/
|
||||
struct trailer_info *parse_trailers(const struct process_trailer_options *opts,
|
||||
const char *str,
|
||||
struct list_head *trailer_objects)
|
||||
{
|
||||
struct trailer_info *info;
|
||||
struct strbuf tok = STRBUF_INIT;
|
||||
struct strbuf val = STRBUF_INIT;
|
||||
size_t i;
|
||||
|
||||
info = trailer_info_get(opts, str);
|
||||
|
||||
for (i = 0; i < info->trailer_nr; i++) {
|
||||
int separator_pos;
|
||||
char *trailer = info->trailers[i];
|
||||
if (starts_with(trailer, comment_line_str))
|
||||
continue;
|
||||
separator_pos = find_separator(trailer, separators);
|
||||
if (separator_pos >= 1) {
|
||||
parse_trailer(&tok, &val, NULL, trailer,
|
||||
separator_pos);
|
||||
if (opts->unfold)
|
||||
unfold_value(&val);
|
||||
add_trailer_item(trailer_objects,
|
||||
strbuf_detach(&tok, NULL),
|
||||
strbuf_detach(&val, NULL));
|
||||
} else if (!opts->only_trailers) {
|
||||
strbuf_addstr(&val, trailer);
|
||||
strbuf_strip_suffix(&val, "\n");
|
||||
add_trailer_item(trailer_objects,
|
||||
NULL,
|
||||
strbuf_detach(&val, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void free_trailers(struct list_head *trailers)
|
||||
{
|
||||
struct list_head *pos, *p;
|
||||
list_for_each_safe(pos, p, trailers) {
|
||||
list_del(pos);
|
||||
free_trailer_item(list_entry(pos, struct trailer_item, list));
|
||||
}
|
||||
}
|
||||
|
||||
size_t trailer_block_start(struct trailer_info *info)
|
||||
{
|
||||
return info->trailer_block_start;
|
||||
}
|
||||
|
||||
size_t trailer_block_end(struct trailer_info *info)
|
||||
{
|
||||
return info->trailer_block_end;
|
||||
}
|
||||
|
||||
int blank_line_before_trailer_block(struct trailer_info *info)
|
||||
{
|
||||
return info->blank_line_before_trailer;
|
||||
}
|
||||
|
||||
void trailer_info_release(struct trailer_info *info)
|
||||
@ -1050,6 +1096,7 @@ void trailer_info_release(struct trailer_info *info)
|
||||
for (i = 0; i < info->trailer_nr; i++)
|
||||
free(info->trailers[i]);
|
||||
free(info->trailers);
|
||||
free(info);
|
||||
}
|
||||
|
||||
void format_trailers(const struct process_trailer_options *opts,
|
||||
@ -1117,21 +1164,19 @@ void format_trailers_from_commit(const struct process_trailer_options *opts,
|
||||
struct strbuf *out)
|
||||
{
|
||||
LIST_HEAD(trailer_objects);
|
||||
struct trailer_info info;
|
||||
|
||||
parse_trailers(opts, &info, msg, &trailer_objects);
|
||||
struct trailer_info *info = parse_trailers(opts, msg, &trailer_objects);
|
||||
|
||||
/* If we want the whole block untouched, we can take the fast path. */
|
||||
if (!opts->only_trailers && !opts->unfold && !opts->filter &&
|
||||
!opts->separator && !opts->key_only && !opts->value_only &&
|
||||
!opts->key_value_separator) {
|
||||
strbuf_add(out, msg + info.trailer_block_start,
|
||||
info.trailer_block_end - info.trailer_block_start);
|
||||
strbuf_add(out, msg + info->trailer_block_start,
|
||||
info->trailer_block_end - info->trailer_block_start);
|
||||
} else
|
||||
format_trailers(opts, &trailer_objects, out);
|
||||
|
||||
free_trailers(&trailer_objects);
|
||||
trailer_info_release(&info);
|
||||
trailer_info_release(info);
|
||||
}
|
||||
|
||||
void trailer_iterator_init(struct trailer_iterator *iter, const char *msg)
|
||||
@ -1140,23 +1185,21 @@ void trailer_iterator_init(struct trailer_iterator *iter, const char *msg)
|
||||
strbuf_init(&iter->key, 0);
|
||||
strbuf_init(&iter->val, 0);
|
||||
opts.no_divider = 1;
|
||||
trailer_info_get(&opts, msg, &iter->internal.info);
|
||||
iter->internal.info = trailer_info_get(&opts, msg);
|
||||
iter->internal.cur = 0;
|
||||
}
|
||||
|
||||
int trailer_iterator_advance(struct trailer_iterator *iter)
|
||||
{
|
||||
while (iter->internal.cur < iter->internal.info.trailer_nr) {
|
||||
char *trailer = iter->internal.info.trailers[iter->internal.cur++];
|
||||
int separator_pos = find_separator(trailer, separators);
|
||||
|
||||
if (separator_pos < 1)
|
||||
continue; /* not a real trailer */
|
||||
if (iter->internal.cur < iter->internal.info->trailer_nr) {
|
||||
char *line = iter->internal.info->trailers[iter->internal.cur++];
|
||||
int separator_pos = find_separator(line, separators);
|
||||
|
||||
iter->raw = line;
|
||||
strbuf_reset(&iter->key);
|
||||
strbuf_reset(&iter->val);
|
||||
parse_trailer(&iter->key, &iter->val, NULL,
|
||||
trailer, separator_pos);
|
||||
line, separator_pos);
|
||||
/* Always unfold values during iteration. */
|
||||
unfold_value(&iter->val);
|
||||
return 1;
|
||||
@ -1166,7 +1209,7 @@ int trailer_iterator_advance(struct trailer_iterator *iter)
|
||||
|
||||
void trailer_iterator_release(struct trailer_iterator *iter)
|
||||
{
|
||||
trailer_info_release(&iter->internal.info);
|
||||
trailer_info_release(iter->internal.info);
|
||||
strbuf_release(&iter->val);
|
||||
strbuf_release(&iter->key);
|
||||
}
|
||||
|
93
trailer.h
93
trailer.h
@ -4,6 +4,7 @@
|
||||
#include "list.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
struct trailer_info;
|
||||
struct strvec;
|
||||
|
||||
enum trailer_where {
|
||||
@ -31,27 +32,6 @@ int trailer_set_where(enum trailer_where *item, const char *value);
|
||||
int trailer_set_if_exists(enum trailer_if_exists *item, const char *value);
|
||||
int trailer_set_if_missing(enum trailer_if_missing *item, const char *value);
|
||||
|
||||
struct trailer_info {
|
||||
/*
|
||||
* True if there is a blank line before the location pointed to by
|
||||
* trailer_block_start.
|
||||
*/
|
||||
int blank_line_before_trailer;
|
||||
|
||||
/*
|
||||
* Offsets to the trailer block start and end positions in the input
|
||||
* string. If no trailer block is found, these are both set to the
|
||||
* "true" end of the input (find_end_of_log_message()).
|
||||
*/
|
||||
size_t trailer_block_start, trailer_block_end;
|
||||
|
||||
/*
|
||||
* Array of trailers found.
|
||||
*/
|
||||
char **trailers;
|
||||
size_t trailer_nr;
|
||||
};
|
||||
|
||||
/*
|
||||
* A list that represents newly-added trailers, such as those provided
|
||||
* with the --trailer command line option of git-interpret-trailers.
|
||||
@ -91,15 +71,63 @@ void parse_trailers_from_command_line_args(struct list_head *arg_head,
|
||||
void process_trailers_lists(struct list_head *head,
|
||||
struct list_head *arg_head);
|
||||
|
||||
void parse_trailers(const struct process_trailer_options *,
|
||||
struct trailer_info *,
|
||||
const char *str,
|
||||
struct list_head *head);
|
||||
/*
|
||||
* Given some input string "str", return a pointer to an opaque trailer_info
|
||||
* structure. Also populate the trailer_objects list with parsed trailer
|
||||
* objects. Internally this calls trailer_info_get() to get the opaque pointer,
|
||||
* but does some extra work to populate the trailer_objects linked list.
|
||||
*
|
||||
* The opaque trailer_info pointer can be used to check the position of the
|
||||
* trailer block as offsets relative to the beginning of "str" in
|
||||
* trailer_block_start() and trailer_block_end().
|
||||
* blank_line_before_trailer_block() returns 1 if there is a blank line just
|
||||
* before the trailer block. All of these functions are useful for preserving
|
||||
* the input before and after the trailer block, if we were to write out the
|
||||
* original input (but with the trailer block itself modified); see
|
||||
* builtin/interpret-trailers.c for an example.
|
||||
*
|
||||
* For iterating through the parsed trailer block (if you don't care about the
|
||||
* position of the trailer block itself in the context of the larger string text
|
||||
* from which it was parsed), please see trailer_iterator_init() which uses the
|
||||
* trailer_info struct internally.
|
||||
*
|
||||
* Lastly, callers should call trailer_info_release() when they are done using
|
||||
* the opaque pointer.
|
||||
*
|
||||
* NOTE: Callers should treat both trailer_info and trailer_objects as
|
||||
* read-only items, because there is some overlap between the two (trailer_info
|
||||
* has "char **trailers" string array, and trailer_objects will have the same
|
||||
* data but as a linked list of trailer_item objects). This API does not perform
|
||||
* any synchronization between the two. In the future we should be able to
|
||||
* reduce the duplication and use just the linked list.
|
||||
*/
|
||||
struct trailer_info *parse_trailers(const struct process_trailer_options *,
|
||||
const char *str,
|
||||
struct list_head *trailer_objects);
|
||||
|
||||
void trailer_info_get(const struct process_trailer_options *,
|
||||
const char *str,
|
||||
struct trailer_info *);
|
||||
/*
|
||||
* Return the offset of the start of the trailer block. That is, 0 is the start
|
||||
* of the input ("str" in parse_trailers()) and some other positive number
|
||||
* indicates how many bytes we have to skip over before we get to the beginning
|
||||
* of the trailer block.
|
||||
*/
|
||||
size_t trailer_block_start(struct trailer_info *);
|
||||
|
||||
/*
|
||||
* Return the end of the trailer block, again relative to the start of the
|
||||
* input.
|
||||
*/
|
||||
size_t trailer_block_end(struct trailer_info *);
|
||||
|
||||
/*
|
||||
* Return 1 if the trailer block had an extra newline (blank line) just before
|
||||
* it.
|
||||
*/
|
||||
int blank_line_before_trailer_block(struct trailer_info *);
|
||||
|
||||
/*
|
||||
* Free trailer_info struct.
|
||||
*/
|
||||
void trailer_info_release(struct trailer_info *info);
|
||||
|
||||
void trailer_config_init(void);
|
||||
@ -127,12 +155,19 @@ void format_trailers_from_commit(const struct process_trailer_options *,
|
||||
* trailer_iterator_release(&iter);
|
||||
*/
|
||||
struct trailer_iterator {
|
||||
/*
|
||||
* Raw line (e.g., "foo: bar baz") before being parsed as a trailer
|
||||
* key/val pair as part of a trailer block (as the "key" and "val"
|
||||
* fields below). If a line fails to parse as a trailer, then the "key"
|
||||
* will be the entire line and "val" will be the empty string.
|
||||
*/
|
||||
const char *raw;
|
||||
struct strbuf key;
|
||||
struct strbuf val;
|
||||
|
||||
/* private */
|
||||
struct {
|
||||
struct trailer_info info;
|
||||
struct trailer_info *info;
|
||||
size_t cur;
|
||||
} internal;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user