Skip to content

Commit fb58ca4

Browse files
FirstLoveLifegitster
authored andcommitted
trailer: append trailers in-process and drop the fork to interpret-trailers
All trailer insertion now funnels through trailer_process(): * builtin/interpret-trailers.c is reduced to file I/O + a single call. * amend_file_with_trailers() shares the same path; the old amend_strbuf_with_trailers() helper is dropped. * New helpers parse_trailer_args()/free_new_trailer_list() convert --trailer=... strings to new_trailer_item lists. Behaviour is unchanged; the full test-suite still passes, and the fork/exec is gone. Signed-off-by: Li Chen <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 866e6a3 commit fb58ca4

File tree

3 files changed

+158
-102
lines changed

3 files changed

+158
-102
lines changed

builtin/interpret-trailers.c

Lines changed: 27 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include "gettext.h"
1010
#include "parse-options.h"
1111
#include "string-list.h"
12-
#include "tempfile.h"
1312
#include "trailer.h"
1413
#include "config.h"
1514

@@ -84,6 +83,7 @@ static int parse_opt_parse(const struct option *opt, const char *arg,
8483
int unset)
8584
{
8685
struct process_trailer_options *v = opt->value;
86+
8787
v->only_trailers = 1;
8888
v->only_input = 1;
8989
v->unfold = 1;
@@ -92,37 +92,6 @@ static int parse_opt_parse(const struct option *opt, const char *arg,
9292
return 0;
9393
}
9494

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-
12695
static void read_input_file(struct strbuf *sb, const char *file)
12796
{
12897
if (file) {
@@ -135,61 +104,6 @@ static void read_input_file(struct strbuf *sb, const char *file)
135104
strbuf_complete_line(sb);
136105
}
137106

138-
static void interpret_trailers(const struct process_trailer_options *opts,
139-
struct list_head *new_trailer_head,
140-
const char *file)
141-
{
142-
LIST_HEAD(head);
143-
struct strbuf sb = STRBUF_INIT;
144-
struct strbuf trailer_block_sb = STRBUF_INIT;
145-
struct trailer_block *trailer_block;
146-
FILE *outfile = stdout;
147-
148-
trailer_config_init();
149-
150-
read_input_file(&sb, file);
151-
152-
if (opts->in_place)
153-
outfile = create_in_place_tempfile(file);
154-
155-
trailer_block = parse_trailers(opts, sb.buf, &head);
156-
157-
/* Print the lines before the trailer block */
158-
if (!opts->only_trailers)
159-
fwrite(sb.buf, 1, trailer_block_start(trailer_block), outfile);
160-
161-
if (!opts->only_trailers && !blank_line_before_trailer_block(trailer_block))
162-
fprintf(outfile, "\n");
163-
164-
165-
if (!opts->only_input) {
166-
LIST_HEAD(config_head);
167-
LIST_HEAD(arg_head);
168-
parse_trailers_from_config(&config_head);
169-
parse_trailers_from_command_line_args(&arg_head, new_trailer_head);
170-
list_splice(&config_head, &arg_head);
171-
process_trailers_lists(&head, &arg_head);
172-
}
173-
174-
/* Print trailer block. */
175-
format_trailers(opts, &head, &trailer_block_sb);
176-
free_trailers(&head);
177-
fwrite(trailer_block_sb.buf, 1, trailer_block_sb.len, outfile);
178-
strbuf_release(&trailer_block_sb);
179-
180-
/* Print the lines after the trailer block as is. */
181-
if (!opts->only_trailers)
182-
fwrite(sb.buf + trailer_block_end(trailer_block), 1,
183-
sb.len - trailer_block_end(trailer_block), outfile);
184-
trailer_block_release(trailer_block);
185-
186-
if (opts->in_place)
187-
if (rename_tempfile(&trailers_tempfile, file))
188-
die_errno(_("could not rename temporary file to %s"), file);
189-
190-
strbuf_release(&sb);
191-
}
192-
193107
int cmd_interpret_trailers(int argc,
194108
const char **argv,
195109
const char *prefix,
@@ -231,14 +145,37 @@ int cmd_interpret_trailers(int argc,
231145
git_interpret_trailers_usage,
232146
options);
233147

148+
trailer_config_init();
149+
234150
if (argc) {
235151
int i;
236-
for (i = 0; i < argc; i++)
237-
interpret_trailers(&opts, &trailers, argv[i]);
152+
for (i = 0; i < argc; i++) {
153+
struct strbuf in_buf = STRBUF_INIT;
154+
struct strbuf out_buf = STRBUF_INIT;
155+
156+
read_input_file(&in_buf, argv[i]);
157+
if (trailer_process(&opts, in_buf.buf, &trailers, &out_buf) < 0)
158+
die(_("failed to process trailers for %s"), argv[i]);
159+
if (opts.in_place)
160+
write_file_buf(argv[i], out_buf.buf, out_buf.len);
161+
else
162+
fwrite(out_buf.buf, 1, out_buf.len, stdout);
163+
strbuf_release(&in_buf);
164+
strbuf_release(&out_buf);
165+
}
238166
} else {
167+
struct strbuf in_buf = STRBUF_INIT;
168+
struct strbuf out_buf = STRBUF_INIT;
169+
239170
if (opts.in_place)
240171
die(_("no input file given for in-place editing"));
241-
interpret_trailers(&opts, &trailers, NULL);
172+
173+
read_input_file(&in_buf, NULL);
174+
if (trailer_process(&opts, in_buf.buf, &trailers, &out_buf) < 0)
175+
die(_("failed to process trailers"));
176+
fwrite(out_buf.buf, 1, out_buf.len, stdout);
177+
strbuf_release(&in_buf);
178+
strbuf_release(&out_buf);
242179
}
243180

244181
new_trailers_clear(&trailers);

trailer.c

Lines changed: 116 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,14 +1224,121 @@ void trailer_iterator_release(struct trailer_iterator *iter)
12241224
strbuf_release(&iter->key);
12251225
}
12261226

1227-
int amend_file_with_trailers(const char *path, const struct strvec *trailer_args)
1227+
static int amend_strbuf_with_trailers(struct strbuf *buf,
1228+
const struct strvec *trailer_args)
12281229
{
1229-
struct child_process run_trailer = CHILD_PROCESS_INIT;
1230-
1231-
run_trailer.git_cmd = 1;
1232-
strvec_pushl(&run_trailer.args, "interpret-trailers",
1233-
"--in-place", "--no-divider",
1234-
path, NULL);
1235-
strvec_pushv(&run_trailer.args, trailer_args->v);
1236-
return run_command(&run_trailer);
1230+
struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
1231+
LIST_HEAD(new_trailer_head);
1232+
struct strbuf out = STRBUF_INIT;
1233+
size_t i;
1234+
1235+
opts.no_divider = 1;
1236+
1237+
for (i = 0; i < trailer_args->nr; i++) {
1238+
const char *arg = trailer_args->v[i];
1239+
const char *text;
1240+
struct new_trailer_item *item;
1241+
if (!skip_prefix(arg, "--trailer=", &text))
1242+
text = arg;
1243+
if (!*text)
1244+
continue;
1245+
item = xcalloc(1, sizeof(*item));
1246+
INIT_LIST_HEAD(&item->list);
1247+
item->text = text;
1248+
list_add_tail(&item->list, &new_trailer_head);
1249+
}
1250+
if (trailer_process(&opts, buf->buf, &new_trailer_head, &out) < 0)
1251+
die("failed to process trailers");
1252+
strbuf_swap(buf, &out);
1253+
strbuf_release(&out);
1254+
while (!list_empty(&new_trailer_head)) {
1255+
struct new_trailer_item *item =
1256+
list_first_entry(&new_trailer_head, struct new_trailer_item, list);
1257+
list_del(&item->list);
1258+
free(item);
1259+
}
1260+
return 0;
12371261
}
1262+
1263+
int trailer_process(const struct process_trailer_options *opts,
1264+
const char *msg,
1265+
struct list_head *new_trailer_head,
1266+
struct strbuf *out)
1267+
{
1268+
struct trailer_block *blk;
1269+
LIST_HEAD(orig_head);
1270+
LIST_HEAD(config_head);
1271+
LIST_HEAD(arg_head);
1272+
struct strbuf trailers_sb = STRBUF_INIT;
1273+
int had_trailer_before;
1274+
1275+
blk = parse_trailers(opts, msg, &orig_head);
1276+
had_trailer_before = !list_empty(&orig_head);
1277+
if (!opts->only_input) {
1278+
parse_trailers_from_config(&config_head);
1279+
parse_trailers_from_command_line_args(&arg_head, new_trailer_head);
1280+
list_splice(&config_head, &arg_head);
1281+
process_trailers_lists(&orig_head, &arg_head);
1282+
}
1283+
format_trailers(opts, &orig_head, &trailers_sb);
1284+
if (!opts->only_trailers && !opts->only_input && !opts->unfold &&
1285+
!opts->trim_empty && list_empty(&orig_head) &&
1286+
(list_empty(new_trailer_head) || opts->only_input)) {
1287+
size_t split = trailer_block_start(blk); /* end-of-log-msg */
1288+
if (!blank_line_before_trailer_block(blk)) {
1289+
strbuf_add(out, msg, split);
1290+
strbuf_addch(out, '\n');
1291+
strbuf_addstr(out, msg + split);
1292+
} else
1293+
strbuf_addstr(out, msg);
1294+
1295+
strbuf_release(&trailers_sb);
1296+
trailer_block_release(blk);
1297+
return 0;
1298+
}
1299+
if (opts->only_trailers) {
1300+
strbuf_addbuf(out, &trailers_sb);
1301+
} else if (had_trailer_before) {
1302+
strbuf_add(out, msg, trailer_block_start(blk));
1303+
if (!blank_line_before_trailer_block(blk))
1304+
strbuf_addch(out, '\n');
1305+
strbuf_addbuf(out, &trailers_sb);
1306+
strbuf_add(out, msg + trailer_block_end(blk),
1307+
strlen(msg) - trailer_block_end(blk));
1308+
}
1309+
else {
1310+
size_t cpos = trailer_block_start(blk);
1311+
strbuf_add(out, msg, cpos);
1312+
if (cpos == 0) /* empty body → just one \n */
1313+
strbuf_addch(out, '\n');
1314+
else if (!blank_line_before_trailer_block(blk))
1315+
strbuf_addch(out, '\n'); /* body without trailing blank */
1316+
1317+
strbuf_addbuf(out, &trailers_sb);
1318+
strbuf_add(out, msg + cpos, strlen(msg) - cpos);
1319+
}
1320+
strbuf_release(&trailers_sb);
1321+
free_trailers(&orig_head);
1322+
trailer_block_release(blk);
1323+
return 0;
1324+
}
1325+
1326+
int amend_file_with_trailers(const char *path,
1327+
const struct strvec *trailer_args)
1328+
{
1329+
struct strbuf buf = STRBUF_INIT;
1330+
1331+
if (!trailer_args || !trailer_args->nr)
1332+
return 0;
1333+
1334+
if (strbuf_read_file(&buf, path, 0) < 0)
1335+
return error_errno("could not read '%s'", path);
1336+
1337+
if (amend_strbuf_with_trailers(&buf, trailer_args))
1338+
die("failed to append trailers");
1339+
1340+
/* `write_file_buf()` aborts on error internally */
1341+
write_file_buf(path, buf.buf, buf.len);
1342+
strbuf_release(&buf);
1343+
return 0;
1344+
}

trailer.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,22 @@ int trailer_iterator_advance(struct trailer_iterator *iter);
196196
void trailer_iterator_release(struct trailer_iterator *iter);
197197

198198
/*
199-
* Augment a file to add trailers to it by running git-interpret-trailers.
200-
* This calls run_command() and its return value is the same (i.e. 0 for
201-
* success, various non-zero for other errors). See run-command.h.
199+
* Augment a file to add trailers to it (similar to 'git interpret-trailers').
200+
* Returns 0 on success or a non-zero error code on failure.
202201
*/
203202
int amend_file_with_trailers(const char *path, const struct strvec *trailer_args);
204203

204+
/*
205+
* Process trailer lines for a commit message in-memory.
206+
* @opts: trailer processing options (e.g. from parse-options)
207+
* @msg: the input message string
208+
* @new_trailer_head: list of new trailers to add (struct new_trailer_item)
209+
* @out: strbuf to store the resulting message (must be initialized)
210+
*
211+
* Returns 0 on success, <0 on error.
212+
*/
213+
int trailer_process(const struct process_trailer_options *opts,
214+
const char *msg,
215+
struct list_head *new_trailer_head,
216+
struct strbuf *out);
205217
#endif /* TRAILER_H */

0 commit comments

Comments
 (0)