7
#include "string-list.h"
8
#include "run-command.h"
9
#include "commit.h"
10
+#include "strvec.h"
11
#include "trailer.h"
12
#include "list.h"
13
#include "tempfile.h"
775
free(cl_separators);
776
}
777
778
+int validate_trailer_args(const struct strvec *cli_args)
779
+{
780
+ char *cl_separators;
781
+ int ret = 0;
782
+
783
+ trailer_config_init();
784
+
785
+ cl_separators = xstrfmt("=%s", separators);
786
+
787
+ for (size_t i = 0; i < cli_args->nr; i++) {
788
+ const char *txt = cli_args->v[i];
789
+ ssize_t separator_pos;
790
+
791
+ if (!*txt) {
792
+ ret = error(_("empty --trailer argument"));
793
+ goto out;
794
+ }
795
+ separator_pos = find_separator(txt, cl_separators);
796
+ if (separator_pos == 0) {
797
+ ret = error(_("invalid trailer '%s': missing key before separator"),
798
+ txt);
799
+ goto out;
800
+ }
801
+ }
802
+out:
803
+ free(cl_separators);
804
+ return ret;
805
+}
806
+
807
static const char *next_line(const char *str)
808
{
809
const char *nl = strchrnul(str, '\n');
1288
return tempfile;
1289
}
1290
1261
-int amend_file_with_trailers(const char *path, const struct strvec *trailer_args)
1291
+int amend_strbuf_with_trailers(struct strbuf *buf,
1292
+ const struct strvec *trailer_args)
1293
{
1263
- struct child_process run_trailer = CHILD_PROCESS_INIT;
1264
-
1265
- run_trailer.git_cmd = 1;
1266
- strvec_pushl(&run_trailer.args, "interpret-trailers",
1267
- "--in-place", "--no-divider",
1268
- path, NULL);
1269
- strvec_pushv(&run_trailer.args, trailer_args->v);
1270
- return run_command(&run_trailer);
1294
+ struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
1295
+ LIST_HEAD(new_trailer_head);
1296
+ struct strbuf out = STRBUF_INIT;
1297
+ size_t i;
1298
+ int ret = 0;
1299
+
1300
+ opts.no_divider = 1;
1301
+
1302
+ for (i = 0; i < trailer_args->nr; i++) {
1303
+ const char *text = trailer_args->v[i];
1304
+ struct new_trailer_item *item;
1305
+
1306
+ if (!*text) {
1307
+ ret = error(_("empty --trailer argument"));
1308
+ goto out;
1309
+ }
1310
+ item = xcalloc(1, sizeof(*item));
1311
+ item->text = xstrdup(text);
1312
+ list_add_tail(&item->list, &new_trailer_head);
1313
+ }
1314
+
1315
+ process_trailers(&opts, &new_trailer_head, buf, &out);
1316
+
1317
+ strbuf_swap(buf, &out);
1318
+out:
1319
+ strbuf_release(&out);
1320
+ free_trailers(&new_trailer_head);
1321
+
1322
+ return ret;
1323
+}
1324
+
1325
+static int write_file_in_place(const char *path, const struct strbuf *buf)
1326
+{
1327
+ struct tempfile *tempfile = trailer_create_in_place_tempfile(path);
1328
+ if (!tempfile)
1329
+ return -1;
1330
+
1331
+ if (write_in_full(tempfile->fd, buf->buf, buf->len) < 0)
1332
+ return error_errno(_("could not write to temporary file"));
1333
+
1334
+ if (rename_tempfile(&tempfile, path))
1335
+ return error_errno(_("could not rename temporary file to %s"), path);
1336
+
1337
+ return 0;
1338
+}
1339
+
1340
+int amend_file_with_trailers(const char *path,
1341
+ const struct strvec *trailer_args)
1342
+{
1343
+ struct strbuf buf = STRBUF_INIT;
1344
+ struct strvec stripped_trailer_args = STRVEC_INIT;
1345
+ int ret = 0;
1346
+ size_t i;
1347
+
1348
+ if (!trailer_args)
1349
+ BUG("amend_file_with_trailers called with NULL trailer_args");
1350
+ if (!trailer_args->nr)
1351
+ return 0;
1352
+
1353
+ for (i = 0; i < trailer_args->nr; i++) {
1354
+ const char *txt = trailer_args->v[i];
1355
+
1356
+ /*
1357
+ * Historically amend_file_with_trailers() passed its arguments
1358
+ * to "git interpret-trailers", which expected argv entries in
1359
+ * "--trailer=<trailer>" form. Continue to accept those for
1360
+ * existing callers, but pass only the value portion to the
1361
+ * in-process implementation.
1362
+ */
1363
+ skip_prefix(txt, "--trailer=", &txt);
1364
+ if (!*txt) {
1365
+ ret = error(_("empty --trailer argument"));
1366
+ goto out;
1367
+ }
1368
+ strvec_push(&stripped_trailer_args, txt);
1369
+ }
1370
+
1371
+ if (validate_trailer_args(&stripped_trailer_args)) {
1372
+ ret = -1;
1373
+ goto out;
1374
+ }
1375
+ if (strbuf_read_file(&buf, path, 0) < 0)
1376
+ ret = error_errno(_("could not read '%s'"), path);
1377
+ else
1378
+ amend_strbuf_with_trailers(&buf, &stripped_trailer_args);
1379
+
1380
+ if (!ret)
1381
+ ret = write_file_in_place(path, &buf);
1382
+out:
1383
+ strvec_clear(&stripped_trailer_args);
1384
+ strbuf_release(&buf);
1385
+ return ret;
1386
}
1387
1388
void process_trailers(const struct process_trailer_options *opts,