All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
From: Paul Tan <pyokagan@gmail.com>
To: git@vger.kernel.org
Cc: Johannes Schindelin <johannes.schindelin@gmx.de>,
	Stefan Beller <sbeller@google.com>, Paul Tan <pyokagan@gmail.com>
Subject: [PATCH/WIP v3 22/31] am: don't use git-mailinfo if --rebasing
Date: Thu, 18 Jun 2015 19:25:34 +0800	[thread overview]
Message-ID: <1434626743-8552-23-git-send-email-pyokagan@gmail.com> (raw)
In-Reply-To: <1434626743-8552-1-git-send-email-pyokagan@gmail.com>

Since 5e835ca (rebase: do not munge commit log message, 2008-04-16),
git am --rebasing no longer gets the commit log message from the patch,
but reads it directly from the commit identified by the "From " header
line.

Since 43c2325 (am: use get_author_ident_from_commit instead of mailinfo
when rebasing, 2010-06-16), git am --rebasing also gets the author name,
email and date directly from the commit.

Since 0fbb95d (am: don't call mailinfo if $rebasing, 2012-06-26), git am
--rebasing does not use git-mailinfo to get the patch body, but rather
generates it directly from the commit itself.

The above 3 commits introduced a separate parse_patch() code path in
git-am.sh's --rebasing mode that bypasses git-mailinfo. Re-implement
this code path in builtin/am.c as parse_patch_rebase().

Signed-off-by: Paul Tan <pyokagan@gmail.com>
---
 builtin/am.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 153 insertions(+), 2 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index 9afa3bb..0d7e37c 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -21,6 +21,8 @@
 #include "sequencer.h"
 #include "revision.h"
 #include "merge-recursive.h"
+#include "revision.h"
+#include "log-tree.h"
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -50,6 +52,30 @@ static const char *firstline(const char *msg)
 	return sb.buf;
 }
 
