Merge branch 'jc/mailinfo-scissors'

* jc/mailinfo-scissors:
  mailinfo.scissors: new configuration
  am/mailinfo: Disable scissors processing by default
  Documentation: describe the scissors mark support of "git am"
  Teach mailinfo to ignore everything before -- >8 -- mark
  builtin-mailinfo.c: fix confusing internal API to mailinfo()
maint
Junio C Hamano 2009-09-07 15:25:37 -07:00
commit b8711f520b
12 changed files with 395 additions and 27 deletions

View File

@ -13,7 +13,7 @@ SYNOPSIS
[--3way] [--interactive] [--committer-date-is-author-date]
[--ignore-date] [--ignore-space-change | --ignore-whitespace]
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
[--reject] [-q | --quiet]
[--reject] [-q | --quiet] [--scissors]
[<mbox> | <Maildir>...]
'git am' (--skip | --resolved | --abort)

@ -39,6 +39,11 @@ OPTIONS
--keep::
Pass `-k` flag to 'git-mailinfo' (see linkgit:git-mailinfo[1]).

-c::
--scissors::
Remove everything in body before a scissors line (see
linkgit:git-mailinfo[1]).

-q::
--quiet::
Be quiet. Only print error messages.
@ -128,10 +133,8 @@ the commit, after stripping common prefix "[PATCH <anything>]".
The "Subject: " line is supposed to concisely describe what the
commit is about in one line of text.

"From: " and "Subject: " lines starting the body (the rest of the
message after the blank line terminating the RFC2822 headers)
override the respective commit author name and title values taken
from the headers.
"From: " and "Subject: " lines starting the body override the respective
commit author name and title values taken from the headers.

The commit message is formed by the title taken from the
"Subject: ", a blank line and the body of the message up to

View File

@ -8,7 +8,7 @@ git-mailinfo - Extracts patch and authorship from a single e-mail message

SYNOPSIS
--------
'git mailinfo' [-k] [-u | --encoding=<encoding> | -n] <msg> <patch>
'git mailinfo' [-k] [-u | --encoding=<encoding> | -n] [--scissors] <msg> <patch>


DESCRIPTION
@ -49,6 +49,20 @@ conversion, even with this flag.
-n::
Disable all charset re-coding of the metadata.

--scissors::
Remove everything in body before a scissors line. A line that
mainly consists of scissors (either ">8" or "8<") and perforation
(dash "-") marks is called a scissors line, and is used to request
the reader to cut the message at that line. If such a line
appears in the body of the message before the patch, everything
before it (including the scissors line itself) is ignored when
this option is used.
+
This is useful if you want to begin your message in a discussion thread
with comments and suggestions on the message you are responding to, and to
conclude it with a patch submission, separating the discussion and the
beginning of the proposed commit log message with a scissors line.

<msg>::
The commit log message extracted from e-mail, usually
except the title line which comes from e-mail Subject.

View File

@ -25,6 +25,7 @@ static enum {
static struct strbuf charset = STRBUF_INIT;
static int patch_lines;
static struct strbuf **p_hdr_data, **s_hdr_data;
static int use_scissors;

#define MAX_HDR_PARSED 10
#define MAX_BOUNDARIES 5
@ -712,6 +713,56 @@ static inline int patchbreak(const struct strbuf *line)
return 0;
}

