1 """%%prog %s [options] %s |
1 """%%prog %s [options] %s |
2 |
2 |
3 CubicWeb main applications controller. |
3 CubicWeb main applications controller. |
4 %s""" |
4 %s""" |
5 |
5 |
6 import sys |
6 import sys |
7 from os import remove, listdir, system, kill, getpgid |
7 from os import remove, listdir, system, kill, getpgid, pathsep |
8 from os.path import exists, join, isfile, isdir |
8 from os.path import exists, join, isfile, isdir |
9 |
9 |
|
10 from logilab.common.clcommands import register_commands, pop_arg |
|
11 |
10 from cubicweb import ConfigurationError, ExecutionError, BadCommandUsage |
12 from cubicweb import ConfigurationError, ExecutionError, BadCommandUsage |
11 from cubicweb.cwconfig import CubicWebConfiguration, CONFIGURATIONS |
13 from cubicweb.cwconfig import CubicWebConfiguration as cwcfg, CONFIGURATIONS |
12 from cubicweb.toolsutils import (Command, register_commands, main_run, |
14 from cubicweb.toolsutils import Command, main_run, rm, create_dir, confirm |
13 rm, create_dir, pop_arg, confirm) |
15 |
14 |
|
15 def wait_process_end(pid, maxtry=10, waittime=1): |
16 def wait_process_end(pid, maxtry=10, waittime=1): |
16 """wait for a process to actually die""" |
17 """wait for a process to actually die""" |
17 import signal |
18 import signal |
18 from time import sleep |
19 from time import sleep |
19 nbtry = 0 |
20 nbtry = 0 |
39 for fname in ('data', 'views', 'views.py'): |
40 for fname in ('data', 'views', 'views.py'): |
40 if exists(join(templdir, fname)): |
41 if exists(join(templdir, fname)): |
41 modes.append('web ui') |
42 modes.append('web ui') |
42 break |
43 break |
43 return modes |
44 return modes |
44 |
45 |
45 |
46 |
46 class ApplicationCommand(Command): |
47 class ApplicationCommand(Command): |
47 """base class for command taking 0 to n application id as arguments |
48 """base class for command taking 0 to n application id as arguments |
48 (0 meaning all registered applications) |
49 (0 meaning all registered applications) |
49 """ |
50 """ |
50 arguments = '[<application>...]' |
51 arguments = '[<application>...]' |
51 options = ( |
52 options = ( |
52 ("force", |
53 ("force", |
53 {'short': 'f', 'action' : 'store_true', |
54 {'short': 'f', 'action' : 'store_true', |
54 'default': False, |
55 'default': False, |
55 'help': 'force command without asking confirmation', |
56 'help': 'force command without asking confirmation', |
56 } |
57 } |
57 ), |
58 ), |
58 ) |
59 ) |
59 actionverb = None |
60 actionverb = None |
60 |
61 |
61 def ordered_instances(self): |
62 def ordered_instances(self): |
62 """return instances in the order in which they should be started, |
63 """return instances in the order in which they should be started, |
63 considering $REGISTRY_DIR/startorder file if it exists (useful when |
64 considering $REGISTRY_DIR/startorder file if it exists (useful when |
64 some instances depends on another as external source |
65 some instances depends on another as external source |
65 """ |
66 """ |
66 regdir = CubicWebConfiguration.registry_dir() |
67 regdir = cwcfg.registry_dir() |
67 _allinstances = list_instances(regdir) |
68 _allinstances = list_instances(regdir) |
68 if isfile(join(regdir, 'startorder')): |
69 if isfile(join(regdir, 'startorder')): |
69 allinstances = [] |
70 allinstances = [] |
70 for line in file(join(regdir, 'startorder')): |
71 for line in file(join(regdir, 'startorder')): |
71 line = line.strip() |
72 line = line.strip() |
72 if line and not line.startswith('#'): |
73 if line and not line.startswith('#'): |
73 try: |
74 try: |
74 _allinstances.remove(line) |
75 _allinstances.remove(line) |
75 allinstances.append(line) |
76 allinstances.append(line) |
76 except ValueError: |
77 except ValueError: |
77 print 'ERROR: startorder file contains unexistant instance %s' % line |
78 print ('ERROR: startorder file contains unexistant ' |
|
79 'instance %s' % line) |
78 allinstances += _allinstances |
80 allinstances += _allinstances |
79 else: |
81 else: |
80 allinstances = _allinstances |
82 allinstances = _allinstances |
81 return allinstances |
83 return allinstances |
82 |
84 |
83 def run(self, args): |
85 def run(self, args): |
84 """run the <command>_method on each argument (a list of application |
86 """run the <command>_method on each argument (a list of application |
85 identifiers) |
87 identifiers) |
86 """ |
88 """ |
87 if not args: |
89 if not args: |
92 # no force option |
94 # no force option |
93 askconfirm = False |
95 askconfirm = False |
94 else: |
96 else: |
95 askconfirm = False |
97 askconfirm = False |
96 self.run_args(args, askconfirm) |
98 self.run_args(args, askconfirm) |
97 |
99 |
98 def run_args(self, args, askconfirm): |
100 def run_args(self, args, askconfirm): |
99 for appid in args: |
101 for appid in args: |
100 if askconfirm: |
102 if askconfirm: |
101 print '*'*72 |
103 print '*'*72 |
102 if not confirm('%s application %r ?' % (self.name, appid)): |
104 if not confirm('%s application %r ?' % (self.name, appid)): |
103 continue |
105 continue |
104 self.run_arg(appid) |
106 self.run_arg(appid) |
105 |
107 |
106 def run_arg(self, appid): |
108 def run_arg(self, appid): |
107 cmdmeth = getattr(self, '%s_application' % self.name) |
109 cmdmeth = getattr(self, '%s_application' % self.name) |
108 try: |
110 try: |
109 cmdmeth(appid) |
111 cmdmeth(appid) |
110 except (KeyboardInterrupt, SystemExit): |
112 except (KeyboardInterrupt, SystemExit): |
151 registered applications |
153 registered applications |
152 """ |
154 """ |
153 name = 'list' |
155 name = 'list' |
154 options = ( |
156 options = ( |
155 ('verbose', |
157 ('verbose', |
156 {'short': 'v', 'action' : 'store_true', |
158 {'short': 'v', 'action' : 'store_true', |
157 'help': "display more information."}), |
159 'help': "display more information."}), |
158 ) |
160 ) |
159 |
161 |
160 def run(self, args): |
162 def run(self, args): |
161 """run the command with its specific arguments""" |
163 """run the command with its specific arguments""" |
162 if args: |
164 if args: |
163 raise BadCommandUsage('Too much arguments') |
165 raise BadCommandUsage('Too much arguments') |
164 print 'CubicWeb version:', CubicWebConfiguration.cubicweb_version() |
166 print 'CubicWeb version:', cwcfg.cubicweb_version() |
165 print 'Detected mode:', CubicWebConfiguration.mode |
167 print 'Detected mode:', cwcfg.mode |
166 print |
168 print |
167 print 'Available configurations:' |
169 print 'Available configurations:' |
168 for config in CONFIGURATIONS: |
170 for config in CONFIGURATIONS: |
169 print '*', config.name |
171 print '*', config.name |
170 for line in config.__doc__.splitlines(): |
172 for line in config.__doc__.splitlines(): |
171 line = line.strip() |
173 line = line.strip() |
172 if not line: |
174 if not line: |
173 continue |
175 continue |
174 print ' ', line |
176 print ' ', line |
175 print |
177 print |
176 cubesdirs = ', '.join(CubicWebConfiguration.cubes_search_path()) |
178 try: |
177 try: |
179 cubesdir = pathsep.join(cwcfg.cubes_search_path()) |
178 namesize = max(len(x) for x in CubicWebConfiguration.available_cubes()) |
180 namesize = max(len(x) for x in cwcfg.available_cubes()) |
179 except ConfigurationError, ex: |
181 except ConfigurationError, ex: |
180 print 'No cubes available:', ex |
182 print 'No cubes available:', ex |
181 except ValueError: |
183 except ValueError: |
182 print 'No cubes available in %s' % cubesdirs |
184 print 'No cubes available in %s' % cubesdir |
183 else: |
185 else: |
184 print 'Available cubes (%s):' % cubesdirs |
186 print 'Available cubes (%s):' % cubesdir |
185 for cube in CubicWebConfiguration.available_cubes(): |
187 for cube in cwcfg.available_cubes(): |
186 if cube in ('CVS', '.svn', 'shared', '.hg'): |
188 if cube in ('CVS', '.svn', 'shared', '.hg'): |
187 continue |
189 continue |
188 try: |
190 try: |
189 tinfo = CubicWebConfiguration.cube_pkginfo(cube) |
191 tinfo = cwcfg.cube_pkginfo(cube) |
190 tversion = tinfo.version |
192 tversion = tinfo.version |
191 except ConfigurationError: |
193 except ConfigurationError: |
192 tinfo = None |
194 tinfo = None |
193 tversion = '[missing cube information]' |
195 tversion = '[missing cube information]' |
194 print '* %s %s' % (cube.ljust(namesize), tversion) |
196 print '* %s %s' % (cube.ljust(namesize), tversion) |
199 print ' '+ ' \n'.join(shortdesc.splitlines()) |
201 print ' '+ ' \n'.join(shortdesc.splitlines()) |
200 modes = detect_available_modes(CubicWebConfiguration.cube_dir(cube)) |
202 modes = detect_available_modes(CubicWebConfiguration.cube_dir(cube)) |
201 print ' available modes: %s' % ', '.join(modes) |
203 print ' available modes: %s' % ', '.join(modes) |
202 print |
204 print |
203 try: |
205 try: |
204 regdir = CubicWebConfiguration.registry_dir() |
206 regdir = cwcfg.registry_dir() |
205 except ConfigurationError, ex: |
207 except ConfigurationError, ex: |
206 print 'No application available:', ex |
208 print 'No application available:', ex |
207 print |
209 print |
208 return |
210 return |
209 instances = list_instances(regdir) |
211 instances = list_instances(regdir) |
210 if instances: |
212 if instances: |
211 print 'Available applications (%s):' % regdir |
213 print 'Available applications (%s):' % regdir |
212 for appid in instances: |
214 for appid in instances: |
213 modes = CubicWebConfiguration.possible_configurations(appid) |
215 modes = cwcfg.possible_configurations(appid) |
214 if not modes: |
216 if not modes: |
215 print '* %s (BROKEN application, no configuration found)' % appid |
217 print '* %s (BROKEN application, no configuration found)' % appid |
216 continue |
218 continue |
217 print '* %s (%s)' % (appid, ', '.join(modes)) |
219 print '* %s (%s)' % (appid, ', '.join(modes)) |
218 try: |
220 try: |
219 config = CubicWebConfiguration.config_for(appid, modes[0]) |
221 config = cwcfg.config_for(appid, modes[0]) |
220 except Exception, exc: |
222 except Exception, exc: |
221 print ' (BROKEN application, %s)' % exc |
223 print ' (BROKEN application, %s)' % exc |
222 continue |
224 continue |
223 else: |
225 else: |
224 print 'No application available in %s' % regdir |
226 print 'No application available in %s' % regdir |
225 print |
227 print |
257 command. Default to "all-in-one", e.g. an installation embedding both the RQL \ |
259 command. Default to "all-in-one", e.g. an installation embedding both the RQL \ |
258 repository and the web server.', |
260 repository and the web server.', |
259 } |
261 } |
260 ), |
262 ), |
261 ) |
263 ) |
262 |
264 |
263 def run(self, args): |
265 def run(self, args): |
264 """run the command with its specific arguments""" |
266 """run the command with its specific arguments""" |
265 from logilab.common.textutils import get_csv |
267 from logilab.common.textutils import get_csv |
266 configname = self.config.config |
268 configname = self.config.config |
267 cubes = get_csv(pop_arg(args, 1)) |
269 cubes = get_csv(pop_arg(args, 1)) |
268 appid = pop_arg(args) |
270 appid = pop_arg(args) |
269 # get the configuration and helper |
271 # get the configuration and helper |
270 CubicWebConfiguration.creating = True |
272 cwcfg.creating = True |
271 config = CubicWebConfiguration.config_for(appid, configname) |
273 config = cwcfg.config_for(appid, configname) |
272 config.set_language = False |
274 config.set_language = False |
273 config.init_cubes(config.expand_cubes(cubes)) |
275 config.init_cubes(config.expand_cubes(cubes)) |
274 helper = self.config_helper(config) |
276 helper = self.config_helper(config) |
275 # check the cube exists |
277 # check the cube exists |
276 try: |
278 try: |
277 templdirs = [CubicWebConfiguration.cube_dir(cube) |
279 templdirs = [cwcfg.cube_dir(cube) |
278 for cube in cubes] |
280 for cube in cubes] |
279 except ConfigurationError, ex: |
281 except ConfigurationError, ex: |
280 print ex |
282 print ex |
281 print '\navailable cubes:', |
283 print '\navailable cubes:', |
282 print ', '.join(CubicWebConfiguration.available_cubes()) |
284 print ', '.join(cwcfg.available_cubes()) |
283 return |
285 return |
284 # create the registry directory for this application |
286 # create the registry directory for this application |
285 create_dir(config.apphome) |
287 create_dir(config.apphome) |
286 # load site_cubicweb from the cubes dir (if any) |
288 # load site_cubicweb from the cubes dir (if any) |
287 config.load_site_cubicweb() |
289 config.load_site_cubicweb() |
293 print |
295 print |
294 helper.bootstrap(cubes, self.config.config_level) |
296 helper.bootstrap(cubes, self.config.config_level) |
295 # write down configuration |
297 # write down configuration |
296 config.save() |
298 config.save() |
297 # handle i18n files structure |
299 # handle i18n files structure |
298 # XXX currently available languages are guessed from translations found |
|
299 # in the first cube given |
300 # in the first cube given |
300 from cubicweb.common import i18n |
301 from cubicweb.common import i18n |
301 langs = [lang for lang, _ in i18n.available_catalogs(join(templdirs[0], 'i18n'))] |
302 langs = [lang for lang, _ in i18n.available_catalogs(join(templdirs[0], 'i18n'))] |
302 errors = config.i18ncompile(langs) |
303 errors = config.i18ncompile(langs) |
303 if errors: |
304 if errors: |
320 print 'application %s (%s) created in %r' % (appid, configname, |
321 print 'application %s (%s) created in %r' % (appid, configname, |
321 config.apphome) |
322 config.apphome) |
322 print |
323 print |
323 helper.postcreate() |
324 helper.postcreate() |
324 |
325 |
325 |
326 |
326 class DeleteApplicationCommand(Command): |
327 class DeleteApplicationCommand(Command): |
327 """Delete an application. Will remove application's files and |
328 """Delete an application. Will remove application's files and |
328 unregister it. |
329 unregister it. |
329 """ |
330 """ |
330 name = 'delete' |
331 name = 'delete' |
331 arguments = '<application>' |
332 arguments = '<application>' |
332 |
333 |
333 options = () |
334 options = () |
334 |
335 |
335 def run(self, args): |
336 def run(self, args): |
336 """run the command with its specific arguments""" |
337 """run the command with its specific arguments""" |
337 appid = pop_arg(args, msg="No application specified !") |
338 appid = pop_arg(args, msg="No application specified !") |
338 configs = [CubicWebConfiguration.config_for(appid, configname) |
339 configs = [cwcfg.config_for(appid, configname) |
339 for configname in CubicWebConfiguration.possible_configurations(appid)] |
340 for configname in cwcfg.possible_configurations(appid)] |
340 if not configs: |
341 if not configs: |
341 raise ExecutionError('unable to guess configuration for %s' % appid) |
342 raise ExecutionError('unable to guess configuration for %s' % appid) |
342 for config in configs: |
343 for config in configs: |
343 helper = self.config_helper(config, required=False) |
344 helper = self.config_helper(config, required=False) |
344 if helper: |
345 if helper: |
358 |
359 |
359 # application commands ######################################################## |
360 # application commands ######################################################## |
360 |
361 |
361 class StartApplicationCommand(ApplicationCommand): |
362 class StartApplicationCommand(ApplicationCommand): |
362 """Start the given applications. If no application is given, start them all. |
363 """Start the given applications. If no application is given, start them all. |
363 |
364 |
364 <application>... |
365 <application>... |
365 identifiers of the applications to start. If no application is |
366 identifiers of the applications to start. If no application is |
366 given, start them all. |
367 given, start them all. |
367 """ |
368 """ |
368 name = 'start' |
369 name = 'start' |
387 """start the application's server""" |
388 """start the application's server""" |
388 # use get() since start may be used from other commands (eg upgrade) |
389 # use get() since start may be used from other commands (eg upgrade) |
389 # without all options defined |
390 # without all options defined |
390 debug = self.get('debug') |
391 debug = self.get('debug') |
391 force = self.get('force') |
392 force = self.get('force') |
392 config = CubicWebConfiguration.config_for(appid) |
393 config = cwcfg.config_for(appid) |
393 if self.get('profile'): |
394 if self.get('profile'): |
394 config.global_set_option('profile', self.config.profile) |
395 config.global_set_option('profile', self.config.profile) |
395 helper = self.config_helper(config, cmdname='start') |
396 helper = self.config_helper(config, cmdname='start') |
396 pidf = config['pid-file'] |
397 pidf = config['pid-file'] |
397 if exists(pidf) and not force: |
398 if exists(pidf) and not force: |
411 return True |
412 return True |
412 |
413 |
413 |
414 |
414 class StopApplicationCommand(ApplicationCommand): |
415 class StopApplicationCommand(ApplicationCommand): |
415 """Stop the given applications. |
416 """Stop the given applications. |
416 |
417 |
417 <application>... |
418 <application>... |
418 identifiers of the applications to stop. If no application is |
419 identifiers of the applications to stop. If no application is |
419 given, stop them all. |
420 given, stop them all. |
420 """ |
421 """ |
421 name = 'stop' |
422 name = 'stop' |
422 actionverb = 'stopped' |
423 actionverb = 'stopped' |
423 |
424 |
424 def ordered_instances(self): |
425 def ordered_instances(self): |
425 instances = super(StopApplicationCommand, self).ordered_instances() |
426 instances = super(StopApplicationCommand, self).ordered_instances() |
426 instances.reverse() |
427 instances.reverse() |
427 return instances |
428 return instances |
428 |
429 |
429 def stop_application(self, appid): |
430 def stop_application(self, appid): |
430 """stop the application's server""" |
431 """stop the application's server""" |
431 config = CubicWebConfiguration.config_for(appid) |
432 config = cwcfg.config_for(appid) |
432 helper = self.config_helper(config, cmdname='stop') |
433 helper = self.config_helper(config, cmdname='stop') |
433 helper.poststop() # do this anyway |
434 helper.poststop() # do this anyway |
434 pidf = config['pid-file'] |
435 pidf = config['pid-file'] |
435 if not exists(pidf): |
436 if not exists(pidf): |
436 print >> sys.stderr, "%s doesn't exist." % pidf |
437 print >> sys.stderr, "%s doesn't exist." % pidf |
457 remove(pidf) |
458 remove(pidf) |
458 except OSError: |
459 except OSError: |
459 # already removed by twistd |
460 # already removed by twistd |
460 pass |
461 pass |
461 print 'application %s stopped' % appid |
462 print 'application %s stopped' % appid |
462 |
463 |
463 |
464 |
464 class RestartApplicationCommand(StartApplicationCommand, |
465 class RestartApplicationCommand(StartApplicationCommand, |
465 StopApplicationCommand): |
466 StopApplicationCommand): |
466 """Restart the given applications. |
467 """Restart the given applications. |
467 |
468 |
468 <application>... |
469 <application>... |
469 identifiers of the applications to restart. If no application is |
470 identifiers of the applications to restart. If no application is |
470 given, restart them all. |
471 given, restart them all. |
471 """ |
472 """ |
472 name = 'restart' |
473 name = 'restart' |
473 actionverb = 'restarted' |
474 actionverb = 'restarted' |
474 |
475 |
475 def run_args(self, args, askconfirm): |
476 def run_args(self, args, askconfirm): |
476 regdir = CubicWebConfiguration.registry_dir() |
477 regdir = cwcfg.registry_dir() |
477 if not isfile(join(regdir, 'startorder')) or len(args) <= 1: |
478 if not isfile(join(regdir, 'startorder')) or len(args) <= 1: |
478 # no specific startorder |
479 # no specific startorder |
479 super(RestartApplicationCommand, self).run_args(args, askconfirm) |
480 super(RestartApplicationCommand, self).run_args(args, askconfirm) |
480 return |
481 return |
481 print ('some specific start order is specified, will first stop all ' |
482 print ('some specific start order is specified, will first stop all ' |
494 forkcmd = ' '.join(forkcmd) |
495 forkcmd = ' '.join(forkcmd) |
495 for appid in reversed(args): |
496 for appid in reversed(args): |
496 status = system('%s %s' % (forkcmd, appid)) |
497 status = system('%s %s' % (forkcmd, appid)) |
497 if status: |
498 if status: |
498 sys.exit(status) |
499 sys.exit(status) |
499 |
500 |
500 def restart_application(self, appid): |
501 def restart_application(self, appid): |
501 self.stop_application(appid) |
502 self.stop_application(appid) |
502 if self.start_application(appid): |
503 if self.start_application(appid): |
503 print 'application %s %s' % (appid, self.actionverb) |
504 print 'application %s %s' % (appid, self.actionverb) |
504 |
505 |
505 |
506 |
506 class ReloadConfigurationCommand(RestartApplicationCommand): |
507 class ReloadConfigurationCommand(RestartApplicationCommand): |
507 """Reload the given applications. This command is equivalent to a |
508 """Reload the given applications. This command is equivalent to a |
508 restart for now. |
509 restart for now. |
509 |
510 |
510 <application>... |
511 <application>... |
511 identifiers of the applications to reload. If no application is |
512 identifiers of the applications to reload. If no application is |
512 given, reload them all. |
513 given, reload them all. |
513 """ |
514 """ |
514 name = 'reload' |
515 name = 'reload' |
515 |
516 |
516 def reload_application(self, appid): |
517 def reload_application(self, appid): |
517 self.restart_application(appid) |
518 self.restart_application(appid) |
518 |
519 |
519 |
520 |
520 class StatusCommand(ApplicationCommand): |
521 class StatusCommand(ApplicationCommand): |
521 """Display status information about the given applications. |
522 """Display status information about the given applications. |
522 |
523 |
523 <application>... |
524 <application>... |
524 identifiers of the applications to status. If no application is |
525 identifiers of the applications to status. If no application is |
525 given, get status information about all registered applications. |
526 given, get status information about all registered applications. |
526 """ |
527 """ |
527 name = 'status' |
528 name = 'status' |
528 options = () |
529 options = () |
529 |
530 |
530 def status_application(self, appid): |
531 @staticmethod |
|
532 def status_application(appid): |
531 """print running status information for an application""" |
533 """print running status information for an application""" |
532 for mode in CubicWebConfiguration.possible_configurations(appid): |
534 for mode in cwcfg.possible_configurations(appid): |
533 config = CubicWebConfiguration.config_for(appid, mode) |
535 config = cwcfg.config_for(appid, mode) |
534 print '[%s-%s]' % (appid, mode), |
536 print '[%s-%s]' % (appid, mode), |
535 try: |
537 try: |
536 pidf = config['pid-file'] |
538 pidf = config['pid-file'] |
537 except KeyError: |
539 except KeyError: |
538 print 'buggy application, pid file not specified' |
540 print 'buggy application, pid file not specified' |
572 'help': 'force migration from the indicated version for the specified cube.'}), |
574 'help': 'force migration from the indicated version for the specified cube.'}), |
573 ('force-cubicweb-version', |
575 ('force-cubicweb-version', |
574 {'short': 'e', 'type' : 'string', 'metavar': 'X.Y.Z', |
576 {'short': 'e', 'type' : 'string', 'metavar': 'X.Y.Z', |
575 'default': None, |
577 'default': None, |
576 'help': 'force migration from the indicated cubicweb version.'}), |
578 'help': 'force migration from the indicated cubicweb version.'}), |
577 |
579 |
578 ('fs-only', |
580 ('fs-only', |
579 {'short': 's', 'action' : 'store_true', |
581 {'short': 's', 'action' : 'store_true', |
580 'default': False, |
582 'default': False, |
581 'help': 'only upgrade files on the file system, not the database.'}), |
583 'help': 'only upgrade files on the file system, not the database.'}), |
582 |
584 |
583 ('nostartstop', |
585 ('nostartstop', |
584 {'short': 'n', 'action' : 'store_true', |
586 {'short': 'n', 'action' : 'store_true', |
585 'default': False, |
587 'default': False, |
586 'help': 'don\'t try to stop application before migration and to restart it after.'}), |
588 'help': 'don\'t try to stop application before migration and to restart it after.'}), |
587 |
589 |
588 ('verbosity', |
590 ('verbosity', |
589 {'short': 'v', 'type' : 'int', 'metavar': '<0..2>', |
591 {'short': 'v', 'type' : 'int', 'metavar': '<0..2>', |
590 'default': 1, |
592 'default': 1, |
591 'help': "0: no confirmation, 1: only main commands confirmed, 2 ask \ |
593 'help': "0: no confirmation, 1: only main commands confirmed, 2 ask \ |
592 for everything."}), |
594 for everything."}), |
593 |
595 |
594 ('backup-db', |
596 ('backup-db', |
595 {'short': 'b', 'type' : 'yn', 'metavar': '<y or n>', |
597 {'short': 'b', 'type' : 'yn', 'metavar': '<y or n>', |
596 'default': None, |
598 'default': None, |
597 'help': "Backup the application database before upgrade.\n"\ |
599 'help': "Backup the application database before upgrade.\n"\ |
598 "If the option is ommitted, confirmation will be ask.", |
600 "If the option is ommitted, confirmation will be ask.", |
609 ) |
611 ) |
610 |
612 |
611 def ordered_instances(self): |
613 def ordered_instances(self): |
612 # need this since mro return StopApplicationCommand implementation |
614 # need this since mro return StopApplicationCommand implementation |
613 return ApplicationCommand.ordered_instances(self) |
615 return ApplicationCommand.ordered_instances(self) |
614 |
616 |
615 def upgrade_application(self, appid): |
617 def upgrade_application(self, appid): |
616 from logilab.common.changelog import Version |
618 from logilab.common.changelog import Version |
617 config = CubicWebConfiguration.config_for(appid) |
619 config = cwcfg.config_for(appid) |
618 config.creating = True # notice we're not starting the server |
620 config.creating = True # notice we're not starting the server |
619 config.verbosity = self.config.verbosity |
621 config.verbosity = self.config.verbosity |
620 try: |
622 try: |
621 config.set_sources_mode(self.config.ext_sources or ('migration',)) |
623 config.set_sources_mode(self.config.ext_sources or ('migration',)) |
622 except AttributeError: |
624 except AttributeError: |
642 except KeyError: |
644 except KeyError: |
643 config.error('no version information for %s' % cube) |
645 config.error('no version information for %s' % cube) |
644 continue |
646 continue |
645 if installedversion > applversion: |
647 if installedversion > applversion: |
646 toupgrade.append( (cube, applversion, installedversion) ) |
648 toupgrade.append( (cube, applversion, installedversion) ) |
647 cubicwebversion = config.cubicweb_version() |
649 cubicwebversion = config.cubicweb_version() |
648 if self.config.force_cubicweb_version: |
650 if self.config.force_cubicweb_version: |
649 applcubicwebversion = Version(self.config.force_cubicweb_version) |
651 applcubicwebversion = Version(self.config.force_cubicweb_version) |
650 vcconf['cubicweb'] = applcubicwebversion |
652 vcconf['cubicweb'] = applcubicwebversion |
651 else: |
653 else: |
652 applcubicwebversion = vcconf.get('cubicweb') |
654 applcubicwebversion = vcconf.get('cubicweb') |
656 print 'no software migration needed for application %s' % appid |
658 print 'no software migration needed for application %s' % appid |
657 return |
659 return |
658 for cube, fromversion, toversion in toupgrade: |
660 for cube, fromversion, toversion in toupgrade: |
659 print '**** %s migration %s -> %s' % (cube, fromversion, toversion) |
661 print '**** %s migration %s -> %s' % (cube, fromversion, toversion) |
660 # only stop once we're sure we have something to do |
662 # only stop once we're sure we have something to do |
661 if not (CubicWebConfiguration.mode == 'dev' or self.config.nostartstop): |
663 if not (cwcfg.mode == 'dev' or self.config.nostartstop): |
662 self.stop_application(appid) |
664 self.stop_application(appid) |
663 # run cubicweb/componants migration scripts |
665 # run cubicweb/componants migration scripts |
664 mih.migrate(vcconf, reversed(toupgrade), self.config) |
666 mih.migrate(vcconf, reversed(toupgrade), self.config) |
665 # rewrite main configuration file |
667 # rewrite main configuration file |
666 mih.rewrite_configuration() |
668 mih.rewrite_configuration() |
667 # handle i18n upgrade: |
669 # handle i18n upgrade: |
668 # * install new languages |
670 # * install new languages |
669 # * recompile catalogs |
671 # * recompile catalogs |
670 # XXX currently available languages are guessed from translations found |
|
671 # in the first componant given |
672 # in the first componant given |
672 from cubicweb.common import i18n |
673 from cubicweb.common import i18n |
673 templdir = CubicWebConfiguration.cube_dir(config.cubes()[0]) |
674 templdir = cwcfg.cube_dir(config.cubes()[0]) |
674 langs = [lang for lang, _ in i18n.available_catalogs(join(templdir, 'i18n'))] |
675 langs = [lang for lang, _ in i18n.available_catalogs(join(templdir, 'i18n'))] |
675 errors = config.i18ncompile(langs) |
676 errors = config.i18ncompile(langs) |
676 if errors: |
677 if errors: |
677 print '\n'.join(errors) |
678 print '\n'.join(errors) |
678 if not confirm('error while compiling message catalogs, ' |
679 if not confirm('error while compiling message catalogs, ' |
704 {'short': 'S', 'action' : 'store_true', |
705 {'short': 'S', 'action' : 'store_true', |
705 'default': False, |
706 'default': False, |
706 'help': 'only connect to the system source when the instance is ' |
707 'help': 'only connect to the system source when the instance is ' |
707 'using multiple sources. You can\'t use this option and the ' |
708 'using multiple sources. You can\'t use this option and the ' |
708 '--ext-sources option at the same time.'}), |
709 '--ext-sources option at the same time.'}), |
709 |
710 |
710 ('ext-sources', |
711 ('ext-sources', |
711 {'short': 'E', 'type' : 'csv', 'metavar': '<sources>', |
712 {'short': 'E', 'type' : 'csv', 'metavar': '<sources>', |
712 'default': None, |
713 'default': None, |
713 'help': "For multisources instances, specify to which sources the \ |
714 'help': "For multisources instances, specify to which sources the \ |
714 repository should connect to for upgrading. When unspecified or 'all' given, \ |
715 repository should connect to for upgrading. When unspecified or 'all' given, \ |
715 will connect to all defined sources. If 'migration' is given, appropriate \ |
716 will connect to all defined sources. If 'migration' is given, appropriate \ |
716 sources for migration will be automatically selected.", |
717 sources for migration will be automatically selected.", |
717 }), |
718 }), |
718 |
719 |
719 ) |
720 ) |
720 def run(self, args): |
721 def run(self, args): |
721 appid = pop_arg(args, 99, msg="No application specified !") |
722 appid = pop_arg(args, 99, msg="No application specified !") |
722 config = CubicWebConfiguration.config_for(appid) |
723 config = cwcfg.config_for(appid) |
723 if self.config.ext_sources: |
724 if self.config.ext_sources: |
724 assert not self.config.system_only |
725 assert not self.config.system_only |
725 sources = self.config.ext_sources |
726 sources = self.config.ext_sources |
726 elif self.config.system_only: |
727 elif self.config.system_only: |
727 sources = ('system',) |
728 sources = ('system',) |
731 mih = config.migration_handler() |
732 mih = config.migration_handler() |
732 if args: |
733 if args: |
733 mih.scripts_session(args) |
734 mih.scripts_session(args) |
734 else: |
735 else: |
735 mih.interactive_shell() |
736 mih.interactive_shell() |
736 mih.shutdown() |
737 mih.shutdown() |
737 |
738 |
738 |
739 |
739 class RecompileApplicationCatalogsCommand(ApplicationCommand): |
740 class RecompileApplicationCatalogsCommand(ApplicationCommand): |
740 """Recompile i18n catalogs for applications. |
741 """Recompile i18n catalogs for applications. |
741 |
742 |
742 <application>... |
743 <application>... |
743 identifiers of the applications to consider. If no application is |
744 identifiers of the applications to consider. If no application is |
744 given, recompile for all registered applications. |
745 given, recompile for all registered applications. |
745 """ |
746 """ |
746 name = 'i18ncompile' |
747 name = 'i18ncompile' |
747 |
748 |
748 def i18ncompile_application(self, appid): |
749 @staticmethod |
|
750 def i18ncompile_application(appid): |
749 """recompile application's messages catalogs""" |
751 """recompile application's messages catalogs""" |
750 config = CubicWebConfiguration.config_for(appid) |
752 config = cwcfg.config_for(appid) |
751 try: |
753 try: |
752 config.bootstrap_cubes() |
754 config.bootstrap_cubes() |
753 except IOError, ex: |
755 except IOError, ex: |
754 import errno |
756 import errno |
755 if ex.errno != errno.ENOENT: |
757 if ex.errno != errno.ENOENT: |
769 |
771 |
770 class ListInstancesCommand(Command): |
772 class ListInstancesCommand(Command): |
771 """list available instances, useful for bash completion.""" |
773 """list available instances, useful for bash completion.""" |
772 name = 'listinstances' |
774 name = 'listinstances' |
773 hidden = True |
775 hidden = True |
774 |
776 |
775 def run(self, args): |
777 def run(self, args): |
776 """run the command with its specific arguments""" |
778 """run the command with its specific arguments""" |
777 regdir = CubicWebConfiguration.registry_dir() |
779 regdir = cwcfg.registry_dir() |
778 for appid in sorted(listdir(regdir)): |
780 for appid in sorted(listdir(regdir)): |
779 print appid |
781 print appid |
780 |
782 |
781 |
783 |
782 class ListCubesCommand(Command): |
784 class ListCubesCommand(Command): |
783 """list available componants, useful for bash completion.""" |
785 """list available componants, useful for bash completion.""" |
784 name = 'listcubes' |
786 name = 'listcubes' |
785 hidden = True |
787 hidden = True |
786 |
788 |
787 def run(self, args): |
789 def run(self, args): |
788 """run the command with its specific arguments""" |
790 """run the command with its specific arguments""" |
789 for cube in CubicWebConfiguration.available_cubes(): |
791 for cube in cwcfg.available_cubes(): |
790 print cube |
792 print cube |
791 |
793 |
792 register_commands((ListCommand, |
794 register_commands((ListCommand, |
793 CreateApplicationCommand, |
795 CreateApplicationCommand, |
794 DeleteApplicationCommand, |
796 DeleteApplicationCommand, |
801 ShellCommand, |
803 ShellCommand, |
802 RecompileApplicationCatalogsCommand, |
804 RecompileApplicationCatalogsCommand, |
803 ListInstancesCommand, ListCubesCommand, |
805 ListInstancesCommand, ListCubesCommand, |
804 )) |
806 )) |
805 |
807 |
806 |
808 |
807 def run(args): |
809 def run(args): |
808 """command line tool""" |
810 """command line tool""" |
809 CubicWebConfiguration.load_cwctl_plugins() |
811 cwcfg.load_cwctl_plugins() |
810 main_run(args, __doc__) |
812 main_run(args, __doc__) |
811 |
813 |
812 if __name__ == '__main__': |
814 if __name__ == '__main__': |
813 run(sys.argv[1:]) |
815 run(sys.argv[1:]) |