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 v4 06/44] builtin-am: auto-detect mbox patches
Date: Sun, 28 Jun 2015 22:05:28 +0800 [thread overview]
Message-ID: <1435500366-31700-7-git-send-email-pyokagan@gmail.com> (raw)
In-Reply-To: <1435500366-31700-1-git-send-email-pyokagan@gmail.com>
Since 15ced75 (git-am foreign patch support: autodetect some patch
formats, 2009-05-27), git-am.sh is able to autodetect mbox, stgit and
mercurial patches through heuristics.
Re-implement support for autodetecting mbox/maildir files in
builtin/am.c.
RFC 2822 requires that lines are terminated by "\r\n". To support this,
implement strbuf_getline_crlf(), which will remove both '\n' and "\r\n"
from the end of the line.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
---
Notes:
v4
* Using strbuf_trim() to remove the \r from CRLF lines is obviously
wrong. Instead, implement strbuf_getline_crlf() to do it correctly for
us.
* Use a regex
* Instead of re-opening the file again in is_email(), rewind the
already-opened data stream.
builtin/am.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 109 insertions(+)
diff --git a/builtin/am.c b/builtin/am.c
index 136ccc6..31d85eb 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -10,6 +10,21 @@
#include "dir.h"
#include "run-command.h"
+/**
+ * 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;
+}
+
enum patch_format {
PATCH_FORMAT_UNKNOWN = 0,
PATCH_FORMAT_MBOX
@@ -131,6 +146,92 @@ static void am_destroy(const struct am_state *state)
}
/**
+ * Determines if the file looks like a piece of RFC2822 mail by grabbing all
+ * non-indented lines and checking if they look like they begin with valid
+ * header field names.
+ *
+ * Returns 1 if the file looks like a piece of mail, 0 otherwise.
+ */
+static int is_mail(FILE *fp)
+{
+ const char *header_regex = "^[!-9;-~]+:";
+ struct strbuf sb = STRBUF_INIT;
+ regex_t regex;
+ int ret = 1;
+
+ if (fseek(fp, 0L, SEEK_SET))
+ die_errno(_("fseek failed"));
+
+ if (regcomp(®ex, header_regex, REG_NOSUB | REG_EXTENDED))
+ die("invalid pattern: %s", header_regex);
+
+ while (!strbuf_getline_crlf(&sb, fp)) {
+ if (!sb.len)
+ break; /* End of header */
+
+ /* Ignore indented folded lines */
+ if (*sb.buf == '\t' || *sb.buf == ' ')
+ continue;
+
+ /* It's a header if it matches header_regex */
+ if (regexec(®ex, sb.buf, 0, NULL, 0)) {
+ ret = 0;
+ goto done;
+ }
+ }
+
+done:
+ regfree(®ex);
+ strbuf_release(&sb);
+ return ret;
+}
+
+/**
+ * Attempts to detect the patch_format of the patches contained in `paths`,
+ * returning the PATCH_FORMAT_* enum value. Returns PATCH_FORMAT_UNKNOWN if
+ * detection fails.
+ */
+static int detect_patch_format(const char **paths)
+{
+ enum patch_format ret = PATCH_FORMAT_UNKNOWN;
+ struct strbuf l1 = STRBUF_INIT;
+ FILE *fp;
+
+ /*
+ * We default to mbox format if input is from stdin and for directories
+ */
+ if (!*paths || !strcmp(*paths, "-") || is_directory(*paths))
+ return PATCH_FORMAT_MBOX;
+
+ /*
+ * Otherwise, check the first few lines of the first patch, starting
+ * from the first non-blank line, to try to detect its format.
+ */
+
+ fp = xfopen(*paths, "r");
+
+ while (!strbuf_getline_crlf(&l1, fp)) {
+ if (l1.len)
+ break;
+ }
+
+ if (starts_with(l1.buf, "From ") || starts_with(l1.buf, "From: ")) {
+ ret = PATCH_FORMAT_MBOX;
+ goto done;
+ }
+
+ if (l1.len && is_mail(fp)) {
+ ret = PATCH_FORMAT_MBOX;
+ goto done;
+ }
+
+done:
+ fclose(fp);
+ strbuf_release(&l1);
+ return ret;
+}
+
+/**
* 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.
*/
@@ -188,6 +289,14 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
static void am_setup(struct am_state *state, enum patch_format patch_format,
const char **paths)
{
+ if (!patch_format)
+ patch_format = detect_patch_format(paths);
+
+ if (!patch_format) {
+ fprintf_ln(stderr, _("Patch format detection failed."));
+ exit(128);
+ }
+
if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
die_errno(_("failed to create directory '%s'"), state->dir);
--
2.5.0.rc0.76.gb2c6e93
next prev parent reply other threads:[~2015-06-28 14:07 UTC|newest]
Thread overview: 74+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-06-28 14:05 [PATCH v4 00/44] Make git-am a builtin Paul Tan
2015-06-28 14:05 ` [PATCH v4 01/44] wrapper: implement xopen() Paul Tan
2015-06-29 4:48 ` Torsten Bögershausen
2015-06-29 5:04 ` Stefan Beller
2015-06-29 17:18 ` Junio C Hamano
2015-07-01 6:05 ` Paul Tan
2015-07-01 6:04 ` Paul Tan
2015-06-28 14:05 ` [PATCH v4 02/44] wrapper: implement xfopen() Paul Tan
2015-06-28 14:05 ` [PATCH v4 03/44] builtin-am: implement skeletal builtin am Paul Tan
2015-06-28 14:05 ` [PATCH v4 04/44] builtin-am: implement patch queue mechanism Paul Tan
2015-06-29 5:08 ` Stefan Beller
2015-07-07 12:50 ` Paul Tan
2015-06-28 14:05 ` [PATCH v4 05/44] builtin-am: split out mbox/maildir patches with git-mailsplit Paul Tan
2015-06-28 14:05 ` Paul Tan [this message]
2015-06-28 14:05 ` [PATCH v4 07/44] builtin-am: extract patch and commit info with git-mailinfo Paul Tan
2015-06-28 14:05 ` [PATCH v4 08/44] builtin-am: apply patch with git-apply Paul Tan
2015-06-28 14:05 ` [PATCH v4 09/44] builtin-am: implement committing applied patch Paul Tan
2015-06-28 14:05 ` [PATCH v4 10/44] builtin-am: refuse to apply patches if index is dirty Paul Tan
2015-06-28 14:05 ` [PATCH v4 11/44] builtin-am: implement --resolved/--continue Paul Tan
2015-06-28 14:05 ` [PATCH v4 12/44] builtin-am: implement --skip Paul Tan
2015-06-28 14:05 ` [PATCH v4 13/44] builtin-am: implement --abort Paul Tan
2015-06-28 14:05 ` [PATCH v4 14/44] builtin-am: reject patches when there's a session in progress Paul Tan
2015-06-28 14:05 ` [PATCH v4 15/44] builtin-am: implement -q/--quiet, GIT_QUIET Paul Tan
2015-06-28 14:05 ` [PATCH v4 16/44] builtin-am: exit with user friendly message on failure Paul Tan
2015-06-28 14:05 ` [PATCH v4 17/44] builtin-am: implement -s/--signoff Paul Tan
2015-06-28 14:05 ` [PATCH v4 18/44] cache-tree: introduce write_index_as_tree() Paul Tan
2015-06-28 14:05 ` [PATCH v4 19/44] builtin-am: implement --3way, am.threeway Paul Tan
2015-06-30 0:18 ` Stefan Beller
2015-06-28 14:05 ` [PATCH v4 20/44] builtin-am: implement --rebasing mode Paul Tan
2015-06-28 14:05 ` [PATCH v4 21/44] builtin-am: bypass git-mailinfo when --rebasing Paul Tan
2015-06-28 14:05 ` [PATCH v4 22/44] builtin-am: handle stray state directory Paul Tan
2015-06-28 14:05 ` [PATCH v4 23/44] builtin-am: implement -u/--utf8 Paul Tan
2015-06-28 14:05 ` [PATCH v4 24/44] builtin-am: implement -k/--keep, --keep-non-patch Paul Tan
2015-06-28 14:05 ` [PATCH v4 25/44] builtin-am: implement --[no-]message-id, am.messageid Paul Tan
2015-06-28 14:05 ` [PATCH v4 26/44] builtin-am: support --keep-cr, am.keepcr Paul Tan
2015-06-28 14:05 ` [PATCH v4 27/44] builtin-am: implement --[no-]scissors Paul Tan
2015-07-07 8:23 ` Paul Tan
2015-06-28 14:05 ` [PATCH v4 28/44] builtin-am: pass git-apply's options to git-apply Paul Tan
2015-06-29 23:56 ` Stefan Beller
2015-07-01 10:22 ` Paul Tan
2015-07-01 17:01 ` Stefan Beller
2015-06-28 14:05 ` [PATCH v4 29/44] builtin-am: implement --ignore-date Paul Tan
2015-06-28 14:05 ` [PATCH v4 30/44] builtin-am: implement --committer-date-is-author-date Paul Tan
2015-06-28 14:05 ` [PATCH v4 31/44] builtin-am: implement -S/--gpg-sign, commit.gpgsign Paul Tan
2015-06-29 23:51 ` Stefan Beller
2015-07-01 8:01 ` Paul Tan
2015-07-01 16:43 ` Stefan Beller
2015-06-28 14:05 ` [PATCH v4 32/44] builtin-am: invoke post-rewrite hook Paul Tan
2015-06-28 14:05 ` [PATCH v4 33/44] builtin-am: support automatic notes copying Paul Tan
2015-06-28 14:05 ` [PATCH v4 34/44] builtin-am: invoke applypatch-msg hook Paul Tan
2015-06-28 14:05 ` [PATCH v4 35/44] builtin-am: invoke pre-applypatch hook Paul Tan
2015-06-28 14:05 ` [PATCH v4 36/44] builtin-am: invoke post-applypatch hook Paul Tan
2015-06-28 14:05 ` [PATCH v4 37/44] builtin-am: rerere support Paul Tan
2015-06-28 14:06 ` [PATCH v4 38/44] builtin-am: support and auto-detect StGit patches Paul Tan
2015-06-29 20:42 ` Stefan Beller
2015-06-29 20:51 ` Eric Sunshine
2015-06-29 21:39 ` Junio C Hamano
2015-07-01 7:25 ` Paul Tan
2015-06-28 14:06 ` [PATCH v4 39/44] builtin-am: support and auto-detect StGit series files Paul Tan
2015-06-28 14:06 ` [PATCH v4 40/44] builtin-am: support and auto-detect mercurial patches Paul Tan
2015-06-29 20:32 ` Stefan Beller
2015-06-29 20:32 ` Stefan Beller
2015-07-01 9:07 ` Paul Tan
2015-07-01 8:48 ` Paul Tan
2015-06-28 14:06 ` [PATCH v4 41/44] builtin-am: implement -i/--interactive Paul Tan
2015-06-28 14:06 ` [PATCH v4 42/44] builtin-am: implement legacy -b/--binary option Paul Tan
2015-06-29 20:05 ` Stefan Beller
[not found] ` <CABPQNSakaoyNRuNz=bcDYWdy4e2O3M4UuYoOT5JAV1mt-BiAOw@mail.gmail.com>
2015-07-14 10:09 ` Paul Tan
2015-06-28 14:06 ` [PATCH v4 43/44] builtin-am: check for valid committer ident Paul Tan
2015-06-29 20:02 ` Stefan Beller
2015-07-01 6:43 ` Paul Tan
2015-06-28 14:06 ` [PATCH v4 44/44] builtin-am: remove redirection to git-am.sh Paul Tan
2015-06-29 5:01 ` [PATCH v4 00/44] Make git-am a builtin Stefan Beller
2015-06-30 0:19 ` Stefan Beller
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=1435500366-31700-7-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.