static int is_scissors_line(const struct strbuf *line)
{
size_t i, len = line->len;
int scissors = 0, gap = 0;
int first_nonblank = -1;
int last_nonblank = 0, visible, perforation = 0, in_perforation = 0;
const char *buf = line->buf;

for (i = 0; i < len; i++) {
if (isspace(buf[i])) {
if (in_perforation) {
perforation++;
gap++;
}
continue;
}
last_nonblank = i;
if (first_nonblank < 0)
first_nonblank = i;
if (buf[i] == '-') {
in_perforation = 1;
perforation++;
continue;
}
if (i + 1 < len &&
(!memcmp(buf + i, ">8", 2) || !memcmp(buf + i, "8<", 2))) {
in_perforation = 1;
perforation += 2;
scissors += 2;
i++;
continue;
}
in_perforation = 0;
}

/*
* The mark must be at least 8 bytes long (e.g. "-- >8 --").
* Even though there can be arbitrary cruft on the same line
* (e.g. "cut here"), in order to avoid misidentification, the
* perforation must occupy more than a third of the visible
* width of the line, and dashes and scissors must occupy more
* than half of the perforation.
*/

visible = last_nonblank - first_nonblank + 1;
return (scissors && 8 <= visible &&
visible < perforation * 3 &&
gap * 2 < perforation);
}

static int handle_commit_msg(struct strbuf *line)
{
static int still_looking = 1;
@ -723,7 +774,8 @@ static int handle_commit_msg(struct strbuf *line)
strbuf_ltrim(line);
if (!line->len)
return 0;
if ((still_looking = check_header(line, s_hdr_data, 0)) != 0)
still_looking = check_header(line, s_hdr_data, 0);
if (still_looking)
return 0;
}

@ -731,6 +783,24 @@ static int handle_commit_msg(struct strbuf *line)
if (metainfo_charset)
convert_to_utf8(line, charset.buf);

if (use_scissors && is_scissors_line(line)) {
int i;
rewind(cmitmsg);
ftruncate(fileno(cmitmsg), 0);
still_looking = 1;

/*
* We may have already read "secondary headers"; purge
* them to give ourselves a clean restart.
*/
for (i = 0; header[i]; i++) {
if (s_hdr_data[i])
strbuf_release(s_hdr_data[i]);
s_hdr_data[i] = NULL;
}
return 0;
}

if (patchbreak(line)) {
fclose(cmitmsg);
cmitmsg = NULL;
@ -885,12 +955,9 @@ static void handle_info(void)
fprintf(fout, "\n");
}

static int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
const char *msg, const char *patch)
static int mailinfo(FILE *in, FILE *out, const char *msg, const char *patch)
{
int peek;
keep_subject = ks;
metainfo_charset = encoding;
fin = in;
fout = out;

@ -924,6 +991,18 @@ static int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
return 0;
}

static int git_mailinfo_config(const char *var, const char *value, void *unused)
{
if (prefixcmp(var, "mailinfo."))
return git_default_config(var, value, unused);
if (!strcmp(var, "mailinfo.scissors")) {
use_scissors = git_config_bool(var, value);
return 0;
}
/* perhaps others here */
return 0;
}

static const char mailinfo_usage[] =
"git mailinfo [-k] [-u | --encoding=<encoding> | -n] msg patch <mail >info";

@ -934,7 +1013,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
/* NEEDSWORK: might want to do the optional .git/ directory
* discovery
*/
git_config(git_default_config, NULL);
git_config(git_mailinfo_config, NULL);

def_charset = (git_commit_encoding ? git_commit_encoding : "UTF-8");
metainfo_charset = def_charset;
@ -948,6 +1027,10 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
metainfo_charset = NULL;
else if (!prefixcmp(argv[1], "--encoding="))
metainfo_charset = argv[1] + 11;
else if (!strcmp(argv[1], "--scissors"))
use_scissors = 1;
else if (!strcmp(argv[1], "--no-scissors"))
use_scissors = 0;
else
usage(mailinfo_usage);
argc--; argv++;
@ -956,5 +1039,5 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
if (argc != 3)
usage(mailinfo_usage);

return !!mailinfo(stdin, stdout, keep_subject, metainfo_charset, argv[1], argv[2]);
return !!mailinfo(stdin, stdout, argv[1], argv[2]);
}

View File

