Mercurial > hg > mercurial-crew-with-dirclash
annotate mercurial/verify.py @ 4359:2e3c54fb79a3
actually port simplemerge to hg
- use bdiff instead of patiencediff; this is a larger change, since
bdiff works on 2 multi-line strings, while patiencediff works on 2
lists;
- rename the main class from Merge3 to Merge3Text and add a Merge3
class that derives from Merge3Text. This new Merge3 class has
the same interface from the original class, so that the tests
still work;
- Merge3 uses util.binary to detect binary data and raises
util.Abort instead of a specific exception;
- don't use the @decorator syntax, to keep python2.3 compatibility;
- the test uses unittest, which likes to print how long it took to
run. This obviously doesn't play too well with hg's test suite,
so we override time.time to fool unittest;
- one test has a different (but still valid) output because of the
different diff algorithm used;
- the TestCase class used by bzr has some extras to help debugging.
test-merge3.py used 2 of them:
- log method to log some data
- assertEqualDiff method to ease viewing diffs of diffs
We add a dummy log method and use regular assertEquals instead of
assertEqualDiff.
- make simplemerge executable and add "#!/usr/bin/env python" header
author | Alexis S. L. Carvalho <alexis@cecm.usp.br> |
---|---|
date | Mon, 16 Apr 2007 20:17:39 -0300 |
parents | b11a2fb59cf5 |
children | 47ef2d228375 |
rev | line source |
---|---|
2802 | 1 # verify.py - repository integrity checking for Mercurial |
2 # | |
3 # Copyright 2006 Matt Mackall <mpm@selenic.com> | |
4 # | |
5 # This software may be used and distributed according to the terms | |
6 # of the GNU General Public License, incorporated herein by reference. | |
7 | |
8 from node import * | |
3893 | 9 from i18n import _ |
2802 | 10 import revlog, mdiff |
11 | |
12 def verify(repo): | |
13 filelinkrevs = {} | |
14 filenodes = {} | |
15 changesets = revisions = files = 0 | |
16 errors = [0] | |
17 warnings = [0] | |
18 neededmanifests = {} | |
19 | |
20 def err(msg): | |
21 repo.ui.warn(msg + "\n") | |
22 errors[0] += 1 | |
23 | |
24 def warn(msg): | |
25 repo.ui.warn(msg + "\n") | |
26 warnings[0] += 1 | |
27 | |
28 def checksize(obj, name): | |
29 d = obj.checksize() | |
30 if d[0]: | |
31 err(_("%s data length off by %d bytes") % (name, d[0])) | |
32 if d[1]: | |
33 err(_("%s index contains %d extra bytes") % (name, d[1])) | |
34 | |
35 def checkversion(obj, name): | |
36 if obj.version != revlog.REVLOGV0: | |
37 if not revlogv1: | |
38 warn(_("warning: `%s' uses revlog format 1") % name) | |
39 elif revlogv1: | |
40 warn(_("warning: `%s' uses revlog format 0") % name) | |
41 | |
4267
b11a2fb59cf5
revlog: simplify revlog version handling
Matt Mackall <mpm@selenic.com>
parents:
3893
diff
changeset
|
42 revlogv1 = repo.changelog.version != revlog.REVLOGV0 |
b11a2fb59cf5
revlog: simplify revlog version handling
Matt Mackall <mpm@selenic.com>
parents:
3893
diff
changeset
|
43 if repo.ui.verbose or not revlogv1: |
2802 | 44 repo.ui.status(_("repository uses revlog format %d\n") % |
45 (revlogv1 and 1 or 0)) | |
46 | |
47 seen = {} | |
48 repo.ui.status(_("checking changesets\n")) | |
49 checksize(repo.changelog, "changelog") | |
50 | |
3468
0e68608bd11d
use xrange instead of range
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
3189
diff
changeset
|
51 for i in xrange(repo.changelog.count()): |
2802 | 52 changesets += 1 |
53 n = repo.changelog.node(i) | |
54 l = repo.changelog.linkrev(n) | |
55 if l != i: | |
56 err(_("incorrect link (%d) for changeset revision %d") %(l, i)) | |
57 if n in seen: | |
58 err(_("duplicate changeset at revision %d") % i) | |
59 seen[n] = 1 | |
60 | |
61 for p in repo.changelog.parents(n): | |
62 if p not in repo.changelog.nodemap: | |
63 err(_("changeset %s has unknown parent %s") % | |
64 (short(n), short(p))) | |
65 try: | |
66 changes = repo.changelog.read(n) | |
67 except KeyboardInterrupt: | |
68 repo.ui.warn(_("interrupted")) | |
69 raise | |
70 except Exception, inst: | |
71 err(_("unpacking changeset %s: %s") % (short(n), inst)) | |
72 continue | |
73 | |
74 neededmanifests[changes[0]] = n | |
75 | |
76 for f in changes[3]: | |
77 filelinkrevs.setdefault(f, []).append(i) | |
78 | |
79 seen = {} | |
80 repo.ui.status(_("checking manifests\n")) | |
81 checkversion(repo.manifest, "manifest") | |
82 checksize(repo.manifest, "manifest") | |
83 | |
3468
0e68608bd11d
use xrange instead of range
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
3189
diff
changeset
|
84 for i in xrange(repo.manifest.count()): |
2802 | 85 n = repo.manifest.node(i) |
86 l = repo.manifest.linkrev(n) | |
87 | |
88 if l < 0 or l >= repo.changelog.count(): | |
89 err(_("bad manifest link (%d) at revision %d") % (l, i)) | |
90 | |
91 if n in neededmanifests: | |
92 del neededmanifests[n] | |
93 | |
94 if n in seen: | |
95 err(_("duplicate manifest at revision %d") % i) | |
96 | |
97 seen[n] = 1 | |
98 | |
99 for p in repo.manifest.parents(n): | |
100 if p not in repo.manifest.nodemap: | |
101 err(_("manifest %s has unknown parent %s") % | |
102 (short(n), short(p))) | |
103 | |
104 try: | |
3189
f3b939444c72
Abstract manifest block parsing.
Brendan Cully <brendan@kublai.com>
parents:
2802
diff
changeset
|
105 for f, fn in repo.manifest.readdelta(n).iteritems(): |
f3b939444c72
Abstract manifest block parsing.
Brendan Cully <brendan@kublai.com>
parents:
2802
diff
changeset
|
106 filenodes.setdefault(f, {})[fn] = 1 |
2802 | 107 except KeyboardInterrupt: |
108 repo.ui.warn(_("interrupted")) | |
109 raise | |
110 except Exception, inst: | |
3189
f3b939444c72
Abstract manifest block parsing.
Brendan Cully <brendan@kublai.com>
parents:
2802
diff
changeset
|
111 err(_("reading delta for manifest %s: %s") % (short(n), inst)) |
2802 | 112 continue |
113 | |
114 repo.ui.status(_("crosschecking files in changesets and manifests\n")) | |
115 | |
116 for m, c in neededmanifests.items(): | |
117 err(_("Changeset %s refers to unknown manifest %s") % | |
118 (short(m), short(c))) | |
119 del neededmanifests | |
120 | |
121 for f in filenodes: | |
122 if f not in filelinkrevs: | |
123 err(_("file %s in manifest but not in changesets") % f) | |
124 | |
125 for f in filelinkrevs: | |
126 if f not in filenodes: | |
127 err(_("file %s in changeset but not in manifest") % f) | |
128 | |
129 repo.ui.status(_("checking files\n")) | |
130 ff = filenodes.keys() | |
131 ff.sort() | |
132 for f in ff: | |
133 if f == "/dev/null": | |
134 continue | |
135 files += 1 | |
136 if not f: | |
137 err(_("file without name in manifest %s") % short(n)) | |
138 continue | |
139 fl = repo.file(f) | |
140 checkversion(fl, f) | |
141 checksize(fl, f) | |
142 | |
143 nodes = {nullid: 1} | |
144 seen = {} | |
3468
0e68608bd11d
use xrange instead of range
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
3189
diff
changeset
|
145 for i in xrange(fl.count()): |
2802 | 146 revisions += 1 |
147 n = fl.node(i) | |
148 | |
149 if n in seen: | |
150 err(_("%s: duplicate revision %d") % (f, i)) | |
151 if n not in filenodes[f]: | |
152 err(_("%s: %d:%s not in manifests") % (f, i, short(n))) | |
153 else: | |
154 del filenodes[f][n] | |
155 | |
156 flr = fl.linkrev(n) | |
157 if flr not in filelinkrevs.get(f, []): | |
158 err(_("%s:%s points to unexpected changeset %d") | |
159 % (f, short(n), flr)) | |
160 else: | |
161 filelinkrevs[f].remove(flr) | |
162 | |
163 # verify contents | |
164 try: | |
165 t = fl.read(n) | |
166 except KeyboardInterrupt: | |
167 repo.ui.warn(_("interrupted")) | |
168 raise | |
169 except Exception, inst: | |
170 err(_("unpacking file %s %s: %s") % (f, short(n), inst)) | |
171 | |
172 # verify parents | |
173 (p1, p2) = fl.parents(n) | |
174 if p1 not in nodes: | |
175 err(_("file %s:%s unknown parent 1 %s") % | |
176 (f, short(n), short(p1))) | |
177 if p2 not in nodes: | |
178 err(_("file %s:%s unknown parent 2 %s") % | |
179 (f, short(n), short(p1))) | |
180 nodes[n] = 1 | |
181 | |
3745
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3468
diff
changeset
|
182 # check renames |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3468
diff
changeset
|
183 try: |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3468
diff
changeset
|
184 rp = fl.renamed(n) |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3468
diff
changeset
|
185 if rp: |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3468
diff
changeset
|
186 fl2 = repo.file(rp[0]) |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3468
diff
changeset
|
187 rev = fl2.rev(rp[1]) |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3468
diff
changeset
|
188 except KeyboardInterrupt: |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3468
diff
changeset
|
189 repo.ui.warn(_("interrupted")) |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3468
diff
changeset
|
190 raise |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3468
diff
changeset
|
191 except Exception, inst: |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3468
diff
changeset
|
192 err(_("checking rename on file %s %s: %s") % (f, short(n), inst)) |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3468
diff
changeset
|
193 |
2802 | 194 # cross-check |
195 for node in filenodes[f]: | |
196 err(_("node %s in manifests not in %s") % (hex(node), f)) | |
197 | |
198 repo.ui.status(_("%d files, %d changesets, %d total revisions\n") % | |
199 (files, changesets, revisions)) | |
200 | |
201 if warnings[0]: | |
202 repo.ui.warn(_("%d warnings encountered!\n") % warnings[0]) | |
203 if errors[0]: | |
204 repo.ui.warn(_("%d integrity errors encountered!\n") % errors[0]) | |
205 return 1 | |
206 |