sapling/backups.py
Laurent Charignon f60df3cc2c backups: show warning message for createmarkers even when evolve is not enabled
Summary:
Before this patch we were making the assumption that evolve on means that
createmarkers is enabled, it is not always the case. This patch refines the
condition for displaying the warning message when marker creation is enabled.

Test Plan: tested on my devserver

Reviewers: pyd, rmcelroy, durham

Reviewed By: durham

Differential Revision: https://phabricator.fb.com/D2311847

Signature: t1:2311847:1438756073:a675742e9b01a2bc6d7afb5dec612f3a5f980c23
2016-01-11 07:41:42 -08:00

145 lines
5.8 KiB
Python

# backups.py
#
# Copyright 2013 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
"""display recently made backups to recover stripped commits"""
from mercurial import extensions, cmdutil, commands, error, bundlerepo
from mercurial import hg, changegroup, exchange, obsolete
from mercurial import bundle2
from mercurial import lock as lockmod
from hgext import pager
from mercurial.node import nullid, short
from mercurial.i18n import _
import os, glob, time
pager.attended.append('backups')
cmdtable = {}
command = cmdutil.command(cmdtable)
testedwith = 'internal'
msgwithcreatermarkers = """Marker creation is enabled so no commit should be
stripped unless you explicitely called hg strip. hg backups will show you the
stripped commits. If you are trying to recover a commit hidden from a previous
command, use hg reflog to get its sha1 and you will be able to access it
directly without recovering a backup."""
verbosetemplate = "{label('status.modified', node|short)} {desc|firstline}\n"
@command('^backups', [
('', 'recover', '', 'brings the specified commit back into the repository')
] + commands.logopts, _('hg backups [--recover HASH]'))
def backups(ui, repo, *pats, **opts):
'''lists the commits available in backup bundles
Without any arguments, this command prints a list of the commits in each
backup bundle.
--recover takes a commit hash and unbundles the first bundle that contains
that commit hash, which puts that commit back in your repository.
--verbose will print the entire commit message and the bundle path for that
backup.
'''
supportsmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)
if supportsmarkers:
# Warn users of obsolescence markers that they probably don't want to
# use backups but reflog instead
ui.warn(msgwithcreatermarkers)
backuppath = repo.join("strip-backup")
backups = filter(os.path.isfile, glob.glob(backuppath + "/*.hg"))
backups.sort(key=lambda x: os.path.getmtime(x), reverse=True)
opts['bundle'] = ''
opts['force'] = None
def display(other, chlist, displayer):
limit = cmdutil.loglimit(opts)
if opts.get('newest_first'):
chlist.reverse()
count = 0
for n in chlist:
if limit is not None and count >= limit:
break
parents = [p for p in other.changelog.parents(n) if p != nullid]
if opts.get('no_merges') and len(parents) == 2:
continue
count += 1
displayer.show(other[n])
recovernode = opts.get('recover')
if recovernode:
if recovernode in repo:
ui.warn("%s already exists in the repo\n" % recovernode)
return
else:
msg = _("Recover commits using: hg backups --recover <commit hash>\n")
ui.status(msg, label="status.removed")
for backup in backups:
# Much of this is copied from the hg incoming logic
source = os.path.relpath(backup, os.getcwd())
source = ui.expandpath(source)
source, branches = hg.parseurl(source, opts.get('branch'))
try:
other = hg.peer(repo, opts, source)
except error.LookupError as ex:
msg = _("\nwarning: unable to open bundle %s") % source
hint = _("\n(missing parent rev %s)\n") % short(ex.name)
ui.warn(msg)
ui.warn(hint)
continue
revs, checkout = hg.addbranchrevs(repo, other, branches,
opts.get('rev'))
if revs:
revs = [other.lookup(rev) for rev in revs]
quiet = ui.quiet
try:
ui.quiet = True
other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo,
other, revs, opts["bundle"],
opts["force"])
except error.LookupError:
continue
finally:
ui.quiet = quiet
try:
if chlist:
if recovernode:
tr = lock = None
try:
lock = repo.lock()
if recovernode in other:
ui.status(_("Unbundling %s\n") % (recovernode))
f = hg.openpath(ui, source)
gen = exchange.readbundle(ui, f, source)
tr = repo.transaction("unbundle")
if not isinstance(gen, bundle2.unbundle20):
gen.apply(repo, 'unbundle', 'bundle:' + source)
if isinstance(gen, bundle2.unbundle20):
bundle2.applybundle(repo, gen, tr,
source='unbundle',
url='bundle:' + source)
tr.close()
break
finally:
lockmod.release(lock, tr)
else:
backupdate = os.path.getmtime(source)
backupdate = time.strftime('%a %H:%M, %Y-%m-%d',
time.localtime(backupdate))
ui.status("\n%s\n" % (backupdate.ljust(50)))
if not ui.verbose:
opts['template'] = verbosetemplate
else:
ui.status("%s%s\n" % ("bundle:".ljust(13), source))
displayer = cmdutil.show_changeset(ui, other, opts, False)
display(other, chlist, displayer)
displayer.close()
finally:
cleanupfn()