21
#include "sequencer.h"
22
#include "revision.h"
23
#include "merge-recursive.h"
24
+#include "revision.h"
25
+#include "log-tree.h"
26
27
/**
28
* Returns 1 if the file is empty or does not exist, 0 otherwise.
789
return ret;
790
}
791
792
+/**
793
+ * Sets commit_id to the commit hash where the mail was generated from.
794
+ * Returns 0 on success, -1 on failure.
795
+ */
796
+static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail)
797
+{
798
+ struct strbuf sb = STRBUF_INIT;
799
+ FILE *fp = xfopen(mail, "r");
800
+ const char *x;
801
+
802
+ if (strbuf_getline(&sb, fp, '\n'))
803
+ return -1;
804
+
805
+ if (!skip_prefix(sb.buf, "From ", &x))
806
+ return -1;
807
+
808
+ if (get_sha1_hex(x, commit_id) < 0)
809
+ return -1;
810
+
811
+ strbuf_release(&sb);
812
+ fclose(fp);
813
+ return 0;
814
+}
815
+
816
+/**
817
+ * Sets state->msg, state->author_name, state->author_email, state->author_date
818
+ * to the commit's respective info.
819
+ */
820
+static void get_commit_info(struct am_state *state, struct commit *commit)
821
+{
822
+ const char *buffer, *ident_line, *author_date, *msg;
823
+ size_t ident_len;
824
+ struct ident_split ident_split;
825
+ struct strbuf sb = STRBUF_INIT;
826
+
827
+ buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding());
828
+
829
+ ident_line = find_commit_header(buffer, "author", &ident_len);
830
+
831
+ if (split_ident_line(&ident_split, ident_line, ident_len) < 0) {
832
+ strbuf_add(&sb, ident_line, ident_len);
833
+ die(_("invalid ident line: %s"), sb.buf);
834
+ }
835
+
836
+ assert(!state->author_name);
837
+ if (ident_split.name_begin) {
838
+ strbuf_add(&sb, ident_split.name_begin,
839
+ ident_split.name_end - ident_split.name_begin);
840
+ state->author_name = strbuf_detach(&sb, NULL);
841
+ } else
842
+ state->author_name = xstrdup("");
843
+
844
+ assert(!state->author_email);
845
+ if (ident_split.mail_begin) {
846
+ strbuf_add(&sb, ident_split.mail_begin,
847
+ ident_split.mail_end - ident_split.mail_begin);
848
+ state->author_email = strbuf_detach(&sb, NULL);
849
+ } else
850
+ state->author_email = xstrdup("");
851
+
852
+ author_date = show_ident_date(&ident_split, DATE_MODE(NORMAL));
853
+ strbuf_addstr(&sb, author_date);
854
+ assert(!state->author_date);
855
+ state->author_date = strbuf_detach(&sb, NULL);
856
+
857
+ assert(!state->msg);
858
+ msg = strstr(buffer, "\n\n");
859
+ if (!msg)
860
+ die(_("unable to parse commit %s"), sha1_to_hex(commit->object.sha1));
861
+ state->msg = xstrdup(msg + 2);
862
+ state->msg_len = strlen(state->msg);
863
+}
864
+
865
+/**
866
+ * Writes `commit` as a patch to the state directory's "patch" file.
867
+ */
868
+static void write_commit_patch(const struct am_state *state, struct commit *commit)
869
+{
870
+ struct rev_info rev_info;
871
+ FILE *fp;
872
+
873
+ fp = xfopen(am_path(state, "patch"), "w");
874
+ init_revisions(&rev_info, NULL);
875
+ rev_info.diff = 1;
876
+ rev_info.abbrev = 0;
877
+ rev_info.disable_stdin = 1;
878
+ rev_info.show_root_diff = 1;
879
+ rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;
880
+ rev_info.no_commit_id = 1;
881
+ DIFF_OPT_SET(&rev_info.diffopt, BINARY);
882
+ DIFF_OPT_SET(&rev_info.diffopt, FULL_INDEX);
883
+ rev_info.diffopt.use_color = 0;
884
+ rev_info.diffopt.file = fp;
885
+ rev_info.diffopt.close_file = 1;
886
+ add_pending_object(&rev_info, &commit->object, "");
887
+ diff_setup_done(&rev_info.diffopt);
888
+ log_tree_commit(&rev_info, commit);
889
+}
890
+
891
+/**
892
+ * Like parse_mail(), but parses the mail by looking up its commit ID
893
+ * directly. This is used in --rebasing mode to bypass git-mailinfo's munging
894
+ * of patches.
895
+ *
896
+ * Will always return 0 as the patch should never be skipped.
897
+ */
898
+static int parse_mail_rebase(struct am_state *state, const char *mail)
899
+{
900
+ struct commit *commit;
901
+ unsigned char commit_sha1[GIT_SHA1_RAWSZ];
902
+
903
+ if (get_mail_commit_sha1(commit_sha1, mail) < 0)
904
+ die(_("could not parse %s"), mail);
905
+
906
+ commit = lookup_commit_or_die(commit_sha1, mail);
907
+
908
+ get_commit_info(state, commit);
909
+
910
+ write_commit_patch(state, commit);
911
+
912
+ return 0;
913
+}
914
+
915
/**
916
* Applies current patch with git-apply. Returns 0 on success, -1 otherwise. If
917
* `index_file` is not NULL, the patch will be applied to that index.
1144
validate_resume_state(state);
1145
resume = 0;
1146
} else {
1022
- if (parse_mail(state, mail))
1147
+ int skip;
1148
+
1149
+ if (state->rebasing)
1150
+ skip = parse_mail_rebase(state, mail);
1151
+ else
1152
+ skip = parse_mail(state, mail);
1153
+
1154
+ if (skip)
1155
goto next; /* mail should be skipped */
1156
1157
write_author_script(state);