##// END OF EJS Templates
diffhelpers: be more tolerant for stripped empty lines of CRLF ending...
Yuya Nishihara -
r37593:230eb959 default
parent child Browse files
Show More
@@ -1,77 +1,77
1 # diffhelpers.py - helper routines for patch
1 # diffhelpers.py - helper routines for patch
2 #
2 #
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from .i18n import _
10 from .i18n import _
11
11
12 from . import (
12 from . import (
13 error,
13 error,
14 )
14 )
15
15
16 def addlines(fp, hunk, lena, lenb, a, b):
16 def addlines(fp, hunk, lena, lenb, a, b):
17 """Read lines from fp into the hunk
17 """Read lines from fp into the hunk
18
18
19 The hunk is parsed into two arrays, a and b. a gets the old state of
19 The hunk is parsed into two arrays, a and b. a gets the old state of
20 the text, b gets the new state. The control char from the hunk is saved
20 the text, b gets the new state. The control char from the hunk is saved
21 when inserting into a, but not b (for performance while deleting files.)
21 when inserting into a, but not b (for performance while deleting files.)
22 """
22 """
23 while True:
23 while True:
24 todoa = lena - len(a)
24 todoa = lena - len(a)
25 todob = lenb - len(b)
25 todob = lenb - len(b)
26 num = max(todoa, todob)
26 num = max(todoa, todob)
27 if num == 0:
27 if num == 0:
28 break
28 break
29 for i in xrange(num):
29 for i in xrange(num):
30 s = fp.readline()
30 s = fp.readline()
31 if not s:
31 if not s:
32 raise error.ParseError(_('incomplete hunk'))
32 raise error.ParseError(_('incomplete hunk'))
33 if s == "\\ No newline at end of file\n":
33 if s == "\\ No newline at end of file\n":
34 fixnewline(hunk, a, b)
34 fixnewline(hunk, a, b)
35 continue
35 continue
36 if s == "\n":
36 if s == '\n' or s == '\r\n':
37 # Some patches may be missing the control char
37 # Some patches may be missing the control char
38 # on empty lines. Supply a leading space.
38 # on empty lines. Supply a leading space.
39 s = " \n"
39 s = ' ' + s
40 hunk.append(s)
40 hunk.append(s)
41 if s.startswith('+'):
41 if s.startswith('+'):
42 b.append(s[1:])
42 b.append(s[1:])
43 elif s.startswith('-'):
43 elif s.startswith('-'):
44 a.append(s)
44 a.append(s)
45 else:
45 else:
46 b.append(s[1:])
46 b.append(s[1:])
47 a.append(s)
47 a.append(s)
48
48
49 def fixnewline(hunk, a, b):
49 def fixnewline(hunk, a, b):
50 """Fix up the last lines of a and b when the patch has no newline at EOF"""
50 """Fix up the last lines of a and b when the patch has no newline at EOF"""
51 l = hunk[-1]
51 l = hunk[-1]
52 # tolerate CRLF in last line
52 # tolerate CRLF in last line
53 if l.endswith('\r\n'):
53 if l.endswith('\r\n'):
54 hline = l[:-2]
54 hline = l[:-2]
55 else:
55 else:
56 hline = l[:-1]
56 hline = l[:-1]
57
57
58 if hline.startswith((' ', '+')):
58 if hline.startswith((' ', '+')):
59 b[-1] = hline[1:]
59 b[-1] = hline[1:]
60 if hline.startswith((' ', '-')):
60 if hline.startswith((' ', '-')):
61 a[-1] = hline
61 a[-1] = hline
62 hunk[-1] = hline
62 hunk[-1] = hline
63
63
64 def testhunk(a, b, bstart):
64 def testhunk(a, b, bstart):
65 """Compare the lines in a with the lines in b
65 """Compare the lines in a with the lines in b
66
66
67 a is assumed to have a control char at the start of each line, this char
67 a is assumed to have a control char at the start of each line, this char
68 is ignored in the compare.
68 is ignored in the compare.
69 """
69 """
70 alen = len(a)
70 alen = len(a)
71 blen = len(b)
71 blen = len(b)
72 if alen > blen - bstart:
72 if alen > blen - bstart:
73 return False
73 return False
74 for i in xrange(alen):
74 for i in xrange(alen):
75 if a[i][1:] != b[i + bstart]:
75 if a[i][1:] != b[i + bstart]:
76 return False
76 return False
77 return True
77 return True
@@ -1,146 +1,173
1 $ cat > makepatch.py <<EOF
1 $ cat > makepatch.py <<EOF
2 > f = open('eol.diff', 'wb')
2 > import sys
3 > f = open(sys.argv[2], 'wb')
3 > w = f.write
4 > w = f.write
4 > w(b'test message\n')
5 > w(b'test message\n')
5 > w(b'diff --git a/a b/a\n')
6 > w(b'diff --git a/a b/a\n')
6 > w(b'--- a/a\n')
7 > w(b'--- a/a\n')
7 > w(b'+++ b/a\n')
8 > w(b'+++ b/a\n')
8 > w(b'@@ -1,5 +1,5 @@\n')
9 > w(b'@@ -1,5 +1,5 @@\n')
9 > w(b' a\n')
10 > w(b' a\n')
10 > w(b'-bbb\r\n')
11 > w(b'-bbb\r\n')
11 > w(b'+yyyy\r\n')
12 > w(b'+yyyy\r\n')
12 > w(b' cc\r\n')
13 > w(b' cc\r\n')
13 > w(b' \n')
14 > w({'empty:lf': b' \n',
15 > 'empty:crlf': b' \r\n',
16 > 'empty:stripped-lf': b'\n',
17 > 'empty:stripped-crlf': b'\r\n'}[sys.argv[1]])
14 > w(b' d\n')
18 > w(b' d\n')
15 > w(b'-e\n')
19 > w(b'-e\n')
16 > w(b'\ No newline at end of file\n')
20 > w(b'\ No newline at end of file\n')
17 > w(b'+z\r\n')
21 > w(b'+z\r\n')
18 > w(b'\ No newline at end of file\r\n')
22 > w(b'\ No newline at end of file\r\n')
19 > EOF
23 > EOF
20
24
21 $ hg init repo
25 $ hg init repo
22 $ cd repo
26 $ cd repo
23 $ echo '\.diff' > .hgignore
27 $ echo '\.diff' > .hgignore
24
28
25
29
26 Test different --eol values
30 Test different --eol values
27
31
28 $ $PYTHON -c 'open("a", "wb").write(b"a\nbbb\ncc\n\nd\ne")'
32 $ $PYTHON -c 'open("a", "wb").write(b"a\nbbb\ncc\n\nd\ne")'
29 $ hg ci -Am adda
33 $ hg ci -Am adda
30 adding .hgignore
34 adding .hgignore
31 adding a
35 adding a
32 $ $PYTHON ../makepatch.py
36 $ $PYTHON ../makepatch.py empty:lf eol.diff
33
37 $ $PYTHON ../makepatch.py empty:crlf eol-empty-crlf.diff
38 $ $PYTHON ../makepatch.py empty:stripped-lf eol-empty-stripped-lf.diff
39 $ $PYTHON ../makepatch.py empty:stripped-crlf eol-empty-stripped-crlf.diff
34
40
35 invalid eol
41 invalid eol
36
42
37 $ hg --config patch.eol='LFCR' import eol.diff
43 $ hg --config patch.eol='LFCR' import eol.diff
38 applying eol.diff
44 applying eol.diff
39 abort: unsupported line endings type: LFCR
45 abort: unsupported line endings type: LFCR
40 [255]
46 [255]
41 $ hg revert -a
47 $ hg revert -a
42
48
43
49
44 force LF
50 force LF
45
51
46 $ hg --traceback --config patch.eol='LF' import eol.diff
52 $ hg --traceback --config patch.eol='LF' import eol.diff
47 applying eol.diff
53 applying eol.diff
54 $ hg id
55 9e4ef7b3d4af tip
48 $ cat a
56 $ cat a
49 a
57 a
50 yyyy
58 yyyy
51 cc
59 cc
52
60
53 d
61 d
54 e (no-eol)
62 e (no-eol)
55 $ hg st
63 $ hg st
56
64
65 (test empty-line variants: all of them should generate the same revision)
66
67 $ hg up -qC 0
68 $ hg --config patch.eol='LF' import eol-empty-crlf.diff
69 applying eol-empty-crlf.diff
70 $ hg id
71 9e4ef7b3d4af tip
72
73 $ hg up -qC 0
74 $ hg --config patch.eol='LF' import eol-empty-stripped-lf.diff
75 applying eol-empty-stripped-lf.diff
76 $ hg id
77 9e4ef7b3d4af tip
78
79 $ hg up -qC 0
80 $ hg --config patch.eol='LF' import eol-empty-stripped-crlf.diff
81 applying eol-empty-stripped-crlf.diff
82 $ hg id
83 9e4ef7b3d4af tip
57
84
58 force CRLF
85 force CRLF
59
86
60 $ hg up -C 0
87 $ hg up -C 0
61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 $ hg --traceback --config patch.eol='CRLF' import eol.diff
89 $ hg --traceback --config patch.eol='CRLF' import eol.diff
63 applying eol.diff
90 applying eol.diff
64 $ cat a
91 $ cat a
65 a\r (esc)
92 a\r (esc)
66 yyyy\r (esc)
93 yyyy\r (esc)
67 cc\r (esc)
94 cc\r (esc)
68 \r (esc)
95 \r (esc)
69 d\r (esc)
96 d\r (esc)
70 e (no-eol)
97 e (no-eol)
71 $ hg st
98 $ hg st
72
99
73
100
74 auto EOL on LF file
101 auto EOL on LF file
75
102
76 $ hg up -C 0
103 $ hg up -C 0
77 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
104 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 $ hg --traceback --config patch.eol='auto' import eol.diff
105 $ hg --traceback --config patch.eol='auto' import eol.diff
79 applying eol.diff
106 applying eol.diff
80 $ cat a
107 $ cat a
81 a
108 a
82 yyyy
109 yyyy
83 cc
110 cc
84
111
85 d
112 d
86 e (no-eol)
113 e (no-eol)
87 $ hg st
114 $ hg st
88
115
89
116
90 auto EOL on CRLF file
117 auto EOL on CRLF file
91
118
92 $ $PYTHON -c 'open("a", "wb").write(b"a\r\nbbb\r\ncc\r\n\r\nd\r\ne")'
119 $ $PYTHON -c 'open("a", "wb").write(b"a\r\nbbb\r\ncc\r\n\r\nd\r\ne")'
93 $ hg commit -m 'switch EOLs in a'
120 $ hg commit -m 'switch EOLs in a'
94 $ hg --traceback --config patch.eol='auto' import eol.diff
121 $ hg --traceback --config patch.eol='auto' import eol.diff
95 applying eol.diff
122 applying eol.diff
96 $ cat a
123 $ cat a
97 a\r (esc)
124 a\r (esc)
98 yyyy\r (esc)
125 yyyy\r (esc)
99 cc\r (esc)
126 cc\r (esc)
100 \r (esc)
127 \r (esc)
101 d\r (esc)
128 d\r (esc)
102 e (no-eol)
129 e (no-eol)
103 $ hg st
130 $ hg st
104
131
105
132
106 auto EOL on new file or source without any EOL
133 auto EOL on new file or source without any EOL
107
134
108 $ $PYTHON -c 'open("noeol", "wb").write(b"noeol")'
135 $ $PYTHON -c 'open("noeol", "wb").write(b"noeol")'
109 $ hg add noeol
136 $ hg add noeol
110 $ hg commit -m 'add noeol'
137 $ hg commit -m 'add noeol'
111 $ $PYTHON -c 'open("noeol", "wb").write(b"noeol\r\nnoeol\n")'
138 $ $PYTHON -c 'open("noeol", "wb").write(b"noeol\r\nnoeol\n")'
112 $ $PYTHON -c 'open("neweol", "wb").write(b"neweol\nneweol\r\n")'
139 $ $PYTHON -c 'open("neweol", "wb").write(b"neweol\nneweol\r\n")'
113 $ hg add neweol
140 $ hg add neweol
114 $ hg diff --git > noeol.diff
141 $ hg diff --git > noeol.diff
115 $ hg revert --no-backup noeol neweol
142 $ hg revert --no-backup noeol neweol
116 $ rm neweol
143 $ rm neweol
117 $ hg --traceback --config patch.eol='auto' import -m noeol noeol.diff
144 $ hg --traceback --config patch.eol='auto' import -m noeol noeol.diff
118 applying noeol.diff
145 applying noeol.diff
119 $ cat noeol
146 $ cat noeol
120 noeol\r (esc)
147 noeol\r (esc)
121 noeol
148 noeol
122 $ cat neweol
149 $ cat neweol
123 neweol
150 neweol
124 neweol\r (esc)
151 neweol\r (esc)
125 $ hg st
152 $ hg st
126
153
127
154
128 Test --eol and binary patches
155 Test --eol and binary patches
129
156
130 $ $PYTHON -c 'open("b", "wb").write(b"a\x00\nb\r\nd")'
157 $ $PYTHON -c 'open("b", "wb").write(b"a\x00\nb\r\nd")'
131 $ hg ci -Am addb
158 $ hg ci -Am addb
132 adding b
159 adding b
133 $ $PYTHON -c 'open("b", "wb").write(b"a\x00\nc\r\nd")'
160 $ $PYTHON -c 'open("b", "wb").write(b"a\x00\nc\r\nd")'
134 $ hg diff --git > bin.diff
161 $ hg diff --git > bin.diff
135 $ hg revert --no-backup b
162 $ hg revert --no-backup b
136
163
137 binary patch with --eol
164 binary patch with --eol
138
165
139 $ hg import --config patch.eol='CRLF' -m changeb bin.diff
166 $ hg import --config patch.eol='CRLF' -m changeb bin.diff
140 applying bin.diff
167 applying bin.diff
141 $ cat b
168 $ cat b
142 a\x00 (esc)
169 a\x00 (esc)
143 c\r (esc)
170 c\r (esc)
144 d (no-eol)
171 d (no-eol)
145 $ hg st
172 $ hg st
146 $ cd ..
173 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now