cwconfig.py
brancholdstable
changeset 7074 e4580e5f0703
parent 7031 a04621040cad
child 7083 b8e35cde46e9
equal deleted inserted replaced
6749:48f468f33704 7074:e4580e5f0703
    20 .. _ResourceMode:
    20 .. _ResourceMode:
    21 
    21 
    22 Resource mode
    22 Resource mode
    23 -------------
    23 -------------
    24 
    24 
    25 A resource *mode* is a predifined set of settings for various resources
    25 A resource *mode* is a predefined set of settings for various resources
    26 directories, such as cubes, instances, etc. to ease development with the
    26 directories, such as cubes, instances, etc. to ease development with the
    27 framework. There are two running modes with *CubicWeb*:
    27 framework. There are two running modes with *CubicWeb*:
    28 
    28 
    29 * 'user', resources are searched / created in the user home directory:
    29 * **system**: resources are searched / created in the system directories (eg
       
    30   usually requiring root access):
       
    31 
       
    32   - instances are stored in :file:`<INSTALL_PREFIX>/etc/cubicweb.d`
       
    33   - temporary files (such as pid file) in :file:`/var/run/cubicweb`
       
    34 
       
    35   where `<INSTALL_PREFIX>` is the detected installation prefix ('/usr/local' for
       
    36   instance).
       
    37 
       
    38 * **user**: resources are searched / created in the user home directory:
    30 
    39 
    31   - instances are stored in :file:`~/etc/cubicweb.d`
    40   - instances are stored in :file:`~/etc/cubicweb.d`
    32   - temporary files (such as pid file) in :file:`/tmp`
    41   - temporary files (such as pid file) in :file:`/tmp`
    33 
    42 
    34 * 'system', resources are searched / created in the system directories (eg
       
    35   usually requiring root access):
       
    36 
       
    37   - instances are stored in :file:`<INSTALL_PREFIX>/etc/cubicweb.d`
       
    38   - temporary files (such as pid file) in :file:`/var/run/cubicweb`
       
    39 
       
    40   where `<INSTALL_PREFIX>` is the detected installation prefix ('/usr/local' for
       
    41   instance).
       
    42 
    43 
    43 
    44 
    44 Notice that each resource path may be explicitly set using an environment
    45 Notice that each resource path may be explicitly set using an environment
    45 variable if the default doesn't suit your needs. Here are the default resource
    46 variable if the default doesn't suit your needs. Here are the default resource
    46 directories that are affected according to mode:
    47 directories that are affected according to mode:
    47 
    48 
    48 * 'system': ::
    49 * **system**: ::
    49 
    50 
    50         CW_INSTANCES_DIR = <INSTALL_PREFIX>/etc/cubicweb.d/
    51         CW_INSTANCES_DIR = <INSTALL_PREFIX>/etc/cubicweb.d/
    51         CW_INSTANCES_DATA_DIR = /var/lib/cubicweb/instances/
    52         CW_INSTANCES_DATA_DIR = /var/lib/cubicweb/instances/
    52         CW_RUNTIME_DIR = /var/run/cubicweb/
    53         CW_RUNTIME_DIR = /var/run/cubicweb/
    53 
    54 
    54 * 'user': ::
    55 * **user**: ::
    55 
    56 
    56         CW_INSTANCES_DIR = ~/etc/cubicweb.d/
    57         CW_INSTANCES_DIR = ~/etc/cubicweb.d/
    57         CW_INSTANCES_DATA_DIR = ~/etc/cubicweb.d/
    58         CW_INSTANCES_DATA_DIR = ~/etc/cubicweb.d/
    58         CW_RUNTIME_DIR = /tmp
    59         CW_RUNTIME_DIR = /tmp
    59 
    60 
    60 Cubes search path is also affected, see the :ref:Cube section.
    61 Cubes search path is also affected, see the :ref:`Cube` section.
    61 
    62 
    62 By default, the mode automatically set to 'user' if a :file:`.hg` directory is found
    63 By default, the mode automatically set to `user` if a :file:`.hg` directory is found
    63 in the cubicweb package, else it's set to 'system'. You can force this by setting
    64 in the cubicweb package, else it's set to `system`. You can force this by setting
    64 the :envvar:`CW_MODE` environment variable to either 'user' or 'system' so you can
    65 the :envvar:`CW_MODE` environment variable to either `user` or `system` so you can
    65 easily:
    66 easily:
    66 
    67 
    67 * use system wide installation but user specific instances and all, without root
    68 * use system wide installation but user specific instances and all, without root
    68   privileges on the system (`export CW_MODE=user`)
    69   privileges on the system (`export CW_MODE=user`)
    69 
    70 
   155 
   156 
   156 CONFIGURATIONS = []
   157 CONFIGURATIONS = []
   157 
   158 
   158 SMTP_LOCK = Lock()
   159 SMTP_LOCK = Lock()
   159 
   160 
   160 
       
   161 class metaconfiguration(type):
       
   162     """metaclass to automaticaly register configuration"""
       
   163     def __new__(mcs, name, bases, classdict):
       
   164         cls = super(metaconfiguration, mcs).__new__(mcs, name, bases, classdict)
       
   165         if classdict.get('name'):
       
   166             CONFIGURATIONS.append(cls)
       
   167         return cls
       
   168 
   161 
   169 def configuration_cls(name):
   162 def configuration_cls(name):
   170     """return the configuration class registered with the given name"""
   163     """return the configuration class registered with the given name"""
   171     try:
   164     try:
   172         return [c for c in CONFIGURATIONS if c.name == name][0]
   165         return [c for c in CONFIGURATIONS if c.name == name][0]
   287 _USR_INSTALL = _INSTALL_PREFIX == '/usr'
   280 _USR_INSTALL = _INSTALL_PREFIX == '/usr'
   288 
   281 
   289 class CubicWebNoAppConfiguration(ConfigurationMixIn):
   282 class CubicWebNoAppConfiguration(ConfigurationMixIn):
   290     """base class for cubicweb configuration without a specific instance directory
   283     """base class for cubicweb configuration without a specific instance directory
   291     """
   284     """
   292     __metaclass__ = metaconfiguration
       
   293     # to set in concrete configuration
   285     # to set in concrete configuration
   294     name = None
   286     name = None
   295     # log messages format (see logging module documentation for available keys)
   287     # log messages format (see logging module documentation for available keys)
   296     log_format = '%(asctime)s - (%(name)s) %(levelname)s: %(message)s'
   288     log_format = '%(asctime)s - (%(name)s) %(levelname)s: %(message)s'
   297     # the format below can be useful to debug multi thread issues:
   289     # the format below can be useful to debug multi thread issues:
   313        ('log-threshold',
   305        ('log-threshold',
   314          {'type' : 'string', # XXX use a dedicated type?
   306          {'type' : 'string', # XXX use a dedicated type?
   315           'default': 'WARNING',
   307           'default': 'WARNING',
   316           'help': 'server\'s log level',
   308           'help': 'server\'s log level',
   317           'group': 'main', 'level': 1,
   309           'group': 'main', 'level': 1,
       
   310           }),
       
   311         ('umask',
       
   312          {'type' : 'int',
       
   313           'default': 077,
       
   314           'help': 'permission umask for files created by the server',
       
   315           'group': 'main', 'level': 2,
   318           }),
   316           }),
   319         # pyro options
   317         # pyro options
   320         ('pyro-instance-id',
   318         ('pyro-instance-id',
   321          {'type' : 'string',
   319          {'type' : 'string',
   322           'default': Method('default_instance_id'),
   320           'default': Method('default_instance_id'),
   441                 extrapath[cubesdir] = 'cubes'
   439                 extrapath[cubesdir] = 'cubes'
   442         return extrapath
   440         return extrapath
   443 
   441 
   444     @classmethod
   442     @classmethod
   445     def cube_dir(cls, cube):
   443     def cube_dir(cls, cube):
   446         """return the cube directory for the given cube id,
   444         """return the cube directory for the given cube id, raise
   447         raise `ConfigurationError` if it doesn't exists
   445         `ConfigurationError` if it doesn't exist
   448         """
   446         """
   449         for directory in cls.cubes_search_path():
   447         for directory in cls.cubes_search_path():
   450             cubedir = join(directory, cube)
   448             cubedir = join(directory, cube)
   451             if exists(cubedir):
   449             if exists(cubedir):
   452                 return cubedir
   450                 return cubedir
   453         raise ConfigurationError('no cube %s in %s' % (cube, cls.cubes_search_path()))
   451         raise ConfigurationError('no cube %r in %s' % (
       
   452             cube, cls.cubes_search_path()))
   454 
   453 
   455     @classmethod
   454     @classmethod
   456     def cube_migration_scripts_dir(cls, cube):
   455     def cube_migration_scripts_dir(cls, cube):
   457         """cube migration scripts directory"""
   456         """cube migration scripts directory"""
   458         return join(cls.cube_dir(cube), 'migration')
   457         return join(cls.cube_dir(cube), 'migration')
   586             cubes.__path__ = cls.cubes_search_path()
   585             cubes.__path__ = cls.cubes_search_path()
   587         except ImportError:
   586         except ImportError:
   588             return # cubes dir doesn't exists
   587             return # cubes dir doesn't exists
   589 
   588 
   590     @classmethod
   589     @classmethod
       
   590     def load_available_configs(cls):
       
   591         from logilab.common.modutils import load_module_from_file
       
   592         for conffile in ('web/webconfig.py',  'etwist/twconfig.py',
       
   593                         'server/serverconfig.py',):
       
   594             if exists(join(CW_SOFTWARE_ROOT, conffile)):
       
   595                 load_module_from_file(join(CW_SOFTWARE_ROOT, conffile))
       
   596 
       
   597     @classmethod
   591     def load_cwctl_plugins(cls):
   598     def load_cwctl_plugins(cls):
   592         from logilab.common.modutils import load_module_from_file
   599         from logilab.common.modutils import load_module_from_file
   593         cls.cls_adjust_sys_path()
   600         cls.cls_adjust_sys_path()
   594         for ctlfile in ('web/webctl.py',  'etwist/twctl.py',
   601         for ctlfile in ('web/webctl.py',  'etwist/twctl.py',
   595                         'server/serverctl.py',
   602                         'server/serverctl.py',
   596                         'devtools/devctl.py', 'goa/goactl.py'):
   603                         'devtools/devctl.py', 'goa/goactl.py'):
   597             if exists(join(CW_SOFTWARE_ROOT, ctlfile)):
   604             if exists(join(CW_SOFTWARE_ROOT, ctlfile)):
   598                 try:
   605                 try:
   599                     load_module_from_file(join(CW_SOFTWARE_ROOT, ctlfile))
   606                     load_module_from_file(join(CW_SOFTWARE_ROOT, ctlfile))
   600                 except ImportError, err:
   607                 except ImportError, err:
   601                     cls.info('could not import the command provider %s (cause : %s)' %
   608                     cls.error('could not import the command provider %s: %s',
   602                                 (ctlfile, err))
   609                               ctlfile, err)
   603                 cls.info('loaded cubicweb-ctl plugin %s', ctlfile)
   610                 cls.info('loaded cubicweb-ctl plugin %s', ctlfile)
   604         for cube in cls.available_cubes():
   611         for cube in cls.available_cubes():
   605             oldpluginfile = join(cls.cube_dir(cube), 'ecplugin.py')
   612             oldpluginfile = join(cls.cube_dir(cube), 'ecplugin.py')
   606             pluginfile = join(cls.cube_dir(cube), 'ccplugin.py')
   613             pluginfile = join(cls.cube_dir(cube), 'ccplugin.py')
   607             initfile = join(cls.cube_dir(cube), '__init__.py')
   614             initfile = join(cls.cube_dir(cube), '__init__.py')
   686                     vregpath.append(path + '.py')
   693                     vregpath.append(path + '.py')
   687         return vregpath
   694         return vregpath
   688 
   695 
   689     def __init__(self, debugmode=False):
   696     def __init__(self, debugmode=False):
   690         register_stored_procedures()
   697         register_stored_procedures()
       
   698         self._cubes = None
   691         super(CubicWebNoAppConfiguration, self).__init__()
   699         super(CubicWebNoAppConfiguration, self).__init__()
   692         self.debugmode = debugmode
   700         self.debugmode = debugmode
   693         self.adjust_sys_path()
   701         self.adjust_sys_path()
   694         self.load_defaults()
   702         self.load_defaults()
   695         # will be properly initialized later by _gettext_init
   703         # will be properly initialized later by _gettext_init
   761         from logilab.common.modutils import load_module_from_modpath, modpath_from_file
   769         from logilab.common.modutils import load_module_from_modpath, modpath_from_file
   762         module = load_module_from_modpath(modpath_from_file(sitefile, self.extrapath))
   770         module = load_module_from_modpath(modpath_from_file(sitefile, self.extrapath))
   763         self.debug('%s loaded', sitefile)
   771         self.debug('%s loaded', sitefile)
   764         return module
   772         return module
   765 
   773 
   766     def eproperty_definitions(self):
   774     def cwproperty_definitions(self):
   767         cfg = self.persistent_options_configuration()
   775         cfg = self.persistent_options_configuration()
   768         for section, options in cfg.options_by_section():
   776         for section, options in cfg.options_by_section():
   769             section = section.lower()
   777             section = section.lower()
   770             for optname, optdict, value in options:
   778             for optname, optdict, value in options:
   771                 key = '%s.%s' % (section, optname)
   779                 key = '%s.%s' % (section, optname)
   789         """return the instance identifier, useful for option which need this
   797         """return the instance identifier, useful for option which need this
   790         as default value
   798         as default value
   791         """
   799         """
   792         return None
   800         return None
   793 
   801 
       
   802     _cubes = None
       
   803 
       
   804     def init_cubes(self, cubes):
       
   805         assert self._cubes is None, self._cubes
       
   806         self._cubes = self.reorder_cubes(cubes)
       
   807         # load cubes'__init__.py file first
       
   808         for cube in cubes:
       
   809             __import__('cubes.%s' % cube)
       
   810         self.load_site_cubicweb()
       
   811 
       
   812     def cubes(self):
       
   813         """return the list of cubes used by this instance
       
   814 
       
   815         result is ordered from the top level cubes to inner dependencies
       
   816         cubes
       
   817         """
       
   818         assert self._cubes is not None, 'cubes not initialized'
       
   819         return self._cubes
       
   820 
       
   821     def cubes_path(self):
       
   822         """return the list of path to cubes used by this instance, from outer
       
   823         most to inner most cubes
       
   824         """
       
   825         return [self.cube_dir(p) for p in self.cubes()]
       
   826 
   794 
   827 
   795 class CubicWebConfiguration(CubicWebNoAppConfiguration):
   828 class CubicWebConfiguration(CubicWebNoAppConfiguration):
   796     """base class for cubicweb server and web configurations"""
   829     """base class for cubicweb server and web configurations"""
   797 
   830 
   798     if CubicWebNoAppConfiguration.mode == 'user':
   831     if CubicWebNoAppConfiguration.mode == 'user':
   868 
   901 
   869     @classmethod
   902     @classmethod
   870     def config_for(cls, appid, config=None, debugmode=False):
   903     def config_for(cls, appid, config=None, debugmode=False):
   871         """return a configuration instance for the given instance identifier
   904         """return a configuration instance for the given instance identifier
   872         """
   905         """
       
   906         cls.load_available_configs()
   873         config = config or guess_configuration(cls.instance_home(appid))
   907         config = config or guess_configuration(cls.instance_home(appid))
   874         configcls = configuration_cls(config)
   908         configcls = configuration_cls(config)
   875         return configcls(appid, debugmode)
   909         return configcls(appid, debugmode)
   876 
   910 
   877     @classmethod
   911     @classmethod
   982             iddir = self.instances_dir()
  1016             iddir = self.instances_dir()
   983         iddir = abspath(os.environ.get('CW_INSTANCES_DATA_DIR', iddir))
  1017         iddir = abspath(os.environ.get('CW_INSTANCES_DATA_DIR', iddir))
   984         return join(iddir, self.appid)
  1018         return join(iddir, self.appid)
   985 
  1019 
   986     def init_cubes(self, cubes):
  1020     def init_cubes(self, cubes):
   987         assert self._cubes is None, self._cubes
  1021         super(CubicWebConfiguration, self).init_cubes(cubes)
   988         self._cubes = self.reorder_cubes(cubes)
       
   989         # load cubes'__init__.py file first
       
   990         for cube in cubes:
       
   991             __import__('cubes.%s' % cube)
       
   992         self.load_site_cubicweb()
       
   993         # reload config file in cases options are defined in cubes __init__
  1022         # reload config file in cases options are defined in cubes __init__
   994         # or site_cubicweb files
  1023         # or site_cubicweb files
   995         self.load_file_configuration(self.main_config_file())
  1024         self.load_file_configuration(self.main_config_file())
   996         # configuration initialization hook
  1025         # configuration initialization hook
   997         self.load_configuration()
  1026         self.load_configuration()
   998 
       
   999     def cubes(self):
       
  1000         """return the list of cubes used by this instance
       
  1001 
       
  1002         result is ordered from the top level cubes to inner dependencies
       
  1003         cubes
       
  1004         """
       
  1005         assert self._cubes is not None
       
  1006         return self._cubes
       
  1007 
       
  1008     def cubes_path(self):
       
  1009         """return the list of path to cubes used by this instance, from outer
       
  1010         most to inner most cubes
       
  1011         """
       
  1012         return [self.cube_dir(p) for p in self.cubes()]
       
  1013 
  1027 
  1014     def add_cubes(self, cubes):
  1028     def add_cubes(self, cubes):
  1015         """add given cubes to the list of used cubes"""
  1029         """add given cubes to the list of used cubes"""
  1016         if not isinstance(cubes, list):
  1030         if not isinstance(cubes, list):
  1017             cubes = list(cubes)
  1031             cubes = list(cubes)
  1263         def update_cb_stack(self, stack):
  1277         def update_cb_stack(self, stack):
  1264             assert len(stack) == 1
  1278             assert len(stack) == 1
  1265             stack[0] = self.source_execute
  1279             stack[0] = self.source_execute
  1266 
  1280 
  1267         def as_sql(self, backend, args):
  1281         def as_sql(self, backend, args):
  1268             raise NotImplementedError('source only callback')
  1282             raise NotImplementedError(
       
  1283                 'This callback is only available for BytesFileSystemStorage '
       
  1284                 'managed attribute. Is FSPATH() argument BFSS managed?')
  1269 
  1285 
  1270         def source_execute(self, source, session, value):
  1286         def source_execute(self, source, session, value):
  1271             fpath = source.binary_to_str(value)
  1287             fpath = source.binary_to_str(value)
  1272             try:
  1288             try:
  1273                 return Binary(fpath)
  1289                 return Binary(fpath)