Mercurial > hg > mercurial-crew-with-dirclash
annotate mercurial/mdiff.py @ 1740:f95654385065
add --daemon option to serve command. for issue 45.
code looks odd because it is portable to windows. windows does not have
os.fork, so have to spawn and use pipe to tell parent ready instead.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Fri, 17 Feb 2006 16:29:30 -0800 |
parents | fde8fb2cbede |
children | 441ea218414e |
rev | line source |
---|---|
239
75840796e8e2
mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents:
184
diff
changeset
|
1 # mdiff.py - diff and patch routines for mercurial |
75840796e8e2
mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents:
184
diff
changeset
|
2 # |
75840796e8e2
mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents:
184
diff
changeset
|
3 # Copyright 2005 Matt Mackall <mpm@selenic.com> |
75840796e8e2
mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents:
184
diff
changeset
|
4 # |
75840796e8e2
mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents:
184
diff
changeset
|
5 # This software may be used and distributed according to the terms |
75840796e8e2
mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents:
184
diff
changeset
|
6 # of the GNU General Public License, incorporated herein by reference. |
75840796e8e2
mdiff.py: kill #! line, add copyright notice
mpm@selenic.com
parents:
184
diff
changeset
|
7 |
1637 | 8 from demandload import demandload |
9 import struct, bdiff, util, mpatch | |
10 demandload(globals(), "re") | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
11 |
1637 | 12 |
13 def unidiff(a, ad, b, bd, fn, r=None, text=False, | |
14 showfunc=False, ignorews=False): | |
396
8f8bb77d560e
Show revisions in diffs like CVS, based on a patch from Goffredo Baroncelli.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
361
diff
changeset
|
15 |
35 | 16 if not a and not b: return "" |
1379 | 17 epoch = util.datestr((0, 0)) |
264
4c1d7072d5cd
Attempt to make diff deal with null sources properly
mpm@selenic.com
parents:
249
diff
changeset
|
18 |
1379 | 19 if not text and (util.binary(a) or util.binary(b)): |
1015
22571b8d35d3
Add automatic binary file detection to diff and export
mpm@selenic.com
parents:
582
diff
changeset
|
20 l = ['Binary file %s has changed\n' % fn] |
1723
fde8fb2cbede
Fix diff against an empty file (issue124) and add a test for this.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1637
diff
changeset
|
21 elif not a: |
264
4c1d7072d5cd
Attempt to make diff deal with null sources properly
mpm@selenic.com
parents:
249
diff
changeset
|
22 b = b.splitlines(1) |
1723
fde8fb2cbede
Fix diff against an empty file (issue124) and add a test for this.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1637
diff
changeset
|
23 if a is None: |
fde8fb2cbede
Fix diff against an empty file (issue124) and add a test for this.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1637
diff
changeset
|
24 l1 = "--- %s\t%s\n" % ("/dev/null", epoch) |
fde8fb2cbede
Fix diff against an empty file (issue124) and add a test for this.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1637
diff
changeset
|
25 else: |
fde8fb2cbede
Fix diff against an empty file (issue124) and add a test for this.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1637
diff
changeset
|
26 l1 = "--- %s\t%s\n" % ("a/" + fn, ad) |
264
4c1d7072d5cd
Attempt to make diff deal with null sources properly
mpm@selenic.com
parents:
249
diff
changeset
|
27 l2 = "+++ %s\t%s\n" % ("b/" + fn, bd) |
4c1d7072d5cd
Attempt to make diff deal with null sources properly
mpm@selenic.com
parents:
249
diff
changeset
|
28 l3 = "@@ -0,0 +1,%d @@\n" % len(b) |
4c1d7072d5cd
Attempt to make diff deal with null sources properly
mpm@selenic.com
parents:
249
diff
changeset
|
29 l = [l1, l2, l3] + ["+" + e for e in b] |
1723
fde8fb2cbede
Fix diff against an empty file (issue124) and add a test for this.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1637
diff
changeset
|
30 elif not b: |
264
4c1d7072d5cd
Attempt to make diff deal with null sources properly
mpm@selenic.com
parents:
249
diff
changeset
|
31 a = a.splitlines(1) |
4c1d7072d5cd
Attempt to make diff deal with null sources properly
mpm@selenic.com
parents:
249
diff
changeset
|
32 l1 = "--- %s\t%s\n" % ("a/" + fn, ad) |
1723
fde8fb2cbede
Fix diff against an empty file (issue124) and add a test for this.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1637
diff
changeset
|
33 if b is None: |
fde8fb2cbede
Fix diff against an empty file (issue124) and add a test for this.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1637
diff
changeset
|
34 l2 = "+++ %s\t%s\n" % ("/dev/null", epoch) |
fde8fb2cbede
Fix diff against an empty file (issue124) and add a test for this.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1637
diff
changeset
|
35 else: |
fde8fb2cbede
Fix diff against an empty file (issue124) and add a test for this.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1637
diff
changeset
|
36 l2 = "+++ %s\t%s\n" % ("b/" + fn, bd) |
264
4c1d7072d5cd
Attempt to make diff deal with null sources properly
mpm@selenic.com
parents:
249
diff
changeset
|
37 l3 = "@@ -1,%d +0,0 @@\n" % len(a) |
4c1d7072d5cd
Attempt to make diff deal with null sources properly
mpm@selenic.com
parents:
249
diff
changeset
|
38 l = [l1, l2, l3] + ["-" + e for e in a] |
4c1d7072d5cd
Attempt to make diff deal with null sources properly
mpm@selenic.com
parents:
249
diff
changeset
|
39 else: |
1637 | 40 al = a.splitlines(1) |
41 bl = b.splitlines(1) | |
42 l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, | |
43 showfunc=showfunc, ignorews=ignorews)) | |
278
777e388c06d6
unidiff: handle empty diffs more gracefully
mpm@selenic.com
parents:
272
diff
changeset
|
44 if not l: return "" |
272
467cea2bf2d8
diff: use tab to separate date from filename
mpm@selenic.com
parents:
264
diff
changeset
|
45 # difflib uses a space, rather than a tab |
1540
8ca9f5b17257
minor optimization: save some string trash
twaldmann@thinkmo.de
parents:
1452
diff
changeset
|
46 l[0] = "%s\t%s\n" % (l[0][:-2], ad) |
8ca9f5b17257
minor optimization: save some string trash
twaldmann@thinkmo.de
parents:
1452
diff
changeset
|
47 l[1] = "%s\t%s\n" % (l[1][:-2], bd) |
170 | 48 |
49 for ln in xrange(len(l)): | |
50 if l[ln][-1] != '\n': | |
51 l[ln] += "\n\ No newline at end of file\n" | |
52 | |
396
8f8bb77d560e
Show revisions in diffs like CVS, based on a patch from Goffredo Baroncelli.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
361
diff
changeset
|
53 if r: |
8f8bb77d560e
Show revisions in diffs like CVS, based on a patch from Goffredo Baroncelli.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
361
diff
changeset
|
54 l.insert(0, "diff %s %s\n" % |
8f8bb77d560e
Show revisions in diffs like CVS, based on a patch from Goffredo Baroncelli.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
361
diff
changeset
|
55 (' '.join(["-r %s" % rev for rev in r]), fn)) |
8f8bb77d560e
Show revisions in diffs like CVS, based on a patch from Goffredo Baroncelli.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
361
diff
changeset
|
56 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
57 return "".join(l) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
58 |
1637 | 59 # somewhat self contained replacement for difflib.unified_diff |
60 # t1 and t2 are the text to be diffed | |
61 # l1 and l2 are the text broken up into lines | |
62 # header1 and header2 are the filenames for the diff output | |
63 # context is the number of context lines | |
64 # showfunc enables diff -p output | |
65 # ignorews ignores all whitespace changes in the diff | |
66 def bunidiff(t1, t2, l1, l2, header1, header2, context=3, showfunc=False, | |
67 ignorews=False): | |
68 def contextend(l, len): | |
69 ret = l + context | |
70 if ret > len: | |
71 ret = len | |
72 return ret | |
73 | |
74 def contextstart(l): | |
75 ret = l - context | |
76 if ret < 0: | |
77 return 0 | |
78 return ret | |
79 | |
80 def yieldhunk(hunk, header): | |
81 if header: | |
82 for x in header: | |
83 yield x | |
84 (astart, a2, bstart, b2, delta) = hunk | |
85 aend = contextend(a2, len(l1)) | |
86 alen = aend - astart | |
87 blen = b2 - bstart + aend - a2 | |
88 | |
89 func = "" | |
90 if showfunc: | |
91 # walk backwards from the start of the context | |
92 # to find a line starting with an alphanumeric char. | |
93 for x in xrange(astart, -1, -1): | |
94 t = l1[x].rstrip() | |
95 if funcre.match(t): | |
96 func = ' ' + t[:40] | |
97 break | |
98 | |
99 yield "@@ -%d,%d +%d,%d @@%s\n" % (astart + 1, alen, | |
100 bstart + 1, blen, func) | |
101 for x in delta: | |
102 yield x | |
103 for x in xrange(a2, aend): | |
104 yield ' ' + l1[x] | |
105 | |
106 header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ] | |
107 | |
108 if showfunc: | |
109 funcre = re.compile('\w') | |
110 if ignorews: | |
111 wsre = re.compile('[ \t]') | |
112 | |
113 # bdiff.blocks gives us the matching sequences in the files. The loop | |
114 # below finds the spaces between those matching sequences and translates | |
115 # them into diff output. | |
116 # | |
117 diff = bdiff.blocks(t1, t2) | |
118 hunk = None | |
119 for i in xrange(len(diff)): | |
120 # The first match is special. | |
121 # we've either found a match starting at line 0 or a match later | |
122 # in the file. If it starts later, old and new below will both be | |
123 # empty and we'll continue to the next match. | |
124 if i > 0: | |
125 s = diff[i-1] | |
126 else: | |
127 s = [0, 0, 0, 0] | |
128 delta = [] | |
129 s1 = diff[i] | |
130 a1 = s[1] | |
131 a2 = s1[0] | |
132 b1 = s[3] | |
133 b2 = s1[2] | |
134 | |
135 old = l1[a1:a2] | |
136 new = l2[b1:b2] | |
137 | |
138 # bdiff sometimes gives huge matches past eof, this check eats them, | |
139 # and deals with the special first match case described above | |
140 if not old and not new: | |
141 continue | |
142 | |
143 if ignorews: | |
144 wsold = wsre.sub('', "".join(old)) | |
145 wsnew = wsre.sub('', "".join(new)) | |
146 if wsold == wsnew: | |
147 continue | |
148 | |
149 astart = contextstart(a1) | |
150 bstart = contextstart(b1) | |
151 prev = None | |
152 if hunk: | |
153 # join with the previous hunk if it falls inside the context | |
154 if astart < hunk[1] + context + 1: | |
155 prev = hunk | |
156 astart = hunk[1] | |
157 bstart = hunk[3] | |
158 else: | |
159 for x in yieldhunk(hunk, header): | |
160 yield x | |
161 # we only want to yield the header if the files differ, and | |
162 # we only want to yield it once. | |
163 header = None | |
164 if prev: | |
165 # we've joined the previous hunk, record the new ending points. | |
166 hunk[1] = a2 | |
167 hunk[3] = b2 | |
168 delta = hunk[4] | |
169 else: | |
170 # create a new hunk | |
171 hunk = [ astart, a2, bstart, b2, delta ] | |
172 | |
173 delta[len(delta):] = [ ' ' + x for x in l1[astart:a1] ] | |
174 delta[len(delta):] = [ '-' + x for x in old ] | |
175 delta[len(delta):] = [ '+' + x for x in new ] | |
176 | |
177 if hunk: | |
178 for x in yieldhunk(hunk, header): | |
179 yield x | |
180 | |
120
bae6f0328f63
Add a function to return the new text from a binary diff
mpm@selenic.com
parents:
75
diff
changeset
|
181 def patchtext(bin): |
bae6f0328f63
Add a function to return the new text from a binary diff
mpm@selenic.com
parents:
75
diff
changeset
|
182 pos = 0 |
bae6f0328f63
Add a function to return the new text from a binary diff
mpm@selenic.com
parents:
75
diff
changeset
|
183 t = [] |
bae6f0328f63
Add a function to return the new text from a binary diff
mpm@selenic.com
parents:
75
diff
changeset
|
184 while pos < len(bin): |
bae6f0328f63
Add a function to return the new text from a binary diff
mpm@selenic.com
parents:
75
diff
changeset
|
185 p1, p2, l = struct.unpack(">lll", bin[pos:pos + 12]) |
bae6f0328f63
Add a function to return the new text from a binary diff
mpm@selenic.com
parents:
75
diff
changeset
|
186 pos += 12 |
bae6f0328f63
Add a function to return the new text from a binary diff
mpm@selenic.com
parents:
75
diff
changeset
|
187 t.append(bin[pos:pos + l]) |
bae6f0328f63
Add a function to return the new text from a binary diff
mpm@selenic.com
parents:
75
diff
changeset
|
188 pos += l |
bae6f0328f63
Add a function to return the new text from a binary diff
mpm@selenic.com
parents:
75
diff
changeset
|
189 return "".join(t) |
bae6f0328f63
Add a function to return the new text from a binary diff
mpm@selenic.com
parents:
75
diff
changeset
|
190 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
191 def patch(a, bin): |
1379 | 192 return mpatch.patches(a, [bin]) |
432 | 193 |
1379 | 194 patches = mpatch.patches |
432 | 195 textdiff = bdiff.bdiff |