grsummary: handle non-hash ids when checking state

Previously, a guest's state (localmods/syncok/unsynced) was computed by
manually comparing the desired changeset id to the full hash of the checked-out
revision, the tags, the bookmarks and the branch. This failed, for example,
when the desired id was an abbreviated hash, or a tag.

The current solution treats the desired id as a revset, and compares the
returned node to the checked-out node. This is more robust: it allows the user
to specify the desired changeset in any way that Mercurial recognizes, and the
equality check no longer depends on the specification method.
1 files changed, 26 insertions(+), 29 deletions(-)

M guestrepo/guestrepo.py
M guestrepo/guestrepo.py +26 -29
@@ 330,9 330,33 @@ def summary(ui, repo, **opts):
     else:
         for guest in filterwarnguests(ui, guests):
             guestrepo = hg.repository(ui, guest.root, create=False)
+
+            # Does the guest have the expected commit checked out?
+            is_synced = guestrepo[guest.csid] == guestrepo['.']
+
+            # Is the expected commit unknown to the outside world?
+            if (hasattr(guestrepo, 'githandler')
+                and os.path.exists(guestrepo.githandler.gitdir)):
+                # This is an hggit repo: unpushed commits have no git id
+                has_outgoing = bool(list(guestrepo.set('first(not(fromgit()))')))
+            else:
+                # This is an hg repo: unpushed commits are in draft phase
+                has_outgoing = bool(list(guestrepo.set('first(draft())')))
+
+            # Are there uncommitted changes?
+            gr_changed = changed(guestrepo, unknown=True)
+
+            # Compute the state
+            if is_synced and (has_outgoing or gr_changed):
+                state = "localmods"
+            if is_synced and not (has_outgoing or gr_changed):
+                state = "syncok"
+            if not is_synced:
+                state = "unsynced"
+
+            # Now let's generate the output
             guestctx = guestrepo['.']  # The checked-out commit
             parents = guestrepo[None].parents()  # The working dir parents
-
             output = [guest.canonpath, "(%s)" % guestctx.branch()]
 
             if opts.get('id'):

          
@@ 346,7 370,6 @@ def summary(ui, repo, **opts):
                 phases = '+'.join(p.phasestr() for p in parents)
                 output.append(str(phases))
 
-
             tags = guestctx.tags()
             if tags:
                 output.append( '/'.join(tags) )

          
@@ 361,37 384,11 @@ def summary(ui, repo, **opts):
                 # TODO: rework to correct Mercurial interfact
                 currentbookmark = bookmarks._readactive(guestrepo, bmarks)
 
-
             if currentbookmark:
                 output.append('*' + currentbookmark)
 
-            gr_changed = False
-            if changed(guestrepo, unknown=True):
+            if gr_changed:
                 output.append('*')
-                gr_changed = True
-
-            # Colorize output
-            if (guest.csid == node.hex(guestctx.parents()[0].node())
-                or guest.csid == guestctx.branch()
-                or guest.csid in guestctx.tags()
-                or guest.csid in guestctx.bookmarks()):
-
-                # Does the guestrepo have unpushed commits?
-                if (hasattr(guestrepo, 'githandler')
-                    and os.path.exists(guestrepo.githandler.gitdir)):
-                    # This is an hggit repo: unpushed commits have no git id
-                    outgoing = list(guestrepo.set('first(not(fromgit()))'))
-                else:
-                    # This is an hg repo: unpushed commits are in draft phase
-                    outgoing = list(guestrepo.set('first(draft())'))
-
-                if outgoing or gr_changed:
-                    state = "localmods"
-                else:
-                    state = "syncok"
-            else:
-                state = "unsynced"
-
 
             ui.write("%s\n" % ' '.join(output), label='guestrepo.' + state)