D338: wireproto: use new peer interface

indygreg (Gregory Szorc) phabricator at mercurial-scm.org
Fri Aug 11 04:20:56 UTC 2017


indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  The wirepeer class provides concrete implementations of peer interface
  methods for calling wire protocol commands. It makes sense for this
  class to inherit from the peer abstract base class. So we change
  that.
  
  Since httppeer and sshpeer have already been converted to the new
  interface, peerrepository is no longer adding any value. So it has
  been removed. httppeer and sshpeer have been updated to reflect the
  loss of peerrepository and the inheritance of the abstract base
  class in wirepeer.
  
  The code changes in wirepeer are reordering of methods to group
  by interface.
  
  Some Python code in tests was updated to reflect changed APIs.
  
  .. api::
  
    peer.peerrepository has been removed. Use repository.peer abstract
    base class to represent a peer repository.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D338

AFFECTED FILES
  mercurial/httppeer.py
  mercurial/peer.py
  mercurial/sshpeer.py
  mercurial/wireproto.py
  tests/notcapable
  tests/test-wireproto.py

CHANGE DETAILS

diff --git a/tests/test-wireproto.py b/tests/test-wireproto.py
--- a/tests/test-wireproto.py
+++ b/tests/test-wireproto.py
@@ -19,7 +19,26 @@
     def __init__(self, serverrepo):
         self.serverrepo = serverrepo
 
-    def _capabilities(self):
+    @property
+    def ui(self):
+        return self.serverrepo.ui
+
+    def url(self):
+        return 'test'
+
+    def local(self):
+        return None
+
+    def peer(self):
+        return self
+
+    def canpush(self):
+        return True
+
+    def close(self):
+        pass
+
+    def capabilities(self):
         return ['batch']
 
     def _call(self, cmd, **args):
diff --git a/tests/notcapable b/tests/notcapable
--- a/tests/notcapable
+++ b/tests/notcapable
@@ -6,9 +6,9 @@
 fi
 
 cat > notcapable-$CAP.py << EOF
-from mercurial import extensions, peer, localrepo
+from mercurial import extensions, localrepo, repository
 def extsetup():
-    extensions.wrapfunction(peer.peerrepository, 'capable', wrapcapable)
+    extensions.wrapfunction(repository.peer, 'capable', wrapcapable)
     extensions.wrapfunction(localrepo.localrepository, 'peer', wrappeer)
 def wrapcapable(orig, self, name, *args, **kwargs):
     if name in '$CAP'.split(' '):
diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py
--- a/mercurial/wireproto.py
+++ b/mercurial/wireproto.py
@@ -27,6 +27,7 @@
     peer,
     pushkey as pushkeymod,
     pycompat,
+    repository,
     streamclone,
     util,
 )
@@ -212,36 +213,15 @@
 
 # client side
 
-class wirepeer(peer.peerrepository):
+class wirepeer(repository.legacypeer):
     """Client-side interface for communicating with a peer repository.
 
     Methods commonly call wire protocol commands of the same name.
 
     See also httppeer.py and sshpeer.py for protocol-specific
     implementations of this interface.
     """
-    def _submitbatch(self, req):
-        """run batch request <req> on the server
-
-        Returns an iterator of the raw responses from the server.
-        """
-        rsp = self._callstream("batch", cmds=encodebatchcmds(req))
-        chunk = rsp.read(1024)
-        work = [chunk]
-        while chunk:
-            while ';' not in chunk and chunk:
-                chunk = rsp.read(1024)
-                work.append(chunk)
-            merged = ''.join(work)
-            while ';' in merged:
-                one, merged = merged.split(';', 1)
-                yield unescapearg(one)
-            chunk = rsp.read(1024)
-            work = [merged, chunk]
-        yield unescapearg(''.join(work))
-
-    def _submitone(self, op, args):
-        return self._call(op, **args)
+    # Begin of basewirepeer interface.
 
     def iterbatch(self):
         return remoteiterbatcher(self)
@@ -293,26 +273,17 @@
         except TypeError:
             self._abort(error.ResponseError(_("unexpected response:"), d))
 
