[PATCH 01 of 16] rebase: move originalwd, external, state and activebookmark to an object

Kostia Balytskyi ikostia at fb.com
Sun May 29 22:38:32 UTC 2016


# HG changeset patch
# User Kostia Balytskyi <ikostia at fb.com>
# Date 1464560371 -3600
#      Sun May 29 23:19:31 2016 +0100
# Node ID c93cbc7223e65ae6cbe36295604fbe83455dbd63
# Parent  318534bb5dfd37b1c95f10ba90b73c5ce562713f
rebase: move originalwd, external, state and activebookmark to an object

This is an initial piece of my effort to refactor rebase. At first I tried to
break the main rebase function into smaller helper functions, but the amount
of state main function maintains as local variables is too big and means that
helper functions would have to be called this way:

  '(v0, v1, v2, v3, ..., vn) = helperfunction(v0, v1, v2, v3, ..., vn)'

So I want to turn rebase into a class in a couple of stages:
- move most of the local variables to be scoped under a RebaseRuntimeState
- break rebase function into pieces and make them methods of this class
- move some other functions to be methods of this class

After I've spent a day on this I realized that I'd better get some feedback
earleir in the process, so please tell me if the above sounds reasonable.

Please do not accept any of theese now.

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -119,6 +119,18 @@
         sourceset = revset.getset(repo, revset.fullreposet(repo), x)
     return subset & revset.baseset([_destrebase(repo, sourceset)])
 
