Re: Mailsplit

2018-09-07 Thread Stephen & Linda Smith
On Friday, September 7, 2018 8:15:43 AM MST Kevin Daudt wrote:
> On Wed, Sep 05, 2018 at 09:17:29PM -0700, Stephen & Linda Smith wrote:
> 
> This is the mailsplit command, and should be executed when running `git
> mailsplit`. What does git --exec-dir return?
> 

The other night when I ran "git mailsplit", I recieved an unknown command 
response.  Since then I have upated to 2.19.0 plush my submitted patches for 
git commit.  With the new build mailsplit is found.

I don't know what was wrong before.





Re: Mailsplit

2018-09-07 Thread Kevin Daudt
On Wed, Sep 05, 2018 at 09:17:29PM -0700, Stephen & Linda Smith wrote:
> I thought I would use "git mailsplit" to split a mbox file (which downloaded 
> from public inbox) so that I could attemp to resurrect a patch series for 
> from 
> a year ago.  
> 
> The motivation is that I downloaded the series [1] and applied to a tag from 
> about the time period that the patch was sent out [2].  
> 
> The "git am -3 patch.mbox  quit 2/3 of the way though.   I resolved the fix. 
> and ran "git am --continue" which didn't apply the rest of the patches in the 
> mbox.
> 
> So two questions:
> 1)  why would git version 2.18.0 not appear to continue applying the patches. 
>   
> 
> 2) where do I find the command "git mailsplit".   The onlything in my 
> installed tree is:
> 
>   $ find  /usr/local/ -name '*mailsplit*'
>   /usr/local/share/doc/git-doc/git-mailsplit.txt
>   /usr/local/share/doc/git-doc/git-mailsplit.html
>   /usr/local/share/man/man1/git-mailsplit.1
>   /usr/local/libexec/git-core/git-mailsplit

This is the mailsplit command, and should be executed when running `git
mailsplit`. What does git --exec-dir return?

Kevin


Re: Mailsplit

2018-09-05 Thread Stephen & Linda Smith
On Wednesday, September 5, 2018 9:17:29 PM MST Stephen & Linda Smith wrote:

> So two questions:
> 1)  why would git version 2.18.0 not appear to continue applying the
> patches.
> 
> 2) where do I find the command "git mailsplit".   The onlything in my
> installed tree is:
> 
Never mind, I downloaded each patch separately.




Mailsplit

2018-09-05 Thread Stephen & Linda Smith
I thought I would use "git mailsplit" to split a mbox file (which downloaded 
from public inbox) so that I could attemp to resurrect a patch series for from 
a year ago.  

The motivation is that I downloaded the series [1] and applied to a tag from 
about the time period that the patch was sent out [2].  

The "git am -3 patch.mbox  quit 2/3 of the way though.   I resolved the fix. 
and ran "git am --continue" which didn't apply the rest of the patches in the 
mbox.

So two questions:
1)  why would git version 2.18.0 not appear to continue applying the patches.   

2) where do I find the command "git mailsplit".   The onlything in my 
installed tree is:

    $ find  /usr/local/ -name '*mailsplit*'
/usr/local/share/doc/git-doc/git-mailsplit.txt
/usr/local/share/doc/git-doc/git-mailsplit.html
/usr/local/share/man/man1/git-mailsplit.1
/usr/local/libexec/git-core/git-mailsplit

sps

[1] 
https://public-inbox.org/git/1502914591-26215-1-git-send-email-martin@mail.zuhause/

[2] I wanted to make sure that I could apply back then before attempting to 
either apply to the latest git version or rebase to the latest git version. 





[PATCH v4 09/25] mailinfo & mailsplit: check for EOF while parsing

2017-05-04 Thread Johannes Schindelin
While POSIX states that it is okay to pass EOF to isspace() (and it seems
to be implied that EOF should *not* be treated as whitespace), and also to
pass EOF to ungetc() (which seems to be intended to fail without buffering
the character), it is much better to handle these cases explicitly. Not
only does it reduce head-scratching (and helps static analysis avoid
reporting false positives), it also lets us handle files containing
nothing but whitespace by erroring out.

Reported via Coverity.

Signed-off-by: Johannes Schindelin 
---
 builtin/mailsplit.c | 10 ++
 mailinfo.c  |  9 -
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 30681681c13..664400b8169 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -232,6 +232,16 @@ static int split_mbox(const char *file, const char *dir, 
int allow_bare,
 
do {
peek = fgetc(f);
+   if (peek == EOF) {
+   if (f == stdin)
+   /* empty stdin is OK */
+   ret = skip;
+   else {
+   fclose(f);
+   error(_("empty mbox: '%s'"), file);
+   }
+   goto out;
+   }
} while (isspace(peek));
ungetc(peek, f);
 
diff --git a/mailinfo.c b/mailinfo.c
index 68037758f2f..f92cb9f729c 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -882,7 +882,10 @@ static int read_one_header_line(struct strbuf *line, FILE 
*in)
for (;;) {
int peek;
 
-   peek = fgetc(in); ungetc(peek, in);
+   peek = fgetc(in);
+   if (peek == EOF)
+   break;
+   ungetc(peek, in);
if (peek != ' ' && peek != '\t')
break;
if (strbuf_getline_lf(&continuation, in))
@@ -1099,6 +1102,10 @@ int mailinfo(struct mailinfo *mi, const char *msg, const 
char *patch)
 
do {
peek = fgetc(mi->input);
+   if (peek == EOF) {
+   fclose(cmitmsg);
+   return error("empty patch: '%s'", patch);
+   }
} while (isspace(peek));
ungetc(peek, mi->input);
 
-- 
2.12.2.windows.2.800.gede8f145e06




[PATCH v3 09/25] mailinfo & mailsplit: check for EOF while parsing

2017-05-02 Thread Johannes Schindelin
While POSIX states that it is okay to pass EOF to isspace() (and it seems
to be implied that EOF should *not* be treated as whitespace), and also to
pass EOF to ungetc() (which seems to be intended to fail without buffering
the character), it is much better to handle these cases explicitly. Not
only does it reduce head-scratching (and helps static analysis avoid
reporting false positives), it also lets us handle files containing
nothing but whitespace by erroring out.

Reported via Coverity.

Signed-off-by: Johannes Schindelin 
---
 builtin/mailsplit.c | 10 ++
 mailinfo.c  |  9 -
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 30681681c13..664400b8169 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -232,6 +232,16 @@ static int split_mbox(const char *file, const char *dir, 
int allow_bare,
 
do {
peek = fgetc(f);
+   if (peek == EOF) {
+   if (f == stdin)
+   /* empty stdin is OK */
+   ret = skip;
+   else {
+   fclose(f);
+   error(_("empty mbox: '%s'"), file);
+   }
+   goto out;
+   }
} while (isspace(peek));
ungetc(peek, f);
 
diff --git a/mailinfo.c b/mailinfo.c
index 68037758f2f..f92cb9f729c 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -882,7 +882,10 @@ static int read_one_header_line(struct strbuf *line, FILE 
*in)
for (;;) {
int peek;
 
-   peek = fgetc(in); ungetc(peek, in);
+   peek = fgetc(in);
+   if (peek == EOF)
+   break;
+   ungetc(peek, in);
if (peek != ' ' && peek != '\t')
break;
if (strbuf_getline_lf(&continuation, in))
@@ -1099,6 +1102,10 @@ int mailinfo(struct mailinfo *mi, const char *msg, const 
char *patch)
 
do {
peek = fgetc(mi->input);
+   if (peek == EOF) {
+   fclose(cmitmsg);
+   return error("empty patch: '%s'", patch);
+   }
} while (isspace(peek));
ungetc(peek, mi->input);
 
-- 
2.12.2.windows.2.800.gede8f145e06




Re: [PATCH v2 09/25] mailinfo & mailsplit: check for EOF while parsing

2017-05-02 Thread Johannes Schindelin
Hi Junio,

On Mon, 1 May 2017, Junio C Hamano wrote:

> Johannes Schindelin  writes:
> 
> > diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
> > index 30681681c13..9b3efc8e987 100644
> > --- a/builtin/mailsplit.c
> > +++ b/builtin/mailsplit.c
> > @@ -233,7 +233,8 @@ static int split_mbox(const char *file, const char 
> > *dir, int allow_bare,
> > do {
> > peek = fgetc(f);
> > } while (isspace(peek));
> > -   ungetc(peek, f);
> > +   if (peek != EOF)
> > +   ungetc(peek, f);
> 
> I agree more with the first sentence in the proposed log message
> than what this code actually does.  I.e. breaking upon seeing an EOF
> explicitly would be nice, just like the change to mailinfo.c in this
> patch we see below.

I changed it to error out with a (translated) "empty mbox: '%s'" as the
other hunks.

> > @@ -1094,14 +1097,18 @@ int mailinfo(struct mailinfo *mi, const char *msg, 
> > const char *patch)
> > return -1;
> > }
> >  
> > -   mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
> > -   mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
> > -
> > do {
> > peek = fgetc(mi->input);
> > +   if (peek == EOF) {
> > +   fclose(cmitmsg);
> > +   return error("empty patch: '%s'", patch);
> > +   }
> > } while (isspace(peek));
> > ungetc(peek, mi->input);
> 
> The handling of EOF is improved, but is it correct to move the
> allocation of p/s_hdr_data down?

Sorry, I *assumed* that the function was passed a zero-initialized
mailinfo struct. And as you pointed out, that assumption was wrong.

My thinking was that I did not want to introduce another leakage by my
patch, but as your careful analysis determined: the only caller that does
not die() afterwards releases the data (and would not even be able to
handle p_hdr_data == NULL...).

I reverted that move.

Ciao,
Dscho


Re: [PATCH v2 09/25] mailinfo & mailsplit: check for EOF while parsing

2017-05-01 Thread Junio C Hamano
Johannes Schindelin  writes:

> While POSIX states that it is okay to pass EOF to isspace() (and it seems
> to be implied that EOF should *not* be treated as whitespace), and also to
> pass EOF to ungetc() (which seems to be intended to fail without buffering
> the character), it is much better to handle these cases explicitly. Not
> only does it reduce head-scratching (and helps static analysis avoid
> reporting false positives), it also lets us handle files containing
> nothing but whitespace by erroring out.
>
> Reported via Coverity.
>
> Signed-off-by: Johannes Schindelin 
> ---
>  builtin/mailsplit.c |  3 ++-
>  mailinfo.c  | 15 +++
>  2 files changed, 13 insertions(+), 5 deletions(-)
>
> diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
> index 30681681c13..9b3efc8e987 100644
> --- a/builtin/mailsplit.c
> +++ b/builtin/mailsplit.c
> @@ -233,7 +233,8 @@ static int split_mbox(const char *file, const char *dir, 
> int allow_bare,
>   do {
>   peek = fgetc(f);
>   } while (isspace(peek));
> - ungetc(peek, f);
> + if (peek != EOF)
> + ungetc(peek, f);

I agree more with the first sentence in the proposed log message
than what this code actually does.  I.e. breaking upon seeing an EOF
explicitly would be nice, just like the change to mailinfo.c in this
patch we see below.

> @@ -1094,14 +1097,18 @@ int mailinfo(struct mailinfo *mi, const char *msg, 
> const char *patch)
>   return -1;
>   }
>  
> - mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
> - mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
> -
>   do {
>   peek = fgetc(mi->input);
> + if (peek == EOF) {
> + fclose(cmitmsg);
> + return error("empty patch: '%s'", patch);
> + }
>   } while (isspace(peek));
>   ungetc(peek, mi->input);

The handling of EOF is improved, but is it correct to move the
allocation of p/s_hdr_data down?

Among the two callers, builtin/am.c just dies when it sees
mailinfo() returns an error, but builtin/mailinfo.c tries to be
nicer and calls clear_mailinfo().  Wouldn't this make that codepath
dereference a NULL pointer?

I think the moral of the story is that people tend to get sloppier
when doing "while we are at it" than the main task, and a reviewer
needs to be more careful while reviewing the "while we are at it"
part of the change than the primary thing a patch wants to do ;-)

> + mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
> + mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
> +
>   /* process the email header */
>   while (read_one_header_line(&line, mi->input))
>   check_header(mi, &line, mi->p_hdr_data, 1);


[PATCH v2 09/25] mailinfo & mailsplit: check for EOF while parsing

2017-04-28 Thread Johannes Schindelin
While POSIX states that it is okay to pass EOF to isspace() (and it seems
to be implied that EOF should *not* be treated as whitespace), and also to
pass EOF to ungetc() (which seems to be intended to fail without buffering
the character), it is much better to handle these cases explicitly. Not
only does it reduce head-scratching (and helps static analysis avoid
reporting false positives), it also lets us handle files containing
nothing but whitespace by erroring out.

Reported via Coverity.

Signed-off-by: Johannes Schindelin 
---
 builtin/mailsplit.c |  3 ++-
 mailinfo.c  | 15 +++
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 30681681c13..9b3efc8e987 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -233,7 +233,8 @@ static int split_mbox(const char *file, const char *dir, 
int allow_bare,
do {
peek = fgetc(f);
} while (isspace(peek));
-   ungetc(peek, f);
+   if (peek != EOF)
+   ungetc(peek, f);
 
if (strbuf_getwholeline(&buf, f, '\n')) {
/* empty stdin is OK */
diff --git a/mailinfo.c b/mailinfo.c
index 68037758f2f..a319911b510 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -882,7 +882,10 @@ static int read_one_header_line(struct strbuf *line, FILE 
*in)
for (;;) {
int peek;
 
-   peek = fgetc(in); ungetc(peek, in);
+   peek = fgetc(in);
+   if (peek == EOF)
+   break;
+   ungetc(peek, in);
if (peek != ' ' && peek != '\t')
break;
if (strbuf_getline_lf(&continuation, in))
@@ -1094,14 +1097,18 @@ int mailinfo(struct mailinfo *mi, const char *msg, 
const char *patch)
return -1;
}
 
-   mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
-   mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
-
do {
peek = fgetc(mi->input);
+   if (peek == EOF) {
+   fclose(cmitmsg);
+   return error("empty patch: '%s'", patch);
+   }
} while (isspace(peek));
ungetc(peek, mi->input);
 
+   mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
+   mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
+
/* process the email header */
while (read_one_header_line(&line, mi->input))
check_header(mi, &line, mi->p_hdr_data, 1);
-- 
2.12.2.windows.2.800.gede8f145e06




Re: [PATCH] format-patch: escape "From " lines recognized by mailsplit

2016-07-25 Thread Eric Wong
Junio C Hamano  wrote:
> Eric Wong  writes:
> 
> >> Also, doesn't it break "git rebase" (non-interactive), or anything
> >> that internally runs format-patch to individual files and then runs
> >> am on each of them, anything that knows that each output file from
> >> format-patch corresponds to a single change and there is no need to
> >> split, badly if we do this unconditionally?
> >
> > Yes, rebase should probably unescape is_from_line matches.
> 
> This shouldn't matter for "git rebase", as it only reads from the
> mbox "From  " line to learn the
> original commit and extract the log message directly from there.

OK.

> But a third-party script that wants to read format-patch output
> would be forced to upgrade, which is a pain if we make this change
> unconditionally.

I suppose unconditionally having mailsplit unescape
">From ...  $DATE" lines might be acceptable?

It'll still propagate these mistakes to older versions of git,
but those installations will eventually become fewer.

> >> IOW, shouldn't this be an optional feature to format-patch that
> >> is triggered by passing a new command line option that currently
> >> nobody is passing?
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] mailinfo: extract is_from_line from mailsplit

2016-07-25 Thread Junio C Hamano
Andreas Schwab  writes:

>> +colon = line + len - 2;
>> +line += 5;
>> +for (;;) {
>> +if (colon < line)
>> +return 0;
>> +if (*--colon == ':')
>> +break;
>> +}
>> +
>> +if (!isdigit(colon[-4]) ||
>> +!isdigit(colon[-2]) ||
>> +!isdigit(colon[-1]) ||
>> +!isdigit(colon[ 1]) ||
>> +!isdigit(colon[ 2]))
>> +return 0;
>> +
>> +/* year */
>> +if (strtol(colon+3, NULL, 10) <= 90)
>> +return 0;
>> +
>> +/* Ok, close enough */
>> +return 1;
>> +}
>
> Should this be made more strict, like by checking for a space before the
> year?

The function seems to judge the line to be "close enough" by
checking these places (please view with fixed-width font ;-):

From me Mon Jul 25 01:23:45 2016
x   x x 

We only see if the year part is more than 90 but we do not even
ensure that it is at the end of the line without any further
garbage, which I think is probably OK for the purpose of "close
enough".

We also do not bother rejecting a single-digit hour, or there is a
colon between the hour and minute part.

I would say requiring SP between the year and the second, and
requiring colon between hour and minute, would probably be a good
change, i.e. something like this:

if (!isdigit(colon[-4]) ||
colon[-3] != ':' ||
!isdigit(colon[-2]) ||
!isdigit(colon[-1]) ||
!isdigit(colon[ 1]) ||
!isdigit(colon[ 2]) ||
colon[3] != ' ')

would be safe enough without increasing the false negatives too
much.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] format-patch: escape "From " lines recognized by mailsplit

2016-07-25 Thread Junio C Hamano
Eric Wong  writes:

>> Also, doesn't it break "git rebase" (non-interactive), or anything
>> that internally runs format-patch to individual files and then runs
>> am on each of them, anything that knows that each output file from
>> format-patch corresponds to a single change and there is no need to
>> split, badly if we do this unconditionally?
>
> Yes, rebase should probably unescape is_from_line matches.

This shouldn't matter for "git rebase", as it only reads from the
mbox "From  " line to learn the
original commit and extract the log message directly from there.

But a third-party script that wants to read format-patch output
would be forced to upgrade, which is a pain if we make this change
unconditionally.

>> IOW, shouldn't this be an optional feature to format-patch that
>> is triggered by passing a new command line option that currently
>> nobody is passing?
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] format-patch: escape "From " lines recognized by mailsplit

2016-07-25 Thread Eric Wong
Junio C Hamano  wrote:
> Junio C Hamano  writes:
> > Eric Wong  writes:
> >
> >> Users have mistakenly copied "From " lines into commit messages
> >> in the past, and will certainly make the same mistakes in the
> >> future.  Since not everyone uses mboxrd, yet, we should at least
> >> prevent miss-split mails by always escaping "From " lines based
> >> on the check used by mailsplit.
> >>
> >> mailsplit will not perform unescaping by default, yet, as it
> >> could cause further invocations of format-patch from old
> >> versions of git to generate bad output.  Propagating the mboxo
> >> escaping is preferable to miss-split patches.  Unescaping may
> >> still be performed via "--mboxrd".
> >
> > As a tool to produce mbox file, quoting like this in format-patch
> > output may make sense, I would think, but shouldn't send-email undo
> > this when sending individual patches?
> 
> Also, doesn't it break "git rebase" (non-interactive), or anything
> that internally runs format-patch to individual files and then runs
> am on each of them, anything that knows that each output file from
> format-patch corresponds to a single change and there is no need to
> split, badly if we do this unconditionally?

Yes, rebase should probably unescape is_from_line matches.

Anything which spawns an editor should probably warn/reprompt
users on is_from_line() matches, too, to prevent user errors
from sneaking in.

> IOW, shouldn't this be an optional feature to format-patch that is
> triggered by passing a new command line option that currently nobody
> is passing?

I added --pretty=mboxrd as the optional feature for this reason.
It'll take a while for people to start using it (or perhaps make
it the default in git 3.0).
In the meantime, I would prefer extra ">" being injected rather
than breaking mailsplit completely.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] format-patch: escape "From " lines recognized by mailsplit

