Mercurial > hg
view mercurial/registrar.py @ 32005:2406dbba49bd
serve: add support for Mercurial subrepositories
I've been using `hg serve --web-conf ...` with a simple '/=projects/**' [paths]
configuration for awhile without issue. Let's ditch the need for the manual
configuration in this case, and limit the repos served to the actual subrepos.
This doesn't attempt to handle the case where a new subrepo appears while the
server is running. That could probably be handled with a hook if somebody wants
it. But it's such a rare case, it probably doesn't matter for the temporary
serves.
The main repo is served at '/', just like a repository without subrepos. I'm
not sure why the duplicate 'adding ...' lines appear on Linux. They don't
appear on Windows (see 594dd384803c), so they are optional.
Subrepositories that are configured with '../path' or absolute paths are not
cloneable from the server. (They aren't cloneable locally either, unless they
also exist at their configured source, perhaps via the share extension.) They
are still served, so that they can be browsed, or cloned individually. If we
care about that cloning someday, we can probably just add the extra entries to
the webconf dictionary. Even if the entries use '../' to escape the root, only
the related subrepositories would end up in the dictionary.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Sat, 15 Apr 2017 18:05:40 -0400 |
parents | bdda942f4b9c |
children | 46ba2cdda476 |
line wrap: on
line source
# registrar.py - utilities to register function for specific purpose # # Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. from __future__ import absolute_import from . import ( error, pycompat, util, ) class _funcregistrarbase(object): """Base of decorator to register a function for specific purpose This decorator stores decorated functions into own dict 'table'. The least derived class can be defined by overriding 'formatdoc', for example:: class keyword(_funcregistrarbase): _docformat = ":%s: %s" This should be used as below: keyword = registrar.keyword() @keyword('bar') def barfunc(*args, **kwargs): '''Explanation of bar keyword .... ''' pass In this case: - 'barfunc' is stored as 'bar' in '_table' of an instance 'keyword' above - 'barfunc.__doc__' becomes ":bar: Explanation of bar keyword" """ def __init__(self, table=None): if table is None: self._table = {} else: self._table = table def __call__(self, decl, *args, **kwargs): return lambda func: self._doregister(func, decl, *args, **kwargs) def _doregister(self, func, decl, *args, **kwargs): name = self._getname(decl) if name in self._table: msg = 'duplicate registration for name: "%s"' % name raise error.ProgrammingError(msg) if func.__doc__ and not util.safehasattr(func, '_origdoc'): doc = pycompat.sysbytes(func.__doc__).strip() func._origdoc = doc func.__doc__ = pycompat.sysstr(self._formatdoc(decl, doc)) self._table[name] = func self._extrasetup(name, func, *args, **kwargs) return func def _parsefuncdecl(self, decl): """Parse function declaration and return the name of function in it """ i = decl.find('(') if i >= 0: return decl[:i] else: return decl def _getname(self, decl): """Return the name of the registered function from decl Derived class should override this, if it allows more descriptive 'decl' string than just a name. """ return decl _docformat = None def _formatdoc(self, decl, doc): """Return formatted document of the registered function for help 'doc' is '__doc__.strip()' of the registered function. """ return self._docformat % (decl, doc) def _extrasetup(self, name, func): """Execute exra setup for registered function, if needed """ pass class revsetpredicate(_funcregistrarbase): """Decorator to register revset predicate Usage:: revsetpredicate = registrar.revsetpredicate() @revsetpredicate('mypredicate(arg1, arg2[, arg3])') def mypredicatefunc(repo, subset, x): '''Explanation of this revset predicate .... ''' pass The first string argument is used also in online help. Optional argument 'safe' indicates whether a predicate is safe for DoS attack (False by default). Optional argument 'takeorder' indicates whether a predicate function takes ordering policy as the last argument. 'revsetpredicate' instance in example above can be used to decorate multiple functions. Decorated functions are registered automatically at loading extension, if an instance named as 'revsetpredicate' is used for decorating in extension. Otherwise, explicit 'revset.loadpredicate()' is needed. """ _getname = _funcregistrarbase._parsefuncdecl _docformat = "``%s``\n %s" def _extrasetup(self, name, func, safe=False, takeorder=False): func._safe = safe func._takeorder = takeorder class filesetpredicate(_funcregistrarbase): """Decorator to register fileset predicate Usage:: filesetpredicate = registrar.filesetpredicate() @filesetpredicate('mypredicate()') def mypredicatefunc(mctx, x): '''Explanation of this fileset predicate .... ''' pass The first string argument is used also in online help. Optional argument 'callstatus' indicates whether a predicate implies 'matchctx.status()' at runtime or not (False, by default). Optional argument 'callexisting' indicates whether a predicate implies 'matchctx.existing()' at runtime or not (False, by default). 'filesetpredicate' instance in example above can be used to decorate multiple functions. Decorated functions are registered automatically at loading extension, if an instance named as 'filesetpredicate' is used for decorating in extension. Otherwise, explicit 'fileset.loadpredicate()' is needed. """ _getname = _funcregistrarbase._parsefuncdecl _docformat = "``%s``\n %s" def _extrasetup(self, name, func, callstatus=False, callexisting=False): func._callstatus = callstatus func._callexisting = callexisting class _templateregistrarbase(_funcregistrarbase): """Base of decorator to register functions as template specific one """ _docformat = ":%s: %s" class templatekeyword(_templateregistrarbase): """Decorator to register template keyword Usage:: templatekeyword = registrar.templatekeyword() @templatekeyword('mykeyword') def mykeywordfunc(repo, ctx, templ, cache, revcache, **args): '''Explanation of this template keyword .... ''' pass The first string argument is used also in online help. 'templatekeyword' instance in example above can be used to decorate multiple functions. Decorated functions are registered automatically at loading extension, if an instance named as 'templatekeyword' is used for decorating in extension. Otherwise, explicit 'templatekw.loadkeyword()' is needed. """ class templatefilter(_templateregistrarbase): """Decorator to register template filer Usage:: templatefilter = registrar.templatefilter() @templatefilter('myfilter') def myfilterfunc(text): '''Explanation of this template filter .... ''' pass The first string argument is used also in online help. 'templatefilter' instance in example above can be used to decorate multiple functions. Decorated functions are registered automatically at loading extension, if an instance named as 'templatefilter' is used for decorating in extension. Otherwise, explicit 'templatefilters.loadkeyword()' is needed. """ class templatefunc(_templateregistrarbase): """Decorator to register template function Usage:: templatefunc = registrar.templatefunc() @templatefunc('myfunc(arg1, arg2[, arg3])', argspec='arg1 arg2 arg3') def myfuncfunc(context, mapping, args): '''Explanation of this template function .... ''' pass The first string argument is used also in online help. If optional 'argspec' is defined, the function will receive 'args' as a dict of named arguments. Otherwise 'args' is a list of positional arguments. 'templatefunc' instance in example above can be used to decorate multiple functions. Decorated functions are registered automatically at loading extension, if an instance named as 'templatefunc' is used for decorating in extension. Otherwise, explicit 'templater.loadfunction()' is needed. """ _getname = _funcregistrarbase._parsefuncdecl def _extrasetup(self, name, func, argspec=None): func._argspec = argspec