Skip to content

Commit 4fecb94

Browse files
committed
Merge branch 'la/trailer-api'
Trailer API updates. Acked-by: Christian Couder <[email protected]> cf. <CAP8UFD1Zd+9q0z1JmfOf60S2vn5-sD3SafDvAJUzRFwHJKcb8A@mail.gmail.com> * la/trailer-api: format_trailers_from_commit(): indirectly call trailer_info_get() format_trailer_info(): move "fast path" to caller format_trailers(): use strbuf instead of FILE trailer_info_get(): reorder parameters trailer: move interpret_trailers() to interpret-trailers.c trailer: reorder format_trailers_from_commit() parameters trailer: rename functions to use 'trailer' shortlog: add test for de-duplicating folded trailers trailer: free trailer_info _after_ all related usage
2 parents 26ab20c + 35ca441 commit 4fecb94

File tree

7 files changed

+204
-147
lines changed

7 files changed

+204
-147
lines changed

builtin/interpret-trailers.c

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "gettext.h"
1010
#include "parse-options.h"
1111
#include "string-list.h"
12+
#include "tempfile.h"
1213
#include "trailer.h"
1314
#include "config.h"
1415

@@ -91,6 +92,102 @@ static int parse_opt_parse(const struct option *opt, const char *arg,
9192
return 0;
9293
}
9394

95+
static struct tempfile *trailers_tempfile;
96+
97+
static FILE *create_in_place_tempfile(const char *file)
98+
{
99+
struct stat st;
100+
struct strbuf filename_template = STRBUF_INIT;
101+
const char *tail;
102+
FILE *outfile;
103+
104+
if (stat(file, &st))
105+
die_errno(_("could not stat %s"), file);
106+
if (!S_ISREG(st.st_mode))
107+
die(_("file %s is not a regular file"), file);
108+
if (!(st.st_mode & S_IWUSR))
109+
die(_("file %s is not writable by user"), file);
110+
111+
/* Create temporary file in the same directory as the original */
112+
tail = strrchr(file, '/');
113+
if (tail)
114+
strbuf_add(&filename_template, file, tail - file + 1);
115+
strbuf_addstr(&filename_template, "git-interpret-trailers-XXXXXX");
116+
117+
trailers_tempfile = xmks_tempfile_m(filename_template.buf, st.st_mode);
118+
strbuf_release(&filename_template);
119+
outfile = fdopen_tempfile(trailers_tempfile, "w");
120+
if (!outfile)
121+
die_errno(_("could not open temporary file"));
122+
123+
return outfile;
124+
}
125+
126+
static void read_input_file(struct strbuf *sb, const char *file)
127+
{
128+
if (file) {
129+
if (strbuf_read_file(sb, file, 0) < 0)
130+
die_errno(_("could not read input file '%s'"), file);
131+
} else {
132+
if (strbuf_read(sb, fileno(stdin), 0) < 0)
133+
die_errno(_("could not read from stdin"));
134+
}
135+
}
136+
137+
static void interpret_trailers(const struct process_trailer_options *opts,
138+
struct list_head *new_trailer_head,
139+
const char *file)
140+
{
141+
LIST_HEAD(head);
142+
struct strbuf sb = STRBUF_INIT;
143+
struct strbuf trailer_block = STRBUF_INIT;
144+
struct trailer_info info;
145+
FILE *outfile = stdout;
146+
147+
trailer_config_init();
148+
149+
read_input_file(&sb, file);
150+
151+
if (opts->in_place)
152+
outfile = create_in_place_tempfile(file);
153+
154+
parse_trailers(opts, &info, sb.buf, &head);
155+
156+
/* Print the lines before the trailers */
157+
if (!opts->only_trailers)
158+
fwrite(sb.buf, 1, info.trailer_block_start, outfile);
159+
160+
if (!opts->only_trailers && !info.blank_line_before_trailer)
161+
fprintf(outfile, "\n");
162+
163+
164+
if (!opts->only_input) {
165+
LIST_HEAD(config_head);
166+
LIST_HEAD(arg_head);
167+
parse_trailers_from_config(&config_head);
168+
parse_trailers_from_command_line_args(&arg_head, new_trailer_head);
169+
list_splice(&config_head, &arg_head);
170+
process_trailers_lists(&head, &arg_head);
171+
}
172+
173+
/* Print trailer block. */
174+
format_trailers(opts, &head, &trailer_block);
175+
free_trailers(&head);
176+
fwrite(trailer_block.buf, 1, trailer_block.len, outfile);
177+
strbuf_release(&trailer_block);
178+
179+
/* Print the lines after the trailers as is */
180+
if (!opts->only_trailers)
181+
fwrite(sb.buf + info.trailer_block_end, 1, sb.len - info.trailer_block_end, outfile);
182+
trailer_info_release(&info);
183+
184+
if (opts->in_place)
185+
if (rename_tempfile(&trailers_tempfile, file))
186+
die_errno(_("could not rename temporary file to %s"), file);
187+
188+
strbuf_release(&sb);
189+
}
190+
94191
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
95192
{
96193
struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
@@ -132,11 +229,11 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
132229
if (argc) {
133230
int i;
134231
for (i = 0; i < argc; i++)
135-
process_trailers(argv[i], &opts, &trailers);
232+
interpret_trailers(&opts, &trailers, argv[i]);
136233
} else {
137234
if (opts.in_place)
138235
die(_("no input file given for in-place editing"));
139-
process_trailers(NULL, &opts, &trailers);
236+
interpret_trailers(&opts, &trailers, NULL);
140237
}
141238

142239
new_trailers_clear(&trailers);

pretty.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1759,7 +1759,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
17591759
goto trailer_out;
17601760
}
17611761
if (*arg == ')') {
1762-
format_trailers_from_commit(sb, msg + c->subject_off, &opts);
1762+
format_trailers_from_commit(&opts, msg + c->subject_off, sb);
17631763
ret = arg - placeholder + 1;
17641764
}
17651765
trailer_out:

