Skip to content

Commit 838c0ba

Browse files
Jialong Wanggitster
authored andcommitted
apply: report input location in header parsing errors
Several header parsing errors in apply.c still report only line numbers. When applying more than one input, that does not tell the user which input the line belongs to. Report the patch input location for these header parsing errors, and update the related tests. While touching parse_git_diff_header(), update the helper state to use the current header line when reporting these errors. Signed-off-by: Jialong Wang <jerrywang183@yahoo.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent c5e15c9 commit 838c0ba

5 files changed

Lines changed: 106 additions & 24 deletions

File tree

apply.c

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
struct gitdiff_data {
4444
struct strbuf *root;
45+
const char *patch_input_file;
4546
int linenr;
4647
int p_value;
4748
};
@@ -900,7 +901,8 @@ static int parse_traditional_patch(struct apply_state *state,
900901
}
901902
}
902903
if (!name)
903-
return error(_("unable to find filename in patch at line %d"), state->linenr);
904+
return error(_("unable to find filename in patch at %s:%d"),
905+
state->patch_input_file, state->linenr);
904906

905907
return 0;
906908
}
@@ -937,20 +939,35 @@ static int gitdiff_verify_name(struct gitdiff_data *state,
937939

938940
if (*name) {
939941
char *another;
940-
if (isnull)
942+
if (isnull) {
943+
if (state->patch_input_file)
944+
return error(_("git apply: bad git-diff - expected /dev/null, got %s at %s:%d"),
945+
*name, state->patch_input_file, state->linenr);
941946
return error(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"),
942947
*name, state->linenr);
948+
}
943949
another = find_name(state->root, line, NULL, state->p_value, TERM_TAB);
944950
if (!another || strcmp(another, *name)) {
945951
free(another);
952+
if (state->patch_input_file)
953+
return error((side == DIFF_NEW_NAME) ?
954+
_("git apply: bad git-diff - inconsistent new filename at %s:%d") :
955+
_("git apply: bad git-diff - inconsistent old filename at %s:%d"),
956+
state->patch_input_file, state->linenr);
946957
return error((side == DIFF_NEW_NAME) ?
947-
_("git apply: bad git-diff - inconsistent new filename on line %d") :
948-
_("git apply: bad git-diff - inconsistent old filename on line %d"), state->linenr);
958+
_("git apply: bad git-diff - inconsistent new filename on line %d") :
959+
_("git apply: bad git-diff - inconsistent old filename on line %d"),
960+
state->linenr);
949961
}
950962
free(another);
951963
} else {
952-
if (!is_dev_null(line))
953-
return error(_("git apply: bad git-diff - expected /dev/null on line %d"), state->linenr);
964+
if (!is_dev_null(line)) {
965+
if (state->patch_input_file)
966+
return error(_("git apply: bad git-diff - expected /dev/null at %s:%d"),
967+
state->patch_input_file, state->linenr);
968+
return error(_("git apply: bad git-diff - expected /dev/null on line %d"),
969+
state->linenr);
970+
}
954971
}
955972

956973
return 0;
@@ -974,12 +991,19 @@ static int gitdiff_newname(struct gitdiff_data *state,
974991
DIFF_NEW_NAME);
975992
}
976993

977-
static int parse_mode_line(const char *line, int linenr, unsigned int *mode)
994+
static int parse_mode_line(const char *line,
995+
const char *patch_input_file,
996+
int linenr,
997+
unsigned int *mode)
978998
{
979999
char *end;
9801000
*mode = strtoul(line, &end, 8);
981-
if (end == line || !isspace(*end))
1001+
if (end == line || !isspace(*end)) {
1002+
if (patch_input_file)
1003+
return error(_("invalid mode at %s:%d: %s"),
1004+
patch_input_file, linenr, line);
9821005
return error(_("invalid mode on line %d: %s"), linenr, line);
1006+
}
9831007
*mode = canon_mode(*mode);
9841008
return 0;
9851009
}
@@ -988,14 +1012,16 @@ static int gitdiff_oldmode(struct gitdiff_data *state,
9881012
const char *line,
9891013
struct patch *patch)
9901014
{
991-
return parse_mode_line(line, state->linenr, &patch->old_mode);
1015+
return parse_mode_line(line, state->patch_input_file, state->linenr,
1016+
&patch->old_mode);
9921017
}
9931018

