##// END OF EJS Templates
check-code: detect and ban 'util.Abort'...
check-code: detect and ban 'util.Abort' We have seen the light, please use the new way.

File last commit:

r26587:56b2bcea default
r26588:b3f7516f default
Show More
repair.py
301 lines | 9.5 KiB | text/x-python | PythonLexer
Matt Mackall
strip: move strip code to a new repair module
r4702 # repair.py - functions for repository repair for mercurial
#
# Copyright 2005, 2006 Chris Mason <mason@suse.com>
# Copyright 2007 Matt Mackall
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Matt Mackall
strip: move strip code to a new repair module
r4702
Gregory Szorc
repair: use absolute_import
r25970 from __future__ import absolute_import
Alain Leufroy
repair: fix missing import...
r16440 import errno
Matt Mackall
strip: move strip code to a new repair module
r4702
Gregory Szorc
repair: use absolute_import
r25970 from .i18n import _
from .node import short
from . import (
bundle2,
changegroup,
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 error,
Gregory Szorc
repair: use absolute_import
r25970 exchange,
util,
)
Matt Mackall
strip: backout 73307643a09f (issue3077)
r15386 def _bundle(repo, bases, heads, node, suffix, compress=True):
Alexis S. L. Carvalho
repair.py: don't use nested functions.
r5905 """create a bundle with the specified revisions as a backup"""
Pierre-Yves David
strip: use bundle2 + cg2 by default when repository use general delta...
r26423 cgversion = '01'
if 'generaldelta' in repo.requirements:
cgversion = '02'
Eric Sumner
repair: add experimental option to write bundle2 files...
r23898
cg = changegroup.changegroupsubset(repo, bases, heads, 'strip',
version=cgversion)
FUJIWARA Katsunori
repair: make paths in "_bundle()" relative to ".hg"...
r20977 backupdir = "strip-backup"
vfs = repo.vfs
if not vfs.isdir(backupdir):
vfs.mkdir(backupdir)
Durham Goode
bundles: do not overwrite existing backup bundles (BC)...
r23835
# Include a hash of all the nodes in the filename for uniqueness
Yuya Nishihara
repair: use _hexlist() to build revset expression from binary nodes...
r25340 allcommits = repo.set('%ln::%ln', bases, heads)
Durham Goode
bundles: do not overwrite existing backup bundles (BC)...
r23835 allhashes = sorted(c.hex() for c in allcommits)
totalhash = util.sha1(''.join(allhashes)).hexdigest()
name = "%s/%s-%s-%s.hg" % (backupdir, short(node), totalhash[:8], suffix)
Pierre-Yves David
strip: compress bundle2 backup using BZ...
r26425 comp = None
Pierre-Yves David
strip: use bundle2 + cg2 by default when repository use general delta...
r26423 if cgversion != '01':
Pierre-Yves David
bundle2: rename format, parts and config to final names...
r24686 bundletype = "HG20"
Pierre-Yves David
strip: compress bundle2 backup using BZ...
r26425 if compress:
comp = 'BZ'
Eric Sumner
repair: add experimental option to write bundle2 files...
r23898 elif compress:
Nicolas Dumazet
repair: do not compress partial bundle if we do not keep it on disk...
r11791 bundletype = "HG10BZ"
else:
bundletype = "HG10UN"
Pierre-Yves David
strip: compress bundle2 backup using BZ...
r26425 return changegroup.writebundle(repo.ui, cg, name, bundletype, vfs,
compression=comp)
Matt Mackall
strip: move strip code to a new repair module
r4702
Alexis S. L. Carvalho
simplify revlog.strip interface and callers; add docstring...
r5910 def _collectfiles(repo, striprev):
"""find out the filelogs affected by the strip"""
Benoit Boissinot
repair: use set instead of dict
r8462 files = set()
Matt Mackall
strip: move strip code to a new repair module
r4702
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 for x in xrange(striprev, len(repo)):
Martin Geisler
repair: bulk update sets...
r8479 files.update(repo[x].files())
Alexis S. L. Carvalho
repair.py: split stripall into two functions; clean it up a bit
r5902
Benoit Boissinot
repair: use set instead of dict
r8462 return sorted(files)
Alexis S. L. Carvalho
repair.py: split stripall into two functions; clean it up a bit
r5902
Benoit Boissinot
strip: remove usage of extranodes...
r13702 def _collectbrokencsets(repo, files, striprev):
"""return the changesets which will be broken by the truncation"""
Matt Mackall
strip: simplify collectone
r13705 s = set()
Benoit Boissinot
strip: remove usage of extranodes...
r13702 def collectone(revlog):
Durham Goode
strip: add faster revlog strip computation...
r20074 _, brokenset = revlog.getstrippoint(striprev)
s.update([revlog.linkrev(r) for r in brokenset])
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909
Matt Mackall
strip: simplify collectone
r13705 collectone(repo.manifest)
for fname in files:
collectone(repo.file(fname))
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909
Matt Mackall
strip: simplify collectone
r13705 return s
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909
Jordi Gutiérrez Hermoso
strip: remove -b/--backup codepaths...
r22057 def strip(ui, repo, nodelist, backup=True, topic='backup'):
# Simple way to maintain backwards compatibility for this
# argument.
if backup in ['none', 'strip']:
backup = False
Pierre-Yves David
clfilter: strip logic should be unfiltered...
r18004 repo = repo.unfiltered()
Idan Kamara
localrepo: introduce destroying function
r18310 repo.destroying()
Joshua Redstone
strip: incrementally update the branchheads cache after a strip...
r17013
Alexis S. L. Carvalho
repair.py: rename chlog to cl
r5901 cl = repo.changelog
Idan Kamara
repair: remove undo files after strip
r16237 # TODO handle undo of merge sets
Wagner Bruna
strip: enhance repair.strip to receive a list of nodes (issue3299)...
r16252 if isinstance(nodelist, str):
nodelist = [nodelist]
striplist = [cl.rev(node) for node in nodelist]
striprev = min(striplist)
Matt Mackall
strip: move strip code to a new repair module
r4702
Alexis S. L. Carvalho
repair.py: rewrite a loop, making it cleaner and faster
r6147 # Some revisions with rev > striprev may not be descendants of striprev.
# We have to find these revisions and put them in a bundle, so that
# we can restore them after the truncations.
# To create the bundle we use repo.changegroupsubset which requires
# the list of heads and bases of the set of interesting revisions.
# (head = revision in the set that has no descendant in the set;
# base = revision in the set that has no ancestor in the set)
Wagner Bruna
strip: enhance repair.strip to receive a list of nodes (issue3299)...
r16252 tostrip = set(striplist)
for rev in striplist:
Bryan O'Sullivan
revlog: descendants(*revs) becomes descendants(revs) (API)...
r16867 for desc in cl.descendants([rev]):
Wagner Bruna
strip: enhance repair.strip to receive a list of nodes (issue3299)...
r16252 tostrip.add(desc)
Benoit Boissinot
strip: remove usage of extranodes...
r13702
files = _collectfiles(repo, striprev)
Matt Mackall
strip: simplify collectone
r13705 saverevs = _collectbrokencsets(repo, files, striprev)
Benoit Boissinot
strip: remove usage of extranodes...
r13702
# compute heads
saveheads = set(saverevs)
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 for r in xrange(striprev + 1, len(cl)):
Benoit Boissinot
strip: remove usage of extranodes...
r13702 if r not in tostrip:
saverevs.add(r)
saveheads.difference_update(cl.parentrevs(r))
saveheads.add(r)
saveheads = [cl.node(r) for r in saveheads]
Matt Mackall
strip: move strip code to a new repair module
r4702
Matt Mackall
strip: backout 73307643a09f (issue3077)
r15386 # compute base nodes
if saverevs:
Bryan O'Sullivan
revlog: descendants(*revs) becomes descendants(revs) (API)...
r16867 descendants = set(cl.descendants(saverevs))
Matt Mackall
strip: backout 73307643a09f (issue3077)
r15386 saverevs.difference_update(descendants)
savebases = [cl.node(r) for r in saverevs]
Wagner Bruna
strip: enhance repair.strip to receive a list of nodes (issue3299)...
r16252 stripbases = [cl.node(r) for r in tostrip]
Siddharth Agarwal
strip: make query to get new bookmark target cheaper...
r18040
# For a set s, max(parents(s) - s) is the same as max(heads(::s - s)), but
# is much faster
newbmtarget = repo.revs('max(parents(%ld) - (%ld))', tostrip, tostrip)
Augie Fackler
strip: move bookmarks to nearest ancestor rather than '.'...
r17264 if newbmtarget:
Pierre-Yves David
repair: use `first` instead of direct indexing...
r22818 newbmtarget = repo[newbmtarget.first()].node()
Augie Fackler
strip: move bookmarks to nearest ancestor rather than '.'...
r17264 else:
newbmtarget = '.'
Matt Mackall
strip: move strip code to a new repair module
r4702
Matt Mackall
bookmarks: move strip support to repair
r13362 bm = repo._bookmarks
updatebm = []
for m in bm:
rev = repo[bm[m]].rev()
if rev in tostrip:
updatebm.append(m)
Matt Mackall
strip: move strip code to a new repair module
r4702 # create a changegroup for all the branches we need to keep
Matt Mackall
strip: be quiet about temporary internal bundle
r11197 backupfile = None
FUJIWARA Katsunori
repair: make "strip()" treat bundle files via vfs...
r20979 vfs = repo.vfs
Mike Edgar
repair: define explicit local variable, don't reuse a comprehension variable...
r24252 node = nodelist[-1]
Jordi Gutiérrez Hermoso
strip: remove -b/--backup codepaths...
r22057 if backup:
Idan Kamara
repair: allow giving strip backup a different name...
r16388 backupfile = _bundle(repo, stripbases, cl.heads(), node, topic)
FUJIWARA Katsunori
repair: make "strip()" treat bundle files via vfs...
r20979 repo.ui.status(_("saved backup bundle to %s\n") %
vfs.join(backupfile))
repo.ui.log("backupbundle", "saved backup bundle to %s\n",
vfs.join(backupfile))
Matt Mackall
strip: backout 73307643a09f (issue3077)
r15386 if saveheads or savebases:
Nicolas Dumazet
repair: do not compress partial bundle if we do not keep it on disk...
r11791 # do not compress partial bundle if we remove it from disk later
Matt Mackall
strip: backout 73307643a09f (issue3077)
r15386 chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp',
Jordi Gutiérrez Hermoso
strip: remove -b/--backup codepaths...
r22057 compress=False)
Matt Mackall
strip: move strip code to a new repair module
r4702
Henrik Stuart
strip: make repair.strip transactional to avoid repository corruption...
r8073 mfst = repo.manifest
Pierre-Yves David
repair: forbid strip from inside a transaction...
r25300 curtr = repo.currenttransaction()
if curtr is not None:
del curtr # avoid carrying reference to transaction for nothing
msg = _('programming error: cannot strip from inside a transaction')
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(msg, hint=_('contact your extension maintainer'))
Pierre-Yves David
repair: forbid strip from inside a transaction...
r25300
Steve Borho
localrepo: add desc parameter to transaction...
r10881 tr = repo.transaction("strip")
Henrik Stuart
strip: make repair.strip transactional to avoid repository corruption...
r8073 offset = len(tr.entries)
Matt Mackall
strip: be quiet about temporary internal bundle
r11197 try:
tr.startgroup()
cl.strip(striprev, tr)
mfst.strip(striprev, tr)
for fn in files:
repo.file(fn).strip(striprev, tr)
tr.endgroup()
Henrik Stuart
strip: make repair.strip transactional to avoid repository corruption...
r8073
Matt Mackall
strip: be quiet about temporary internal bundle
r11197 try:
for i in xrange(offset, len(tr.entries)):
file, troffset, ignore = tr.entries[i]
Angel Ezquerra
localrepo: remove all external users of localrepo.sopener...
r23878 repo.svfs(file, 'a').truncate(troffset)
Durham Goode
fncache: clean up fncache during strips...
r20885 if troffset == 0:
repo.store.markremoved(file)
Matt Mackall
strip: be quiet about temporary internal bundle
r11197 tr.close()
Pierre-Yves David
strip: use the 'finally: tr.release' pattern during stripping...
r26012 finally:
tr.release()
Matt Mackall
strip: be quiet about temporary internal bundle
r11197
Matt Mackall
strip: backout 73307643a09f (issue3077)
r15386 if saveheads or savebases:
Matt Mackall
strip: hide unbundle messages by default...
r11202 ui.note(_("adding branch\n"))
FUJIWARA Katsunori
repair: make "strip()" treat bundle files via vfs...
r20979 f = vfs.open(chgrpfile, "rb")
Pierre-Yves David
bundle2: add a ui argument to readbundle...
r21064 gen = exchange.readbundle(ui, f, chgrpfile, vfs)
Matt Mackall
strip: hide unbundle messages by default...
r11202 if not repo.ui.verbose:
# silence internal shuffling chatter
repo.ui.pushbuffer()
Eric Sumner
repair: add experimental option to write bundle2 files...
r23898 if isinstance(gen, bundle2.unbundle20):
tr = repo.transaction('strip')
Eric Sumner
repair: setup hookargs when processing bundle2s...
r24170 tr.hookargs = {'source': 'strip',
'url': 'bundle:' + vfs.join(chgrpfile)}
Eric Sumner
repair: add experimental option to write bundle2 files...
r23898 try:
bundle2.processbundle(repo, gen, lambda: tr)
tr.close()
finally:
tr.release()
else:
changegroup.addchangegroup(repo, gen, 'strip',
'bundle:' + vfs.join(chgrpfile),
True)
Matt Mackall
strip: hide unbundle messages by default...
r11202 if not repo.ui.verbose:
repo.ui.popbuffer()
Matt Mackall
strip: be quiet about temporary internal bundle
r11197 f.close()
Matt Mackall
bookmarks: move strip support to repair
r13362
Idan Kamara
repair: remove undo files after strip
r16237 # remove undo files
FUJIWARA Katsunori
localrepo: make "undofiles()" return list of tuples "(vfs, relative filename)"...
r20975 for undovfs, undofile in repo.undofiles():
Idan Kamara
repair: remove undo files after strip
r16237 try:
FUJIWARA Katsunori
localrepo: make "undofiles()" return list of tuples "(vfs, relative filename)"...
r20975 undovfs.unlink(undofile)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as e:
Idan Kamara
repair: remove undo files after strip
r16237 if e.errno != errno.ENOENT:
FUJIWARA Katsunori
localrepo: make "undofiles()" return list of tuples "(vfs, relative filename)"...
r20975 ui.warn(_('error removing %s: %s\n') %
(undovfs.join(undofile), str(e)))
Idan Kamara
repair: remove undo files after strip
r16237
Matt Mackall
bookmarks: move strip support to repair
r13362 for m in updatebm:
Augie Fackler
strip: move bookmarks to nearest ancestor rather than '.'...
r17264 bm[m] = repo[newbmtarget].node()
Augie Fackler
bookmarks: introduce a bmstore to manage bookmark persistence...
r17922 bm.write()
Brodie Rao
check-code: ignore naked excepts with a "re-raise" comment...
r16705 except: # re-raises
Matt Mackall
strip: be quiet about temporary internal bundle
r11197 if backupfile:
Martin Geisler
mark ui.warn strings for translation
r11600 ui.warn(_("strip failed, full bundle stored in '%s'\n")
FUJIWARA Katsunori
repair: make "strip()" treat bundle files via vfs...
r20979 % vfs.join(backupfile))
Matt Mackall
strip: be quiet about temporary internal bundle
r11197 elif saveheads:
Martin Geisler
mark ui.warn strings for translation
r11600 ui.warn(_("strip failed, partial bundle stored in '%s'\n")
FUJIWARA Katsunori
repair: make "strip()" treat bundle files via vfs...
r20979 % vfs.join(chgrpfile))
Henrik Stuart
strip: make repair.strip transactional to avoid repository corruption...
r8073 raise
Jordi Gutiérrez Hermoso
strip: remove -b/--backup codepaths...
r22057 else:
if saveheads or savebases:
# Remove partial backup only if there were no exceptions
vfs.unlink(chgrpfile)
Matt Mackall
strip: move strip code to a new repair module
r4702
Pierre-Yves David
destroyed: drop complex branchcache rebuilt logic...
r18395 repo.destroyed()
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652
def rebuildfncache(ui, repo):
"""Rebuilds the fncache file from repo history.
Missing entries will be added. Extra entries will be removed.
"""
repo = repo.unfiltered()
if 'fncache' not in repo.requirements:
ui.warn(_('(not rebuilding fncache because repository does not '
Wagner Bruna
repair: fix typo in warning message
r25874 'support fncache)\n'))
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652 return
lock = repo.lock()
try:
fnc = repo.store.fncache
# Trigger load of fncache.
if 'irrelevant' in fnc:
pass
oldentries = set(fnc.entries)
newentries = set()
seenfiles = set()
repolen = len(repo)
for rev in repo:
ui.progress(_('changeset'), rev, total=repolen)
ctx = repo[rev]
for f in ctx.files():
# This is to minimize I/O.
if f in seenfiles:
continue
seenfiles.add(f)
i = 'data/%s.i' % f
d = 'data/%s.d' % f
if repo.store._exists(i):
newentries.add(i)
if repo.store._exists(d):
newentries.add(d)
ui.progress(_('changeset'), None)
addcount = len(newentries - oldentries)
removecount = len(oldentries - newentries)
for p in sorted(oldentries - newentries):
ui.write(_('removing %s\n') % p)
for p in sorted(newentries - oldentries):
ui.write(_('adding %s\n') % p)
if addcount or removecount:
ui.write(_('%d items added, %d removed from fncache\n') %
(addcount, removecount))
fnc.entries = newentries
fnc._dirty = True
tr = repo.transaction('fncache')
try:
fnc.write(tr)
tr.close()
finally:
tr.release()
else:
ui.write(_('fncache already up to date\n'))
finally:
lock.release()