Issue with empty patch detection Signed-off-by: Nicolas Morey-Chaisemartin <nicolas@xxxxxxxxxxxxxxxxxxxxxx> --- builtin/am.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 126 insertions(+), 17 deletions(-) diff --git a/builtin/am.c b/builtin/am.c index 92c485350..702cbf8e0 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -111,6 +111,11 @@ struct am_state { char *msg; size_t msg_len; + /* Series metadata */ + int series_id; + int series_len; + int cover_id; + /* when --rebasing, records the original commit the patch came from */ struct object_id orig_commit; @@ -131,6 +136,8 @@ struct am_state { int committer_date_is_author_date; int ignore_date; int allow_rerere_autoupdate; + int cover_at_tip; + int applying_cover; const char *sign_commit; int rebasing; }; @@ -160,6 +167,7 @@ static void am_state_init(struct am_state *state) if (!git_config_get_bool("commit.gpgsign", &gpgsign)) state->sign_commit = gpgsign ? "" : NULL; + } /** @@ -432,6 +440,20 @@ static void am_load(struct am_state *state) read_state_file(&sb, state, "utf8", 1); state->utf8 = !strcmp(sb.buf, "t"); + read_state_file(&sb, state, "cover-at-tip", 1); + state->cover_at_tip = !strcmp(sb.buf, "t"); + + if (state->cover_at_tip) { + read_state_file(&sb, state, "series_id", 1); + state->series_id = strtol(sb.buf, NULL, 10); + + read_state_file(&sb, state, "series_len", 1); + state->series_len = strtol(sb.buf, NULL, 10); + + read_state_file(&sb, state, "cover_id", 1); + state->cover_id = strtol(sb.buf, NULL, 10); + } + if (file_exists(am_path(state, "rerere-autoupdate"))) { read_state_file(&sb, state, "rerere-autoupdate", 1); state->allow_rerere_autoupdate = strcmp(sb.buf, "t") ? @@ -1020,6 +1042,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format, write_state_bool(state, "quiet", state->quiet); write_state_bool(state, "sign", state->signoff); write_state_bool(state, "utf8", state->utf8); + write_state_bool(state, "cover-at-tip", state->cover_at_tip); if (state->allow_rerere_autoupdate) write_state_bool(state, "rerere-autoupdate", @@ -1076,6 +1099,12 @@ static void am_setup(struct am_state *state, enum patch_format patch_format, delete_ref(NULL, "ORIG_HEAD", NULL, 0); } + if (state->cover_at_tip) { + write_state_count(state, "series_id", state->series_id); + write_state_count(state, "series_len", state->series_len); + write_state_count(state, "cover_id", state->cover_id); + } + /* * NOTE: Since the "next" and "last" files determine if an am_state * session is in progress, they should be written last. @@ -1088,13 +1117,9 @@ static void am_setup(struct am_state *state, enum patch_format patch_format, } /** - * Increments the patch pointer, and cleans am_state for the application of the - * next patch. - */ -static void am_next(struct am_state *state) + * Cleans am_state. + */static void am_clean(struct am_state *state) { - struct object_id head; - FREE_AND_NULL(state->author_name); FREE_AND_NULL(state->author_email); FREE_AND_NULL(state->author_date); @@ -1106,14 +1131,6 @@ static void am_next(struct am_state *state) oidclr(&state->orig_commit); unlink(am_path(state, "original-commit")); - - if (!get_oid("HEAD", &head)) - write_state_text(state, "abort-safety", oid_to_hex(&head)); - else - write_state_text(state, "abort-safety", ""); - - state->cur++; - write_state_count(state, "next", state->cur); } /** @@ -1274,6 +1291,7 @@ static int parse_mail(struct am_state *state, const char *mail) fclose(mi.input); fclose(mi.output); + /* Extract message and author information */ fp = xfopen(am_path(state, "info"), "r"); while (!strbuf_getline_lf(&sb, fp)) { @@ -1298,9 +1316,30 @@ static int parse_mail(struct am_state *state, const char *mail) goto finish; } - if (is_empty_file(am_path(state, "patch"))) { - printf_ln(_("Patch is empty.")); - die_user_resolve(state); + if (!state->applying_cover) { + + state->series_id = mi.series_id; + state->series_len = mi.series_len; + + if (state->cover_at_tip) { + write_state_count(state, "series_id", state->series_id); + write_state_count(state, "series_len", state->series_len); + write_state_count(state, "cover_id", state->cover_id); + } + + if (mi.series_id == 0){ + state->cover_id = state->cur; + ret = 1; + goto finish; + } + + if (is_empty_file(am_path(state, "patch"))) { + printf_ln(_("Patch is empty.")); + die_user_resolve(state); + } else if (state->cur == 1) { + /* First mail is not empty. cover-at-tip cannot apply */ + state->cover_at_tip = 0; + } } strbuf_addstr(&msg, "\n\n"); @@ -1776,6 +1815,74 @@ static int do_interactive(struct am_state *state) } } + +/** + * Apply the cover letter of a patch series + */ +static void do_apply_cover(struct am_state *state) +{ + int previous_cur = state->cur; + const char *mail; + + am_clean(state); + + state->cur = state->cover_id; + state->applying_cover = 1; + mail = am_path(state, msgnum(state)); + if (!file_exists(mail)) + die("BUG: cover has disapeared"); + + if(parse_mail(state, mail)) + die("BUG: first patch is not a cover-letter"); + + if (state->signoff) + am_append_signoff(state); + + write_author_script(state); + write_commit_msg(state); + + if (state->interactive && do_interactive(state)) + goto cancel_cover; + + say(state, stdout, _("Applying: %.*s"), linelen(state->msg), state->msg); + + do_commit(state); + cancel_cover: + state->cur = previous_cur; + state->applying_cover = 0; + + /* Reset series metadata */ + state->series_len = 0; + state->series_id = 0; + state->cover_id = 0; +} + +/** + * Increments the patch pointer, and cleans am_state for the application of the + * next patch. + */ +static void am_next(struct am_state *state) +{ + struct object_id head; + + /* Flush the cover letter if needed */ + if (state->cover_at_tip == 1 && + state->series_len > 0 && + state->series_id == state->series_len && + state->cover_id > 0) + do_apply_cover(state); + + am_clean(state); + + if (!get_oid("HEAD", &head)) + write_state_text(state, "abort-safety", oid_to_hex(&head)); + else + write_state_text(state, "abort-safety", ""); + + state->cur++; + write_state_count(state, "next", state->cur); +} + /** * Applies all queued mail. * @@ -2287,6 +2394,8 @@ int cmd_am(int argc, const char **argv, const char *prefix) N_("lie about committer date")), OPT_BOOL(0, "ignore-date", &state.ignore_date, N_("use current timestamp for author date")), + OPT_BOOL(0, "cover-at-tip", &state.cover_at_tip, + N_("apply cover letter to the tip of the branch")), OPT_RERERE_AUTOUPDATE(&state.allow_rerere_autoupdate), { OPTION_STRING, 'S', "gpg-sign", &state.sign_commit, N_("key-id"), N_("GPG-sign commits"), -- 2.15.0.169.g3d3eebb67.dirty