evolve: move the evolve command to evolvecmd.py
authorPulkit Goyal <7895pulkit@gmail.com>
Fri, 19 Jan 2018 19:32:34 +0530
changeset 3470 ece5cd58147d
parent 3469 e97bfd529e72
child 3472 05bd493d496d
evolve: move the evolve command to evolvecmd.py This patch moves finishes the code movement by moving the evolve command to evolvecmd.py.
hgext3rd/evolve/__init__.py
hgext3rd/evolve/evolvecmd.py
--- a/hgext3rd/evolve/__init__.py	Sun Jan 21 20:33:39 2018 +0530
+++ b/hgext3rd/evolve/__init__.py	Fri Jan 19 19:32:34 2018 +0530
@@ -292,12 +292,10 @@
     node,
     obsolete,
     patch,
-    phases,
     revset,
     scmutil,
 )
 
-from mercurial.commands import mergetoolopts
 from mercurial.i18n import _
 from mercurial.node import nullid
 
@@ -357,6 +355,7 @@
 
 eh = exthelper.exthelper()
 eh.merge(debugcmd.eh)
+eh.merge(evolvecmd.eh)
 eh.merge(obsexchange.eh)
 eh.merge(checkheads.eh)
 eh.merge(safeguard.eh)
@@ -946,216 +945,6 @@
     _deprecatealias('gup', 'next')
     _deprecatealias('gdown', 'previous')
 
