builtin/apply: make apply_all_patches() return 128 or 1 on error
[gitweb.git] / builtin / am.c
index 5668e0c3a5a7e04d266b20e2a5ae60f2a7aa98cd..b77bf11acecd7cd80171c78378154c712415af6f 100644 (file)
@@ -45,21 +45,6 @@ static int is_empty_file(const char *filename)
        return !st.st_size;
 }
 
-/**
- * Like strbuf_getline(), but treats both '\n' and "\r\n" as line terminators.
- */
-static int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)
-{
-       if (strbuf_getwholeline(sb, fp, '\n'))
-               return EOF;
-       if (sb->buf[sb->len - 1] == '\n') {
-               strbuf_setlen(sb, sb->len - 1);
-               if (sb->len > 0 && sb->buf[sb->len - 1] == '\r')
-                       strbuf_setlen(sb, sb->len - 1);
-       }
-       return 0;
-}
-
 /**
  * Returns the length of the first line of msg.
  */
@@ -85,7 +70,8 @@ enum patch_format {
        PATCH_FORMAT_MBOX,
        PATCH_FORMAT_STGIT,
        PATCH_FORMAT_STGIT_SERIES,
-       PATCH_FORMAT_HG
+       PATCH_FORMAT_HG,
+       PATCH_FORMAT_MBOXRD
 };
 
 enum keep_type {
@@ -198,22 +184,22 @@ static inline const char *am_path(const struct am_state *state, const char *path
 /**
  * For convenience to call write_file()
  */
-static int write_state_text(const struct am_state *state,
-                           const char *name, const char *string)
+static void write_state_text(const struct am_state *state,
+                            const char *name, const char *string)
 {
-       return write_file(am_path(state, name), "%s", string);
+       write_file(am_path(state, name), "%s", string);
 }
 
-static int write_state_count(const struct am_state *state,
-                            const char *name, int value)
+static void write_state_count(const struct am_state *state,
+                             const char *name, int value)
 {
-       return write_file(am_path(state, name), "%d", value);
+       write_file(am_path(state, name), "%d", value);
 }
 
-static int write_state_bool(const struct am_state *state,
-                           const char *name, int value)
+static void write_state_bool(const struct am_state *state,
+                            const char *name, int value)
 {
-       return write_state_text(state, name, value ? "t" : "f");
+       write_state_text(state, name, value ? "t" : "f");
 }
 
 /**
@@ -284,7 +270,7 @@ static char *read_shell_var(FILE *fp, const char *key)
        struct strbuf sb = STRBUF_INIT;
        const char *str;
 
-       if (strbuf_getline(&sb, fp, '\n'))
+       if (strbuf_getline_lf(&sb, fp))
                goto fail;
 
        if (!skip_prefix(sb.buf, key, &str))
@@ -417,13 +403,8 @@ static int read_commit_msg(struct am_state *state)
  */
 static void write_commit_msg(const struct am_state *state)
 {
-       int fd;
        const char *filename = am_path(state, "final-commit");
-
-       fd = xopen(filename, O_WRONLY | O_CREAT, 0666);
-       if (write_in_full(fd, state->msg, state->msg_len) < 0)
-               die_errno(_("could not write to %s"), filename);
-       close(fd);
+       write_file_buf(filename, state->msg, state->msg_len);
 }
 
 /**
@@ -573,7 +554,7 @@ static int copy_notes_for_rebase(const struct am_state *state)
 
        fp = xfopen(am_path(state, "rewritten"), "r");
 
-       while (!strbuf_getline(&sb, fp, '\n')) {
+       while (!strbuf_getline_lf(&sb, fp)) {
                unsigned char from_obj[GIT_SHA1_RAWSZ], to_obj[GIT_SHA1_RAWSZ];
 
                if (sb.len != GIT_SHA1_HEXSZ * 2 + 1) {
@@ -628,7 +609,7 @@ static int is_mail(FILE *fp)
        if (regcomp(&regex, header_regex, REG_NOSUB | REG_EXTENDED))
                die("invalid pattern: %s", header_regex);
 
-       while (!strbuf_getline_crlf(&sb, fp)) {
+       while (!strbuf_getline(&sb, fp)) {
                if (!sb.len)
                        break; /* End of header */
 
@@ -675,7 +656,7 @@ static int detect_patch_format(const char **paths)
 
        fp = xfopen(*paths, "r");
 
-       while (!strbuf_getline_crlf(&l1, fp)) {
+       while (!strbuf_getline(&l1, fp)) {
                if (l1.len)
                        break;
        }
@@ -696,9 +677,9 @@ static int detect_patch_format(const char **paths)
        }
 
        strbuf_reset(&l2);
-       strbuf_getline_crlf(&l2, fp);
+       strbuf_getline(&l2, fp);
        strbuf_reset(&l3);
-       strbuf_getline_crlf(&l3, fp);
+       strbuf_getline(&l3, fp);
 
        /*
         * If the second line is empty and the third is a From, Author or Date
@@ -727,7 +708,8 @@ static int detect_patch_format(const char **paths)
  * Splits out individual email patches from `paths`, where each path is either
  * a mbox file or a Maildir. Returns 0 on success, -1 on failure.
  */
-static int split_mail_mbox(struct am_state *state, const char **paths, int keep_cr)
+static int split_mail_mbox(struct am_state *state, const char **paths,
+                               int keep_cr, int mboxrd)
 {
        struct child_process cp = CHILD_PROCESS_INIT;
        struct strbuf last = STRBUF_INIT;
@@ -739,6 +721,8 @@ static int split_mail_mbox(struct am_state *state, const char **paths, int keep_
        argv_array_push(&cp.args, "-b");
        if (keep_cr)
                argv_array_push(&cp.args, "--keep-cr");
+       if (mboxrd)
+               argv_array_push(&cp.args, "--mboxrd");
        argv_array_push(&cp.args, "--");
        argv_array_pushv(&cp.args, paths);
 
@@ -784,15 +768,15 @@ static int split_mail_conv(mail_conv_fn fn, struct am_state *state,
                        in = fopen(*paths, "r");
 
                if (!in)
-                       return error(_("could not open '%s' for reading: %s"),
-                                       *paths, strerror(errno));
+                       return error_errno(_("could not open '%s' for reading"),
+                                          *paths);
 
                mail = mkpath("%s/%0*d", state->dir, state->prec, i + 1);
 
                out = fopen(mail, "w");
                if (!out)
-                       return error(_("could not open '%s' for writing: %s"),
-                                       mail, strerror(errno));
+                       return error_errno(_("could not open '%s' for writing"),
+                                          mail);
 
                ret = fn(out, in, keep_cr);
 
@@ -817,7 +801,7 @@ static int stgit_patch_to_mail(FILE *out, FILE *in, int keep_cr)
        struct strbuf sb = STRBUF_INIT;
        int subject_printed = 0;
 
-       while (!strbuf_getline(&sb, in, '\n')) {
+       while (!strbuf_getline_lf(&sb, in)) {
                const char *str;
 
                if (str_isspace(sb.buf))
@@ -872,10 +856,9 @@ static int split_mail_stgit_series(struct am_state *state, const char **paths,
 
        fp = fopen(*paths, "r");
        if (!fp)
-               return error(_("could not open '%s' for reading: %s"), *paths,
-                               strerror(errno));
+               return error_errno(_("could not open '%s' for reading"), *paths);
 
-       while (!strbuf_getline(&sb, fp, '\n')) {
+       while (!strbuf_getline_lf(&sb, fp)) {
                if (*sb.buf == '#')
                        continue; /* skip comment lines */
 
@@ -900,7 +883,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)
 {
        struct strbuf sb = STRBUF_INIT;
 
-       while (!strbuf_getline(&sb, in, '\n')) {
+       while (!strbuf_getline_lf(&sb, in)) {
                const char *str;
 
                if (skip_prefix(sb.buf, "# User ", &str))
@@ -981,13 +964,15 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
 
        switch (patch_format) {
        case PATCH_FORMAT_MBOX:
-               return split_mail_mbox(state, paths, keep_cr);
+               return split_mail_mbox(state, paths, keep_cr, 0);
        case PATCH_FORMAT_STGIT:
                return split_mail_conv(stgit_patch_to_mail, state, paths, keep_cr);
        case PATCH_FORMAT_STGIT_SERIES:
                return split_mail_stgit_series(state, paths, keep_cr);
        case PATCH_FORMAT_HG:
                return split_mail_conv(hg_patch_to_mail, state, paths, keep_cr);
+       case PATCH_FORMAT_MBOXRD:
+               return split_mail_mbox(state, paths, keep_cr, 1);
        default:
                die("BUG: invalid patch_format");
        }
@@ -1317,7 +1302,7 @@ static int parse_mail(struct am_state *state, const char *mail)
 
        /* Extract message and author information */
        fp = xfopen(am_path(state, "info"), "r");
-       while (!strbuf_getline(&sb, fp, '\n')) {
+       while (!strbuf_getline_lf(&sb, fp)) {
                const char *x;
 
                if (skip_prefix(sb.buf, "Subject: ", &x)) {
@@ -1383,7 +1368,7 @@ static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail)
        FILE *fp = xfopen(mail, "r");
        const char *x;
 
-       if (strbuf_getline(&sb, fp, '\n'))
+       if (strbuf_getline_lf(&sb, fp))
                return -1;
 
        if (!skip_prefix(sb.buf, "From ", &x))
@@ -1594,14 +1579,14 @@ static int build_fake_ancestor(const struct am_state *state, const char *index_f
 }
 
 /**
- * Do the three-way merge using fake ancestor, his tree constructed
+ * Do the three-way merge using fake ancestor, their tree constructed
  * from the fake ancestor and the postimage of the patch, and our
  * state.
  */
 static int run_fallback_merge_recursive(const struct am_state *state,
                                        unsigned char *orig_tree,
                                        unsigned char *our_tree,
-                                       unsigned char *his_tree)
+                                       unsigned char *their_tree)
 {
        struct child_process cp = CHILD_PROCESS_INIT;
        int status;
@@ -1609,7 +1594,7 @@ static int run_fallback_merge_recursive(const struct am_state *state,
        cp.git_cmd = 1;
 
        argv_array_pushf(&cp.env_array, "GITHEAD_%s=%.*s",
-                        sha1_to_hex(his_tree), linelen(state->msg), state->msg);
+                        sha1_to_hex(their_tree), linelen(state->msg), state->msg);
        if (state->quiet)
                argv_array_push(&cp.env_array, "GIT_MERGE_VERBOSITY=0");
 
@@ -1617,7 +1602,7 @@ static int run_fallback_merge_recursive(const struct am_state *state,
        argv_array_push(&cp.args, sha1_to_hex(orig_tree));
        argv_array_push(&cp.args, "--");
        argv_array_push(&cp.args, sha1_to_hex(our_tree));
-       argv_array_push(&cp.args, sha1_to_hex(his_tree));
+       argv_array_push(&cp.args, sha1_to_hex(their_tree));
 
        status = run_command(&cp) ? (-1) : 0;
        discard_cache();
@@ -1630,7 +1615,7 @@ static int run_fallback_merge_recursive(const struct am_state *state,
  */
 static int fall_back_threeway(const struct am_state *state, const char *index_path)
 {
-       unsigned char orig_tree[GIT_SHA1_RAWSZ], his_tree[GIT_SHA1_RAWSZ],
+       unsigned char orig_tree[GIT_SHA1_RAWSZ], their_tree[GIT_SHA1_RAWSZ],
                      our_tree[GIT_SHA1_RAWSZ];
 
        if (get_sha1("HEAD", our_tree) < 0)
@@ -1667,7 +1652,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
                return error(_("Did you hand edit your patch?\n"
                                "It does not apply to blobs recorded in its index."));
 
-       if (write_index_as_tree(his_tree, &the_index, index_path, 0, NULL))
+       if (write_index_as_tree(their_tree, &the_index, index_path, 0, NULL))
                return error("could not write tree");
 
        say(state, stdout, _("Falling back to patching base and 3-way merge..."));
@@ -1677,13 +1662,13 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
 
        /*
         * This is not so wrong. Depending on which base we picked, orig_tree
-        * may be wildly different from ours, but his_tree has the same set of
+        * may be wildly different from ours, but their_tree has the same set of
         * wildly different changes in parts the patch did not touch, so
         * recursive ends up canceling them, saying that we reverted all those
         * changes.
         */
 
-       if (run_fallback_merge_recursive(state, orig_tree, our_tree, his_tree)) {
+       if (run_fallback_merge_recursive(state, orig_tree, our_tree, their_tree)) {
                rerere(state->allow_rerere_autoupdate);
                return error(_("Failed to merge in the changes."));
        }
@@ -2217,6 +2202,8 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
                *opt_value = PATCH_FORMAT_STGIT_SERIES;
        else if (!strcmp(arg, "hg"))
                *opt_value = PATCH_FORMAT_HG;
+       else if (!strcmp(arg, "mboxrd"))
+               *opt_value = PATCH_FORMAT_MBOXRD;
        else
                return error(_("Invalid value for --patch-format: %s"), arg);
        return 0;