2016-07-24 Thread Junio C Hamano
Junio C Hamano  writes:

> Eric Wong  writes:
>
>> Users have mistakenly copied "From " lines into commit messages
>> in the past, and will certainly make the same mistakes in the
>> future.  Since not everyone uses mboxrd, yet, we should at least
>> prevent miss-split mails by always escaping "From " lines based
>> on the check used by mailsplit.
>>
>> mailsplit will not perform unescaping by default, yet, as it
>> could cause further invocations of format-patch from old
>> versions of git to generate bad output.  Propagating the mboxo
>> escaping is preferable to miss-split patches.  Unescaping may
>> still be performed via "--mboxrd".
>
> As a tool to produce mbox file, quoting like this in format-patch
> output may make sense, I would think, but shouldn't send-email undo
> this when sending individual patches?

Also, doesn't it break "git rebase" (non-interactive), or anything
that internally runs format-patch to individual files and then runs
am on each of them, anything that knows that each output file from
format-patch corresponds to a single change and there is no need to
split, badly if we do this unconditionally?

IOW, shouldn't this be an optional feature to format-patch that is
triggered by passing a new command line option that currently nobody
is passing?
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 2/2] format-patch: escape "From " lines recognized by mailsplit

2016-07-24 Thread Jeff King
On Sun, Jul 24, 2016 at 09:37:57AM +0200, Johannes Schindelin wrote:

> On Sun, 24 Jul 2016, Eric Wong wrote:
> 
> > @@ -1745,9 +1746,18 @@ void pp_remainder(struct pretty_print_context *pp,
> > strbuf_add_tabexpand(sb, pp->expand_tabs_in_log,
> >  line, linelen);
> > else {
> > -   if (pp->fmt == CMIT_FMT_MBOXRD &&
> > -   is_mboxrd_from(line, linelen))
> > -   strbuf_addch(sb, '>');
> > +   switch (pp->fmt) {
> > +   case CMIT_FMT_EMAIL:
> > +   if (is_from_line(line, linelen))
> > +   strbuf_addch(sb, '>');
> > +   break;
> > +   case CMIT_FMT_MBOXRD:
> > +   if (is_mboxrd_from(line, linelen))
> > +   strbuf_addch(sb, '>');
> > +   break;
> > +   default:
> > +   break;
> > +   }
> 
> Sorry to be nitpicking once again; I think this would be conciser (and
> easier to read at least for me) as:
> 
> - if (pp->fmt == CMIT_FMT_MBOXRD &&
> - is_mboxrd_from(line, linelen))
> + if ((pp->fmt == CMIT_FMT_MBOXRD &&
> +  is_mboxrd_from(line, linelen)) ||
> + (pp->fmt == CMIT_FMT_EMAIL &&
> +  is_from_line(line, linelen)))
>   strbuf_addch(sb, '>');

Since we are nitpicking, I think:

  static int needs_from_quoting(enum cmit_fmt fmt,
const char *line, size_t len)
  {
if (fmt == CMIT_FMT_MBOXRD && is_mboxrd_from(line, linelen))
return 1;
if (fmt == CMIT_FMT_EMAIL && is_from_line(line, linelen))
return 1;
return 0;
  }

  ...
  if (needs_from_quoting(pp->fmt, line, linelen))
strbuf_addch(sb, '>');

is even nicer. There are lots of alternatives to write the helper
function, and I do not care much which one is chosen. But splitting it
out into a concise "do we need to do this?" query function makes the
flow in pp_remainder much easier to follow.

-Peff
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] format-patch: escape "From " lines recognized by mailsplit

2016-07-24 Thread Eric Wong
Junio C Hamano  wrote:
> As a tool to produce mbox file, quoting like this in format-patch
> output may make sense, I would think, but shouldn't send-email undo
> this when sending individual patches?

Yes, that sounds like a good idea.  Thanks.
Will followup in a day or two.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] mailinfo: extract is_from_line from mailsplit

2016-07-24 Thread Andreas Schwab
Johannes Schindelin  writes:

> Hi Andreas,
>
> On Sun, 24 Jul 2016, Andreas Schwab wrote:
>
>> Eric Wong  writes:
>> 
>> > diff --git a/mailinfo.c b/mailinfo.c
>> > index 9f19ca1..0ebd953 100644
>> > --- a/mailinfo.c
>> > +++ b/mailinfo.c
>> > @@ -1035,3 +1035,34 @@ void clear_mailinfo(struct mailinfo *mi)
>> >  
>> >strbuf_release(&mi->log_message);
>> >  }
>> > +
>> > +int is_from_line(const char *line, int len)
>> > +{
>> > +  const char *colon;
>> > +
>> > +  if (len < 20 || memcmp("From ", line, 5))
>> > +  return 0;
>> > +
>> > +  colon = line + len - 2;
>> > +  line += 5;
>> > +  for (;;) {
>> > +  if (colon < line)
>> > +  return 0;
>> > +  if (*--colon == ':')
>> > +  break;
>> > +  }
>> > +
>> > +  if (!isdigit(colon[-4]) ||
>> > +  !isdigit(colon[-2]) ||
>> > +  !isdigit(colon[-1]) ||
>> > +  !isdigit(colon[ 1]) ||
>> > +  !isdigit(colon[ 2]))
>> > +  return 0;
>> > +
>> > +  /* year */
>> > +  if (strtol(colon+3, NULL, 10) <= 90)
>> > +  return 0;
>> > +
>> > +  /* Ok, close enough */
>> > +  return 1;
>> > +}
>> 
>> Should this be made more strict, like by checking for a space before the
>> year?
>
> This patch only moves the function, so it would be inappropriate to change
> it.
>
> If you want to make it stricter, you will have to submit a separate patch.

You didn't answer my question.

Andreas.

-- 
Andreas Schwab, sch...@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] mailinfo: extract is_from_line from mailsplit

2016-07-24 Thread Johannes Schindelin
Hi Andreas,

On Sun, 24 Jul 2016, Andreas Schwab wrote:

> Eric Wong  writes:
> 
> > diff --git a/mailinfo.c b/mailinfo.c
> > index 9f19ca1..0ebd953 100644
> > --- a/mailinfo.c
> > +++ b/mailinfo.c
> > @@ -1035,3 +1035,34 @@ void clear_mailinfo(struct mailinfo *mi)
> >  
> > strbuf_release(&mi->log_message);
> >  }
> > +
> > +int is_from_line(const char *line, int len)
> > +{
> > +   const char *colon;
> > +
> > +   if (len < 20 || memcmp("From ", line, 5))
> > +   return 0;
> > +
> > +   colon = line + len - 2;
> > +   line += 5;
> > +   for (;;) {
> > +   if (colon < line)
> > +   return 0;
> > +   if (*--colon == ':')
> > +   break;
> > +   }
> > +
> > +   if (!isdigit(colon[-4]) ||
> > +   !isdigit(colon[-2]) ||
> > +   !isdigit(colon[-1]) ||
> > +   !isdigit(colon[ 1]) ||
> > +   !isdigit(colon[ 2]))
> > +   return 0;
> > +
> > +   /* year */
> > +   if (strtol(colon+3, NULL, 10) <= 90)
> > +   return 0;
> > +
> > +   /* Ok, close enough */
> > +   return 1;
> > +}
> 
> Should this be made more strict, like by checking for a space before the
> year?

This patch only moves the function, so it would be inappropriate to change
it.

If you want to make it stricter, you will have to submit a separate patch.

Ciao,
Johannes
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 2/2] format-patch: escape "From " lines recognized by mailsplit

2016-07-24 Thread Johannes Schindelin
Hi Eric,

On Sun, 24 Jul 2016, Eric Wong wrote:

> @@ -1745,9 +1746,18 @@ void pp_remainder(struct pretty_print_context *pp,
>   strbuf_add_tabexpand(sb, pp->expand_tabs_in_log,
>line, linelen);
>   else {
> - if (pp->fmt == CMIT_FMT_MBOXRD &&
> - is_mboxrd_from(line, linelen))
> - strbuf_addch(sb, '>');
> + switch (pp->fmt) {
> + case CMIT_FMT_EMAIL:
> + if (is_from_line(line, linelen))
> + strbuf_addch(sb, '>');
> + break;
> + case CMIT_FMT_MBOXRD:
> + if (is_mboxrd_from(line, linelen))
> + strbuf_addch(sb, '>');
> + break;
> + default:
> + break;
> + }

Sorry to be nitpicking once again; I think this would be conciser (and
easier to read at least for me) as:

-   if (pp->fmt == CMIT_FMT_MBOXRD &&
-   is_mboxrd_from(line, linelen))
+   if ((pp->fmt == CMIT_FMT_MBOXRD &&
+is_mboxrd_from(line, linelen)) ||
+   (pp->fmt == CMIT_FMT_EMAIL &&
+is_from_line(line, linelen)))
strbuf_addch(sb, '>');

> diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
> index 1206c48..8fa3982 100755
> --- a/t/t4014-format-patch.sh
> +++ b/t/t4014-format-patch.sh
> @@ -1606,4 +1606,18 @@ test_expect_success 'format-patch --pretty=mboxrd' '
>   test_cmp expect actual
>  '
>  
> +test_expect_success 'format-patch From escaping' '
> + cat >msg <<-INPUT_END &&
> + somebody pasted format-patch output into a body
> +
> + From  Mon Sep 17 00:00:00 2001
> + INPUT_END
> +
> + C=$(git commit-tree HEAD^^{tree} -p HEAD  + git format-patch --stdout -1 $C~1..$C >patch &&

Either "-1 $C" or "$C~1..$C", not both...

> + git grep -h --no-index \
> + ">From  " \
> + patch
> +'
> +
>  test_done
> -- 
> EW

Heh, that's a nice Git version ;-)

Ciao,
Dscho
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] mailinfo: extract is_from_line from mailsplit

2016-07-24 Thread Andreas Schwab
Eric Wong  writes:

> diff --git a/mailinfo.c b/mailinfo.c
> index 9f19ca1..0ebd953 100644
> --- a/mailinfo.c
> +++ b/mailinfo.c
> @@ -1035,3 +1035,34 @@ void clear_mailinfo(struct mailinfo *mi)
>  
>   strbuf_release(&mi->log_message);
>  }
> +
> +int is_from_line(const char *line, int len)
> +{
> + const char *colon;
> +
> + if (len < 20 || memcmp("From ", line, 5))
> + return 0;
> +
> + colon = line + len - 2;
> + line += 5;
> + for (;;) {
> + if (colon < line)
> + return 0;
> + if (*--colon == ':')
> + break;
> + }
> +
> + if (!isdigit(colon[-4]) ||
> + !isdigit(colon[-2]) ||
> + !isdigit(colon[-1]) ||
> + !isdigit(colon[ 1]) ||
> + !isdigit(colon[ 2]))
> + return 0;
> +
> + /* year */
> + if (strtol(colon+3, NULL, 10) <= 90)
> + return 0;
> +
> + /* Ok, close enough */
> + return 1;
> +}

Should this be made more strict, like by checking for a space before the
year?

Andreas.

-- 
Andreas Schwab, sch...@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] format-patch: escape "From " lines recognized by mailsplit

2016-07-24 Thread Junio C Hamano
Eric Wong  writes:

> Users have mistakenly copied "From " lines into commit messages
> in the past, and will certainly make the same mistakes in the
> future.  Since not everyone uses mboxrd, yet, we should at least
> prevent miss-split mails by always escaping "From " lines based
> on the check used by mailsplit.
>
> mailsplit will not perform unescaping by default, yet, as it
> could cause further invocations of format-patch from old
> versions of git to generate bad output.  Propagating the mboxo
> escaping is preferable to miss-split patches.  Unescaping may
> still be performed via "--mboxrd".

As a tool to produce mbox file, quoting like this in format-patch
output may make sense, I would think, but shouldn't send-email undo
this when sending individual patches?
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] mailinfo: extract is_from_line from mailsplit

