changeset 30685:95325386cd1a

exchange: use rich class for sorting clone bundle entries Python 3 removed the "cmp" argument from sorted(). Custom sorting in Python 3 must be implemented with the dunder comparison methods on types and/or with a "key" function. This patch converts our custom "cmp" function to a custom type. The implementation is very similar to functools.cmp_to_key(). However, cmp_to_key() doesn't exist in Python 2, so we can't use it. This was the only use of the "cmp" argument to sorted() in the code base.
author Gregory Szorc <gregory.szorc@gmail.com>
date Mon, 26 Dec 2016 12:11:29 -0700
parents 0064a1eb28e2
children 8352c42a0a0d
files mercurial/exchange.py
diffstat 1 files changed, 41 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/exchange.py	Mon Dec 26 00:02:42 2016 +0000
+++ b/mercurial/exchange.py	Mon Dec 26 12:11:29 2016 -0700
@@ -1902,18 +1902,22 @@
 
     return newentries
 
-def sortclonebundleentries(ui, entries):
-    prefers = ui.configlist('ui', 'clonebundleprefers', default=[])
-    if not prefers:
-        return list(entries)
+class clonebundleentry(object):
+    """Represents an item in a clone bundles manifest.
+
+    This rich class is needed to support sorting since sorted() in Python 3
+    doesn't support ``cmp`` and our comparison is complex enough that ``key=``
+    won't work.
+    """
 
-    prefers = [p.split('=', 1) for p in prefers]
+    def __init__(self, value, prefers):
+        self.value = value
+        self.prefers = prefers
 
-    # Our sort function.
-    def compareentry(a, b):
-        for prefkey, prefvalue in prefers:
-            avalue = a.get(prefkey)
-            bvalue = b.get(prefkey)
+    def _cmp(self, other):
+        for prefkey, prefvalue in self.prefers:
+            avalue = self.value.get(prefkey)
+            bvalue = other.value.get(prefkey)
 
             # Special case for b missing attribute and a matches exactly.
             if avalue is not None and bvalue is None and avalue == prefvalue:
@@ -1944,7 +1948,33 @@
         # back to index order.
         return 0
 
-    return sorted(entries, cmp=compareentry)
+    def __lt__(self, other):
+        return self._cmp(other) < 0
+
+    def __gt__(self, other):
+        return self._cmp(other) > 0
+
+    def __eq__(self, other):
+        return self._cmp(other) == 0
+
+    def __le__(self, other):
+        return self._cmp(other) <= 0
+
+    def __ge__(self, other):
+        return self._cmp(other) >= 0
+
+    def __ne__(self, other):
+        return self._cmp(other) != 0
+
+def sortclonebundleentries(ui, entries):
+    prefers = ui.configlist('ui', 'clonebundleprefers', default=[])
+    if not prefers:
+        return list(entries)
+
+    prefers = [p.split('=', 1) for p in prefers]
+
+    items = sorted(clonebundleentry(v, prefers) for v in entries)
+    return [i.value for i in items]
 
 def trypullbundlefromurl(ui, repo, url):
     """Attempt to apply a bundle from a URL."""