-@eh.command(
-    '^evolve|stabilize|solve',
-    [('n', 'dry-run', False,
-      _('do not perform actions, just print what would be done')),
-     ('', 'confirm', False,
-      _('ask for confirmation before performing the action')),
-     ('A', 'any', False,
-      _('also consider troubled changesets unrelated to current working '
-        'directory')),
-     ('r', 'rev', [], _('solves troubles of these revisions')),
-     ('', 'bumped', False, _('solves only bumped changesets')),
-     ('', 'phase-divergent', False, _('solves only phase-divergent changesets')),
-     ('', 'divergent', False, _('solves only divergent changesets')),
-     ('', 'content-divergent', False, _('solves only content-divergent changesets')),
-     ('', 'unstable', False, _('solves only unstable changesets')),
-     ('', 'orphan', False, _('solves only orphan changesets (default)')),
-     ('a', 'all', False, _('evolve all troubled changesets related to the '
-                           'current  working directory and its descendants')),
-     ('c', 'continue', False, _('continue an interrupted evolution')),
-     ('l', 'list', False, 'provide details on troubled changesets in the repo'),
-    ] + mergetoolopts,
-    _('[OPTIONS]...')
-)
-def evolve(ui, repo, **opts):
-    """solve troubled changesets in your repository
-
-    Modifying history can lead to various types of troubled changesets:
-    unstable, bumped, or divergent. The evolve command resolves your troubles
-    by executing one of the following actions:
-
-    - update working copy to a successor
-    - rebase an unstable changeset
-    - extract the desired changes from a bumped changeset
-    - fuse divergent changesets back together
-
-    If you pass no arguments, evolve works in automatic mode: it will execute a
-    single action to reduce instability related to your working copy. There are
-    two cases for this action. First, if the parent of your working copy is
-    obsolete, evolve updates to the parent's successor. Second, if the working
-    copy parent is not obsolete but has obsolete predecessors, then evolve
-    determines if there is an unstable changeset that can be rebased onto the
-    working copy parent in order to reduce instability.
-    If so, evolve rebases that changeset. If not, evolve refuses to guess your
-    intention, and gives a hint about what you might want to do next.
-
-    Any time evolve creates a changeset, it updates the working copy to the new
-    changeset. (Currently, every successful evolve operation involves an update
-    as well; this may change in future.)
-
-    Automatic mode only handles common use cases. For example, it avoids taking
-    action in the case of ambiguity, and it ignores unstable changesets that
-    are not related to your working copy.
-    It also refuses to solve bumped or divergent changesets unless you
-    explicitly request such behavior (see below).
-
-    Eliminating all instability around your working copy may require multiple
-    invocations of :hg:`evolve`. Alternately, use ``--all`` to recursively
-    select and evolve all unstable changesets that can be rebased onto the
-    working copy parent.
-    This is more powerful than successive invocations, since ``--all`` handles
-    ambiguous cases (e.g. unstable changesets with multiple children) by
-    evolving all branches.
-
-    When your repository cannot be handled by automatic mode, you might need to
-    use ``--rev`` to specify a changeset to evolve. For example, if you have
-    an unstable changeset that is not related to the working copy parent,
-    you could use ``--rev`` to evolve it. Or, if some changeset has multiple
-    unstable children, evolve in automatic mode refuses to guess which one to
-    evolve; you have to use ``--rev`` in that case.
-
-    Alternately, ``--any`` makes evolve search for the next evolvable changeset
-    regardless of whether it is related to the working copy parent.
-
-    You can supply multiple revisions to evolve multiple troubled changesets
-    in a single invocation. In revset terms, ``--any`` is equivalent to ``--rev
-    first(unstable())``. ``--rev`` and ``--all`` are mutually exclusive, as are
-    ``--rev`` and ``--any``.
-
-    ``hg evolve --any --all`` is useful for cleaning up instability across all
-    branches, letting evolve figure out the appropriate order and destination.
-
-    When you have troubled changesets that are not unstable, :hg:`evolve`
-    refuses to consider them unless you specify the category of trouble you
-    wish to resolve, with ``--bumped`` or ``--divergent``. These options are
-    currently mutually exclusive with each other and with ``--unstable``
-    (the default). You can combine ``--bumped`` or ``--divergent`` with
-    ``--rev``, ``--all``, or ``--any``.
-
-    You can also use the evolve command to list the troubles affecting your
-    repository by using the --list flag. You can choose to display only some
-    categories of troubles with the --unstable, --divergent or --bumped flags.
-    """
-
-    opts = evolvecmd._checkevolveopts(repo, opts)
-    # Options
-    contopt = opts['continue']
-    anyopt = opts['any']
-    allopt = opts['all']
-    startnode = repo['.']
-    dryrunopt = opts['dry_run']
-    confirmopt = opts['confirm']
-    revopt = opts['rev']
-
-    troublecategories = ['phase_divergent', 'content_divergent', 'orphan']
-    specifiedcategories = [t.replace('_', '')
-                           for t in troublecategories
-                           if opts[t]]
-    if opts['list']:
-        compat.startpager(ui, 'evolve')
-        evolvecmd.listtroubles(ui, repo, specifiedcategories, **opts)
-        return
-
-    targetcat = 'orphan'
-    if 1 < len(specifiedcategories):
-        msg = _('cannot specify more than one trouble category to solve (yet)')
-        raise error.Abort(msg)
-    elif len(specifiedcategories) == 1:
-        targetcat = specifiedcategories[0]
-    elif repo['.'].obsolete():
-        displayer = cmdutil.show_changeset(ui, repo,
-                                           {'template': shorttemplate})
-        # no args and parent is obsolete, update to successors
-        try:
-            ctx = repo[utility._singlesuccessor(repo, repo['.'])]
-        except utility.MultipleSuccessorsError as exc:
-            repo.ui.write_err('parent is obsolete with multiple successors:\n')
-            for ln in exc.successorssets:
-                for n in ln:
-                    displayer.show(repo[n])
-            return 2
-
-        ui.status(_('update:'))
-        if not ui.quiet:
-            displayer.show(ctx)
-
-        if dryrunopt:
-            return 0
-        res = hg.update(repo, ctx.rev())
-        if ctx != startnode:
-            ui.status(_('working directory is now at %s\n') % ctx)
-        return res
-
-    ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'evolve')
-    troubled = set(repo.revs('troubled()'))
-
-    # Progress handling
-    seen = 1
-    count = allopt and len(troubled) or 1
-    showprogress = allopt
-
-    def progresscb():
-        if revopt or allopt:
-            ui.progress(_('evolve'), seen, unit=_('changesets'), total=count)
-
-    # Continuation handling
-    if contopt:
-        evolvestate = state.cmdstate(repo)
-        if not evolvestate:
-            raise error.Abort('no evolve to continue')
-        evolvestate.load()
-        orig = repo[evolvestate['current']]
-        with repo.wlock(), repo.lock():
-            ctx = orig
-            source = ctx.extra().get('source')
-            extra = {}
-            if source:
-                extra['source'] = source
-                extra['intermediate-source'] = ctx.hex()
-            else:
-                extra['source'] = ctx.hex()
-            user = ctx.user()
-            date = ctx.date()
-            message = ctx.description()
-            ui.status(_('evolving %d:%s "%s"\n') % (ctx.rev(), ctx,
-                                                    message.split('\n', 1)[0]))
-            targetphase = max(ctx.phase(), phases.draft)
-            overrides = {('phases', 'new-commit'): targetphase}
-
-            with repo.ui.configoverride(overrides, 'evolve-continue'):
-                node = repo.commit(text=message, user=user,
-                                   date=date, extra=extra)
-
-            obsolete.createmarkers(repo, [(ctx, (repo[node],))])
-            evolvestate.delete()
-            return
-
-    cmdutil.bailifchanged(repo)
-
-    revs = evolvecmd._selectrevs(repo, allopt, revopt, anyopt, targetcat)
-
-    if not revs:
-        return evolvecmd._handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat)
-
-    # For the progress bar to show
-    count = len(revs)
-    replacements = {}
-    # Order the revisions
-    if targetcat == 'orphan':
-        revs = evolvecmd._orderrevs(repo, revs)
-    for rev in revs:
-        curctx = repo[rev]
-        progresscb()
-        ret = evolvecmd._solveone(ui, repo, curctx, dryrunopt, confirmopt,
-                                  progresscb, targetcat)
-        seen += 1
-        if ret[0]:
-            replacements[curctx.node()] = [ret[1]]
-    progresscb()
-    evolvecmd._cleanup(ui, repo, startnode, showprogress)
-
 def _gettopic(ctx):
     """handle topic fetching with or without the extension"""
     return getattr(ctx, 'topic', lambda: '')()
