##// END OF EJS Templates
Remove dates from git export file lines - they confuse git-apply
Brendan Cully -
r3026:d838bfac default
parent child Browse files
Show More
@@ -1,247 +1,250
1 1 # mdiff.py - diff and patch routines for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from demandload import demandload
9 9 import bdiff, mpatch
10 10 demandload(globals(), "re struct util")
11 11
12 12 def splitnewlines(text):
13 13 '''like str.splitlines, but only split on newlines.'''
14 14 lines = [l + '\n' for l in text.split('\n')]
15 15 if lines:
16 16 if lines[-1] == '\n':
17 17 lines.pop()
18 18 else:
19 19 lines[-1] = lines[-1][:-1]
20 20 return lines
21 21
22 22 class diffopts(object):
23 23 '''context is the number of context lines
24 24 text treats all files as text
25 25 showfunc enables diff -p output
26 26 git enables the git extended patch format
27 27 ignorews ignores all whitespace changes in the diff
28 28 ignorewsamount ignores changes in the amount of whitespace
29 29 ignoreblanklines ignores changes whose lines are all blank'''
30 30
31 31 defaults = {
32 32 'context': 3,
33 33 'text': False,
34 34 'showfunc': True,
35 35 'git': False,
36 36 'ignorews': False,
37 37 'ignorewsamount': False,
38 38 'ignoreblanklines': False,
39 39 }
40 40
41 41 __slots__ = defaults.keys()
42 42
43 43 def __init__(self, **opts):
44 44 for k in self.__slots__:
45 45 v = opts.get(k)
46 46 if v is None:
47 47 v = self.defaults[k]
48 48 setattr(self, k, v)
49 49
50 50 defaultopts = diffopts()
51 51
52 52 def unidiff(a, ad, b, bd, fn, r=None, opts=defaultopts):
53 def datetag(date):
54 return opts.git and '\n' or '\t%s\n' % date
55
53 56 if not a and not b: return ""
54 57 epoch = util.datestr((0, 0))
55 58
56 59 if not opts.text and (util.binary(a) or util.binary(b)):
57 60 l = ['Binary file %s has changed\n' % fn]
58 61 elif not a:
59 62 b = splitnewlines(b)
60 63 if a is None:
61 l1 = "--- %s\t%s\n" % ("/dev/null", epoch)
64 l1 = '--- /dev/null%s' % datetag(epoch)
62 65 else:
63 l1 = "--- %s\t%s\n" % ("a/" + fn, ad)
64 l2 = "+++ %s\t%s\n" % ("b/" + fn, bd)
66 l1 = "--- %s%s" % ("a/" + fn, datetag(ad))
67 l2 = "+++ %s%s" % ("b/" + fn, datetag(bd))
65 68 l3 = "@@ -0,0 +1,%d @@\n" % len(b)
66 69 l = [l1, l2, l3] + ["+" + e for e in b]
67 70 elif not b:
68 71 a = splitnewlines(a)
69 l1 = "--- %s\t%s\n" % ("a/" + fn, ad)
72 l1 = "--- %s%s" % ("a/" + fn, datetag(ad))
70 73 if b is None:
71 l2 = "+++ %s\t%s\n" % ("/dev/null", epoch)
74 l2 = '+++ /dev/null%s' % datetag(epoch)
72 75 else:
73 l2 = "+++ %s\t%s\n" % ("b/" + fn, bd)
76 l2 = "+++ %s%s" % ("b/" + fn, datetag(bd))
74 77 l3 = "@@ -1,%d +0,0 @@\n" % len(a)
75 78 l = [l1, l2, l3] + ["-" + e for e in a]
76 79 else:
77 80 al = splitnewlines(a)
78 81 bl = splitnewlines(b)
79 82 l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, opts=opts))
80 83 if not l: return ""
81 84 # difflib uses a space, rather than a tab
82 l[0] = "%s\t%s\n" % (l[0][:-2], ad)
83 l[1] = "%s\t%s\n" % (l[1][:-2], bd)
85 l[0] = "%s%s" % (l[0][:-2], datetag(ad))
86 l[1] = "%s%s" % (l[1][:-2], datetag(bd))
84 87
85 88 for ln in xrange(len(l)):
86 89 if l[ln][-1] != '\n':
87 90 l[ln] += "\n\ No newline at end of file\n"
88 91
89 92 if r:
90 93 l.insert(0, "diff %s %s\n" %
91 94 (' '.join(["-r %s" % rev for rev in r]), fn))
92 95
93 96 return "".join(l)
94 97
95 98 # somewhat self contained replacement for difflib.unified_diff
96 99 # t1 and t2 are the text to be diffed
97 100 # l1 and l2 are the text broken up into lines
98 101 # header1 and header2 are the filenames for the diff output
99 102 def bunidiff(t1, t2, l1, l2, header1, header2, opts=defaultopts):
100 103 def contextend(l, len):
101 104 ret = l + opts.context
102 105 if ret > len:
103 106 ret = len
104 107 return ret
105 108
106 109 def contextstart(l):
107 110 ret = l - opts.context
108 111 if ret < 0:
109 112 return 0
110 113 return ret
111 114
112 115 def yieldhunk(hunk, header):
113 116 if header:
114 117 for x in header:
115 118 yield x
116 119 (astart, a2, bstart, b2, delta) = hunk
117 120 aend = contextend(a2, len(l1))
118 121 alen = aend - astart
119 122 blen = b2 - bstart + aend - a2
120 123
121 124 func = ""
122 125 if opts.showfunc:
123 126 # walk backwards from the start of the context
124 127 # to find a line starting with an alphanumeric char.
125 128 for x in xrange(astart, -1, -1):
126 129 t = l1[x].rstrip()
127 130 if funcre.match(t):
128 131 func = ' ' + t[:40]
129 132 break
130 133
131 134 yield "@@ -%d,%d +%d,%d @@%s\n" % (astart + 1, alen,
132 135 bstart + 1, blen, func)
133 136 for x in delta:
134 137 yield x
135 138 for x in xrange(a2, aend):
136 139 yield ' ' + l1[x]
137 140
138 141 header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ]
139 142
140 143 if opts.showfunc:
141 144 funcre = re.compile('\w')
142 145 if opts.ignorewsamount:
143 146 wsamountre = re.compile('[ \t]+')
144 147 wsappendedre = re.compile(' \n')
145 148 if opts.ignoreblanklines:
146 149 wsblanklinesre = re.compile('\n')
147 150 if opts.ignorews:
148 151 wsre = re.compile('[ \t]')
149 152
150 153 # bdiff.blocks gives us the matching sequences in the files. The loop
151 154 # below finds the spaces between those matching sequences and translates
152 155 # them into diff output.
153 156 #
154 157 diff = bdiff.blocks(t1, t2)
155 158 hunk = None
156 159 for i in xrange(len(diff)):
157 160 # The first match is special.
158 161 # we've either found a match starting at line 0 or a match later
159 162 # in the file. If it starts later, old and new below will both be
160 163 # empty and we'll continue to the next match.
161 164 if i > 0:
162 165 s = diff[i-1]
163 166 else:
164 167 s = [0, 0, 0, 0]
165 168 delta = []
166 169 s1 = diff[i]
167 170 a1 = s[1]
168 171 a2 = s1[0]
169 172 b1 = s[3]
170 173 b2 = s1[2]
171 174
172 175 old = l1[a1:a2]
173 176 new = l2[b1:b2]
174 177
175 178 # bdiff sometimes gives huge matches past eof, this check eats them,
176 179 # and deals with the special first match case described above
177 180 if not old and not new:
178 181 continue
179 182
180 183 if opts.ignoreblanklines:
181 184 wsold = wsblanklinesre.sub('', "".join(old))
182 185 wsnew = wsblanklinesre.sub('', "".join(new))
183 186 if wsold == wsnew:
184 187 continue
185 188
186 189 if opts.ignorewsamount:
187 190 wsold = wsamountre.sub(' ', "".join(old))
188 191 wsold = wsappendedre.sub('\n', wsold)
189 192 wsnew = wsamountre.sub(' ', "".join(new))
190 193 wsnew = wsappendedre.sub('\n', wsnew)
191 194 if wsold == wsnew:
192 195 continue
193 196
194 197 if opts.ignorews:
195 198 wsold = wsre.sub('', "".join(old))
196 199 wsnew = wsre.sub('', "".join(new))
197 200 if wsold == wsnew:
198 201 continue
199 202
200 203 astart = contextstart(a1)
201 204 bstart = contextstart(b1)
202 205 prev = None
203 206 if hunk:
204 207 # join with the previous hunk if it falls inside the context
205 208 if astart < hunk[1] + opts.context + 1:
206 209 prev = hunk
207 210 astart = hunk[1]
208 211 bstart = hunk[3]
209 212 else:
210 213 for x in yieldhunk(hunk, header):
211 214 yield x
212 215 # we only want to yield the header if the files differ, and
213 216 # we only want to yield it once.
214 217 header = None
215 218 if prev:
216 219 # we've joined the previous hunk, record the new ending points.
217 220 hunk[1] = a2
218 221 hunk[3] = b2
219 222 delta = hunk[4]
220 223 else:
221 224 # create a new hunk
222 225 hunk = [ astart, a2, bstart, b2, delta ]
223 226
224 227 delta[len(delta):] = [ ' ' + x for x in l1[astart:a1] ]
225 228 delta[len(delta):] = [ '-' + x for x in old ]
226 229 delta[len(delta):] = [ '+' + x for x in new ]
227 230
228 231 if hunk:
229 232 for x in yieldhunk(hunk, header):
230 233 yield x
231 234
232 235 def patchtext(bin):
233 236 pos = 0
234 237 t = []
235 238 while pos < len(bin):
236 239 p1, p2, l = struct.unpack(">lll", bin[pos:pos + 12])
237 240 pos += 12
238 241 t.append(bin[pos:pos + l])
239 242 pos += l
240 243 return "".join(t)
241 244
242 245 def patch(a, bin):
243 246 return mpatch.patches(a, [bin])
244 247
245 248 patches = mpatch.patches
246 249 patchedsize = mpatch.patchedsize
247 250 textdiff = bdiff.bdiff
General Comments 0
You need to be logged in to leave comments. Login now