Issue with empty patch detection
Signed-off-by: Nicolas Morey-Chaisemartin <[email protected]>
---
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