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