##// END OF EJS Templates
registrar: move "constant" possiblecmdtypes to class level...
Martin von Zweigbergk -
r34896:7b857c59 default
parent child Browse files
Show More
@@ -1,404 +1,404 b''
1 1 # registrar.py - utilities to register function for specific purpose
2 2 #
3 3 # Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 from .i18n import _
11 11 from . import (
12 12 configitems,
13 13 error,
14 14 pycompat,
15 15 util,
16 16 )
17 17
18 18 # unlike the other registered items, config options are neither functions or
19 19 # classes. Registering the option is just small function call.
20 20 #
21 21 # We still add the official API to the registrar module for consistency with
22 22 # the other items extensions want might to register.
23 23 configitem = configitems.getitemregister
24 24
25 25 class _funcregistrarbase(object):
26 26 """Base of decorator to register a function for specific purpose
27 27
28 28 This decorator stores decorated functions into own dict 'table'.
29 29
30 30 The least derived class can be defined by overriding 'formatdoc',
31 31 for example::
32 32
33 33 class keyword(_funcregistrarbase):
34 34 _docformat = ":%s: %s"
35 35
36 36 This should be used as below:
37 37
38 38 keyword = registrar.keyword()
39 39
40 40 @keyword('bar')
41 41 def barfunc(*args, **kwargs):
42 42 '''Explanation of bar keyword ....
43 43 '''
44 44 pass
45 45
46 46 In this case:
47 47
48 48 - 'barfunc' is stored as 'bar' in '_table' of an instance 'keyword' above
49 49 - 'barfunc.__doc__' becomes ":bar: Explanation of bar keyword"
50 50 """
51 51 def __init__(self, table=None):
52 52 if table is None:
53 53 self._table = {}
54 54 else:
55 55 self._table = table
56 56
57 57 def __call__(self, decl, *args, **kwargs):
58 58 return lambda func: self._doregister(func, decl, *args, **kwargs)
59 59
60 60 def _doregister(self, func, decl, *args, **kwargs):
61 61 name = self._getname(decl)
62 62
63 63 if name in self._table:
64 64 msg = 'duplicate registration for name: "%s"' % name
65 65 raise error.ProgrammingError(msg)
66 66
67 67 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
68 68 doc = pycompat.sysbytes(func.__doc__).strip()
69 69 func._origdoc = doc
70 70 func.__doc__ = pycompat.sysstr(self._formatdoc(decl, doc))
71 71
72 72 self._table[name] = func
73 73 self._extrasetup(name, func, *args, **kwargs)
74 74
75 75 return func
76 76
77 77 def _parsefuncdecl(self, decl):
78 78 """Parse function declaration and return the name of function in it
79 79 """
80 80 i = decl.find('(')
81 81 if i >= 0:
82 82 return decl[:i]
83 83 else:
84 84 return decl
85 85
86 86 def _getname(self, decl):
87 87 """Return the name of the registered function from decl
88 88
89 89 Derived class should override this, if it allows more
90 90 descriptive 'decl' string than just a name.
91 91 """
92 92 return decl
93 93
94 94 _docformat = None
95 95
96 96 def _formatdoc(self, decl, doc):
97 97 """Return formatted document of the registered function for help
98 98
99 99 'doc' is '__doc__.strip()' of the registered function.
100 100 """
101 101 return self._docformat % (decl, doc)
102 102
103 103 def _extrasetup(self, name, func):
104 104 """Execute exra setup for registered function, if needed
105 105 """
106 106
107 107 class command(_funcregistrarbase):
108 108 """Decorator to register a command function to table
109 109
110 110 This class receives a command table as its argument. The table should
111 111 be a dict.
112 112
113 113 The created object can be used as a decorator for adding commands to
114 114 that command table. This accepts multiple arguments to define a command.
115 115
116 116 The first argument is the command name.
117 117
118 118 The options argument is an iterable of tuples defining command arguments.
119 119 See ``mercurial.fancyopts.fancyopts()`` for the format of each tuple.
120 120
121 121 The synopsis argument defines a short, one line summary of how to use the
122 122 command. This shows up in the help output.
123 123
124 124 The norepo argument defines whether the command does not require a
125 125 local repository. Most commands operate against a repository, thus the
126 126 default is False.
127 127
128 128 The optionalrepo argument defines whether the command optionally requires
129 129 a local repository.
130 130
131 131 The inferrepo argument defines whether to try to find a repository from the
132 132 command line arguments. If True, arguments will be examined for potential
133 133 repository locations. See ``findrepo()``. If a repository is found, it
134 134 will be used.
135 135
136 136 There are three constants in the class which tells what type of the command
137 137 that is. That information will be helpful at various places. It will be also
138 138 be used to decide what level of access the command has on hidden commits.
139 139 The constants are:
140 140
141 141 unrecoverablewrite is for those write commands which can't be recovered like
142 142 push.
143 143 recoverablewrite is for write commands which can be recovered like commit.
144 144 readonly is for commands which are read only.
145 145 """
146 146
147 147 unrecoverablewrite = "unrecoverable"
148 148 recoverablewrite = "recoverable"
149 149 readonly = "readonly"
150 150
151 possiblecmdtypes = {unrecoverablewrite, recoverablewrite, readonly}
152
151 153 def _doregister(self, func, name, options=(), synopsis=None,
152 154 norepo=False, optionalrepo=False, inferrepo=False,
153 155 cmdtype=unrecoverablewrite):
154 156
155 possiblecmdtypes = set([self.unrecoverablewrite, self.recoverablewrite,
156 self.readonly])
157 if cmdtype not in possiblecmdtypes:
157 if cmdtype not in self.possiblecmdtypes:
158 158 raise error.ProgrammingError(_("unknown cmdtype value '%s' for "
159 159 "'%s' command") % (cmdtype, name))
160 160 func.norepo = norepo
161 161 func.optionalrepo = optionalrepo
162 162 func.inferrepo = inferrepo
163 163 func.cmdtype = cmdtype
164 164 if synopsis:
165 165 self._table[name] = func, list(options), synopsis
166 166 else:
167 167 self._table[name] = func, list(options)
168 168 return func
169 169
170 170 class revsetpredicate(_funcregistrarbase):
171 171 """Decorator to register revset predicate
172 172
173 173 Usage::
174 174
175 175 revsetpredicate = registrar.revsetpredicate()
176 176
177 177 @revsetpredicate('mypredicate(arg1, arg2[, arg3])')
178 178 def mypredicatefunc(repo, subset, x):
179 179 '''Explanation of this revset predicate ....
180 180 '''
181 181 pass
182 182
183 183 The first string argument is used also in online help.
184 184
185 185 Optional argument 'safe' indicates whether a predicate is safe for
186 186 DoS attack (False by default).
187 187
188 188 Optional argument 'takeorder' indicates whether a predicate function
189 189 takes ordering policy as the last argument.
190 190
191 191 Optional argument 'weight' indicates the estimated run-time cost, useful
192 192 for static optimization, default is 1. Higher weight means more expensive.
193 193 Usually, revsets that are fast and return only one revision has a weight of
194 194 0.5 (ex. a symbol); revsets with O(changelog) complexity and read only the
195 195 changelog have weight 10 (ex. author); revsets reading manifest deltas have
196 196 weight 30 (ex. adds); revset reading manifest contents have weight 100
197 197 (ex. contains). Note: those values are flexible. If the revset has a
198 198 same big-O time complexity as 'contains', but with a smaller constant, it
199 199 might have a weight of 90.
200 200
201 201 'revsetpredicate' instance in example above can be used to
202 202 decorate multiple functions.
203 203
204 204 Decorated functions are registered automatically at loading
205 205 extension, if an instance named as 'revsetpredicate' is used for
206 206 decorating in extension.
207 207
208 208 Otherwise, explicit 'revset.loadpredicate()' is needed.
209 209 """
210 210 _getname = _funcregistrarbase._parsefuncdecl
211 211 _docformat = "``%s``\n %s"
212 212
213 213 def _extrasetup(self, name, func, safe=False, takeorder=False, weight=1):
214 214 func._safe = safe
215 215 func._takeorder = takeorder
216 216 func._weight = weight
217 217
218 218 class filesetpredicate(_funcregistrarbase):
219 219 """Decorator to register fileset predicate
220 220
221 221 Usage::
222 222
223 223 filesetpredicate = registrar.filesetpredicate()
224 224
225 225 @filesetpredicate('mypredicate()')
226 226 def mypredicatefunc(mctx, x):
227 227 '''Explanation of this fileset predicate ....
228 228 '''
229 229 pass
230 230
231 231 The first string argument is used also in online help.
232 232
233 233 Optional argument 'callstatus' indicates whether a predicate
234 234 implies 'matchctx.status()' at runtime or not (False, by
235 235 default).
236 236
237 237 Optional argument 'callexisting' indicates whether a predicate
238 238 implies 'matchctx.existing()' at runtime or not (False, by
239 239 default).
240 240
241 241 'filesetpredicate' instance in example above can be used to
242 242 decorate multiple functions.
243 243
244 244 Decorated functions are registered automatically at loading
245 245 extension, if an instance named as 'filesetpredicate' is used for
246 246 decorating in extension.
247 247
248 248 Otherwise, explicit 'fileset.loadpredicate()' is needed.
249 249 """
250 250 _getname = _funcregistrarbase._parsefuncdecl
251 251 _docformat = "``%s``\n %s"
252 252
253 253 def _extrasetup(self, name, func, callstatus=False, callexisting=False):
254 254 func._callstatus = callstatus
255 255 func._callexisting = callexisting
256 256
257 257 class _templateregistrarbase(_funcregistrarbase):
258 258 """Base of decorator to register functions as template specific one
259 259 """
260 260 _docformat = ":%s: %s"
261 261
262 262 class templatekeyword(_templateregistrarbase):
263 263 """Decorator to register template keyword
264 264
265 265 Usage::
266 266
267 267 templatekeyword = registrar.templatekeyword()
268 268
269 269 @templatekeyword('mykeyword')
270 270 def mykeywordfunc(repo, ctx, templ, cache, revcache, **args):
271 271 '''Explanation of this template keyword ....
272 272 '''
273 273 pass
274 274
275 275 The first string argument is used also in online help.
276 276
277 277 'templatekeyword' instance in example above can be used to
278 278 decorate multiple functions.
279 279
280 280 Decorated functions are registered automatically at loading
281 281 extension, if an instance named as 'templatekeyword' is used for
282 282 decorating in extension.
283 283
284 284 Otherwise, explicit 'templatekw.loadkeyword()' is needed.
285 285 """
286 286
287 287 class templatefilter(_templateregistrarbase):
288 288 """Decorator to register template filer
289 289
290 290 Usage::
291 291
292 292 templatefilter = registrar.templatefilter()
293 293
294 294 @templatefilter('myfilter')
295 295 def myfilterfunc(text):
296 296 '''Explanation of this template filter ....
297 297 '''
298 298 pass
299 299
300 300 The first string argument is used also in online help.
301 301
302 302 'templatefilter' instance in example above can be used to
303 303 decorate multiple functions.
304 304
305 305 Decorated functions are registered automatically at loading
306 306 extension, if an instance named as 'templatefilter' is used for
307 307 decorating in extension.
308 308
309 309 Otherwise, explicit 'templatefilters.loadkeyword()' is needed.
310 310 """
311 311
312 312 class templatefunc(_templateregistrarbase):
313 313 """Decorator to register template function
314 314
315 315 Usage::
316 316
317 317 templatefunc = registrar.templatefunc()
318 318
319 319 @templatefunc('myfunc(arg1, arg2[, arg3])', argspec='arg1 arg2 arg3')
320 320 def myfuncfunc(context, mapping, args):
321 321 '''Explanation of this template function ....
322 322 '''
323 323 pass
324 324
325 325 The first string argument is used also in online help.
326 326
327 327 If optional 'argspec' is defined, the function will receive 'args' as
328 328 a dict of named arguments. Otherwise 'args' is a list of positional
329 329 arguments.
330 330
331 331 'templatefunc' instance in example above can be used to
332 332 decorate multiple functions.
333 333
334 334 Decorated functions are registered automatically at loading
335 335 extension, if an instance named as 'templatefunc' is used for
336 336 decorating in extension.
337 337
338 338 Otherwise, explicit 'templater.loadfunction()' is needed.
339 339 """
340 340 _getname = _funcregistrarbase._parsefuncdecl
341 341
342 342 def _extrasetup(self, name, func, argspec=None):
343 343 func._argspec = argspec
344 344
345 345 class internalmerge(_funcregistrarbase):
346 346 """Decorator to register in-process merge tool
347 347
348 348 Usage::
349 349
350 350 internalmerge = registrar.internalmerge()
351 351
352 352 @internalmerge('mymerge', internalmerge.mergeonly,
353 353 onfailure=None, precheck=None):
354 354 def mymergefunc(repo, mynode, orig, fcd, fco, fca,
355 355 toolconf, files, labels=None):
356 356 '''Explanation of this internal merge tool ....
357 357 '''
358 358 return 1, False # means "conflicted", "no deletion needed"
359 359
360 360 The first string argument is used to compose actual merge tool name,
361 361 ":name" and "internal:name" (the latter is historical one).
362 362
363 363 The second argument is one of merge types below:
364 364
365 365 ========== ======== ======== =========
366 366 merge type precheck premerge fullmerge
367 367 ========== ======== ======== =========
368 368 nomerge x x x
369 369 mergeonly o x o
370 370 fullmerge o o o
371 371 ========== ======== ======== =========
372 372
373 373 Optional argument 'onfailure' is the format of warning message
374 374 to be used at failure of merging (target filename is specified
375 375 at formatting). Or, None or so, if warning message should be
376 376 suppressed.
377 377
378 378 Optional argument 'precheck' is the function to be used
379 379 before actual invocation of internal merge tool itself.
380 380 It takes as same arguments as internal merge tool does, other than
381 381 'files' and 'labels'. If it returns false value, merging is aborted
382 382 immediately (and file is marked as "unresolved").
383 383
384 384 'internalmerge' instance in example above can be used to
385 385 decorate multiple functions.
386 386
387 387 Decorated functions are registered automatically at loading
388 388 extension, if an instance named as 'internalmerge' is used for
389 389 decorating in extension.
390 390
391 391 Otherwise, explicit 'filemerge.loadinternalmerge()' is needed.
392 392 """
393 393 _docformat = "``:%s``\n %s"
394 394
395 395 # merge type definitions:
396 396 nomerge = None
397 397 mergeonly = 'mergeonly' # just the full merge, no premerge
398 398 fullmerge = 'fullmerge' # both premerge and merge
399 399
400 400 def _extrasetup(self, name, func, mergetype,
401 401 onfailure=None, precheck=None):
402 402 func.mergetype = mergetype
403 403 func.onfailure = onfailure
404 404 func.precheck = precheck
General Comments 0
You need to be logged in to leave comments. Login now