##// END OF EJS Templates
merge with crew.
Vadim Gelfer -
r1729:ace6d26f merge default
parent child Browse files
Show More
@@ -1,189 +1,195
1 1 # mdiff.py - diff and patch routines for mercurial
2 2 #
3 3 # Copyright 2005 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 struct, bdiff, util, mpatch
10 10 demandload(globals(), "re")
11 11
12 12
13 13 def unidiff(a, ad, b, bd, fn, r=None, text=False,
14 14 showfunc=False, ignorews=False):
15 15
16 16 if not a and not b: return ""
17 17 epoch = util.datestr((0, 0))
18 18
19 19 if not text and (util.binary(a) or util.binary(b)):
20 20 l = ['Binary file %s has changed\n' % fn]
21 elif a == None:
21 elif not a:
22 22 b = b.splitlines(1)
23 l1 = "--- %s\t%s\n" % ("/dev/null", epoch)
23 if a is None:
24 l1 = "--- %s\t%s\n" % ("/dev/null", epoch)
25 else:
26 l1 = "--- %s\t%s\n" % ("a/" + fn, ad)
24 27 l2 = "+++ %s\t%s\n" % ("b/" + fn, bd)
25 28 l3 = "@@ -0,0 +1,%d @@\n" % len(b)
26 29 l = [l1, l2, l3] + ["+" + e for e in b]
27 elif b == None:
30 elif not b:
28 31 a = a.splitlines(1)
29 32 l1 = "--- %s\t%s\n" % ("a/" + fn, ad)
30 l2 = "+++ %s\t%s\n" % ("/dev/null", epoch)
33 if b is None:
34 l2 = "+++ %s\t%s\n" % ("/dev/null", epoch)
35 else:
36 l2 = "+++ %s\t%s\n" % ("b/" + fn, bd)
31 37 l3 = "@@ -1,%d +0,0 @@\n" % len(a)
32 38 l = [l1, l2, l3] + ["-" + e for e in a]
33 39 else:
34 40 al = a.splitlines(1)
35 41 bl = b.splitlines(1)
36 42 l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn,
37 43 showfunc=showfunc, ignorews=ignorews))
38 44 if not l: return ""
39 45 # difflib uses a space, rather than a tab
40 46 l[0] = "%s\t%s\n" % (l[0][:-2], ad)
41 47 l[1] = "%s\t%s\n" % (l[1][:-2], bd)
42 48
43 49 for ln in xrange(len(l)):
44 50 if l[ln][-1] != '\n':
45 51 l[ln] += "\n\ No newline at end of file\n"
46 52
47 53 if r:
48 54 l.insert(0, "diff %s %s\n" %
49 55 (' '.join(["-r %s" % rev for rev in r]), fn))
50 56
51 57 return "".join(l)
52 58
53 59 # somewhat self contained replacement for difflib.unified_diff
54 60 # t1 and t2 are the text to be diffed
55 61 # l1 and l2 are the text broken up into lines
56 62 # header1 and header2 are the filenames for the diff output
57 63 # context is the number of context lines
58 64 # showfunc enables diff -p output
59 65 # ignorews ignores all whitespace changes in the diff
60 66 def bunidiff(t1, t2, l1, l2, header1, header2, context=3, showfunc=False,
61 67 ignorews=False):
62 68 def contextend(l, len):
63 69 ret = l + context
64 70 if ret > len:
65 71 ret = len
66 72 return ret
67 73
68 74 def contextstart(l):
69 75 ret = l - context
70 76 if ret < 0:
71 77 return 0
72 78 return ret
73 79
74 80 def yieldhunk(hunk, header):
75 81 if header:
76 82 for x in header:
77 83 yield x
78 84 (astart, a2, bstart, b2, delta) = hunk
79 85 aend = contextend(a2, len(l1))
80 86 alen = aend - astart
81 87 blen = b2 - bstart + aend - a2
82 88
83 89 func = ""
84 90 if showfunc:
85 91 # walk backwards from the start of the context
86 92 # to find a line starting with an alphanumeric char.
87 93 for x in xrange(astart, -1, -1):
88 94 t = l1[x].rstrip()
89 95 if funcre.match(t):
90 96 func = ' ' + t[:40]
91 97 break
92 98
93 99 yield "@@ -%d,%d +%d,%d @@%s\n" % (astart + 1, alen,
94 100 bstart + 1, blen, func)
95 101 for x in delta:
96 102 yield x
97 103 for x in xrange(a2, aend):
98 104 yield ' ' + l1[x]
99 105
100 106 header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ]
101 107
102 108 if showfunc:
103 109 funcre = re.compile('\w')
104 110 if ignorews:
105 111 wsre = re.compile('[ \t]')
106 112
107 113 # bdiff.blocks gives us the matching sequences in the files. The loop
108 114 # below finds the spaces between those matching sequences and translates
109 115 # them into diff output.
110 116 #
111 117 diff = bdiff.blocks(t1, t2)
112 118 hunk = None
113 119 for i in xrange(len(diff)):
114 120 # The first match is special.
115 121 # we've either found a match starting at line 0 or a match later
116 122 # in the file. If it starts later, old and new below will both be
117 123 # empty and we'll continue to the next match.
118 124 if i > 0:
119 125 s = diff[i-1]
120 126 else:
121 127 s = [0, 0, 0, 0]
122 128 delta = []
123 129 s1 = diff[i]
124 130 a1 = s[1]
125 131 a2 = s1[0]
126 132 b1 = s[3]
127 133 b2 = s1[2]
128 134
129 135 old = l1[a1:a2]
130 136 new = l2[b1:b2]
131 137
132 138 # bdiff sometimes gives huge matches past eof, this check eats them,
133 139 # and deals with the special first match case described above
134 140 if not old and not new:
135 141 continue
136 142
137 143 if ignorews:
138 144 wsold = wsre.sub('', "".join(old))
139 145 wsnew = wsre.sub('', "".join(new))
140 146 if wsold == wsnew:
141 147 continue
142 148
143 149 astart = contextstart(a1)
144 150 bstart = contextstart(b1)
145 151 prev = None
146 152 if hunk:
147 153 # join with the previous hunk if it falls inside the context
148 154 if astart < hunk[1] + context + 1:
149 155 prev = hunk
150 156 astart = hunk[1]
151 157 bstart = hunk[3]
152 158 else:
153 159 for x in yieldhunk(hunk, header):
154 160 yield x
155 161 # we only want to yield the header if the files differ, and
156 162 # we only want to yield it once.
157 163 header = None
158 164 if prev:
159 165 # we've joined the previous hunk, record the new ending points.
160 166 hunk[1] = a2
161 167 hunk[3] = b2
162 168 delta = hunk[4]
163 169 else:
164 170 # create a new hunk
165 171 hunk = [ astart, a2, bstart, b2, delta ]
166 172
167 173 delta[len(delta):] = [ ' ' + x for x in l1[astart:a1] ]
168 174 delta[len(delta):] = [ '-' + x for x in old ]
169 175 delta[len(delta):] = [ '+' + x for x in new ]
170 176
171 177 if hunk:
172 178 for x in yieldhunk(hunk, header):
173 179 yield x
174 180
175 181 def patchtext(bin):
176 182 pos = 0
177 183 t = []
178 184 while pos < len(bin):
179 185 p1, p2, l = struct.unpack(">lll", bin[pos:pos + 12])
180 186 pos += 12
181 187 t.append(bin[pos:pos + l])
182 188 pos += l
183 189 return "".join(t)
184 190
185 191 def patch(a, bin):
186 192 return mpatch.patches(a, [bin])
187 193
188 194 patches = mpatch.patches
189 195 textdiff = bdiff.bdiff
@@ -1,14 +1,18
1 1 #!/bin/sh
2 2
3 3 hg init
4 4 touch a
5 5 hg add a
6 6 hg ci -m "a" -d "0 0"
7 7
8 8 echo 123 > b
9 9 hg add b
10 10 hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
11 11 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
12 12
13 13 hg diff -r tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
14 14 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
15
16 echo foo > a
17 hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
18 -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
@@ -1,10 +1,20
1 1 diff -r 3903775176ed b
2 2 --- /dev/null
3 3 +++ b/b
4 4 @@ -0,0 +1,1 @@
5 5 +123
6 6 diff -r 3903775176ed b
7 7 --- /dev/null
8 8 +++ b/b
9 9 @@ -0,0 +1,1 @@
10 10 +123
11 diff -r 3903775176ed a
12 --- a/a
13 +++ b/a
14 @@ -0,0 +1,1 @@
15 +foo
16 diff -r 3903775176ed b
17 --- /dev/null
18 +++ b/b
19 @@ -0,0 +1,1 @@
20 +123
General Comments 0
You need to be logged in to leave comments. Login now