Show More
@@ -173,89 +173,11 b' def supportedcompengines(ui, role):' | |||||
173 |
|
173 | |||
174 | return compengines |
|
174 | return compengines | |
175 |
|
175 | |||
176 | class commandentry(object): |
|
|||
177 | """Represents a declared wire protocol command.""" |
|
|||
178 | def __init__(self, func, args='', transports=None, |
|
|||
179 | permission='push'): |
|
|||
180 | self.func = func |
|
|||
181 | self.args = args |
|
|||
182 | self.transports = transports or set() |
|
|||
183 | self.permission = permission |
|
|||
184 |
|
||||
185 | def _merge(self, func, args): |
|
|||
186 | """Merge this instance with an incoming 2-tuple. |
|
|||
187 |
|
||||
188 | This is called when a caller using the old 2-tuple API attempts |
|
|||
189 | to replace an instance. The incoming values are merged with |
|
|||
190 | data not captured by the 2-tuple and a new instance containing |
|
|||
191 | the union of the two objects is returned. |
|
|||
192 | """ |
|
|||
193 | return commandentry(func, args=args, transports=set(self.transports), |
|
|||
194 | permission=self.permission) |
|
|||
195 |
|
||||
196 | # Old code treats instances as 2-tuples. So expose that interface. |
|
|||
197 | def __iter__(self): |
|
|||
198 | yield self.func |
|
|||
199 | yield self.args |
|
|||
200 |
|
||||
201 | def __getitem__(self, i): |
|
|||
202 | if i == 0: |
|
|||
203 | return self.func |
|
|||
204 | elif i == 1: |
|
|||
205 | return self.args |
|
|||
206 | else: |
|
|||
207 | raise IndexError('can only access elements 0 and 1') |
|
|||
208 |
|
||||
209 | class commanddict(dict): |
|
|||
210 | """Container for registered wire protocol commands. |
|
|||
211 |
|
||||
212 | It behaves like a dict. But __setitem__ is overwritten to allow silent |
|
|||
213 | coercion of values from 2-tuples for API compatibility. |
|
|||
214 | """ |
|
|||
215 | def __setitem__(self, k, v): |
|
|||
216 | if isinstance(v, commandentry): |
|
|||
217 | pass |
|
|||
218 | # Cast 2-tuples to commandentry instances. |
|
|||
219 | elif isinstance(v, tuple): |
|
|||
220 | if len(v) != 2: |
|
|||
221 | raise ValueError('command tuples must have exactly 2 elements') |
|
|||
222 |
|
||||
223 | # It is common for extensions to wrap wire protocol commands via |
|
|||
224 | # e.g. ``wireproto.commands[x] = (newfn, args)``. Because callers |
|
|||
225 | # doing this aren't aware of the new API that uses objects to store |
|
|||
226 | # command entries, we automatically merge old state with new. |
|
|||
227 | if k in self: |
|
|||
228 | v = self[k]._merge(v[0], v[1]) |
|
|||
229 | else: |
|
|||
230 | # Use default values from @wireprotocommand. |
|
|||
231 | v = commandentry(v[0], args=v[1], |
|
|||
232 | transports=set(wireprototypes.TRANSPORTS), |
|
|||
233 | permission='push') |
|
|||
234 | else: |
|
|||
235 | raise ValueError('command entries must be commandentry instances ' |
|
|||
236 | 'or 2-tuples') |
|
|||
237 |
|
||||
238 | return super(commanddict, self).__setitem__(k, v) |
|
|||
239 |
|
||||
240 | def commandavailable(self, command, proto): |
|
|||
241 | """Determine if a command is available for the requested protocol.""" |
|
|||
242 | assert proto.name in wireprototypes.TRANSPORTS |
|
|||
243 |
|
||||
244 | entry = self.get(command) |
|
|||
245 |
|
||||
246 | if not entry: |
|
|||
247 | return False |
|
|||
248 |
|
||||
249 | if proto.name not in entry.transports: |
|
|||
250 | return False |
|
|||
251 |
|
||||
252 | return True |
|
|||
253 |
|
||||
254 | # For version 1 transports. |
|
176 | # For version 1 transports. | |
255 | commands = commanddict() |
|
177 | commands = wireprototypes.commanddict() | |
256 |
|
178 | |||
257 | # For version 2 transports. |
|
179 | # For version 2 transports. | |
258 | commandsv2 = commanddict() |
|
180 | commandsv2 = wireprototypes.commanddict() | |
259 |
|
181 | |||
260 | def wireprotocommand(name, args=None, permission='push'): |
|
182 | def wireprotocommand(name, args=None, permission='push'): | |
261 | """Decorator to declare a wire protocol command. |
|
183 | """Decorator to declare a wire protocol command. | |
@@ -297,9 +219,8 b' def wireprotocommand(name, args=None, pe' | |||||
297 | if name in commands: |
|
219 | if name in commands: | |
298 | raise error.ProgrammingError('%s command already registered ' |
|
220 | raise error.ProgrammingError('%s command already registered ' | |
299 | 'for version 1' % name) |
|
221 | 'for version 1' % name) | |
300 |
commands[name] = commandentry( |
|
222 | commands[name] = wireprototypes.commandentry( | |
301 | transports=transports, |
|
223 | func, args=args, transports=transports, permission=permission) | |
302 | permission=permission) |
|
|||
303 |
|
224 | |||
304 | return func |
|
225 | return func | |
305 | return register |
|
226 | return register |
@@ -241,3 +241,81 b' class baseprotocolhandler(zi.Interface):' | |||||
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 |
@@ -438,7 +438,7 b' def wireprotocommand(name, args=None, pe' | |||||
438 | raise error.ProgrammingError('%s command already registered ' |
|
438 | raise error.ProgrammingError('%s command already registered ' | |
439 | 'for version 2' % name) |
|
439 | 'for version 2' % name) | |
440 |
|
440 | |||
441 | wireproto.commandsv2[name] = wireproto.commandentry( |
|
441 | wireproto.commandsv2[name] = wireprototypes.commandentry( | |
442 | func, args=args, transports=transports, permission=permission) |
|
442 | func, args=args, transports=transports, permission=permission) | |
443 |
|
443 | |||
444 | return func |
|
444 | return func |
General Comments 0
You need to be logged in to leave comments.
Login now