cwconfig.py
branchtls-sprint
changeset 1446 e951a860eeaf
parent 1263 01152fffd593
child 1493 8270580b65a0
child 1520 b097057e629d
equal deleted inserted replaced
1437:ea75dfe32317 1446:e951a860eeaf
    62     ('encoding',
    62     ('encoding',
    63      {'type' : 'string',
    63      {'type' : 'string',
    64       'default': 'UTF-8',
    64       'default': 'UTF-8',
    65       'help': _('user interface encoding'),
    65       'help': _('user interface encoding'),
    66       'group': 'ui', 'sitewide': True,
    66       'group': 'ui', 'sitewide': True,
    67       }),    
    67       }),
    68     ('language',
    68     ('language',
    69      {'type' : 'string',
    69      {'type' : 'string',
    70       'default': 'en',
    70       'default': 'en',
    71       'vocabulary': Method('available_languages'),
    71       'vocabulary': Method('available_languages'),
    72       'help': _('language of the user interface'),
    72       'help': _('language of the user interface'),
    73       'group': 'ui', 
    73       'group': 'ui',
    74       }),
    74       }),
    75     ('date-format',
    75     ('date-format',
    76      {'type' : 'string',
    76      {'type' : 'string',
    77       'default': '%Y/%m/%d',
    77       'default': '%Y/%m/%d',
    78       'help': _('how to format date in the ui ("man strftime" for format description)'),
    78       'help': _('how to format date in the ui ("man strftime" for format description)'),
    79       'group': 'ui', 
    79       'group': 'ui',
    80       }),
    80       }),
    81     ('datetime-format',
    81     ('datetime-format',
    82      {'type' : 'string',
    82      {'type' : 'string',
    83       'default': '%Y/%m/%d %H:%M',
    83       'default': '%Y/%m/%d %H:%M',
    84       'help': _('how to format date and time in the ui ("man strftime" for format description)'),
    84       'help': _('how to format date and time in the ui ("man strftime" for format description)'),
    85       'group': 'ui', 
    85       'group': 'ui',
    86       }),
    86       }),
    87     ('time-format',
    87     ('time-format',
    88      {'type' : 'string',
    88      {'type' : 'string',
    89       'default': '%H:%M',
    89       'default': '%H:%M',
    90       'help': _('how to format time in the ui ("man strftime" for format description)'),
    90       'help': _('how to format time in the ui ("man strftime" for format description)'),
    91       'group': 'ui', 
    91       'group': 'ui',
    92       }),
    92       }),
    93     ('float-format',
    93     ('float-format',
    94      {'type' : 'string',
    94      {'type' : 'string',
    95       'default': '%.3f',
    95       'default': '%.3f',
    96       'help': _('how to format float numbers in the ui'),
    96       'help': _('how to format float numbers in the ui'),
    97       'group': 'ui', 
    97       'group': 'ui',
    98       }),
    98       }),
    99     ('default-text-format',
    99     ('default-text-format',
   100      {'type' : 'choice',
   100      {'type' : 'choice',
   101       'choices': ('text/plain', 'text/rest', 'text/html'),
   101       'choices': ('text/plain', 'text/rest', 'text/html'),
   102       'default': 'text/html', # use fckeditor in the web ui
   102       'default': 'text/html', # use fckeditor in the web ui
   103       'help': _('default text format for rich text fields.'),
   103       'help': _('default text format for rich text fields.'),
   104       'group': 'ui', 
   104       'group': 'ui',
   105       }),
   105       }),
   106     ('short-line-size',
   106     ('short-line-size',
   107      {'type' : 'int',
   107      {'type' : 'int',
   108       'default': 40,
   108       'default': 40,
   109       'help': _('maximum number of characters in short description'),
   109       'help': _('maximum number of characters in short description'),
   112     )
   112     )
   113 
   113 
   114 def register_persistent_options(options):
   114 def register_persistent_options(options):
   115     global PERSISTENT_OPTIONS
   115     global PERSISTENT_OPTIONS
   116     PERSISTENT_OPTIONS = merge_options(PERSISTENT_OPTIONS + options)
   116     PERSISTENT_OPTIONS = merge_options(PERSISTENT_OPTIONS + options)
   117                 
   117 
   118 CFGTYPE2ETYPE_MAP = {
   118 CFGTYPE2ETYPE_MAP = {
   119     'string': 'String',
   119     'string': 'String',
   120     'choice': 'String',
   120     'choice': 'String',
   121     'yn':     'Boolean',
   121     'yn':     'Boolean',
   122     'int':    'Int',
   122     'int':    'Int',
   123     'float' : 'Float',
   123     'float' : 'Float',
   124     }
   124     }
   125     
   125 
   126 class CubicWebNoAppConfiguration(ConfigurationMixIn):
   126 class CubicWebNoAppConfiguration(ConfigurationMixIn):
   127     """base class for cubicweb configuration without a specific instance directory
   127     """base class for cubicweb configuration without a specific instance directory
   128     """
   128     """
   129     __metaclass__ = metaconfiguration
   129     __metaclass__ = metaconfiguration
   130     # to set in concrete configuration
   130     # to set in concrete configuration
   196           'help': 'comma separated list of identifiers of application objects (<registry>.<oid>) to disable',
   196           'help': 'comma separated list of identifiers of application objects (<registry>.<oid>) to disable',
   197           'group': 'appobjects', 'inputlevel': 2,
   197           'group': 'appobjects', 'inputlevel': 2,
   198           }),
   198           }),
   199         )
   199         )
   200     # static and class methods used to get application independant resources ##
   200     # static and class methods used to get application independant resources ##
   201         
   201 
   202     @staticmethod
   202     @staticmethod
   203     def cubicweb_version():
   203     def cubicweb_version():
   204         """return installed cubicweb version"""
   204         """return installed cubicweb version"""
   205         from logilab.common.changelog import Version
   205         from logilab.common.changelog import Version
   206         from cubicweb import __pkginfo__
   206         from cubicweb import __pkginfo__
   207         version = __pkginfo__.numversion
   207         version = __pkginfo__.numversion
   208         assert len(version) == 3, version
   208         assert len(version) == 3, version
   209         return Version(version)
   209         return Version(version)
   210     
   210 
   211     @staticmethod
   211     @staticmethod
   212     def persistent_options_configuration():
   212     def persistent_options_configuration():
   213         return Configuration(options=PERSISTENT_OPTIONS)
   213         return Configuration(options=PERSISTENT_OPTIONS)
   214 
   214 
   215     @classmethod
   215     @classmethod
   218         library views and data may be found)
   218         library views and data may be found)
   219         """
   219         """
   220         if cls.mode in ('dev', 'test') and not os.environ.get('APYCOT_ROOT'):
   220         if cls.mode in ('dev', 'test') and not os.environ.get('APYCOT_ROOT'):
   221             return join(CW_SOFTWARE_ROOT, 'web')
   221             return join(CW_SOFTWARE_ROOT, 'web')
   222         return cls.cube_dir('shared')
   222         return cls.cube_dir('shared')
   223         
   223 
   224     @classmethod
   224     @classmethod
   225     def i18n_lib_dir(cls):
   225     def i18n_lib_dir(cls):
   226         """return application's i18n directory"""
   226         """return application's i18n directory"""
   227         if cls.mode in ('dev', 'test') and not os.environ.get('APYCOT_ROOT'):
   227         if cls.mode in ('dev', 'test') and not os.environ.get('APYCOT_ROOT'):
   228             return join(CW_SOFTWARE_ROOT, 'i18n')
   228             return join(CW_SOFTWARE_ROOT, 'i18n')
   234         for directory in cls.cubes_search_path():
   234         for directory in cls.cubes_search_path():
   235             for cube in os.listdir(directory):
   235             for cube in os.listdir(directory):
   236                 if isdir(join(directory, cube)) and not cube in ('CVS', '.svn', 'shared', '.hg'):
   236                 if isdir(join(directory, cube)) and not cube in ('CVS', '.svn', 'shared', '.hg'):
   237                     cubes.add(cube)
   237                     cubes.add(cube)
   238         return sorted(cubes)
   238         return sorted(cubes)
   239     
   239 
   240     @classmethod
   240     @classmethod
   241     def cubes_search_path(cls):
   241     def cubes_search_path(cls):
   242         """return the path of directories where cubes should be searched"""
   242         """return the path of directories where cubes should be searched"""
   243         path = []
   243         path = []
   244         try:
   244         try:
   249         except KeyError:
   249         except KeyError:
   250             pass
   250             pass
   251         if not cls.CUBES_DIR in path:
   251         if not cls.CUBES_DIR in path:
   252             path.append(cls.CUBES_DIR)
   252             path.append(cls.CUBES_DIR)
   253         return path
   253         return path
   254     
   254 
   255     @classmethod
   255     @classmethod
   256     def cube_dir(cls, cube):
   256     def cube_dir(cls, cube):
   257         """return the cube directory for the given cube id,
   257         """return the cube directory for the given cube id,
   258         raise ConfigurationError if it doesn't exists
   258         raise ConfigurationError if it doesn't exists
   259         """
   259         """
   265 
   265 
   266     @classmethod
   266     @classmethod
   267     def cube_migration_scripts_dir(cls, cube):
   267     def cube_migration_scripts_dir(cls, cube):
   268         """cube migration scripts directory"""
   268         """cube migration scripts directory"""
   269         return join(cls.cube_dir(cube), 'migration')
   269         return join(cls.cube_dir(cube), 'migration')
   270     
   270 
   271     @classmethod
   271     @classmethod
   272     def cube_pkginfo(cls, cube):
   272     def cube_pkginfo(cls, cube):
   273         """return the information module for the given cube"""
   273         """return the information module for the given cube"""
   274         cube = CW_MIGRATION_MAP.get(cube, cube)
   274         cube = CW_MIGRATION_MAP.get(cube, cube)
   275         try:
   275         try:
   278             raise ConfigurationError('unable to find packaging information for '
   278             raise ConfigurationError('unable to find packaging information for '
   279                                      'cube %s (%s: %s)' % (cube, ex.__class__.__name__, ex))
   279                                      'cube %s (%s: %s)' % (cube, ex.__class__.__name__, ex))
   280 
   280 
   281     @classmethod
   281     @classmethod
   282     def cube_version(cls, cube):
   282     def cube_version(cls, cube):
   283         """return the version of the cube located in the given directory        
   283         """return the version of the cube located in the given directory
   284         """
   284         """
   285         from logilab.common.changelog import Version
   285         from logilab.common.changelog import Version
   286         version = cls.cube_pkginfo(cube).numversion
   286         version = cls.cube_pkginfo(cube).numversion
   287         assert len(version) == 3, version
   287         assert len(version) == 3, version
   288         return Version(version)
   288         return Version(version)
   341                         try:
   341                         try:
   342                             deps.remove(cube)
   342                             deps.remove(cube)
   343                         except KeyError:
   343                         except KeyError:
   344                             continue
   344                             continue
   345         return tuple(reversed(cubes))
   345         return tuple(reversed(cubes))
   346     
   346 
   347     @classmethod
   347     @classmethod
   348     def cls_adjust_sys_path(cls):
   348     def cls_adjust_sys_path(cls):
   349         """update python path if necessary"""
   349         """update python path if necessary"""
   350         cubes_parent_dir = normpath(join(cls.CUBES_DIR, '..'))
   350         cubes_parent_dir = normpath(join(cls.CUBES_DIR, '..'))
   351         if not cubes_parent_dir in sys.path:
   351         if not cubes_parent_dir in sys.path:
   379                 try:
   379                 try:
   380                     __import__('cubes.%s' % cube)
   380                     __import__('cubes.%s' % cube)
   381                 except:
   381                 except:
   382                     cls.exception('while loading cube %s', cube)
   382                     cls.exception('while loading cube %s', cube)
   383             else:
   383             else:
   384                 cls.warning('no __init__ file in cube %s', cube) 
   384                 cls.warning('no __init__ file in cube %s', cube)
   385 
   385 
   386     @classmethod
   386     @classmethod
   387     def init_available_cubes(cls):
   387     def init_available_cubes(cls):
   388         """cubes may register some sources (svnfile for instance) in their
   388         """cubes may register some sources (svnfile for instance) in their
   389         __init__ file, so they should be loaded early in the startup process
   389         __init__ file, so they should be loaded early in the startup process
   391         for cube in cls.available_cubes():
   391         for cube in cls.available_cubes():
   392             try:
   392             try:
   393                 __import__('cubes.%s' % cube)
   393                 __import__('cubes.%s' % cube)
   394             except Exception, ex:
   394             except Exception, ex:
   395                 cls.warning("can't init cube %s: %s", cube, ex)
   395                 cls.warning("can't init cube %s: %s", cube, ex)
   396         
   396 
   397     cubicweb_vobject_path = set(['entities'])
   397     cubicweb_vobject_path = set(['entities'])
   398     cube_vobject_path = set(['entities'])
   398     cube_vobject_path = set(['entities'])
   399 
   399 
   400     @classmethod
   400     @classmethod
   401     def build_vregistry_path(cls, templpath, evobjpath=None, tvobjpath=None):
   401     def build_vregistry_path(cls, templpath, evobjpath=None, tvobjpath=None):
   439                 if exists(path):
   439                 if exists(path):
   440                     vregpath.append(path)
   440                     vregpath.append(path)
   441                 elif exists(path + '.py'):
   441                 elif exists(path + '.py'):
   442                     vregpath.append(path + '.py')
   442                     vregpath.append(path + '.py')
   443         return vregpath
   443         return vregpath
   444         
   444 
   445     def __init__(self):
   445     def __init__(self):
   446         ConfigurationMixIn.__init__(self)
   446         ConfigurationMixIn.__init__(self)
   447         self.adjust_sys_path()
   447         self.adjust_sys_path()
   448         self.load_defaults()
   448         self.load_defaults()
   449         self.translations = {} 
   449         self.translations = {}
   450 
   450 
   451     def adjust_sys_path(self):
   451     def adjust_sys_path(self):
   452         self.cls_adjust_sys_path()
   452         self.cls_adjust_sys_path()
   453         
   453 
   454     def init_log(self, logthreshold=None, debug=False, 
   454     def init_log(self, logthreshold=None, debug=False,
   455                  logfile=None, syslog=False):
   455                  logfile=None, syslog=False):
   456         """init the log service"""
   456         """init the log service"""
   457         if logthreshold is None:
   457         if logthreshold is None:
   458             if debug:
   458             if debug:
   459                 logthreshold = 'DEBUG'
   459                 logthreshold = 'DEBUG'
   466     def vregistry_path(self):
   466     def vregistry_path(self):
   467         """return a list of files or directories where the registry will look
   467         """return a list of files or directories where the registry will look
   468         for application objects. By default return nothing in NoApp config.
   468         for application objects. By default return nothing in NoApp config.
   469         """
   469         """
   470         return []
   470         return []
   471     
   471 
   472     def eproperty_definitions(self):
   472     def eproperty_definitions(self):
   473         cfg = self.persistent_options_configuration()
   473         cfg = self.persistent_options_configuration()
   474         for section, options in cfg.options_by_section():
   474         for section, options in cfg.options_by_section():
   475             section = section.lower()
   475             section = section.lower()
   476             for optname, optdict, value in options:
   476             for optname, optdict, value in options:
   479                 default = cfg.option_default(optname, optdict)
   479                 default = cfg.option_default(optname, optdict)
   480                 pdef = {'type': type, 'vocabulary': vocab, 'default': default,
   480                 pdef = {'type': type, 'vocabulary': vocab, 'default': default,
   481                         'help': optdict['help'],
   481                         'help': optdict['help'],
   482                         'sitewide': optdict.get('sitewide', False)}
   482                         'sitewide': optdict.get('sitewide', False)}
   483                 yield key, pdef
   483                 yield key, pdef
   484                 
   484 
   485     def map_option(self, optdict):
   485     def map_option(self, optdict):
   486         try:
   486         try:
   487             vocab = optdict['choices']
   487             vocab = optdict['choices']
   488         except KeyError:
   488         except KeyError:
   489             vocab = optdict.get('vocabulary')
   489             vocab = optdict.get('vocabulary')
   490             if isinstance(vocab, Method):
   490             if isinstance(vocab, Method):
   491                 vocab = getattr(self, vocab.method, ())
   491                 vocab = getattr(self, vocab.method, ())
   492         return CFGTYPE2ETYPE_MAP[optdict['type']], vocab
   492         return CFGTYPE2ETYPE_MAP[optdict['type']], vocab
   493 
   493 
   494     
   494 
   495 class CubicWebConfiguration(CubicWebNoAppConfiguration):
   495 class CubicWebConfiguration(CubicWebNoAppConfiguration):
   496     """base class for cubicweb server and web configurations"""
   496     """base class for cubicweb server and web configurations"""
   497     
   497 
   498     INSTANCE_DATA_DIR = None
   498     INSTANCE_DATA_DIR = None
   499     if CubicWebNoAppConfiguration.mode == 'test':
   499     if CubicWebNoAppConfiguration.mode == 'test':
   500         root = os.environ['APYCOT_ROOT']
   500         root = os.environ['APYCOT_ROOT']
   501         REGISTRY_DIR = '%s/etc/cubicweb.d/' % root
   501         REGISTRY_DIR = '%s/etc/cubicweb.d/' % root
   502         RUNTIME_DIR = '/tmp/'
   502         RUNTIME_DIR = '/tmp/'
   515 
   515 
   516     # for some commands (creation...) we don't want to initialize gettext
   516     # for some commands (creation...) we don't want to initialize gettext
   517     set_language = True
   517     set_language = True
   518     # set this to true to avoid false error message while creating an application
   518     # set this to true to avoid false error message while creating an application
   519     creating = False
   519     creating = False
   520     
   520 
   521     options = CubicWebNoAppConfiguration.options + (
   521     options = CubicWebNoAppConfiguration.options + (
   522         ('log-file',
   522         ('log-file',
   523          {'type' : 'string',
   523          {'type' : 'string',
   524           'default': Method('default_log_file'),
   524           'default': Method('default_log_file'),
   525           'help': 'file where output logs should be written',
   525           'help': 'file where output logs should be written',
   538           'help': 'listening port of the SMTP mail server',
   538           'help': 'listening port of the SMTP mail server',
   539           'group': 'email', 'inputlevel': 1,
   539           'group': 'email', 'inputlevel': 1,
   540           }),
   540           }),
   541         ('sender-name',
   541         ('sender-name',
   542          {'type' : 'string',
   542          {'type' : 'string',
   543           'default': Method('default_application_id'), 
   543           'default': Method('default_application_id'),
   544           'help': 'name used as HELO name for outgoing emails from the \
   544           'help': 'name used as HELO name for outgoing emails from the \
   545 repository.',
   545 repository.',
   546           'group': 'email', 'inputlevel': 2,
   546           'group': 'email', 'inputlevel': 2,
   547           }),
   547           }),
   548         ('sender-addr',
   548         ('sender-addr',
   556 
   556 
   557     @classmethod
   557     @classmethod
   558     def runtime_dir(cls):
   558     def runtime_dir(cls):
   559         """run time directory for pid file..."""
   559         """run time directory for pid file..."""
   560         return env_path('CW_RUNTIME', cls.RUNTIME_DIR, 'run time')
   560         return env_path('CW_RUNTIME', cls.RUNTIME_DIR, 'run time')
   561     
   561 
   562     @classmethod
   562     @classmethod
   563     def registry_dir(cls):
   563     def registry_dir(cls):
   564         """return the control directory"""
   564         """return the control directory"""
   565         return env_path('CW_REGISTRY', cls.REGISTRY_DIR, 'registry')
   565         return env_path('CW_REGISTRY', cls.REGISTRY_DIR, 'registry')
   566 
   566 
   568     def instance_data_dir(cls):
   568     def instance_data_dir(cls):
   569         """return the instance data directory"""
   569         """return the instance data directory"""
   570         return env_path('CW_INSTANCE_DATA',
   570         return env_path('CW_INSTANCE_DATA',
   571                         cls.INSTANCE_DATA_DIR or cls.REGISTRY_DIR,
   571                         cls.INSTANCE_DATA_DIR or cls.REGISTRY_DIR,
   572                         'additional data')
   572                         'additional data')
   573         
   573 
   574     @classmethod
   574     @classmethod
   575     def migration_scripts_dir(cls):
   575     def migration_scripts_dir(cls):
   576         """cubicweb migration scripts directory"""
   576         """cubicweb migration scripts directory"""
   577         return env_path('CW_MIGRATION', cls.MIGRATION_DIR, 'migration')
   577         return env_path('CW_MIGRATION', cls.MIGRATION_DIR, 'migration')
   578 
   578 
   581         """return a configuration instance for the given application identifier
   581         """return a configuration instance for the given application identifier
   582         """
   582         """
   583         config = config or guess_configuration(cls.application_home(appid))
   583         config = config or guess_configuration(cls.application_home(appid))
   584         configcls = configuration_cls(config)
   584         configcls = configuration_cls(config)
   585         return configcls(appid)
   585         return configcls(appid)
   586     
   586 
   587     @classmethod
   587     @classmethod
   588     def possible_configurations(cls, appid):
   588     def possible_configurations(cls, appid):
   589         """return the name of possible configurations for the given
   589         """return the name of possible configurations for the given
   590         application id
   590         application id
   591         """
   591         """
   592         home = cls.application_home(appid)
   592         home = cls.application_home(appid)
   593         return possible_configurations(home)
   593         return possible_configurations(home)
   594     
   594 
   595     @classmethod
   595     @classmethod
   596     def application_home(cls, appid):
   596     def application_home(cls, appid):
   597         """return the home directory of the application with the given
   597         """return the home directory of the application with the given
   598         application id
   598         application id
   599         """
   599         """
   608                'twisted'   : ('common', 'web'),}
   608                'twisted'   : ('common', 'web'),}
   609     @classmethod
   609     @classmethod
   610     def accept_mode(cls, mode):
   610     def accept_mode(cls, mode):
   611         #assert mode in cls.MODES, mode
   611         #assert mode in cls.MODES, mode
   612         return mode in cls.MCOMPAT[cls.name]
   612         return mode in cls.MCOMPAT[cls.name]
   613             
   613 
   614     # default configuration methods ###########################################
   614     # default configuration methods ###########################################
   615     
   615 
   616     def default_application_id(self):
   616     def default_application_id(self):
   617         """return the application identifier, useful for option which need this
   617         """return the application identifier, useful for option which need this
   618         as default value
   618         as default value
   619         """
   619         """
   620         return self.appid
   620         return self.appid
   632                 except IOError:
   632                 except IOError:
   633                     path = '%s-%s.log' % (basepath, i)
   633                     path = '%s-%s.log' % (basepath, i)
   634                     i += 1
   634                     i += 1
   635             return path
   635             return path
   636         return '/var/log/cubicweb/%s-%s.log' % (self.appid, self.name)
   636         return '/var/log/cubicweb/%s-%s.log' % (self.appid, self.name)
   637     
   637 
   638     def default_pid_file(self):
   638     def default_pid_file(self):
   639         """return default path to the pid file of the application'server"""
   639         """return default path to the pid file of the application'server"""
   640         return join(self.runtime_dir(), '%s-%s.pid' % (self.appid, self.name))
   640         return join(self.runtime_dir(), '%s-%s.pid' % (self.appid, self.name))
   641     
   641 
   642     # instance methods used to get application specific resources #############
   642     # instance methods used to get application specific resources #############
   643     
   643 
   644     def __init__(self, appid):
   644     def __init__(self, appid):
   645         self.appid = appid
   645         self.appid = appid
   646         CubicWebNoAppConfiguration.__init__(self)
   646         CubicWebNoAppConfiguration.__init__(self)
   647         self._cubes = None
   647         self._cubes = None
   648         self._site_loaded = set()
   648         self._site_loaded = set()
   656             sys.path.insert(0, self.apphome)
   656             sys.path.insert(0, self.apphome)
   657 
   657 
   658     @property
   658     @property
   659     def apphome(self):
   659     def apphome(self):
   660         return join(self.registry_dir(), self.appid)
   660         return join(self.registry_dir(), self.appid)
   661     
   661 
   662     @property
   662     @property
   663     def appdatahome(self):
   663     def appdatahome(self):
   664         return join(self.instance_data_dir(), self.appid)
   664         return join(self.instance_data_dir(), self.appid)
   665         
   665 
   666     def init_cubes(self, cubes):
   666     def init_cubes(self, cubes):
   667         assert self._cubes is None
   667         assert self._cubes is None
   668         self._cubes = self.reorder_cubes(cubes)
   668         self._cubes = self.reorder_cubes(cubes)
   669         # load cubes'__init__.py file first
   669         # load cubes'__init__.py file first
   670         for cube in cubes:
   670         for cube in cubes:
   673         # reload config file in cases options are defined in cubes __init__
   673         # reload config file in cases options are defined in cubes __init__
   674         # or site_cubicweb files
   674         # or site_cubicweb files
   675         self.load_file_configuration(self.main_config_file())
   675         self.load_file_configuration(self.main_config_file())
   676         # configuration initialization hook
   676         # configuration initialization hook
   677         self.load_configuration()
   677         self.load_configuration()
   678         
   678 
   679     def cubes(self):
   679     def cubes(self):
   680         """return the list of cubes used by this instance
   680         """return the list of cubes used by this instance
   681 
   681 
   682         result is ordered from the top level cubes to inner dependencies
   682         result is ordered from the top level cubes to inner dependencies
   683         cubes
   683         cubes
   684         """
   684         """
   685         assert self._cubes is not None
   685         assert self._cubes is not None
   686         return self._cubes
   686         return self._cubes
   687         
   687 
   688     def cubes_path(self):
   688     def cubes_path(self):
   689         """return the list of path to cubes used by this instance, from outer
   689         """return the list of path to cubes used by this instance, from outer
   690         most to inner most cubes
   690         most to inner most cubes
   691         """
   691         """
   692         return [self.cube_dir(p) for p in self.cubes()]
   692         return [self.cube_dir(p) for p in self.cubes()]
   694     def add_cubes(self, cubes):
   694     def add_cubes(self, cubes):
   695         """add given cubes to the list of used cubes"""
   695         """add given cubes to the list of used cubes"""
   696         if not isinstance(cubes, list):
   696         if not isinstance(cubes, list):
   697             cubes = list(cubes)
   697             cubes = list(cubes)
   698         self._cubes = self.reorder_cubes(list(self._cubes) + cubes)
   698         self._cubes = self.reorder_cubes(list(self._cubes) + cubes)
   699         
   699 
   700     def main_config_file(self):
   700     def main_config_file(self):
   701         """return application's control configuration file"""
   701         """return application's control configuration file"""
   702         return join(self.apphome, '%s.conf' % self.name)
   702         return join(self.apphome, '%s.conf' % self.name)
   703             
   703 
   704     def save(self):
   704     def save(self):
   705         """write down current configuration"""
   705         """write down current configuration"""
   706         self.generate_config(open(self.main_config_file(), 'w'))
   706         self.generate_config(open(self.main_config_file(), 'w'))
   707 
   707 
   708     @cached
   708     @cached
   711         infos = []
   711         infos = []
   712         for pkg in self.cubes():
   712         for pkg in self.cubes():
   713             version = self.cube_version(pkg)
   713             version = self.cube_version(pkg)
   714             infos.append('%s-%s' % (pkg, version))
   714             infos.append('%s-%s' % (pkg, version))
   715         return md5.new(';'.join(infos)).hexdigest()
   715         return md5.new(';'.join(infos)).hexdigest()
   716                 
   716 
   717     def load_site_cubicweb(self):
   717     def load_site_cubicweb(self):
   718         """load (web?) application's specific site_cubicweb file"""
   718         """load (web?) application's specific site_cubicweb file"""
   719         for path in reversed([self.apphome] + self.cubes_path()):
   719         for path in reversed([self.apphome] + self.cubes_path()):
   720             sitefile = join(path, 'site_cubicweb.py')
   720             sitefile = join(path, 'site_cubicweb.py')
   721             if exists(sitefile) and not sitefile in self._site_loaded:
   721             if exists(sitefile) and not sitefile in self._site_loaded:
   725                 sitefile = join(path, 'site_erudi.py')
   725                 sitefile = join(path, 'site_erudi.py')
   726                 if exists(sitefile) and not sitefile in self._site_loaded:
   726                 if exists(sitefile) and not sitefile in self._site_loaded:
   727                     self._load_site_cubicweb(sitefile)
   727                     self._load_site_cubicweb(sitefile)
   728                     self._site_loaded.add(sitefile)
   728                     self._site_loaded.add(sitefile)
   729                     self.warning('site_erudi.py is deprecated, should be renamed to site_cubicweb.py')
   729                     self.warning('site_erudi.py is deprecated, should be renamed to site_cubicweb.py')
   730                 
   730 
   731     def _load_site_cubicweb(self, sitefile):
   731     def _load_site_cubicweb(self, sitefile):
   732         context = {}
   732         context = {}
   733         execfile(sitefile, context, context)
   733         execfile(sitefile, context, context)
   734         self.info('%s loaded', sitefile)
   734         self.info('%s loaded', sitefile)
   735         # cube specific options
   735         # cube specific options
   736         if context.get('options'):
   736         if context.get('options'):
   737             self.register_options(context['options'])
   737             self.register_options(context['options'])
   738             self.load_defaults()
   738             self.load_defaults()
   739                 
   739 
   740     def load_configuration(self):
   740     def load_configuration(self):
   741         """load application's configuration files"""
   741         """load application's configuration files"""
   742         super(CubicWebConfiguration, self).load_configuration()
   742         super(CubicWebConfiguration, self).load_configuration()
   743         if self.apphome and self.set_language:
   743         if self.apphome and self.set_language:
   744             # init gettext
   744             # init gettext
   745             self._set_language()
   745             self._set_language()
   746             
   746 
   747     def init_log(self, logthreshold=None, debug=False, force=False):
   747     def init_log(self, logthreshold=None, debug=False, force=False):
   748         """init the log service"""
   748         """init the log service"""
   749         if not force and hasattr(self, '_logging_initialized'):
   749         if not force and hasattr(self, '_logging_initialized'):
   750             return
   750             return
   751         self._logging_initialized = True
   751         self._logging_initialized = True
   767         for path in glob(join(self.apphome, 'i18n',
   767         for path in glob(join(self.apphome, 'i18n',
   768                               '*', 'LC_MESSAGES', 'cubicweb.mo')):
   768                               '*', 'LC_MESSAGES', 'cubicweb.mo')):
   769             lang = path.split(os.sep)[-3]
   769             lang = path.split(os.sep)[-3]
   770             if lang != 'en':
   770             if lang != 'en':
   771                 yield lang
   771                 yield lang
   772         
   772 
   773     def _set_language(self):
   773     def _set_language(self):
   774         """set language for gettext"""
   774         """set language for gettext"""
   775         from gettext import translation
   775         from gettext import translation
   776         path = join(self.apphome, 'i18n')
   776         path = join(self.apphome, 'i18n')
   777         for language in self.available_languages():
   777         for language in self.available_languages():
   779             try:
   779             try:
   780                 tr = translation('cubicweb', path, languages=[language])
   780                 tr = translation('cubicweb', path, languages=[language])
   781                 self.translations[language] = tr.ugettext
   781                 self.translations[language] = tr.ugettext
   782             except (ImportError, AttributeError, IOError):
   782             except (ImportError, AttributeError, IOError):
   783                 self.exception('localisation support error for language %s',
   783                 self.exception('localisation support error for language %s',
   784                                language)            
   784                                language)
   785     
   785 
   786     def vregistry_path(self):
   786     def vregistry_path(self):
   787         """return a list of files or directories where the registry will look
   787         """return a list of files or directories where the registry will look
   788         for application objects
   788         for application objects
   789         """
   789         """
   790         templpath = list(reversed(self.cubes_path()))
   790         templpath = list(reversed(self.cubes_path()))
   794 
   794 
   795     def set_sources_mode(self, sources):
   795     def set_sources_mode(self, sources):
   796         if not 'all' in sources:
   796         if not 'all' in sources:
   797             print 'warning: ignoring specified sources, requires a repository '\
   797             print 'warning: ignoring specified sources, requires a repository '\
   798                   'configuration'
   798                   'configuration'
   799         
   799 
   800     def migration_handler(self):
   800     def migration_handler(self):
   801         """return a migration handler instance"""
   801         """return a migration handler instance"""
   802         from cubicweb.common.migration import MigrationHelper
   802         from cubicweb.common.migration import MigrationHelper
   803         return MigrationHelper(self, verbosity=self.verbosity)
   803         return MigrationHelper(self, verbosity=self.verbosity)
   804 
   804 
   812         sourcedirs = [join(path, 'i18n') for path in self.cubes_path()]
   812         sourcedirs = [join(path, 'i18n') for path in self.cubes_path()]
   813         sourcedirs.append(self.i18n_lib_dir())
   813         sourcedirs.append(self.i18n_lib_dir())
   814         return i18n.compile_i18n_catalogs(sourcedirs, i18ndir, langs)
   814         return i18n.compile_i18n_catalogs(sourcedirs, i18ndir, langs)
   815 
   815 
   816 set_log_methods(CubicWebConfiguration, logging.getLogger('cubicweb.configuration'))
   816 set_log_methods(CubicWebConfiguration, logging.getLogger('cubicweb.configuration'))
   817         
   817 
   818 # alias to get a configuration instance from an application id
   818 # alias to get a configuration instance from an application id
   819 application_configuration = CubicWebConfiguration.config_for        
   819 application_configuration = CubicWebConfiguration.config_for
   820 
   820