62 |
62 |
63 def warn(self, msg): |
63 def warn(self, msg): |
64 self.ui.warn(msg + "\n") |
64 self.ui.warn(msg + "\n") |
65 self.warnings[0] += 1 |
65 self.warnings[0] += 1 |
66 |
66 |
|
67 def err(self, linkrev, msg, filename=None): |
|
68 if linkrev is not None: |
|
69 self.badrevs.add(linkrev) |
|
70 else: |
|
71 linkrev = '?' |
|
72 msg = "%s: %s" % (linkrev, msg) |
|
73 if filename: |
|
74 msg = "%s@%s" % (filename, msg) |
|
75 self.ui.warn(" " + msg + "\n") |
|
76 self.errors[0] += 1 |
|
77 |
67 def verify(self): |
78 def verify(self): |
68 repo = self.repo |
79 repo = self.repo |
69 mflinkrevs = {} |
80 mflinkrevs = {} |
70 filelinkrevs = {} |
81 filelinkrevs = {} |
71 filenodes = {} |
82 filenodes = {} |
79 lrugetctx = self.lrugetctx |
90 lrugetctx = self.lrugetctx |
80 |
91 |
81 if not repo.url().startswith('file:'): |
92 if not repo.url().startswith('file:'): |
82 raise error.Abort(_("cannot verify bundle or remote repos")) |
93 raise error.Abort(_("cannot verify bundle or remote repos")) |
83 |
94 |
84 def err(linkrev, msg, filename=None): |
|
85 if linkrev is not None: |
|
86 badrevs.add(linkrev) |
|
87 else: |
|
88 linkrev = '?' |
|
89 msg = "%s: %s" % (linkrev, msg) |
|
90 if filename: |
|
91 msg = "%s@%s" % (filename, msg) |
|
92 ui.warn(" " + msg + "\n") |
|
93 errors[0] += 1 |
|
94 |
95 |
95 def exc(linkrev, msg, inst, filename=None): |
96 def exc(linkrev, msg, inst, filename=None): |
96 if isinstance(inst, KeyboardInterrupt): |
97 if isinstance(inst, KeyboardInterrupt): |
97 ui.warn(_("interrupted")) |
98 ui.warn(_("interrupted")) |
98 raise |
99 raise |
99 if not str(inst): |
100 if not str(inst): |
100 inst = repr(inst) |
101 inst = repr(inst) |
101 err(linkrev, "%s: %s" % (msg, inst), filename) |
102 self.err(linkrev, "%s: %s" % (msg, inst), filename) |
102 |
103 |
103 |
104 |
104 def checklog(obj, name, linkrev): |
105 def checklog(obj, name, linkrev): |
105 if not len(obj) and (havecl or havemf): |
106 if not len(obj) and (havecl or havemf): |
106 err(linkrev, _("empty or missing %s") % name) |
107 self.err(linkrev, _("empty or missing %s") % name) |
107 return |
108 return |
108 |
109 |
109 d = obj.checksize() |
110 d = obj.checksize() |
110 if d[0]: |
111 if d[0]: |
111 err(None, _("data length off by %d bytes") % d[0], name) |
112 self.err(None, _("data length off by %d bytes") % d[0], name) |
112 if d[1]: |
113 if d[1]: |
113 err(None, _("index contains %d extra bytes") % d[1], name) |
114 self.err(None, _("index contains %d extra bytes") % d[1], name) |
114 |
115 |
115 if obj.version != revlog.REVLOGV0: |
116 if obj.version != revlog.REVLOGV0: |
116 if not revlogv1: |
117 if not revlogv1: |
117 self.warn(_("warning: `%s' uses revlog format 1") % name) |
118 self.warn(_("warning: `%s' uses revlog format 1") % name) |
118 elif revlogv1: |
119 elif revlogv1: |
123 if lr < 0 or (havecl and lr not in linkrevs): |
124 if lr < 0 or (havecl and lr not in linkrevs): |
124 if lr < 0 or lr >= len(cl): |
125 if lr < 0 or lr >= len(cl): |
125 msg = _("rev %d points to nonexistent changeset %d") |
126 msg = _("rev %d points to nonexistent changeset %d") |
126 else: |
127 else: |
127 msg = _("rev %d points to unexpected changeset %d") |
128 msg = _("rev %d points to unexpected changeset %d") |
128 err(None, msg % (i, lr), f) |
129 self.err(None, msg % (i, lr), f) |
129 if linkrevs: |
130 if linkrevs: |
130 if f and len(linkrevs) > 1: |
131 if f and len(linkrevs) > 1: |
131 try: |
132 try: |
132 # attempt to filter down to real linkrevs |
133 # attempt to filter down to real linkrevs |
133 linkrevs = [l for l in linkrevs |
134 linkrevs = [l for l in linkrevs |
139 lr = None # can't be trusted |
140 lr = None # can't be trusted |
140 |
141 |
141 try: |
142 try: |
142 p1, p2 = obj.parents(node) |
143 p1, p2 = obj.parents(node) |
143 if p1 not in seen and p1 != nullid: |
144 if p1 not in seen and p1 != nullid: |
144 err(lr, _("unknown parent 1 %s of %s") % |
145 self.err(lr, _("unknown parent 1 %s of %s") % |
145 (short(p1), short(node)), f) |
146 (short(p1), short(node)), f) |
146 if p2 not in seen and p2 != nullid: |
147 if p2 not in seen and p2 != nullid: |
147 err(lr, _("unknown parent 2 %s of %s") % |
148 self.err(lr, _("unknown parent 2 %s of %s") % |
148 (short(p2), short(node)), f) |
149 (short(p2), short(node)), f) |
149 except Exception as inst: |
150 except Exception as inst: |
150 exc(lr, _("checking parents of %s") % short(node), inst, f) |
151 exc(lr, _("checking parents of %s") % short(node), inst, f) |
151 |
152 |
152 if node in seen: |
153 if node in seen: |
153 err(lr, _("duplicate revision %d (%d)") % (i, seen[node]), f) |
154 self.err(lr, _("duplicate revision %d (%d)") % |
|
155 (i, seen[node]), f) |
154 seen[node] = i |
156 seen[node] = i |
155 return lr |
157 return lr |
156 |
158 |
157 if os.path.exists(repo.sjoin("journal")): |
159 if os.path.exists(repo.sjoin("journal")): |
158 ui.warn(_("abandoned transaction found - run hg recover\n")) |
160 ui.warn(_("abandoned transaction found - run hg recover\n")) |
199 n = mf.node(i) |
201 n = mf.node(i) |
200 lr = checkentry(mf, i, n, seen, mflinkrevs.get(n, []), "manifest") |
202 lr = checkentry(mf, i, n, seen, mflinkrevs.get(n, []), "manifest") |
201 if n in mflinkrevs: |
203 if n in mflinkrevs: |
202 del mflinkrevs[n] |
204 del mflinkrevs[n] |
203 else: |
205 else: |
204 err(lr, _("%s not in changesets") % short(n), "manifest") |
206 self.err(lr, _("%s not in changesets") % short(n), "manifest") |
205 |
207 |
206 try: |
208 try: |
207 for f, fn in mf.readdelta(n).iteritems(): |
209 for f, fn in mf.readdelta(n).iteritems(): |
208 if not f: |
210 if not f: |
209 err(lr, _("file without name in manifest")) |
211 self.err(lr, _("file without name in manifest")) |
210 elif f != "/dev/null": # ignore this in very old repos |
212 elif f != "/dev/null": # ignore this in very old repos |
211 if _validpath(repo, f): |
213 if _validpath(repo, f): |
212 filenodes.setdefault( |
214 filenodes.setdefault( |
213 _normpath(f), {}).setdefault(fn, lr) |
215 _normpath(f), {}).setdefault(fn, lr) |
214 except Exception as inst: |
216 except Exception as inst: |
224 for c in mflinkrevs[m]]): |
226 for c in mflinkrevs[m]]): |
225 count += 1 |
227 count += 1 |
226 if m == nullid: |
228 if m == nullid: |
227 continue |
229 continue |
228 ui.progress(_('crosschecking'), count, total=total) |
230 ui.progress(_('crosschecking'), count, total=total) |
229 err(c, _("changeset refers to unknown manifest %s") % short(m)) |
231 self.err(c, _("changeset refers to unknown manifest %s") % |
|
232 short(m)) |
230 mflinkrevs = None # del is bad here due to scope issues |
233 mflinkrevs = None # del is bad here due to scope issues |
231 |
234 |
232 for f in sorted(filelinkrevs): |
235 for f in sorted(filelinkrevs): |
233 count += 1 |
236 count += 1 |
234 ui.progress(_('crosschecking'), count, total=total) |
237 ui.progress(_('crosschecking'), count, total=total) |
235 if f not in filenodes: |
238 if f not in filenodes: |
236 lr = filelinkrevs[f][0] |
239 lr = filelinkrevs[f][0] |
237 err(lr, _("in changeset but not in manifest"), f) |
240 self.err(lr, _("in changeset but not in manifest"), f) |
238 |
241 |
239 if havecl: |
242 if havecl: |
240 for f in sorted(filenodes): |
243 for f in sorted(filenodes): |
241 count += 1 |
244 count += 1 |
242 ui.progress(_('crosschecking'), count, total=total) |
245 ui.progress(_('crosschecking'), count, total=total) |
244 try: |
247 try: |
245 fl = repo.file(f) |
248 fl = repo.file(f) |
246 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]]) |
249 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]]) |
247 except Exception: |
250 except Exception: |
248 lr = None |
251 lr = None |
249 err(lr, _("in manifest but not in changeset"), f) |
252 self.err(lr, _("in manifest but not in changeset"), f) |
250 |
253 |
251 ui.progress(_('crosschecking'), None) |
254 ui.progress(_('crosschecking'), None) |
252 |
255 |
253 ui.status(_("checking files\n")) |
256 ui.status(_("checking files\n")) |
254 |
257 |
255 storefiles = set() |
258 storefiles = set() |
256 for f, f2, size in repo.store.datafiles(): |
259 for f, f2, size in repo.store.datafiles(): |
257 if not f: |
260 if not f: |
258 err(None, _("cannot decode filename '%s'") % f2) |
261 self.err(None, _("cannot decode filename '%s'") % f2) |
259 elif size > 0 or not revlogv1: |
262 elif size > 0 or not revlogv1: |
260 storefiles.add(_normpath(f)) |
263 storefiles.add(_normpath(f)) |
261 |
264 |
262 files = sorted(set(filenodes) | set(filelinkrevs)) |
265 files = sorted(set(filenodes) | set(filelinkrevs)) |
263 total = len(files) |
266 total = len(files) |
294 revisions += 1 |
297 revisions += 1 |
295 n = fl.node(i) |
298 n = fl.node(i) |
296 lr = checkentry(fl, i, n, seen, linkrevs, f) |
299 lr = checkentry(fl, i, n, seen, linkrevs, f) |
297 if f in filenodes: |
300 if f in filenodes: |
298 if havemf and n not in filenodes[f]: |
301 if havemf and n not in filenodes[f]: |
299 err(lr, _("%s not in manifests") % (short(n)), f) |
302 self.err(lr, _("%s not in manifests") % (short(n)), f) |
300 else: |
303 else: |
301 del filenodes[f][n] |
304 del filenodes[f][n] |
302 |
305 |
303 # verify contents |
306 # verify contents |
304 try: |
307 try: |
305 l = len(fl.read(n)) |
308 l = len(fl.read(n)) |
306 rp = fl.renamed(n) |
309 rp = fl.renamed(n) |
307 if l != fl.size(i): |
310 if l != fl.size(i): |
308 if len(fl.revision(n)) != fl.size(i): |
311 if len(fl.revision(n)) != fl.size(i): |
309 err(lr, _("unpacked size is %s, %s expected") % |
312 self.err(lr, _("unpacked size is %s, %s expected") % |
310 (l, fl.size(i)), f) |
313 (l, fl.size(i)), f) |
311 except error.CensoredNodeError: |
314 except error.CensoredNodeError: |
312 # experimental config: censor.policy |
315 # experimental config: censor.policy |
313 if ui.config("censor", "policy", "abort") == "abort": |
316 if ui.config("censor", "policy", "abort") == "abort": |
314 err(lr, _("censored file data"), f) |
317 self.err(lr, _("censored file data"), f) |
315 except Exception as inst: |
318 except Exception as inst: |
316 exc(lr, _("unpacking %s") % short(n), inst, f) |
319 exc(lr, _("unpacking %s") % short(n), inst, f) |
317 |
320 |
318 # check renames |
321 # check renames |
319 try: |
322 try: |
328 if not found: |
331 if not found: |
329 self.warn(_("warning: copy source of '%s' not" |
332 self.warn(_("warning: copy source of '%s' not" |
330 " in parents of %s") % (f, ctx)) |
333 " in parents of %s") % (f, ctx)) |
331 fl2 = repo.file(rp[0]) |
334 fl2 = repo.file(rp[0]) |
332 if not len(fl2): |
335 if not len(fl2): |
333 err(lr, _("empty or missing copy source revlog " |
336 self.err(lr, _("empty or missing copy source " |
334 "%s:%s") % (rp[0], short(rp[1])), f) |
337 "revlog %s:%s") % (rp[0], short(rp[1])), f) |
335 elif rp[1] == nullid: |
338 elif rp[1] == nullid: |
336 ui.note(_("warning: %s@%s: copy source" |
339 ui.note(_("warning: %s@%s: copy source" |
337 " revision is nullid %s:%s\n") |
340 " revision is nullid %s:%s\n") |
338 % (f, lr, rp[0], short(rp[1]))) |
341 % (f, lr, rp[0], short(rp[1]))) |
339 else: |
342 else: |
343 |
346 |
344 # cross-check |
347 # cross-check |
345 if f in filenodes: |
348 if f in filenodes: |
346 fns = [(lr, n) for n, lr in filenodes[f].iteritems()] |
349 fns = [(lr, n) for n, lr in filenodes[f].iteritems()] |
347 for lr, node in sorted(fns): |
350 for lr, node in sorted(fns): |
348 err(lr, _("%s in manifests not found") % short(node), f) |
351 self.err(lr, _("%s in manifests not found") % short(node), |
|
352 f) |
349 ui.progress(_('checking'), None) |
353 ui.progress(_('checking'), None) |
350 |
354 |
351 for f in storefiles: |
355 for f in storefiles: |
352 self.warn(_("warning: orphan revlog '%s'") % f) |
356 self.warn(_("warning: orphan revlog '%s'") % f) |
353 |
357 |