-    def branches(self, nodes):
-        n = encodelist(nodes)
-        d = self._call("branches", nodes=n)
-        try:
-            br = [tuple(decodelist(b)) for b in d.splitlines()]
-            return br
-        except ValueError:
-            self._abort(error.ResponseError(_("unexpected response:"), d))
-
-    def between(self, pairs):
-        batch = 8 # avoid giant requests
-        r = []
-        for i in xrange(0, len(pairs), batch):
-            n = " ".join([encodelist(p, '-') for p in pairs[i:i + batch]])
-            d = self._call("between", pairs=n)
-            try:
-                r.extend(l and decodelist(l) or [] for l in d.splitlines())
-            except ValueError:
-                self._abort(error.ResponseError(_("unexpected response:"), d))
-        return r
+    @batchable
+    def listkeys(self, namespace):
+        if not self.capable('pushkey'):
+            yield {}, None
+        f = future()
+        self.ui.debug('preparing listkeys for "%s"\n' % namespace)
+        yield {'namespace': encoding.fromlocal(namespace)}, f
+        d = f.value
+        self.ui.debug('received listkey for "%s": %i bytes\n'
+                      % (namespace, len(d)))
+        yield pushkeymod.decodekeys(d)
 
     @batchable
     def pushkey(self, namespace, key, old, new):
@@ -335,34 +306,9 @@
             self.ui.status(_('remote: '), l)
         yield d
 
-    @batchable
-    def listkeys(self, namespace):
-        if not self.capable('pushkey'):
-            yield {}, None
-        f = future()
-        self.ui.debug('preparing listkeys for "%s"\n' % namespace)
-        yield {'namespace': encoding.fromlocal(namespace)}, f
-        d = f.value
-        self.ui.debug('received listkey for "%s": %i bytes\n'
-                      % (namespace, len(d)))
-        yield pushkeymod.decodekeys(d)
-
     def stream_out(self):
         return self._callstream('stream_out')
 
-    def changegroup(self, nodes, kind):
-        n = encodelist(nodes)
-        f = self._callcompressable("changegroup", roots=n)
-        return changegroupmod.cg1unpacker(f, 'UN')
-
-    def changegroupsubset(self, bases, heads, kind):
-        self.requirecap('changegroupsubset', _('look up remote changes'))
-        bases = encodelist(bases)
-        heads = encodelist(heads)
-        f = self._callcompressable("changegroupsubset",
-                                   bases=bases, heads=heads)
-        return changegroupmod.cg1unpacker(f, 'UN')
-
     def getbundle(self, source, **kwargs):
         self.requirecap('getbundle', _('look up remote changes'))
         opts = {}
@@ -433,6 +379,69 @@
             ret = bundle2.getunbundler(self.ui, stream)
         return ret
 
+    # End of basewirepeer interface.
+
+    # Begin of baselegacywirepeer interface.
+
+    def branches(self, nodes):
+        n = encodelist(nodes)
+        d = self._call("branches", nodes=n)
+        try:
+            br = [tuple(decodelist(b)) for b in d.splitlines()]
+            return br
+        except ValueError:
+            self._abort(error.ResponseError(_("unexpected response:"), d))
+
+    def between(self, pairs):
+        batch = 8 # avoid giant requests
+        r = []
+        for i in xrange(0, len(pairs), batch):
+            n = " ".join([encodelist(p, '-') for p in pairs[i:i + batch]])
+            d = self._call("between", pairs=n)
+            try:
+                r.extend(l and decodelist(l) or [] for l in d.splitlines())
+            except ValueError:
+                self._abort(error.ResponseError(_("unexpected response:"), d))
+        return r
+
+    def changegroup(self, nodes, kind):
+        n = encodelist(nodes)
+        f = self._callcompressable("changegroup", roots=n)
+        return changegroupmod.cg1unpacker(f, 'UN')
+
+    def changegroupsubset(self, bases, heads, kind):
+        self.requirecap('changegroupsubset', _('look up remote changes'))
+        bases = encodelist(bases)
+        heads = encodelist(heads)
+        f = self._callcompressable("changegroupsubset",
+                                   bases=bases, heads=heads)
+        return changegroupmod.cg1unpacker(f, 'UN')
+
+    # End of baselegacywirepeer interface.
+
+    def _submitbatch(self, req):
+        """run batch request <req> on the server
+
+        Returns an iterator of the raw responses from the server.
+        """
+        rsp = self._callstream("batch", cmds=encodebatchcmds(req))
+        chunk = rsp.read(1024)
+        work = [chunk]
+        while chunk:
+            while ';' not in chunk and chunk:
+                chunk = rsp.read(1024)
+                work.append(chunk)
+            merged = ''.join(work)
+            while ';' in merged:
+                one, merged = merged.split(';', 1)
+                yield unescapearg(one)
+            chunk = rsp.read(1024)
+            work = [merged, chunk]
+        yield unescapearg(''.join(work))
+
+    def _submitone(self, op, args):
+        return self._call(op, **args)
+
     def debugwireargs(self, one, two, three=None, four=None, five=None):
         # don't pass optional arguments left at their default value
         opts = {}
diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py
--- a/mercurial/sshpeer.py
+++ b/mercurial/sshpeer.py
@@ -13,7 +13,6 @@
 from . import (
     error,
     pycompat,
-    repository,
     util,
     wireproto,
 )
@@ -115,7 +114,7 @@
     def flush(self):
         return self._main.flush()
 
-class sshpeer(wireproto.wirepeer, repository.legacypeer):
+class sshpeer(wireproto.wirepeer):
     def __init__(self, ui, path, create=False):
         self._url = path
         self._ui = ui
@@ -151,9 +150,6 @@
 
         self._validaterepo(sshcmd, args, remotecmd)
 
-        # TODO remove this alias once peerrepository inheritance is removed.
-        self._capabilities = self.capabilities
-
     # Begin of _basepeer interface.
 
     @util.propertycache
diff --git a/mercurial/peer.py b/mercurial/peer.py
--- a/mercurial/peer.py
+++ b/mercurial/peer.py
@@ -95,46 +95,3 @@
         return next(batchable)
     setattr(plain, 'batchable', f)
     return plain
-
-class peerrepository(object):
-    def iterbatch(self):
-        """Batch requests but allow iterating over the results.
-
-        This is to allow interleaving responses with things like
-        progress updates for clients.
-        """
-        return localiterbatcher(self)
-
-    def capable(self, name):
-        '''tell whether repo supports named capability.
-        return False if not supported.
-        if boolean capability, return True.
-        if string capability, return string.'''
-        caps = self._capabilities()
-        if name in caps:
-            return True
-        name_eq = name + '='
-        for cap in caps:
-            if cap.startswith(name_eq):
-                return cap[len(name_eq):]
-        return False
-
-    def requirecap(self, name, purpose):
-        '''raise an exception if the given capability is not present'''
-        if not self.capable(name):
-            raise error.CapabilityError(
-                _('cannot %s; remote repository does not '
-                  'support the %r capability') % (purpose, name))
-
-    def local(self):
-        '''return peer as a localrepo, or None'''
-        return None
-
-    def peer(self):
-        return self
-
-    def canpush(self):
-        return True
-
-    def close(self):
-        pass
diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py
--- a/mercurial/httppeer.py
+++ b/mercurial/httppeer.py
@@ -21,7 +21,6 @@
     error,
     httpconnection,
     pycompat,
-    repository,
     statichttprepo,
     url,
     util,
@@ -87,7 +86,7 @@
 
     resp.__class__ = readerproxy
 
-class httppeer(wireproto.wirepeer, repository.legacypeer):
+class httppeer(wireproto.wirepeer):
     def __init__(self, ui, path):
         self._path = path
         self._caps = None
@@ -107,9 +106,6 @@
         self._urlopener = url.opener(ui, authinfo)
         self._requestbuilder = urlreq.request
 
-        # TODO remove once peerrepository isn't in inheritance.
-        self._capabilities = self.capabilities
-
     def __del__(self):
         urlopener = getattr(self, '_urlopener', None)
         if urlopener:



To: indygreg, #hg-reviewers
Cc: mercurial-devel


More information about the Mercurial-devel mailing list