@ -15,6 +15,7 @@ q,quiet be quiet
s,signoff add a Signed-off-by line to the commit message
u,utf8 recode into utf8 (default)
k,keep pass -k flag to git-mailinfo
c,scissors strip everything before a scissors line
whitespace= pass it through git-apply
ignore-space-change pass it through git-apply
ignore-whitespace pass it through git-apply
@ -288,7 +289,7 @@ split_patches () {
prec=4
dotest="$GIT_DIR/rebase-apply"
sign= utf8=t keep= skip= interactive= resolved= rebasing= abort=
resolvemsg= resume=
resolvemsg= resume= scissors=
git_apply_opt=
committer_date_is_author_date=
ignore_date=
@ -310,6 +311,10 @@ do
utf8= ;;
-k|--keep)
keep=t ;;
-c|--scissors)
scissors=t ;;
--no-scissors)
scissors=f ;;
-r|--resolved)
resolved=t ;;
--skip)
@ -317,7 +322,7 @@ do
--abort)
abort=t ;;
--rebasing)
rebasing=t threeway=t keep=t ;;
rebasing=t threeway=t keep=t scissors=f ;;
-d|--dotest)
die "-d option is no longer supported. Do not use."
;;
@ -435,14 +440,14 @@ else

split_patches "$@"

# -s, -u, -k, --whitespace, -3, -C, -q and -p flags are kept
# for the resuming session after a patch failure.
# -i can and must be given when resuming.
# -i can and must be given when resuming; everything
# else is kept
echo " $git_apply_opt" >"$dotest/apply-opt"
echo "$threeway" >"$dotest/threeway"
echo "$sign" >"$dotest/sign"
echo "$utf8" >"$dotest/utf8"
echo "$keep" >"$dotest/keep"
echo "$scissors" >"$dotest/scissors"
echo "$GIT_QUIET" >"$dotest/quiet"
echo 1 >"$dotest/next"
if test -n "$rebasing"
@ -484,6 +489,12 @@ if test "$(cat "$dotest/keep")" = t
then
keep=-k
fi
case "$(cat "$dotest/scissors")" in
t)
scissors=--scissors ;;
f)
scissors=--no-scissors ;;
esac
if test "$(cat "$dotest/quiet")" = t
then
GIT_QUIET=t
@ -538,7 +549,7 @@ do
# by the user, or the user can tell us to do so by --resolved flag.
case "$resume" in
'')
git mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
git mailinfo $keep $scissors $utf8 "$dotest/msg" "$dotest/patch" \
<"$dotest/$msgnum" >"$dotest/info" ||
stop_here $this


View File

@ -11,18 +11,26 @@ test_expect_success 'split sample box' \
'git mailsplit -o. "$TEST_DIRECTORY"/t5100/sample.mbox >last &&
last=`cat last` &&
echo total is $last &&
test `cat last` = 13'
test `cat last` = 14'

check_mailinfo () {
mail=$1 opt=$2
mo="$mail$opt"
git mailinfo -u $opt msg$mo patch$mo <$mail >info$mo &&
test_cmp "$TEST_DIRECTORY"/t5100/msg$mo msg$mo &&
test_cmp "$TEST_DIRECTORY"/t5100/patch$mo patch$mo &&
test_cmp "$TEST_DIRECTORY"/t5100/info$mo info$mo
}


for mail in `echo 00*`
do
test_expect_success "mailinfo $mail" '
git mailinfo -u msg$mail patch$mail <$mail >info$mail &&
echo msg &&
test_cmp "$TEST_DIRECTORY"/t5100/msg$mail msg$mail &&
echo patch &&
test_cmp "$TEST_DIRECTORY"/t5100/patch$mail patch$mail &&
echo info &&
test_cmp "$TEST_DIRECTORY"/t5100/info$mail info$mail
check_mailinfo $mail "" &&
if test -f "$TEST_DIRECTORY"/t5100/msg$mail--scissors
then
check_mailinfo $mail --scissors
fi
'
done


5
t/t5100/info0014 Normal file
View File

@ -0,0 +1,5 @@
Author: Junio Hamano
Email: junkio@cox.net
Subject: BLAH ONE
Date: Thu, 20 Aug 2009 17:18:22 -0700

