18 |
18 |
19 def _verify(repo): |
19 def _verify(repo): |
20 filelinkrevs = {} |
20 filelinkrevs = {} |
21 filenodes = {} |
21 filenodes = {} |
22 changesets = revisions = files = 0 |
22 changesets = revisions = files = 0 |
|
23 firstbad = [None] |
23 errors = [0] |
24 errors = [0] |
24 warnings = [0] |
25 warnings = [0] |
25 neededmanifests = {} |
26 neededmanifests = {} |
26 |
27 |
27 def err(msg): |
28 def err(linkrev, msg, filename=None): |
28 repo.ui.warn(msg + "\n") |
29 if linkrev != None: |
|
30 if firstbad[0] != None: |
|
31 firstbad[0] = min(firstbad[0], linkrev) |
|
32 else: |
|
33 firstbad[0] = linkrev |
|
34 else: |
|
35 linkrev = "?" |
|
36 msg = "%s: %s" % (linkrev, msg) |
|
37 if filename: |
|
38 msg = "%s@%s" % (filename, msg) |
|
39 repo.ui.warn(" " + msg + "\n") |
29 errors[0] += 1 |
40 errors[0] += 1 |
30 |
41 |
31 def warn(msg): |
42 def warn(msg): |
32 repo.ui.warn(msg + "\n") |
43 repo.ui.warn(msg + "\n") |
33 warnings[0] += 1 |
44 warnings[0] += 1 |
34 |
45 |
35 def checksize(obj, name): |
46 def checksize(obj, name): |
36 d = obj.checksize() |
47 d = obj.checksize() |
37 if d[0]: |
48 if d[0]: |
38 err(_("%s data length off by %d bytes") % (name, d[0])) |
49 err(None, _("data length off by %d bytes") % d[0], name) |
39 if d[1]: |
50 if d[1]: |
40 err(_("%s index contains %d extra bytes") % (name, d[1])) |
51 err(None, _("index contains %d extra bytes") % d[1], name) |
41 |
52 |
42 def checkversion(obj, name): |
53 def checkversion(obj, name): |
43 if obj.version != revlog.REVLOGV0: |
54 if obj.version != revlog.REVLOGV0: |
44 if not revlogv1: |
55 if not revlogv1: |
45 warn(_("warning: `%s' uses revlog format 1") % name) |
56 warn(_("warning: `%s' uses revlog format 1") % name) |
58 for i in xrange(repo.changelog.count()): |
69 for i in xrange(repo.changelog.count()): |
59 changesets += 1 |
70 changesets += 1 |
60 n = repo.changelog.node(i) |
71 n = repo.changelog.node(i) |
61 l = repo.changelog.linkrev(n) |
72 l = repo.changelog.linkrev(n) |
62 if l != i: |
73 if l != i: |
63 err(_("incorrect link (%d) for changeset revision %d") %(l, i)) |
74 err(i, _("incorrect link (%d) for changeset") %(l)) |
64 if n in seen: |
75 if n in seen: |
65 err(_("duplicate changeset at revision %d") % i) |
76 err(i, _("duplicates changeset at revision %d") % seen[n]) |
66 seen[n] = 1 |
77 seen[n] = i |
67 |
78 |
68 for p in repo.changelog.parents(n): |
79 for p in repo.changelog.parents(n): |
69 if p not in repo.changelog.nodemap: |
80 if p not in repo.changelog.nodemap: |
70 err(_("changeset %s has unknown parent %s") % |
81 err(i, _("changeset has unknown parent %s") % short(p)) |
71 (short(n), short(p))) |
|
72 try: |
82 try: |
73 changes = repo.changelog.read(n) |
83 changes = repo.changelog.read(n) |
74 except KeyboardInterrupt: |
84 except KeyboardInterrupt: |
75 repo.ui.warn(_("interrupted")) |
85 repo.ui.warn(_("interrupted")) |
76 raise |
86 raise |
77 except Exception, inst: |
87 except Exception, inst: |
78 err(_("unpacking changeset %s: %s") % (short(n), inst)) |
88 err(i, _("unpacking changeset: %s") % inst) |
79 continue |
89 continue |
80 |
90 |
81 neededmanifests[changes[0]] = n |
91 if changes[0] not in neededmanifests: |
|
92 neededmanifests[changes[0]] = i |
82 |
93 |
83 for f in changes[3]: |
94 for f in changes[3]: |
84 filelinkrevs.setdefault(f, []).append(i) |
95 filelinkrevs.setdefault(f, []).append(i) |
85 |
96 |
86 seen = {} |
97 seen = {} |
91 for i in xrange(repo.manifest.count()): |
102 for i in xrange(repo.manifest.count()): |
92 n = repo.manifest.node(i) |
103 n = repo.manifest.node(i) |
93 l = repo.manifest.linkrev(n) |
104 l = repo.manifest.linkrev(n) |
94 |
105 |
95 if l < 0 or l >= repo.changelog.count(): |
106 if l < 0 or l >= repo.changelog.count(): |
96 err(_("bad manifest link (%d) at revision %d") % (l, i)) |
107 err(None, _("bad link (%d) at manifest revision %d") % (l, i)) |
97 |
108 |
98 if n in neededmanifests: |
109 if n in neededmanifests: |
99 del neededmanifests[n] |
110 del neededmanifests[n] |
100 |
111 |
101 if n in seen: |
112 if n in seen: |
102 err(_("duplicate manifest at revision %d") % i) |
113 err(l, _("duplicates manifest from %d") % seen[n]) |
103 |
114 |
104 seen[n] = 1 |
115 seen[n] = l |
105 |
116 |
106 for p in repo.manifest.parents(n): |
117 for p in repo.manifest.parents(n): |
107 if p not in repo.manifest.nodemap: |
118 if p not in repo.manifest.nodemap: |
108 err(_("manifest %s has unknown parent %s") % |
119 err(l, _("manifest has unknown parent %s") % short(p)) |
109 (short(n), short(p))) |
|
110 |
120 |
111 try: |
121 try: |
112 for f, fn in repo.manifest.readdelta(n).iteritems(): |
122 for f, fn in repo.manifest.readdelta(n).iteritems(): |
113 filenodes.setdefault(f, {})[fn] = 1 |
123 fns = filenodes.setdefault(f, {}) |
|
124 if fn not in fns: |
|
125 fns[fn] = n |
114 except KeyboardInterrupt: |
126 except KeyboardInterrupt: |
115 repo.ui.warn(_("interrupted")) |
127 repo.ui.warn(_("interrupted")) |
116 raise |
128 raise |
117 except Exception, inst: |
129 except Exception, inst: |
118 err(_("reading delta for manifest %s: %s") % (short(n), inst)) |
130 err(l, _("reading manifest delta: %s") % inst) |
119 continue |
131 continue |
120 |
132 |
121 repo.ui.status(_("crosschecking files in changesets and manifests\n")) |
133 repo.ui.status(_("crosschecking files in changesets and manifests\n")) |
122 |
134 |
123 for m, c in neededmanifests.items(): |
135 nm = neededmanifests.items() |
124 err(_("Changeset %s refers to unknown manifest %s") % |
136 nm.sort() |
125 (short(m), short(c))) |
137 for m, c in nm: |
126 del neededmanifests |
138 err(m, _("changeset refers to unknown manifest %s") % short(c)) |
|
139 del neededmanifests, nm |
127 |
140 |
128 for f in filenodes: |
141 for f in filenodes: |
129 if f not in filelinkrevs: |
142 if f not in filelinkrevs: |
130 err(_("file %s in manifest but not in changesets") % f) |
143 lrs = [repo.manifest.linkrev(n) for n in filenodes[f]] |
|
144 lrs.sort() |
|
145 err(lrs[0], _("in manifest but not in changeset"), f) |
131 |
146 |
132 for f in filelinkrevs: |
147 for f in filelinkrevs: |
133 if f not in filenodes: |
148 if f not in filenodes: |
134 err(_("file %s in changeset but not in manifest") % f) |
149 lr = filelinkrevs[f][0] |
|
150 err(lr, _("in changeset but not in manifest"), f) |
135 |
151 |
136 repo.ui.status(_("checking files\n")) |
152 repo.ui.status(_("checking files\n")) |
137 ff = filenodes.keys() |
153 ff = filenodes.keys() |
138 ff.sort() |
154 ff.sort() |
139 for f in ff: |
155 for f in ff: |
140 if f == "/dev/null": |
156 if f == "/dev/null": |
141 continue |
157 continue |
142 files += 1 |
158 files += 1 |
143 if not f: |
159 if not f: |
144 err(_("file without name in manifest %s") % short(n)) |
160 lr = repo.manifest.linkrev(filenodes[f][0]) |
|
161 err(lr, _("file without name in manifest %s") % short(ff[n])) |
145 continue |
162 continue |
146 fl = repo.file(f) |
163 fl = repo.file(f) |
147 checkversion(fl, f) |
164 checkversion(fl, f) |
148 checksize(fl, f) |
165 checksize(fl, f) |
149 |
166 |
|
167 seen = {} |
150 nodes = {nullid: 1} |
168 nodes = {nullid: 1} |
151 seen = {} |
|
152 for i in xrange(fl.count()): |
169 for i in xrange(fl.count()): |
153 revisions += 1 |
170 revisions += 1 |
154 n = fl.node(i) |
171 n = fl.node(i) |
|
172 flr = fl.linkrev(n) |
|
173 |
|
174 if flr not in filelinkrevs.get(f, []): |
|
175 if flr < 0 or flr >= repo.changelog.count(): |
|
176 err(None, _("rev %d point to nonexistent changeset %d") |
|
177 % (i, flr), f) |
|
178 else: |
|
179 err(None, _("rev %d points to unexpected changeset %d") |
|
180 % (i, flr), f) |
|
181 if f in filelinkrevs: |
|
182 warn(_(" (expected %s)") % filelinkrevs[f][0]) |
|
183 flr = None # can't be trusted |
|
184 else: |
|
185 filelinkrevs[f].remove(flr) |
155 |
186 |
156 if n in seen: |
187 if n in seen: |
157 err(_("%s: duplicate revision %d") % (f, i)) |
188 err(flr, _("duplicate revision %d") % i, f) |
158 if n not in filenodes[f]: |
189 if n not in filenodes[f]: |
159 err(_("%s: %d:%s not in manifests") % (f, i, short(n))) |
190 err(flr, _("%s not in manifests") % (short(n)), f) |
160 else: |
191 else: |
161 del filenodes[f][n] |
192 del filenodes[f][n] |
162 |
|
163 flr = fl.linkrev(n) |
|
164 if flr not in filelinkrevs.get(f, []): |
|
165 err(_("%s:%s points to unexpected changeset %d") |
|
166 % (f, short(n), flr)) |
|
167 err(_("expecting one of %s" % filelinkrevs.get(f, []))) |
|
168 else: |
|
169 filelinkrevs[f].remove(flr) |
|
170 |
193 |
171 # verify contents |
194 # verify contents |
172 try: |
195 try: |
173 t = fl.read(n) |
196 t = fl.read(n) |
174 except KeyboardInterrupt: |
197 except KeyboardInterrupt: |
175 repo.ui.warn(_("interrupted")) |
198 repo.ui.warn(_("interrupted")) |
176 raise |
199 raise |
177 except Exception, inst: |
200 except Exception, inst: |
178 err(_("unpacking file %s %s: %s") % (f, short(n), inst)) |
201 err(flr, _("unpacking %s: %s") % (short(n), inst), f) |
179 |
202 |
180 # verify parents |
203 # verify parents |
181 (p1, p2) = fl.parents(n) |
204 try: |
182 if p1 not in nodes: |
205 (p1, p2) = fl.parents(n) |
183 err(_("file %s:%s unknown parent 1 %s") % |
206 if p1 not in nodes: |
184 (f, short(n), short(p1))) |
207 err(flr, _("unknown parent 1 %s of %s") % |
185 if p2 not in nodes: |
208 (short(p1), short(n)), f) |
186 err(_("file %s:%s unknown parent 2 %s") % |
209 if p2 not in nodes: |
187 (f, short(n), short(p1))) |
210 err(flr, _("unknown parent 2 %s of %s") % |
|
211 (short(p2), short(p1)), f) |
|
212 except KeyboardInterrupt: |
|
213 repo.ui.warn(_("interrupted")) |
|
214 raise |
|
215 except Exception, inst: |
|
216 err(flr, _("checking parents of %s: %s") % (short(n), inst), f) |
188 nodes[n] = 1 |
217 nodes[n] = 1 |
189 |
218 |
190 # check renames |
219 # check renames |
191 try: |
220 try: |
192 rp = fl.renamed(n) |
221 rp = fl.renamed(n) |
195 rev = fl2.rev(rp[1]) |
224 rev = fl2.rev(rp[1]) |
196 except KeyboardInterrupt: |
225 except KeyboardInterrupt: |
197 repo.ui.warn(_("interrupted")) |
226 repo.ui.warn(_("interrupted")) |
198 raise |
227 raise |
199 except Exception, inst: |
228 except Exception, inst: |
200 err(_("checking rename on file %s %s: %s") % (f, short(n), inst)) |
229 err(flr, _("checking rename of %s: %s") % |
|
230 (short(n), inst), f) |
201 |
231 |
202 # cross-check |
232 # cross-check |
203 for node in filenodes[f]: |
233 fns = [(repo.manifest.linkrev(filenodes[f][n]), n) |
204 err(_("node %s in manifests not in %s") % (hex(node), f)) |
234 for n in filenodes[f]] |
|
235 fns.sort() |
|
236 for lr, node in fns: |
|
237 err(lr, _("%s in manifests not found") % short(node), f) |
205 |
238 |
206 repo.ui.status(_("%d files, %d changesets, %d total revisions\n") % |
239 repo.ui.status(_("%d files, %d changesets, %d total revisions\n") % |
207 (files, changesets, revisions)) |
240 (files, changesets, revisions)) |
208 |
241 |
209 if warnings[0]: |
242 if warnings[0]: |
210 repo.ui.warn(_("%d warnings encountered!\n") % warnings[0]) |
243 repo.ui.warn(_("%d warnings encountered!\n") % warnings[0]) |
211 if errors[0]: |
244 if errors[0]: |
212 repo.ui.warn(_("%d integrity errors encountered!\n") % errors[0]) |
245 repo.ui.warn(_("%d integrity errors encountered!\n") % errors[0]) |
|
246 if firstbad[0]: |
|
247 repo.ui.warn(_("(first damaged changeset appears to be %d)\n") |
|
248 % firstbad[0]) |
213 return 1 |
249 return 1 |
214 |
250 |