ref-filter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1991,7 +1991,7 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct exp
19911991
struct strbuf s = STRBUF_INIT;
19921992

19931993
/* Format the trailer info according to the trailer_opts given */
1994-
format_trailers_from_commit(&s, subpos, &atom->u.contents.trailer_opts);
1994+
format_trailers_from_commit(&atom->u.contents.trailer_opts, subpos, &s);
19951995

19961996
v->s = strbuf_detach(&s, NULL);
19971997
} else if (atom->u.contents.option == C_BARE)

sequencer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,
332332
sb->buf[sb->len - ignore_footer] = '\0';
333333
}
334334

335-
trailer_info_get(&info, sb->buf, &opts);
335+
trailer_info_get(&opts, sb->buf, &info);
336336

337337
if (ignore_footer)
338338
sb->buf[sb->len - ignore_footer] = saved_char;

t/t4201-shortlog.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,38 @@ test_expect_success 'shortlog de-duplicates trailers in a single commit' '
312312
test_cmp expect actual
313313
'
314314

315+
# Trailers that have unfolded (single line) and folded (multiline) values which
316+
# are otherwise identical are treated as the same trailer for de-duplication.
317+
test_expect_success 'shortlog de-duplicates trailers in a single commit (folded/unfolded values)' '
318+
git commit --allow-empty -F - <<-\EOF &&
319+
subject one
320+
321+
this message has two distinct values, plus a repeat (folded)
322+
323+
Repeated-trailer: Foo foo foo
324+
Repeated-trailer: Bar
325+
Repeated-trailer: Foo
326+
foo foo
327+
EOF
328+
329+
git commit --allow-empty -F - <<-\EOF &&
330+
subject two
331+
332+
similar to the previous, but without the second distinct value
333+
334+
Repeated-trailer: Foo foo foo
335+
Repeated-trailer: Foo
336+
foo foo
337+
EOF
338+
339+
cat >expect <<-\EOF &&
340+
2 Foo foo foo
341+
1 Bar
342+
EOF
343+
git shortlog -ns --group=trailer:repeated-trailer -2 HEAD >actual &&
344+
test_cmp expect actual
345+
'
346+
315347
test_expect_success 'shortlog can match multiple groups' '
316348
git commit --allow-empty -F - <<-\EOF &&
317349
subject one

0 commit comments

Comments
 (0)