{"thread":{"id":"2829","subject":"[PATCH] git-am support for naked email messages (take 2)","startedAt":"2005-12-14T06:39:23Z","lastAt":"2005-12-14T08:38:54Z","messageCount":2,"participants":["H. Peter Anvin","Martin Langhoff"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"13608","messageId":"439FBE1B.4050601@zytor.com","threadId":"2829","inReplyTo":null,"subject":"[PATCH] git-am support for naked email messages (take 2)","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2005-12-14T06:39:23Z","receivedAt":"2005-12-14T06:39:23Z","isPatch":true,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"This allows git-am to accept single-message files as well as mboxes. \nUnlike the previous version, this one doesn't need to be explicitly told \nwhich one it is; rather, it looks to see if the first line is a From \nline and uses it to select mbox mode or not.\n\nI moved the logic to do all this into git-mailsplit, which got a new \nuser interface as result, although the old interface is still available \nfor backwards compatibility.\n\nSigned-off-by: H. Peter Anvin <hpa@zytor.com>\n\n\ndiff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt\nindex 03a9477..e0703e9 100644\n--- a/Documentation/git-mailsplit.txt\n+++ b/Documentation/git-mailsplit.txt\n@@ -7,7 +7,7 @@ git-mailsplit - Totally braindamaged mbo\n \n SYNOPSIS\n --------\n-'git-mailsplit' [-d<prec>] [<mbox>] <directory>\n+'git-mailsplit' [-b] [-f<nn>] [-d<prec>] -o<directory> [--] [<mbox>...]\n \n DESCRIPTION\n -----------\n@@ -23,11 +23,18 @@ OPTIONS\n <directory>::\n \tDirectory in which to place the individual messages.\n \n+-b::\n+\tIf any file doesn't begin with a From line, assume it is a\n+\tsingle mail message instead of signalling error.\n+\n -d<prec>::\n \tInstead of the default 4 digits with leading zeros,\n \tdifferent precision can be specified for the generated\n \tfilenames.\n \n+-f<nn>::\n+\tSkip the first <nn> numbers, for example if -f3 is specified,\n+\tstart the numbering with 0004.\n \n Author\n ------\ndiff --git a/git-am.sh b/git-am.sh\nindex 6ed527c..f143b7e 100755\n--- a/git-am.sh\n+++ b/git-am.sh\n@@ -164,10 +164,7 @@ else\n \t# Start afresh.\n \tmkdir -p \"$dotest\" || exit\n \n-\t# cat does the right thing for us, including '-' to mean\n-\t# standard input.\n-\tcat \"$@\" |\n-\tgit-mailsplit -d$prec \"$dotest/\" >\"$dotest/last\" || {\n+\tgit-mailsplit -d\"$prec\" -o\"$dotest\" -b -- \"$@\" > \"$dotest/last\" ||  {\n \t\trm -fr \"$dotest\"\n \t\texit 1\n \t}\ndiff --git a/mailsplit.c b/mailsplit.c\nindex 189f4ed..f49cbf7 100644\n--- a/mailsplit.c\n+++ b/mailsplit.c\n@@ -15,7 +15,7 @@\n #include \"cache.h\"\n \n static const char git_mailsplit_usage[] =\n-\"git-mailsplit [-d<prec>] [<mbox>] <directory>\";\n+\"git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>...\";\n \n static int is_from_line(const char *line, int len)\n {\n@@ -56,14 +56,15 @@ static char buf[4096];\n  * the Unix \"From \" line.  Write it into the specified\n  * file.\n  */\n-static int split_one(FILE *mbox, const char *name)\n+static int split_one(FILE *mbox, const char *name, int allow_bare)\n {\n \tFILE *output = NULL;\n \tint len = strlen(buf);\n \tint fd;\n \tint status = 0;\n+\tint is_bare = !is_from_line(buf, len);\n \n-\tif (!is_from_line(buf, len))\n+\tif (is_bare && !allow_bare)\n \t\tgoto corrupt;\n \n \tfd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666);\n@@ -88,7 +89,7 @@ static int split_one(FILE *mbox, const c\n \t\t\tdie(\"cannot read mbox\");\n \t\t}\n \t\tlen = strlen(buf);\n-\t\tif (!is_partial && is_from_line(buf, len))\n+\t\tif (!is_partial && !is_bare && is_from_line(buf, len))\n \t\t\tbreak; /* done with one message */\n \t}\n \tfclose(output);\n@@ -104,54 +105,84 @@ static int split_one(FILE *mbox, const c\n \n int main(int argc, const char **argv)\n {\n-\tint i, nr, nr_prec = 4;\n-\tFILE *mbox = NULL;\n+\tint nr = 0, nr_prec = 4;\n+\tint allow_bare = 0;\n+\tconst char *dir = NULL;\n+\tconst char **argp;\n+\tstatic const char *stdin_only[] = { \"-\", NULL };\n+\tchar *name;\n \n-\tfor (i = 1; i < argc; i++) {\n-\t\tconst char *arg = argv[i];\n+\tfor (argp = argv+1; *argp; argp++) {\n+\t\tconst char *arg = *argp;\n \n \t\tif (arg[0] != '-')\n \t\t\tbreak;\n \t\t/* do flags here */\n-\t\tif (!strncmp(arg, \"-d\", 2)) {\n-\t\t\tnr_prec = strtol(arg + 2, NULL, 10);\n+\t\tif ( arg[1] == 'd' ) {\n+\t\t\tnr_prec = strtol(arg+2, NULL, 10);\n \t\t\tif (nr_prec < 3 || 10 <= nr_prec)\n \t\t\t\tusage(git_mailsplit_usage);\n \t\t\tcontinue;\n+\t\t} else if ( arg[1] == 'f' ) {\n+\t\t\tnr = strtol(arg+2, NULL, 10);\n+\t\t} else if ( arg[1] == 'b' && !arg[2] ) {\n+\t\t\tallow_bare = 1;\n+\t\t} else if ( arg[1] == 'o' && arg[2] ) {\n+\t\t\tdir = arg+2;\n+\t\t} else if ( arg[1] == '-' && !arg[2] ) {\n+\t\t\targp++;\t/* -- marks end of options */\n+\t\t\tbreak;\n+\t\t} else {\n+\t\t\tdie(\"unknown option: %s\", arg);\n \t\t}\n \t}\n \n-\t/* Either one remaining arg (dir), or two (mbox and dir) */\n-\tswitch (argc - i) {\n-\tcase 1:\n-\t\tmbox = stdin;\n-\t\tbreak;\n-\tcase 2:\n-\t\tif ((mbox = fopen(argv[i], \"r\")) == NULL)\n-\t\t\tdie(\"cannot open mbox %s for reading\", argv[i]);\n-\t\tbreak;\n-\tdefault:\n-\t\tusage(git_mailsplit_usage);\n+\tif ( !dir ) {\n+\t\t/* Backwards compatibility: if no -o specified, accept\n+\t\t   <mbox> <dir> or just <dir> */\n+\t\tswitch (argc - (argp-argv)) {\n+\t\tcase 1:\n+\t\t\tdir = argp[0];\n+\t\t\targp = stdin_only;\n+\t\t\tbreak;\n+\t\tcase 2:\n+\t\t\tstdin_only[0] = argp[0];\n+\t\t\tdir = argp[1];\n+\t\t\targp = stdin_only;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tusage(git_mailsplit_usage);\n+\t\t}\n+\t} else {\n+\t\t/* New usage: if no more argument, parse stdin */\n+\t\tif ( !*argp )\n+\t\t\targp = stdin_only;\n \t}\n-\tif (chdir(argv[argc - 1]) < 0)\n-\t\tusage(git_mailsplit_usage);\n-\n-\tnr = 0;\n-\tif (fgets(buf, sizeof(buf), mbox) == NULL)\n-\t\tdie(\"cannot read mbox\");\n \n-\tfor (;;) {\n-\t\tchar name[10];\n+\tname = xmalloc(strlen(dir)+2+3*sizeof nr);\n \n-\t\tsprintf(name, \"%0*d\", nr_prec, ++nr);\n-\t\tswitch (split_one(mbox, name)) {\n-\t\tcase 0:\n-\t\t\tbreak;\n-\t\tcase 1:\n-\t\t\tprintf(\"%d\\n\", nr);\n-\t\t\treturn 0;\n-\t\tdefault:\n-\t\t\texit(1);\n+\twhile ( argp ) {\n+\t\tconst char *file = *argp++;\n+\t\tFILE *f = !strcmp(file, \"-\") ? stdin : fopen(file, \"rt\");\n+\t\tint file_done = 0;\n+\n+\t\tif ( !f )\n+\t\t\tdie (\"cannot open mbox %s\", file);\n+\n+\t\tif (fgets(buf, sizeof(buf), f) == NULL)\n+\t\t\tdie(\"cannot read mbox %s\", file);\n+\n+\t\twhile (!file_done) {\n+\t\t\tchar name[10];\n+\t\t\t\n+\t\t\tsprintf(name, \"%s/%0*d\", dir, nr_prec, ++nr);\n+\t\t\tfile_done = split_one(f, name, allow_bare);\n \t\t}\n+\n+\t\tif (f != stdin)\n+\t\t\tfclose(f);\n \t}\n+\n+\tprintf(\"%d\\n\", nr);\n+\treturn 0;\n }\n"},{"id":"13611","messageId":"46a038f90512140038j606642d0x29633be4fa21829f@mail.gmail.com","threadId":"2829","inReplyTo":"439FBE1B.4050601@zytor.com","subject":"Re: [PATCH] git-am support for naked email messages (take 2)","fromName":"Martin Langhoff","fromEmail":"martin.langhoff@gmail.com","sentAt":"2005-12-14T08:38:54Z","receivedAt":"2005-12-14T08:38:54Z","isPatch":true,"sender":{"key":"martin.langhoff@gmail.com","avatar":"https://gravatar.com/avatar/1e3f311b6c4c15836501901ca58f8c0b0667246488084ba524d8bc9867e22fd9?d=mp&s=160"},"body":"On 12/14/05, H. Peter Anvin <hpa@zytor.com> wrote:\n> This allows git-am to accept single-message files as well as mboxes.\n> Unlike the previous version, this one doesn't need to be explicitly told\n> which one it is; rather, it looks to see if the first line is a From\n> line and uses it to select mbox mode or not.\n\nYes, please. These changes to git-am/git-mailsplit are very welcome by\nthose that don't use mbox-based MUAs. The whole workflow if git-am is\nreally trying if you are IMAP or Gmail/webmail based.\n\nBTW, I recently had a go at using a Perl Gmail library to fetch\nmessages with a particular label into an mbox, but the library didn't\nwork, and I don't want to be chasing the taillights of gmails internal\nAPI. If the python Gmail library works better, I may have a go at\nlearning python ;-)\n\ncheers,\n\n\nmartin\n"}]}