Previous, registering different object with the same name would silently
overwrite the first value with the second one. We now detect the situation and
raise an error. No extension in test or core had the issues.
This patch also adds loadfunction() to templater, because this
combination helps to figure out how they cooperate with each other.
Listing up loadfunction() in dispatch.extraloaders causes implicit
loading template function at loading (3rd party) extension.
This patch explicitly tests whether templatefunc decorator works as
expected, because there is no bundled extension, which defines
template function.
This change requires that "templatefunc" attribute of (3rd party)
extension is registrar.templatefunc or so.
This patch also adds loadfilter() to templatefilters, because this
combination helps to figure out how they cooperate with each other.
Listing up loadfilter() in dispatch.extraloaders causes implicit
loading template filter functions at loading (3rd party) extension.
This change requires that "templatefilter" attribute of (3rd party)
extension is registrar.templatefilter or so.
_templateregistrarbase is defined as a super class of templatekeyword,
for ease of adding template common features between "keyword",
"filter" and "function".
This patch also adds loadkeyword() to templatekw, because this
combination helps to figure out how they cooperate with each other.
Listing up loadkeyword() in dispatch.extraloaders causes implicit
loading template keyword functions at loading (3rd party) extension.
This change requires that "templatekeyword" attribute of (3rd party)
extension is registrar.templatekeyword or so.
filesetpredicate is used to replace fileset.predicate in subsequent
patch.
This patch also adds loadpredicate() to fileset, because this
combination helps to figure out how the name of "status caller" (or
"existing caller") predicate is put into _statuscallers (or
_existingcallers).
Listing up loadpredicate() in dispatch.extraloaders causes implicit
loading fileset predicate functions at loading (3rd party) extension.
revsetpredicate is used to replace revset.predicate and
revset.extpredicate in subsequent patches.
This patch also adds loadpredicate() to revset, because this
combination helps to figure out how the name of safe predicate is put
into safesymbols.
This patch still uses safesymbols set to examine whether the predicate
corresponded to the 'name' is safe from DoS attack or not, because
just setting func._safe property needs changes below for such
examination.
before:
name in revset.safesymbols
after:
getattr(revset.symbols.get(name, None), '_safe', False)
"automatic registration" described in help doc of revsetpredicate
class will be achieved by the subsequent patch, which lists
loadpredicate() up in dispatch.extraloaders.
_funcregistrarbase differs from funcregistrar in points below:
- every code paths should use same class derived from
_funcregistrarbase to register functions in a same category
funcregistrar expects (3rd party) extensions to use (a class
derived from) delayregistrar.
- actual extra setup should be executed in another function
For example, marking revset predicate as "safe" is executed in a
class derived from _funcregistrarbase, but putting name of "safe"
predicate into safesymbols is executed in another function for it.
funcregistrar expects derived classes to do so.
New class is named as module private one, because code paths, which
register functions, should use not it directly but one derived from
it.
Using decorator can localize changes for adding (or removing) a revset
predicate function in source code.
It is also useful to pick predicates up for specific purpose. For
example, subsequent patch marks predicates as "safe" by decorator.
This patch defines 'parsefuncdecl()' in 'funcregistrar' class, because
this implementation can be uesd by other decorator class for fileset
predicate and template function.
This class centralizes the common logic to register function for
specific purpose like below:
- template keyword, filter and function
- revset predicate
- fileset predicate
- webcommand
'funcregistrar' also formats help document of the function with the
'decl'(aration) specified at the construction.
This can avoid (1) redundancy between 'decl' and help document, and
(2) accidental typo of help document. For example, 'foo' should appear
twice like below, if without such formatting:
@keyword('foo')
def foo(....):
""":foo: Explanation of keyword foo ..."""
Almost all cases needs very simple document formatting like below:
- "``DECL``\n EXPLANATION"
- ":DECL: EXPLANATION"
But webcommand needs a little complicated formatting like:
/PATH/SPEC
----------
EXPLANATION ....
To make minirst recognize the section header, hyphen line should be as
long as "/PATH/SPEC". It should be arranged by program.
Implementing 'formatdoc()' in derived class can support complicated
formatting in the latter case. But it seems redundant for simple one
in the former case.
Therefore, 'funcregistrar' does:
- invoke 'self.formatdoc', if it is callable (for the latter case)
- use it as the format string, otherwise (for the former case)