9941019
static int gitdiff_newmode(struct gitdiff_data *state,
9951020
const char *line,
9961021
struct patch *patch)
9971022
{
998-
return parse_mode_line(line, state->linenr, &patch->new_mode);
1023+
return parse_mode_line(line, state->patch_input_file, state->linenr,
1024+
&patch->new_mode);
9991025
}
10001026

10011027
static int gitdiff_delete(struct gitdiff_data *state,
@@ -1314,6 +1340,7 @@ static int check_header_line(int linenr, struct patch *patch)
13141340
}
13151341

13161342
int parse_git_diff_header(struct strbuf *root,
1343+
const char *patch_input_file,
13171344
int *linenr,
13181345
int p_value,
13191346
const char *line,
@@ -1345,6 +1372,7 @@ int parse_git_diff_header(struct strbuf *root,
13451372
size -= len;
13461373
(*linenr)++;
13471374
parse_hdr_state.root = root;
1375+
parse_hdr_state.patch_input_file = patch_input_file;
13481376
parse_hdr_state.linenr = *linenr;
13491377
parse_hdr_state.p_value = p_value;
13501378

@@ -1382,6 +1410,7 @@ int parse_git_diff_header(struct strbuf *root,
13821410
int res;
13831411
if (len < oplen || memcmp(p->str, line, oplen))
13841412
continue;
1413+
parse_hdr_state.linenr = *linenr;
13851414
res = p->fn(&parse_hdr_state, line + oplen, patch);
13861415
if (res < 0)
13871416
return -1;
@@ -1396,21 +1425,33 @@ int parse_git_diff_header(struct strbuf *root,
13961425
done:
13971426
if (!patch->old_name && !patch->new_name) {
13981427
if (!patch->def_name) {
1399-
error(Q_("git diff header lacks filename information when removing "
1400-
"%d leading pathname component (line %d)",
1401-
"git diff header lacks filename information when removing "
1402-
"%d leading pathname components (line %d)",
1403-
parse_hdr_state.p_value),
1404-
parse_hdr_state.p_value, *linenr);
1428+
if (patch_input_file)
1429+
error(Q_("git diff header lacks filename information when removing "
1430+
"%d leading pathname component at %s:%d",
1431+
"git diff header lacks filename information when removing "
1432+
"%d leading pathname components at %s:%d",
1433+
parse_hdr_state.p_value),
1434+
parse_hdr_state.p_value, patch_input_file, *linenr);
1435+
else
1436+
error(Q_("git diff header lacks filename information when removing "
1437+
"%d leading pathname component (line %d)",
1438+
"git diff header lacks filename information when removing "
1439+
"%d leading pathname components (line %d)",
1440+
parse_hdr_state.p_value),
1441+
parse_hdr_state.p_value, *linenr);
14051442
return -128;
14061443
}
14071444
patch->old_name = xstrdup(patch->def_name);
14081445
patch->new_name = xstrdup(patch->def_name);
14091446
}
14101447
if ((!patch->new_name && !patch->is_delete) ||
14111448
(!patch->old_name && !patch->is_new)) {
1412-
error(_("git diff header lacks filename information "
1413-
"(line %d)"), *linenr);
1449+
if (patch_input_file)
1450+
error(_("git diff header lacks filename information at %s:%d"),
1451+
patch_input_file, *linenr);
1452+
else
1453+
error(_("git diff header lacks filename information (line %d)"),
1454+
*linenr);
14141455
return -128;
14151456
}
14161457
patch->is_toplevel_relative = 1;
@@ -1577,8 +1618,9 @@ static int find_header(struct apply_state *state,
15771618
struct fragment dummy;
15781619
if (parse_fragment_header(line, len, &dummy) < 0)
15791620
continue;
1580-
error(_("patch fragment without header at line %d: %.*s"),
1581-
state->linenr, (int)len-1, line);
1621+
error(_("patch fragment without header at %s:%d: %.*s"),
1622+
state->patch_input_file, state->linenr,
1623+
(int)len-1, line);
15821624
return -128;
15831625
}
15841626

@@ -1590,7 +1632,9 @@ static int find_header(struct apply_state *state,
15901632
* or mode change, so we handle that specially
15911633
*/
15921634
if (!memcmp("diff --git ", line, 11)) {
1593-
int git_hdr_len = parse_git_diff_header(&state->root, &state->linenr,
1635+
int git_hdr_len = parse_git_diff_header(&state->root,
1636+
state->patch_input_file,
1637+
&state->linenr,
15941638
state->p_value, line, len,
15951639
size, patch);
15961640
if (git_hdr_len < 0)

apply.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ int check_apply_state(struct apply_state *state, int force_apply);
167167
* Returns -1 on failure, the length of the parsed header otherwise.
168168
*/
169169
int parse_git_diff_header(struct strbuf *root,
170+
const char *patch_input_file,
170171
int *linenr,
171172
int p_value,
172173
const char *line,

range-diff.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ static int read_patches(const char *range, struct string_list *list,
140140
if (eol)
141141
*eol = '\n';
142142
orig_len = len;
143-
len = parse_git_diff_header(&root, &linenr, 0, line,
143+
len = parse_git_diff_header(&root, NULL, &linenr, 0, line,
144144
len, size, &patch);
145145
if (len < 0) {
146146
error(_("could not parse git header '%.*s'"),

t/t4100-apply-stat.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,42 @@ test_expect_success 'applying multiple patches reports the corrupted input' '
8787
echo "error: corrupt patch at bad.patch:4" >expect &&
8888
test_cmp expect err
8989
'
90+
91+
test_expect_success 'applying a patch without a header reports the input' '
92+
cat >fragment.patch <<-\EOF &&
93+
@@ -1 +1 @@
94+
-a
95+
+b
96+
EOF
97+
test_must_fail git apply fragment.patch 2>err &&
98+
echo "error: patch fragment without header at fragment.patch:1: @@ -1 +1 @@" >expect &&
99+
test_cmp expect err
100+
'
101+
102+
test_expect_success 'applying a patch with a missing filename reports the input' '
103+
cat >missing.patch <<-\EOF &&
104+
diff --git a/f b/f
105+
index 7898192..6178079 100644
106+
--- a/f
107+
@@ -1 +1 @@
108+
-a
109+
+b
110+
EOF
111+
test_must_fail git apply missing.patch 2>err &&
112+
echo "error: git diff header lacks filename information at missing.patch:4" >expect &&
113+
test_cmp expect err
114+
'
115+
116+
test_expect_success 'applying a patch with an invalid mode reports the input' '
117+
cat >mode.patch <<-\EOF &&
118+
diff --git a/f b/f
119+
old mode 10x644
120+
EOF
121+
test_must_fail git apply mode.patch 2>err &&
122+
cat >expect <<-\EOF &&
123+
error: invalid mode at mode.patch:2: 10x644
124+
125+
EOF
126+
test_cmp expect err
127+
'
90128
test_done

t/t4254-am-corrupt.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,8 @@ test_expect_success setup '
6565
test_expect_success 'try to apply corrupted patch' '
6666
test_when_finished "git am --abort" &&
6767
test_must_fail git -c advice.amWorkDir=false -c advice.mergeConflict=false am bad-patch.diff 2>actual &&
68-
echo "error: git diff header lacks filename information (line 4)" >expected &&
6968
test_path_is_file f &&
70-
test_cmp expected actual
69+
test_grep "error: git diff header lacks filename information at .*rebase-apply/patch:4" actual
7170
'
7271

7372
test_expect_success "NUL in commit message's body" '

0 commit comments

Comments
 (0)