mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 09:17:30 +03:00
1bcc10919d
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
162 lines
6.0 KiB
Python
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
|