evolve: unify revision handling and rework error message
authorPierre-Yves David <pierre-yves.david@fb.com>
Fri, 19 Jun 2015 14:26:33 -0700
changeset 1410 2c451fece7a6
parent 1409 3276730e4b32
child 1411 64515965c0df
evolve: unify revision handling and rework error message This changesets do a massive refactoring of the way evolve select changesets to be evolve. We now use a two stages approach: 1) read command line argument and produce a list of revision to evolve. 2) evolve all these revisions. This allow a much cleaner, robust and extensible code. In the process the error message issued when there is nothing to evolve have been updated to informs about other troubles in the repository and point at useful option to solve them. The 'update' case is handled independently at the start of the function.
README
hgext/evolve.py
tests/test-evolve.t
tests/test-stabilize-order.t
--- a/README	Fri Jun 19 14:32:54 2015 -0700
+++ b/README	Fri Jun 19 14:26:33 2015 -0700
@@ -57,6 +57,8 @@
 - evolve: revision are processed in the order they stack on destination
 - evolve: properly skip unstable revision with non-evolved unstable parent
 - evolve: gain --unstable --divergent --bumped flag to select the trouble
+- evolve: issue more useful error message and hint when evolve has nothing to
+  do as invocated.
 
 5.1.5 --
 
--- a/hgext/evolve.py	Fri Jun 19 14:32:54 2015 -0700
+++ b/hgext/evolve.py	Fri Jun 19 14:26:33 2015 -0700
@@ -1204,54 +1204,100 @@
     finally:
         lockmod.release(tr, lock, wlock)
 
-def _handlenotrouble(ui, repo, startnode, dryrunopt):
+def _handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat):
     """Used by the evolve function to display an error message when
     no troubles can be resolved"""
-    if repo['.'].obsolete():
-        displayer = cmdutil.show_changeset(
-            ui, repo, {'template': shorttemplate})
-        successors = set()
-
-        for successorsset in obsolete.successorssets(repo, repo['.'].node()):
-            for nodeid in successorsset:
-                successors.add(repo[nodeid])
-
-        if not successors:
-            ui.warn(_('parent is obsolete without successors; ' +
-                      'likely killed\n'))
-            return 2
-
-        elif len(successors) > 1:
-            ui.warn(_('parent is obsolete with multiple successors:\n'))
-
-            for ctx in sorted(successors, key=lambda ctx: ctx.rev()):
-                displayer.show(ctx)
-
-            return 2
-
+    troublecategories = ['bumped', 'divergent', 'unstable']
+    unselectedcategories = [c for c in troublecategories if c != targetcat]
+    msg = None
+    hint = None
+
+    troubled = {
+            "unstable": repo.revs("unstable()"),
+            "divergent": repo.revs("divergent()"),
+            "bumped": repo.revs("bumped()"),
+            "all": repo.revs("troubled()"),
+    }
+
+
+    hintmap = {
+            'bumped': _("do you want to use --bumped"),
+            'bumped+divergent': _("do you want to use --bumped or --divergent"),
+            'bumped+unstable': _("do you want to use --bumped or --unstable"),
+            'divergent': _("do you want to use --divergent"),
+            'divergent+unstable': _("do you want to use --divergent"
+                                    " or --unstable"),
+            'unstable': _("do you want to use --unstable"),
+            'any+bumped': _("do you want to use --any (or --rev) and --bumped"),
+            'any+bumped+divergent': _("do you want to use --any (or --rev) and"
+                                      " --bumped or --divergent"),
+            'any+bumped+unstable': _("do you want to use --any (or --rev) and"
+                                     "--bumped or --unstable"),
+            'any+divergent': _("do you want to use --any (or --rev) and"
+                               " --divergent"),
+            'any+divergent+unstable': _("do you want to use --any (or --rev)"
+                                        " and --divergent or --unstable"),
+            'any+unstable': _("do you want to use --any (or --rev)"
+                              "and --unstable"),
+    }
+
+    if revopt:
+        revs = scmutil.revrange(repo, revopt)
+        if not revs:
+            msg = _("set of specified revisions is empty")
         else:
-            ctx = successors.pop()
-
-            ui.status(_('update:'))
-            if not ui.quiet:
-                displayer.show(ctx)
-
-            if dryrunopt:
-                return 0
+            msg = _("no %s changesets in specified revisions") % targetcat
+            othertroubles = []
+            for cat in unselectedcategories:
+                if revs & troubled[cat]:
+                    othertroubles.append(cat)
+            if othertroubles:
+                hint = hintmap['+'.join(othertroubles)]
+
+    elif allopt or anyopt:
+        msg = _("no %s changesets to evolve") % targetcat
+        othertroubles = []
+        for cat in unselectedcategories:
+            if troubled[cat]:
+                othertroubles.append(cat)
+        if othertroubles:
+            hint = hintmap['+'.join(othertroubles)]
+
+    else:
+        # evolve without any option = relative to the current wdir
+        if targetcat == 'unstable':
+            msg = _("nothing to evolve on current working copy parent")
+        else:
+            msg = _("current working copy parent is not %s") % targetcat
+
+        p1 = repo['.'].rev()
+        othertroubles = []
+        for cat in unselectedcategories:
+            if p1 in troubled[cat]:
+                othertroubles.append(cat)
+        if othertroubles:
+            hint = hintmap['+'.join(othertroubles)]
+        else:
+            l = len(troubled[targetcat])
+            if l:
+                hint = (_("%d other %s in the repository, do you want --any or --rev")
+                        % (l, targetcat))
             else:
