sapling/hgext3rd/fbmetaedit.py
Mateusz Kwapich 1bcc10919d fbmetaedit: intoduce the extension
Summary:
It's just copy-paste from my mutable-history patch series that ended up as
persistent hotfix.

The wrapping logic is very simple: it redirects '--fold' calls to original
metaedit and handles all the rest.

Test Plan:
Included a big copy-pase from test-evolve.t preserving only cases that were
executing metaedit and modified for the smaller test repo (the metaedit tests
were at the end of evolve test file).

Reviewers: #sourcecontrol, quark, simonfar

Reviewed By: quark, simonfar

Subscribers: rmcelroy, quark, mjpieters

Differential Revision: https://phabricator.intern.facebook.com/D4708017

Signature: t1:4708017:1489524494:d682aab857e8422bb1a23adc22dddfb9f505b6b3
2017-03-15 07:40:26 -07:00

162 lines
6.0 KiB
Python

# fbmetaedit.py - improved metaedit functionality
#
# Copyright 2017 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.
"""extends the existing metaedit functionality
Speeds up metaedit by reusing manifestes and allows to metaedit
multiple commit at once.
"""
from mercurial import (
cmdutil,
context,
error,
extensions,
lock as lockmod,
scmutil,
obsolete,
)
from mercurial.i18n import _
wrapcommand = extensions.wrapcommand
wrapfunction = extensions.wrapfunction
cmdtable = {}
command = cmdutil.command(cmdtable)
testedwith = 'ships-with-fb-hgext'
def uisetup(ui):
order = extensions._order
order.remove('fbmetaedit')
order.append('fbmetaedit')
def extsetup(ui):
try:
evolve = extensions.find('evolve')
def metarewrite(repo, old, newbases, commitopts):
"""Return (nodeid, created) where nodeid is the identifier of the
changeset generated by the rewrite process, and created is True if
nodeid was actually created. If created is False, nodeid
references a changeset existing before the rewrite call.
"""
wlock = lock = tr = None
try:
wlock = repo.wlock()
lock = repo.lock()
tr = repo.transaction('rewrite')
updatebookmarks = evolve._bookmarksupdater(repo, old.node(), tr)
message = cmdutil.logmessage(repo.ui, commitopts)
if not message:
message = old.description()
user = commitopts.get('user') or old.user()
date = commitopts.get('date') or None # old.date()
extra = dict(commitopts.get('extra', old.extra()))
extra['branch'] = old.branch()
new = context.metadataonlyctx(repo,
old,
parents=newbases,
text=message,
user=user,
date=date,
extra=extra)
if commitopts.get('edit'):
new._text = cmdutil.commitforceeditor(repo, new, [])
revcount = len(repo)
newid = repo.commitctx(new)
new = repo[newid]
created = len(repo) != revcount
updatebookmarks(newid)
tr.close()
return newid, created
finally:
lockmod.release(tr, lock, wlock)
def _metaedit(orig, ui, repo, *revs, **opts):
if opts['fold']:
return orig(ui, repo, *revs, **opts)
revs = list(revs)
revs.extend(opts['rev'])
if not revs:
revs = ['.']
wlock = lock = None
try:
wlock = repo.wlock()
lock = repo.lock()
revs = scmutil.revrange(repo, revs)
if repo.revs("%ld and public()", revs):
raise error.Abort(_('cannot edit commit information for '
'public revisions'))
wctx = repo[None]
p1 = wctx.p1()
tr = repo.transaction('metaedit')
try:
commitopts = opts.copy()
allctx = [repo[r] for r in revs]
if commitopts.get('message') or commitopts.get('logfile'):
commitopts['edit'] = False
else:
commitopts['edit'] = True
replacemap = {}
# we need topological order
allctx = sorted(allctx, key=lambda c: c.rev())
# all descendats that can be safely rewritten
newunstable = evolve._disallowednewunstable(repo, revs)
newunstablectx = sorted([repo[r] for r in newunstable],
key=lambda c: c.rev())
def _rewritesingle(c, _commitopts):
if _commitopts.get('edit', False):
_commitopts['message'] = \
"HG: Commit message of changeset %s\n%s" %\
(str(c), c.description())
bases = [
replacemap.get(c.p1().node(), c.p1().node()),
replacemap.get(c.p2().node(), c.p2().node()),
]
newid, created = metarewrite(repo, c, bases,
commitopts=_commitopts)
if created:
replacemap[c.node()] = newid
for c in allctx:
_rewritesingle(c, commitopts)
for c in newunstablectx:
_rewritesingle(c,
{'date': commitopts.get('date') or None})
if p1.node() in replacemap:
repo.setparents(replacemap[p1.node()])
if len(replacemap) > 0:
obsolete.createmarkers(
repo,
[(repo[old], (repo[new],))
for old, new in replacemap.iteritems()],
)
# TODO: set poroper phase boundaries (affects secret
# phase only)
else:
ui.status(_("nothing changed\n"))
tr.close()
finally:
tr.release()
finally:
lockmod.release(lock, wlock)
wrapcommand(evolve.cmdtable, 'metaedit', _metaedit)
except KeyError:
pass # evolve not found