mercurial/peer.py
branchstable
changeset 26813 b66e3ca0b90c
parent 25965 e6b56b2c1f26
child 28434 d549cbb5503d
equal deleted inserted replaced
26535:d3712209921d 26813:b66e3ca0b90c
     4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
     4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
     5 #
     5 #
     6 # This software may be used and distributed according to the terms of the
     6 # This software may be used and distributed according to the terms of the
     7 # GNU General Public License version 2 or any later version.
     7 # GNU General Public License version 2 or any later version.
     8 
     8 
     9 from i18n import _
     9 from __future__ import absolute_import
    10 import error
    10 
       
    11 from .i18n import _
       
    12 from . import (
       
    13     error,
       
    14     util,
       
    15 )
       
    16 
       
    17 # abstract batching support
       
    18 
       
    19 class future(object):
       
    20     '''placeholder for a value to be set later'''
       
    21     def set(self, value):
       
    22         if util.safehasattr(self, 'value'):
       
    23             raise error.RepoError("future is already set")
       
    24         self.value = value
       
    25 
       
    26 class batcher(object):
       
    27     '''base class for batches of commands submittable in a single request
       
    28 
       
    29     All methods invoked on instances of this class are simply queued and
       
    30     return a a future for the result. Once you call submit(), all the queued
       
    31     calls are performed and the results set in their respective futures.
       
    32     '''
       
    33     def __init__(self):
       
    34         self.calls = []
       
    35     def __getattr__(self, name):
       
    36         def call(*args, **opts):
       
    37             resref = future()
       
    38             self.calls.append((name, args, opts, resref,))
       
    39             return resref
       
    40         return call
       
    41     def submit(self):
       
    42         pass
       
    43 
       
    44 class localbatch(batcher):
       
    45     '''performs the queued calls directly'''
       
    46     def __init__(self, local):
       
    47         batcher.__init__(self)
       
    48         self.local = local
       
    49     def submit(self):
       
    50         for name, args, opts, resref in self.calls:
       
    51             resref.set(getattr(self.local, name)(*args, **opts))
       
    52 
       
    53 def batchable(f):
       
    54     '''annotation for batchable methods
       
    55 
       
    56     Such methods must implement a coroutine as follows:
       
    57 
       
    58     @batchable
       
    59     def sample(self, one, two=None):
       
    60         # Handle locally computable results first:
       
    61         if not one:
       
    62             yield "a local result", None
       
    63         # Build list of encoded arguments suitable for your wire protocol:
       
    64         encargs = [('one', encode(one),), ('two', encode(two),)]
       
    65         # Create future for injection of encoded result:
       
    66         encresref = future()
       
    67         # Return encoded arguments and future:
       
    68         yield encargs, encresref
       
    69         # Assuming the future to be filled with the result from the batched
       
    70         # request now. Decode it:
       
    71         yield decode(encresref.value)
       
    72 
       
    73     The decorator returns a function which wraps this coroutine as a plain
       
    74     method, but adds the original method as an attribute called "batchable",
       
    75     which is used by remotebatch to split the call into separate encoding and
       
    76     decoding phases.
       
    77     '''
       
    78     def plain(*args, **opts):
       
    79         batchable = f(*args, **opts)
       
    80         encargsorres, encresref = batchable.next()
       
    81         if not encresref:
       
    82             return encargsorres # a local result in this case
       
    83         self = args[0]
       
    84         encresref.set(self._submitone(f.func_name, encargsorres))
       
    85         return batchable.next()
       
    86     setattr(plain, 'batchable', f)
       
    87     return plain
    11 
    88 
    12 class peerrepository(object):
    89 class peerrepository(object):
       
    90 
       
    91     def batch(self):
       
    92         return localbatch(self)
    13 
    93 
    14     def capable(self, name):
    94     def capable(self, name):
    15         '''tell whether repo supports named capability.
    95         '''tell whether repo supports named capability.
    16         return False if not supported.
    96         return False if not supported.
    17         if boolean capability, return True.
    97         if boolean capability, return True.