-                res = hg.update(repo, ctx.rev())
-                if ctx != startnode:
-                    ui.status(_('working directory is now at %s\n') % ctx)
-                return res
-
-    troubled = repo.revs('troubled()')
-    if troubled:
-        ui.write_err(_('nothing to evolve here\n'))
-        ui.status(_('(%i troubled changesets, do you want --any ?)\n')
-                  % len(troubled))
+                othertroubles = []
+                for cat in unselectedcategories:
+                    if troubled[cat]:
+                        othertroubles.append(cat)
+                if othertroubles:
+                    hint = hintmap['any+'+('+'.join(othertroubles))]
+                else:
+                    msg = _("no troubled changesets")
+
+    assert msg is not None
+    ui.write_err(msg+"\n")
+    if hint:
+        ui.write_err("("+hint+")\n")
         return 2
     else:
-        ui.write_err(_('no troubled changesets\n'))
         return 1
 
 def _cleanup(ui, repo, startnode, showprogress):
@@ -1316,6 +1362,24 @@
                 rdependencies[succ].add(r)
     return dependencies, rdependencies
 
+def _selectrevs(repo, allopt, revopt, anyopt, targetcat):
+    """select troubles in repo matching according to given options"""
+    revs = set()
+    if allopt or revopt:
+        revs = repo.revs(targetcat+'()')
+        if revopt:
+            revs = scmutil.revrange(repo, revopt) & revs
+    elif anyopt:
+        revs = repo.revs('first(%s())' % (targetcat))
+    elif targetcat == 'unstable':
+        tro = _stabilizableunstable(repo, repo['.'])
+        if tro is not None:
+            revs = set([tro])
+    elif targetcat in repo['.'].troubles():
+        revs = set([repo['.'].rev()])
+    return revs
+
+
 def orderrevs(repo, revs):
     """ Compute an ordering to solve instability for the given revs
 
@@ -1425,6 +1489,17 @@
             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()'))
 
@@ -1450,26 +1525,13 @@
 
     if revopt and allopt:
         raise util.Abort('cannot specify both "--rev" and "--all"')
-
-    revs = set()
-    if allopt or revopt:
-        revs = repo.revs(targetcat+'()')
-        if revopt:
-            revs = repo.revs(revopt) & revs
-    elif anyopt:
-        revs = repo.revs('first(%s())' % (targetcat))
-    elif targetcat == 'unstable':
-        tro = _stabilizableunstable(repo, repo['.'])
-        if tro is None:
-            return _handlenotrouble(ui, repo, startnode, dryrunopt)
-        revs = set([tro])
-    elif targetcat in repo['.'].troubles():
-        revs = set([repo['.'].rev()])
     if revopt and anyopt:
         raise util.Abort('cannot specify both "--rev" and "--any"')
+
+    revs = _selectrevs(repo, allopt, revopt, anyopt, targetcat)
+
     if not revs:
-        msg = "no troubled changes in the specified revisions"
-        raise util.Abort(msg)
+        return _handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat)
 
     # For the progress bar to show
     count = len(revs)
--- a/tests/test-evolve.t	Fri Jun 19 14:32:54 2015 -0700
+++ b/tests/test-evolve.t	Fri Jun 19 14:26:33 2015 -0700
@@ -880,8 +880,8 @@
   $ hg up 8
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg evolve
-  nothing to evolve here
-  (2 troubled changesets, do you want --any ?)
+  nothing to evolve on current working copy parent
+  (2 other unstable in the repository, do you want --any or --rev)
   [2]
 
 
@@ -1017,12 +1017,13 @@
 
 Evolving an empty revset should do nothing
   $ hg evolve --rev "16 and 15"
-  abort: no troubled changes in the specified revisions
-  [255]
+  set of specified revisions is empty
+  [1]
 
   $ hg evolve --rev "14::" --bumped
-  abort: no troubled changes in the specified revisions
-  [255]
+  no bumped changesets in specified revisions
+  (do you want to use --unstable)
+  [2]
   $ hg evolve --rev "14::" --unstable
   move:[15] add gg
   atop:[18] a3
--- a/tests/test-stabilize-order.t	Fri Jun 19 14:32:54 2015 -0700
+++ b/tests/test-stabilize-order.t	Fri Jun 19 14:26:33 2015 -0700
@@ -153,8 +153,8 @@
   $ hg up 9
   2 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg evolve -v
-  nothing to evolve here
-  (1 troubled changesets, do you want --any ?)
+  nothing to evolve on current working copy parent
+  (1 other unstable in the repository, do you want --any or --rev)
   [2]
   $ hg evolve --any -v
   move:[9] addc
@@ -180,5 +180,5 @@
   o  0:c471ef929e6a@default(draft) addroot
   
   $ hg evolve --any -v
-  abort: no troubled changes in the specified revisions
-  [255]
+  no unstable changesets to evolve
+  [1]