merge: return an attrs class from update() and applyupdates()
authorGregory Szorc <gregory.szorc@gmail.com>
Mon, 05 Mar 2018 00:02:13 -0500
changeset 37107 71543b942eea
parent 37106 3d3cff1f6bde
child 37108 0351fb0153ba
merge: return an attrs class from update() and applyupdates() Previously, we returned a tuple containing counts. The result of an update is kind of complex and the use of tuples with nameless fields made the code a bit harder to read and constrained future expansion of the return value. Let's invent an attrs-defined class for representing the result of an update operation. We provide __getitem__ and __len__ implementations for backwards compatibility as a container type to minimize code churn. In (at least) Python 2, the % operator seems to insist on using tuples. So we had to update a consumer using the % operator. .. api:: merge.update() and merge.applyupdates() now return a class with named attributes instead of a tuple. Switch consumers to access elements by name instead of by offset. Differential Revision: https://phab.mercurial-scm.org/D2692
mercurial/hg.py
mercurial/merge.py
--- a/mercurial/hg.py	Fri Feb 23 11:48:58 2018 +0530
+++ b/mercurial/hg.py	Mon Mar 05 00:02:13 2018 -0500
@@ -752,7 +752,9 @@
     if quietempty and not any(stats):
         return
     repo.ui.status(_("%d files updated, %d files merged, "
-                     "%d files removed, %d files unresolved\n") % stats)
+                     "%d files removed, %d files unresolved\n") % (
+                   stats.updatedcount, stats.mergedcount,
+                   stats.removedcount, stats.unresolvedcount))
 
 def updaterepo(repo, node, overwrite, updatecheck=None):
     """Update the working directory to node.
--- a/mercurial/merge.py	Fri Feb 23 11:48:58 2018 +0530
+++ b/mercurial/merge.py	Mon Mar 05 00:02:13 2018 -0500
@@ -22,6 +22,9 @@
     nullid,
     nullrev,
 )
+from .thirdparty import (
+    attr,
+)
 from . import (
     copies,
     error,
@@ -1398,6 +1401,30 @@
     prefetch = scmutil.fileprefetchhooks
     prefetch(repo, ctx, [f for sublist in oplist for f, args, msg in sublist])
 
+@attr.s(frozen=True)
+class updateresult(object):
+    updatedcount = attr.ib()
+    mergedcount = attr.ib()
+    removedcount = attr.ib()
+    unresolvedcount = attr.ib()
+
+    # TODO remove container emulation once consumers switch to new API.
+
+    def __getitem__(self, x):
+        if x == 0:
+            return self.updatedcount
+        elif x == 1:
+            return self.mergedcount
+        elif x == 2:
+            return self.removedcount
+        elif x == 3:
+            return self.unresolvedcount
+        else:
+            raise IndexError('can only access items 0-3')
+
+    def __len__(self):
+        return 4
+
 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
     """apply the merge action list to the working directory
 
@@ -1581,7 +1608,8 @@
         if not proceed:
             # XXX setting unresolved to at least 1 is a hack to make sure we
             # error out
-            return updated, merged, removed, max(len(unresolvedf), 1)
+            return updateresult(updated, merged, removed,
+                                max(len(unresolvedf), 1))
         newactions = []
         for f, args, msg in mergeactions:
             if f in unresolvedf:
@@ -1656,8 +1684,7 @@
         actions['m'] = [a for a in actions['m'] if a[0] in mfiles]
 
     progress(_updating, None, total=numupdates, unit=_files)
-
-    return updated, merged, removed, unresolved
+    return updateresult(updated, merged, removed, unresolved)
 
 def recordupdates(repo, actions, branchmerge):
     "record merge actions to the dirstate"
@@ -1878,7 +1905,7 @@
                 # call the hooks and exit early
                 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
                 repo.hook('update', parent1=xp2, parent2='', error=0)
-                return 0, 0, 0, 0
+                return updateresult(0, 0, 0, 0)
 
             if (updatecheck == 'linear' and
                     pas not in ([p1], [p2])):  # nonlinear