2016-07-23 Thread Eric Wong
We will be reusing is_from_line for quoting format-patch output
in the next commit.

Suggested-by: Johannes Schindelin 
Signed-off-by: Eric Wong 
---
 builtin/mailsplit.c | 32 +---
 mailinfo.c  | 31 +++
 mailinfo.h  |  1 +
 3 files changed, 33 insertions(+), 31 deletions(-)

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 3068168..bb8f9c9 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -8,41 +8,11 @@
 #include "builtin.h"
 #include "string-list.h"
 #include "strbuf.h"
+#include "mailinfo.h"
 
 static const char git_mailsplit_usage[] =
 "git mailsplit [-d] [-f] [-b] [--keep-cr] -o 
[(|)...]";
 
-static int is_from_line(const char *line, int len)
-{
-   const char *colon;
-
-   if (len < 20 || memcmp("From ", line, 5))
-   return 0;
-
-   colon = line + len - 2;
-   line += 5;
-   for (;;) {
-   if (colon < line)
-   return 0;
-   if (*--colon == ':')
-   break;
-   }
-
-   if (!isdigit(colon[-4]) ||
-   !isdigit(colon[-2]) ||
-   !isdigit(colon[-1]) ||
-   !isdigit(colon[ 1]) ||
-   !isdigit(colon[ 2]))
-   return 0;
-
-   /* year */
-   if (strtol(colon+3, NULL, 10) <= 90)
-   return 0;
-
-   /* Ok, close enough */
-   return 1;
-}
-
 static struct strbuf buf = STRBUF_INIT;
 static int keep_cr;
 static int mboxrd;
diff --git a/mailinfo.c b/mailinfo.c
index 9f19ca1..0ebd953 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -1035,3 +1035,34 @@ void clear_mailinfo(struct mailinfo *mi)
 
strbuf_release(&mi->log_message);
 }
+
+int is_from_line(const char *line, int len)
+{
+   const char *colon;
+
+   if (len < 20 || memcmp("From ", line, 5))
+   return 0;
+
+   colon = line + len - 2;
+   line += 5;
+   for (;;) {
+   if (colon < line)
+   return 0;
+   if (*--colon == ':')
+   break;
+   }
+
+   if (!isdigit(colon[-4]) ||
+   !isdigit(colon[-2]) ||
+   !isdigit(colon[-1]) ||
+   !isdigit(colon[ 1]) ||
+   !isdigit(colon[ 2]))
+   return 0;
+
+   /* year */
+   if (strtol(colon+3, NULL, 10) <= 90)
+   return 0;
+
+   /* Ok, close enough */
+   return 1;
+}
diff --git a/mailinfo.h b/mailinfo.h
index 93776a7..c1430a0 100644
--- a/mailinfo.h
+++ b/mailinfo.h
@@ -37,5 +37,6 @@ struct mailinfo {
 extern void setup_mailinfo(struct mailinfo *);
 extern int mailinfo(struct mailinfo *, const char *msg, const char *patch);
 extern void clear_mailinfo(struct mailinfo *);
+int is_from_line(const char *line, int len);
 
 #endif /* MAILINFO_H */
-- 
EW
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] format-patch: escape "From " lines recognized by mailsplit

2016-07-23 Thread Eric Wong
Users have mistakenly copied "From " lines into commit messages
in the past, and will certainly make the same mistakes in the
future.  Since not everyone uses mboxrd, yet, we should at least
prevent miss-split mails by always escaping "From " lines based
on the check used by mailsplit.

mailsplit will not perform unescaping by default, yet, as it
could cause further invocations of format-patch from old
versions of git to generate bad output.  Propagating the mboxo
escaping is preferable to miss-split patches.  Unescaping may
still be performed via "--mboxrd".

ref: https://public-inbox.org/git/20160606230248.ga15...@dcvr.yhbt.net/T/#u

Signed-off-by: Eric Wong 
---
 pretty.c| 16 +---
 t/t4014-format-patch.sh | 14 ++
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/pretty.c b/pretty.c
index 9fa42c2..898c0a3 100644
--- a/pretty.c
+++ b/pretty.c
@@ -10,6 +10,7 @@
 #include "color.h"
 #include "reflog-walk.h"
 #include "gpg-interface.h"
+#include "mailinfo.h"
 
 static char *user_format;
 static struct cmt_fmt_map {
@@ -1745,9 +1746,18 @@ void pp_remainder(struct pretty_print_context *pp,
strbuf_add_tabexpand(sb, pp->expand_tabs_in_log,
 line, linelen);
else {
-   if (pp->fmt == CMIT_FMT_MBOXRD &&
-   is_mboxrd_from(line, linelen))
-   strbuf_addch(sb, '>');
+   switch (pp->fmt) {
+   case CMIT_FMT_EMAIL:
+   if (is_from_line(line, linelen))
+   strbuf_addch(sb, '>');
+   break;
+   case CMIT_FMT_MBOXRD:
+   if (is_mboxrd_from(line, linelen))
+   strbuf_addch(sb, '>');
+   break;
+   default:
+   break;
+   }
 
strbuf_add(sb, line, linelen);
}
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 1206c48..8fa3982 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -1606,4 +1606,18 @@ test_expect_success 'format-patch --pretty=mboxrd' '
test_cmp expect actual
 '
 
+test_expect_success 'format-patch From escaping' '
+   cat >msg <<-INPUT_END &&
+   somebody pasted format-patch output into a body
+
+   From  Mon Sep 17 00:00:00 2001
+   INPUT_END
+
+   C=$(git commit-tree HEAD^^{tree} -p HEAD patch &&
+   git grep -h --no-index \
+   ">From  " \
+   patch
+'
+
 test_done
-- 
EW
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] format-patch: escape "From " lines recognized by mailsplit

2016-07-23 Thread Eric Wong
Johannes Schindelin  wrote:
> I think that this change:



> deserves to live in a separate patch... It would make the real change
> stick out better.

Good point, I actually wrote a looser check based on
is_mboxrd_from before realizing the stricter check from
mailsplit would probably be more appropriate to use by default.


The following changes since commit 08bb3500a2a718c3c78b0547c68601cafa7a8fd9:

  Sixth batch of topics for 2.10 (2016-07-19 13:26:16 -0700)

are available in the git repository at:

  git://bogomips.org/git-svn.git mboxo

for you to fetch changes up to 4f769f1799db11f135948bf517f2d8d864fa778f:

  format-patch: escape "From " lines recognized by mailsplit (2016-07-23 
21:38:40 +)


Eric Wong (2):
  mailinfo: extract is_from_line from mailsplit
  format-patch: escape "From " lines recognized by mailsplit

 builtin/mailsplit.c | 32 +---
 mailinfo.c  | 31 +++
 mailinfo.h  |  1 +
 pretty.c| 16 +---
 t/t4014-format-patch.sh | 14 ++
 5 files changed, 60 insertions(+), 34 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] format-patch: escape "From " lines recognized by mailsplit

2016-07-23 Thread Johannes Schindelin
Hi Eric,

I think that this change:

On Fri, 22 Jul 2016, Eric Wong wrote:

> diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
> index 3068168..bb8f9c9 100644
> --- a/builtin/mailsplit.c
> +++ b/builtin/mailsplit.c
> @@ -8,41 +8,11 @@
>  #include "builtin.h"
>  #include "string-list.h"
>  #include "strbuf.h"
> +#include "mailinfo.h"
>  
>  static const char git_mailsplit_usage[] =
>  "git mailsplit [-d] [-f] [-b] [--keep-cr] -o 
> [(|)...]";
>  
> -static int is_from_line(const char *line, int len)
> -{
> - const char *colon;
> -
> - if (len < 20 || memcmp("From ", line, 5))
> - return 0;
> -
> - colon = line + len - 2;
> - line += 5;
> - for (;;) {
> - if (colon < line)
> - return 0;
> - if (*--colon == ':')
> - break;
> - }
> -
> - if (!isdigit(colon[-4]) ||
> - !isdigit(colon[-2]) ||
> - !isdigit(colon[-1]) ||
> - !isdigit(colon[ 1]) ||
> - !isdigit(colon[ 2]))
> - return 0;
> -
> - /* year */
> - if (strtol(colon+3, NULL, 10) <= 90)
> - return 0;
> -
> - /* Ok, close enough */
> - return 1;
> -}
> -
>  static struct strbuf buf = STRBUF_INIT;
>  static int keep_cr;
>  static int mboxrd;
> diff --git a/mailinfo.c b/mailinfo.c
> index 9f19ca1..0ebd953 100644
> --- a/mailinfo.c
> +++ b/mailinfo.c
> @@ -1035,3 +1035,34 @@ void clear_mailinfo(struct mailinfo *mi)
>  
>   strbuf_release(&mi->log_message);
>  }
> +
> +int is_from_line(const char *line, int len)
> +{
> + const char *colon;
> +
> + if (len < 20 || memcmp("From ", line, 5))
> + return 0;
> +
> + colon = line + len - 2;
> + line += 5;
> + for (;;) {
> + if (colon < line)
> + return 0;
> + if (*--colon == ':')
> + break;
> + }
> +
> + if (!isdigit(colon[-4]) ||
> + !isdigit(colon[-2]) ||
> + !isdigit(colon[-1]) ||
> + !isdigit(colon[ 1]) ||
> + !isdigit(colon[ 2]))
> + return 0;
> +
> + /* year */
> + if (strtol(colon+3, NULL, 10) <= 90)
> + return 0;
> +
> + /* Ok, close enough */
> + return 1;
> +}
> diff --git a/mailinfo.h b/mailinfo.h
> index 93776a7..c1430a0 100644
> --- a/mailinfo.h
> +++ b/mailinfo.h
> @@ -37,5 +37,6 @@ struct mailinfo {
>  extern void setup_mailinfo(struct mailinfo *);
>  extern int mailinfo(struct mailinfo *, const char *msg, const char *patch);
>  extern void clear_mailinfo(struct mailinfo *);
> +int is_from_line(const char *line, int len);
>  
>  #endif /* MAILINFO_H */

deserves to live in a separate patch... It would make the real change
stick out better.

Ciao,
Dscho
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] format-patch: escape "From " lines recognized by mailsplit

2016-07-22 Thread Eric Wong
Users have mistakenly copied "From " lines into commit messages
in the past, and will certainly make the same mistakes in the
future.  Since not everyone uses mboxrd, yet, we should at least
prevent miss-split mails by always escaping "From " lines based
on the check used by mailsplit.

mailsplit will not perform unescaping by default, yet, as it
could cause further invocations of format-patch from old
versions of git to generate bad output.  Propagating the mboxo
escaping is preferable to miss-split patches.  Unescaping may
still be performed via "--mboxrd".

ref: https://public-inbox.org/git/20160606230248.ga15...@dcvr.yhbt.net/T/#u

Signed-off-by: Eric Wong 
---
 builtin/mailsplit.c | 32 +---
 mailinfo.c  | 31 +++
 mailinfo.h  |  1 +
 pretty.c| 16 +---
 t/t4014-format-patch.sh | 14 ++
 5 files changed, 60 insertions(+), 34 deletions(-)

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 3068168..bb8f9c9 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -8,41 +8,11 @@
 #include "builtin.h"
 #include "string-list.h"
 #include "strbuf.h"
+#include "mailinfo.h"
 
 static const char git_mailsplit_usage[] =
 "git mailsplit [-d] [-f] [-b] [--keep-cr] -o 
[(|)...]";
 
-static int is_from_line(const char *line, int len)
-{
-   const char *colon;
-
-   if (len < 20 || memcmp("From ", line, 5))
-   return 0;
-
-   colon = line + len - 2;
-   line += 5;
-   for (;;) {
-   if (colon < line)
-   return 0;
-   if (*--colon == ':')
-   break;
-   }
-
-   if (!isdigit(colon[-4]) ||
-   !isdigit(colon[-2]) ||
-   !isdigit(colon[-1]) ||
-   !isdigit(colon[ 1]) ||
-   !isdigit(colon[ 2]))
-   return 0;
-
-   /* year */
-   if (strtol(colon+3, NULL, 10) <= 90)
-   return 0;
-
-   /* Ok, close enough */
-   return 1;
-}
-
 static struct strbuf buf = STRBUF_INIT;
 static int keep_cr;
 static int mboxrd;
diff --git a/mailinfo.c b/mailinfo.c
index 9f19ca1..0ebd953 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -1035,3 +1035,34 @@ void clear_mailinfo(struct mailinfo *mi)
 
strbuf_release(&mi->log_message);
 }
