16 from logilab.common.logging_ext import set_log_methods, init_log |
21 from logilab.common.logging_ext import set_log_methods, init_log |
17 from logilab.common.configuration import (Configuration, Method, |
22 from logilab.common.configuration import (Configuration, Method, |
18 ConfigurationMixIn, merge_options) |
23 ConfigurationMixIn, merge_options) |
19 |
24 |
20 from cubicweb import CW_SOFTWARE_ROOT, CW_MIGRATION_MAP, ConfigurationError |
25 from cubicweb import CW_SOFTWARE_ROOT, CW_MIGRATION_MAP, ConfigurationError |
21 from cubicweb.toolsutils import env_path, read_config, create_dir |
26 from cubicweb.toolsutils import env_path, create_dir |
22 |
27 |
23 CONFIGURATIONS = [] |
28 CONFIGURATIONS = [] |
24 |
29 |
25 _ = unicode |
30 _ = unicode |
26 |
31 |
54 if len(modes) != 1: |
59 if len(modes) != 1: |
55 raise ConfigurationError('unable to guess configuration from %r %s' |
60 raise ConfigurationError('unable to guess configuration from %r %s' |
56 % (directory, modes)) |
61 % (directory, modes)) |
57 return modes[0] |
62 return modes[0] |
58 |
63 |
59 # XXX generate this according to the configuration (repository/all-in-one/web) |
|
60 VREGOPTIONS = [] |
|
61 for registry in ('etypes', 'hooks', 'controllers', 'actions', 'components', |
|
62 'views', 'templates', 'boxes', 'contentnavigation', 'urlrewriting', |
|
63 'facets'): |
|
64 VREGOPTIONS.append(('disable-%s'%registry, |
|
65 {'type' : 'csv', 'default': (), |
|
66 'help': 'list of identifier of application objects from the %s registry to disable'%registry, |
|
67 'group': 'appobjects', 'inputlevel': 2, |
|
68 })) |
|
69 VREGOPTIONS = tuple(VREGOPTIONS) |
|
70 |
64 |
71 # persistent options definition |
65 # persistent options definition |
72 PERSISTENT_OPTIONS = ( |
66 PERSISTENT_OPTIONS = ( |
73 ('encoding', |
67 ('encoding', |
74 {'type' : 'string', |
68 {'type' : 'string', |
75 'default': 'UTF-8', |
69 'default': 'UTF-8', |
76 'help': _('user interface encoding'), |
70 'help': _('user interface encoding'), |
77 'group': 'ui', 'sitewide': True, |
71 'group': 'ui', 'sitewide': True, |
78 }), |
72 }), |
79 ('language', |
73 ('language', |
80 {'type' : 'string', |
74 {'type' : 'string', |
81 'default': 'en', |
75 'default': 'en', |
82 'vocabulary': Method('available_languages'), |
76 'vocabulary': Method('available_languages'), |
83 'help': _('language of the user interface'), |
77 'help': _('language of the user interface'), |
84 'group': 'ui', |
78 'group': 'ui', |
85 }), |
79 }), |
86 ('date-format', |
80 ('date-format', |
87 {'type' : 'string', |
81 {'type' : 'string', |
88 'default': '%Y/%m/%d', |
82 'default': '%Y/%m/%d', |
89 'help': _('how to format date in the ui ("man strftime" for format description)'), |
83 'help': _('how to format date in the ui ("man strftime" for format description)'), |
90 'group': 'ui', |
84 'group': 'ui', |
91 }), |
85 }), |
92 ('datetime-format', |
86 ('datetime-format', |
93 {'type' : 'string', |
87 {'type' : 'string', |
94 'default': '%Y/%m/%d %H:%M', |
88 'default': '%Y/%m/%d %H:%M', |
95 'help': _('how to format date and time in the ui ("man strftime" for format description)'), |
89 'help': _('how to format date and time in the ui ("man strftime" for format description)'), |
96 'group': 'ui', |
90 'group': 'ui', |
97 }), |
91 }), |
98 ('time-format', |
92 ('time-format', |
99 {'type' : 'string', |
93 {'type' : 'string', |
100 'default': '%H:%M', |
94 'default': '%H:%M', |
101 'help': _('how to format time in the ui ("man strftime" for format description)'), |
95 'help': _('how to format time in the ui ("man strftime" for format description)'), |
102 'group': 'ui', |
96 'group': 'ui', |
103 }), |
97 }), |
104 ('float-format', |
98 ('float-format', |
105 {'type' : 'string', |
99 {'type' : 'string', |
106 'default': '%.3f', |
100 'default': '%.3f', |
107 'help': _('how to format float numbers in the ui'), |
101 'help': _('how to format float numbers in the ui'), |
108 'group': 'ui', |
102 'group': 'ui', |
109 }), |
103 }), |
110 ('default-text-format', |
104 ('default-text-format', |
111 {'type' : 'choice', |
105 {'type' : 'choice', |
112 'choices': ('text/plain', 'text/rest', 'text/html'), |
106 'choices': ('text/plain', 'text/rest', 'text/html'), |
113 'default': 'text/html', # use fckeditor in the web ui |
107 'default': 'text/html', # use fckeditor in the web ui |
114 'help': _('default text format for rich text fields.'), |
108 'help': _('default text format for rich text fields.'), |
115 'group': 'ui', |
109 'group': 'ui', |
116 }), |
110 }), |
117 ('short-line-size', |
111 ('short-line-size', |
118 {'type' : 'int', |
112 {'type' : 'int', |
119 'default': 40, |
113 'default': 40, |
120 'help': _('maximum number of characters in short description'), |
114 'help': _('maximum number of characters in short description'), |
123 ) |
117 ) |
124 |
118 |
125 def register_persistent_options(options): |
119 def register_persistent_options(options): |
126 global PERSISTENT_OPTIONS |
120 global PERSISTENT_OPTIONS |
127 PERSISTENT_OPTIONS = merge_options(PERSISTENT_OPTIONS + options) |
121 PERSISTENT_OPTIONS = merge_options(PERSISTENT_OPTIONS + options) |
128 |
122 |
129 CFGTYPE2ETYPE_MAP = { |
123 CFGTYPE2ETYPE_MAP = { |
130 'string': 'String', |
124 'string': 'String', |
131 'choice': 'String', |
125 'choice': 'String', |
132 'yn': 'Boolean', |
126 'yn': 'Boolean', |
133 'int': 'Int', |
127 'int': 'Int', |
134 'float' : 'Float', |
128 'float' : 'Float', |
135 } |
129 } |
136 |
130 |
137 class CubicWebNoAppConfiguration(ConfigurationMixIn): |
131 class CubicWebNoAppConfiguration(ConfigurationMixIn): |
138 """base class for cubicweb configuration without a specific instance directory |
132 """base class for cubicweb configuration without a specific instance directory |
139 """ |
133 """ |
140 __metaclass__ = metaconfiguration |
134 __metaclass__ = metaconfiguration |
141 # to set in concrete configuration |
135 # to set in concrete configuration |
155 CUBES_DIR = abspath(normpath(join(CW_SOFTWARE_ROOT, '../cubes'))) |
149 CUBES_DIR = abspath(normpath(join(CW_SOFTWARE_ROOT, '../cubes'))) |
156 else: |
150 else: |
157 mode = 'installed' |
151 mode = 'installed' |
158 CUBES_DIR = '/usr/share/cubicweb/cubes/' |
152 CUBES_DIR = '/usr/share/cubicweb/cubes/' |
159 |
153 |
160 options = VREGOPTIONS + ( |
154 options = ( |
161 ('log-threshold', |
155 ('log-threshold', |
162 {'type' : 'string', # XXX use a dedicated type? |
156 {'type' : 'string', # XXX use a dedicated type? |
163 'default': 'ERROR', |
157 'default': 'ERROR', |
164 'help': 'server\'s log level', |
158 'help': 'server\'s log level', |
165 'group': 'main', 'inputlevel': 1, |
159 'group': 'main', 'inputlevel': 1, |
193 {'type' : 'string', |
187 {'type' : 'string', |
194 'default': None, |
188 'default': None, |
195 'help': 'web server root url', |
189 'help': 'web server root url', |
196 'group': 'main', 'inputlevel': 1, |
190 'group': 'main', 'inputlevel': 1, |
197 }), |
191 }), |
|
192 ('use-request-subdomain', |
|
193 {'type' : 'yn', |
|
194 'default': None, |
|
195 'help': ('if set, base-url subdomain is replaced by the request\'s ' |
|
196 'host, to help managing sites with several subdomains in a ' |
|
197 'single cubicweb instance'), |
|
198 'group': 'main', 'inputlevel': 1, |
|
199 }), |
198 ('mangle-emails', |
200 ('mangle-emails', |
199 {'type' : 'yn', |
201 {'type' : 'yn', |
200 'default': False, |
202 'default': False, |
201 'help': "don't display actual email addresses but mangle them if \ |
203 'help': "don't display actual email addresses but mangle them if \ |
202 this option is set to yes", |
204 this option is set to yes", |
203 'group': 'email', 'inputlevel': 2, |
205 'group': 'email', 'inputlevel': 2, |
204 }), |
206 }), |
|
207 ('disable-appobjects', |
|
208 {'type' : 'csv', 'default': (), |
|
209 'help': 'comma separated list of identifiers of application objects (<registry>.<oid>) to disable', |
|
210 'group': 'appobjects', 'inputlevel': 2, |
|
211 }), |
205 ) |
212 ) |
206 # static and class methods used to get application independant resources ## |
213 # static and class methods used to get application independant resources ## |
207 |
214 |
208 @staticmethod |
215 @staticmethod |
209 def cubicweb_version(): |
216 def cubicweb_version(): |
210 """return installed cubicweb version""" |
217 """return installed cubicweb version""" |
211 from logilab.common.changelog import Version |
218 from logilab.common.changelog import Version |
212 from cubicweb import __pkginfo__ |
219 from cubicweb import __pkginfo__ |
213 version = __pkginfo__.numversion |
220 version = __pkginfo__.numversion |
214 assert len(version) == 3, version |
221 assert len(version) == 3, version |
215 return Version(version) |
222 return Version(version) |
216 |
223 |
217 @staticmethod |
224 @staticmethod |
218 def persistent_options_configuration(): |
225 def persistent_options_configuration(): |
219 return Configuration(options=PERSISTENT_OPTIONS) |
226 return Configuration(options=PERSISTENT_OPTIONS) |
220 |
227 |
221 @classmethod |
228 @classmethod |
224 library views and data may be found) |
231 library views and data may be found) |
225 """ |
232 """ |
226 if cls.mode in ('dev', 'test') and not os.environ.get('APYCOT_ROOT'): |
233 if cls.mode in ('dev', 'test') and not os.environ.get('APYCOT_ROOT'): |
227 return join(CW_SOFTWARE_ROOT, 'web') |
234 return join(CW_SOFTWARE_ROOT, 'web') |
228 return cls.cube_dir('shared') |
235 return cls.cube_dir('shared') |
229 |
236 |
230 @classmethod |
237 @classmethod |
231 def i18n_lib_dir(cls): |
238 def i18n_lib_dir(cls): |
232 """return application's i18n directory""" |
239 """return application's i18n directory""" |
233 if cls.mode in ('dev', 'test') and not os.environ.get('APYCOT_ROOT'): |
240 if cls.mode in ('dev', 'test') and not os.environ.get('APYCOT_ROOT'): |
234 return join(CW_SOFTWARE_ROOT, 'i18n') |
241 return join(CW_SOFTWARE_ROOT, 'i18n') |
240 for directory in cls.cubes_search_path(): |
247 for directory in cls.cubes_search_path(): |
241 for cube in os.listdir(directory): |
248 for cube in os.listdir(directory): |
242 if isdir(join(directory, cube)) and not cube in ('CVS', '.svn', 'shared', '.hg'): |
249 if isdir(join(directory, cube)) and not cube in ('CVS', '.svn', 'shared', '.hg'): |
243 cubes.add(cube) |
250 cubes.add(cube) |
244 return sorted(cubes) |
251 return sorted(cubes) |
245 |
252 |
246 @classmethod |
253 @classmethod |
247 def cubes_search_path(cls): |
254 def cubes_search_path(cls): |
248 """return the path of directories where cubes should be searched""" |
255 """return the path of directories where cubes should be searched""" |
249 path = [] |
256 path = [] |
250 try: |
257 try: |
271 |
278 |
272 @classmethod |
279 @classmethod |
273 def cube_migration_scripts_dir(cls, cube): |
280 def cube_migration_scripts_dir(cls, cube): |
274 """cube migration scripts directory""" |
281 """cube migration scripts directory""" |
275 return join(cls.cube_dir(cube), 'migration') |
282 return join(cls.cube_dir(cube), 'migration') |
276 |
283 |
277 @classmethod |
284 @classmethod |
278 def cube_pkginfo(cls, cube): |
285 def cube_pkginfo(cls, cube): |
279 """return the information module for the given cube""" |
286 """return the information module for the given cube""" |
280 cube = CW_MIGRATION_MAP.get(cube, cube) |
287 cube = CW_MIGRATION_MAP.get(cube, cube) |
281 try: |
288 try: |
284 raise ConfigurationError('unable to find packaging information for ' |
291 raise ConfigurationError('unable to find packaging information for ' |
285 'cube %s (%s: %s)' % (cube, ex.__class__.__name__, ex)) |
292 'cube %s (%s: %s)' % (cube, ex.__class__.__name__, ex)) |
286 |
293 |
287 @classmethod |
294 @classmethod |
288 def cube_version(cls, cube): |
295 def cube_version(cls, cube): |
289 """return the version of the cube located in the given directory |
296 """return the version of the cube located in the given directory |
290 """ |
297 """ |
291 from logilab.common.changelog import Version |
298 from logilab.common.changelog import Version |
292 version = cls.cube_pkginfo(cube).numversion |
299 version = cls.cube_pkginfo(cube).numversion |
293 assert len(version) == 3, version |
300 assert len(version) == 3, version |
294 return Version(version) |
301 return Version(version) |
385 try: |
392 try: |
386 __import__('cubes.%s' % cube) |
393 __import__('cubes.%s' % cube) |
387 except: |
394 except: |
388 cls.exception('while loading cube %s', cube) |
395 cls.exception('while loading cube %s', cube) |
389 else: |
396 else: |
390 cls.warning('no __init__ file in cube %s', cube) |
397 cls.warning('no __init__ file in cube %s', cube) |
391 |
398 |
392 @classmethod |
399 @classmethod |
393 def init_available_cubes(cls): |
400 def init_available_cubes(cls): |
394 """cubes may register some sources (svnfile for instance) in their |
401 """cubes may register some sources (svnfile for instance) in their |
395 __init__ file, so they should be loaded early in the startup process |
402 __init__ file, so they should be loaded early in the startup process |
397 for cube in cls.available_cubes(): |
404 for cube in cls.available_cubes(): |
398 try: |
405 try: |
399 __import__('cubes.%s' % cube) |
406 __import__('cubes.%s' % cube) |
400 except Exception, ex: |
407 except Exception, ex: |
401 cls.warning("can't init cube %s: %s", cube, ex) |
408 cls.warning("can't init cube %s: %s", cube, ex) |
402 |
409 |
403 cubicweb_vobject_path = set(['entities']) |
410 cubicweb_vobject_path = set(['entities']) |
404 cube_vobject_path = set(['entities']) |
411 cube_vobject_path = set(['entities']) |
405 |
412 |
406 @classmethod |
413 @classmethod |
407 def build_vregistry_path(cls, templpath, evobjpath=None, tvobjpath=None): |
414 def build_vregistry_path(cls, templpath, evobjpath=None, tvobjpath=None): |
445 if exists(path): |
452 if exists(path): |
446 vregpath.append(path) |
453 vregpath.append(path) |
447 elif exists(path + '.py'): |
454 elif exists(path + '.py'): |
448 vregpath.append(path + '.py') |
455 vregpath.append(path + '.py') |
449 return vregpath |
456 return vregpath |
450 |
457 |
451 def __init__(self): |
458 def __init__(self): |
452 ConfigurationMixIn.__init__(self) |
459 ConfigurationMixIn.__init__(self) |
453 self.adjust_sys_path() |
460 self.adjust_sys_path() |
454 self.load_defaults() |
461 self.load_defaults() |
455 self.translations = {} |
462 self.translations = {} |
456 |
463 |
457 def adjust_sys_path(self): |
464 def adjust_sys_path(self): |
458 self.cls_adjust_sys_path() |
465 self.cls_adjust_sys_path() |
459 |
466 |
460 def init_log(self, logthreshold=None, debug=False, |
467 def init_log(self, logthreshold=None, debug=False, |
461 logfile=None, syslog=False): |
468 logfile=None, syslog=False): |
462 """init the log service""" |
469 """init the log service""" |
463 if logthreshold is None: |
470 if logthreshold is None: |
464 if debug: |
471 if debug: |
465 logthreshold = 'DEBUG' |
472 logthreshold = 'DEBUG' |
472 def vregistry_path(self): |
479 def vregistry_path(self): |
473 """return a list of files or directories where the registry will look |
480 """return a list of files or directories where the registry will look |
474 for application objects. By default return nothing in NoApp config. |
481 for application objects. By default return nothing in NoApp config. |
475 """ |
482 """ |
476 return [] |
483 return [] |
477 |
484 |
478 def eproperty_definitions(self): |
485 def eproperty_definitions(self): |
479 cfg = self.persistent_options_configuration() |
486 cfg = self.persistent_options_configuration() |
480 for section, options in cfg.options_by_section(): |
487 for section, options in cfg.options_by_section(): |
481 section = section.lower() |
488 section = section.lower() |
482 for optname, optdict, value in options: |
489 for optname, optdict, value in options: |
485 default = cfg.option_default(optname, optdict) |
492 default = cfg.option_default(optname, optdict) |
486 pdef = {'type': type, 'vocabulary': vocab, 'default': default, |
493 pdef = {'type': type, 'vocabulary': vocab, 'default': default, |
487 'help': optdict['help'], |
494 'help': optdict['help'], |
488 'sitewide': optdict.get('sitewide', False)} |
495 'sitewide': optdict.get('sitewide', False)} |
489 yield key, pdef |
496 yield key, pdef |
490 |
497 |
491 def map_option(self, optdict): |
498 def map_option(self, optdict): |
492 try: |
499 try: |
493 vocab = optdict['choices'] |
500 vocab = optdict['choices'] |
494 except KeyError: |
501 except KeyError: |
495 vocab = optdict.get('vocabulary') |
502 vocab = optdict.get('vocabulary') |
496 if isinstance(vocab, Method): |
503 if isinstance(vocab, Method): |
497 vocab = getattr(self, vocab.method, ()) |
504 vocab = getattr(self, vocab.method, ()) |
498 return CFGTYPE2ETYPE_MAP[optdict['type']], vocab |
505 return CFGTYPE2ETYPE_MAP[optdict['type']], vocab |
499 |
506 |
500 |
507 |
501 class CubicWebConfiguration(CubicWebNoAppConfiguration): |
508 class CubicWebConfiguration(CubicWebNoAppConfiguration): |
502 """base class for cubicweb server and web configurations""" |
509 """base class for cubicweb server and web configurations""" |
503 |
510 |
504 INSTANCE_DATA_DIR = None |
511 INSTANCE_DATA_DIR = None |
505 if CubicWebNoAppConfiguration.mode == 'test': |
512 if CubicWebNoAppConfiguration.mode == 'test': |
506 root = os.environ['APYCOT_ROOT'] |
513 root = os.environ['APYCOT_ROOT'] |
507 REGISTRY_DIR = '%s/etc/cubicweb.d/' % root |
514 REGISTRY_DIR = '%s/etc/cubicweb.d/' % root |
508 RUNTIME_DIR = '/tmp/' |
515 RUNTIME_DIR = '/tmp/' |
544 'help': 'listening port of the SMTP mail server', |
551 'help': 'listening port of the SMTP mail server', |
545 'group': 'email', 'inputlevel': 1, |
552 'group': 'email', 'inputlevel': 1, |
546 }), |
553 }), |
547 ('sender-name', |
554 ('sender-name', |
548 {'type' : 'string', |
555 {'type' : 'string', |
549 'default': Method('default_application_id'), |
556 'default': Method('default_application_id'), |
550 'help': 'name used as HELO name for outgoing emails from the \ |
557 'help': 'name used as HELO name for outgoing emails from the \ |
551 repository.', |
558 repository.', |
552 'group': 'email', 'inputlevel': 2, |
559 'group': 'email', 'inputlevel': 2, |
553 }), |
560 }), |
554 ('sender-addr', |
561 ('sender-addr', |
562 |
569 |
563 @classmethod |
570 @classmethod |
564 def runtime_dir(cls): |
571 def runtime_dir(cls): |
565 """run time directory for pid file...""" |
572 """run time directory for pid file...""" |
566 return env_path('CW_RUNTIME', cls.RUNTIME_DIR, 'run time') |
573 return env_path('CW_RUNTIME', cls.RUNTIME_DIR, 'run time') |
567 |
574 |
568 @classmethod |
575 @classmethod |
569 def registry_dir(cls): |
576 def registry_dir(cls): |
570 """return the control directory""" |
577 """return the control directory""" |
571 return env_path('CW_REGISTRY', cls.REGISTRY_DIR, 'registry') |
578 return env_path('CW_REGISTRY', cls.REGISTRY_DIR, 'registry') |
572 |
579 |
574 def instance_data_dir(cls): |
581 def instance_data_dir(cls): |
575 """return the instance data directory""" |
582 """return the instance data directory""" |
576 return env_path('CW_INSTANCE_DATA', |
583 return env_path('CW_INSTANCE_DATA', |
577 cls.INSTANCE_DATA_DIR or cls.REGISTRY_DIR, |
584 cls.INSTANCE_DATA_DIR or cls.REGISTRY_DIR, |
578 'additional data') |
585 'additional data') |
579 |
586 |
580 @classmethod |
587 @classmethod |
581 def migration_scripts_dir(cls): |
588 def migration_scripts_dir(cls): |
582 """cubicweb migration scripts directory""" |
589 """cubicweb migration scripts directory""" |
583 return env_path('CW_MIGRATION', cls.MIGRATION_DIR, 'migration') |
590 return env_path('CW_MIGRATION', cls.MIGRATION_DIR, 'migration') |
584 |
591 |
587 """return a configuration instance for the given application identifier |
594 """return a configuration instance for the given application identifier |
588 """ |
595 """ |
589 config = config or guess_configuration(cls.application_home(appid)) |
596 config = config or guess_configuration(cls.application_home(appid)) |
590 configcls = configuration_cls(config) |
597 configcls = configuration_cls(config) |
591 return configcls(appid) |
598 return configcls(appid) |
592 |
599 |
593 @classmethod |
600 @classmethod |
594 def possible_configurations(cls, appid): |
601 def possible_configurations(cls, appid): |
595 """return the name of possible configurations for the given |
602 """return the name of possible configurations for the given |
596 application id |
603 application id |
597 """ |
604 """ |
598 home = cls.application_home(appid) |
605 home = cls.application_home(appid) |
599 return possible_configurations(home) |
606 return possible_configurations(home) |
600 |
607 |
601 @classmethod |
608 @classmethod |
602 def application_home(cls, appid): |
609 def application_home(cls, appid): |
603 """return the home directory of the application with the given |
610 """return the home directory of the application with the given |
604 application id |
611 application id |
605 """ |
612 """ |
614 'twisted' : ('common', 'web'),} |
621 'twisted' : ('common', 'web'),} |
615 @classmethod |
622 @classmethod |
616 def accept_mode(cls, mode): |
623 def accept_mode(cls, mode): |
617 #assert mode in cls.MODES, mode |
624 #assert mode in cls.MODES, mode |
618 return mode in cls.MCOMPAT[cls.name] |
625 return mode in cls.MCOMPAT[cls.name] |
619 |
626 |
620 # default configuration methods ########################################### |
627 # default configuration methods ########################################### |
621 |
628 |
622 def default_application_id(self): |
629 def default_application_id(self): |
623 """return the application identifier, useful for option which need this |
630 """return the application identifier, useful for option which need this |
624 as default value |
631 as default value |
625 """ |
632 """ |
626 return self.appid |
633 return self.appid |
638 except IOError: |
645 except IOError: |
639 path = '%s-%s.log' % (basepath, i) |
646 path = '%s-%s.log' % (basepath, i) |
640 i += 1 |
647 i += 1 |
641 return path |
648 return path |
642 return '/var/log/cubicweb/%s-%s.log' % (self.appid, self.name) |
649 return '/var/log/cubicweb/%s-%s.log' % (self.appid, self.name) |
643 |
650 |
644 def default_pid_file(self): |
651 def default_pid_file(self): |
645 """return default path to the pid file of the application'server""" |
652 """return default path to the pid file of the application'server""" |
646 return join(self.runtime_dir(), '%s-%s.pid' % (self.appid, self.name)) |
653 return join(self.runtime_dir(), '%s-%s.pid' % (self.appid, self.name)) |
647 |
654 |
648 # instance methods used to get application specific resources ############# |
655 # instance methods used to get application specific resources ############# |
649 |
656 |
650 def __init__(self, appid): |
657 def __init__(self, appid): |
651 self.appid = appid |
658 self.appid = appid |
652 CubicWebNoAppConfiguration.__init__(self) |
659 CubicWebNoAppConfiguration.__init__(self) |
653 self._cubes = None |
660 self._cubes = None |
654 self._site_loaded = set() |
661 self._site_loaded = set() |
662 sys.path.insert(0, self.apphome) |
669 sys.path.insert(0, self.apphome) |
663 |
670 |
664 @property |
671 @property |
665 def apphome(self): |
672 def apphome(self): |
666 return join(self.registry_dir(), self.appid) |
673 return join(self.registry_dir(), self.appid) |
667 |
674 |
668 @property |
675 @property |
669 def appdatahome(self): |
676 def appdatahome(self): |
670 return join(self.instance_data_dir(), self.appid) |
677 return join(self.instance_data_dir(), self.appid) |
671 |
678 |
672 def init_cubes(self, cubes): |
679 def init_cubes(self, cubes): |
673 assert self._cubes is None |
680 assert self._cubes is None, self._cubes |
674 self._cubes = self.reorder_cubes(cubes) |
681 self._cubes = self.reorder_cubes(cubes) |
675 # load cubes'__init__.py file first |
682 # load cubes'__init__.py file first |
676 for cube in cubes: |
683 for cube in cubes: |
677 __import__('cubes.%s' % cube) |
684 __import__('cubes.%s' % cube) |
678 self.load_site_cubicweb() |
685 self.load_site_cubicweb() |
679 # reload config file in cases options are defined in cubes __init__ |
686 # reload config file in cases options are defined in cubes __init__ |
680 # or site_cubicweb files |
687 # or site_cubicweb files |
681 self.load_file_configuration(self.main_config_file()) |
688 self.load_file_configuration(self.main_config_file()) |
682 # configuration initialization hook |
689 # configuration initialization hook |
683 self.load_configuration() |
690 self.load_configuration() |
684 |
691 |
685 def cubes(self): |
692 def cubes(self): |
686 """return the list of cubes used by this instance |
693 """return the list of cubes used by this instance |
687 |
694 |
688 result is ordered from the top level cubes to inner dependencies |
695 result is ordered from the top level cubes to inner dependencies |
689 cubes |
696 cubes |
690 """ |
697 """ |
691 assert self._cubes is not None |
698 assert self._cubes is not None |
692 return self._cubes |
699 return self._cubes |
693 |
700 |
694 def cubes_path(self): |
701 def cubes_path(self): |
695 """return the list of path to cubes used by this instance, from outer |
702 """return the list of path to cubes used by this instance, from outer |
696 most to inner most cubes |
703 most to inner most cubes |
697 """ |
704 """ |
698 return [self.cube_dir(p) for p in self.cubes()] |
705 return [self.cube_dir(p) for p in self.cubes()] |
700 def add_cubes(self, cubes): |
707 def add_cubes(self, cubes): |
701 """add given cubes to the list of used cubes""" |
708 """add given cubes to the list of used cubes""" |
702 if not isinstance(cubes, list): |
709 if not isinstance(cubes, list): |
703 cubes = list(cubes) |
710 cubes = list(cubes) |
704 self._cubes = self.reorder_cubes(list(self._cubes) + cubes) |
711 self._cubes = self.reorder_cubes(list(self._cubes) + cubes) |
705 |
712 |
706 def main_config_file(self): |
713 def main_config_file(self): |
707 """return application's control configuration file""" |
714 """return application's control configuration file""" |
708 return join(self.apphome, '%s.conf' % self.name) |
715 return join(self.apphome, '%s.conf' % self.name) |
709 |
716 |
710 def save(self): |
717 def save(self): |
711 """write down current configuration""" |
718 """write down current configuration""" |
712 self.generate_config(open(self.main_config_file(), 'w')) |
719 self.generate_config(open(self.main_config_file(), 'w')) |
713 |
720 |
714 @cached |
721 @cached |
717 infos = [] |
724 infos = [] |
718 for pkg in self.cubes(): |
725 for pkg in self.cubes(): |
719 version = self.cube_version(pkg) |
726 version = self.cube_version(pkg) |
720 infos.append('%s-%s' % (pkg, version)) |
727 infos.append('%s-%s' % (pkg, version)) |
721 return md5.new(';'.join(infos)).hexdigest() |
728 return md5.new(';'.join(infos)).hexdigest() |
722 |
729 |
723 def load_site_cubicweb(self): |
730 def load_site_cubicweb(self): |
724 """load (web?) application's specific site_cubicweb file""" |
731 """load (web?) application's specific site_cubicweb file""" |
725 for path in reversed([self.apphome] + self.cubes_path()): |
732 for path in reversed([self.apphome] + self.cubes_path()): |
726 sitefile = join(path, 'site_cubicweb.py') |
733 sitefile = join(path, 'site_cubicweb.py') |
727 if exists(sitefile) and not sitefile in self._site_loaded: |
734 if exists(sitefile) and not sitefile in self._site_loaded: |
731 sitefile = join(path, 'site_erudi.py') |
738 sitefile = join(path, 'site_erudi.py') |
732 if exists(sitefile) and not sitefile in self._site_loaded: |
739 if exists(sitefile) and not sitefile in self._site_loaded: |
733 self._load_site_cubicweb(sitefile) |
740 self._load_site_cubicweb(sitefile) |
734 self._site_loaded.add(sitefile) |
741 self._site_loaded.add(sitefile) |
735 self.warning('site_erudi.py is deprecated, should be renamed to site_cubicweb.py') |
742 self.warning('site_erudi.py is deprecated, should be renamed to site_cubicweb.py') |
736 |
743 |
737 def _load_site_cubicweb(self, sitefile): |
744 def _load_site_cubicweb(self, sitefile): |
738 context = {} |
745 context = {} |
739 execfile(sitefile, context, context) |
746 execfile(sitefile, context, context) |
740 self.info('%s loaded', sitefile) |
747 self.info('%s loaded', sitefile) |
741 # cube specific options |
748 # cube specific options |
742 if context.get('options'): |
749 if context.get('options'): |
743 self.register_options(context['options']) |
750 self.register_options(context['options']) |
744 self.load_defaults() |
751 self.load_defaults() |
745 |
752 |
746 def load_configuration(self): |
753 def load_configuration(self): |
747 """load application's configuration files""" |
754 """load application's configuration files""" |
748 super(CubicWebConfiguration, self).load_configuration() |
755 super(CubicWebConfiguration, self).load_configuration() |
749 if self.apphome and self.set_language: |
756 if self.apphome and self.set_language: |
750 # init gettext |
757 # init gettext |
751 self._set_language() |
758 self._set_language() |
752 |
759 |
753 def init_log(self, logthreshold=None, debug=False, force=False): |
760 def init_log(self, logthreshold=None, debug=False, force=False): |
754 """init the log service""" |
761 """init the log service""" |
755 if not force and hasattr(self, '_logging_initialized'): |
762 if not force and hasattr(self, '_logging_initialized'): |
756 return |
763 return |
757 self._logging_initialized = True |
764 self._logging_initialized = True |
773 for path in glob(join(self.apphome, 'i18n', |
780 for path in glob(join(self.apphome, 'i18n', |
774 '*', 'LC_MESSAGES', 'cubicweb.mo')): |
781 '*', 'LC_MESSAGES', 'cubicweb.mo')): |
775 lang = path.split(os.sep)[-3] |
782 lang = path.split(os.sep)[-3] |
776 if lang != 'en': |
783 if lang != 'en': |
777 yield lang |
784 yield lang |
778 |
785 |
779 def _set_language(self): |
786 def _set_language(self): |
780 """set language for gettext""" |
787 """set language for gettext""" |
781 from gettext import translation |
788 from gettext import translation |
782 path = join(self.apphome, 'i18n') |
789 path = join(self.apphome, 'i18n') |
783 for language in self.available_languages(): |
790 for language in self.available_languages(): |
785 try: |
792 try: |
786 tr = translation('cubicweb', path, languages=[language]) |
793 tr = translation('cubicweb', path, languages=[language]) |
787 self.translations[language] = tr.ugettext |
794 self.translations[language] = tr.ugettext |
788 except (ImportError, AttributeError, IOError): |
795 except (ImportError, AttributeError, IOError): |
789 self.exception('localisation support error for language %s', |
796 self.exception('localisation support error for language %s', |
790 language) |
797 language) |
791 |
798 |
792 def vregistry_path(self): |
799 def vregistry_path(self): |
793 """return a list of files or directories where the registry will look |
800 """return a list of files or directories where the registry will look |
794 for application objects |
801 for application objects |
795 """ |
802 """ |
796 templpath = list(reversed(self.cubes_path())) |
803 templpath = list(reversed(self.cubes_path())) |
800 |
807 |
801 def set_sources_mode(self, sources): |
808 def set_sources_mode(self, sources): |
802 if not 'all' in sources: |
809 if not 'all' in sources: |
803 print 'warning: ignoring specified sources, requires a repository '\ |
810 print 'warning: ignoring specified sources, requires a repository '\ |
804 'configuration' |
811 'configuration' |
805 |
812 |
806 def migration_handler(self): |
813 def migration_handler(self): |
807 """return a migration handler instance""" |
814 """return a migration handler instance""" |
808 from cubicweb.common.migration import MigrationHelper |
815 from cubicweb.common.migration import MigrationHelper |
809 return MigrationHelper(self, verbosity=self.verbosity) |
816 return MigrationHelper(self, verbosity=self.verbosity) |
810 |
817 |
818 sourcedirs = [join(path, 'i18n') for path in self.cubes_path()] |
825 sourcedirs = [join(path, 'i18n') for path in self.cubes_path()] |
819 sourcedirs.append(self.i18n_lib_dir()) |
826 sourcedirs.append(self.i18n_lib_dir()) |
820 return i18n.compile_i18n_catalogs(sourcedirs, i18ndir, langs) |
827 return i18n.compile_i18n_catalogs(sourcedirs, i18ndir, langs) |
821 |
828 |
822 set_log_methods(CubicWebConfiguration, logging.getLogger('cubicweb.configuration')) |
829 set_log_methods(CubicWebConfiguration, logging.getLogger('cubicweb.configuration')) |
823 |
830 |
824 # alias to get a configuration instance from an application id |
831 # alias to get a configuration instance from an application id |
825 application_configuration = CubicWebConfiguration.config_for |
832 application_configuration = CubicWebConfiguration.config_for |
826 |
833 |