# HG changeset patch # User Gregory Szorc # Date 1482779489 25200 # Node ID 95325386cd1a250a60299fea6359355cf40df62e # Parent 0064a1eb28e246ded9b726c696d048143d1b23f1 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. diff -r 0064a1eb28e2 -r 95325386cd1a mercurial/exchange.py --- 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."""