am: learn to process quoted lines that ends with CRLF
In previous changes, mailinfo has learnt to process lines that decoded from base64 or quoted-printable, and ends with CRLF. Let's teach "am" that new trick, too. Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Đoàn Trần Công Danh committed
May 10, 2021 at 00:12 UTC
59b519ab7e703ebdbad06bd9ba3cae6e55d880d0
6 files changed
+110
Documentation/git-am.txt
+4
@@ -15,6 +15,7 @@ SYNOPSIS
15
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
16
[--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
17
[--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>]
18
+ [--quoted-cr=<action>]
19
[(<mbox> | <Maildir>)...]
20
'git am' (--continue | --skip | --abort | --quit | --show-current-patch[=(diff|raw)])
21
@@ -59,6 +60,9 @@ OPTIONS
60
--no-scissors::
61
Ignore scissors lines (see linkgit:git-mailinfo[1]).
62
63
+--quoted-cr=<action>::
64
+ This flag will be passed down to 'git mailinfo' (see linkgit:git-mailinfo[1]).
65
+
66
-m::
67
--message-id::
68
Pass the `-m` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]),
builtin/am.c
+51
@@ -116,6 +116,7 @@ struct am_state {
116
int keep; /* enum keep_type */
117
int message_id;
118
int scissors; /* enum scissors_type */
119
+ int quoted_cr; /* enum quoted_cr_action */
120
struct strvec git_apply_opts;
121
const char *resolvemsg;
122
int committer_date_is_author_date;
@@ -145,6 +146,7 @@ static void am_state_init(struct am_state *state)
146
git_config_get_bool("am.messageid", &state->message_id);
147
148
state->scissors = SCISSORS_UNSET;
149
+ state->quoted_cr = quoted_cr_unset;
150
151
strvec_init(&state->git_apply_opts);
152
@@ -165,6 +167,16 @@ static void am_state_release(struct am_state *state)
167
strvec_clear(&state->git_apply_opts);
168
}
169
170
+static int am_option_parse_quoted_cr(const struct option *opt,
171
+ const char *arg, int unset)
172
+{
173
+ BUG_ON_OPT_NEG(unset);
174
+
175
+ if (mailinfo_parse_quoted_cr_action(arg, opt->value) != 0)
176
+ return error(_("bad action '%s' for '%s'"), arg, "--quoted-cr");
177
+ return 0;
178
+}
179
+
180
/**
181
* Returns path relative to the am_state directory.
182
*/
@@ -397,6 +409,12 @@ static void am_load(struct am_state *state)
409
else
410
state->scissors = SCISSORS_UNSET;
411
412
+ read_state_file(&sb, state, "quoted-cr", 1);
413
+ if (!*sb.buf)
414
+ state->quoted_cr = quoted_cr_unset;
415
+ else if (mailinfo_parse_quoted_cr_action(sb.buf, &state->quoted_cr) != 0)
416
+ die(_("could not parse %s"), am_path(state, "quoted-cr"));
417
+
418
read_state_file(&sb, state, "apply-opt", 1);
419
strvec_clear(&state->git_apply_opts);
420
if (sq_dequote_to_strvec(sb.buf, &state->git_apply_opts) < 0)
@@ -1002,6 +1020,24 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,
1020
}
1021
write_state_text(state, "scissors", str);
1022
1023
+ switch (state->quoted_cr) {
1024
+ case quoted_cr_unset:
1025
+ str = "";
1026
+ break;
1027
+ case quoted_cr_nowarn:
1028
+ str = "nowarn";
1029
+ break;
1030
+ case quoted_cr_warn:
1031
+ str = "warn";
1032
+ break;
1033
+ case quoted_cr_strip:
1034
+ str = "strip";
1035
+ break;
1036
+ default:
1037
+ BUG("invalid value for state->quoted_cr");
1038
+ }
1039
+ write_state_text(state, "quoted-cr", str);
1040
+
1041
sq_quote_argv(&sb, state->git_apply_opts.v);
1042
write_state_text(state, "apply-opt", sb.buf);
1043
@@ -1162,6 +1198,18 @@ static int parse_mail(struct am_state *state, const char *mail)
1198
BUG("invalid value for state->scissors");
1199
}
1200
1201
+ switch (state->quoted_cr) {
1202
+ case quoted_cr_unset:
1203
+ break;
1204
+ case quoted_cr_nowarn:
1205
+ case quoted_cr_warn:
1206
+ case quoted_cr_strip:
1207
+ mi.quoted_cr = state->quoted_cr;
1208
+ break;
1209
+ default:
1210
+ BUG("invalid value for state->quoted_cr");
1211
+ }
1212
+
1213
mi.input = xfopen(mail, "r");
1214
mi.output = xfopen(am_path(state, "info"), "w");
1215
if (mailinfo(&mi, am_path(state, "msg"), am_path(state, "patch")))
@@ -2242,6 +2290,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
2290
0, PARSE_OPT_NONEG),
2291
OPT_BOOL('c', "scissors", &state.scissors,
2292
N_("strip everything before a scissors line")),
2293
+ OPT_CALLBACK_F(0, "quoted-cr", &state.quoted_cr, N_("action"),
2294
+ N_("pass it through git-mailinfo"),
2295
+ PARSE_OPT_NONEG, am_option_parse_quoted_cr),
2296
OPT_PASSTHRU_ARGV(0, "whitespace", &state.git_apply_opts, N_("action"),
2297
N_("pass it through git-apply"),
2298
0),
contrib/completion/git-completion.bash
+5
@@ -1333,6 +1333,7 @@ __git_whitespacelist="nowarn warn error error-all fix"
1333
__git_patchformat="mbox stgit stgit-series hg mboxrd"
1334
__git_showcurrentpatch="diff raw"
1335
__git_am_inprogress_options="--skip --continue --resolved --abort --quit --show-current-patch"
1336
+__git_quoted_cr="nowarn warn strip"
1337
1338
_git_am ()
1339
{
@@ -1354,6 +1355,10 @@ _git_am ()
1355
__gitcomp "$__git_showcurrentpatch" "" "${cur##--show-current-patch=}"
1356
return
1357
;;
1358
+ --quoted-cr=*)
1359
+ __gitcomp "$__git_quoted_cr" "" "${cur##--quoted-cr=}"
1360
+ return
1361
+ ;;
1362
--*)
1363
__gitcomp_builtin am "" \
1364
"$__git_am_inprogress_options"
mailinfo.h
+1
@@ -6,6 +6,7 @@
6
#define MAX_BOUNDARIES 5
7
8
enum quoted_cr_action {
9
+ quoted_cr_unset = -1,
10
quoted_cr_nowarn,
11
quoted_cr_warn,
12
quoted_cr_strip,
t/t4258-am-quoted-cr.sh
new
+37
@@ -0,0 +1,37 @@
1
+#!/bin/sh
2
+
3
+test_description='test am --quoted-cr=<action>'
4
+
5
+. ./test-lib.sh
6
+
7
+DATA="$TEST_DIRECTORY/t4258"
8
+
9
+test_expect_success 'setup' '
10
+ test_write_lines one two three >text &&
11
+ test_commit one text &&
12
+ test_write_lines one owt three >text &&
13
+ test_commit two text
14
+'
15
+
16
+test_expect_success 'am warn if quoted-cr is found' '
17
+ git reset --hard one &&
18
+ test_must_fail git am "$DATA/mbox" 2>err &&
19
+ grep "quoted CRLF detected" err
20
+'
21
+
22
+test_expect_success 'am --quoted-cr=strip' '
23
+ test_might_fail git am --abort &&
24
+ git reset --hard one &&
25
+ git am --quoted-cr=strip "$DATA/mbox" &&
26
+ git diff --exit-code HEAD two
27
+'
28
+
29
+test_expect_success 'am with config mailinfo.quotecr=strip' '
30
+ test_might_fail git am --abort &&
31
+ git reset --hard one &&
32
+ test_config mailinfo.quotedCr strip &&
33
+ git am "$DATA/mbox" &&
34
+ git diff --exit-code HEAD two
35
+'
36
+
37
+test_done
t/t4258/mbox
new
+12
@@ -0,0 +1,12 @@
1
+From: A U Thor <mail@example.com>
2
+To: list@example.org
3
+Subject: [PATCH v2] sample
4
+Date: Mon, 3 Aug 2020 22:40:55 +0700
5
+Message-Id: <msg-id@example.com>
6
+Content-Type: text/plain; charset="utf-8"
7
+Content-Transfer-Encoding: base64
8
+
9
+VGhpcyBpcyBjb21taXQgbWVzc2FnZS4NCi0tLQ0KIHRleHQgfCAyICstDQogMSBmaWxlIGNoYW5n
10
+ZWQsIDEgaW5zZXJ0aW9uKCspLCAxIGRlbGV0aW9uKC0pDQoNCmRpZmYgLS1naXQgYS90ZXh0IGIv
11
+dGV4dA0KaW5kZXggNTYyNmFiZi4uZjcxOWVmZCAxMDA2NDQNCi0tLSBhL3RleHQNCisrKyBiL3Rl
12
+eHQNCkBAIC0xICsxIEBADQotb25lDQordHdvDQotLSANCjIuMzEuMQoK