##// END OF EJS Templates
exchange: backout changeset c26335fa4225...
exchange: backout changeset c26335fa4225 Changeset c26335fa4225 has good intends but introduce significant behavior regressions for multiple important cases. In short there are many case where push would have caught instability creation/propagation that are no longer covered. These behavior have been covered for many years and even if some related case are not currently caught, the covered one should not be regressed. The next four changesets introduce tests for some of these cases. However we could produce many more tests cases since the area is wide and they are many possible combination. (And we should cover them when getting back to this issue) Since 5.5 is one week away, the most reasonable approach seems to back this out while we devise a new way to move forward that preserve the current behavior, catch more issues and also improves the situation that c26335fa4225 target. In addition to the behavior change, c26335fa4225 also introduced output changes. These output changes does not requires a backout per-se, but are part of the same changeset. However they come with a couple of issues that also requires attention: 1) the bulk of the error message have been shoehorned into a multiple line abort message. This seems quite different from what we usually do. The abort message should be a compact and efficient message, with extra details being issued as normal error output beforehand. (with --verbose/--quiet) support. 2) the current output is unbounded, so if there is many (tens, hundreds, thousands, …) of unstable/obsolete changeset involved in the push, the output can quickly become a scary and un-usuable wall of text. So we need some limitation here (same as we have with the remote head list that says A, B , C and # others).

File last commit:

r45704:c93dd9d9 default
r45782:6063c185 stable
Show More
repair.py
539 lines | 17.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 _
Augie Fackler
repair: reliably obtain bytestr of node ids
r34219 from .node import (
hex,
short,
)
Gregory Szorc
repair: use absolute_import
r25970 from . import (
bundle2,
changegroup,
strip: use the 'writenewbundle' function to get bundle on disk...
r32468 discovery,
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 error,
Gregory Szorc
repair: use absolute_import
r25970 exchange,
Kostia Balytskyi
obsstore: move delete function from obsstore class to repair module...
r28868 obsolete,
obsutil: move 'exclusivemarkers' to the new modules...
r33144 obsutil,
utils: move the `dirs` definition in pathutil (API)...
r43923 pathutil,
Boris Feld
strip: ignore orphaned internal changesets while computing safe strip roots...
r39781 phases,
Gregory Szorc
global: use pycompat.xrange()...
r38806 pycompat,
Gregory Szorc
repair: use absolute_import
r25970 util,
)
Augie Fackler
core: migrate uses of hashlib.sha1 to hashutil.sha1...
r44517 from .utils import (
hashutil,
stringutil,
)
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
repair: use absolute_import
r25970
Augie Fackler
formatting: blacken the codebase...
r43346 def backupbundle(
repo, bases, heads, node, suffix, compress=True, obsolescence=True
):
Alexis S. L. Carvalho
repair.py: don't use nested functions.
r5905 """create a bundle with the specified revisions as a backup"""
Eric Sumner
repair: add experimental option to write bundle2 files...
r23898
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 backupdir = b"strip-backup"
FUJIWARA Katsunori
repair: make paths in "_bundle()" relative to ".hg"...
r20977 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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 allcommits = repo.set(b'%ln::%ln', bases, heads)
Durham Goode
bundles: do not overwrite existing backup bundles (BC)...
r23835 allhashes = sorted(c.hex() for c in allcommits)
Augie Fackler
core: migrate uses of hashlib.sha1 to hashutil.sha1...
r44517 totalhash = hashutil.sha1(b''.join(allhashes)).digest()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 name = b"%s/%s-%s-%s.hg" % (
Augie Fackler
formatting: blacken the codebase...
r43346 backupdir,
short(node),
hex(totalhash[:4]),
suffix,
)
Durham Goode
bundles: do not overwrite existing backup bundles (BC)...
r23835
Martin von Zweigbergk
repair: preserve phase also when not using generaldelta (issue5678)...
r34179 cgversion = changegroup.localversion(repo)
Pierre-Yves David
strip: compress bundle2 backup using BZ...
r26425 comp = None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if cgversion != b'01':
bundletype = b"HG20"
Pierre-Yves David
strip: compress bundle2 backup using BZ...
r26425 if compress:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 comp = b'BZ'
Eric Sumner
repair: add experimental option to write bundle2 files...
r23898 elif compress:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 bundletype = b"HG10BZ"
Nicolas Dumazet
repair: do not compress partial bundle if we do not keep it on disk...
r11791 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 bundletype = b"HG10UN"
strip: use the 'writenewbundle' function to get bundle on disk...
r32468
Manuel Jacob
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`...
r45704 outgoing = discovery.outgoing(repo, missingroots=bases, ancestorsof=heads)
Martin von Zweigbergk
strip: include phases in bundle (BC)...
r33032 contentopts = {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'cg.version': cgversion,
b'obsolescence': obsolescence,
b'phases': True,
Martin von Zweigbergk
strip: include phases in bundle (BC)...
r33032 }
Augie Fackler
formatting: blacken the codebase...
r43346 return bundle2.writenewbundle(
repo.ui,
repo,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'strip',
Augie Fackler
formatting: blacken the codebase...
r43346 name,
bundletype,
outgoing,
contentopts,
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
Gregory Szorc
global: use pycompat.xrange()...
r38806 for x in pycompat.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
Augie Fackler
formatting: blacken the codebase...
r43346
Durham Goode
repair: refactor broken linkrev collection...
r33690 def _collectrevlog(revlog, striprev):
_, brokenset = revlog.getstrippoint(striprev)
return [revlog.linkrev(r) for r in brokenset]
Augie Fackler
formatting: blacken the codebase...
r43346
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()
Alexis S. L. Carvalho
strip: calculate list of extra nodes to save and pass it to changegroupsubset...
r5909
Martin von Zweigbergk
strip: fix bug with treemanifests and unordered linkrevs...
r43183 for revlog in manifestrevlogs(repo):
s.update(_collectrevlog(revlog, striprev))
Matt Mackall
strip: simplify collectone
r13705 for fname in files:
Durham Goode
repair: refactor broken linkrev collection...
r33690 s.update(_collectrevlog(repo.file(fname), striprev))
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
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 def strip(ui, repo, nodelist, backup=True, topic=b'backup'):
Martin von Zweigbergk
repair: clarify in comment that caller must take lock, but not transaction...
r32922 # This function requires the caller to lock the repo, but it operates
# within a transaction of its own, and thus requires there to be no current
# transaction when it is called.
Martin von Zweigbergk
repair: move check for existing transaction earlier...
r32924 if repo.currenttransaction() is not None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.ProgrammingError(b'cannot strip from inside a transaction')
Martin von Zweigbergk
repair: move check for existing transaction earlier...
r32924
Jordi Gutiérrez Hermoso
strip: remove -b/--backup codepaths...
r22057 # Simple way to maintain backwards compatibility for this
# argument.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if backup in [b'none', b'strip']:
Jordi Gutiérrez Hermoso
strip: remove -b/--backup codepaths...
r22057 backup = False
Pierre-Yves David
clfilter: strip logic should be unfiltered...
r18004 repo = repo.unfiltered()
Idan Kamara
localrepo: introduce destroying function
r18310 repo.destroying()
Boris Feld
strip: move attributes shortcut assigned earlier...
r41131 vfs = repo.vfs
strip: access bookmark before getting a reference to changelog...
r42902 # load bookmark before changelog to avoid side effect from outdated
# changelog (see repo._refreshchangelog)
repo._bookmarks
Boris Feld
strip: move attributes shortcut assigned earlier...
r41131 cl = repo.changelog
Joshua Redstone
strip: incrementally update the branchheads cache after a strip...
r17013
Idan Kamara
repair: remove undo files after strip
r16237 # TODO handle undo of merge sets
Matt Harbison
repair: fix an `isinstance(nodelist, str)` check for py3...
r44179 if isinstance(nodelist, bytes):
Wagner Bruna
strip: enhance repair.strip to receive a list of nodes (issue3299)...
r16252 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
Martin von Zweigbergk
repair: combine two loops over changelog revisions...
r30707 files = _collectfiles(repo, striprev)
saverevs = _collectbrokencsets(repo, files, striprev)
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)
Martin von Zweigbergk
repair: combine two loops over changelog revisions...
r30707 saveheads = set(saverevs)
Martin von Zweigbergk
repair: speed up stripping of many roots...
r30706 for r in cl.revs(start=striprev + 1):
if any(p in tostrip for p in cl.parentrevs(r)):
tostrip.add(r)
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
strip: strip obsmarkers exclusive to the stripped changeset...
r32629 stripobsidx = obsmarkers = ()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if repo.ui.configbool(b'devel', b'strip-obsmarkers'):
obsutil: move 'exclusivemarkers' to the new modules...
r33144 obsmarkers = obsutil.exclusivemarkers(repo, stripbases)
strip: strip obsmarkers exclusive to the stripped changeset...
r32629 if obsmarkers:
Augie Fackler
formatting: blacken the codebase...
r43346 stripobsidx = [
i for i, m in enumerate(repo.obsstore) if m in obsmarkers
]
strip: strip obsmarkers exclusive to the stripped changeset...
r32629
Boris Feld
strip: extract bookmark movement into a separate function...
r41135 newbmtarget, updatebm = _bookmarkmovements(repo, tostrip)
Matt Mackall
bookmarks: move strip support to repair
r13362
Matt Mackall
strip: be quiet about temporary internal bundle
r11197 backupfile = None
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:
Boris Feld
strip: extract code to create strip backup...
r41133 backupfile = _createstripbackup(repo, stripbases, node, topic)
Boris Feld
strip: clarify comment around bundle create...
r41132 # create a changegroup for all the branches we need to keep
Martin von Zweigbergk
strip: don't use "full" and "partial" to describe bundles...
r29954 tmpbundlefile = None
Martin von Zweigbergk
strip: simplify some repeated conditions...
r29951 if saveheads:
Martin von Zweigbergk
strip: don't use "full" and "partial" to describe bundles...
r29954 # do not compress temporary bundle if we remove it from disk later
strip: do not include obsolescence markers for the temporary bundle...
r32628 #
# We do not include obsolescence, it might re-introduce prune markers
# we are trying to strip. This is harmless since the stripped markers
# are already backed up and we did not touched the markers for the
# saved changesets.
Augie Fackler
formatting: blacken the codebase...
r43346 tmpbundlefile = backupbundle(
repo,
savebases,
saveheads,
node,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'temp',
Augie Fackler
formatting: blacken the codebase...
r43346 compress=False,
obsolescence=False,
)
Matt Mackall
strip: move strip code to a new repair module
r4702
Kyle Lippincott
procutil: correct spelling of uninterruptable -> uninterruptible...
r41106 with ui.uninterruptible():
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with repo.transaction(b"strip") as tr:
Gregory Szorc
transaction: make entries a private attribute (API)...
r39722 # TODO this code violates the interface abstraction of the
# transaction and makes assumptions that file storage is
# using append-only files. We'll need some kind of storage
# API to handle stripping for us.
offset = len(tr._entries)
Henrik Stuart
strip: make repair.strip transactional to avoid repository corruption...
r8073
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 tr.startgroup()
cl.strip(striprev, tr)
stripmanifest(repo, striprev, tr, files)
Henrik Stuart
strip: make repair.strip transactional to avoid repository corruption...
r8073
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 for fn in files:
repo.file(fn).strip(striprev, tr)
tr.endgroup()
Matt Mackall
strip: be quiet about temporary internal bundle
r11197
Gregory Szorc
transaction: make entries a private attribute (API)...
r39722 for i in pycompat.xrange(offset, len(tr._entries)):
file, troffset, ignore = tr._entries[i]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with repo.svfs(file, b'a', checkambig=True) as fp:
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 fp.truncate(troffset)
if troffset == 0:
repo.store.markremoved(file)
deleteobsmarkers(repo.obsstore, stripobsidx)
del repo.obsstore
repo.invalidatevolatilesets()
repo._phasecache.filterunknown(repo)
strip: strip obsmarkers exclusive to the stripped changeset...
r32629
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 if tmpbundlefile:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.note(_(b"adding branch\n"))
f = vfs.open(tmpbundlefile, b"rb")
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 gen = exchange.readbundle(ui, f, tmpbundlefile, vfs)
if not repo.ui.verbose:
# silence internal shuffling chatter
repo.ui.pushbuffer()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 tmpbundleurl = b'bundle:' + vfs.join(tmpbundlefile)
txnname = b'strip'
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 if not isinstance(gen, bundle2.unbundle20):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 txnname = b"strip\n%s" % util.hidepassword(tmpbundleurl)
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 with repo.transaction(txnname) as tr:
Augie Fackler
formatting: blacken the codebase...
r43346 bundle2.applybundle(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo, gen, tr, source=b'strip', url=tmpbundleurl
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 if not repo.ui.verbose:
repo.ui.popbuffer()
f.close()
Matt Harbison
repair: use context manager for lock management...
r31626
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with repo.transaction(b'repair') as tr:
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 bmchanges = [(m, repo[newbmtarget].node()) for m in updatebm]
Boris Feld
strip: extract bookmark movement into a separate function...
r41135 repo._bookmarks.applychanges(repo, tr, bmchanges)
Laurent Charignon
repair: use bookmarks.recordchange instead of bookmarks.write...
r27157
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 # remove undo files
for undovfs, undofile in repo.undofiles():
try:
undovfs.unlink(undofile)
except OSError as e:
if e.errno != errno.ENOENT:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'error removing %s: %s\n')
Augie Fackler
formatting: blacken the codebase...
r43346 % (
undovfs.join(undofile),
stringutil.forcebytestr(e),
)
)
Idan Kamara
repair: remove undo files after strip
r16237
Augie Fackler
formatting: blacken the codebase...
r43346 except: # re-raises
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 if backupfile:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"strip failed, backup bundle stored in '%s'\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % vfs.join(backupfile)
)
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 if tmpbundlefile:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"strip failed, unrecovered changes stored in '%s'\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % vfs.join(tmpbundlefile)
)
ui.warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"(fix the problem, then recover the changesets with "
b"\"hg unbundle '%s'\")\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% vfs.join(tmpbundlefile)
)
Augie Fackler
repair: mark the critical section of strip() as unsafe...
r38546 raise
else:
if tmpbundlefile:
# Remove temporary bundle only if there were no exceptions
vfs.unlink(tmpbundlefile)
Matt Mackall
strip: move strip code to a new repair module
r4702
Pierre-Yves David
destroyed: drop complex branchcache rebuilt logic...
r18395 repo.destroyed()
Martin von Zweigbergk
repair: make strip() return backup file path...
r30274 # return the backup file path (or None if 'backup' was False) so
# extensions can use it
return backupfile
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 def softstrip(ui, repo, nodelist, backup=True, topic=b'backup'):
Boris Feld
strip: introduce a soft strip option...
r41960 """perform a "soft" strip using the archived phase"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 tostrip = [c.node() for c in repo.set(b'sort(%ln::)', nodelist)]
Boris Feld
strip: introduce a soft strip option...
r41960 if not tostrip:
return None
newbmtarget, updatebm = _bookmarkmovements(repo, tostrip)
if backup:
node = tostrip[0]
backupfile = _createstripbackup(repo, tostrip, node, topic)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with repo.transaction(b'strip') as tr:
Boris Feld
strip: introduce a soft strip option...
r41960 phases.retractboundary(repo, tr, phases.archived, tostrip)
bmchanges = [(m, repo[newbmtarget].node()) for m in updatebm]
repo._bookmarks.applychanges(repo, tr, bmchanges)
return backupfile
Boris Feld
strip: extract bookmark movement into a separate function...
r41135 def _bookmarkmovements(repo, tostrip):
# compute necessary bookmark movement
bm = repo._bookmarks
updatebm = []
for m in bm:
rev = repo[bm[m]].rev()
if rev in tostrip:
updatebm.append(m)
newbmtarget = None
Augie Fackler
repair: reword comment about bookmarks logic...
r42432 # If we need to move bookmarks, compute bookmark
# targets. Otherwise we can skip doing this logic.
if updatebm:
Boris Feld
strip: extract bookmark movement into a separate function...
r41135 # For a set s, max(parents(s) - s) is the same as max(heads(::s - s)),
# but is much faster
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 newbmtarget = repo.revs(b'max(parents(%ld) - (%ld))', tostrip, tostrip)
Boris Feld
strip: extract bookmark movement into a separate function...
r41135 if newbmtarget:
newbmtarget = repo[newbmtarget.first()].node()
else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 newbmtarget = b'.'
Boris Feld
strip: extract bookmark movement into a separate function...
r41135 return newbmtarget, updatebm
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
strip: extract code to create strip backup...
r41133 def _createstripbackup(repo, stripbases, node, topic):
# backup the changeset we are about to strip
vfs = repo.vfs
cl = repo.changelog
backupfile = backupbundle(repo, stripbases, cl.heads(), node, topic)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.status(_(b"saved backup bundle to %s\n") % vfs.join(backupfile))
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.log(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"backupbundle", b"saved backup bundle to %s\n", vfs.join(backupfile)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Boris Feld
strip: extract code to create strip backup...
r41133 return backupfile
Augie Fackler
formatting: blacken the codebase...
r43346
Jun Wu
strip: add a delayedstrip method that works in a transaction...
r33087 def safestriproots(ui, repo, nodes):
"""return list of roots of nodes where descendants are covered by nodes"""
torev = repo.unfiltered().changelog.rev
Augie Fackler
cleanup: run pyupgrade on our source tree to clean up varying things...
r44937 revs = {torev(n) for n in nodes}
Jun Wu
strip: add a delayedstrip method that works in a transaction...
r33087 # tostrip = wanted - unsafe = wanted - ancestors(orphaned)
# orphaned = affected - wanted
# affected = descendants(roots(wanted))
# wanted = revs
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 revset = b'%ld - ( ::( (roots(%ld):: and not _phase(%s)) -%ld) )'
Boris Feld
strip: ignore orphaned internal changesets while computing safe strip roots...
r39781 tostrip = set(repo.revs(revset, revs, revs, phases.internal, revs))
Jun Wu
strip: add a delayedstrip method that works in a transaction...
r33087 notstrip = revs - tostrip
if notstrip:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 nodestr = b', '.join(sorted(short(repo[n].node()) for n in notstrip))
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 _(b'warning: orphaned descendants detected, not stripping %s\n')
Augie Fackler
formatting: blacken the codebase...
r43346 % nodestr
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return [c.node() for c in repo.set(b'roots(%ld)', tostrip)]
Jun Wu
strip: add a delayedstrip method that works in a transaction...
r33087
Augie Fackler
formatting: blacken the codebase...
r43346
Jun Wu
strip: add a delayedstrip method that works in a transaction...
r33087 class stripcallback(object):
"""used as a transaction postclose callback"""
def __init__(self, ui, repo, backup, topic):
self.ui = ui
self.repo = repo
self.backup = backup
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.topic = topic or b'backup'
Jun Wu
strip: add a delayedstrip method that works in a transaction...
r33087 self.nodelist = []
def addnodes(self, nodes):
self.nodelist.extend(nodes)
def __call__(self, tr):
roots = safestriproots(self.ui, self.repo, self.nodelist)
if roots:
Jun Wu
strip: respect the backup option in stripcallback...
r33108 strip(self.ui, self.repo, roots, self.backup, self.topic)
Jun Wu
strip: add a delayedstrip method that works in a transaction...
r33087
Augie Fackler
formatting: blacken the codebase...
r43346
Sushil khanchi
rebase: support "history-editing-backup" config option...
r38835 def delayedstrip(ui, repo, nodelist, topic=None, backup=True):
Jun Wu
strip: add a delayedstrip method that works in a transaction...
r33087 """like strip, but works inside transaction and won't strip irreverent revs
nodelist must explicitly contain all descendants. Otherwise a warning will
be printed that some nodes are not stripped.
Sushil khanchi
rebase: support "history-editing-backup" config option...
r38835 Will do a backup if `backup` is True. The last non-None "topic" will be
used as the backup topic name. The default backup topic name is "backup".
Jun Wu
strip: add a delayedstrip method that works in a transaction...
r33087 """
tr = repo.currenttransaction()
if not tr:
nodes = safestriproots(ui, repo, nodelist)
Sushil khanchi
rebase: support "history-editing-backup" config option...
r38835 return strip(ui, repo, nodes, backup=backup, topic=topic)
Jun Wu
strip: add a delayedstrip method that works in a transaction...
r33087 # transaction postclose callbacks are called in alphabet order.
# use '\xff' as prefix so we are likely to be called last.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 callback = tr.getpostclose(b'\xffstrip')
Jun Wu
strip: add a delayedstrip method that works in a transaction...
r33087 if callback is None:
Sushil khanchi
rebase: support "history-editing-backup" config option...
r38835 callback = stripcallback(ui, repo, backup=backup, topic=topic)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 tr.addpostclose(b'\xffstrip', callback)
Jun Wu
strip: add a delayedstrip method that works in a transaction...
r33087 if topic:
callback.topic = topic
callback.addnodes(nodelist)
Augie Fackler
formatting: blacken the codebase...
r43346
Durham Goode
repair: move manifest strip to a separate function...
r33691 def stripmanifest(repo, striprev, tr, files):
Martin von Zweigbergk
repair: extract a helper for generating all manifest revlogs...
r43182 for revlog in manifestrevlogs(repo):
revlog.strip(striprev, tr)
Durham Goode
repair: move manifest strip to a separate function...
r33691
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
repair: extract a helper for generating all manifest revlogs...
r43182 def manifestrevlogs(repo):
yield repo.manifestlog.getstorage(b'')
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'treemanifest' in repo.requirements:
Augie Fackler
repair: reword comments that I noticed while working on source formatting...
r42439 # This logic is safe if treemanifest isn't enabled, but also
# pointless, so we skip it if treemanifest isn't enabled.
Durham Goode
hg: backout optimizing for treemanifests...
r32296 for unencoded, encoded, size in repo.store.datafiles():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if unencoded.startswith(b'meta/') and unencoded.endswith(
b'00manifest.i'
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Durham Goode
hg: backout optimizing for treemanifests...
r32296 dir = unencoded[5:-12]
Martin von Zweigbergk
repair: extract a helper for generating all manifest revlogs...
r43182 yield repo.manifestlog.getstorage(dir)
Durham Goode
strip: move tree strip logic to it's own function...
r32196
Augie Fackler
formatting: blacken the codebase...
r43346
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()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'fncache' not in repo.requirements:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'(not rebuilding fncache because repository does not '
b'support fncache)\n'
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652 return
Bryan O'Sullivan
with: use context manager in rebuildfncache again
r27860 with repo.lock():
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652 fnc = repo.store.fncache
Valentin Gatien-Baron
fncache: make debugrebuildfncache not fail on broken fncache...
r42960 fnc.ensureloaded(warn=ui.warn)
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652
oldentries = set(fnc.entries)
newentries = set()
seenfiles = set()
Augie Fackler
formatting: blacken the codebase...
r43346 progress = ui.makeprogress(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'rebuilding'), unit=_(b'changesets'), total=len(repo)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652 for rev in repo:
Martin von Zweigbergk
repair: use progress helper...
r38413 progress.update(rev)
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652
ctx = repo[rev]
for f in ctx.files():
# This is to minimize I/O.
if f in seenfiles:
continue
seenfiles.add(f)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 i = b'data/%s.i' % f
d = b'data/%s.d' % f
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652
if repo.store._exists(i):
newentries.add(i)
if repo.store._exists(d):
newentries.add(d)
Martin von Zweigbergk
repair: use progress helper...
r38413 progress.complete()
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'treemanifest' in repo.requirements:
Augie Fackler
repair: reword comments that I noticed while working on source formatting...
r42439 # This logic is safe if treemanifest isn't enabled, but also
# pointless, so we skip it if treemanifest isn't enabled.
utils: move the `dirs` definition in pathutil (API)...
r43923 for dir in pathutil.dirs(seenfiles):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 i = b'meta/%s/00manifest.i' % dir
d = b'meta/%s/00manifest.d' % dir
Martin von Zweigbergk
treemanifests: fix streaming clone...
r28007
if repo.store._exists(i):
newentries.add(i)
if repo.store._exists(d):
newentries.add(d)
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652 addcount = len(newentries - oldentries)
removecount = len(oldentries - newentries)
for p in sorted(oldentries - newentries):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.write(_(b'removing %s\n') % p)
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652 for p in sorted(newentries - oldentries):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.write(_(b'adding %s\n') % p)
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652
if addcount or removecount:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'%d items added, %d removed from fncache\n')
Augie Fackler
formatting: blacken the codebase...
r43346 % (addcount, removecount)
)
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652 fnc.entries = newentries
fnc._dirty = True
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with repo.transaction(b'fncache') as tr:
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652 fnc.write(tr)
else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.write(_(b'fncache already up to date\n'))
Gregory Szorc
repair: add functionality to rebuild fncache...
r25652
Augie Fackler
formatting: blacken the codebase...
r43346
Kostia Balytskyi
obsstore: move delete function from obsstore class to repair module...
r28868 def deleteobsmarkers(obsstore, indices):
"""Delete some obsmarkers from obsstore and return how many were deleted
'indices' is a list of ints which are the indices
of the markers to be deleted.
Every invocation of this function completely rewrites the obsstore file,
skipping the markers we want to be removed. The new temporary file is
created, remaining markers are written there and on .close() this file
gets atomically renamed to obsstore, thus guaranteeing consistency."""
if not indices:
# we don't want to rewrite the obsstore with the same content
return
left = []
current = obsstore._all
n = 0
for i, m in enumerate(current):
if i in indices:
n += 1
continue
left.append(m)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 newobsstorefile = obsstore.svfs(b'obsstore', b'w', atomictemp=True)
Kostia Balytskyi
obsstore: move delete function from obsstore class to repair module...
r28868 for bytes in obsolete.encodemarkers(left, True, obsstore._version):
newobsstorefile.write(bytes)
newobsstorefile.close()
return n