+/**
+ * Iterate over lines, each terminated by c, in a string, without modifying the
+ * string itself. begin will be set to the beginning of the line, while end
+ * will be set to the line termination or null character at the end of the line
+ * or string. On the first call, begin and end must be initialized to the
+ * string to be iterated over. E.g.:
+ *
+ *	const char *begin, *end, *str = "1\n2\n3";
+ *	begin = end = str;
+ *	while (!getbufline(&begin, &end, '\n'))
+ *		...
+ */
+static int getbufline(const char **begin, const char **end, int c)
+{
+	if (!**end)
+		return EOF;
+	else if (**end == c)
+		*begin = *end + 1;
+	else
+		*begin = *end;
+	*end = strchrnul(*begin, c);
+	return 0;
+}
+
 enum patch_format {
 	PATCH_FORMAT_UNKNOWN = 0,
 	PATCH_FORMAT_MBOX
@@ -675,6 +701,126 @@ static int parse_patch(struct am_state *state, const char *patch)
 }
 
 /**
+ * Sets commit_id to the commit hash where the patch was generated from.
+ * Returns 0 on success, -1 on failure.
+ */
+static int get_patch_commit_sha1(unsigned char *commit_id, const char *patch)
+{
+	struct strbuf sb = STRBUF_INIT;
+	FILE *fp = xfopen(patch, "r");
+	const char *x;
+
+	if (strbuf_getline(&sb, fp, '\n'))
+		return -1;
+
+	if (!skip_prefix(sb.buf, "From ", &x))
+		return -1;
+
+	if (get_sha1_hex(x, commit_id) < 0)
+		return -1;
+
+	strbuf_release(&sb);
+	fclose(fp);
+	return 0;
+}
+
+/**
+ * Sets state->msg, state->author_name, state->author_email, state->author_date
+ * to the commit's respective info.
+ */
+static void get_commit_info(struct am_state *state, struct commit *commit)
+{
+	const char *buf, *begin, *end;
+
+	buf = logmsg_reencode(commit, NULL, get_commit_output_encoding());
+	begin = end = buf;
+
+	while (!getbufline(&begin, &end, '\n')) {
+		const char *x;
+
+		if (skip_prefix(begin, "author ", &x)) {
+			struct ident_split split;
+			const char *date;
+
+			if (split_ident_line(&split, x, end - x) < 0) {
+				struct strbuf sb = STRBUF_INIT;
+
+				strbuf_add(&sb, x, end - x);
+				die(_("invalid ident line: %s"), sb.buf);
+			}
+
+			if (split.name_begin)
+				strbuf_add(&state->author_name,
+					split.name_begin,
+					split.name_end - split.name_begin);
+
+			if (split.mail_begin)
+				strbuf_add(&state->author_email,
+					split.mail_begin,
+					split.mail_end - split.mail_begin);
+
+			date = show_ident_date(&split, DATE_NORMAL);
+			strbuf_addstr(&state->author_date, date);
+		} else if (begin == end) {
+			end++;
+			break;
+		}
+	}
+
+	strbuf_addstr(&state->msg, end);
+}
+
+/**
+ * Writes commit as a patch to $state_dir/patch.
+ */
+static void write_commit_patch(const struct am_state *state, struct commit *commit)
+{
+	struct rev_info rev_info;
+	FILE *fp;
+
+	fp = xfopen(am_path(state, "patch"), "w");
+	init_revisions(&rev_info, NULL);
+	rev_info.diff = 1;
+	rev_info.abbrev = 0;
+	rev_info.disable_stdin = 1;
+	rev_info.show_root_diff = 1;
+	rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;
+	rev_info.no_commit_id = 1;
+	DIFF_OPT_SET(&rev_info.diffopt, BINARY);
+	DIFF_OPT_SET(&rev_info.diffopt, FULL_INDEX);
+	rev_info.diffopt.use_color = 0;
+	rev_info.diffopt.file = fp;
+	rev_info.diffopt.close_file = 1;
+	add_pending_object(&rev_info, &commit->object, "");
+	diff_setup_done(&rev_info.diffopt);
+	log_tree_commit(&rev_info, commit);
+}
+
+/**
+ * Like parse_patch(), but parses the patch by looking up its commit ID
+ * directly. This is used in --rebasing mode to bypass git-mailinfo's munging
+ * of patches.
+ *
+ * Will always return 0 as the patch should never be skipped.
+ */
+static int parse_patch_rebase(struct am_state *state, const char *patch)
+{
+	struct commit *commit;
+	unsigned char commit_sha1[GIT_SHA1_RAWSZ];
+
+	if (get_patch_commit_sha1(commit_sha1, patch) < 0)
+		die(_("could not parse %s"), patch);
+
+	commit = lookup_commit_or_die(commit_sha1, patch);
+
+	get_commit_info(state, commit);
+
+	write_commit_patch(state, commit);
+
+	return 0;
+}
+
+/**
  * Dies with a user-friendly message on how to proceed after resolving the
  * problem. This message can be overridden with state->resolvemsg.
  */
