##// END OF EJS Templates
peer: ensure command names are always ascii bytestrs...
Augie Fackler -
r34734:115efdd9 default
parent child Browse files
Show More
@@ -1,98 +1,100
1 1 # peer.py - repository base classes for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 from __future__ import absolute_import
10 10
11 11 from . import (
12 12 error,
13 pycompat,
13 14 util,
14 15 )
15 16
16 17 # abstract batching support
17 18
18 19 class future(object):
19 20 '''placeholder for a value to be set later'''
20 21 def set(self, value):
21 22 if util.safehasattr(self, 'value'):
22 23 raise error.RepoError("future is already set")
23 24 self.value = value
24 25
25 26 class batcher(object):
26 27 '''base class for batches of commands submittable in a single request
27 28
28 29 All methods invoked on instances of this class are simply queued and
29 30 return a a future for the result. Once you call submit(), all the queued
30 31 calls are performed and the results set in their respective futures.
31 32 '''
32 33 def __init__(self):
33 34 self.calls = []
34 35 def __getattr__(self, name):
35 36 def call(*args, **opts):
36 37 resref = future()
37 38 # Please don't invent non-ascii method names, or you will
38 39 # give core hg a very sad time.
39 40 self.calls.append((name.encode('ascii'), args, opts, resref,))
40 41 return resref
41 42 return call
42 43 def submit(self):
43 44 raise NotImplementedError()
44 45
45 46 class iterbatcher(batcher):
46 47
47 48 def submit(self):
48 49 raise NotImplementedError()
49 50
50 51 def results(self):
51 52 raise NotImplementedError()
52 53
53 54 class localiterbatcher(iterbatcher):
54 55 def __init__(self, local):
55 56 super(iterbatcher, self).__init__()
56 57 self.local = local
57 58
58 59 def submit(self):
59 60 # submit for a local iter batcher is a noop
60 61 pass
61 62
62 63 def results(self):
63 64 for name, args, opts, resref in self.calls:
64 65 resref.set(getattr(self.local, name)(*args, **opts))
65 66 yield resref.value
66 67
67 68 def batchable(f):
68 69 '''annotation for batchable methods
69 70
70 71 Such methods must implement a coroutine as follows:
71 72
72 73 @batchable
73 74 def sample(self, one, two=None):
74 75 # Build list of encoded arguments suitable for your wire protocol:
75 76 encargs = [('one', encode(one),), ('two', encode(two),)]
76 77 # Create future for injection of encoded result:
77 78 encresref = future()
78 79 # Return encoded arguments and future:
79 80 yield encargs, encresref
80 81 # Assuming the future to be filled with the result from the batched
81 82 # request now. Decode it:
82 83 yield decode(encresref.value)
83 84
84 85 The decorator returns a function which wraps this coroutine as a plain
85 86 method, but adds the original method as an attribute called "batchable",
86 87 which is used by remotebatch to split the call into separate encoding and
87 88 decoding phases.
88 89 '''
89 90 def plain(*args, **opts):
90 91 batchable = f(*args, **opts)
91 92 encargsorres, encresref = next(batchable)
92 93 if not encresref:
93 94 return encargsorres # a local result in this case
94 95 self = args[0]
95 encresref.set(self._submitone(f.__name__, encargsorres))
96 cmd = pycompat.bytesurl(f.__name__) # ensure cmd is ascii bytestr
97 encresref.set(self._submitone(cmd, encargsorres))
96 98 return next(batchable)
97 99 setattr(plain, 'batchable', f)
98 100 return plain
General Comments 0
You need to be logged in to leave comments. Login now