[PATCH 1 of 7 v4] rebase: introduce a RebaseRuntimeState (RRS) class

Kostia Balytskyi ikostia at fb.com
Sun Jun 5 17:46:15 UTC 2016


# HG changeset patch
# User Kostia Balytskyi <ikostia at fb.com>
# Date 1465136332 -3600
#      Sun Jun 05 15:18:52 2016 +0100
# Node ID 52b8a1170cb6e1ec6c0c547ed02ceddf3a749edc
# Parent  9ac309946df9e69bb73ded75f2fc5b84a4e785c2
rebase: introduce a RebaseRuntimeState (RRS) class

RebaseRuntimeState is a class that will in future contain all of the state
necessary to perform rebase operation and have pieces of rebase logic as
its methods.

This commit introduces the class and moves the following local variables to
be its fields:
- originalwd
- external
- state
- activebookmark


As per marmoute's request, I am resending the prefix of the "refactor rebase"
series, containint only 7 patches. 6 of those have to do with refactoring
itself, while the last one is about removing the logic to abort the rebase
operation if all changesets have equivalents in the destination. Whoever
will review/accept this, please remove this paragraph in flight.

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -119,6 +119,17 @@ def _revsetdestrebase(repo, subset, x):
         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 +240,8 @@ def rebase(ui, repo, **opts):
     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 +302,9 @@ def rebase(ui, repo, **opts):
                 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 +318,17 @@ def rebase(ui, repo, **opts):
                     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 +374,12 @@ def rebase(ui, repo, **opts):
                                  % 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 +391,7 @@ def rebase(ui, repo, **opts):
             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 +403,13 @@ def rebase(ui, repo, **opts):
 
         # 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 +420,16 @@ def rebase(ui, repo, **opts):
             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 +437,7 @@ def rebase(ui, repo, **opts):
                     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 +461,38 @@ def rebase(ui, repo, **opts):
                     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 +500,14 @@ def rebase(ui, repo, **opts):
                 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 +515,17 @@ def rebase(ui, repo, **opts):
                 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 +534,10 @@ def rebase(ui, repo, **opts):
 
         # 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 +546,14 @@ def rebase(ui, repo, **opts):
             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 +562,9 @@ def rebase(ui, repo, **opts):
         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