@@ -885,12 +1031,17 @@ static void am_run(struct am_state *state)
 
 	while (state->cur <= state->last) {
 		const char *patch = am_path(state, msgnum(state));
-		int apply_status;
+		int apply_status, skip;
 
 		if (!file_exists(patch))
 			goto next;
 
-		if (parse_patch(state, patch))
+		if (state->rebasing)
+			skip = parse_patch_rebase(state, patch);
+		else
+			skip = parse_patch(state, patch);
+
+		if (skip)
 			goto next; /* patch should be skipped */
 
 		write_author_script(state);
-- 
2.1.4

  parent reply	other threads:[~2015-06-18 11:27 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-18 11:25 [PATCH/WIP v3 00/31] Make git-am a builtin Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 01/31] wrapper: implement xopen() Paul Tan
2015-06-24 16:28   ` Johannes Schindelin
2015-06-24 16:59     ` Stefan Beller
2015-06-24 18:39       ` Johannes Schindelin
2015-07-01  9:41         ` Paul Tan
2015-07-01  9:53           ` Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 02/31] wrapper: implement xfopen() Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 03/31] am: implement skeletal builtin am Paul Tan
2015-06-18 20:26   ` Junio C Hamano
2015-06-19  9:56     ` Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 04/31] am: implement patch queue mechanism Paul Tan
2015-06-18 17:47   ` Stefan Beller
2015-06-18 20:43   ` Junio C Hamano
2015-06-19 12:49     ` Paul Tan
2015-06-24 14:59   ` Johannes Schindelin
2015-06-25 15:16     ` Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 05/31] am: split out mbox/maildir patches with git-mailsplit Paul Tan
2015-06-18 20:52   ` Junio C Hamano
2015-06-18 11:25 ` [PATCH/WIP v3 06/31] am: detect mbox patches Paul Tan
2015-06-18 21:02   ` Junio C Hamano
2015-06-24  8:41     ` Paul Tan
2015-06-24 15:10   ` Johannes Schindelin
2015-06-25 13:40     ` Paul Tan
2015-06-26  7:42       ` Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 07/31] am: extract patch, message and authorship with git-mailinfo Paul Tan
2015-06-18 21:10   ` Junio C Hamano
2015-06-19  9:22     ` Paul Tan
2015-06-19 16:13       ` Junio C Hamano
2015-06-24  7:54         ` Paul Tan
2015-06-24 15:59           ` Junio C Hamano
2015-06-25 11:54             ` Paul Tan
     [not found]       ` <CAPc5daVbpB_T4cY1xvLrBKPUZw0JNMXqNAOsKE-R7NPO2nrnZA@mail.gmail.com>
2015-06-19 16:15         ` Paul Tan
2015-06-19 20:12           ` Johannes Schindelin
2015-06-24 16:36   ` Johannes Schindelin
2015-06-26  8:11     ` Paul Tan
2015-06-26 20:41       ` Junio C Hamano
2015-06-18 11:25 ` [PATCH/WIP v3 08/31] am: apply patch with git-apply Paul Tan
2015-06-18 21:23   ` Junio C Hamano
2015-06-18 11:25 ` [PATCH/WIP v3 09/31] am: commit applied patch Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 10/31] am: refresh the index at start Paul Tan
2015-06-18 21:28   ` Junio C Hamano
2015-06-19  8:07     ` Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 11/31] am: refuse to apply patches if index is dirty Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 12/31] am: implement --resolved/--continue Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 13/31] am: implement --skip Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 14/31] am: implement --abort Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 15/31] am: don't accept patches when there's a session in progress Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 16/31] am: implement quiet option Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 17/31] am: exit with user friendly message on patch failure Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 18/31] am: implement am --signoff Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 19/31] cache-tree: introduce write_index_as_tree() Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 20/31] am: implement 3-way merge Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 21/31] am: --rebasing Paul Tan
2015-06-18 11:25 ` Paul Tan [this message]
2015-06-18 11:25 ` [PATCH/WIP v3 23/31] am: handle stray state directory Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 24/31] am: implement -k/--keep, --keep-non-patch Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 25/31] am: implement --[no-]message-id, am.messageid Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 26/31] am: support --keep-cr, am.keepcr Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 27/31] am: implement --[no-]scissors Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 28/31] am: pass git-apply's options to git-apply Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 29/31] am: implement --ignore-date Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 30/31] am: implement --committer-date-is-author-date Paul Tan
2015-06-18 11:25 ` [PATCH/WIP v3 31/31] am: implement -S/--gpg-sign, commit.gpgsign Paul Tan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1434626743-8552-23-git-send-email-pyokagan@gmail.com \
    --to=pyokagan@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=johannes.schindelin@gmx.de \
    --cc=sbeller@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.