Mercurial > hg
view mercurial/registrar.py @ 27764:dd0c5f4d1b53
util: adjust 'datapath' to be correct in a frozen OS X package
Apparently unlike py2exe, py2app copies the Mercurial source tree as-is to a
Contents/Resources subdirectory of an app bundle, and places its binary stub in
Contents/MacOS. (The Windows install has the 'hgext' and 'mercurial' modules in
'lib/library.zip', while the help and templates subdirectories have been moved
out of the mercurial directory to the root of the installation. I assume that
the python code living in a zip file is why "py2exe doesn't support __file__".)
Therefore, prior to this change, Mercurial in a frozen app bundle on OS X would
go looking for help *.txt, templates and locale info in Contents/MacOS, where
they don't exist.
There are only a handful of places that test for frozen, and not all of them are
wrong for OS X, so it seems wiser to handle them on a case by case basis, rather
that try to change mainfrozen(). The remaining cases are:
1) util.hgexecutable() wrongly points to the bundled python executable, and
affects $HG in util.system() launched processes (e.g. external hooks)
2) util.hgcmd() wrongly points to the bundled python executable, but it seems
to only affect 'hg serve -d'
3) hook._pythonhook() may be OK, since I didn't see anything outrageous when
printing sys.path from an internal hook. I'm not sure if this special
case is needed on OS X though.
4) sslutil._plainapplepython() is OK, because sys.executable is not
/usr/bin/python, nor is it in /System/Library/Frameworks
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Sun, 10 Jan 2016 17:49:01 -0500 |
parents | 60bf90eb8bf8 |
children | b983a2f04987 |
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 ( util, ) class funcregistrar(object): """Base of decorator to register a fuction for specific purpose The least derived class can be defined by overriding 'table' and 'formatdoc', for example:: symbols = {} class keyword(funcregistrar): table = symbols formatdoc = ":%s: %s" @keyword('bar') def barfunc(*args, **kwargs): '''Explanation of bar keyword .... ''' pass In this case: - 'barfunc' is registered as 'bar' in 'symbols' - online help uses ":bar: Explanation of bar keyword" """ def __init__(self, decl): """'decl' is a name or more descriptive string of a function Specification of 'decl' depends on registration purpose. """ self.decl = decl table = None def __call__(self, func): """Execute actual registration for specified function """ name = self.getname() if func.__doc__ and not util.safehasattr(func, '_origdoc'): doc = func.__doc__.strip() func._origdoc = doc if callable(self.formatdoc): func.__doc__ = self.formatdoc(doc) else: # convenient shortcut for simple format func.__doc__ = self.formatdoc % (self.decl, doc) self.table[name] = func self.extraaction(name, func) return func def getname(self): """Return the name of the registered function from self.decl Derived class should override this, if it allows more descriptive 'decl' string than just a name. """ return self.decl def parsefuncdecl(self): """Parse function declaration and return the name of function in it """ i = self.decl.find('(') if i > 0: return self.decl[:i] else: return self.decl def formatdoc(self, doc): """Return formatted document of the registered function for help 'doc' is '__doc__.strip()' of the registered function. If this is overridden by non-callable object in derived class, such value is treated as "format string" and used to format document by 'self.formatdoc % (self.decl, doc)' for convenience. """ raise NotImplementedError() def extraaction(self, name, func): """Execute exra action for registered function, if needed """ pass class delayregistrar(object): """Decorator to delay actual registration until uisetup or so For example, the decorator class to delay registration by 'keyword' funcregistrar can be defined as below:: class extkeyword(delayregistrar): registrar = keyword """ def __init__(self): self._list = [] registrar = None def __call__(self, *args, **kwargs): """Return the decorator to delay actual registration until setup """ assert self.registrar is not None def decorator(func): # invocation of self.registrar() here can detect argument # mismatching immediately self._list.append((func, self.registrar(*args, **kwargs))) return func return decorator def setup(self): """Execute actual registration """ while self._list: func, decorator = self._list.pop(0) decorator(func)