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