comparison mercurial/verify.py @ 26900:d1c741644d25

verify: add a hook that can let extensions manipulate file lists Without a hook of this nature, narrowhg[0] clones always result in 'hg verify' reporting terrible damage to the entire repository history. With this hook, we can ignore files that aren't supposed to be in the clone, and then get an accurate report of any damage present (or not) in the repo. 0: https://bitbucket.org/Google/narrowhg
author Augie Fackler <augie@google.com>
date Wed, 04 Nov 2015 12:14:18 -0500
parents 56b2bcea2529
children 937e73a6e4ff
comparison
equal deleted inserted replaced
26899:5f88e092f82c 26900:d1c741644d25
32 # under hg < 2.4, convert didn't sanitize paths properly, so a 32 # under hg < 2.4, convert didn't sanitize paths properly, so a
33 # converted repo may contain repeated slashes 33 # converted repo may contain repeated slashes
34 while '//' in f: 34 while '//' in f:
35 f = f.replace('//', '/') 35 f = f.replace('//', '/')
36 return f 36 return f
37
38 def _validpath(repo, path):
39 """Returns False if a path should NOT be treated as part of a repo.
40
41 For all in-core cases, this returns True, as we have no way for a
42 path to be mentioned in the history but not actually be
43 relevant. For narrow clones, this is important because many
44 filelogs will be missing, and changelog entries may mention
45 modified files that are outside the narrow scope.
46 """
47 return True
37 48
38 def _verify(repo): 49 def _verify(repo):
39 repo = repo.unfiltered() 50 repo = repo.unfiltered()
40 mflinkrevs = {} 51 mflinkrevs = {}
41 filelinkrevs = {} 52 filelinkrevs = {}
152 changes = cl.read(n) 163 changes = cl.read(n)
153 if changes[0] != nullid: 164 if changes[0] != nullid:
154 mflinkrevs.setdefault(changes[0], []).append(i) 165 mflinkrevs.setdefault(changes[0], []).append(i)
155 refersmf = True 166 refersmf = True
156 for f in changes[3]: 167 for f in changes[3]:
157 filelinkrevs.setdefault(_normpath(f), []).append(i) 168 if _validpath(repo, f):
169 filelinkrevs.setdefault(_normpath(f), []).append(i)
158 except Exception as inst: 170 except Exception as inst:
159 refersmf = True 171 refersmf = True
160 exc(i, _("unpacking changeset %s") % short(n), inst) 172 exc(i, _("unpacking changeset %s") % short(n), inst)
161 ui.progress(_('checking'), None) 173 ui.progress(_('checking'), None)
162 174
179 try: 191 try:
180 for f, fn in mf.readdelta(n).iteritems(): 192 for f, fn in mf.readdelta(n).iteritems():
181 if not f: 193 if not f:
182 err(lr, _("file without name in manifest")) 194 err(lr, _("file without name in manifest"))
183 elif f != "/dev/null": # ignore this in very old repos 195 elif f != "/dev/null": # ignore this in very old repos
184 filenodes.setdefault(_normpath(f), {}).setdefault(fn, lr) 196 if _validpath(repo, f):
197 filenodes.setdefault(
198 _normpath(f), {}).setdefault(fn, lr)
185 except Exception as inst: 199 except Exception as inst:
186 exc(lr, _("reading manifest delta %s") % short(n), inst) 200 exc(lr, _("reading manifest delta %s") % short(n), inst)
187 ui.progress(_('checking'), None) 201 ui.progress(_('checking'), None)
188 202
189 ui.status(_("crosschecking files in changesets and manifests\n")) 203 ui.status(_("crosschecking files in changesets and manifests\n"))