cwconfig.py
brancholdstable
changeset 4985 02b52bf9f5f8
parent 4936 a4b772a0d801
child 4938 b1a4fe480de5
equal deleted inserted replaced
4563:c25da7573ebd 4985:02b52bf9f5f8
    76 _ = unicode
    76 _ = unicode
    77 
    77 
    78 import sys
    78 import sys
    79 import os
    79 import os
    80 import logging
    80 import logging
       
    81 import tempfile
    81 from smtplib import SMTP
    82 from smtplib import SMTP
    82 from threading import Lock
    83 from threading import Lock
    83 from os.path import exists, join, expanduser, abspath, normpath, basename, isdir
    84 from os.path import exists, join, expanduser, abspath, normpath, basename, isdir
    84 import tempfile
    85 from warnings import warn
    85 
    86 
    86 from logilab.common.decorators import cached
    87 from logilab.common.decorators import cached, classproperty
    87 from logilab.common.deprecation import deprecated
    88 from logilab.common.deprecation import deprecated
    88 from logilab.common.logging_ext import set_log_methods, init_log
    89 from logilab.common.logging_ext import set_log_methods, init_log
    89 from logilab.common.configuration import (Configuration, Method,
    90 from logilab.common.configuration import (Configuration, Method,
    90                                           ConfigurationMixIn, merge_options)
    91                                           ConfigurationMixIn, merge_options)
    91 
    92 
   112     except IndexError:
   113     except IndexError:
   113         raise ConfigurationError('no such config %r (check it exists with "cubicweb-ctl list")' % name)
   114         raise ConfigurationError('no such config %r (check it exists with "cubicweb-ctl list")' % name)
   114 
   115 
   115 def possible_configurations(directory):
   116 def possible_configurations(directory):
   116     """return a list of installed configurations in a directory
   117     """return a list of installed configurations in a directory
   117     according to *-ctl files
   118     according to \*-ctl files
   118     """
   119     """
   119     return [name for name in ('repository', 'twisted', 'all-in-one')
   120     return [name for name in ('repository', 'twisted', 'all-in-one')
   120             if exists(join(directory, '%s.conf' % name))]
   121             if exists(join(directory, '%s.conf' % name))]
   121 
   122 
   122 def guess_configuration(directory):
   123 def guess_configuration(directory):
   214     # debug mode
   215     # debug mode
   215     debugmode = False
   216     debugmode = False
   216 
   217 
   217     if os.environ.get('APYCOT_ROOT'):
   218     if os.environ.get('APYCOT_ROOT'):
   218         mode = 'test'
   219         mode = 'test'
   219         if CWDEV:
   220         # allow to test cubes within apycot using cubicweb not installed by
       
   221         # apycot
       
   222         if __file__.startswith(os.environ['APYCOT_ROOT']):
   220             CUBES_DIR = '%(APYCOT_ROOT)s/local/share/cubicweb/cubes/' % os.environ
   223             CUBES_DIR = '%(APYCOT_ROOT)s/local/share/cubicweb/cubes/' % os.environ
   221             # create __init__ file
   224             # create __init__ file
   222             file(join(CUBES_DIR, '__init__.py'), 'w').close()
   225             file(join(CUBES_DIR, '__init__.py'), 'w').close()
   223         else:
   226         else:
   224             CUBES_DIR = '/usr/share/cubicweb/cubes/'
   227             CUBES_DIR = '/usr/share/cubicweb/cubes/'
   233         CUBES_DIR = '/usr/share/cubicweb/cubes/'
   236         CUBES_DIR = '/usr/share/cubicweb/cubes/'
   234 
   237 
   235     options = (
   238     options = (
   236        ('log-threshold',
   239        ('log-threshold',
   237          {'type' : 'string', # XXX use a dedicated type?
   240          {'type' : 'string', # XXX use a dedicated type?
   238           'default': 'ERROR',
   241           'default': 'WARNING',
   239           'help': 'server\'s log level',
   242           'help': 'server\'s log level',
   240           'group': 'main', 'inputlevel': 1,
   243           'group': 'main', 'inputlevel': 1,
   241           }),
   244           }),
   242         # pyro options
   245         # pyro options
   243         ('pyro-instance-id',
   246         ('pyro-instance-id',
   288           'default': False,
   291           'default': False,
   289           'help': "don't display actual email addresses but mangle them if \
   292           'help': "don't display actual email addresses but mangle them if \
   290 this option is set to yes",
   293 this option is set to yes",
   291           'group': 'email', 'inputlevel': 2,
   294           'group': 'email', 'inputlevel': 2,
   292           }),
   295           }),
   293         ('disable-appobjects',
       
   294          {'type' : 'csv', 'default': (),
       
   295           'help': 'comma separated list of identifiers of application objects (<registry>.<oid>) to disable',
       
   296           'group': 'appobjects', 'inputlevel': 2,
       
   297           }),
       
   298         )
   296         )
   299     # static and class methods used to get instance independant resources ##
   297     # static and class methods used to get instance independant resources ##
   300 
   298 
   301     @staticmethod
   299     @staticmethod
   302     def cubicweb_version():
   300     def cubicweb_version():
   330     @classmethod
   328     @classmethod
   331     def available_cubes(cls):
   329     def available_cubes(cls):
   332         cubes = set()
   330         cubes = set()
   333         for directory in cls.cubes_search_path():
   331         for directory in cls.cubes_search_path():
   334             if not os.path.exists(directory):
   332             if not os.path.exists(directory):
   335                 self.error('unexistant directory in cubes search path: %s'
   333                 cls.error('unexistant directory in cubes search path: %s'
   336                            % directory)
   334                            % directory)
   337                 continue
   335                 continue
   338             for cube in os.listdir(directory):
   336             for cube in os.listdir(directory):
   339                 if isdir(join(directory, cube)) and not cube == 'shared':
   337                 if isdir(join(directory, cube)) and not cube == 'shared':
   340                     cubes.add(cube)
   338                     cubes.add(cube)
   349                 directory = abspath(normpath(directory))
   347                 directory = abspath(normpath(directory))
   350                 if exists(directory) and not directory in path:
   348                 if exists(directory) and not directory in path:
   351                     path.append(directory)
   349                     path.append(directory)
   352         except KeyError:
   350         except KeyError:
   353             pass
   351             pass
   354         if not cls.CUBES_DIR in path:
   352         if not cls.CUBES_DIR in path and exists(cls.CUBES_DIR):
   355             path.append(cls.CUBES_DIR)
   353             path.append(cls.CUBES_DIR)
   356         return path
   354         return path
       
   355 
       
   356     @classproperty
       
   357     def extrapath(cls):
       
   358         extrapath = {}
       
   359         for cubesdir in cls.cubes_search_path():
       
   360             if cubesdir != cls.CUBES_DIR:
       
   361                 extrapath[cubesdir] = 'cubes'
       
   362         return extrapath
   357 
   363 
   358     @classmethod
   364     @classmethod
   359     def cube_dir(cls, cube):
   365     def cube_dir(cls, cube):
   360         """return the cube directory for the given cube id,
   366         """return the cube directory for the given cube id,
   361         raise ConfigurationError if it doesn't exists
   367         raise ConfigurationError if it doesn't exists
   468     @classmethod
   474     @classmethod
   469     def load_cwctl_plugins(cls):
   475     def load_cwctl_plugins(cls):
   470         from logilab.common.modutils import load_module_from_file
   476         from logilab.common.modutils import load_module_from_file
   471         cls.cls_adjust_sys_path()
   477         cls.cls_adjust_sys_path()
   472         for ctlfile in ('web/webctl.py',  'etwist/twctl.py',
   478         for ctlfile in ('web/webctl.py',  'etwist/twctl.py',
   473                         'server/serverctl.py', 'hercule.py',
   479                         'server/serverctl.py',
   474                         'devtools/devctl.py', 'goa/goactl.py'):
   480                         'devtools/devctl.py', 'goa/goactl.py'):
   475             if exists(join(CW_SOFTWARE_ROOT, ctlfile)):
   481             if exists(join(CW_SOFTWARE_ROOT, ctlfile)):
   476                 try:
   482                 try:
   477                     load_module_from_file(join(CW_SOFTWARE_ROOT, ctlfile))
   483                     load_module_from_file(join(CW_SOFTWARE_ROOT, ctlfile))
   478                 except ImportError, err:
   484                 except ImportError, err:
   479                     cls.info('could not import the command provider %s (cause : %s)' %
   485                     cls.info('could not import the command provider %s (cause : %s)' %
   480                                 (ctlfile, err))
   486                                 (ctlfile, err))
   481                 cls.info('loaded cubicweb-ctl plugin %s', ctlfile)
   487                 cls.info('loaded cubicweb-ctl plugin %s', ctlfile)
   482         for cube in cls.available_cubes():
   488         for cube in cls.available_cubes():
   483             pluginfile = join(cls.cube_dir(cube), 'ecplugin.py')
   489             oldpluginfile = join(cls.cube_dir(cube), 'ecplugin.py')
       
   490             pluginfile = join(cls.cube_dir(cube), 'ccplugin.py')
   484             initfile = join(cls.cube_dir(cube), '__init__.py')
   491             initfile = join(cls.cube_dir(cube), '__init__.py')
   485             if exists(pluginfile):
   492             if exists(pluginfile):
       
   493                 try:
       
   494                     __import__('cubes.%s.ccplugin' % cube)
       
   495                     cls.info('loaded cubicweb-ctl plugin from %s', cube)
       
   496                 except:
       
   497                     cls.exception('while loading plugin %s', pluginfile)
       
   498             elif exists(oldpluginfile):
       
   499                 warn('[3.6] %s: ecplugin module should be renamed to ccplugin' % cube,
       
   500                      DeprecationWarning)
   486                 try:
   501                 try:
   487                     __import__('cubes.%s.ecplugin' % cube)
   502                     __import__('cubes.%s.ecplugin' % cube)
   488                     cls.info('loaded cubicweb-ctl plugin from %s', cube)
   503                     cls.info('loaded cubicweb-ctl plugin from %s', cube)
   489                 except:
   504                 except:
   490                     cls.exception('while loading plugin %s', pluginfile)
   505                     cls.exception('while loading plugin %s', oldpluginfile)
   491             elif exists(initfile):
   506             elif exists(initfile):
   492                 try:
   507                 try:
   493                     __import__('cubes.%s' % cube)
   508                     __import__('cubes.%s' % cube)
   494                 except:
   509                 except:
   495                     cls.exception('while loading cube %s', cube)
   510                     cls.exception('while loading cube %s', cube)
   554                 elif exists(path + '.py'):
   569                 elif exists(path + '.py'):
   555                     vregpath.append(path + '.py')
   570                     vregpath.append(path + '.py')
   556         return vregpath
   571         return vregpath
   557 
   572 
   558     def __init__(self):
   573     def __init__(self):
       
   574         register_stored_procedures()
   559         ConfigurationMixIn.__init__(self)
   575         ConfigurationMixIn.__init__(self)
   560         self.adjust_sys_path()
   576         self.adjust_sys_path()
   561         self.load_defaults()
   577         self.load_defaults()
   562         self.translations = {}
   578         self.translations = {}
   563         # don't register ReStructured Text directives by simple import, avoid pb
   579         # don't register ReStructured Text directives by simple import, avoid pb
   622 
   638 
   623 class CubicWebConfiguration(CubicWebNoAppConfiguration):
   639 class CubicWebConfiguration(CubicWebNoAppConfiguration):
   624     """base class for cubicweb server and web configurations"""
   640     """base class for cubicweb server and web configurations"""
   625 
   641 
   626     INSTANCES_DATA_DIR = None
   642     INSTANCES_DATA_DIR = None
   627     if CubicWebNoAppConfiguration.mode == 'test':
   643     if os.environ.get('APYCOT_ROOT'):
   628         root = os.environ['APYCOT_ROOT']
   644         root = os.environ['APYCOT_ROOT']
   629         REGISTRY_DIR = '%s/etc/cubicweb.d/' % root
   645         REGISTRY_DIR = '%s/etc/cubicweb.d/' % root
       
   646         if not exists(REGISTRY_DIR):
       
   647             os.makedirs(REGISTRY_DIR)
   630         RUNTIME_DIR = tempfile.gettempdir()
   648         RUNTIME_DIR = tempfile.gettempdir()
   631         if CWDEV:
   649         # allow to test cubes within apycot using cubicweb not installed by
       
   650         # apycot
       
   651         if __file__.startswith(os.environ['APYCOT_ROOT']):
   632             MIGRATION_DIR = '%s/local/share/cubicweb/migration/' % root
   652             MIGRATION_DIR = '%s/local/share/cubicweb/migration/' % root
   633         else:
   653         else:
   634             MIGRATION_DIR = '/usr/share/cubicweb/migration/'
   654             MIGRATION_DIR = '/usr/share/cubicweb/migration/'
   635         if not exists(REGISTRY_DIR):
       
   636             os.makedirs(REGISTRY_DIR)
       
   637     else:
   655     else:
   638         if CubicWebNoAppConfiguration.mode == 'user':
   656         if CubicWebNoAppConfiguration.mode == 'user':
   639             REGISTRY_DIR = expanduser('~/etc/cubicweb.d/')
   657             REGISTRY_DIR = expanduser('~/etc/cubicweb.d/')
   640             RUNTIME_DIR = tempfile.gettempdir()
   658             RUNTIME_DIR = tempfile.gettempdir()
   641             INSTANCES_DATA_DIR = REGISTRY_DIR
   659             INSTANCES_DATA_DIR = REGISTRY_DIR
   860             else:
   878             else:
   861                 sitefile = join(path, 'site_erudi.py')
   879                 sitefile = join(path, 'site_erudi.py')
   862                 if exists(sitefile) and not sitefile in self._site_loaded:
   880                 if exists(sitefile) and not sitefile in self._site_loaded:
   863                     self._load_site_cubicweb(sitefile)
   881                     self._load_site_cubicweb(sitefile)
   864                     self._site_loaded.add(sitefile)
   882                     self._site_loaded.add(sitefile)
   865                     self.warning('site_erudi.py is deprecated, should be renamed to site_cubicweb.py')
   883                     self.warning('[3.5] site_erudi.py is deprecated, should be renamed to site_cubicweb.py')
   866 
   884 
   867     def _load_site_cubicweb(self, sitefile):
   885     def _load_site_cubicweb(self, sitefile):
   868         from logilab.common.modutils import load_module_from_file
   886         # XXX extrapath argument to load_module_from_file only in lgc > 0.46
   869         module = load_module_from_file(sitefile)
   887         from logilab.common.modutils import load_module_from_modpath, modpath_from_file
       
   888         def load_module_from_file(filepath, path=None, use_sys=1, extrapath=None):
       
   889             return load_module_from_modpath(modpath_from_file(filepath, extrapath),
       
   890                                             path, use_sys)
       
   891         module = load_module_from_file(sitefile, extrapath=self.extrapath)
   870         self.info('%s loaded', sitefile)
   892         self.info('%s loaded', sitefile)
   871         # cube specific options
   893         # cube specific options
   872         if getattr(module, 'options', None):
   894         if getattr(module, 'options', None):
   873             self.register_options(module.options)
   895             self.register_options(module.options)
   874             self.load_defaults()
   896             self.load_defaults()
   894 
   916 
   895     def available_languages(self, *args):
   917     def available_languages(self, *args):
   896         """return available translation for an instance, by looking for
   918         """return available translation for an instance, by looking for
   897         compiled catalog
   919         compiled catalog
   898 
   920 
   899         take *args to be usable as a vocabulary method
   921         take \*args to be usable as a vocabulary method
   900         """
   922         """
   901         from glob import glob
   923         from glob import glob
   902         yield 'en' # ensure 'en' is yielded even if no .mo found
   924         yield 'en' # ensure 'en' is yielded even if no .mo found
   903         for path in glob(join(self.apphome, 'i18n',
   925         for path in glob(join(self.apphome, 'i18n',
   904                               '*', 'LC_MESSAGES')):
   926                               '*', 'LC_MESSAGES')):
   933             print 'warning: ignoring specified sources, requires a repository '\
   955             print 'warning: ignoring specified sources, requires a repository '\
   934                   'configuration'
   956                   'configuration'
   935 
   957 
   936     def migration_handler(self):
   958     def migration_handler(self):
   937         """return a migration handler instance"""
   959         """return a migration handler instance"""
   938         from cubicweb.common.migration import MigrationHelper
   960         from cubicweb.migration import MigrationHelper
   939         return MigrationHelper(self, verbosity=self.verbosity)
   961         return MigrationHelper(self, verbosity=self.verbosity)
   940 
   962 
   941     def i18ncompile(self, langs=None):
   963     def i18ncompile(self, langs=None):
   942         from cubicweb.common import i18n
   964         from cubicweb import i18n
   943         if langs is None:
   965         if langs is None:
   944             langs = self.available_languages()
   966             langs = self.available_languages()
   945         i18ndir = join(self.apphome, 'i18n')
   967         i18ndir = join(self.apphome, 'i18n')
   946         if not exists(i18ndir):
   968         if not exists(i18ndir):
   947             create_dir(i18ndir)
   969             create_dir(i18ndir)
   974 set_log_methods(CubicWebConfiguration, logging.getLogger('cubicweb.configuration'))
   996 set_log_methods(CubicWebConfiguration, logging.getLogger('cubicweb.configuration'))
   975 
   997 
   976 # alias to get a configuration instance from an instance id
   998 # alias to get a configuration instance from an instance id
   977 instance_configuration = CubicWebConfiguration.config_for
   999 instance_configuration = CubicWebConfiguration.config_for
   978 application_configuration = deprecated('use instance_configuration')(instance_configuration)
  1000 application_configuration = deprecated('use instance_configuration')(instance_configuration)
       
  1001 
       
  1002 
       
  1003 _EXT_REGISTERED = False
       
  1004 def register_stored_procedures():
       
  1005     from logilab.common.adbh import FunctionDescr
       
  1006     from rql.utils import register_function, iter_funcnode_variables
       
  1007 
       
  1008     global _EXT_REGISTERED
       
  1009     if _EXT_REGISTERED:
       
  1010         return
       
  1011     _EXT_REGISTERED = True
       
  1012 
       
  1013     class COMMA_JOIN(FunctionDescr):
       
  1014         supported_backends = ('postgres', 'sqlite',)
       
  1015         rtype = 'String'
       
  1016 
       
  1017         @classmethod
       
  1018         def st_description(cls, funcnode, mainindex, tr):
       
  1019             return ', '.join(sorted(term.get_description(mainindex, tr)
       
  1020                                     for term in iter_funcnode_variables(funcnode)))
       
  1021 
       
  1022     register_function(COMMA_JOIN)  # XXX do not expose?
       
  1023 
       
  1024 
       
  1025     class CONCAT_STRINGS(COMMA_JOIN):
       
  1026         aggregat = True
       
  1027 
       
  1028     register_function(CONCAT_STRINGS) # XXX bw compat
       
  1029 
       
  1030     class GROUP_CONCAT(CONCAT_STRINGS):
       
  1031         supported_backends = ('mysql', 'postgres', 'sqlite',)
       
  1032 
       
  1033     register_function(GROUP_CONCAT)
       
  1034 
       
  1035 
       
  1036     class LIMIT_SIZE(FunctionDescr):
       
  1037         supported_backends = ('postgres', 'sqlite',)
       
  1038         rtype = 'String'
       
  1039 
       
  1040         @classmethod
       
  1041         def st_description(cls, funcnode, mainindex, tr):
       
  1042             return funcnode.children[0].get_description(mainindex, tr)
       
  1043 
       
  1044     register_function(LIMIT_SIZE)
       
  1045 
       
  1046 
       
  1047     class TEXT_LIMIT_SIZE(LIMIT_SIZE):
       
  1048         supported_backends = ('mysql', 'postgres', 'sqlite',)
       
  1049 
       
  1050     register_function(TEXT_LIMIT_SIZE)
       
  1051 
       
  1052 
       
  1053 
       
  1054     class FSPATH(FunctionDescr):
       
  1055         supported_backends = ('postgres', 'sqlite',)
       
  1056         rtype = 'Bytes'
       
  1057 
       
  1058     register_function(FSPATH)