+class RebaseRuntimeState(object):
+    """This class is a container for rebase runtime state"""
+    def __init__(self):
+        self.originalwd = None
+        self.external = nullrev
+        # Mapping between the old revision id and either what is the new rebased
+        # revision or what needs to be done with the old revision. The state
+        # dict will be what contains most of the rebase progress state.
+
+        self.state = {}
+        self.activebookmark = None
+
 @command('rebase',
     [('s', 'source', '',
      _('rebase the specified changeset and descendants'), _('REV')),
@@ -229,13 +241,8 @@
     unresolved conflicts.
 
     """
-    originalwd = target = None
-    activebookmark = None
-    external = nullrev
-    # Mapping between the old revision id and either what is the new rebased
-    # revision or what needs to be done with the old revision. The state dict
-    # will be what contains most of the rebase progress state.
-    state = {}
+    rtstate = RebaseRuntimeState()
+    target = None
     skipped = set()
     targetancestors = set()
 
@@ -296,8 +303,9 @@
                 ui.warn(_('tool option will be ignored\n'))
 
             try:
-                (originalwd, target, state, skipped, collapsef, keepf,
-                 keepbranchesf, external, activebookmark) = restorestatus(repo)
+                (rtstate.originalwd, target, rtstate.state, skipped,
+                 collapsef, keepf, keepbranchesf, rtstate.external,
+                 rtstate.activebookmark) = restorestatus(repo)
                 collapsemsg = restorecollapsemsg(repo)
             except error.RepoLookupError:
                 if abortf:
@@ -311,18 +319,17 @@
                     hint = _('use "hg rebase --abort" to clear broken state')
                     raise error.Abort(msg, hint=hint)
             if abortf:
-                return abort(repo, originalwd, target, state,
-                             activebookmark=activebookmark)
+                return abort(repo, rtstate.originalwd, target, rtstate.state,
+                             activebookmark=rtstate.activebookmark)
 
             obsoletenotrebased = {}
             if ui.configbool('experimental', 'rebaseskipobsolete',
                              default=True):
-                rebaseobsrevs = set([r for r, status in state.items()
-                                     if status == revprecursor])
-                rebasesetrevs = set(state.keys())
+                rebaseobsrevs = set([r for r, st in rtstate.state.items()
+                                     if st == revprecursor])
+                rebasesetrevs = set(rtstate.state.keys())
                 obsoletenotrebased = _computeobsoletenotrebased(repo,
-                                                                rebaseobsrevs,
-                                                                target)
+                                        rebaseobsrevs, target)
                 rebaseobsskipped = set(obsoletenotrebased)
                 _checkobsrebase(repo, ui, rebaseobsrevs, rebasesetrevs,
                                 rebaseobsskipped)
@@ -368,11 +375,12 @@
                                  % repo[root],
                                  hint=_('see "hg help phases" for details'))
 
-            originalwd, target, state = result
+            (rtstate.originalwd, target, rtstate.state) = result
             if collapsef:
                 targetancestors = repo.changelog.ancestors([target],
                                                            inclusive=True)
-                external = externalparent(repo, state, targetancestors)
+                rtstate.external = externalparent(repo, rtstate.state,
+                                                       targetancestors)
 
             if dest.closesbranch() and not keepbranchesf:
                 ui.status(_('reopening closed branch head %s\n') % dest)
@@ -384,7 +392,7 @@
             extrafns.insert(0, _savebranch)
             if collapsef:
                 branches = set()
-                for rev in state:
+                for rev in rtstate.state:
                     branches.add(repo[rev].branch())
                     if len(branches) > 1:
                         raise error.Abort(_('cannot collapse multiple named '
@@ -396,13 +404,13 @@
 
         # Keep track of the current bookmarks in order to reset them later
         currentbookmarks = repo._bookmarks.copy()
-        activebookmark = activebookmark or repo._activebookmark
-        if activebookmark:
+        rtstate.activebookmark = rtstate.activebookmark or repo._activebookmark
+        if rtstate.activebookmark:
             bookmarks.deactivate(repo)
 
         extrafn = _makeextrafn(extrafns)
 
-        sortedstate = sorted(state)
+        sortedstate = sorted(rtstate.state)
         total = len(sortedstate)
         pos = 0
         for rev in sortedstate:
@@ -413,15 +421,16 @@
             if names:
                 desc += ' (%s)' % ' '.join(names)
             pos += 1
-            if state[rev] == revtodo:
+            if rtstate.state[rev] == revtodo:
                 ui.status(_('rebasing %s\n') % desc)
                 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
                             _('changesets'), total)
-                p1, p2, base = defineparents(repo, rev, target, state,
+                p1, p2, base = defineparents(repo, rev, target, rtstate.state,
                                              targetancestors,
                                              obsoletenotrebased)
-                storestatus(repo, originalwd, target, state, collapsef, keepf,
-                            keepbranchesf, external, activebookmark)
+                storestatus(repo, rtstate.originalwd, target, rtstate.state,
+                            collapsef, keepf, keepbranchesf,
+                            rtstate.external, rtstate.activebookmark)
                 storecollapsemsg(repo, collapsemsg)
                 if len(repo[None].parents()) == 2:
                     repo.ui.debug('resuming interrupted rebase\n')
@@ -429,7 +438,7 @@
                     try:
                         ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
                                      'rebase')
-                        stats = rebasenode(repo, rev, p1, base, state,
+                        stats = rebasenode(repo, rev, p1, base, rtstate.state,
                                            collapsef, target)
                         if stats and stats[3] > 0:
                             raise error.InterventionRequired(
@@ -453,38 +462,38 @@
                     newnode = None
                 # Update the state
                 if newnode is not None:
-                    state[rev] = repo[newnode].rev()
+                    rtstate.state[rev] = repo[newnode].rev()
                     ui.debug('rebased as %s\n' % short(newnode))
                 else:
                     if not collapsef:
                         ui.warn(_('note: rebase of %d:%s created no changes '
                                   'to commit\n') % (rev, ctx))
                         skipped.add(rev)
-                    state[rev] = p1
+                    rtstate.state[rev] = p1
                     ui.debug('next revision set to %s\n' % p1)
-            elif state[rev] == nullmerge:
+            elif rtstate.state[rev] == nullmerge:
                 ui.debug('ignoring null merge rebase of %s\n' % rev)
-            elif state[rev] == revignored:
+            elif rtstate.state[rev] == revignored:
                 ui.status(_('not rebasing ignored %s\n') % desc)
-            elif state[rev] == revprecursor:
+            elif rtstate.state[rev] == revprecursor:
                 targetctx = repo[obsoletenotrebased[rev]]
                 desctarget = '%d:%s "%s"' % (targetctx.rev(), targetctx,
                              targetctx.description().split('\n', 1)[0])
                 msg = _('note: not rebasing %s, already in destination as %s\n')
                 ui.status(msg % (desc, desctarget))
-            elif state[rev] == revpruned:
+            elif rtstate.state[rev] == revpruned:
                 msg = _('note: not rebasing %s, it has no successor\n')
                 ui.status(msg % desc)
             else:
                 ui.status(_('already rebased %s as %s\n') %
-                          (desc, repo[state[rev]]))
+                          (desc, repo[rtstate.state[rev]]))
 
         ui.progress(_('rebasing'), None)
         ui.note(_('rebase merging completed\n'))
 
         if collapsef and not keepopen:
-            p1, p2, _base = defineparents(repo, min(state), target,
-                                          state, targetancestors,
+            p1, p2, _base = defineparents(repo, min(rtstate.state), target,
+                                          rtstate.state, targetancestors,
                                           obsoletenotrebased)
             editopt = opts.get('edit')
             editform = 'rebase.collapse'
@@ -492,12 +501,14 @@
                 commitmsg = collapsemsg
             else:
                 commitmsg = 'Collapsed revision'
-                for rebased in state:
-                    if rebased not in skipped and state[rebased] > nullmerge:
+                for rebased in rtstate.state:
+                    if rebased not in skipped and\
+                       rtstate.state[rebased] > nullmerge:
                         commitmsg += '\n* %s' % repo[rebased].description()
                 editopt = True
             editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
-            newnode = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
+            newnode = concludenode(repo, rev, p1, rtstate.external,
+                                   commitmsg=commitmsg,
                                    extrafn=extrafn, editor=editor,
                                    keepbranches=keepbranchesf,
                                    date=date)
@@ -505,17 +516,17 @@
                 newrev = target
             else:
                 newrev = repo[newnode].rev()
-            for oldrev in state.iterkeys():
-                if state[oldrev] > nullmerge:
-                    state[oldrev] = newrev
+            for oldrev in rtstate.state.iterkeys():
+                if rtstate.state[oldrev] > nullmerge:
+                    rtstate.state[oldrev] = newrev
 
         if 'qtip' in repo.tags():
-            updatemq(repo, state, skipped, **opts)
+            updatemq(repo, rtstate.state, skipped, **opts)
 
         if currentbookmarks:
             # Nodeids are needed to reset bookmarks
             nstate = {}
-            for k, v in state.iteritems():
+            for k, v in rtstate.state.iteritems():
                 if v > nullmerge:
                     nstate[repo[k].node()] = repo[v].node()
             # XXX this is the same as dest.node() for the non-continue path --
@@ -524,10 +535,10 @@
 
         # restore original working directory
         # (we do this before stripping)
-        newwd = state.get(originalwd, originalwd)
+        newwd = rtstate.state.get(rtstate.originalwd, rtstate.originalwd)
         if newwd < 0:
             # original directory is a parent of rebase set root or ignored
-            newwd = originalwd
+            newwd = rtstate.originalwd
         if newwd not in [c.rev() for c in repo[None].parents()]:
             ui.note(_("update back to initial working directory parent\n"))
             hg.updaterepo(repo, newwd, False)
@@ -536,14 +547,14 @@
             collapsedas = None
             if collapsef:
                 collapsedas = newnode
-            clearrebased(ui, repo, state, skipped, collapsedas)
+            clearrebased(ui, repo, rtstate.state, skipped, collapsedas)
 
         with repo.transaction('bookmark') as tr:
             if currentbookmarks:
                 updatebookmarks(repo, targetnode, nstate, currentbookmarks, tr)
-                if activebookmark not in repo._bookmarks:
+                if rtstate.activebookmark not in repo._bookmarks:
                     # active bookmark was divergent one and has been deleted
-                    activebookmark = None
+                    rtstate.activebookmark = None
         clearstatus(repo)
         clearcollapsemsg(repo)
 
@@ -552,9 +563,9 @@
         if skipped:
             ui.note(_("%d revisions have been skipped\n") % len(skipped))
 
-        if (activebookmark and
-            repo['.'].node() == repo._bookmarks[activebookmark]):
-                bookmarks.activate(repo, activebookmark)
+        if (rtstate.activebookmark and
+            repo['.'].node() == repo._bookmarks[rtstate.activebookmark]):
+                bookmarks.activate(repo, rtstate.activebookmark)
 
     finally:
         release(lock, wlock)


More information about the Mercurial-devel mailing list