# Copyright (c) 2004 DoCoMo Euro-Labs GmbH (Munich, Germany). # Copyright (c) 2001-2004 LOGILAB S.A. (Paris, FRANCE). # # http://www.docomolab-euro.com/ -- mailto:tarlano@docomolab-euro.com # http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """narval interpreter's configuration handling :version: $Revision:$ :author: Logilab :copyright: 2001-2004 LOGILAB S.A. (Paris, FRANCE) 2004 DoCoMo Euro-Labs GmbH (Munich, Germany) :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr http://www.docomolab-euro.com/ -- mailto:tarlano@docomolab-euro.com """ __revision__ = "$Id: config.py 20 2004-04-15 14:43:51Z syt $" __docformat__ = "restructuredtext en" import sys import shutil import os from os.path import normpath, join, split, expanduser, isfile, exists, dirname from ConfigParser import SafeConfigParser from narval.__pkginfo__ import version def normjoin(*path_elements): """join path elements and normalize the resulting path before returning it """ return normpath(join(*path_elements)) class ConfigurationError(Exception): """exception class for configuration errors""" # expected subdirectories in a narval home HOME_SUBDIRS = ('data', #'doc', FIXME: removed doc due to a packaging pb #'extensions', #'elements', 'interfaces', 'protocol_handlers', #'modules', 'recipes', #'dtd' ) def create_home(): """create the narval home by copying the skeleton""" home = get_home() try: os.listdir(home) except OSError: os.mkdir(home) share = get_share() for directory in HOME_SUBDIRS: dest = normjoin(home, directory) try: os.listdir(dest) except OSError: if directory == 'data': shutil.copytree(normjoin(share, directory), dest) else: # recipe os.mkdir(dest) def check_home(): """validate the narval home directory""" home = get_home() if not exists(home): raise ConfigurationError('''Narval home %s doesn\'t exist. Create it using the --create-home option of the narval interpreter''' % home) for directory in HOME_SUBDIRS: dest = normjoin(home, directory) try: os.listdir(dest) except OSError: raise ConfigurationError('''\ Narval home %s seems to be incomplete (missing %s subdirectory). Fix it using the --create-home option of the narval interpreter''' % ( home, directory)) ## def narval_path(): ## """return the narval actions/recipes path (i.e. a list of directories ## to search for actions,elements, interfaces, protocol handlers ## (i.e. python modules) and recipes (xml files) ## """ ## path = os.environ.get('NARVAL_PATH') ## if not path: ## path = [] ## else: ## path = path.split(':') ## if not config.get_home() in path: ## path.append(config.get_home()) ## if not config.get_share() in path: ## path.append(config.get_share()) ## # FIXME: devel mode ! ## return [directory for directory in path if exists(directory)] class _Configuration: """Holds configuration information for the application""" def __init__(self): self._home = None self._home_from_command_line = False self._share = None self._share_from_command_line = False self._user_home = None ## self._path = None ## def get_path(self): ## return self._path def get_home(self): return self._home def get_share(self): return self._share def get_user_home(self): return self._user_home def _set_home(self, home, from_command_line=False): self.__set_conf_attr('_home', home, '_home_from_command_line', from_command_line) def _set_share(self, share, from_command_line=False): self.__set_conf_attr('_share', share, '_share_from_command_line', from_command_line) def _set_user_home(self, user_home): self.__set_conf_attr('_user_home', user_home) ## def _set_path(self, path): ## if self._path: ## for directory in self._path: ## try: ## sys.path.remove(directory) ## except: ## continue ## reversed_path = path[:] ## reversed_path.reverse() ## for directory in reversed_path: ## sys.path.insert(0, directory) ## self._path = path def __set_conf_attr(self, attr, value, protection_attr=None, from_command_line=None): if protection_attr is None or from_command_line or not getattr(self, protection_attr): if value == 'None': if getattr(self, attr) is not None: return value = None if protection_attr is not None: setattr(self, protection_attr, from_command_line) setattr(self, attr, value) class Configurator: """Creates a configuration object""" def __init__(self): self.__conf = _Configuration() def build_config(self): self._parse_environ() if sys.platform == "win32": self._parse_registry() else: self._parse_file() devel_share = join(dirname(__file__), 'share') if exists(devel_share): self.__conf._set_share(devel_share) def set_home_from_command_line(self, home): self.__conf._set_home(home, True) def set_share_from_command_line(self, share): self.__conf._set_share(share, True) def get_configuration(self): return self.__conf def _parse_file(self, filename=None): if filename is None: filename = self._guess_candidate_config_files() parser = SafeConfigParser() parser.read(filename) self.__conf._set_home(parser.get('Directories', 'HOME')) self.__conf._set_share(parser.get('Directories', 'SHARE')) def _parse_environ(self): self.__conf._set_share(os.getenv('NARVAL_SHARE')) user_home = os.getenv('HOME') or os.getenv('USERPROFILE') self.__conf._set_user_home(user_home) narval_home = os.getenv('NARVAL_HOME', join(self.__conf.get_user_home(), '.narval')) self.__conf._set_home(narval_home) ## self.__conf._set_share(narval_path()) def _parse_registry(self): if sys.platform == 'win32': from _winreg import OpenKey, QueryInfoKey, EnumValue, \ HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE d = {} key_name = r"Software\Logilab\Narval\%s\config" % version _register_values(HKEY_LOCAL_MACHINE, key_name, d) _register_values(HKEY_CURRENT_USER, key_name, d) # user home key_name = r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders' try: key = OpenKey(HKEY_CURRENT_USER, key_name) for i in range(QueryInfoKey(key)[1]): (name, value, _) = EnumValue(key, i) if name == 'AppData': self.__conf.set_user_home(join(value.encode('mbcs'), 'narval_data')) break except: log(LOG_INFO, 'problem accessing registry HKCU\\%s to get NARVAL_HOME. ' 'Using defaults.', key_name) if not d.has_key('home'): d['home'] = d['user_home'] self.__conf._set_home(d['home']) self.__conf._set_share(d['share']) def _guess_candidate_config_files(self): candidates = ['/etc/narval/narval.conf'] head, tail = split(__file__) devel_conf = normjoin(head, 'conf', 'narval.conf') # FIXME: windows ? while head and head != '/': if tail == 'lib': candidates.append(join(head, 'etc', 'narval.conf')) break head, tail = split(head) candidates.append(devel_conf) localconf = expanduser('~/.narval.conf') candidates.append(localconf) candidates = [cand for cand in candidates if isfile(cand)] if not candidates: self._build_default_conf(localconf) candidates = [localconf] return candidates def _build_default_conf(self, filename): f = open(filename, 'w') f.write('[Directories]\n') f.write('HOME: None\n') f.write('SHARE: None\n') f.close() def _register_values(section, key_name, conf_dict): """register values in conf_dict in the windows registry :param section: root section of the registry :type key_name: str :param key_name: name of the key in the section :type conf_dict: dict :param conf_dict: dictionary handling values to register """ if sys.platform == "win32": from _winreg import OpenKey, QueryInfoKey, EnumValue try: key = OpenKey(section, key_name) for i in range(QueryInfoKey(key)[1]): (name, value, _) = EnumValue(key, i) conf_dict[name.lower()] = value.encode('mbcs') key.Close() except: log(LOG_INFO, 'problem accessing registry HKLM\\%s', key_name) DEFAULT_CONFIGURATOR = Configurator() DEFAULT_CONFIGURATOR.build_config() def get_home(): """return the narval home""" home = DEFAULT_CONFIGURATOR.get_configuration().get_home() if home not in sys.path: sys.path.insert(0, home) return home def get_user_home(): """return the user's home""" return DEFAULT_CONFIGURATOR.get_configuration().get_user_home() def get_share(): """return the narval shared directory""" return DEFAULT_CONFIGURATOR.get_configuration().get_share()