View File

@ -0,0 +1,5 @@
Author: Junio C Hamano
Email: gitster@pobox.com
Subject: Teach mailinfo to ignore everything before -- >8 -- mark
Date: Thu, 20 Aug 2009 17:18:22 -0700

18
t/t5100/msg0014 Normal file
View File

@ -0,0 +1,18 @@
In real life, we will see a discussion that inspired this patch
discussing related and unrelated things around >8 scissors mark
in this part of the message.

Subject: [PATCH] BLAH TWO

And then we will see the scissors.

This line is not a scissors mark -- >8 -- but talks about it.
- - >8 - - please remove everything above this line - - >8 - -

Subject: [PATCH] Teach mailinfo to ignore everything before -- >8 -- mark
From: Junio C Hamano <gitster@pobox.com>

This teaches mailinfo the scissors -- >8 -- mark; the command ignores
everything before it in the message body.

Signed-off-by: Junio C Hamano <gitster@pobox.com>

View File

@ -0,0 +1,4 @@
This teaches mailinfo the scissors -- >8 -- mark; the command ignores
everything before it in the message body.

Signed-off-by: Junio C Hamano <gitster@pobox.com>

64
t/t5100/patch0014 Normal file
View File

@ -0,0 +1,64 @@
---
builtin-mailinfo.c | 37 ++++++++++++++++++++++++++++++++++++-
1 files changed, 36 insertions(+), 1 deletions(-)

diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index b0b5d8f..461c47e 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -712,6 +712,34 @@ static inline int patchbreak(const struct strbuf *line)
return 0;
}
+static int scissors(const struct strbuf *line)
+{
+ size_t i, len = line->len;
+ int scissors_dashes_seen = 0;
+ const char *buf = line->buf;
+
+ for (i = 0; i < len; i++) {
+ if (isspace(buf[i]))
+ continue;
+ if (buf[i] == '-') {
+ scissors_dashes_seen |= 02;
+ continue;
+ }
+ if (i + 1 < len && !memcmp(buf + i, ">8", 2)) {
+ scissors_dashes_seen |= 01;
+ i++;
+ continue;
+ }
+ if (i + 7 < len && !memcmp(buf + i, "cut here", 8)) {
+ i += 7;
+ continue;
+ }
+ /* everything else --- not scissors */
+ break;
+ }
+ return scissors_dashes_seen == 03;
+}
+
static int handle_commit_msg(struct strbuf *line)
{
static int still_looking = 1;
@@ -723,10 +751,17 @@ static int handle_commit_msg(struct strbuf *line)
strbuf_ltrim(line);
if (!line->len)
return 0;
- if ((still_looking = check_header(line, s_hdr_data, 0)) != 0)
+ still_looking = check_header(line, s_hdr_data, 0);
+ if (still_looking)
return 0;
}
+ if (scissors(line)) {
+ fseek(cmitmsg, 0L, SEEK_SET);
+ still_looking = 1;
+ return 0;
+ }
+
/* normalize the log message to UTF-8. */
if (metainfo_charset)
convert_to_utf8(line, charset.buf);
--
1.6.4.1

View File

@ -0,0 +1,64 @@
---
builtin-mailinfo.c | 37 ++++++++++++++++++++++++++++++++++++-
1 files changed, 36 insertions(+), 1 deletions(-)

diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index b0b5d8f..461c47e 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -712,6 +712,34 @@ static inline int patchbreak(const struct strbuf *line)
return 0;
}
+static int scissors(const struct strbuf *line)
+{
+ size_t i, len = line->len;
+ int scissors_dashes_seen = 0;
+ const char *buf = line->buf;
+
+ for (i = 0; i < len; i++) {
+ if (isspace(buf[i]))
+ continue;
+ if (buf[i] == '-') {
+ scissors_dashes_seen |= 02;
+ continue;
+ }
+ if (i + 1 < len && !memcmp(buf + i, ">8", 2)) {
+ scissors_dashes_seen |= 01;
+ i++;
+ continue;
+ }
+ if (i + 7 < len && !memcmp(buf + i, "cut here", 8)) {
+ i += 7;
+ continue;
+ }
+ /* everything else --- not scissors */
+ break;
+ }
+ return scissors_dashes_seen == 03;
+}
+
static int handle_commit_msg(struct strbuf *line)
{
static int still_looking = 1;
@@ -723,10 +751,17 @@ static int handle_commit_msg(struct strbuf *line)
strbuf_ltrim(line);
if (!line->len)
return 0;
- if ((still_looking = check_header(line, s_hdr_data, 0)) != 0)
+ still_looking = check_header(line, s_hdr_data, 0);
+ if (still_looking)
return 0;
}
+ if (scissors(line)) {
+ fseek(cmitmsg, 0L, SEEK_SET);
+ still_looking = 1;
+ return 0;
+ }
+
/* normalize the log message to UTF-8. */
if (metainfo_charset)
convert_to_utf8(line, charset.buf);
--
1.6.4.1

View File

@ -561,3 +561,92 @@ From: <a.u.thor@example.com> (A U Thor)
Date: Fri, 9 Jun 2006 00:44:16 -0700
Subject: [PATCH] a patch

From nobody Mon Sep 17 00:00:00 2001
From: Junio Hamano <junkio@cox.net>
Date: Thu, 20 Aug 2009 17:18:22 -0700
Subject: Why doesn't git-am does not like >8 scissors mark?

Subject: [PATCH] BLAH ONE

In real life, we will see a discussion that inspired this patch
discussing related and unrelated things around >8 scissors mark
in this part of the message.

Subject: [PATCH] BLAH TWO

And then we will see the scissors.

This line is not a scissors mark -- >8 -- but talks about it.
- - >8 - - please remove everything above this line - - >8 - -

Subject: [PATCH] Teach mailinfo to ignore everything before -- >8 -- mark
From: Junio C Hamano <gitster@pobox.com>

This teaches mailinfo the scissors -- >8 -- mark; the command ignores
everything before it in the message body.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin-mailinfo.c | 37 ++++++++++++++++++++++++++++++++++++-
1 files changed, 36 insertions(+), 1 deletions(-)

diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index b0b5d8f..461c47e 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -712,6 +712,34 @@ static inline int patchbreak(const struct strbuf *line)
return 0;
}
+static int scissors(const struct strbuf *line)
+{
+ size_t i, len = line->len;
+ int scissors_dashes_seen = 0;
+ const char *buf = line->buf;
+
+ for (i = 0; i < len; i++) {
+ if (isspace(buf[i]))
+ continue;
+ if (buf[i] == '-') {
+ scissors_dashes_seen |= 02;
+ continue;
+ }
+ if (i + 1 < len && !memcmp(buf + i, ">8", 2)) {
+ scissors_dashes_seen |= 01;
+ i++;
+ continue;
+ }
+ if (i + 7 < len && !memcmp(buf + i, "cut here", 8)) {
+ i += 7;
+ continue;
+ }
+ /* everything else --- not scissors */
+ break;
+ }
+ return scissors_dashes_seen == 03;
+}
+
static int handle_commit_msg(struct strbuf *line)
{
static int still_looking = 1;
@@ -723,10 +751,17 @@ static int handle_commit_msg(struct strbuf *line)
strbuf_ltrim(line);
if (!line->len)
return 0;
- if ((still_looking = check_header(line, s_hdr_data, 0)) != 0)
+ still_looking = check_header(line, s_hdr_data, 0);
+ if (still_looking)
return 0;
}
+ if (scissors(line)) {
+ fseek(cmitmsg, 0L, SEEK_SET);
+ still_looking = 1;
+ return 0;
+ }
+
/* normalize the log message to UTF-8. */
if (metainfo_charset)
convert_to_utf8(line, charset.buf);
--
1.6.4.1