diff --git a/hgext/infinitepush/__init__.py b/hgext/infinitepush/__init__.py --- a/hgext/infinitepush/__init__.py +++ b/hgext/infinitepush/__init__.py @@ -120,7 +120,6 @@ extensions, hg, localrepo, - peer, phases, pushkey, pycompat, @@ -354,11 +353,11 @@ else: return orig(self, namespace) -@peer.batchable +@wireprotov1peer.batchable def listkeyspatterns(self, namespace, patterns): if not self.capable('pushkey'): yield {}, None - f = peer.future() + f = wireprotov1peer.future() self.ui.debug('preparing listkeys for "%s" with pattern "%s"\n' % (namespace, patterns)) yield { diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -49,7 +49,6 @@ narrowspec, obsolete, pathutil, - peer, phases, pushkey, pycompat, @@ -66,6 +65,7 @@ txnutil, util, vfs as vfsmod, + wireprotov1peer, ) from .utils import ( procutil, @@ -153,6 +153,20 @@ 'unbundle'} legacycaps = moderncaps.union({'changegroupsubset'}) +class localiterbatcher(wireprotov1peer.iterbatcher): + def __init__(self, local): + super(localiterbatcher, self).__init__() + self.local = local + + def submit(self): + # submit for a local iter batcher is a noop + pass + + def results(self): + for name, args, opts, resref in self.calls: + resref.set(getattr(self.local, name)(*args, **opts)) + yield resref.value + class localpeer(repository.peer): '''peer for a local repo; reflects only the most recent API''' @@ -273,7 +287,7 @@ # Begin of peer interface. def iterbatch(self): - return peer.localiterbatcher(self) + return localiterbatcher(self) # End of peer interface. diff --git a/mercurial/peer.py b/mercurial/peer.py deleted file mode 100644 --- a/mercurial/peer.py +++ /dev/null @@ -1,100 +0,0 @@ -# peer.py - repository base classes for mercurial -# -# Copyright 2005, 2006 Matt Mackall -# Copyright 2006 Vadim Gelfer -# -# This software may be used and distributed according to the terms of the -# GNU General Public License version 2 or any later version. - -from __future__ import absolute_import - -from . import ( - error, - pycompat, - util, -) - -# abstract batching support - -class future(object): - '''placeholder for a value to be set later''' - def set(self, value): - if util.safehasattr(self, 'value'): - raise error.RepoError("future is already set") - self.value = value - -class batcher(object): - '''base class for batches of commands submittable in a single request - - All methods invoked on instances of this class are simply queued and - return a a future for the result. Once you call submit(), all the queued - calls are performed and the results set in their respective futures. - ''' - def __init__(self): - self.calls = [] - def __getattr__(self, name): - def call(*args, **opts): - resref = future() - # Please don't invent non-ascii method names, or you will - # give core hg a very sad time. - self.calls.append((name.encode('ascii'), args, opts, resref,)) - return resref - return call - def submit(self): - raise NotImplementedError() - -class iterbatcher(batcher): - - def submit(self): - raise NotImplementedError() - - def results(self): - raise NotImplementedError() - -class localiterbatcher(iterbatcher): - def __init__(self, local): - super(iterbatcher, self).__init__() - self.local = local - - def submit(self): - # submit for a local iter batcher is a noop - pass - - def results(self): - for name, args, opts, resref in self.calls: - resref.set(getattr(self.local, name)(*args, **opts)) - yield resref.value - -def batchable(f): - '''annotation for batchable methods - - Such methods must implement a coroutine as follows: - - @batchable - def sample(self, one, two=None): - # Build list of encoded arguments suitable for your wire protocol: - encargs = [('one', encode(one),), ('two', encode(two),)] - # Create future for injection of encoded result: - encresref = future() - # Return encoded arguments and future: - yield encargs, encresref - # Assuming the future to be filled with the result from the batched - # request now. Decode it: - yield decode(encresref.value) - - The decorator returns a function which wraps this coroutine as a plain - method, but adds the original method as an attribute called "batchable", - which is used by remotebatch to split the call into separate encoding and - decoding phases. - ''' - def plain(*args, **opts): - batchable = f(*args, **opts) - encargsorres, encresref = next(batchable) - if not encresref: - return encargsorres # a local result in this case - self = args[0] - cmd = pycompat.bytesurl(f.__name__) # ensure cmd is ascii bytestr - encresref.set(self._submitone(cmd, encargsorres)) - return next(batchable) - setattr(plain, 'batchable', f) - return plain diff --git a/mercurial/wireprotov1peer.py b/mercurial/wireprotov1peer.py --- a/mercurial/wireprotov1peer.py +++ b/mercurial/wireprotov1peer.py @@ -19,7 +19,6 @@ changegroup as changegroupmod, encoding, error, - peer, pushkey as pushkeymod, pycompat, repository, @@ -29,7 +28,76 @@ urlreq = util.urlreq -class remoteiterbatcher(peer.iterbatcher): +def batchable(f): + '''annotation for batchable methods + + Such methods must implement a coroutine as follows: + + @batchable + def sample(self, one, two=None): + # Build list of encoded arguments suitable for your wire protocol: + encargs = [('one', encode(one),), ('two', encode(two),)] + # Create future for injection of encoded result: + encresref = future() + # Return encoded arguments and future: + yield encargs, encresref + # Assuming the future to be filled with the result from the batched + # request now. Decode it: + yield decode(encresref.value) + + The decorator returns a function which wraps this coroutine as a plain + method, but adds the original method as an attribute called "batchable", + which is used by remotebatch to split the call into separate encoding and + decoding phases. + ''' + def plain(*args, **opts): + batchable = f(*args, **opts) + encargsorres, encresref = next(batchable) + if not encresref: + return encargsorres # a local result in this case + self = args[0] + cmd = pycompat.bytesurl(f.__name__) # ensure cmd is ascii bytestr + encresref.set(self._submitone(cmd, encargsorres)) + return next(batchable) + setattr(plain, 'batchable', f) + return plain + +class future(object): + '''placeholder for a value to be set later''' + def set(self, value): + if util.safehasattr(self, 'value'): + raise error.RepoError("future is already set") + self.value = value + +class batcher(object): + '''base class for batches of commands submittable in a single request + + All methods invoked on instances of this class are simply queued and + return a a future for the result. Once you call submit(), all the queued + calls are performed and the results set in their respective futures. + ''' + def __init__(self): + self.calls = [] + def __getattr__(self, name): + def call(*args, **opts): + resref = future() + # Please don't invent non-ascii method names, or you will + # give core hg a very sad time. + self.calls.append((name.encode('ascii'), args, opts, resref,)) + return resref + return call + def submit(self): + raise NotImplementedError() + +class iterbatcher(batcher): + + def submit(self): + raise NotImplementedError() + + def results(self): + raise NotImplementedError() + +class remoteiterbatcher(iterbatcher): def __init__(self, remote): super(remoteiterbatcher, self).__init__() self._remote = remote @@ -92,11 +160,6 @@ yield finalfuture.value -# Forward a couple of names from peer to make wireproto interactions -# slightly more sensible. -batchable = peer.batchable -future = peer.future - def encodebatchcmds(req): """Return a ``cmds`` argument value for the ``batch`` command.""" escapearg = wireprototypes.escapebatcharg diff --git a/tests/test-batching.py b/tests/test-batching.py --- a/tests/test-batching.py +++ b/tests/test-batching.py @@ -9,9 +9,10 @@ from mercurial import ( error, - peer, + localrepo, util, wireprotov1peer, + ) # equivalent of repo.repository @@ -31,7 +32,7 @@ return "Hello, %s" % name def batchiter(self): '''Support for local batching.''' - return peer.localiterbatcher(self) + return localrepo.localiterbatcher(self) # usage of "thing" interface def use(it): @@ -51,7 +52,7 @@ bar2 = batch.bar(b="Uno", a="Due") # Future shouldn't be set until we submit(). - assert isinstance(foo, peer.future) + assert isinstance(foo, wireprotov1peer.future) assert not util.safehasattr(foo, 'value') assert not util.safehasattr(bar, 'value') batch.submit() @@ -179,16 +180,16 @@ def batchiter(self): return wireprotov1peer.remoteiterbatcher(self) - @peer.batchable + @wireprotov1peer.batchable def foo(self, one, two=None): encargs = [('one', mangle(one),), ('two', mangle(two),)] - encresref = peer.future() + encresref = wireprotov1peer.future() yield encargs, encresref yield unmangle(encresref.value) - @peer.batchable + @wireprotov1peer.batchable def bar(self, b, a): - encresref = peer.future() + encresref = wireprotov1peer.future() yield [('b', mangle(b),), ('a', mangle(a),)], encresref yield unmangle(encresref.value)