##// END OF EJS Templates
templatekw: change default value of 'requires' to ()...
Yuya Nishihara -
r42535:de65ae32 default
parent child Browse files
Show More
@@ -1,503 +1,501 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 . import (
11 11 configitems,
12 12 error,
13 13 pycompat,
14 14 util,
15 15 )
16 16
17 17 # unlike the other registered items, config options are neither functions or
18 18 # classes. Registering the option is just small function call.
19 19 #
20 20 # We still add the official API to the registrar module for consistency with
21 21 # the other items extensions want might to register.
22 22 configitem = configitems.getitemregister
23 23
24 24 class _funcregistrarbase(object):
25 25 """Base of decorator to register a function for specific purpose
26 26
27 27 This decorator stores decorated functions into own dict 'table'.
28 28
29 29 The least derived class can be defined by overriding 'formatdoc',
30 30 for example::
31 31
32 32 class keyword(_funcregistrarbase):
33 33 _docformat = ":%s: %s"
34 34
35 35 This should be used as below:
36 36
37 37 keyword = registrar.keyword()
38 38
39 39 @keyword('bar')
40 40 def barfunc(*args, **kwargs):
41 41 '''Explanation of bar keyword ....
42 42 '''
43 43 pass
44 44
45 45 In this case:
46 46
47 47 - 'barfunc' is stored as 'bar' in '_table' of an instance 'keyword' above
48 48 - 'barfunc.__doc__' becomes ":bar: Explanation of bar keyword"
49 49 """
50 50 def __init__(self, table=None):
51 51 if table is None:
52 52 self._table = {}
53 53 else:
54 54 self._table = table
55 55
56 56 def __call__(self, decl, *args, **kwargs):
57 57 return lambda func: self._doregister(func, decl, *args, **kwargs)
58 58
59 59 def _doregister(self, func, decl, *args, **kwargs):
60 60 name = self._getname(decl)
61 61
62 62 if name in self._table:
63 63 msg = 'duplicate registration for name: "%s"' % name
64 64 raise error.ProgrammingError(msg)
65 65
66 66 if func.__doc__ and not util.safehasattr(func, '_origdoc'):
67 67 doc = pycompat.sysbytes(func.__doc__).strip()
68 68 func._origdoc = doc
69 69 func.__doc__ = pycompat.sysstr(self._formatdoc(decl, doc))
70 70
71 71 self._table[name] = func
72 72 self._extrasetup(name, func, *args, **kwargs)
73 73
74 74 return func
75 75
76 76 def _merge(self, registrarbase):
77 77 """Merge the entries of the given registrar object into this one.
78 78
79 79 The other registrar object must not contain any entries already in the
80 80 current one, or a ProgrammmingError is raised. Additionally, the types
81 81 of the two registrars must match.
82 82 """
83 83 if not isinstance(registrarbase, type(self)):
84 84 msg = "cannot merge different types of registrar"
85 85 raise error.ProgrammingError(msg)
86 86
87 87 dups = set(registrarbase._table).intersection(self._table)
88 88
89 89 if dups:
90 90 msg = 'duplicate registration for names: "%s"' % '", "'.join(dups)
91 91 raise error.ProgrammingError(msg)
92 92
93 93 self._table.update(registrarbase._table)
94 94
95 95 def _parsefuncdecl(self, decl):
96 96 """Parse function declaration and return the name of function in it
97 97 """
98 98 i = decl.find('(')
99 99 if i >= 0:
100 100 return decl[:i]
101 101 else:
102 102 return decl
103 103
104 104 def _getname(self, decl):
105 105 """Return the name of the registered function from decl
106 106
107 107 Derived class should override this, if it allows more
108 108 descriptive 'decl' string than just a name.
109 109 """
110 110 return decl
111 111
112 112 _docformat = None
113 113
114 114 def _formatdoc(self, decl, doc):
115 115 """Return formatted document of the registered function for help
116 116
117 117 'doc' is '__doc__.strip()' of the registered function.
118 118 """
119 119 return self._docformat % (decl, doc)
120 120
121 121 def _extrasetup(self, name, func):
122 122 """Execute exra setup for registered function, if needed
123 123 """
124 124
125 125 class command(_funcregistrarbase):
126 126 """Decorator to register a command function to table
127 127
128 128 This class receives a command table as its argument. The table should
129 129 be a dict.
130 130
131 131 The created object can be used as a decorator for adding commands to
132 132 that command table. This accepts multiple arguments to define a command.
133 133
134 134 The first argument is the command name (as bytes).
135 135
136 136 The `options` keyword argument is an iterable of tuples defining command
137 137 arguments. See ``mercurial.fancyopts.fancyopts()`` for the format of each
138 138 tuple.
139 139
140 140 The `synopsis` argument defines a short, one line summary of how to use the
141 141 command. This shows up in the help output.
142 142
143 143 There are three arguments that control what repository (if any) is found
144 144 and passed to the decorated function: `norepo`, `optionalrepo`, and
145 145 `inferrepo`.
146 146
147 147 The `norepo` argument defines whether the command does not require a
148 148 local repository. Most commands operate against a repository, thus the
149 149 default is False. When True, no repository will be passed.
150 150
151 151 The `optionalrepo` argument defines whether the command optionally requires
152 152 a local repository. If no repository can be found, None will be passed
153 153 to the decorated function.
154 154
155 155 The `inferrepo` argument defines whether to try to find a repository from
156 156 the command line arguments. If True, arguments will be examined for
157 157 potential repository locations. See ``findrepo()``. If a repository is
158 158 found, it will be used and passed to the decorated function.
159 159
160 160 The `intents` argument defines a set of intended actions or capabilities
161 161 the command is taking. These intents can be used to affect the construction
162 162 of the repository object passed to the command. For example, commands
163 163 declaring that they are read-only could receive a repository that doesn't
164 164 have any methods allowing repository mutation. Other intents could be used
165 165 to prevent the command from running if the requested intent could not be
166 166 fulfilled.
167 167
168 168 If `helpcategory` is set (usually to one of the constants in the help
169 169 module), the command will be displayed under that category in the help's
170 170 list of commands.
171 171
172 172 The following intents are defined:
173 173
174 174 readonly
175 175 The command is read-only
176 176
177 177 The signature of the decorated function looks like this:
178 178 def cmd(ui[, repo] [, <args>] [, <options>])
179 179
180 180 `repo` is required if `norepo` is False.
181 181 `<args>` are positional args (or `*args`) arguments, of non-option
182 182 arguments from the command line.
183 183 `<options>` are keyword arguments (or `**options`) of option arguments
184 184 from the command line.
185 185
186 186 See the WritingExtensions and MercurialApi documentation for more exhaustive
187 187 descriptions and examples.
188 188 """
189 189
190 190 # Command categories for grouping them in help output.
191 191 # These can also be specified for aliases, like:
192 192 # [alias]
193 193 # myalias = something
194 194 # myalias:category = repo
195 195 CATEGORY_REPO_CREATION = 'repo'
196 196 CATEGORY_REMOTE_REPO_MANAGEMENT = 'remote'
197 197 CATEGORY_COMMITTING = 'commit'
198 198 CATEGORY_CHANGE_MANAGEMENT = 'management'
199 199 CATEGORY_CHANGE_ORGANIZATION = 'organization'
200 200 CATEGORY_FILE_CONTENTS = 'files'
201 201 CATEGORY_CHANGE_NAVIGATION = 'navigation'
202 202 CATEGORY_WORKING_DIRECTORY = 'wdir'
203 203 CATEGORY_IMPORT_EXPORT = 'import'
204 204 CATEGORY_MAINTENANCE = 'maintenance'
205 205 CATEGORY_HELP = 'help'
206 206 CATEGORY_MISC = 'misc'
207 207 CATEGORY_NONE = 'none'
208 208
209 209 def _doregister(self, func, name, options=(), synopsis=None,
210 210 norepo=False, optionalrepo=False, inferrepo=False,
211 211 intents=None, helpcategory=None, helpbasic=False):
212 212 func.norepo = norepo
213 213 func.optionalrepo = optionalrepo
214 214 func.inferrepo = inferrepo
215 215 func.intents = intents or set()
216 216 func.helpcategory = helpcategory
217 217 func.helpbasic = helpbasic
218 218 if synopsis:
219 219 self._table[name] = func, list(options), synopsis
220 220 else:
221 221 self._table[name] = func, list(options)
222 222 return func
223 223
224 224 INTENT_READONLY = b'readonly'
225 225
226 226 class revsetpredicate(_funcregistrarbase):
227 227 """Decorator to register revset predicate
228 228
229 229 Usage::
230 230
231 231 revsetpredicate = registrar.revsetpredicate()
232 232
233 233 @revsetpredicate('mypredicate(arg1, arg2[, arg3])')
234 234 def mypredicatefunc(repo, subset, x):
235 235 '''Explanation of this revset predicate ....
236 236 '''
237 237 pass
238 238
239 239 The first string argument is used also in online help.
240 240
241 241 Optional argument 'safe' indicates whether a predicate is safe for
242 242 DoS attack (False by default).
243 243
244 244 Optional argument 'takeorder' indicates whether a predicate function
245 245 takes ordering policy as the last argument.
246 246
247 247 Optional argument 'weight' indicates the estimated run-time cost, useful
248 248 for static optimization, default is 1. Higher weight means more expensive.
249 249 Usually, revsets that are fast and return only one revision has a weight of
250 250 0.5 (ex. a symbol); revsets with O(changelog) complexity and read only the
251 251 changelog have weight 10 (ex. author); revsets reading manifest deltas have
252 252 weight 30 (ex. adds); revset reading manifest contents have weight 100
253 253 (ex. contains). Note: those values are flexible. If the revset has a
254 254 same big-O time complexity as 'contains', but with a smaller constant, it
255 255 might have a weight of 90.
256 256
257 257 'revsetpredicate' instance in example above can be used to
258 258 decorate multiple functions.
259 259
260 260 Decorated functions are registered automatically at loading
261 261 extension, if an instance named as 'revsetpredicate' is used for
262 262 decorating in extension.
263 263
264 264 Otherwise, explicit 'revset.loadpredicate()' is needed.
265 265 """
266 266 _getname = _funcregistrarbase._parsefuncdecl
267 267 _docformat = "``%s``\n %s"
268 268
269 269 def _extrasetup(self, name, func, safe=False, takeorder=False, weight=1):
270 270 func._safe = safe
271 271 func._takeorder = takeorder
272 272 func._weight = weight
273 273
274 274 class filesetpredicate(_funcregistrarbase):
275 275 """Decorator to register fileset predicate
276 276
277 277 Usage::
278 278
279 279 filesetpredicate = registrar.filesetpredicate()
280 280
281 281 @filesetpredicate('mypredicate()')
282 282 def mypredicatefunc(mctx, x):
283 283 '''Explanation of this fileset predicate ....
284 284 '''
285 285 pass
286 286
287 287 The first string argument is used also in online help.
288 288
289 289 Optional argument 'callstatus' indicates whether a predicate
290 290 implies 'matchctx.status()' at runtime or not (False, by
291 291 default).
292 292
293 293 Optional argument 'weight' indicates the estimated run-time cost, useful
294 294 for static optimization, default is 1. Higher weight means more expensive.
295 295 There are predefined weights in the 'filesetlang' module.
296 296
297 297 ====== =============================================================
298 298 Weight Description and examples
299 299 ====== =============================================================
300 300 0.5 basic match patterns (e.g. a symbol)
301 301 10 computing status (e.g. added()) or accessing a few files
302 302 30 reading file content for each (e.g. grep())
303 303 50 scanning working directory (ignored())
304 304 ====== =============================================================
305 305
306 306 'filesetpredicate' instance in example above can be used to
307 307 decorate multiple functions.
308 308
309 309 Decorated functions are registered automatically at loading
310 310 extension, if an instance named as 'filesetpredicate' is used for
311 311 decorating in extension.
312 312
313 313 Otherwise, explicit 'fileset.loadpredicate()' is needed.
314 314 """
315 315 _getname = _funcregistrarbase._parsefuncdecl
316 316 _docformat = "``%s``\n %s"
317 317
318 318 def _extrasetup(self, name, func, callstatus=False, weight=1):
319 319 func._callstatus = callstatus
320 320 func._weight = weight
321 321
322 322 class _templateregistrarbase(_funcregistrarbase):
323 323 """Base of decorator to register functions as template specific one
324 324 """
325 325 _docformat = ":%s: %s"
326 326
327 327 class templatekeyword(_templateregistrarbase):
328 328 """Decorator to register template keyword
329 329
330 330 Usage::
331 331
332 332 templatekeyword = registrar.templatekeyword()
333 333
334 334 # new API (since Mercurial 4.6)
335 335 @templatekeyword('mykeyword', requires={'repo', 'ctx'})
336 336 def mykeywordfunc(context, mapping):
337 337 '''Explanation of this template keyword ....
338 338 '''
339 339 pass
340 340
341 341 The first string argument is used also in online help.
342 342
343 343 Optional argument 'requires' should be a collection of resource names
344 which the template keyword depends on. This also serves as a flag to
345 switch to the new API. If 'requires' is unspecified, all template
346 keywords and resources are expanded to the function arguments.
344 which the template keyword depends on.
347 345
348 346 'templatekeyword' instance in example above can be used to
349 347 decorate multiple functions.
350 348
351 349 Decorated functions are registered automatically at loading
352 350 extension, if an instance named as 'templatekeyword' is used for
353 351 decorating in extension.
354 352
355 353 Otherwise, explicit 'templatekw.loadkeyword()' is needed.
356 354 """
357 355
358 def _extrasetup(self, name, func, requires=None):
356 def _extrasetup(self, name, func, requires=()):
359 357 func._requires = requires
360 358
361 359 class templatefilter(_templateregistrarbase):
362 360 """Decorator to register template filer
363 361
364 362 Usage::
365 363
366 364 templatefilter = registrar.templatefilter()
367 365
368 366 @templatefilter('myfilter', intype=bytes)
369 367 def myfilterfunc(text):
370 368 '''Explanation of this template filter ....
371 369 '''
372 370 pass
373 371
374 372 The first string argument is used also in online help.
375 373
376 374 Optional argument 'intype' defines the type of the input argument,
377 375 which should be (bytes, int, templateutil.date, or None for any.)
378 376
379 377 'templatefilter' instance in example above can be used to
380 378 decorate multiple functions.
381 379
382 380 Decorated functions are registered automatically at loading
383 381 extension, if an instance named as 'templatefilter' is used for
384 382 decorating in extension.
385 383
386 384 Otherwise, explicit 'templatefilters.loadkeyword()' is needed.
387 385 """
388 386
389 387 def _extrasetup(self, name, func, intype=None):
390 388 func._intype = intype
391 389
392 390 class templatefunc(_templateregistrarbase):
393 391 """Decorator to register template function
394 392
395 393 Usage::
396 394
397 395 templatefunc = registrar.templatefunc()
398 396
399 397 @templatefunc('myfunc(arg1, arg2[, arg3])', argspec='arg1 arg2 arg3',
400 398 requires={'ctx'})
401 399 def myfuncfunc(context, mapping, args):
402 400 '''Explanation of this template function ....
403 401 '''
404 402 pass
405 403
406 404 The first string argument is used also in online help.
407 405
408 406 If optional 'argspec' is defined, the function will receive 'args' as
409 407 a dict of named arguments. Otherwise 'args' is a list of positional
410 408 arguments.
411 409
412 410 Optional argument 'requires' should be a collection of resource names
413 411 which the template function depends on.
414 412
415 413 'templatefunc' instance in example above can be used to
416 414 decorate multiple functions.
417 415
418 416 Decorated functions are registered automatically at loading
419 417 extension, if an instance named as 'templatefunc' is used for
420 418 decorating in extension.
421 419
422 420 Otherwise, explicit 'templatefuncs.loadfunction()' is needed.
423 421 """
424 422 _getname = _funcregistrarbase._parsefuncdecl
425 423
426 424 def _extrasetup(self, name, func, argspec=None, requires=()):
427 425 func._argspec = argspec
428 426 func._requires = requires
429 427
430 428 class internalmerge(_funcregistrarbase):
431 429 """Decorator to register in-process merge tool
432 430
433 431 Usage::
434 432
435 433 internalmerge = registrar.internalmerge()
436 434
437 435 @internalmerge('mymerge', internalmerge.mergeonly,
438 436 onfailure=None, precheck=None,
439 437 binary=False, symlink=False):
440 438 def mymergefunc(repo, mynode, orig, fcd, fco, fca,
441 439 toolconf, files, labels=None):
442 440 '''Explanation of this internal merge tool ....
443 441 '''
444 442 return 1, False # means "conflicted", "no deletion needed"
445 443
446 444 The first string argument is used to compose actual merge tool name,
447 445 ":name" and "internal:name" (the latter is historical one).
448 446
449 447 The second argument is one of merge types below:
450 448
451 449 ========== ======== ======== =========
452 450 merge type precheck premerge fullmerge
453 451 ========== ======== ======== =========
454 452 nomerge x x x
455 453 mergeonly o x o
456 454 fullmerge o o o
457 455 ========== ======== ======== =========
458 456
459 457 Optional argument 'onfailure' is the format of warning message
460 458 to be used at failure of merging (target filename is specified
461 459 at formatting). Or, None or so, if warning message should be
462 460 suppressed.
463 461
464 462 Optional argument 'precheck' is the function to be used
465 463 before actual invocation of internal merge tool itself.
466 464 It takes as same arguments as internal merge tool does, other than
467 465 'files' and 'labels'. If it returns false value, merging is aborted
468 466 immediately (and file is marked as "unresolved").
469 467
470 468 Optional argument 'binary' is a binary files capability of internal
471 469 merge tool. 'nomerge' merge type implies binary=True.
472 470
473 471 Optional argument 'symlink' is a symlinks capability of inetrnal
474 472 merge function. 'nomerge' merge type implies symlink=True.
475 473
476 474 'internalmerge' instance in example above can be used to
477 475 decorate multiple functions.
478 476
479 477 Decorated functions are registered automatically at loading
480 478 extension, if an instance named as 'internalmerge' is used for
481 479 decorating in extension.
482 480
483 481 Otherwise, explicit 'filemerge.loadinternalmerge()' is needed.
484 482 """
485 483 _docformat = "``:%s``\n %s"
486 484
487 485 # merge type definitions:
488 486 nomerge = None
489 487 mergeonly = 'mergeonly' # just the full merge, no premerge
490 488 fullmerge = 'fullmerge' # both premerge and merge
491 489
492 490 def _extrasetup(self, name, func, mergetype,
493 491 onfailure=None, precheck=None,
494 492 binary=False, symlink=False):
495 493 func.mergetype = mergetype
496 494 func.onfailure = onfailure
497 495 func.precheck = precheck
498 496
499 497 binarycap = binary or mergetype == self.nomerge
500 498 symlinkcap = symlink or mergetype == self.nomerge
501 499
502 500 # actual capabilities, which this internal merge tool has
503 501 func.capabilities = {"binary": binarycap, "symlink": symlinkcap}
General Comments 0
You need to be logged in to leave comments. Login now