#include "string-list.h"
#include "run-command.h"
#include "commit.h"
+#include "strvec.h"
#include "trailer.h"
#include "list.h"
#include "tempfile.h"
free(cl_separators);
}
+int validate_trailer_args(const struct strvec *cli_args)
+{
+ char *cl_separators;
+ int ret = 0;
+
+ trailer_config_init();
+
+ cl_separators = xstrfmt("=%s", separators);
+
+ for (size_t i = 0; i < cli_args->nr; i++) {
+ const char *txt = cli_args->v[i];
+ ssize_t separator_pos;
+
+ if (!*txt) {
+ ret = error(_("empty --trailer argument"));
+ goto out;
+ }
+ separator_pos = find_separator(txt, cl_separators);
+ if (separator_pos == 0) {
+ ret = error(_("invalid trailer '%s': missing key before separator"),
+ txt);
+ goto out;
+ }
+ }
+out:
+ free(cl_separators);
+ return ret;
+}
+
static const char *next_line(const char *str)
{
const char *nl = strchrnul(str, '\n');
return tempfile;
}
-int amend_file_with_trailers(const char *path, const struct strvec *trailer_args)
+int amend_strbuf_with_trailers(struct strbuf *buf,
+ const struct strvec *trailer_args)
{
- struct child_process run_trailer = CHILD_PROCESS_INIT;
-
- run_trailer.git_cmd = 1;
- strvec_pushl(&run_trailer.args, "interpret-trailers",
- "--in-place", "--no-divider",
- path, NULL);
- strvec_pushv(&run_trailer.args, trailer_args->v);
- return run_command(&run_trailer);
+ struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
+ LIST_HEAD(new_trailer_head);
+ struct strbuf out = STRBUF_INIT;
+ size_t i;
+ int ret = 0;
+
+ opts.no_divider = 1;
+
+ for (i = 0; i < trailer_args->nr; i++) {
+ const char *text = trailer_args->v[i];
+ struct new_trailer_item *item;
+
+ if (!*text) {
+ ret = error(_("empty --trailer argument"));
+ goto out;
+ }
+ item = xcalloc(1, sizeof(*item));
+ item->text = xstrdup(text);
+ list_add_tail(&item->list, &new_trailer_head);
+ }
+
+ process_trailers(&opts, &new_trailer_head, buf, &out);
+
+ strbuf_swap(buf, &out);
+out:
+ strbuf_release(&out);
+ free_trailers(&new_trailer_head);
+
+ return ret;
+}
+
+static int write_file_in_place(const char *path, const struct strbuf *buf)
+{
+ struct tempfile *tempfile = trailer_create_in_place_tempfile(path);
+ if (!tempfile)
+ return -1;
+
+ if (write_in_full(tempfile->fd, buf->buf, buf->len) < 0)
+ return error_errno(_("could not write to temporary file"));
+
+ if (rename_tempfile(&tempfile, path))
+ return error_errno(_("could not rename temporary file to %s"), path);
+
+ return 0;
+}
+
+int amend_file_with_trailers(const char *path,
+ const struct strvec *trailer_args)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct strvec stripped_trailer_args = STRVEC_INIT;
+ int ret = 0;
+ size_t i;
+
+ if (!trailer_args)
+ BUG("amend_file_with_trailers called with NULL trailer_args");
+ if (!trailer_args->nr)
+ return 0;
+
+ for (i = 0; i < trailer_args->nr; i++) {
+ const char *txt = trailer_args->v[i];
+
+ /*
+ * Historically amend_file_with_trailers() passed its arguments
+ * to "git interpret-trailers", which expected argv entries in
+ * "--trailer=<trailer>" form. Continue to accept those for
+ * existing callers, but pass only the value portion to the
+ * in-process implementation.
+ */
+ skip_prefix(txt, "--trailer=", &txt);
+ if (!*txt) {
+ ret = error(_("empty --trailer argument"));
+ goto out;
+ }
+ strvec_push(&stripped_trailer_args, txt);
+ }
+
+ if (validate_trailer_args(&stripped_trailer_args)) {
+ ret = -1;
+ goto out;
+ }
+ if (strbuf_read_file(&buf, path, 0) < 0)
+ ret = error_errno(_("could not read '%s'"), path);
+ else
+ amend_strbuf_with_trailers(&buf, &stripped_trailer_args);
+
+ if (!ret)
+ ret = write_file_in_place(path, &buf);
+out:
+ strvec_clear(&stripped_trailer_args);
+ strbuf_release(&buf);
+ return ret;
}
void process_trailers(const struct process_trailer_options *opts,
void parse_trailers_from_command_line_args(struct list_head *arg_head,
struct list_head *new_trailer_head);
+int validate_trailer_args(const struct strvec *cli_args);
+
void process_trailers_lists(struct list_head *head,
struct list_head *arg_head);
void trailer_iterator_release(struct trailer_iterator *iter);
/*
- * Augment a file to add trailers to it by running git-interpret-trailers.
- * This calls run_command() and its return value is the same (i.e. 0 for
- * success, various non-zero for other errors). See run-command.h.
+ * Append trailers specified in trailer_args to buf in-place.
+ *
+ * Each element of trailer_args should be in the same format as the value
+ * accepted by --trailer=<trailer> (i.e., without the --trailer= prefix).
+ */
+int amend_strbuf_with_trailers(struct strbuf *buf,
+ const struct strvec *trailer_args);
+
+/*
+ * Augment a file by appending trailers specified in trailer_args.
+ *
+ * Each element of trailer_args should be an argv-style --trailer=<trailer>
+ * option (i.e., including the --trailer= prefix).
+ *
+ * Returns 0 on success or a non-zero error code on failure.
*/
int amend_file_with_trailers(const char *path, const struct strvec *trailer_args);