cubicweb/cwconfig.py
changeset 12549 e2db422752b4
parent 12544 56e1132f19c3
child 12567 26744ad37953
equal deleted inserted replaced
12548:6eec3213bec9 12549:e2db422752b4
   106 If :file:`.hg` directory is found into the cubicweb package, there are
   106 If :file:`.hg` directory is found into the cubicweb package, there are
   107 specific resource rules.
   107 specific resource rules.
   108 
   108 
   109 `<CW_SOFTWARE_ROOT>` is the source checkout's ``cubicweb`` directory:
   109 `<CW_SOFTWARE_ROOT>` is the source checkout's ``cubicweb`` directory:
   110 
   110 
   111 * main cubes directory is `<CW_SOFTWARE_ROOT>/../../cubes`. You can specify
       
   112   another one with :envvar:`CW_INSTANCES_DIR` environment variable or simply
       
   113   add some other directories by using :envvar:`CW_CUBES_PATH`
       
   114 
       
   115 * cubicweb migration files are searched in `<CW_SOFTWARE_ROOT>/misc/migration`
   111 * cubicweb migration files are searched in `<CW_SOFTWARE_ROOT>/misc/migration`
   116   instead of `<INSTALL_PREFIX>/share/cubicweb/migration/`.
   112   instead of `<INSTALL_PREFIX>/share/cubicweb/migration/`.
   117 
   113 
   118 
   114 
   119 Development Mode (virtualenv)
   115 Development Mode (virtualenv)
   155 
   151 
   156 .. envvar:: CW_MODE
   152 .. envvar:: CW_MODE
   157 
   153 
   158    Resource mode: user or system, as explained in :ref:`ResourceMode`.
   154    Resource mode: user or system, as explained in :ref:`ResourceMode`.
   159 
   155 
   160 .. envvar:: CW_CUBES_PATH
       
   161 
       
   162    Augments the default search path for cubes. You may specify several
       
   163    directories using ':' as separator (';' under windows environment).
       
   164 
       
   165 .. envvar:: CW_INSTANCES_DIR
   156 .. envvar:: CW_INSTANCES_DIR
   166 
   157 
   167    Directory where cubicweb instances will be found.
   158    Directory where cubicweb instances will be found.
   168 
   159 
   169 .. envvar:: CW_INSTANCES_DATA_DIR
   160 .. envvar:: CW_INSTANCES_DATA_DIR
   179 
   170 
   180 import importlib
   171 import importlib
   181 import logging
   172 import logging
   182 import logging.config
   173 import logging.config
   183 import os
   174 import os
   184 from os.path import (exists, join, expanduser, abspath, normpath,
   175 from os.path import (exists, join, expanduser, abspath,
   185                      basename, isdir, dirname, splitext, realpath)
   176                      basename, dirname, splitext, realpath)
   186 import pkgutil
   177 import pkgutil
   187 import pkg_resources
   178 import pkg_resources
   188 import re
       
   189 from smtplib import SMTP
   179 from smtplib import SMTP
   190 import stat
   180 import stat
   191 import sys
   181 import sys
   192 from threading import Lock
   182 from threading import Lock
   193 from warnings import filterwarnings
   183 from warnings import filterwarnings
   194 
   184 
   195 from six import text_type
   185 from six import text_type
   196 
   186 
   197 from logilab.common.decorators import cached, classproperty
   187 from logilab.common.decorators import cached
   198 from logilab.common.logging_ext import set_log_methods, init_log
   188 from logilab.common.logging_ext import set_log_methods, init_log
   199 from logilab.common.configuration import (Configuration, Method,
   189 from logilab.common.configuration import (Configuration, Method,
   200                                           ConfigurationMixIn, merge_options,
   190                                           ConfigurationMixIn, merge_options,
   201                                           _validate as lgc_validate)
   191                                           _validate as lgc_validate)
   202 
   192 
   370         mode = os.environ.get('CW_MODE', 'user')
   360         mode = os.environ.get('CW_MODE', 'user')
   371     else:
   361     else:
   372         mode = os.environ.get('CW_MODE', 'system')
   362         mode = os.environ.get('CW_MODE', 'system')
   373     assert mode in ('system', 'user'), '"CW_MODE" should be either "user" or "system"'
   363     assert mode in ('system', 'user'), '"CW_MODE" should be either "user" or "system"'
   374 
   364 
   375     _CUBES_DIR = join(_INSTALL_PREFIX, 'share', 'cubicweb', 'cubes')
       
   376     assert _CUBES_DIR  # XXX only meaningful if CW_CUBES_DIR is not set
       
   377     CUBES_DIR = realpath(abspath(os.environ.get('CW_CUBES_DIR', _CUBES_DIR)))
       
   378     CUBES_PATH = os.environ.get('CW_CUBES_PATH', '').split(os.pathsep)
       
   379 
       
   380     options = (
   365     options = (
   381        ('log-threshold',
   366        ('log-threshold',
   382          {'type' : 'string', # XXX use a dedicated type?
   367          {'type' : 'string', # XXX use a dedicated type?
   383           'default': 'WARNING',
   368           'default': 'WARNING',
   384           'help': 'server\'s log level',
   369           'help': 'server\'s log level',
   467                 if not modname.startswith('cubicweb_'):
   452                 if not modname.startswith('cubicweb_'):
   468                     cls.warning('entry point %s does not appear to be a cube',
   453                     cls.warning('entry point %s does not appear to be a cube',
   469                                 entry_point)
   454                                 entry_point)
   470                     continue
   455                     continue
   471                 cubes.add(modname)
   456                 cubes.add(modname)
   472         # Legacy cubes.
       
   473         for directory in cls.cubes_search_path():
       
   474             if not exists(directory):
       
   475                 cls.error('unexistant directory in cubes search path: %s'
       
   476                           % directory)
       
   477                 continue
       
   478             for cube in os.listdir(directory):
       
   479                 if cube == 'shared':
       
   480                     continue
       
   481                 if not re.match('[_A-Za-z][_A-Za-z0-9]*$', cube):
       
   482                     continue # skip invalid python package name
       
   483                 if cube == 'pyramid':
       
   484                     cls._warn_pyramid_cube()
       
   485                     continue
       
   486                 cubedir = join(directory, cube)
       
   487                 if isdir(cubedir) and exists(join(cubedir, '__init__.py')):
       
   488                     cubes.add(cube)
       
   489 
   457 
   490         def sortkey(cube):
   458         def sortkey(cube):
   491             """Preserve sorting with "cubicweb_" prefix."""
   459             """Preserve sorting with "cubicweb_" prefix."""
   492             prefix = 'cubicweb_'
   460             prefix = 'cubicweb_'
   493             if cube.startswith(prefix):
   461             if cube.startswith(prefix):
   498             return cube
   466             return cube
   499 
   467 
   500         return sorted(cubes, key=sortkey)
   468         return sorted(cubes, key=sortkey)
   501 
   469 
   502     @classmethod
   470     @classmethod
   503     def cubes_search_path(cls):
       
   504         """return the path of directories where cubes should be searched"""
       
   505         path = [realpath(abspath(normpath(directory))) for directory in cls.CUBES_PATH
       
   506                 if directory.strip() and exists(directory.strip())]
       
   507         if not cls.CUBES_DIR in path and exists(cls.CUBES_DIR):
       
   508             path.append(cls.CUBES_DIR)
       
   509         return path
       
   510 
       
   511     @classproperty
       
   512     def extrapath(cls):
       
   513         extrapath = {}
       
   514         for cubesdir in cls.cubes_search_path():
       
   515             if cubesdir != cls.CUBES_DIR:
       
   516                 extrapath[cubesdir] = 'cubes'
       
   517         return extrapath
       
   518 
       
   519     @classmethod
       
   520     def cube_dir(cls, cube):
   471     def cube_dir(cls, cube):
   521         """return the cube directory for the given cube id, raise
   472         """return the cube directory for the given cube id, raise
   522         `ConfigurationError` if it doesn't exist
   473         `ConfigurationError` if it doesn't exist
   523         """
   474         """
   524         pkgname = _cube_pkgname(cube)
   475         pkgname = _cube_pkgname(cube)
   525         loader = pkgutil.find_loader(pkgname)
   476         loader = pkgutil.find_loader(pkgname)
   526         if loader:
   477         if loader:
   527             return dirname(loader.get_filename())
   478             return dirname(loader.get_filename())
   528         # Legacy cubes.
       
   529         for directory in cls.cubes_search_path():
       
   530             cubedir = join(directory, cube)
       
   531             if exists(cubedir):
       
   532                 return cubedir
       
   533         msg = 'no module %(pkg)s in search path nor cube %(cube)r in %(path)s'
   479         msg = 'no module %(pkg)s in search path nor cube %(cube)r in %(path)s'
   534         raise ConfigurationError(msg % {'cube': cube,
   480         raise ConfigurationError(msg % {'cube': cube,
   535                                         'pkg': _cube_pkgname(cube),
   481                                         'pkg': _cube_pkgname(cube)})
   536                                         'path': cls.cubes_search_path()})
       
   537 
   482 
   538     @classmethod
   483     @classmethod
   539     def cube_migration_scripts_dir(cls, cube):
   484     def cube_migration_scripts_dir(cls, cube):
   540         """cube migration scripts directory"""
   485         """cube migration scripts directory"""
   541         return join(cls.cube_dir(cube), 'migration')
   486         return join(cls.cube_dir(cube), 'migration')
   542 
   487 
   543     @classmethod
   488     @classmethod
   544     def cube_pkginfo(cls, cube):
   489     def cube_pkginfo(cls, cube):
   545         """return the information module for the given cube"""
   490         """return the information module for the given cube"""
       
   491         cube = CW_MIGRATION_MAP.get(cube, cube)
   546         pkgname = _cube_pkgname(cube)
   492         pkgname = _cube_pkgname(cube)
   547         try:
   493         return importlib.import_module('%s.__pkginfo__' % pkgname)
   548             return importlib.import_module('%s.__pkginfo__' % pkgname)
       
   549         except ImportError:
       
   550             cube = CW_MIGRATION_MAP.get(cube, cube)
       
   551             try:
       
   552                 parent = __import__('cubes.%s.__pkginfo__' % cube)
       
   553                 return getattr(parent, cube).__pkginfo__
       
   554             except Exception as ex:
       
   555                 raise ConfigurationError(
       
   556                     'unable to find packaging information for cube %s (%s: %s)'
       
   557                     % (cube, ex.__class__.__name__, ex))
       
   558 
   494 
   559     @classmethod
   495     @classmethod
   560     def cube_version(cls, cube):
   496     def cube_version(cls, cube):
   561         """return the version of the cube located in the given directory
   497         """return the version of the cube located in the given directory
   562         """
   498         """
   650             return ordered_nodes(graph)
   586             return ordered_nodes(graph)
   651         except UnorderableGraph as ex:
   587         except UnorderableGraph as ex:
   652             raise ConfigurationError(ex)
   588             raise ConfigurationError(ex)
   653 
   589 
   654     @classmethod
   590     @classmethod
   655     def cls_adjust_sys_path(cls):
       
   656         """update python path if necessary"""
       
   657         import cubes
       
   658         cubes.__path__ = cls.cubes_search_path()
       
   659 
       
   660     @classmethod
       
   661     def load_available_configs(cls):
   591     def load_available_configs(cls):
   662         for confmod in ('web.webconfig',
   592         for confmod in ('web.webconfig',
   663                         'server.serverconfig', 'pyramid.config'):
   593                         'server.serverconfig', 'pyramid.config'):
   664             try:
   594             try:
   665                 __import__('cubicweb.%s' % confmod)
   595                 __import__('cubicweb.%s' % confmod)
   667                 cls.warning('failed to load config module %s (%s)',
   597                 cls.warning('failed to load config module %s (%s)',
   668                             confmod, exc)
   598                             confmod, exc)
   669 
   599 
   670     @classmethod
   600     @classmethod
   671     def load_cwctl_plugins(cls):
   601     def load_cwctl_plugins(cls):
   672         cls.cls_adjust_sys_path()
       
   673         for ctlmod in ('web.webctl', 'server.serverctl',
   602         for ctlmod in ('web.webctl', 'server.serverctl',
   674                        'devtools.devctl', 'pyramid.pyramidctl'):
   603                        'devtools.devctl', 'pyramid.pyramidctl'):
   675             try:
   604             try:
   676                 __import__('cubicweb.%s' % ctlmod)
   605                 __import__('cubicweb.%s' % ctlmod)
   677             except ImportError as exc:
   606             except ImportError as exc:
   681             cls.info('loaded cubicweb-ctl plugin %s', ctlmod)
   610             cls.info('loaded cubicweb-ctl plugin %s', ctlmod)
   682         for cube in cls.available_cubes():
   611         for cube in cls.available_cubes():
   683             cubedir = cls.cube_dir(cube)
   612             cubedir = cls.cube_dir(cube)
   684             pluginfile = join(cubedir, 'ccplugin.py')
   613             pluginfile = join(cubedir, 'ccplugin.py')
   685             initfile = join(cubedir, '__init__.py')
   614             initfile = join(cubedir, '__init__.py')
   686             if cube.startswith('cubicweb_'):
   615             pkgname = _cube_pkgname(cube)
   687                 pkgname = cube
       
   688             else:
       
   689                 pkgname = 'cubes.%s' % cube
       
   690             if exists(pluginfile):
   616             if exists(pluginfile):
   691                 try:
   617                 try:
   692                     __import__(pkgname + '.ccplugin')
   618                     __import__(pkgname + '.ccplugin')
   693                     cls.info('loaded cubicweb-ctl plugin from %s', cube)
   619                     cls.info('loaded cubicweb-ctl plugin from %s', cube)
   694                 except Exception:
   620                 except Exception:
   727         else:
   653         else:
   728             cw_rest_init()
   654             cw_rest_init()
   729 
   655 
   730     def adjust_sys_path(self):
   656     def adjust_sys_path(self):
   731         # overriden in CubicWebConfiguration
   657         # overriden in CubicWebConfiguration
   732         self.cls_adjust_sys_path()
   658         pass
   733 
   659 
   734     def init_log(self, logthreshold=None, logfile=None, syslog=False):
   660     def init_log(self, logthreshold=None, logfile=None, syslog=False):
   735         """init the log service"""
   661         """init the log service"""
   736         if logthreshold is None:
   662         if logthreshold is None:
   737             if self.debugmode:
   663             if self.debugmode:
   791             self._load_site_cubicweb(None)
   717             self._load_site_cubicweb(None)
   792 
   718 
   793     def _load_site_cubicweb(self, cube):
   719     def _load_site_cubicweb(self, cube):
   794         """Load site_cubicweb.py from `cube` (or apphome if cube is None)."""
   720         """Load site_cubicweb.py from `cube` (or apphome if cube is None)."""
   795         if cube is not None:
   721         if cube is not None:
   796             try:
   722             modname = _cube_pkgname(cube)
   797                 modname = 'cubicweb_%s' % cube
   723             __import__(modname)
   798                 __import__(modname)
       
   799             except ImportError:
       
   800                 modname = 'cubes.%s' % cube
       
   801                 __import__(modname)
       
   802             modname = modname + '.site_cubicweb'
   724             modname = modname + '.site_cubicweb'
   803             __import__(modname)
   725             __import__(modname)
   804             return sys.modules[modname]
   726             return sys.modules[modname]
   805         else:
   727         else:
   806             import imp
   728             import imp
   850             self._warn_pyramid_cube()
   772             self._warn_pyramid_cube()
   851             cubes.remove('pyramid')
   773             cubes.remove('pyramid')
   852         self._cubes = self.reorder_cubes(cubes)
   774         self._cubes = self.reorder_cubes(cubes)
   853         # load cubes'__init__.py file first
   775         # load cubes'__init__.py file first
   854         for cube in cubes:
   776         for cube in cubes:
   855             try:
   777             importlib.import_module(_cube_pkgname(cube))
   856                 importlib.import_module(_cube_pkgname(cube))
       
   857             except ImportError:
       
   858                 # Legacy cube.
       
   859                 __import__('cubes.%s' % cube)
       
   860         self.load_site_cubicweb()
   778         self.load_site_cubicweb()
   861 
   779 
   862     def cubes(self):
   780     def cubes(self):
   863         """return the list of cubes used by this instance
   781         """return the list of cubes used by this instance
   864 
   782