+
+int is_from_line(const char *line, int len)
+{
+   const char *colon;
+
+   if (len < 20 || memcmp("From ", line, 5))
+   return 0;
+
+   colon = line + len - 2;
+   line += 5;
+   for (;;) {
+   if (colon < line)
+   return 0;
+   if (*--colon == ':')
+   break;
+   }
+
+   if (!isdigit(colon[-4]) ||
+   !isdigit(colon[-2]) ||
+   !isdigit(colon[-1]) ||
+   !isdigit(colon[ 1]) ||
+   !isdigit(colon[ 2]))
+   return 0;
+
+   /* year */
+   if (strtol(colon+3, NULL, 10) <= 90)
+   return 0;
+
+   /* Ok, close enough */
+   return 1;
+}
diff --git a/mailinfo.h b/mailinfo.h
index 93776a7..c1430a0 100644
--- a/mailinfo.h
+++ b/mailinfo.h
@@ -37,5 +37,6 @@ struct mailinfo {
 extern void setup_mailinfo(struct mailinfo *);
 extern int mailinfo(struct mailinfo *, const char *msg, const char *patch);
 extern void clear_mailinfo(struct mailinfo *);
+int is_from_line(const char *line, int len);
 
 #endif /* MAILINFO_H */
diff --git a/pretty.c b/pretty.c
index 9fa42c2..898c0a3 100644
--- a/pretty.c
+++ b/pretty.c
@@ -10,6 +10,7 @@
 #include "color.h"
 #include "reflog-walk.h"
 #include "gpg-interface.h"
+#include "mailinfo.h"
 
 static char *user_format;
 static struct cmt_fmt_map {
@@ -1745,9 +1746,18 @@ void pp_remainder(struct pretty_print_context *pp,
strbuf_add_tabexpand(sb, pp->expand_tabs_in_log,
 line, linelen);
else {
-   if (pp->fmt == CMIT_FMT_MBOXRD &&
-   is_mboxrd_from(line, linelen))
-   strbuf_addch(sb, '>');
+   switch (pp->fmt) {
+   case CMIT_FMT_EMAIL:
+   if (is_from_line(line, linelen))
+   strbuf_addch(sb, '>');
+   break;
+   case CMIT_FMT_MBOXRD:
+   if (is_mboxrd_from(line, linelen))
+   strbuf_addch(sb, '>');
+   break;
+   default:
+   break;
+   }
 
strbuf_add(sb, line, linel

Re: [PATCH v2 2/3] mailsplit: support unescaping mboxrd messages

2016-06-06 Thread Eric Wong
Junio C Hamano  wrote:
> This just makes me wonder if there is a practical reason why people
> would not want this always enabled.  I just looked at output from
> 
> $ git log --grep='>>*From '

Missing '^' ?

Auto-unescaping in mailsplit might throw off people on older
versions of git if reserialized as mail, though.
Maybe in a few years, we can consider it.

Auto-escaping on the other hand, I think we start doing in
--pretty=email by default soon/today.  At least for lines
matching the stricter is_from_line() check from mailsplit.

> in the kernel repository, and I saw no cases where the committer
> really wanted to preserve the leading one or more '>' on that line.
> No, I didn't go through all of 150+ such commits, but I did check
> the couple dozen of them from the recent history.
> 
> Our history also have 5 instances of them, none of which should have
> had the leading '>' if the committer were careful.

Right, but I'm actually more worried about unescaped /^From /
breaking further attempts to split.

git log --grep='^From .*:.*:.* .*'

...finds 45 commits in Linux 4.6.1 which might cause incorrect
splits.  We have 5 of those ourselves.

Technically it is backwards-incompatible, but I would rather
leave an extra '>' in the commit than break a split.

> > +>From the beginning, mbox should have been mboxrd
> 
> Indeed ;-)

Yes, I'm really wishing we did this 11 years ago :)
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2 2/3] mailsplit: support unescaping mboxrd messages

2016-06-06 Thread Junio C Hamano
Eric Wong  writes:

> This will allow us to parse the output of --pretty=mboxrd
> and the output of other mboxrd generators.
>
> Signed-off-by: Eric Wong 
> ---
>  Documentation/git-mailsplit.txt |  7 ++-
>  builtin/mailsplit.c | 18 ++
>  t/t5100-mailinfo.sh | 31 +++
>  t/t5100/0001mboxrd  |  4 
>  t/t5100/0002mboxrd  |  5 +
>  t/t5100/sample.mboxrd   | 19 +++
>  6 files changed, 83 insertions(+), 1 deletion(-)
>  create mode 100644 t/t5100/0001mboxrd
>  create mode 100644 t/t5100/0002mboxrd
>  create mode 100644 t/t5100/sample.mboxrd
>
> diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt
> index 4d1b871..e3b2a88 100644
> --- a/Documentation/git-mailsplit.txt
> +++ b/Documentation/git-mailsplit.txt
> @@ -8,7 +8,8 @@ git-mailsplit - Simple UNIX mbox splitter program
>  SYNOPSIS
>  
>  [verse]
> -'git mailsplit' [-b] [-f] [-d] [--keep-cr] -o [--] 
> [(|)...]
> +'git mailsplit' [-b] [-f] [-d] [--keep-cr] [--mboxrd]
> + -o [--] [(|)...]
>  
>  DESCRIPTION
>  ---
> @@ -47,6 +48,10 @@ OPTIONS
>  --keep-cr::
>   Do not remove `\r` from lines ending with `\r\n`.
>  
> +--mboxrd::
> + Input is of the "mboxrd" format and "^>+From " line escaping is
> + reversed.

This just makes me wonder if there is a practical reason why people
would not want this always enabled.  I just looked at output from

$ git log --grep='>>*From '

in the kernel repository, and I saw no cases where the committer
really wanted to preserve the leading one or more '>' on that line.
No, I didn't go through all of 150+ such commits, but I did check
the couple dozen of them from the recent history.

Our history also have 5 instances of them, none of which should have
had the leading '>' if the committer were careful.

> diff --git a/t/t5100/sample.mboxrd b/t/t5100/sample.mboxrd
> new file mode 100644
> index 000..79ad5ae
> --- /dev/null
> +++ b/t/t5100/sample.mboxrd
> @@ -0,0 +1,19 @@
> +From mboxrd Mon Sep 17 00:00:00 2001
> +From: mboxrd writer 
> +Date: Fri, 9 Jun 2006 00:44:16 -0700
> +Subject: [PATCH] a commit with escaped From lines
> +
> +>From the beginning, mbox should have been mboxrd

Indeed ;-)
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 2/3] mailsplit: support unescaping mboxrd messages

2016-06-04 Thread Eric Wong
This will allow us to parse the output of --pretty=mboxrd
and the output of other mboxrd generators.

Signed-off-by: Eric Wong 
---
 Documentation/git-mailsplit.txt |  7 ++-
 builtin/mailsplit.c | 18 ++
 t/t5100-mailinfo.sh | 31 +++
 t/t5100/0001mboxrd  |  4 
 t/t5100/0002mboxrd  |  5 +
 t/t5100/sample.mboxrd   | 19 +++
 6 files changed, 83 insertions(+), 1 deletion(-)
 create mode 100644 t/t5100/0001mboxrd
 create mode 100644 t/t5100/0002mboxrd
 create mode 100644 t/t5100/sample.mboxrd

diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt
index 4d1b871..e3b2a88 100644
--- a/Documentation/git-mailsplit.txt
+++ b/Documentation/git-mailsplit.txt
@@ -8,7 +8,8 @@ git-mailsplit - Simple UNIX mbox splitter program
 SYNOPSIS
 
 [verse]
-'git mailsplit' [-b] [-f] [-d] [--keep-cr] -o [--] 
[(|)...]
+'git mailsplit' [-b] [-f] [-d] [--keep-cr] [--mboxrd]
+   -o [--] [(|)...]
 
 DESCRIPTION
 ---
@@ -47,6 +48,10 @@ OPTIONS
 --keep-cr::
Do not remove `\r` from lines ending with `\r\n`.
 
+--mboxrd::
+   Input is of the "mboxrd" format and "^>+From " line escaping is
+   reversed.
+
 GIT
 ---
 Part of the linkgit:git[1] suite
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 4859ede..3068168 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -45,6 +45,19 @@ static int is_from_line(const char *line, int len)
 
 static struct strbuf buf = STRBUF_INIT;
 static int keep_cr;
+static int mboxrd;
+
+static int is_gtfrom(const struct strbuf *buf)
+{
+   size_t min = strlen(">From ");
+   size_t ngt;
+
+   if (buf->len < min)
+   return 0;
+
+   ngt = strspn(buf->buf, ">");
+   return ngt && starts_with(buf->buf + ngt, "From ");
+}
 
 /* Called with the first line (potentially partial)
  * already in buf[] -- normally that should begin with
@@ -77,6 +90,9 @@ static int split_one(FILE *mbox, const char *name, int 
allow_bare)
strbuf_addch(&buf, '\n');
}
 
+   if (mboxrd && is_gtfrom(&buf))
+   strbuf_remove(&buf, 0, 1);
+
if (fwrite(buf.buf, 1, buf.len, output) != buf.len)
die_errno("cannot write output");
 
@@ -271,6 +287,8 @@ int cmd_mailsplit(int argc, const char **argv, const char 
*prefix)
keep_cr = 1;
} else if ( arg[1] == 'o' && arg[2] ) {
dir = arg+2;
+   } else if (!strcmp(arg, "--mboxrd")) {
+   mboxrd = 1;
} else if ( arg[1] == '-' && !arg[2] ) {
argp++; /* -- marks end of options */
break;
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index 85b3df5..1a5a546 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -111,4 +111,35 @@ test_expect_success 'mailinfo on message with quoted 
>From' '
test_cmp "$TEST_DIRECTORY"/t5100/quoted-from.expect quoted-from/msg
 '
 
+test_expect_success 'mailinfo unescapes with --mboxrd' '
+   mkdir mboxrd &&
+   git mailsplit -omboxrd --mboxrd \
+   "$TEST_DIRECTORY"/t5100/sample.mboxrd >last &&
+   test x"$(cat last)" = x2 &&
+   for i in 0001 0002
+   do
+   git mailinfo mboxrd/msg mboxrd/patch \
+ mboxrd/out &&
+   test_cmp "$TEST_DIRECTORY"/t5100/${i}mboxrd mboxrd/msg
+   done &&
+   sp=" " &&
+   echo "From " >expect &&
+   echo "From " >>expect &&
+   echo >> expect &&
+   cat >sp <<-INPUT_END &&
+   From mboxrd Mon Sep 17 00:00:00 2001
+   From: trailing spacer 
+   Subject: [PATCH] a commit with trailing space
+
+   From$sp
+   >From$sp
+
+   INPUT_END
+
+   git mailsplit -f2 -omboxrd --mboxrd last &&
+   test x"$(cat last)" = x1 &&
+   git mailinfo mboxrd/msg mboxrd/patch From escaped
+From not mangled but this line should have been escaped
+
diff --git a/t/t5100/0002mboxrd b/t/t5100/0002mboxrd
new file mode 100644
index 000..71343d4
--- /dev/null
+++ b/t/t5100/0002mboxrd
@@ -0,0 +1,5 @@
+ >From unchanged
+ From also unchanged
+no trailing space, no escaping necessary and '>' was intended:
+>From
+
diff --git a/t/t5100/sample.mboxrd b/t/t5100/sample.mboxrd
new file mode 100644
index 000..79ad5ae
--- /dev/null
+++ b/t/t5100/sample.mboxrd
@@ -0,0 +1,19 @@
+From mbo

[PATCH 2/3] mailsplit: support unescaping mboxrd messages

2016-05-30 Thread Eric Wong
This will allow us to parse the output of --pretty=mboxrd
and the output of other mboxrd generators.

Signed-off-by: Eric Wong 
---
 Documentation/git-mailsplit.txt |  7 ++-
 builtin/mailsplit.c | 23 +++
 t/t5100-mailinfo.sh | 13 +
 t/t5100/0001mboxrd  |  4 
 t/t5100/0002mboxrd  |  3 +++
 t/t5100/sample.mboxrd   | 17 +
 6 files changed, 66 insertions(+), 1 deletion(-)
 create mode 100644 t/t5100/0001mboxrd
 create mode 100644 t/t5100/0002mboxrd
 create mode 100644 t/t5100/sample.mboxrd

diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt
index 4d1b871..e3b2a88 100644
--- a/Documentation/git-mailsplit.txt
+++ b/Documentation/git-mailsplit.txt
@@ -8,7 +8,8 @@ git-mailsplit - Simple UNIX mbox splitter program
 SYNOPSIS
 
 [verse]
-'git mailsplit' [-b] [-f] [-d] [--keep-cr] -o [--] 
[(|)...]
+'git mailsplit' [-b] [-f] [-d] [--keep-cr] [--mboxrd]
+   -o [--] [(|)...]
 
 DESCRIPTION
 ---
@@ -47,6 +48,10 @@ OPTIONS
 --keep-cr::
Do not remove `\r` from lines ending with `\r\n`.
 
+--mboxrd::
+   Input is of the "mboxrd" format and "^>+From " line escaping is
+   reversed.
+
 GIT
 ---
 Part of the linkgit:git[1] suite
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 4859ede..fad871d 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -45,6 +45,7 @@ static int is_from_line(const char *line, int len)
 
 static struct strbuf buf = STRBUF_INIT;
 static int keep_cr;
+static regex_t *gtfrom;
 
 /* Called with the first line (potentially partial)
  * already in buf[] -- normally that should begin with
@@ -77,6 +78,10 @@ static int split_one(FILE *mbox, const char *name, int 
allow_bare)
strbuf_addch(&buf, '\n');
}
 
+   if (gtfrom && buf.len > (sizeof(">From ") - 1) &&
+   !regexec(gtfrom, buf.buf, 0, 0, 0))
+   strbuf_remove(&buf, 0, 1);
+
if (fwrite(buf.buf, 1, buf.len, output) != buf.len)
die_errno("cannot write output");
 
@@ -242,6 +247,22 @@ out:
return ret;
 }
 
+static regex_t *gtfrom_prepare(void)
+{
+   static regex_t preg;
+   const char re[] = "^>+From ";
+   int err = regcomp(&preg, re, REG_NOSUB | REG_EXTENDED);
+
+   if (err) {
+   char errbuf[1024];
+   regerror(err, &preg, errbuf, sizeof(errbuf));
+   regfree(&preg);
+   die("Cannot prepare regexp `%s': %s", re, errbuf);
+   }
+
+   return &preg;
+}
+
 int cmd_mailsplit(int argc, const char **argv, const char *prefix)
 {
int nr = 0, nr_prec = 4, num = 0;
@@ -271,6 +292,8 @@ int cmd_mailsplit(int argc, const char **argv, const char 
*prefix)
keep_cr = 1;
} else if ( arg[1] == 'o' && arg[2] ) {
dir = arg+2;
+   } else if (!strcmp(arg, "--mboxrd")) {
+   gtfrom = gtfrom_prepare();
} else if ( arg[1] == '-' && !arg[2] ) {
argp++; /* -- marks end of options */
break;
diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh
index 85b3df5..62b442c 100755
--- a/t/t5100-mailinfo.sh
+++ b/t/t5100-mailinfo.sh
@@ -111,4 +111,17 @@ test_expect_success 'mailinfo on message with quoted 
>From' '
test_cmp "$TEST_DIRECTORY"/t5100/quoted-from.expect quoted-from/msg
 '
 
+test_expect_success 'mailinfo unescapes with --mboxrd' '
+   mkdir mboxrd &&
+   git mailsplit -omboxrd --mboxrd \
+   "$TEST_DIRECTORY"/t5100/sample.mboxrd >last &&
+   test x"$(cat last)" = x2 &&
+   for i in 0001 0002
+   do
+   git mailinfo mboxrd/msg mboxrd/patch \
+ mboxrd/out &&
+   test_cmp "$TEST_DIRECTORY"/t5100/${i}mboxrd mboxrd/msg
+   done
+'
+
 test_done
diff --git a/t/t5100/0001mboxrd b/t/t5100/0001mboxrd
new file mode 100644
index 000..494ec55
--- /dev/null
+++ b/t/t5100/0001mboxrd
@@ -0,0 +1,4 @@
+From the beginning, mbox should have been mboxrd
+>From escaped
+From not mangled but this line should have been escaped
+
diff --git a/t/t5100/0002mboxrd b/t/t5100/0002mboxrd
new file mode 100644
index 000..3c30b0b
--- /dev/null
+++ b/t/t5100/0002mboxrd
@@ -0,0 +1,3 @@
+ >From unchanged
+ From also unchanged
+
diff --git a/t/t5100/sample.mboxrd b/t/t5100/sample.mboxrd
new file mode 100644
index 000..75de6dd
--- /dev/null
+++ b/t/t5100/sample.mboxrd
@@ -0,0 +1,17 @@
+From mboxrd Mon Sep 17 00:00:00 2001
+From: 

[PATCH 10/68] mailsplit: make PATH_MAX buffers dynamic

2015-09-24 Thread Jeff King
There are several PATH_MAX-sized buffers in mailsplit, along
with some questionable uses of sprintf.  These are not
really of security interest, as local mailsplit pathnames
are not typically under control of an attacker, and you
could generally only overflow a few numbers at the end of a
path that approaches PATH_MAX (a longer path would choke
mailsplit long before). But it does not hurt to be careful,
and as a bonus we lift some limits for systems with
too-small PATH_MAX varibles.

Signed-off-by: Jeff King 
---
 builtin/mailsplit.c | 34 +++---
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 9de06e3..104277a 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -98,30 +98,37 @@ static int populate_maildir_list(struct string_list *list, 
const char *path)
 {
DIR *dir;
struct dirent *dent;
-   char name[PATH_MAX];
+   char *name = NULL;
char *subs[] = { "cur", "new", NULL };
char **sub;
+   int ret = -1;
 
for (sub = subs; *sub; ++sub) {
-   snprintf(name, sizeof(name), "%s/%s", path, *sub);
+   free(name);
+   name = xstrfmt("%s/%s", path, *sub);
if ((dir = opendir(name)) == NULL) {
if (errno == ENOENT)
continue;
error("cannot opendir %s (%s)", name, strerror(errno));
-   return -1;
+   goto out;
}
 
while ((dent = readdir(dir)) != NULL) {
if (dent->d_name[0] == '.')
continue;
-   snprintf(name, sizeof(name), "%s/%s", *sub, 
dent->d_name);
+   free(name);
+   name = xstrfmt("%s/%s", *sub, dent->d_name);
string_list_insert(list, name);
}
 
closedir(dir);
}
 
-   return 0;
+   ret = 0;
+
+out:
+   free(name);
+   return ret;
 }
 
 static int maildir_filename_cmp(const char *a, const char *b)
@@ -148,8 +155,7 @@ static int maildir_filename_cmp(const char *a, const char 
*b)
 static int split_maildir(const char *maildir, const char *dir,
int nr_prec, int skip)
 {
-   char file[PATH_MAX];
-   char name[PATH_MAX];
+   char *file = NULL;
FILE *f = NULL;
int ret = -1;
int i;
@@ -161,7 +167,11 @@ static int split_maildir(const char *maildir, const char 
*dir,
goto out;
 
for (i = 0; i < list.nr; i++) {
-   snprintf(file, sizeof(file), "%s/%s", maildir, 
list.items[i].string);
+   char *name;
+
+   free(file);
+   file = xstrfmt("%s/%s", maildir, list.items[i].string);
+
f = fopen(file, "r");
if (!f) {
error("cannot open mail %s (%s)", file, 
strerror(errno));
@@ -173,8 +183,9 @@ static int split_maildir(const char *maildir, const char 
*dir,
goto out;
}
 
-   sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+   name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
split_one(f, name, 1);
+   free(name);
 
fclose(f);
f = NULL;
@@ -184,6 +195,7 @@ static int split_maildir(const char *maildir, const char 
*dir,
 out:
if (f)
fclose(f);
+   free(file);
string_list_clear(&list, 1);
return ret;
 }
@@ -191,7 +203,6 @@ out:
 static int split_mbox(const char *file, const char *dir, int allow_bare,
  int nr_prec, int skip)
 {
-   char name[PATH_MAX];
int ret = -1;
int peek;
 
@@ -218,8 +229,9 @@ static int split_mbox(const char *file, const char *dir, 
int allow_bare,
}
 
while (!file_done) {
-   sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+   char *name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
file_done = split_one(f, name, allow_bare);
+   free(name);
}
 
if (f != stdin)
-- 
2.6.0.rc3.454.g204ad51

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 02/68] mailsplit: fix FILE* leak in split_maildir

2015-09-24 Thread Jeff King
If we encounter an error while splitting a maildir, we exit
the function early, leaking the open filehandle. This isn't
a big deal, since we exit the program soon after, but it's
easy enough to be careful.

Signed-off-by: Jeff King 
---
 builtin/mailsplit.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 8e02ea1..9de06e3 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -150,6 +150,7 @@ static int split_maildir(const char *maildir, const char 
*dir,
 {
char file[PATH_MAX];
char name[PATH_MAX];
+   FILE *f = NULL;
int ret = -1;
int i;
struct string_list list = STRING_LIST_INIT_DUP;
@@ -160,7 +161,6 @@ static int split_maildir(const char *maildir, const char 
*dir,
goto out;
 
for (i = 0; i < list.nr; i++) {
-   FILE *f;
snprintf(file, sizeof(file), "%s/%s", maildir, 
list.items[i].string);
f = fopen(file, "r");
if (!f) {
@@ -177,10 +177,13 @@ static int split_maildir(const char *maildir, const char 
*dir,
split_one(f, name, 1);
 
fclose(f);
+   f = NULL;
}
 
ret = skip;
 out:
+   if (f)
+   fclose(f);
string_list_clear(&list, 1);
return ret;
 }
-- 
2.6.0.rc3.454.g204ad51

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 10/67] mailsplit: make PATH_MAX buffers dynamic

2015-09-16 Thread Jeff King
On Wed, Sep 16, 2015 at 11:13:37AM -0700, Junio C Hamano wrote:

> Jeff King  writes:
> 
> > +   free(file);
> > +   file = xstrfmt("%s/%s", maildir, list.items[i].string);
> 
> Repeated pattern makes one wonder if a thin wrapper
> 
>   xstrfmt_to(&file, "%s/%s", maildir, list.items[i].string);
> 
> that first frees the existing value and then overwrites is an
> overall win.  Perhaps not, as you would (1) initialize the variable
> to NULL before doing a series of xstrfmt_to(), and (2) free the final
> one yourself.

Yeah, exactly. If you want to wrap it up in something that understands
invariants, I think strbuf is the way to go. I dunno. Maybe I should
just have done this whole thing with strbufs.

-Peff
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 10/67] mailsplit: make PATH_MAX buffers dynamic

2015-09-16 Thread Junio C Hamano
Jeff King  writes:

> + free(file);
> + file = xstrfmt("%s/%s", maildir, list.items[i].string);

Repeated pattern makes one wonder if a thin wrapper

xstrfmt_to(&file, "%s/%s", maildir, list.items[i].string);

that first frees the existing value and then overwrites is an
overall win.  Perhaps not, as you would (1) initialize the variable
to NULL before doing a series of xstrfmt_to(), and (2) free the final
one yourself.

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 10/67] mailsplit: make PATH_MAX buffers dynamic

2015-09-16 Thread Jeff King
On Wed, Sep 16, 2015 at 06:14:18AM -0400, Jeff King wrote:

> I guess we could get away with always calling free() right before
> assigning (the equivalent of strbuf_reset()), and then rely on exiting
> the loop to "out" to do the final free. And then the result (versus the
> original code, not my patch) would look like:

And here is the whole patch converted to that style. I'm planning to go
with this, as the resulting diff is much smaller and much more clear
that we are touching only the allocations.

I _hope_ the result is pretty easy to understand. There is some subtlety
to the loop assumptions:

 - on entering, the pointer is NULL or an allocated buffer to be
   recycled; either way, free() is OK

 - on leaving, the pointer is either NULL (if we never ran the loop) or
   a buffer to be freed. The free() at the end is necessary to handle
   this.

That is not too complicated, but it is not an idiom we use elsewhere
(whereas recycled strbufs are). I can switch the whole thing to strbufs
if that's the direction we want to go.

-- >8 --
Subject: [PATCH] mailsplit: make PATH_MAX buffers dynamic

There are several static PATH_MAX-sized buffers in
mailsplit, along with some questionable uses of sprintf.
These are not really of security interest, as local
mailsplit pathnames are not typically under control of an
attacker, and you could generally only overflow a few
numbers at the end of a path that approaches PATH_MAX (a
longer path would choke mailsplit long before). But it does
not hurt to be careful, and as a bonus we lift some limits
for systems with too-small PATH_MAX varibles.

Signed-off-by: Jeff King 
---
 builtin/mailsplit.c | 34 +++---
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 9de06e3..104277a 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -98,30 +98,37 @@ static int populate_maildir_list(struct string_list *list, 
const char *path)
 {
DIR *dir;
struct dirent *dent;
-   char name[PATH_MAX];
+   char *name = NULL;
char *subs[] = { "cur", "new", NULL };
char **sub;
+   int ret = -1;
 
for (sub = subs; *sub; ++sub) {
-   snprintf(name, sizeof(name), "%s/%s", path, *sub);
+   free(name);
+   name = xstrfmt("%s/%s", path, *sub);
if ((dir = opendir(name)) == NULL) {
if (errno == ENOENT)
continue;
error("cannot opendir %s (%s)", name, strerror(errno));
-   return -1;
+   goto out;
}
 
while ((dent = readdir(dir)) != NULL) {
if (dent->d_name[0] == '.')
continue;
-   snprintf(name, sizeof(name), "%s/%s", *sub, 
dent->d_name);
+   free(name);
+   name = xstrfmt("%s/%s", *sub, dent->d_name);
string_list_insert(list, name);
}
 
closedir(dir);
}
 
-   return 0;
+   ret = 0;
+
+out:
+   free(name);
+   return ret;
 }
 
 static int maildir_filename_cmp(const char *a, const char *b)
@@ -148,8 +155,7 @@ static int maildir_filename_cmp(const char *a, const char 
*b)
 static int split_maildir(const char *maildir, const char *dir,
int nr_prec, int skip)
 {
-   char file[PATH_MAX];
-   char name[PATH_MAX];
+   char *file = NULL;
FILE *f = NULL;
int ret = -1;
int i;
@@ -161,7 +167,11 @@ static int split_maildir(const char *maildir, const char 
*dir,
goto out;
 
for (i = 0; i < list.nr; i++) {
-   snprintf(file, sizeof(file), "%s/%s", maildir, 
list.items[i].string);
+   char *name;
+
+   free(file);
+   file = xstrfmt("%s/%s", maildir, list.items[i].string);
+
f = fopen(file, "r");
if (!f) {
error("cannot open mail %s (%s)", file, 
strerror(errno));
@@ -173,8 +183,9 @@ static int split_maildir(const char *maildir, const char 
*dir,
goto out;
}
 
-   sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+   name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
split_one(f, name, 1);
+   free(name);
 
fclose(f);
f = NULL;
@@ -184,6 +195,7 @@ static int split_maildir(const char *maildir, const char 
*dir,
 out:
if (f)
fclose(f);
+   free(file);
string_list_clear(&list, 1);
return ret;
 }
@@ -191,7 +203,6 @@ out:
 static int split_mbox(const char *file, co

Re: [PATCH 10/67] mailsplit: make PATH_MAX buffers dynamic

2015-09-16 Thread Jeff King
On Tue, Sep 15, 2015 at 08:51:26PM -0400, Eric Sunshine wrote:

> > if (strbuf_getwholeline(&buf, f, '\n')) {
> > -   error("cannot read mail %s (%s)", file, 
> > strerror(errno));
> > +   error("cannot read mail %s (%s)", file.buf, 
> > strerror(errno));
> > goto out;
> > }
> >
> > -   sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
> > +   name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
> > split_one(f, name, 1);
> > +   free(name);
> 
> Hmm, why does 'file' become a strbuf which is re-used each time
> through the loop, but 'name' is treated differently and gets
> re-allocated upon each iteration? Why doesn't 'name' deserve the same
> treatment as 'file'?

My thinking was rather the other way around: why doesn't "file" get the
same treatment as "name"?

I generally prefer xstrfmt to strbufs in these patches for two reasons:

  1. The result has fewer lines.

  2. The variable switches from an array to a pointer, so accessing it
 doesn't change. Whereas with a strbuf, you have to s/foo/foo.buf/
 wherever it is accessed.

We can do that easily with "name"; we allocate it, use it, and free it.
But the lifetime of "file" crosses the "goto out" boundaries, and so
it's simplest to clean it up in the "out" section. Doing that correctly
with a bare pointer is tricky (you have to re-NULL it every time you
free the old value), whereas the strbuf's invariants make it trivial.

I guess we could get away with always calling free() right before
assigning (the equivalent of strbuf_reset()), and then rely on exiting
the loop to "out" to do the final free. And then the result (versus the
original code, not my patch) would look like:

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 9de06e3..a82dd0d 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -148,8 +155,7 @@ static int maildir_filename_cmp(const char *a, const char 
*b)
 static int split_maildir(const char *maildir, const char *dir,
int nr_prec, int skip)
 {
-   char file[PATH_MAX];
-   char name[PATH_MAX];
+   char *file = NULL;
FILE *f = NULL;
int ret = -1;
int i;
@@ -161,7 +167,11 @@ static int split_maildir(const char *maildir, const char 
*dir,
goto out;
 
for (i = 0; i < list.nr; i++) {
-   snprintf(file, sizeof(file), "%s/%s", maildir, 
list.items[i].string);
+   char *name;
+
+   free(file);
+   file = xstrfmt("%s/%s", maildir, list.items[i].string);
+
f = fopen(file, "r");
if (!f) {
error("cannot open mail %s (%s)", file, 
strerror(errno));
@@ -173,8 +183,9 @@ static int split_maildir(const char *maildir, const char 
*dir,
goto out;
}
 
-   sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+   name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
split_one(f, name, 1);
+   free(name);
 
fclose(f);
f = NULL;
@@ -184,6 +195,7 @@ static int split_maildir(const char *maildir, const char 
*dir,
 out:
if (f)
fclose(f);
+   free(file);
string_list_clear(&list, 1);
return ret;
 }

which is not so bad.

Of course this is more allocations per loop than using a strbuf. I doubt
it matters in practice (we are about to fopen() and read into a strbuf,
after all!), but we could also follow the opposite direction and use
strbufs for both.

-Peff
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 10/67] mailsplit: make PATH_MAX buffers dynamic

2015-09-15 Thread Eric Sunshine
On Tue, Sep 15, 2015 at 11:28 AM, Jeff King  wrote:
> There are several static PATH_MAX-sized buffers in
> mailsplit, along with some questionable uses of sprintf.
> These are not really of security interest, as local
> mailsplit pathnames are not typically under control of an
> attacker.  But it does not hurt to be careful, and as a
> bonus we lift some limits for systems with too-small
> PATH_MAX varibles.
>
> Signed-off-by: Jeff King 
> ---
> diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
> index 9de06e3..fb0bc08 100644
> --- a/builtin/mailsplit.c
> +++ b/builtin/mailsplit.c
> @@ -148,8 +155,7 @@ static int maildir_filename_cmp(const char *a, const char 
> *b)
>  static int split_maildir(const char *maildir, const char *dir,
> int nr_prec, int skip)
>  {
> -   char file[PATH_MAX];
> -   char name[PATH_MAX];
> +   struct strbuf file = STRBUF_INIT;
> FILE *f = NULL;
> int ret = -1;
> int i;
> @@ -161,20 +167,25 @@ static int split_maildir(const char *maildir, const 
> char *dir,
> goto out;
>
> for (i = 0; i < list.nr; i++) {
> -   snprintf(file, sizeof(file), "%s/%s", maildir, 
> list.items[i].string);
> -   f = fopen(file, "r");
> +   char *name;
> +
> +   strbuf_reset(&file);
> +   strbuf_addf(&file, "%s/%s", maildir, list.items[i].string);
> +
> +   f = fopen(file.buf, "r");
> if (!f) {
> -   error("cannot open mail %s (%s)", file, 
> strerror(errno));
> +   error("cannot open mail %s (%s)", file.buf, 
> strerror(errno));
> goto out;
> }
>
> if (strbuf_getwholeline(&buf, f, '\n')) {
> -   error("cannot read mail %s (%s)", file, 
> strerror(errno));
> +   error("cannot read mail %s (%s)", file.buf, 
> strerror(errno));
> goto out;
> }
>
> -   sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
> +   name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
> split_one(f, name, 1);
> +   free(name);

Hmm, why does 'file' become a strbuf which is re-used each time
through the loop, but 'name' is treated differently and gets
re-allocated upon each iteration? Why doesn't 'name' deserve the same
treatment as 'file'?

> fclose(f);
> f = NULL;
> @@ -184,6 +195,7 @@ static int split_maildir(const char *maildir, const char 
> *dir,
>  out:
> if (f)
> fclose(f);
> +   strbuf_release(&file);
> string_list_clear(&list, 1);
> return ret;
>  }
> @@ -191,7 +203,6 @@ out:
>  static int split_mbox(const char *file, const char *dir, int allow_bare,
>   int nr_prec, int skip)
>  {
> -   char name[PATH_MAX];
> int ret = -1;
> int peek;
>
> @@ -218,8 +229,9 @@ static int split_mbox(const char *file, const char *dir, 
> int allow_bare,
> }
>
> while (!file_done) {
> -   sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
> +   char *name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
> file_done = split_one(f, name, allow_bare);
> +   free(name);

Same question, pretty much: Why not make 'name' a strbuf which is
re-used in the loop? (I don't have a strong preference; I'm just
trying to understand the apparent inconsistency of treatment.)

> }
>
> if (f != stdin)
> --
> 2.6.0.rc2.408.ga2926b9
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 10/67] mailsplit: make PATH_MAX buffers dynamic

2015-09-15 Thread Jeff King
There are several static PATH_MAX-sized buffers in
mailsplit, along with some questionable uses of sprintf.
These are not really of security interest, as local
mailsplit pathnames are not typically under control of an
attacker.  But it does not hurt to be careful, and as a
bonus we lift some limits for systems with too-small
PATH_MAX varibles.

Signed-off-by: Jeff King 
---
 builtin/mailsplit.c | 46 +-
 1 file changed, 29 insertions(+), 17 deletions(-)

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 9de06e3..fb0bc08 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -98,30 +98,37 @@ static int populate_maildir_list(struct string_list *list, 
const char *path)
 {
DIR *dir;
struct dirent *dent;
-   char name[PATH_MAX];
+   struct strbuf name = STRBUF_INIT;
char *subs[] = { "cur", "new", NULL };
char **sub;
+   int ret = -1;
 
for (sub = subs; *sub; ++sub) {
-   snprintf(name, sizeof(name), "%s/%s", path, *sub);
-   if ((dir = opendir(name)) == NULL) {
+   strbuf_reset(&name);
+   strbuf_addf(&name, "%s/%s", path, *sub);
+   if ((dir = opendir(name.buf)) == NULL) {
if (errno == ENOENT)
continue;
-   error("cannot opendir %s (%s)", name, strerror(errno));
-   return -1;
+   error("cannot opendir %s (%s)", name.buf, 
strerror(errno));
+   goto out;
}
 
while ((dent = readdir(dir)) != NULL) {
if (dent->d_name[0] == '.')
continue;
-   snprintf(name, sizeof(name), "%s/%s", *sub, 
dent->d_name);
-   string_list_insert(list, name);
+   strbuf_reset(&name);
+   strbuf_addf(&name, "%s/%s", *sub, dent->d_name);
+   string_list_insert(list, name.buf);
}
 
closedir(dir);
}
 
-   return 0;
+   ret = 0;
+
+out:
+   strbuf_release(&name);
+   return ret;
 }
 
 static int maildir_filename_cmp(const char *a, const char *b)
@@ -148,8 +155,7 @@ static int maildir_filename_cmp(const char *a, const char 
*b)
 static int split_maildir(const char *maildir, const char *dir,
int nr_prec, int skip)
 {
-   char file[PATH_MAX];
-   char name[PATH_MAX];
+   struct strbuf file = STRBUF_INIT;
FILE *f = NULL;
int ret = -1;
int i;
@@ -161,20 +167,25 @@ static int split_maildir(const char *maildir, const char 
*dir,
goto out;
 
for (i = 0; i < list.nr; i++) {
-   snprintf(file, sizeof(file), "%s/%s", maildir, 
list.items[i].string);
-   f = fopen(file, "r");
+   char *name;
+
+   strbuf_reset(&file);
+   strbuf_addf(&file, "%s/%s", maildir, list.items[i].string);
+
+   f = fopen(file.buf, "r");
if (!f) {
-   error("cannot open mail %s (%s)", file, 
strerror(errno));
+   error("cannot open mail %s (%s)", file.buf, 
strerror(errno));
goto out;
}
 
if (strbuf_getwholeline(&buf, f, '\n')) {
-   error("cannot read mail %s (%s)", file, 
strerror(errno));
+   error("cannot read mail %s (%s)", file.buf, 
strerror(errno));
goto out;
}
 
-   sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+   name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
split_one(f, name, 1);
+   free(name);
 
fclose(f);
f = NULL;
@@ -184,6 +195,7 @@ static int split_maildir(const char *maildir, const char 
*dir,
 out:
if (f)
fclose(f);
+   strbuf_release(&file);
string_list_clear(&list, 1);
return ret;
 }
@@ -191,7 +203,6 @@ out:
 static int split_mbox(const char *file, const char *dir, int allow_bare,
  int nr_prec, int skip)
 {
-   char name[PATH_MAX];
int ret = -1;
int peek;
 
@@ -218,8 +229,9 @@ static int split_mbox(const char *file, const char *dir, 
int allow_bare,
}
 
while (!file_done) {
-   sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+   char *name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
file_done = split_one(f, name, allow_bare);
+   free(name);
}
 
if (f != stdin)
-- 
2.6.0.rc2.408.ga2926b9

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 02/67] mailsplit: fix FILE* leak in split_maildir

2015-09-15 Thread Jeff King
If we encounter an error while splitting a maildir, we exit
the function early, leaking the open filehandle. This isn't
a big deal, since we exit the program soon after, but it's
easy enough to be careful.

Signed-off-by: Jeff King 
---
 builtin/mailsplit.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 8e02ea1..9de06e3 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -150,6 +150,7 @@ static int split_maildir(const char *maildir, const char 
*dir,
 {
char file[PATH_MAX];
char name[PATH_MAX];
+   FILE *f = NULL;
int ret = -1;
int i;
struct string_list list = STRING_LIST_INIT_DUP;
@@ -160,7 +161,6 @@ static int split_maildir(const char *maildir, const char 
*dir,
goto out;
 
for (i = 0; i < list.nr; i++) {
-   FILE *f;
snprintf(file, sizeof(file), "%s/%s", maildir, 
list.items[i].string);
f = fopen(file, "r");
if (!f) {
@@ -177,10 +177,13 @@ static int split_maildir(const char *maildir, const char 
*dir,
split_one(f, name, 1);
 
fclose(f);
+   f = NULL;
}
 
ret = skip;
 out:
+   if (f)
+   fclose(f);
string_list_clear(&list, 1);
return ret;
 }
-- 
2.6.0.rc2.408.ga2926b9

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 05/45] builtin-am: split out mbox/maildir patches with git-mailsplit

2015-08-04 Thread Paul Tan
git-am.sh supports mbox, stgit and mercurial patches. Re-implement
support for splitting out mbox/maildirs using git-mailsplit, while also
implementing the framework required to support other patch formats in
the future.

Re-implement support for the --patch-format option (since a5a6755
(git-am foreign patch support: introduce patch_format, 2009-05-27)) to
allow the user to choose between the different patch formats.

Helped-by: Junio C Hamano 
Signed-off-by: Paul Tan 
---
 builtin/am.c | 107 +--
 1 file changed, 104 insertions(+), 3 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index ac172c4..5f3c131 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -8,6 +8,12 @@
 #include "exec_cmd.h"
 #include "parse-options.h"
 #include "dir.h"
+#include "run-command.h"
+
+enum patch_format {
+   PATCH_FORMAT_UNKNOWN = 0,
+   PATCH_FORMAT_MBOX
+};
 
 struct am_state {
/* state directory path */
@@ -16,6 +22,9 @@ struct am_state {
/* current and last patch numbers, 1-indexed */
int cur;
int last;
+
+   /* number of digits in patch filename */
+   int prec;
 };
 
 /**
@@ -28,6 +37,8 @@ static void am_state_init(struct am_state *state, const char 
*dir)
 
assert(dir);
state->dir = xstrdup(dir);
+
+   state->prec = 4;
 }
 
 /**
@@ -117,13 +128,71 @@ static void am_destroy(const struct am_state *state)
 }
 
 /**
+ * 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.
+ */
+static int split_mail_mbox(struct am_state *state, const char **paths)
+{
+   struct child_process cp = CHILD_PROCESS_INIT;
+   struct strbuf last = STRBUF_INIT;
+
+   cp.git_cmd = 1;
+   argv_array_push(&cp.args, "mailsplit");
+   argv_array_pushf(&cp.args, "-d%d", state->prec);
+   argv_array_pushf(&cp.args, "-o%s", state->dir);
+   argv_array_push(&cp.args, "-b");
+   argv_array_push(&cp.args, "--");
+   argv_array_pushv(&cp.args, paths);
+
+   if (capture_command(&cp, &last, 8))
+   return -1;
+
+   state->cur = 1;
+   state->last = strtol(last.buf, NULL, 10);
+
+   return 0;
+}
+
+/**
+ * Splits a list of files/directories into individual email patches. Each path
+ * in `paths` must be a file/directory that is formatted according to
+ * `patch_format`.
+ *
+ * Once split out, the individual email patches will be stored in the state
+ * directory, with each patch's filename being its index, padded to state->prec
+ * digits.
+ *
+ * state->cur will be set to the index of the first mail, and state->last will
+ * be set to the index of the last mail.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int split_mail(struct am_state *state, enum patch_format patch_format,
+   const char **paths)
+{
+   switch (patch_format) {
+   case PATCH_FORMAT_MBOX:
+   return split_mail_mbox(state, paths);
+   default:
+   die("BUG: invalid patch_format");
+   }
+   return -1;
+}
+
+/**
  * Setup a new am session for applying patches
  */
-static void am_setup(struct am_state *state)
+static void am_setup(struct am_state *state, enum patch_format patch_format,
+   const char **paths)
 {
if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
die_errno(_("failed to create directory '%s'"), state->dir);
 
+   if (split_mail(state, patch_format, paths) < 0) {
+   am_destroy(state);
+   die(_("Failed to split patches."));
+   }
+
/*
 * NOTE: Since the "next" and "last" files determine if an am_state
 * session is in progress, they should be written last.
@@ -159,9 +228,25 @@ static void am_run(struct am_state *state)
am_destroy(state);
 }
 
+/**
+ * parse_options() callback that validates and sets opt->value to the
+ * PATCH_FORMAT_* enum value corresponding to `arg`.
+ */
+static int parse_opt_patchformat(const struct option *opt, const char *arg, 
int unset)
+{
+   int *opt_value = opt->value;
+
+   if (!strcmp(arg, "mbox"))
+   *opt_value = PATCH_FORMAT_MBOX;
+   else
+   return error(_("Invalid value for --patch-format: %s"), arg);
+   return 0;
+}
+
 int cmd_am(int argc, const char **argv, const char *prefix)
 {
struct am_state state;
+   int patch_format = PATCH_FORMAT_UNKNOWN;
 
const char * const usage[] = {
N_("git am [options] [(|)...]"),
@@ -169,6 +254,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
};
 
struct option options[] = {

[PATCH v6 05/45] builtin-am: split out mbox/maildir patches with git-mailsplit

2015-07-19 Thread Paul Tan
git-am.sh supports mbox, stgit and mercurial patches. Re-implement
support for splitting out mbox/maildirs using git-mailsplit, while also
implementing the framework required to support other patch formats in
the future.

Re-implement support for the --patch-format option (since a5a6755
(git-am foreign patch support: introduce patch_format, 2009-05-27)) to
allow the user to choose between the different patch formats.

Helped-by: Junio C Hamano 
Signed-off-by: Paul Tan 
---
 builtin/am.c | 107 +--
 1 file changed, 104 insertions(+), 3 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index ac172c4..5f3c131 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -8,6 +8,12 @@
 #include "exec_cmd.h"
 #include "parse-options.h"
 #include "dir.h"
+#include "run-command.h"
+
+enum patch_format {
+   PATCH_FORMAT_UNKNOWN = 0,
+   PATCH_FORMAT_MBOX
+};
 
 struct am_state {
/* state directory path */
@@ -16,6 +22,9 @@ struct am_state {
/* current and last patch numbers, 1-indexed */
int cur;
int last;
+
+   /* number of digits in patch filename */
+   int prec;
 };
 
 /**
@@ -28,6 +37,8 @@ static void am_state_init(struct am_state *state, const char 
*dir)
 
assert(dir);
state->dir = xstrdup(dir);
+
+   state->prec = 4;
 }
 
 /**
@@ -117,13 +128,71 @@ static void am_destroy(const struct am_state *state)
 }
 
 /**
+ * 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.
+ */
+static int split_mail_mbox(struct am_state *state, const char **paths)
+{
+   struct child_process cp = CHILD_PROCESS_INIT;
+   struct strbuf last = STRBUF_INIT;
+
+   cp.git_cmd = 1;
+   argv_array_push(&cp.args, "mailsplit");
+   argv_array_pushf(&cp.args, "-d%d", state->prec);
+   argv_array_pushf(&cp.args, "-o%s", state->dir);
+   argv_array_push(&cp.args, "-b");
+   argv_array_push(&cp.args, "--");
+   argv_array_pushv(&cp.args, paths);
+
+   if (capture_command(&cp, &last, 8))
+   return -1;
+
+   state->cur = 1;
+   state->last = strtol(last.buf, NULL, 10);
+
+   return 0;
+}
+
+/**
+ * Splits a list of files/directories into individual email patches. Each path
+ * in `paths` must be a file/directory that is formatted according to
+ * `patch_format`.
+ *
+ * Once split out, the individual email patches will be stored in the state
+ * directory, with each patch's filename being its index, padded to state->prec
+ * digits.
+ *
+ * state->cur will be set to the index of the first mail, and state->last will
+ * be set to the index of the last mail.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int split_mail(struct am_state *state, enum patch_format patch_format,
+   const char **paths)
+{
+   switch (patch_format) {
+   case PATCH_FORMAT_MBOX:
+   return split_mail_mbox(state, paths);
+   default:
+   die("BUG: invalid patch_format");
+   }
+   return -1;
+}
+
+/**
  * Setup a new am session for applying patches
  */
-static void am_setup(struct am_state *state)
+static void am_setup(struct am_state *state, enum patch_format patch_format,
+   const char **paths)
 {
if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
die_errno(_("failed to create directory '%s'"), state->dir);
 
+   if (split_mail(state, patch_format, paths) < 0) {
+   am_destroy(state);
+   die(_("Failed to split patches."));
+   }
+
/*
 * NOTE: Since the "next" and "last" files determine if an am_state
 * session is in progress, they should be written last.
@@ -159,9 +228,25 @@ static void am_run(struct am_state *state)
am_destroy(state);
 }
 
+/**
+ * parse_options() callback that validates and sets opt->value to the
+ * PATCH_FORMAT_* enum value corresponding to `arg`.
+ */
+static int parse_opt_patchformat(const struct option *opt, const char *arg, 
int unset)
+{
+   int *opt_value = opt->value;
+
+   if (!strcmp(arg, "mbox"))
+   *opt_value = PATCH_FORMAT_MBOX;
+   else
+   return error(_("Invalid value for --patch-format: %s"), arg);
+   return 0;
+}
+
 int cmd_am(int argc, const char **argv, const char *prefix)
 {
struct am_state state;
+   int patch_format = PATCH_FORMAT_UNKNOWN;
 
const char * const usage[] = {
N_("git am [options] [(|)...]"),
@@ -169,6 +254,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
};
 
struct option options[] = {

[PATCH v5 05/44] builtin-am: split out mbox/maildir patches with git-mailsplit

2015-07-07 Thread Paul Tan
git-am.sh supports mbox, stgit and mercurial patches. Re-implement
support for splitting out mbox/maildirs using git-mailsplit, while also
implementing the framework required to support other patch formats in
the future.

Re-implement support for the --patch-format option (since a5a6755
(git-am foreign patch support: introduce patch_format, 2009-05-27)) to
allow the user to choose between the different patch formats.

Helped-by: Junio C Hamano 
Signed-off-by: Paul Tan 
---
 builtin/am.c | 107 +--
 1 file changed, 104 insertions(+), 3 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index 292f793..ae93e0e 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -8,6 +8,12 @@
 #include "exec_cmd.h"
 #include "parse-options.h"
 #include "dir.h"
+#include "run-command.h"
+
+enum patch_format {
+   PATCH_FORMAT_UNKNOWN = 0,
+   PATCH_FORMAT_MBOX
+};
 
 struct am_state {
/* state directory path */
@@ -16,6 +22,9 @@ struct am_state {
/* current and last patch numbers, 1-indexed */
int cur;
int last;
+
+   /* number of digits in patch filename */
+   int prec;
 };
 
 /**
@@ -28,6 +37,8 @@ static void am_state_init(struct am_state *state, const char 
*dir)
 
assert(dir);
state->dir = xstrdup(dir);
+
+   state->prec = 4;
 }
 
 /**
@@ -120,13 +131,71 @@ static void am_destroy(const struct am_state *state)
 }
 
 /**
+ * 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.
+ */
+static int split_mail_mbox(struct am_state *state, const char **paths)
+{
+   struct child_process cp = CHILD_PROCESS_INIT;
+   struct strbuf last = STRBUF_INIT;
+
+   cp.git_cmd = 1;
+   argv_array_push(&cp.args, "mailsplit");
+   argv_array_pushf(&cp.args, "-d%d", state->prec);
+   argv_array_pushf(&cp.args, "-o%s", state->dir);
+   argv_array_push(&cp.args, "-b");
+   argv_array_push(&cp.args, "--");
+   argv_array_pushv(&cp.args, paths);
+
+   if (capture_command(&cp, &last, 8))
+   return -1;
+
+   state->cur = 1;
+   state->last = strtol(last.buf, NULL, 10);
+
+   return 0;
+}
+
+/**
+ * Splits a list of files/directories into individual email patches. Each path
+ * in `paths` must be a file/directory that is formatted according to
+ * `patch_format`.
+ *
+ * Once split out, the individual email patches will be stored in the state
+ * directory, with each patch's filename being its index, padded to state->prec
+ * digits.
+ *
+ * state->cur will be set to the index of the first mail, and state->last will
+ * be set to the index of the last mail.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int split_mail(struct am_state *state, enum patch_format patch_format,
+   const char **paths)
+{
+   switch (patch_format) {
+   case PATCH_FORMAT_MBOX:
+   return split_mail_mbox(state, paths);
+   default:
+   die("BUG: invalid patch_format");
+   }
+   return -1;
+}
+
+/**
  * Setup a new am session for applying patches
  */
-static void am_setup(struct am_state *state)
+static void am_setup(struct am_state *state, enum patch_format patch_format,
+   const char **paths)
 {
if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
die_errno(_("failed to create directory '%s'"), state->dir);
 
+   if (split_mail(state, patch_format, paths) < 0) {
+   am_destroy(state);
+   die(_("Failed to split patches."));
+   }
+
/*
 * NOTE: Since the "next" and "last" files determine if an am_state
 * session is in progress, they should be written last.
@@ -162,9 +231,25 @@ static void am_run(struct am_state *state)
am_destroy(state);
 }
 
+/**
+ * parse_options() callback that validates and sets opt->value to the
+ * PATCH_FORMAT_* enum value corresponding to `arg`.
+ */
+static int parse_opt_patchformat(const struct option *opt, const char *arg, 
int unset)
+{
+   int *opt_value = opt->value;
+
+   if (!strcmp(arg, "mbox"))
+   *opt_value = PATCH_FORMAT_MBOX;
+   else
+   return error(_("Invalid value for --patch-format: %s"), arg);
+   return 0;
+}
+
 int cmd_am(int argc, const char **argv, const char *prefix)
 {
struct am_state state;
+   int patch_format = PATCH_FORMAT_UNKNOWN;
 
const char * const usage[] = {
N_("git am [options] [(|)...]"),
@@ -172,6 +257,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
};
 
struct option options[] = {

[PATCH v4 05/44] builtin-am: split out mbox/maildir patches with git-mailsplit

2015-06-28 Thread Paul Tan
git-am.sh supports mbox, stgit and mercurial patches. Re-implement
support for splitting out mbox/maildirs using git-mailsplit, while also
implementing the framework required to support other patch formats in
the future.

Re-implement support for the --patch-format option (since a5a6755
(git-am foreign patch support: introduce patch_format, 2009-05-27)) to
allow the user to choose between the different patch formats.

Helped-by: Junio C Hamano 
Signed-off-by: Paul Tan 
---

Notes:
v4

* The term "patch" was overloaded to mean "the RFC2822 mail" and the
  "patch diff". To avoid confusion, use "mail" to refer to the RFC2822
  mail, and thus split_patches() has been renamed to split_mail().

* An argv_array is used for `paths` instead of a string_list to avoid
  clunkiness with string_list_item in later patches.

 builtin/am.c | 107 +--
 1 file changed, 104 insertions(+), 3 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index 5b4e9af..136ccc6 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -8,6 +8,12 @@
 #include "exec_cmd.h"
 #include "parse-options.h"
 #include "dir.h"
+#include "run-command.h"
+
+enum patch_format {
+   PATCH_FORMAT_UNKNOWN = 0,
+   PATCH_FORMAT_MBOX
+};
 
 struct am_state {
/* state directory path */
@@ -16,6 +22,9 @@ struct am_state {
/* current and last patch numbers, 1-indexed */
int cur;
int last;
+
+   /* number of digits in patch filename */
+   int prec;
 };
 
 /**
@@ -28,6 +37,8 @@ static void am_state_init(struct am_state *state, const char 
*dir)
 
assert(dir);
state->dir = xstrdup(dir);
+
+   state->prec = 4;
 }
 
 /**
@@ -120,13 +131,71 @@ static void am_destroy(const struct am_state *state)
 }
 
 /**
+ * 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.
+ */
+static int split_mail_mbox(struct am_state *state, const char **paths)
+{
+   struct child_process cp = CHILD_PROCESS_INIT;
+   struct strbuf last = STRBUF_INIT;
+
+   cp.git_cmd = 1;
+   argv_array_push(&cp.args, "mailsplit");
+   argv_array_pushf(&cp.args, "-d%d", state->prec);
+   argv_array_pushf(&cp.args, "-o%s", state->dir);
+   argv_array_push(&cp.args, "-b");
+   argv_array_push(&cp.args, "--");
+   argv_array_pushv(&cp.args, paths);
+
+   if (capture_command(&cp, &last, 8))
+   return -1;
+
+   state->cur = 1;
+   state->last = strtol(last.buf, NULL, 10);
+
+   return 0;
+}
+
+/**
+ * Splits a list of files/directories into individual email patches. Each path
+ * in `paths` must be a file/directory that is formatted according to
+ * `patch_format`.
+ *
+ * Once split out, the individual email patches will be stored in the state
+ * directory, with each patch's filename being its index, padded to state->prec
+ * digits.
+ *
+ * state->cur will be set to the index of the first mail, and state->last will
+ * be set to the index of the last mail.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int split_mail(struct am_state *state, enum patch_format patch_format,
+   const char **paths)
+{
+   switch (patch_format) {
+   case PATCH_FORMAT_MBOX:
+   return split_mail_mbox(state, paths);
+   default:
+   die("BUG: invalid patch_format");
+   }
+   return -1;
+}
+
+/**
  * Setup a new am session for applying patches
  */
-static void am_setup(struct am_state *state)
+static void am_setup(struct am_state *state, enum patch_format patch_format,
+   const char **paths)
 {
if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
die_errno(_("failed to create directory '%s'"), state->dir);
 
+   if (split_mail(state, patch_format, paths) < 0) {
+   am_destroy(state);
+   die(_("Failed to split patches."));
+   }
+
/*
 * NOTE: Since the "next" and "last" files determine if an am_state
 * session is in progress, they should be written last.
@@ -162,9 +231,25 @@ static void am_run(struct am_state *state)
am_destroy(state);
 }
 
+/**
+ * parse_options() callback that validates and sets opt->value to the
+ * PATCH_FORMAT_* enum value corresponding to `arg`.
+ */
+static int parse_opt_patchformat(const struct option *opt, const char *arg, 
int unset)
+{
+   int *opt_value = opt->value;
+
+   if (!strcmp(arg, "mbox"))
+   *opt_value = PATCH_FORMAT_MBOX;
+   else
+   return error(_("Invalid value for --patch-forma

Re: [PATCH/WIP v3 05/31] am: split out mbox/maildir patches with git-mailsplit

2015-06-18 Thread Junio C Hamano
Paul Tan  writes:

> @@ -111,13 +122,69 @@ static void am_destroy(const struct am_state *state)
>  }
>  
>  /**
> + * Splits out individual patches from `paths`, where each path is either a 
> mbox
> + * file or a Maildir. Return 0 on success, -1 on failure.
> + */

"Splits" and then "Return"?  Be consistent.

> +static int split_patches_mbox(struct am_state *state, struct string_list 
> *paths)
> +{
> ...
> +}

Looks straightforward ;-)

> +/**
> + * parse_options() callback that validates and sets opt->value to the
> + * PATCH_FORMAT_* enum value corresponding to `arg`.
> + */
> +static int parse_opt_patchformat(const struct option *opt, const char *arg, 
> int unset)
> +{
> + int *opt_value = opt->value;
> +
> + if (!strcmp(arg, "mbox"))
> + *opt_value = PATCH_FORMAT_MBOX;
> + else
> + return -1;
> + return 0;
> +}
> +
>  static struct am_state state;
> +static int opt_patch_format;
>  
>  static const char * const am_usage[] = {
>   N_("git am [options] [(|)...]"),
> @@ -156,6 +239,8 @@ static const char * const am_usage[] = {
>  };
>  
>  static struct option am_options[] = {
> + OPT_CALLBACK(0, "patch-format", &opt_patch_format, N_("format"),
> + N_("format the patch(es) are in"), parse_opt_patchformat),
>   OPT_END()
>  };

Looking good ;-).

Just FYI, you do not have to make am_options[], and the variables
that are referenced from there, e.g. opt_patch_format, etc., global
variables (instead you can have them all in the function scope of
cmd_am()).
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/WIP v3 05/31] am: split out mbox/maildir patches with git-mailsplit

2015-06-18 Thread Paul Tan
git-am.sh supports mbox, stgit and mercurial patches. Re-implement
support for splitting out mbox/maildirs using git-mailsplit, while also
implementing the framework required to support other patch formats in
the future.

Re-implement support for the --patch-format option (since a5a6755
(git-am foreign patch support: introduce patch_format, 2009-05-27)) to
allow the user to choose between the different patch formats.

Signed-off-by: Paul Tan 
---

Notes:
v3

* Moved the TODO comment to the previous patch

 builtin/am.c | 104 +--
 1 file changed, 101 insertions(+), 3 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index af68c51..e9a3687 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -8,6 +8,12 @@
 #include "exec_cmd.h"
 #include "parse-options.h"
 #include "dir.h"
+#include "run-command.h"
+
+enum patch_format {
+   PATCH_FORMAT_UNKNOWN = 0,
+   PATCH_FORMAT_MBOX
+};
 
 struct am_state {
/* state directory path */
@@ -16,6 +22,9 @@ struct am_state {
/* current and last patch numbers, 1-indexed */
int cur;
int last;
+
+   /* number of digits in patch filename */
+   int prec;
 };
 
 /**
@@ -26,6 +35,8 @@ static void am_state_init(struct am_state *state)
memset(state, 0, sizeof(*state));
 
strbuf_init(&state->dir, 0);
+
+   state->prec = 4;
 }
 
 /**
@@ -111,13 +122,69 @@ static void am_destroy(const struct am_state *state)
 }
 
 /**
+ * Splits out individual patches from `paths`, where each path is either a mbox
+ * file or a Maildir. Return 0 on success, -1 on failure.
+ */
+static int split_patches_mbox(struct am_state *state, struct string_list 
*paths)
+{
+   struct child_process cp = CHILD_PROCESS_INIT;
+   struct string_list_item *item;
+   struct strbuf last = STRBUF_INIT;
+
+   cp.git_cmd = 1;
+   argv_array_push(&cp.args, "mailsplit");
+   argv_array_pushf(&cp.args, "-d%d", state->prec);
+   argv_array_pushf(&cp.args, "-o%s", state->dir.buf);
+   argv_array_push(&cp.args, "-b");
+   argv_array_push(&cp.args, "--");
+
+   for_each_string_list_item(item, paths)
+   argv_array_push(&cp.args, item->string);
+
+   if (capture_command(&cp, &last, 8))
+   return -1;
+
+   state->cur = 1;
+   state->last = strtol(last.buf, NULL, 10);
+
+   return 0;
+}
+
+/**
+ * Splits out individual patches, of patch_format, contained within paths.
+ * These patches will be stored in the state directory, with each patch's
+ * filename being its index, padded to state->prec digits. state->cur will be
+ * set to the index of the first patch, and state->last will be set to the
+ * index of the last patch.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int split_patches(struct am_state *state, enum patch_format 
patch_format,
+   struct string_list *paths)
+{
+   switch (patch_format) {
+   case PATCH_FORMAT_MBOX:
+   return split_patches_mbox(state, paths);
+   default:
+   die("BUG: invalid patch_format");
+   }
+   return -1;
+}
+
+/**
  * Setup a new am session for applying patches
  */
-static void am_setup(struct am_state *state)
+static void am_setup(struct am_state *state, enum patch_format patch_format,
+   struct string_list *paths)
 {
if (mkdir(state->dir.buf, 0777) < 0 && errno != EEXIST)
die_errno(_("failed to create directory '%s'"), state->dir.buf);
 
+   if (split_patches(state, patch_format, paths) < 0) {
+   am_destroy(state);
+   die(_("Failed to split patches."));
+   }
+
write_file(am_path(state, "next"), 1, "%d", state->cur);
 
write_file(am_path(state, "last"), 1, "%d", state->last);
@@ -148,7 +215,23 @@ static void am_run(struct am_state *state)
am_destroy(state);
 }
 
+/**
+ * parse_options() callback that validates and sets opt->value to the
+ * PATCH_FORMAT_* enum value corresponding to `arg`.
+ */
+static int parse_opt_patchformat(const struct option *opt, const char *arg, 
int unset)
+{
+   int *opt_value = opt->value;
+
+   if (!strcmp(arg, "mbox"))
+   *opt_value = PATCH_FORMAT_MBOX;
+   else
+   return -1;
+   return 0;
+}
+
 static struct am_state state;
+static int opt_patch_format;
 
 static const char * const am_usage[] = {
N_("git am [options] [(|)...]"),
@@ -156,6 +239,8 @@ static const char * const am_usage[] = {
 };
 
 static struct option am_options[] = {
+   OPT_CALLBACK(0, "patch-format", &opt_patch_format, N_("format"),
+   N_

Re: [PATCH/WIP v2 05/19] am: split out mbox/maildir patches with git-mailsplit

2015-06-15 Thread Paul Tan
On Fri, Jun 12, 2015 at 1:45 AM, Stefan Beller  wrote:
> On Thu, Jun 11, 2015 at 3:21 AM, Paul Tan  wrote:
>> @@ -138,13 +202,33 @@ static void am_next(struct am_state *state)
>>   */
>>  static void am_run(struct am_state *state)
>>  {
>> -   while (state->cur <= state->last)
>> +   while (state->cur <= state->last) {
>> +
>> +   /* TODO: Patch application not implemented yet */
>> +
>> am_next(state);
>> +   }
>
> When reviewing the previous patch I did look at this loop for awhile confused,
> if you want to apply patches in am_next(state) and thought there might be
> a better approach.
>
> Maybe you want to move this chunk with the TODO into the previous patch,
> so it's clear after reading the documentation of am_run, that the actual am is
> missing there.

Ah right, this is a mistake. This comment should be in the previous patch.

Thanks,
Paul
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH/WIP v2 05/19] am: split out mbox/maildir patches with git-mailsplit

2015-06-11 Thread Stefan Beller
On Thu, Jun 11, 2015 at 3:21 AM, Paul Tan  wrote:
> git-am.sh supports mbox, stgit and mercurial patches. Re-implement
> support for splitting out mbox/maildirs using git-mailsplit, while also
> implementing the framework required to support other patch formats in
> the future.
>
> Re-implement support for the --patch-format option (since a5a6755
> (git-am foreign patch support: introduce patch_format, 2009-05-27)) to
> allow the user to choose between the different patch formats.
>
> Signed-off-by: Paul Tan 
> ---
>
> Notes:
> v2
>
> * Declare int opt_patchformat as static.
>
> * Fix up indentation style for the switch()
>
>  builtin/am.c | 107 
> ---
>  1 file changed, 103 insertions(+), 4 deletions(-)
>
> diff --git a/builtin/am.c b/builtin/am.c
> index f061d21..5198a8e 100644
> --- a/builtin/am.c
> +++ b/builtin/am.c
> @@ -8,6 +8,12 @@
>  #include "exec_cmd.h"
>  #include "parse-options.h"
>  #include "dir.h"
> +#include "run-command.h"
> +
> +enum patch_format {
> +   PATCH_FORMAT_UNKNOWN = 0,
> +   PATCH_FORMAT_MBOX
> +};
>
>  struct am_state {
> /* state directory path */
> @@ -16,6 +22,9 @@ struct am_state {
> /* current and last patch numbers, 1-indexed */
> int cur;
> int last;
> +
> +   /* number of digits in patch filename */
> +   int prec;
>  };
>
>  /**
> @@ -26,6 +35,7 @@ static void am_state_init(struct am_state *state)
> memset(state, 0, sizeof(*state));
>
> strbuf_init(&state->dir, 0);
> +   state->prec = 4;
>  }
>
>  /**
> @@ -111,13 +121,67 @@ static void am_destroy(const struct am_state *state)
>  }
>
>  /**
> + * Splits out individual patches from `paths`, where each path is either a 
> mbox
> + * file or a Maildir. Return 0 on success, -1 on failure.
> + */
> +static int split_patches_mbox(struct am_state *state, struct string_list 
> *paths)
> +{
> +   struct child_process cp = CHILD_PROCESS_INIT;
> +   struct string_list_item *item;
> +   struct strbuf last = STRBUF_INIT;
> +
> +   cp.git_cmd = 1;
> +   argv_array_push(&cp.args, "mailsplit");
> +   argv_array_pushf(&cp.args, "-d%d", state->prec);
> +   argv_array_pushf(&cp.args, "-o%s", state->dir.buf);
> +   argv_array_push(&cp.args, "-b");
> +   argv_array_push(&cp.args, "--");
> +
> +   for_each_string_list_item(item, paths)
> +   argv_array_push(&cp.args, item->string);
> +
> +   if (capture_command(&cp, &last, 8))
> +   return -1;
> +
> +   state->cur = 1;
> +   state->last = strtol(last.buf, NULL, 10);
> +
> +   return 0;
> +}
> +
> +/**
> + * Splits out individual patches, of patch_format, contained within paths.
> + * These patches will be stored in the state directory, with each patch's
> + * filename being its index, padded to state->prec digits. state->cur will be
> + * set to the index of the first patch, and state->last will be set to the
> + * index of the last patch. Returns 0 on success, -1 on failure.
> + */
> +static int split_patches(struct am_state *state, enum patch_format 
> patch_format,
> +   struct string_list *paths)
> +{
> +   switch (patch_format) {
> +   case PATCH_FORMAT_MBOX:
> +   return split_patches_mbox(state, paths);
> +   default:
> +   die("BUG: invalid patch_format");
> +   }
> +   return -1;
> +}
> +
> +/**
>   * Setup a new am session for applying patches
>   */
> -static void am_setup(struct am_state *state)
> +static void am_setup(struct am_state *state, enum patch_format patch_format,
> +   struct string_list *paths)
>  {
> if (mkdir(state->dir.buf, 0777) < 0 && errno != EEXIST)
> die_errno(_("failed to create directory '%s'"), 
> state->dir.buf);
>
> +   if (split_patches(state, patch_format, paths) < 0) {
> +   am_destroy(state);
> +   die(_("Failed to split patches."));
> +   }
> +
> write_file(am_path(state, "next"), 1, "%d", state->cur);
>
> write_file(am_path(state, "last"), 1, "%d", state->last);
> @@ -138,13 +202,33 @@ static void am_next(struct am_state *state)
>   */
>  static void am_run(struct am_state *state)
>  {
> -   while (state->cur <= state->

[PATCH/WIP v2 05/19] am: split out mbox/maildir patches with git-mailsplit

2015-06-11 Thread Paul Tan
git-am.sh supports mbox, stgit and mercurial patches. Re-implement
support for splitting out mbox/maildirs using git-mailsplit, while also
implementing the framework required to support other patch formats in
the future.

Re-implement support for the --patch-format option (since a5a6755
(git-am foreign patch support: introduce patch_format, 2009-05-27)) to
allow the user to choose between the different patch formats.

Signed-off-by: Paul Tan 
---

Notes:
v2

* Declare int opt_patchformat as static.

* Fix up indentation style for the switch()

 builtin/am.c | 107 ---
 1 file changed, 103 insertions(+), 4 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index f061d21..5198a8e 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -8,6 +8,12 @@
 #include "exec_cmd.h"
 #include "parse-options.h"
 #include "dir.h"
+#include "run-command.h"
+
+enum patch_format {
+   PATCH_FORMAT_UNKNOWN = 0,
+   PATCH_FORMAT_MBOX
+};
 
 struct am_state {
/* state directory path */
@@ -16,6 +22,9 @@ struct am_state {
/* current and last patch numbers, 1-indexed */
int cur;
int last;
+
+   /* number of digits in patch filename */
+   int prec;
 };
 
 /**
@@ -26,6 +35,7 @@ static void am_state_init(struct am_state *state)
memset(state, 0, sizeof(*state));
 
strbuf_init(&state->dir, 0);
+   state->prec = 4;
 }
 
 /**
@@ -111,13 +121,67 @@ static void am_destroy(const struct am_state *state)
 }
 
 /**
+ * Splits out individual patches from `paths`, where each path is either a mbox
+ * file or a Maildir. Return 0 on success, -1 on failure.
+ */
+static int split_patches_mbox(struct am_state *state, struct string_list 
*paths)
+{
+   struct child_process cp = CHILD_PROCESS_INIT;
+   struct string_list_item *item;
+   struct strbuf last = STRBUF_INIT;
+
+   cp.git_cmd = 1;
+   argv_array_push(&cp.args, "mailsplit");
+   argv_array_pushf(&cp.args, "-d%d", state->prec);
+   argv_array_pushf(&cp.args, "-o%s", state->dir.buf);
+   argv_array_push(&cp.args, "-b");
+   argv_array_push(&cp.args, "--");
+
+   for_each_string_list_item(item, paths)
+   argv_array_push(&cp.args, item->string);
+
+   if (capture_command(&cp, &last, 8))
+   return -1;
+
+   state->cur = 1;
+   state->last = strtol(last.buf, NULL, 10);
+
+   return 0;
+}
+
+/**
+ * Splits out individual patches, of patch_format, contained within paths.
+ * These patches will be stored in the state directory, with each patch's
+ * filename being its index, padded to state->prec digits. state->cur will be
+ * set to the index of the first patch, and state->last will be set to the
+ * index of the last patch. Returns 0 on success, -1 on failure.
+ */
+static int split_patches(struct am_state *state, enum patch_format 
patch_format,
+   struct string_list *paths)
+{
+   switch (patch_format) {
+   case PATCH_FORMAT_MBOX:
+   return split_patches_mbox(state, paths);
+   default:
+   die("BUG: invalid patch_format");
+   }
+   return -1;
+}
+
+/**
  * Setup a new am session for applying patches
  */
-static void am_setup(struct am_state *state)
+static void am_setup(struct am_state *state, enum patch_format patch_format,
+   struct string_list *paths)
 {
if (mkdir(state->dir.buf, 0777) < 0 && errno != EEXIST)
die_errno(_("failed to create directory '%s'"), state->dir.buf);
 
+   if (split_patches(state, patch_format, paths) < 0) {
+   am_destroy(state);
+   die(_("Failed to split patches."));
+   }
+
write_file(am_path(state, "next"), 1, "%d", state->cur);
 
write_file(am_path(state, "last"), 1, "%d", state->last);
@@ -138,13 +202,33 @@ static void am_next(struct am_state *state)
  */
 static void am_run(struct am_state *state)
 {
-   while (state->cur <= state->last)
+   while (state->cur <= state->last) {
+
+   /* TODO: Patch application not implemented yet */
+
am_next(state);
+   }
 
am_destroy(state);
 }
 
+/**
+ * parse_options() callback that validates and sets opt->value to the
+ * PATCH_FORMAT_* enum value corresponding to `arg`.
+ */
+static int parse_opt_patchformat(const struct option *opt, const char *arg, 
int unset)
+{
+   int *opt_value = opt->value;
+
+   if (!strcmp(arg, "mbox"))
+   *opt_value = PATCH_FORMAT_MBOX;
+   else
+   return -1;
+   return 0;
+}
+
 static struct am_state state;
+static int opt_patch_format;
 
 static 

Re: [PATCH/WIP 4/8] am: split out mbox/maildir patches with git-mailsplit

2015-06-02 Thread Paul Tan
On Fri, May 29, 2015 at 7:05 AM, Eric Sunshine  wrote:
> On Wed, May 27, 2015 at 9:33 AM, Paul Tan  wrote:
>> @@ -128,13 +190,32 @@ static void am_next(struct am_state *state)
>>   */
>> +/**
>> + * parse_options() callback that validates and sets opt->value to the
>> + * PATCH_FORMAT_* enum value corresponding to `arg`.
>> + */
>> +static int parse_opt_patchformat(const struct option *opt, const char *arg, 
>> int unset)
>> +{
>> +   int *opt_value = opt->value;
>> +
>> +   if (!strcmp(arg, "mbox"))
>> +   *opt_value = PATCH_FORMAT_MBOX;
>> +   else
>> +   return -1;
>> +   return 0;
>> +}
>> +
>>  struct am_state state;
>> +int opt_patch_format;
>
> Should these two variables be static?

Whoops. Yes, they should.

Thanks,
Paul
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH/WIP 4/8] am: split out mbox/maildir patches with git-mailsplit

2015-05-28 Thread Eric Sunshine
On Wed, May 27, 2015 at 9:33 AM, Paul Tan  wrote:
> git-am.sh supports mbox, stgit and mercurial patches. Re-implement
> support for splitting out mbox/maildirs using git-mailsplit, while also
> implementing the framework required to support other patch formats in
> the future.
>
> Re-implement support for the --patch-format option (since a5a6755
> (git-am foreign patch support: introduce patch_format, 2009-05-27)) to
> allow the user to choose between the different patch formats.
>
> Signed-off-by: Paul Tan 
> ---
> @@ -128,13 +190,32 @@ static void am_next(struct am_state *state)
>   */
> +/**
> + * parse_options() callback that validates and sets opt->value to the
> + * PATCH_FORMAT_* enum value corresponding to `arg`.
> + */
> +static int parse_opt_patchformat(const struct option *opt, const char *arg, 
> int unset)
> +{
> +   int *opt_value = opt->value;
> +
> +   if (!strcmp(arg, "mbox"))
> +   *opt_value = PATCH_FORMAT_MBOX;
> +   else
> +   return -1;
> +   return 0;
> +}
> +
>  struct am_state state;
> +int opt_patch_format;

Should these two variables be static?

>  static const char * const am_usage[] = {
> N_("git am [options] [(|)...]"),
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH/WIP 4/8] am: split out mbox/maildir patches with git-mailsplit

2015-05-27 Thread Paul Tan
git-am.sh supports mbox, stgit and mercurial patches. Re-implement
support for splitting out mbox/maildirs using git-mailsplit, while also
implementing the framework required to support other patch formats in
the future.

Re-implement support for the --patch-format option (since a5a6755
(git-am foreign patch support: introduce patch_format, 2009-05-27)) to
allow the user to choose between the different patch formats.

Signed-off-by: Paul Tan 
---
 builtin/am.c | 104 ---
 1 file changed, 100 insertions(+), 4 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index 6c9..9c7b058 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -6,11 +6,18 @@
 #include "cache.h"
 #include "parse-options.h"
 #include "dir.h"
+#include "run-command.h"
+
+enum patch_format {
+   PATCH_FORMAT_UNKNOWN = 0,
+   PATCH_FORMAT_MBOX
+};
 
 struct am_state {
struct strbuf dir;/* state directory path */
int cur;  /* current patch number */
int last; /* last patch number */
+   int prec; /* number of digits in patch filename */
 };
 
 /**
@@ -21,6 +28,7 @@ static void am_state_init(struct am_state *state)
memset(state, 0, sizeof(*state));
 
strbuf_init(&state->dir, 0);
+   state->prec = 4;
 }
 
 /**
@@ -101,13 +109,67 @@ static void am_destroy(const struct am_state *state)
 }
 
 /**
+ * Splits out individual patches from `paths`, where each path is either a mbox
+ * file or a Maildir. Return 0 on success, -1 on failure.
+ */
+static int split_patches_mbox(struct am_state *state, struct string_list 
*paths)
+{
+   struct child_process cp = CHILD_PROCESS_INIT;
+   struct string_list_item *item;
+   struct strbuf last = STRBUF_INIT;
+
+   cp.git_cmd = 1;
+   argv_array_push(&cp.args, "mailsplit");
+   argv_array_pushf(&cp.args, "-d%d", state->prec);
+   argv_array_pushf(&cp.args, "-o%s", state->dir.buf);
+   argv_array_push(&cp.args, "-b");
+   argv_array_push(&cp.args, "--");
+
+   for_each_string_list_item(item, paths)
+   argv_array_push(&cp.args, item->string);
+
+   if (capture_command(&cp, &last, 8))
+   return -1;
+
+   state->cur = 1;
+   state->last = strtol(last.buf, NULL, 10);
+
+   return 0;
+}
+
+/**
+ * Splits out individual patches, of patch_format, contained within paths.
+ * These patches will be stored in the state directory, with each patch's
+ * filename being its index, padded to state->prec digits. state->cur will be
+ * set to the index of the first patch, and state->last will be set to the
+ * index of the last patch. Returns 0 on success, -1 on failure.
+ */
+static int split_patches(struct am_state *state, enum patch_format 
patch_format,
+   struct string_list *paths)
+{
+   switch (patch_format) {
+   case PATCH_FORMAT_MBOX:
+   return split_patches_mbox(state, paths);
+   default:
+   die("BUG: invalid patch_format");
+   }
+   return -1;
+}
+
+/**
  * Setup a new am session for applying patches
  */
-static void am_setup(struct am_state *state)
+static void am_setup(struct am_state *state, enum patch_format patch_format,
+   struct string_list *paths)
 {
if (mkdir(state->dir.buf, 0777) < 0 && errno != EEXIST)
die_errno(_("failed to create directory '%s'"), state->dir.buf);
 
+   if (split_patches(state, patch_format, paths) < 0) {
+   am_destroy(state);
+   die(_("Failed to split patches."));
+   }
+
write_file(am_path(state, "next"), 1, "%d", state->cur);
 
write_file(am_path(state, "last"), 1, "%d", state->last);
@@ -128,13 +190,32 @@ static void am_next(struct am_state *state)
  */
 static void am_run(struct am_state *state)
 {
-   while (state->cur <= state->last)
+   while (state->cur <= state->last) {
+   /* patch application not implemented yet */
+
am_next(state);
+   }
 
am_destroy(state);
 }
 
+/**
+ * parse_options() callback that validates and sets opt->value to the
+ * PATCH_FORMAT_* enum value corresponding to `arg`.
+ */
+static int parse_opt_patchformat(const struct option *opt, const char *arg, 
int unset)
+{
+   int *opt_value = opt->value;
+
+   if (!strcmp(arg, "mbox"))
+   *opt_value = PATCH_FORMAT_MBOX;
+   else
+   return -1;
+   return 0;
+}
+
 struct am_state state;
+int opt_patch_format;
 
 static const char * const am_usage[] = {
N_("git am [options] [

[PATCH] mailsplit: remove unnecessary unlink(2) call

2014-10-04 Thread René Scharfe
The output file hasn't been created at this point, yet, so there is no
need to delete it when exiting early.

Suggested-by: Jeff King 
Signed-off-by: Rene Scharfe 
---
Original thread: http://thread.gmane.org/gmane.comp.version-control.git/255140

 builtin/mailsplit.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 763cda0..8e02ea1 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -59,7 +59,6 @@ static int split_one(FILE *mbox, const char *name, int 
allow_bare)
int is_bare = !is_from_line(buf.buf, buf.len);
 
if (is_bare && !allow_bare) {
-   unlink(name);
fprintf(stderr, "corrupt mailbox\n");
exit(1);
}
-- 
2.1.2
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html