--- a/hgext3rd/evolve/evolvecmd.py	Sun Jan 21 20:33:39 2018 +0530
+++ b/hgext3rd/evolve/evolvecmd.py	Fri Jan 19 19:32:34 2018 +0530
@@ -32,6 +32,7 @@
 from . import (
     cmdrewrite,
     compat,
+    exthelper,
     rewriteutil,
     state,
     utility,
@@ -42,7 +43,9 @@
 _bookmarksupdater = rewriteutil.bookmarksupdater
 sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
 
+eh = exthelper.exthelper()
 _bookmarksupdater = rewriteutil.bookmarksupdater
+mergetoolopts = cmdutil.mergetoolopts
 
 def _solveone(ui, repo, ctx, dryrun, confirm, progresscb, category):
     """Resolve the troubles affecting one revision
@@ -949,3 +952,213 @@
         })
 
     return divergence
+
+@eh.command(
+    '^evolve|stabilize|solve',
+    [('n', 'dry-run', False,
+      _('do not perform actions, just print what would be done')),
+     ('', 'confirm', False,
+      _('ask for confirmation before performing the action')),
+     ('A', 'any', False,
+      _('also consider troubled changesets unrelated to current working '
+        'directory')),
+     ('r', 'rev', [], _('solves troubles of these revisions')),
+     ('', 'bumped', False, _('solves only bumped changesets')),
+     ('', 'phase-divergent', False, _('solves only phase-divergent changesets')),
+     ('', 'divergent', False, _('solves only divergent changesets')),
+     ('', 'content-divergent', False, _('solves only content-divergent changesets')),
+     ('', 'unstable', False, _('solves only unstable changesets')),
+     ('', 'orphan', False, _('solves only orphan changesets (default)')),
+     ('a', 'all', False, _('evolve all troubled changesets related to the '
+                           'current  working directory and its descendants')),
+     ('c', 'continue', False, _('continue an interrupted evolution')),
+     ('l', 'list', False, 'provide details on troubled changesets in the repo'),
+    ] + mergetoolopts,
+    _('[OPTIONS]...')
+)
+def evolve(ui, repo, **opts):
+    """solve troubled changesets in your repository
+
+    Modifying history can lead to various types of troubled changesets:
+    unstable, bumped, or divergent. The evolve command resolves your troubles
+    by executing one of the following actions:
+
+    - update working copy to a successor
+    - rebase an unstable changeset
+    - extract the desired changes from a bumped changeset
+    - fuse divergent changesets back together
+
+    If you pass no arguments, evolve works in automatic mode: it will execute a
+    single action to reduce instability related to your working copy. There are
+    two cases for this action. First, if the parent of your working copy is
+    obsolete, evolve updates to the parent's successor. Second, if the working
+    copy parent is not obsolete but has obsolete predecessors, then evolve
+    determines if there is an unstable changeset that can be rebased onto the
+    working copy parent in order to reduce instability.
+    If so, evolve rebases that changeset. If not, evolve refuses to guess your
+    intention, and gives a hint about what you might want to do next.
+
+    Any time evolve creates a changeset, it updates the working copy to the new
+    changeset. (Currently, every successful evolve operation involves an update
+    as well; this may change in future.)
+
+    Automatic mode only handles common use cases. For example, it avoids taking
+    action in the case of ambiguity, and it ignores unstable changesets that
+    are not related to your working copy.
+    It also refuses to solve bumped or divergent changesets unless you
+    explicitly request such behavior (see below).
+
+    Eliminating all instability around your working copy may require multiple
+    invocations of :hg:`evolve`. Alternately, use ``--all`` to recursively
+    select and evolve all unstable changesets that can be rebased onto the
+    working copy parent.
+    This is more powerful than successive invocations, since ``--all`` handles
+    ambiguous cases (e.g. unstable changesets with multiple children) by
+    evolving all branches.
+
+    When your repository cannot be handled by automatic mode, you might need to
+    use ``--rev`` to specify a changeset to evolve. For example, if you have
+    an unstable changeset that is not related to the working copy parent,
+    you could use ``--rev`` to evolve it. Or, if some changeset has multiple
+    unstable children, evolve in automatic mode refuses to guess which one to
+    evolve; you have to use ``--rev`` in that case.
+
+    Alternately, ``--any`` makes evolve search for the next evolvable changeset
+    regardless of whether it is related to the working copy parent.
+
+    You can supply multiple revisions to evolve multiple troubled changesets
+    in a single invocation. In revset terms, ``--any`` is equivalent to ``--rev
+    first(unstable())``. ``--rev`` and ``--all`` are mutually exclusive, as are
+    ``--rev`` and ``--any``.
+
+    ``hg evolve --any --all`` is useful for cleaning up instability across all
+    branches, letting evolve figure out the appropriate order and destination.
+
+    When you have troubled changesets that are not unstable, :hg:`evolve`
+    refuses to consider them unless you specify the category of trouble you
+    wish to resolve, with ``--bumped`` or ``--divergent``. These options are
+    currently mutually exclusive with each other and with ``--unstable``
+    (the default). You can combine ``--bumped`` or ``--divergent`` with
+    ``--rev``, ``--all``, or ``--any``.
+
+    You can also use the evolve command to list the troubles affecting your
+    repository by using the --list flag. You can choose to display only some
+    categories of troubles with the --unstable, --divergent or --bumped flags.
+    """
+
+    opts = _checkevolveopts(repo, opts)
+    # Options
+    contopt = opts['continue']
+    anyopt = opts['any']
+    allopt = opts['all']
+    startnode = repo['.']
+    dryrunopt = opts['dry_run']
+    confirmopt = opts['confirm']
+    revopt = opts['rev']
+
+    troublecategories = ['phase_divergent', 'content_divergent', 'orphan']
+    specifiedcategories = [t.replace('_', '')
+                           for t in troublecategories
+                           if opts[t]]
+    if opts['list']:
+        compat.startpager(ui, 'evolve')
+        listtroubles(ui, repo, specifiedcategories, **opts)
+        return
+
+    targetcat = 'orphan'
+    if 1 < len(specifiedcategories):
+        msg = _('cannot specify more than one trouble category to solve (yet)')
+        raise error.Abort(msg)
+    elif len(specifiedcategories) == 1:
+        targetcat = specifiedcategories[0]
+    elif repo['.'].obsolete():
+        displayer = cmdutil.show_changeset(ui, repo,
+                                           {'template': shorttemplate})
+        # no args and parent is obsolete, update to successors
+        try:
+            ctx = repo[utility._singlesuccessor(repo, repo['.'])]
+        except utility.MultipleSuccessorsError as exc:
+            repo.ui.write_err('parent is obsolete with multiple successors:\n')
+            for ln in exc.successorssets:
+                for n in ln:
+                    displayer.show(repo[n])
+            return 2
+
+        ui.status(_('update:'))
+        if not ui.quiet:
+            displayer.show(ctx)
+
+        if dryrunopt:
+            return 0
+        res = hg.update(repo, ctx.rev())
+        if ctx != startnode:
+            ui.status(_('working directory is now at %s\n') % ctx)
+        return res
+
+    ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'evolve')
+    troubled = set(repo.revs('troubled()'))
+
+    # Progress handling
+    seen = 1
+    count = allopt and len(troubled) or 1
+    showprogress = allopt
+
+    def progresscb():
+        if revopt or allopt:
+            ui.progress(_('evolve'), seen, unit=_('changesets'), total=count)
+
+    # Continuation handling
+    if contopt:
+        evolvestate = state.cmdstate(repo)
+        if not evolvestate:
+            raise error.Abort('no evolve to continue')
+        evolvestate.load()
+        orig = repo[evolvestate['current']]
+        with repo.wlock(), repo.lock():
+            ctx = orig
+            source = ctx.extra().get('source')
+            extra = {}
+            if source:
+                extra['source'] = source
+                extra['intermediate-source'] = ctx.hex()
+            else:
+                extra['source'] = ctx.hex()
+            user = ctx.user()
+            date = ctx.date()
+            message = ctx.description()
+            ui.status(_('evolving %d:%s "%s"\n') % (ctx.rev(), ctx,
+                                                    message.split('\n', 1)[0]))
+            targetphase = max(ctx.phase(), phases.draft)
+            overrides = {('phases', 'new-commit'): targetphase}
+
+            with repo.ui.configoverride(overrides, 'evolve-continue'):
+                node = repo.commit(text=message, user=user,
+                                   date=date, extra=extra)
+
+            obsolete.createmarkers(repo, [(ctx, (repo[node],))])
+            evolvestate.delete()
+            return
+
+    cmdutil.bailifchanged(repo)
+
+    revs = _selectrevs(repo, allopt, revopt, anyopt, targetcat)
+
+    if not revs:
+        return _handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat)
+
+    # For the progress bar to show
+    count = len(revs)
+    replacements = {}
+    # Order the revisions
+    if targetcat == 'orphan':
+        revs = _orderrevs(repo, revs)
+    for rev in revs:
+        curctx = repo[rev]
+        progresscb()
+        ret = _solveone(ui, repo, curctx, dryrunopt, confirmopt,
+                        progresscb, targetcat)
+        seen += 1
+        if ret[0]:
+            replacements[curctx.node()] = [ret[1]]
+    progresscb()
+    _cleanup(ui, repo, startnode, showprogress)