Mercurial > public > mercurial-scm > hg
comparison mercurial/wireprototypes.py @ 37781:352932a11905
wireproto: move command registration types to wireprototypes
These are shared across wire protocol implementations. wireprototypes
is our module for common code.
Differential Revision: https://phab.mercurial-scm.org/D3396
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Mon, 16 Apr 2018 21:52:33 -0700 |
parents | 564a3eec6e63 |
children | 9d818539abfa |
comparison
equal
deleted
inserted
replaced
37780:8acd3a9ac4fd | 37781:352932a11905 |
---|---|
239 | 239 |
240 The argument is the permission required to proceed. If the client | 240 The argument is the permission required to proceed. If the client |
241 doesn't have that permission, the exception should raise or abort | 241 doesn't have that permission, the exception should raise or abort |
242 in a protocol specific manner. | 242 in a protocol specific manner. |
243 """ | 243 """ |
244 | |
245 class commandentry(object): | |
246 """Represents a declared wire protocol command.""" | |
247 def __init__(self, func, args='', transports=None, | |
248 permission='push'): | |
249 self.func = func | |
250 self.args = args | |
251 self.transports = transports or set() | |
252 self.permission = permission | |
253 | |
254 def _merge(self, func, args): | |
255 """Merge this instance with an incoming 2-tuple. | |
256 | |
257 This is called when a caller using the old 2-tuple API attempts | |
258 to replace an instance. The incoming values are merged with | |
259 data not captured by the 2-tuple and a new instance containing | |
260 the union of the two objects is returned. | |
261 """ | |
262 return commandentry(func, args=args, transports=set(self.transports), | |
263 permission=self.permission) | |
264 | |
265 # Old code treats instances as 2-tuples. So expose that interface. | |
266 def __iter__(self): | |
267 yield self.func | |
268 yield self.args | |
269 | |
270 def __getitem__(self, i): | |
271 if i == 0: | |
272 return self.func | |
273 elif i == 1: | |
274 return self.args | |
275 else: | |
276 raise IndexError('can only access elements 0 and 1') | |
277 | |
278 class commanddict(dict): | |
279 """Container for registered wire protocol commands. | |
280 | |
281 It behaves like a dict. But __setitem__ is overwritten to allow silent | |
282 coercion of values from 2-tuples for API compatibility. | |
283 """ | |
284 def __setitem__(self, k, v): | |
285 if isinstance(v, commandentry): | |
286 pass | |
287 # Cast 2-tuples to commandentry instances. | |
288 elif isinstance(v, tuple): | |
289 if len(v) != 2: | |
290 raise ValueError('command tuples must have exactly 2 elements') | |
291 | |
292 # It is common for extensions to wrap wire protocol commands via | |
293 # e.g. ``wireproto.commands[x] = (newfn, args)``. Because callers | |
294 # doing this aren't aware of the new API that uses objects to store | |
295 # command entries, we automatically merge old state with new. | |
296 if k in self: | |
297 v = self[k]._merge(v[0], v[1]) | |
298 else: | |
299 # Use default values from @wireprotocommand. | |
300 v = commandentry(v[0], args=v[1], | |
301 transports=set(TRANSPORTS), | |
302 permission='push') | |
303 else: | |
304 raise ValueError('command entries must be commandentry instances ' | |
305 'or 2-tuples') | |
306 | |
307 return super(commanddict, self).__setitem__(k, v) | |
308 | |
309 def commandavailable(self, command, proto): | |
310 """Determine if a command is available for the requested protocol.""" | |
311 assert proto.name in TRANSPORTS | |
312 | |
313 entry = self.get(command) | |
314 | |
315 if not entry: | |
316 return False | |
317 | |
318 if proto.name not in entry.transports: | |
319 return False | |
320 | |
321 return True |