Details
Details
- Reviewers
- None
- Group Reviewers
hg-reviewers - Commits
- rHGa06dc62f1c82: shelve: pass transaction around to clarify where it's used
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Lint
Lint Skipped - Unit
Unit Tests Skipped
hg-reviewers |
Lint Skipped |
Unit Tests Skipped |
Path | Packages | |||
---|---|---|---|---|
M | hgext/shelve.py (21 lines) |
Commit | Parents | Author | Summary | Date |
---|---|---|---|---|
Martin von Zweigbergk | May 7 2018, 8:08 PM |
Status | Author | Revision | |
---|---|---|---|
Closed | martinvonz | ||
Closed | martinvonz |
def opener(self, mode='rb'): | def opener(self, mode='rb'): | ||||
try: | try: | ||||
return self.vfs(self.fname, mode) | return self.vfs(self.fname, mode) | ||||
except IOError as err: | except IOError as err: | ||||
if err.errno != errno.ENOENT: | if err.errno != errno.ENOENT: | ||||
raise | raise | ||||
raise error.Abort(_("shelved change '%s' not found") % self.name) | raise error.Abort(_("shelved change '%s' not found") % self.name) | ||||
def applybundle(self): | def applybundle(self, tr): | ||||
fp = self.opener() | fp = self.opener() | ||||
try: | try: | ||||
targetphase = phases.internal | targetphase = phases.internal | ||||
if not phases.supportinternal(self.repo): | if not phases.supportinternal(self.repo): | ||||
targetphase = phases.secret | targetphase = phases.secret | ||||
gen = exchange.readbundle(self.repo.ui, fp, self.fname, self.vfs) | gen = exchange.readbundle(self.repo.ui, fp, self.fname, self.vfs) | ||||
pretip = self.repo['tip'] | pretip = self.repo['tip'] | ||||
tr = self.repo.currenttransaction() | |||||
bundle2.applybundle(self.repo, gen, tr, | bundle2.applybundle(self.repo, gen, tr, | ||||
source='unshelve', | source='unshelve', | ||||
url='bundle:' + self.vfs.join(self.fname), | url='bundle:' + self.vfs.join(self.fname), | ||||
targetphase=targetphase) | targetphase=targetphase) | ||||
shelvectx = self.repo['tip'] | shelvectx = self.repo['tip'] | ||||
if pretip == shelvectx: | if pretip == shelvectx: | ||||
shelverev = tr.changes['revduplicates'][-1] | shelverev = tr.changes['revduplicates'][-1] | ||||
shelvectx = self.repo[shelverev] | shelvectx = self.repo[shelverev] | ||||
if activebookmark: | if activebookmark: | ||||
bookmarks.deactivate(repo) | bookmarks.deactivate(repo) | ||||
return activebookmark | return activebookmark | ||||
def _restoreactivebookmark(repo, mark): | def _restoreactivebookmark(repo, mark): | ||||
if mark: | if mark: | ||||
bookmarks.activate(repo, mark) | bookmarks.activate(repo, mark) | ||||
def _aborttransaction(repo): | def _aborttransaction(repo, tr): | ||||
'''Abort current transaction for shelve/unshelve, but keep dirstate | '''Abort current transaction for shelve/unshelve, but keep dirstate | ||||
''' | ''' | ||||
tr = repo.currenttransaction() | |||||
dirstatebackupname = 'dirstate.shelve' | dirstatebackupname = 'dirstate.shelve' | ||||
narrowspecbackupname = 'narrowspec.shelve' | narrowspecbackupname = 'narrowspec.shelve' | ||||
repo.dirstate.savebackup(tr, dirstatebackupname) | repo.dirstate.savebackup(tr, dirstatebackupname) | ||||
narrowspec.savebackup(repo, narrowspecbackupname) | narrowspec.savebackup(repo, narrowspecbackupname) | ||||
tr.abort() | tr.abort() | ||||
narrowspec.restorebackup(repo, narrowspecbackupname) | narrowspec.restorebackup(repo, narrowspecbackupname) | ||||
repo.dirstate.restorebackup(None, dirstatebackupname) | repo.dirstate.restorebackup(None, dirstatebackupname) | ||||
def _includeunknownfiles(repo, pats, opts, extra): | def _includeunknownfiles(repo, pats, opts, extra): | ||||
s = repo.status(match=scmutil.match(repo[None], pats, opts), | s = repo.status(match=scmutil.match(repo[None], pats, opts), | ||||
unknown=True) | unknown=True) | ||||
if s.unknown: | if s.unknown: | ||||
extra['shelve_unknown'] = '\0'.join(s.unknown) | extra['shelve_unknown'] = '\0'.join(s.unknown) | ||||
repo[None].add(s.unknown) | repo[None].add(s.unknown) | ||||
def _finishshelve(repo): | def _finishshelve(repo, tr): | ||||
if phases.supportinternal(repo): | if phases.supportinternal(repo): | ||||
tr = repo.currenttransaction() | |||||
tr.close() | tr.close() | ||||
else: | else: | ||||
_aborttransaction(repo) | _aborttransaction(repo, tr) | ||||
def createcmd(ui, repo, pats, opts): | def createcmd(ui, repo, pats, opts): | ||||
"""subcommand that creates a new shelve""" | """subcommand that creates a new shelve""" | ||||
with repo.wlock(): | with repo.wlock(): | ||||
cmdutil.checkunfinished(repo) | cmdutil.checkunfinished(repo) | ||||
return _docreatecmd(ui, repo, pats, opts) | return _docreatecmd(ui, repo, pats, opts) | ||||
def _docreatecmd(ui, repo, pats, opts): | def _docreatecmd(ui, repo, pats, opts): | ||||
if ui.formatted(): | if ui.formatted(): | ||||
desc = stringutil.ellipsis(desc, ui.termwidth()) | desc = stringutil.ellipsis(desc, ui.termwidth()) | ||||
ui.status(_('shelved as %s\n') % name) | ui.status(_('shelved as %s\n') % name) | ||||
hg.update(repo, parent.node()) | hg.update(repo, parent.node()) | ||||
if origbranch != repo['.'].branch() and not _isbareshelve(pats, opts): | if origbranch != repo['.'].branch() and not _isbareshelve(pats, opts): | ||||
repo.dirstate.setbranch(origbranch) | repo.dirstate.setbranch(origbranch) | ||||
_finishshelve(repo) | _finishshelve(repo, tr) | ||||
finally: | finally: | ||||
_restoreactivebookmark(repo, activebookmark) | _restoreactivebookmark(repo, activebookmark) | ||||
lockmod.release(tr, lock) | lockmod.release(tr, lock) | ||||
def _isbareshelve(pats, opts): | def _isbareshelve(pats, opts): | ||||
return (not pats | return (not pats | ||||
and not opts.get('interactive', False) | and not opts.get('interactive', False) | ||||
and not opts.get('include', False) | and not opts.get('include', False) | ||||
tempopts = {} | tempopts = {} | ||||
tempopts['message'] = "pending changes temporary commit" | tempopts['message'] = "pending changes temporary commit" | ||||
tempopts['date'] = opts.get('date') | tempopts['date'] = opts.get('date') | ||||
with ui.configoverride({('ui', 'quiet'): True}): | with ui.configoverride({('ui', 'quiet'): True}): | ||||
node = cmdutil.commit(ui, repo, commitfunc, [], tempopts) | node = cmdutil.commit(ui, repo, commitfunc, [], tempopts) | ||||
tmpwctx = repo[node] | tmpwctx = repo[node] | ||||
return tmpwctx, addedbefore | return tmpwctx, addedbefore | ||||
def _unshelverestorecommit(ui, repo, basename): | def _unshelverestorecommit(ui, repo, tr, basename): | ||||
"""Recreate commit in the repository during the unshelve""" | """Recreate commit in the repository during the unshelve""" | ||||
repo = repo.unfiltered() | repo = repo.unfiltered() | ||||
node = None | node = None | ||||
if shelvedfile(repo, basename, 'shelve').exists(): | if shelvedfile(repo, basename, 'shelve').exists(): | ||||
node = shelvedfile(repo, basename, 'shelve').readinfo()['node'] | node = shelvedfile(repo, basename, 'shelve').readinfo()['node'] | ||||
if node is None or node not in repo: | if node is None or node not in repo: | ||||
with ui.configoverride({('ui', 'quiet'): True}): | with ui.configoverride({('ui', 'quiet'): True}): | ||||
shelvectx = shelvedfile(repo, basename, 'hg').applybundle() | shelvectx = shelvedfile(repo, basename, 'hg').applybundle(tr) | ||||
# We might not strip the unbundled changeset, so we should keep track of | # We might not strip the unbundled changeset, so we should keep track of | ||||
# the unshelve node in case we need to reuse it (eg: unshelve --keep) | # the unshelve node in case we need to reuse it (eg: unshelve --keep) | ||||
if node is None: | if node is None: | ||||
info = {'node': nodemod.hex(shelvectx.node())} | info = {'node': nodemod.hex(shelvectx.node())} | ||||
shelvedfile(repo, basename, 'shelve').writeinfo(info) | shelvedfile(repo, basename, 'shelve').writeinfo(info) | ||||
else: | else: | ||||
shelvectx = repo[node] | shelvectx = repo[node] | ||||
def _finishunshelve(repo, oldtiprev, tr, activebookmark): | def _finishunshelve(repo, oldtiprev, tr, activebookmark): | ||||
_restoreactivebookmark(repo, activebookmark) | _restoreactivebookmark(repo, activebookmark) | ||||
# The transaction aborting will strip all the commits for us, | # The transaction aborting will strip all the commits for us, | ||||
# but it doesn't update the inmemory structures, so addchangegroup | # but it doesn't update the inmemory structures, so addchangegroup | ||||
# hooks still fire and try to operate on the missing commits. | # hooks still fire and try to operate on the missing commits. | ||||
# Clean up manually to prevent this. | # Clean up manually to prevent this. | ||||
repo.unfiltered().changelog.strip(oldtiprev, tr) | repo.unfiltered().changelog.strip(oldtiprev, tr) | ||||
_aborttransaction(repo) | _aborttransaction(repo, tr) | ||||
def _checkunshelveuntrackedproblems(ui, repo, shelvectx): | def _checkunshelveuntrackedproblems(ui, repo, shelvectx): | ||||
"""Check potential problems which may result from working | """Check potential problems which may result from working | ||||
copy having untracked changes.""" | copy having untracked changes.""" | ||||
wcdeleted = set(repo.status().deleted) | wcdeleted = set(repo.status().deleted) | ||||
shelvetouched = set(shelvectx.files()) | shelvetouched = set(shelvectx.files()) | ||||
intersection = wcdeleted.intersection(shelvetouched) | intersection = wcdeleted.intersection(shelvetouched) | ||||
if intersection: | if intersection: | ||||
# ...-> pctx -> tmpwctx -> shelvectx | # ...-> pctx -> tmpwctx -> shelvectx | ||||
# where tmpwctx is an optional commit with the user's pending changes | # where tmpwctx is an optional commit with the user's pending changes | ||||
# and shelvectx is the unshelved changes. Then we merge it all down | # and shelvectx is the unshelved changes. Then we merge it all down | ||||
# to the original pctx. | # to the original pctx. | ||||
activebookmark = _backupactivebookmark(repo) | activebookmark = _backupactivebookmark(repo) | ||||
tmpwctx, addedbefore = _commitworkingcopychanges(ui, repo, opts, | tmpwctx, addedbefore = _commitworkingcopychanges(ui, repo, opts, | ||||
tmpwctx) | tmpwctx) | ||||
repo, shelvectx = _unshelverestorecommit(ui, repo, basename) | repo, shelvectx = _unshelverestorecommit(ui, repo, tr, basename) | ||||
_checkunshelveuntrackedproblems(ui, repo, shelvectx) | _checkunshelveuntrackedproblems(ui, repo, shelvectx) | ||||
branchtorestore = '' | branchtorestore = '' | ||||
if shelvectx.branch() != shelvectx.p1().branch(): | if shelvectx.branch() != shelvectx.p1().branch(): | ||||
branchtorestore = shelvectx.branch() | branchtorestore = shelvectx.branch() | ||||
shelvectx = _rebaserestoredcommit(ui, repo, opts, tr, oldtiprev, | shelvectx = _rebaserestoredcommit(ui, repo, opts, tr, oldtiprev, | ||||
basename, pctx, tmpwctx, | basename, pctx, tmpwctx, | ||||
shelvectx, branchtorestore, | shelvectx, branchtorestore, |