Mercurial > hg
annotate mercurial/verify.py @ 6034:83633602e2c5
qinit -c: add ^\.hg and ^\.mq to .hgignore
author | Alexis S. L. Carvalho <alexis@cecm.usp.br> |
---|---|
date | Fri, 08 Feb 2008 18:07:55 -0200 |
parents | 29be4228303b |
children | ceaa752fa316 |
rev | line source |
---|---|
2778 | 1 # verify.py - repository integrity checking for Mercurial |
2 # | |
4635
63b9d2deed48
Updated copyright notices and add "and others" to "hg version"
Thomas Arendsen Hein <thomas@intevation.de>
parents:
4395
diff
changeset
|
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com> |
2778 | 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 * | |
3891 | 9 from i18n import _ |
5175
012dbf88b9b2
remove unneeded imports of mdiff
Matt Mackall <mpm@selenic.com>
parents:
4915
diff
changeset
|
10 import revlog |
2778 | 11 |
12 def verify(repo): | |
4915
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4635
diff
changeset
|
13 lock = repo.lock() |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4635
diff
changeset
|
14 try: |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4635
diff
changeset
|
15 return _verify(repo) |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4635
diff
changeset
|
16 finally: |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4635
diff
changeset
|
17 del lock |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4635
diff
changeset
|
18 |
97b734fb9c6f
Use try/finally pattern to cleanup locks and transactions
Matt Mackall <mpm@selenic.com>
parents:
4635
diff
changeset
|
19 def _verify(repo): |
2778 | 20 filelinkrevs = {} |
21 filenodes = {} | |
22 changesets = revisions = files = 0 | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
23 firstbad = [None] |
2778 | 24 errors = [0] |
25 warnings = [0] | |
26 neededmanifests = {} | |
27 | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
28 def err(linkrev, msg, filename=None): |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
29 if linkrev != None: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
30 if firstbad[0] != None: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
31 firstbad[0] = min(firstbad[0], linkrev) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
32 else: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
33 firstbad[0] = linkrev |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
34 else: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
35 linkrev = "?" |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
36 msg = "%s: %s" % (linkrev, msg) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
37 if filename: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
38 msg = "%s@%s" % (filename, msg) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
39 repo.ui.warn(" " + msg + "\n") |
2778 | 40 errors[0] += 1 |
41 | |
42 def warn(msg): | |
43 repo.ui.warn(msg + "\n") | |
44 warnings[0] += 1 | |
45 | |
46 def checksize(obj, name): | |
47 d = obj.checksize() | |
48 if d[0]: | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
49 err(None, _("data length off by %d bytes") % d[0], name) |
2778 | 50 if d[1]: |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
51 err(None, _("index contains %d extra bytes") % d[1], name) |
2778 | 52 |
53 def checkversion(obj, name): | |
54 if obj.version != revlog.REVLOGV0: | |
55 if not revlogv1: | |
56 warn(_("warning: `%s' uses revlog format 1") % name) | |
57 elif revlogv1: | |
58 warn(_("warning: `%s' uses revlog format 0") % name) | |
59 | |
4258
b11a2fb59cf5
revlog: simplify revlog version handling
Matt Mackall <mpm@selenic.com>
parents:
3891
diff
changeset
|
60 revlogv1 = repo.changelog.version != revlog.REVLOGV0 |
b11a2fb59cf5
revlog: simplify revlog version handling
Matt Mackall <mpm@selenic.com>
parents:
3891
diff
changeset
|
61 if repo.ui.verbose or not revlogv1: |
2778 | 62 repo.ui.status(_("repository uses revlog format %d\n") % |
63 (revlogv1 and 1 or 0)) | |
64 | |
65 seen = {} | |
66 repo.ui.status(_("checking changesets\n")) | |
67 checksize(repo.changelog, "changelog") | |
68 | |
3473
0e68608bd11d
use xrange instead of range
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
3196
diff
changeset
|
69 for i in xrange(repo.changelog.count()): |
2778 | 70 changesets += 1 |
71 n = repo.changelog.node(i) | |
72 l = repo.changelog.linkrev(n) | |
73 if l != i: | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
74 err(i, _("incorrect link (%d) for changeset") %(l)) |
2778 | 75 if n in seen: |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
76 err(i, _("duplicates changeset at revision %d") % seen[n]) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
77 seen[n] = i |
2778 | 78 |
79 for p in repo.changelog.parents(n): | |
80 if p not in repo.changelog.nodemap: | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
81 err(i, _("changeset has unknown parent %s") % short(p)) |
2778 | 82 try: |
83 changes = repo.changelog.read(n) | |
84 except KeyboardInterrupt: | |
85 repo.ui.warn(_("interrupted")) | |
86 raise | |
87 except Exception, inst: | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
88 err(i, _("unpacking changeset: %s") % inst) |
2778 | 89 continue |
90 | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
91 if changes[0] not in neededmanifests: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
92 neededmanifests[changes[0]] = i |
2778 | 93 |
94 for f in changes[3]: | |
95 filelinkrevs.setdefault(f, []).append(i) | |
96 | |
97 seen = {} | |
98 repo.ui.status(_("checking manifests\n")) | |
99 checkversion(repo.manifest, "manifest") | |
100 checksize(repo.manifest, "manifest") | |
101 | |
3473
0e68608bd11d
use xrange instead of range
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
3196
diff
changeset
|
102 for i in xrange(repo.manifest.count()): |
2778 | 103 n = repo.manifest.node(i) |
104 l = repo.manifest.linkrev(n) | |
105 | |
106 if l < 0 or l >= repo.changelog.count(): | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
107 err(None, _("bad link (%d) at manifest revision %d") % (l, i)) |
2778 | 108 |
109 if n in neededmanifests: | |
110 del neededmanifests[n] | |
111 | |
112 if n in seen: | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
113 err(l, _("duplicates manifest from %d") % seen[n]) |
2778 | 114 |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
115 seen[n] = l |
2778 | 116 |
117 for p in repo.manifest.parents(n): | |
118 if p not in repo.manifest.nodemap: | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
119 err(l, _("manifest has unknown parent %s") % short(p)) |
2778 | 120 |
121 try: | |
3196
f3b939444c72
Abstract manifest block parsing.
Brendan Cully <brendan@kublai.com>
parents:
2778
diff
changeset
|
122 for f, fn in repo.manifest.readdelta(n).iteritems(): |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
123 fns = filenodes.setdefault(f, {}) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
124 if fn not in fns: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
125 fns[fn] = n |
2778 | 126 except KeyboardInterrupt: |
127 repo.ui.warn(_("interrupted")) | |
128 raise | |
129 except Exception, inst: | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
130 err(l, _("reading manifest delta: %s") % inst) |
2778 | 131 continue |
132 | |
133 repo.ui.status(_("crosschecking files in changesets and manifests\n")) | |
134 | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
135 nm = neededmanifests.items() |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
136 nm.sort() |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
137 for m, c in nm: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
138 err(m, _("changeset refers to unknown manifest %s") % short(c)) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
139 del neededmanifests, nm |
2778 | 140 |
141 for f in filenodes: | |
142 if f not in filelinkrevs: | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
143 lrs = [repo.manifest.linkrev(n) for n in filenodes[f]] |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
144 lrs.sort() |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
145 err(lrs[0], _("in manifest but not in changeset"), f) |
2778 | 146 |
147 for f in filelinkrevs: | |
148 if f not in filenodes: | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
149 lr = filelinkrevs[f][0] |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
150 err(lr, _("in changeset but not in manifest"), f) |
2778 | 151 |
152 repo.ui.status(_("checking files\n")) | |
153 ff = filenodes.keys() | |
154 ff.sort() | |
155 for f in ff: | |
156 if f == "/dev/null": | |
157 continue | |
158 files += 1 | |
159 if not f: | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
160 lr = repo.manifest.linkrev(filenodes[f][0]) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
161 err(lr, _("file without name in manifest %s") % short(ff[n])) |
2778 | 162 continue |
163 fl = repo.file(f) | |
164 checkversion(fl, f) | |
165 checksize(fl, f) | |
166 | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
167 seen = {} |
2778 | 168 nodes = {nullid: 1} |
3473
0e68608bd11d
use xrange instead of range
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
3196
diff
changeset
|
169 for i in xrange(fl.count()): |
2778 | 170 revisions += 1 |
171 n = fl.node(i) | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
172 flr = fl.linkrev(n) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
173 |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
174 if flr not in filelinkrevs.get(f, []): |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
175 if flr < 0 or flr >= repo.changelog.count(): |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
176 err(None, _("rev %d point to nonexistent changeset %d") |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
177 % (i, flr), f) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
178 else: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
179 err(None, _("rev %d points to unexpected changeset %d") |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
180 % (i, flr), f) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
181 if f in filelinkrevs: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
182 warn(_(" (expected %s)") % filelinkrevs[f][0]) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
183 flr = None # can't be trusted |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
184 else: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
185 filelinkrevs[f].remove(flr) |
2778 | 186 |
187 if n in seen: | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
188 err(flr, _("duplicate revision %d") % i, f) |
2778 | 189 if n not in filenodes[f]: |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
190 err(flr, _("%s not in manifests") % (short(n)), f) |
2778 | 191 else: |
192 del filenodes[f][n] | |
193 | |
194 # verify contents | |
195 try: | |
196 t = fl.read(n) | |
197 except KeyboardInterrupt: | |
198 repo.ui.warn(_("interrupted")) | |
199 raise | |
200 except Exception, inst: | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
201 err(flr, _("unpacking %s: %s") % (short(n), inst), f) |
2778 | 202 |
203 # verify parents | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
204 try: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
205 (p1, p2) = fl.parents(n) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
206 if p1 not in nodes: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
207 err(flr, _("unknown parent 1 %s of %s") % |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
208 (short(p1), short(n)), f) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
209 if p2 not in nodes: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
210 err(flr, _("unknown parent 2 %s of %s") % |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
211 (short(p2), short(p1)), f) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
212 except KeyboardInterrupt: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
213 repo.ui.warn(_("interrupted")) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
214 raise |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
215 except Exception, inst: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
216 err(flr, _("checking parents of %s: %s") % (short(n), inst), f) |
2778 | 217 nodes[n] = 1 |
218 | |
3744
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3473
diff
changeset
|
219 # check renames |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3473
diff
changeset
|
220 try: |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3473
diff
changeset
|
221 rp = fl.renamed(n) |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3473
diff
changeset
|
222 if rp: |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3473
diff
changeset
|
223 fl2 = repo.file(rp[0]) |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3473
diff
changeset
|
224 rev = fl2.rev(rp[1]) |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3473
diff
changeset
|
225 except KeyboardInterrupt: |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3473
diff
changeset
|
226 repo.ui.warn(_("interrupted")) |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3473
diff
changeset
|
227 raise |
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3473
diff
changeset
|
228 except Exception, inst: |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
229 err(flr, _("checking rename of %s: %s") % |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
230 (short(n), inst), f) |
3744
d626fc9e3985
verify: add rename link checking
Matt Mackall <mpm@selenic.com>
parents:
3473
diff
changeset
|
231 |
2778 | 232 # cross-check |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
233 fns = [(repo.manifest.linkrev(filenodes[f][n]), n) |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
234 for n in filenodes[f]] |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
235 fns.sort() |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
236 for lr, node in fns: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
237 err(lr, _("%s in manifests not found") % short(node), f) |
2778 | 238 |
239 repo.ui.status(_("%d files, %d changesets, %d total revisions\n") % | |
240 (files, changesets, revisions)) | |
241 | |
242 if warnings[0]: | |
243 repo.ui.warn(_("%d warnings encountered!\n") % warnings[0]) | |
244 if errors[0]: | |
245 repo.ui.warn(_("%d integrity errors encountered!\n") % errors[0]) | |
5313
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
246 if firstbad[0]: |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
247 repo.ui.warn(_("(first damaged changeset appears to be %d)\n") |
29be4228303b
verify: report first bad changeset
Matt Mackall <mpm@selenic.com>
parents:
5179
diff
changeset
|
248 % firstbad[0]) |
2778 | 249 return 1 |
250 |