34 def kill(*args): |
34 def kill(*args): |
35 """win32 kill implementation""" |
35 """win32 kill implementation""" |
36 def getpgid(): |
36 def getpgid(): |
37 """win32 getpgid implementation""" |
37 """win32 getpgid implementation""" |
38 |
38 |
39 from six.moves.urllib.parse import urlparse |
|
40 |
|
41 from logilab.common.clcommands import CommandLine |
39 from logilab.common.clcommands import CommandLine |
42 from logilab.common.shellutils import ASK |
40 from logilab.common.shellutils import ASK |
43 from logilab.common.configuration import merge_options |
41 from logilab.common.configuration import merge_options |
44 from logilab.common.decorators import clear_cache |
42 from logilab.common.decorators import clear_cache |
45 |
43 |
46 from cubicweb import ConfigurationError, ExecutionError, BadCommandUsage |
44 from cubicweb import ConfigurationError, ExecutionError, BadCommandUsage |
47 from cubicweb.cwconfig import CubicWebConfiguration as cwcfg, CONFIGURATIONS |
45 from cubicweb.cwconfig import CubicWebConfiguration as cwcfg, CONFIGURATIONS |
48 from cubicweb.toolsutils import Command, rm, create_dir, underline_title |
46 from cubicweb.toolsutils import Command, rm, create_dir, underline_title |
49 from cubicweb.__pkginfo__ import version |
47 from cubicweb.__pkginfo__ import version as cw_version |
50 |
48 |
51 # don't check duplicated commands, it occurs when reloading site_cubicweb |
49 # don't check duplicated commands, it occurs when reloading site_cubicweb |
52 CWCTL = CommandLine('cubicweb-ctl', 'The CubicWeb swiss-knife.', |
50 CWCTL = CommandLine('cubicweb-ctl', 'The CubicWeb swiss-knife.', |
53 version=version, check_duplicated_command=False) |
51 version=cw_version, check_duplicated_command=False) |
54 |
52 |
55 |
53 |
56 def wait_process_end(pid, maxtry=10, waittime=1): |
54 def wait_process_end(pid, maxtry=10, waittime=1): |
57 """wait for a process to actually die""" |
55 """wait for a process to actually die""" |
58 import signal |
56 import signal |
133 |
131 |
134 def run_args(self, args, askconfirm): |
132 def run_args(self, args, askconfirm): |
135 status = 0 |
133 status = 0 |
136 for appid in args: |
134 for appid in args: |
137 if askconfirm: |
135 if askconfirm: |
138 print('*'*72) |
136 print('*' * 72) |
139 if not ASK.confirm('%s instance %r ?' % (self.name, appid)): |
137 if not ASK.confirm('%s instance %r ?' % (self.name, appid)): |
140 continue |
138 continue |
141 try: |
139 try: |
142 status = max(status, self.run_arg(appid)) |
140 status = max(status, self.run_arg(appid)) |
143 except (KeyboardInterrupt, SystemExit): |
141 except (KeyboardInterrupt, SystemExit): |
144 sys.stderr.write('%s aborted\n' % self.name) |
142 sys.stderr.write('%s aborted\n' % self.name) |
145 return 2 # specific error code |
143 return 2 # specific error code |
146 sys.exit(status) |
144 sys.exit(status) |
147 |
145 |
148 def run_arg(self, appid): |
146 def run_arg(self, appid): |
149 cmdmeth = getattr(self, '%s_instance' % self.name) |
147 cmdmeth = getattr(self, '%s_instance' % self.name) |
150 try: |
148 try: |
151 status = cmdmeth(appid) or 0 |
149 status = cmdmeth(appid) or 0 |
152 except (ExecutionError, ConfigurationError) as ex: |
150 except (ExecutionError, ConfigurationError) as ex: |
153 sys.stderr.write('instance %s not %s: %s\n' % ( |
151 sys.stderr.write('instance %s not %s: %s\n' % ( |
154 appid, self.actionverb, ex)) |
152 appid, self.actionverb, ex)) |
155 status = 4 |
153 status = 4 |
156 except Exception as ex: |
154 except Exception as ex: |
157 import traceback |
155 import traceback |
158 traceback.print_exc() |
156 traceback.print_exc() |
159 sys.stderr.write('instance %s not %s: %s\n' % ( |
157 sys.stderr.write('instance %s not %s: %s\n' % ( |
160 appid, self.actionverb, ex)) |
158 appid, self.actionverb, ex)) |
161 status = 8 |
159 status = 8 |
162 return status |
160 return status |
|
161 |
163 |
162 |
164 class InstanceCommandFork(InstanceCommand): |
163 class InstanceCommandFork(InstanceCommand): |
165 """Same as `InstanceCommand`, but command is forked in a new environment |
164 """Same as `InstanceCommand`, but command is forked in a new environment |
166 for each argument |
165 for each argument |
167 """ |
166 """ |
168 |
167 |
169 def run_args(self, args, askconfirm): |
168 def run_args(self, args, askconfirm): |
170 if len(args) > 1: |
169 if len(args) > 1: |
171 forkcmd = ' '.join(w for w in sys.argv if not w in args) |
170 forkcmd = ' '.join(w for w in sys.argv if w not in args) |
172 else: |
171 else: |
173 forkcmd = None |
172 forkcmd = None |
174 for appid in args: |
173 for appid in args: |
175 if askconfirm: |
174 if askconfirm: |
176 print('*'*72) |
175 print('*' * 72) |
177 if not ASK.confirm('%s instance %r ?' % (self.name, appid)): |
176 if not ASK.confirm('%s instance %r ?' % (self.name, appid)): |
178 continue |
177 continue |
179 if forkcmd: |
178 if forkcmd: |
180 status = system('%s %s' % (forkcmd, appid)) |
179 status = system('%s %s' % (forkcmd, appid)) |
181 if status: |
180 if status: |
287 |
286 |
288 if mode == 'all': |
287 if mode == 'all': |
289 # configuration management problem solving |
288 # configuration management problem solving |
290 cfgpb.solve() |
289 cfgpb.solve() |
291 if cfgpb.warnings: |
290 if cfgpb.warnings: |
292 print('Warnings:\n', '\n'.join('* '+txt for txt in cfgpb.warnings)) |
291 print('Warnings:\n', '\n'.join('* ' + txt for txt in cfgpb.warnings)) |
293 if cfgpb.errors: |
292 if cfgpb.errors: |
294 print('Errors:') |
293 print('Errors:') |
295 for op, cube, version, src in cfgpb.errors: |
294 for op, cube, version, src in cfgpb.errors: |
296 if op == 'add': |
295 if op == 'add': |
297 print('* cube', cube, end=' ') |
296 print('* cube', cube, end=' ') |
298 if version: |
297 if version: |
299 print(' version', version, end=' ') |
298 print(' version', version, end=' ') |
300 print('is not installed, but required by %s' % src) |
299 print('is not installed, but required by %s' % src) |
301 else: |
300 else: |
302 print('* cube %s version %s is installed, but version %s is required by %s' % ( |
301 print( |
303 cube, cfgpb.cubes[cube], version, src)) |
302 '* cube %s version %s is installed, but version %s is required by %s' |
|
303 % (cube, cfgpb.cubes[cube], version, src) |
|
304 ) |
|
305 |
304 |
306 |
305 def check_options_consistency(config): |
307 def check_options_consistency(config): |
306 if config.automatic and config.config_level > 0: |
308 if config.automatic and config.config_level > 0: |
307 raise BadCommandUsage('--automatic and --config-level should not be ' |
309 raise BadCommandUsage('--automatic and --config-level should not be ' |
308 'used together') |
310 'used together') |
|
311 |
309 |
312 |
310 class CreateInstanceCommand(Command): |
313 class CreateInstanceCommand(Command): |
311 """Create an instance from a cube. This is a unified |
314 """Create an instance from a cube. This is a unified |
312 command which can handle web / server / all-in-one installation |
315 command which can handle web / server / all-in-one installation |
313 according to available parts of the software library and of the |
316 according to available parts of the software library and of the |
323 name = 'create' |
326 name = 'create' |
324 arguments = '<cube> <instance>' |
327 arguments = '<cube> <instance>' |
325 min_args = max_args = 2 |
328 min_args = max_args = 2 |
326 options = ( |
329 options = ( |
327 ('automatic', |
330 ('automatic', |
328 {'short': 'a', 'action' : 'store_true', |
331 {'short': 'a', 'action': 'store_true', |
329 'default': False, |
332 'default': False, |
330 'help': 'automatic mode: never ask and use default answer to every ' |
333 'help': 'automatic mode: never ask and use default answer to every ' |
331 'question. this may require that your login match a database super ' |
334 'question. this may require that your login match a database super ' |
332 'user (allowed to create database & all).', |
335 'user (allowed to create database & all).', |
333 }), |
336 }), |
334 ('config-level', |
337 ('config-level', |
335 {'short': 'l', 'type' : 'int', 'metavar': '<level>', |
338 {'short': 'l', 'type': 'int', 'metavar': '<level>', |
336 'default': 0, |
339 'default': 0, |
337 'help': 'configuration level (0..2): 0 will ask for essential ' |
340 'help': 'configuration level (0..2): 0 will ask for essential ' |
338 'configuration parameters only while 2 will ask for all parameters', |
341 'configuration parameters only while 2 will ask for all parameters', |
339 }), |
342 }), |
340 ('config', |
343 ('config', |
341 {'short': 'c', 'type' : 'choice', 'metavar': '<install type>', |
344 {'short': 'c', 'type': 'choice', 'metavar': '<install type>', |
342 'choices': ('all-in-one', 'repository', 'pyramid'), |
345 'choices': ('all-in-one', 'repository', 'pyramid'), |
343 'default': 'all-in-one', |
346 'default': 'all-in-one', |
344 'help': 'installation type, telling which part of an instance ' |
347 'help': 'installation type, telling which part of an instance ' |
345 'should be installed. You can list available configurations using the' |
348 'should be installed. You can list available configurations using the' |
346 ' "list" command. Default to "all-in-one", e.g. an installation ' |
349 ' "list" command. Default to "all-in-one", e.g. an installation ' |
374 print(ex) |
377 print(ex) |
375 print('\navailable cubes:', end=' ') |
378 print('\navailable cubes:', end=' ') |
376 print(', '.join(available_cube_names(cwcfg))) |
379 print(', '.join(available_cube_names(cwcfg))) |
377 return |
380 return |
378 # create the registry directory for this instance |
381 # create the registry directory for this instance |
379 print('\n'+underline_title('Creating the instance %s' % appid)) |
382 print('\n' + underline_title('Creating the instance %s' % appid)) |
380 create_dir(config.apphome) |
383 create_dir(config.apphome) |
381 # cubicweb-ctl configuration |
384 # cubicweb-ctl configuration |
382 if not self.config.automatic: |
385 if not self.config.automatic: |
383 print('\n'+underline_title('Configuring the instance (%s.conf)' |
386 print('\n' + underline_title('Configuring the instance (%s.conf)' |
384 % configname)) |
387 % configname)) |
385 config.input_config('main', self.config.config_level) |
388 config.input_config('main', self.config.config_level) |
386 # configuration'specific stuff |
389 # configuration'specific stuff |
387 print() |
390 print() |
388 helper.bootstrap(cubes, self.config.automatic, self.config.config_level) |
391 helper.bootstrap(cubes, self.config.automatic, self.config.config_level) |
389 # input for cubes specific options |
392 # input for cubes specific options |
404 langs = [lang for lang, _ in i18n.available_catalogs(join(templdirs[0], 'i18n'))] |
407 langs = [lang for lang, _ in i18n.available_catalogs(join(templdirs[0], 'i18n'))] |
405 errors = config.i18ncompile(langs) |
408 errors = config.i18ncompile(langs) |
406 if errors: |
409 if errors: |
407 print('\n'.join(errors)) |
410 print('\n'.join(errors)) |
408 if self.config.automatic \ |
411 if self.config.automatic \ |
409 or not ASK.confirm('error while compiling message catalogs, ' |
412 or not ASK.confirm('error while compiling message catalogs, ' |
410 'continue anyway ?'): |
413 'continue anyway ?'): |
411 print('creation not completed') |
414 print('creation not completed') |
412 return |
415 return |
413 # create the additional data directory for this instance |
416 # create the additional data directory for this instance |
414 if config.appdatahome != config.apphome: # true in dev mode |
417 if config.appdatahome != config.apphome: # true in dev mode |
415 create_dir(config.appdatahome) |
418 create_dir(config.appdatahome) |
416 create_dir(join(config.appdatahome, 'backup')) |
419 create_dir(join(config.appdatahome, 'backup')) |
417 if config['uid']: |
420 if config['uid']: |
418 from logilab.common.shellutils import chown |
421 from logilab.common.shellutils import chown |
419 # this directory should be owned by the uid of the server process |
422 # this directory should be owned by the uid of the server process |
468 """ |
471 """ |
469 name = 'start' |
472 name = 'start' |
470 actionverb = 'started' |
473 actionverb = 'started' |
471 options = ( |
474 options = ( |
472 ("debug", |
475 ("debug", |
473 {'short': 'D', 'action' : 'store_true', |
476 {'short': 'D', 'action': 'store_true', |
474 'help': 'start server in debug mode.'}), |
477 'help': 'start server in debug mode.'}), |
475 ("force", |
478 ("force", |
476 {'short': 'f', 'action' : 'store_true', |
479 {'short': 'f', 'action': 'store_true', |
477 'default': False, |
480 'default': False, |
478 'help': 'start the instance even if it seems to be already \ |
481 'help': 'start the instance even if it seems to be already \ |
479 running.'}), |
482 running.'}), |
480 ('profile', |
483 ('profile', |
481 {'short': 'P', 'type' : 'string', 'metavar': '<stat file>', |
484 {'short': 'P', 'type': 'string', 'metavar': '<stat file>', |
482 'default': None, |
485 'default': None, |
483 'help': 'profile code and use the specified file to store stats', |
486 'help': 'profile code and use the specified file to store stats', |
484 }), |
487 }), |
485 ('loglevel', |
488 ('loglevel', |
486 {'short': 'l', 'type' : 'choice', 'metavar': '<log level>', |
489 {'short': 'l', 'type': 'choice', 'metavar': '<log level>', |
487 'default': None, 'choices': ('debug', 'info', 'warning', 'error'), |
490 'default': None, 'choices': ('debug', 'info', 'warning', 'error'), |
488 'help': 'debug if -D is set, error otherwise', |
491 'help': 'debug if -D is set, error otherwise', |
489 }), |
492 }), |
490 ('param', |
493 ('param', |
491 {'short': 'p', 'type' : 'named', 'metavar' : 'key1:value1,key2:value2', |
494 {'short': 'p', 'type': 'named', 'metavar': 'key1:value1,key2:value2', |
492 'default': {}, |
495 'default': {}, |
493 'help': 'override <key> configuration file option with <value>.', |
496 'help': 'override <key> configuration file option with <value>.', |
494 }), |
497 }), |
495 ) |
498 ) |
496 |
499 |
497 def start_instance(self, appid): |
500 def start_instance(self, appid): |
498 """start the instance's server""" |
501 """start the instance's server""" |
499 try: |
502 try: |
500 import twisted # noqa |
503 import twisted # noqa |
650 """ |
654 """ |
651 name = 'upgrade' |
655 name = 'upgrade' |
652 actionverb = 'upgraded' |
656 actionverb = 'upgraded' |
653 options = InstanceCommand.options + ( |
657 options = InstanceCommand.options + ( |
654 ('force-cube-version', |
658 ('force-cube-version', |
655 {'short': 't', 'type' : 'named', 'metavar': 'cube1:X.Y.Z,cube2:X.Y.Z', |
659 {'short': 't', 'type': 'named', 'metavar': 'cube1:X.Y.Z,cube2:X.Y.Z', |
656 'default': None, |
660 'default': None, |
657 'help': 'force migration from the indicated version for the specified cube(s).'}), |
661 'help': 'force migration from the indicated version for the specified cube(s).'}), |
658 |
662 |
659 ('force-cubicweb-version', |
663 ('force-cubicweb-version', |
660 {'short': 'e', 'type' : 'string', 'metavar': 'X.Y.Z', |
664 {'short': 'e', 'type': 'string', 'metavar': 'X.Y.Z', |
661 'default': None, |
665 'default': None, |
662 'help': 'force migration from the indicated cubicweb version.'}), |
666 'help': 'force migration from the indicated cubicweb version.'}), |
663 |
667 |
664 ('fs-only', |
668 ('fs-only', |
665 {'short': 's', 'action' : 'store_true', |
669 {'short': 's', 'action': 'store_true', |
666 'default': False, |
670 'default': False, |
667 'help': 'only upgrade files on the file system, not the database.'}), |
671 'help': 'only upgrade files on the file system, not the database.'}), |
668 |
672 |
669 ('no-config-update', |
673 ('no-config-update', |
670 {'short': 'C', 'action': 'store_true', |
674 {'short': 'C', 'action': 'store_true', |
671 'default': False, |
675 'default': False, |
672 'help': 'do NOT update config file if set.'}), |
676 'help': 'do NOT update config file if set.'}), |
673 |
677 |
674 ('nostartstop', |
678 ('nostartstop', |
675 {'short': 'n', 'action' : 'store_true', |
679 {'short': 'n', 'action': 'store_true', |
676 'default': False, |
680 'default': False, |
677 'help': 'don\'t try to stop instance before migration and to restart it after.'}), |
681 'help': 'don\'t try to stop instance before migration and to restart it after.'}), |
678 |
682 |
679 ('verbosity', |
683 ('verbosity', |
680 {'short': 'v', 'type' : 'int', 'metavar': '<0..2>', |
684 {'short': 'v', 'type': 'int', 'metavar': '<0..2>', |
681 'default': 1, |
685 'default': 1, |
682 'help': "0: no confirmation, 1: only main commands confirmed, 2 ask \ |
686 'help': "0: no confirmation, 1: only main commands confirmed, 2 ask \ |
683 for everything."}), |
687 for everything."}), |
684 |
688 |
685 ('backup-db', |
689 ('backup-db', |
686 {'short': 'b', 'type' : 'yn', 'metavar': '<y or n>', |
690 {'short': 'b', 'type': 'yn', 'metavar': '<y or n>', |
687 'default': None, |
691 'default': None, |
688 'help': "Backup the instance database before upgrade.\n"\ |
692 'help': "Backup the instance database before upgrade.\n" |
689 "If the option is ommitted, confirmation will be ask.", |
693 "If the option is ommitted, confirmation will be ask.", |
690 }), |
694 }), |
691 |
695 |
692 ('ext-sources', |
696 ('ext-sources', |
693 {'short': 'E', 'type' : 'csv', 'metavar': '<sources>', |
697 {'short': 'E', 'type': 'csv', 'metavar': '<sources>', |
694 'default': None, |
698 'default': None, |
695 'help': "For multisources instances, specify to which sources the \ |
699 'help': "For multisources instances, specify to which sources the \ |
696 repository should connect to for upgrading. When unspecified or 'migration' is \ |
700 repository should connect to for upgrading. When unspecified or 'migration' is \ |
697 given, appropriate sources for migration will be automatically selected \ |
701 given, appropriate sources for migration will be automatically selected \ |
698 (recommended). If 'all' is given, will connect to all defined sources.", |
702 (recommended). If 'all' is given, will connect to all defined sources.", |
699 }), |
703 }), |
700 ) |
704 ) |
701 |
705 |
702 def upgrade_instance(self, appid): |
706 def upgrade_instance(self, appid): |
703 print('\n' + underline_title('Upgrading the instance %s' % appid)) |
707 print('\n' + underline_title('Upgrading the instance %s' % appid)) |
704 from logilab.common.changelog import Version |
708 from logilab.common.changelog import Version |
705 config = cwcfg.config_for(appid) |
709 config = cwcfg.config_for(appid) |
706 instance_running = exists(config['pid-file']) |
710 instance_running = exists(config['pid-file']) |
707 config.repairing = True # notice we're not starting the server |
711 config.repairing = True # notice we're not starting the server |
708 config.verbosity = self.config.verbosity |
712 config.verbosity = self.config.verbosity |
709 set_sources_mode = getattr(config, 'set_sources_mode', None) |
713 set_sources_mode = getattr(config, 'set_sources_mode', None) |
710 if set_sources_mode is not None: |
714 if set_sources_mode is not None: |
711 set_sources_mode(self.config.ext_sources or ('migration',)) |
715 set_sources_mode(self.config.ext_sources or ('migration',)) |
712 # get instance and installed versions for the server and the componants |
716 # get instance and installed versions for the server and the componants |
802 config.quick_start = True |
806 config.quick_start = True |
803 if hasattr(config, 'set_sources_mode'): |
807 if hasattr(config, 'set_sources_mode'): |
804 config.set_sources_mode(('migration',)) |
808 config.set_sources_mode(('migration',)) |
805 vcconf = config.repository().get_versions() |
809 vcconf = config.repository().get_versions() |
806 for key in sorted(vcconf): |
810 for key in sorted(vcconf): |
807 print(key+': %s.%s.%s' % vcconf[key]) |
811 print(key + ': %s.%s.%s' % vcconf[key]) |
|
812 |
808 |
813 |
809 class ShellCommand(Command): |
814 class ShellCommand(Command): |
810 """Run an interactive migration shell on an instance. This is a python shell |
815 """Run an interactive migration shell on an instance. This is a python shell |
811 with enhanced migration commands predefined in the namespace. An additional |
816 with enhanced migration commands predefined in the namespace. An additional |
812 argument may be given corresponding to a file containing commands to execute |
817 argument may be given corresponding to a file containing commands to execute |
825 name = 'shell' |
830 name = 'shell' |
826 arguments = '<instance> [batch command file(s)] [-- <script arguments>]' |
831 arguments = '<instance> [batch command file(s)] [-- <script arguments>]' |
827 min_args = 1 |
832 min_args = 1 |
828 options = ( |
833 options = ( |
829 ('system-only', |
834 ('system-only', |
830 {'short': 'S', 'action' : 'store_true', |
835 {'short': 'S', 'action': 'store_true', |
831 'help': 'only connect to the system source when the instance is ' |
836 'help': 'only connect to the system source when the instance is ' |
832 'using multiple sources. You can\'t use this option and the ' |
837 'using multiple sources. You can\'t use this option and the ' |
833 '--ext-sources option at the same time.', |
838 '--ext-sources option at the same time.', |
834 'group': 'local' |
839 'group': 'local' |
835 }), |
840 }), |
836 |
841 |
837 ('ext-sources', |
842 ('ext-sources', |
838 {'short': 'E', 'type' : 'csv', 'metavar': '<sources>', |
843 {'short': 'E', 'type': 'csv', 'metavar': '<sources>', |
839 'help': "For multisources instances, specify to which sources the \ |
844 'help': "For multisources instances, specify to which sources the \ |
840 repository should connect to for upgrading. When unspecified or 'all' given, \ |
845 repository should connect to for upgrading. When unspecified or 'all' given, \ |
841 will connect to all defined sources. If 'migration' is given, appropriate \ |
846 will connect to all defined sources. If 'migration' is given, appropriate \ |
842 sources for migration will be automatically selected.", |
847 sources for migration will be automatically selected.", |
843 'group': 'local' |
848 'group': 'local' |
844 }), |
849 }), |
845 |
850 |
846 ('force', |
851 ('force', |
847 {'short': 'f', 'action' : 'store_true', |
852 {'short': 'f', 'action': 'store_true', |
848 'help': 'don\'t check instance is up to date.', |
853 'help': 'don\'t check instance is up to date.', |
849 'group': 'local' |
854 'group': 'local' |
850 }), |
855 }), |
851 |
856 |
852 ) |
857 ) |
853 |
858 |
854 def _get_mih(self, appid): |
859 def _get_mih(self, appid): |
855 """ returns migration context handler & shutdown function """ |
860 """ returns migration context handler & shutdown function """ |
856 config = cwcfg.config_for(appid) |
861 config = cwcfg.config_for(appid) |
857 if self.config.ext_sources: |
862 if self.config.ext_sources: |
928 def run(self, args): |
933 def run(self, args): |
929 """run the command with its specific arguments""" |
934 """run the command with its specific arguments""" |
930 for cube in cwcfg.available_cubes(): |
935 for cube in cwcfg.available_cubes(): |
931 print(cube) |
936 print(cube) |
932 |
937 |
|
938 |
933 class ConfigureInstanceCommand(InstanceCommand): |
939 class ConfigureInstanceCommand(InstanceCommand): |
934 """Configure instance. |
940 """Configure instance. |
935 |
941 |
936 <instance>... |
942 <instance>... |
937 identifier of the instance to configure. |
943 identifier of the instance to configure. |
938 """ |
944 """ |
939 name = 'configure' |
945 name = 'configure' |
940 actionverb = 'configured' |
946 actionverb = 'configured' |
941 |
947 |
942 options = merge_options(InstanceCommand.options + |
948 options = merge_options( |
943 (('param', |
949 InstanceCommand.options + ( |
944 {'short': 'p', 'type' : 'named', 'metavar' : 'key1:value1,key2:value2', |
950 ('param', |
945 'default': None, |
951 {'short': 'p', 'type': 'named', 'metavar': 'key1:value1,key2:value2', |
946 'help': 'set <key> to <value> in configuration file.', |
952 'default': None, |
947 }), |
953 'help': 'set <key> to <value> in configuration file.'}), |
948 )) |
954 ), |
|
955 ) |
949 |
956 |
950 def configure_instance(self, appid): |
957 def configure_instance(self, appid): |
951 if self.config.param is not None: |
958 if self.config.param is not None: |
952 appcfg = cwcfg.config_for(appid) |
959 appcfg = cwcfg.config_for(appid) |
953 for key, value in self.config.param.items(): |
960 for key, value in self.config.param.items(): |
954 try: |
961 try: |
955 appcfg.global_set_option(key, value) |
962 appcfg.global_set_option(key, value) |
956 except KeyError: |
963 except KeyError: |
957 raise ConfigurationError('unknown configuration key "%s" for mode %s' % (key, appcfg.name)) |
964 raise ConfigurationError( |
|
965 'unknown configuration key "%s" for mode %s' % (key, appcfg.name)) |
958 appcfg.save() |
966 appcfg.save() |
959 |
967 |
960 |
968 |
961 # WSGI ######### |
969 # WSGI ######### |
962 |
970 |