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) |