# HG changeset patch # User Sylvain Thénault # Date 1301476641 -7200 # Node ID ba51dac1115da19cafdf0cf674f4c4ee3647462e # Parent 20807d3d7cf6a9fac6cacb5376bf152c49cba85b [c-c create] unification of c-c create and its subcommands handling * create/db-create/db-init uniformly accept --automatic and --config-level options, properly passed along the way * --automatic option fixed so it doesn't need yes or no argument * closes ##1537265 on the way diff -r 20807d3d7cf6 -r ba51dac1115d cwctl.py --- a/cwctl.py Wed Mar 30 11:08:15 2011 +0200 +++ b/cwctl.py Wed Mar 30 11:17:21 2011 +0200 @@ -300,6 +300,11 @@ print '* cube %s version %s is installed, but version %s is required by %s' % ( cube, cfgpb.cubes[cube], version, src) +def check_options_consistency(config): + if config.automatic and config.config_level > 0: + raise BadCommandUsage('--automatic and --config-level should not be ' + 'used together') + class CreateInstanceCommand(Command): """Create an instance from a cube. This is an unified command which can handle web / server / all-in-one installation @@ -309,7 +314,7 @@ the name of cube to use (list available cube names using the "list" command). You can use several cubes by separating - them using comma (e.g. 'jpl,eemail') + them using comma (e.g. 'jpl,email') an identifier for the instance to create """ @@ -317,28 +322,34 @@ arguments = ' ' min_args = max_args = 2 options = ( - ("config-level", + ('automatic', + {'short': 'a', 'action' : 'store_true', + 'default': False, + 'help': 'automatic mode: never ask and use default answer to every ' + 'question. this may require that your login match a database super ' + 'user (allowed to create database & all).', + }), + ('config-level', {'short': 'l', 'type' : 'int', 'metavar': '', 'default': 0, - 'help': 'configuration level (0..2): 0 will ask for essential \ -configuration parameters only while 2 will ask for all parameters', - } - ), - ("config", + 'help': 'configuration level (0..2): 0 will ask for essential ' + 'configuration parameters only while 2 will ask for all parameters', + }), + ('config', {'short': 'c', 'type' : 'choice', 'metavar': '', 'choices': ('all-in-one', 'repository', 'twisted'), 'default': 'all-in-one', - 'help': 'installation type, telling which part of an instance \ -should be installed. You can list available configurations using the "list" \ -command. Default to "all-in-one", e.g. an installation embedding both the RQL \ -repository and the web server.', - } - ), + 'help': 'installation type, telling which part of an instance ' + 'should be installed. You can list available configurations using the' + ' "list" command. Default to "all-in-one", e.g. an installation ' + 'embedding both the RQL repository and the web server.', + }), ) def run(self, args): """run the command with its specific arguments""" from logilab.common.textutils import splitstrip + check_options_consistency(self.config) configname = self.config.config cubes, appid = args cubes = splitstrip(cubes) @@ -360,17 +371,19 @@ print '\n'+underline_title('Creating the instance %s' % appid) create_dir(config.apphome) # cubicweb-ctl configuration - print '\n'+underline_title('Configuring the instance (%s.conf)' % configname) - config.input_config('main', self.config.config_level) + if not self.config.automatic: + print '\n'+underline_title('Configuring the instance (%s.conf)' + % configname) + config.input_config('main', self.config.config_level) # configuration'specific stuff print - helper.bootstrap(cubes, self.config.config_level) + helper.bootstrap(cubes, self.config.automatic, self.config.config_level) # input for cubes specific options sections = set(sect.lower() for sect, opt, odict in config.all_options() if 'type' in odict and odict.get('level') <= self.config.config_level) for section in sections: - if section not in ('main', 'email', 'pyro'): + if section not in ('main', 'email', 'pyro', 'web'): print '\n' + underline_title('%s options' % section) config.input_config(section, self.config.config_level) # write down configuration @@ -385,8 +398,9 @@ errors = config.i18ncompile(langs) if errors: print '\n'.join(errors) - if not ASK.confirm('error while compiling message catalogs, ' - 'continue anyway ?'): + if self.config.automatic \ + or not ASK.confirm('error while compiling message catalogs, ' + 'continue anyway ?'): print 'creation not completed' return # create the additional data directory for this instance @@ -399,7 +413,7 @@ print 'set %s as owner of the data directory' % config['uid'] chown(config.appdatahome, config['uid']) print '\n-> creation done for %r.\n' % config.apphome - helper.postcreate() + helper.postcreate(self.config.automatic) def _handle_win32(self, config, appid): if sys.platform != 'win32': diff -r 20807d3d7cf6 -r ba51dac1115d dbapi.py --- a/dbapi.py Wed Mar 30 11:08:15 2011 +0200 +++ b/dbapi.py Wed Mar 30 11:17:21 2011 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. diff -r 20807d3d7cf6 -r ba51dac1115d etwist/twctl.py --- a/etwist/twctl.py Wed Mar 30 11:08:15 2011 +0200 +++ b/etwist/twctl.py Wed Mar 30 11:17:21 2011 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -51,10 +51,10 @@ """ cfgname = 'all-in-one' - def bootstrap(self, cubes, inputlevel=0): + def bootstrap(self, cubes, automatic=False, inputlevel=0): """bootstrap this configuration""" - serverctl.RepositoryCreateHandler.bootstrap(self, cubes, inputlevel) - TWCreateHandler.bootstrap(self, cubes, inputlevel) + serverctl.RepositoryCreateHandler.bootstrap(self, cubes, automatic, inputlevel) + TWCreateHandler.bootstrap(self, cubes, automatic, inputlevel) class AllInOneStartHandler(TWStartHandler): cmdname = 'start' diff -r 20807d3d7cf6 -r ba51dac1115d server/serverctl.py --- a/server/serverctl.py Wed Mar 30 11:08:15 2011 +0200 +++ b/server/serverctl.py Wed Mar 30 11:17:21 2011 +0200 @@ -27,11 +27,11 @@ from logilab.common import nullobject from logilab.common.configuration import Configuration -from logilab.common.shellutils import ASK +from logilab.common.shellutils import ASK, generate_password from cubicweb import AuthenticationError, ExecutionError, ConfigurationError from cubicweb.toolsutils import Command, CommandHandler, underline_title -from cubicweb.cwctl import CWCTL +from cubicweb.cwctl import CWCTL, check_options_consistency from cubicweb.server import SOURCE_TYPES from cubicweb.server.serverconfig import ( USER_OPTIONS, ServerConfiguration, SourceConfiguration, @@ -154,38 +154,49 @@ cmdname = 'create' cfgname = 'repository' - def bootstrap(self, cubes, inputlevel=0): + def bootstrap(self, cubes, automatic=False, inputlevel=0): """create an instance by copying files from the given cube and by asking information necessary to build required configuration files """ config = self.config - print underline_title('Configuring the repository') - config.input_config('email', inputlevel) - # ask for pyro configuration if pyro is activated and we're not using a - # all-in-one config, in which case this is done by the web side command - # handler - if config.pyro_enabled() and config.name != 'all-in-one': - config.input_config('pyro', inputlevel) - print '\n'+underline_title('Configuring the sources') + if not automatic: + print underline_title('Configuring the repository') + config.input_config('email', inputlevel) + # ask for pyro configuration if pyro is activated and we're not + # using a all-in-one config, in which case this is done by the web + # side command handler + if config.pyro_enabled() and config.name != 'all-in-one': + config.input_config('pyro', inputlevel) + print '\n'+underline_title('Configuring the sources') sourcesfile = config.sources_file() - # XXX hack to make Method('default_instance_id') usable in db option - # defs (in native.py) + # hack to make Method('default_instance_id') usable in db option defs + # (in native.py) sconfig = SourceConfiguration(config, options=SOURCE_TYPES['native'].options) - sconfig.input_config(inputlevel=inputlevel) + if not automatic: + sconfig.input_config(inputlevel=inputlevel) + print sourcescfg = {'system': sconfig} - print - sconfig = Configuration(options=USER_OPTIONS) - sconfig.input_config(inputlevel=inputlevel) + if automatic: + # XXX modify a copy + password = generate_password() + print 'Administration account is admin / %s' % password + USER_OPTIONS[1][1]['default'] = password + sconfig = Configuration(options=USER_OPTIONS) + else: + sconfig = Configuration(options=USER_OPTIONS) + sconfig.input_config(inputlevel=inputlevel) sourcescfg['admin'] = sconfig config.write_sources_file(sourcescfg) # remember selected cubes for later initialization of the database config.write_bootstrap_cubes_file(cubes) - def postcreate(self): - if ASK.confirm('Run db-create to create the system database ?'): - verbosity = (self.config.mode == 'installed') and 'y' or 'n' - CWCTL.run(['db-create', self.config.appid]) + def postcreate(self, automatic=False, inputlevel=0): + if automatic: + CWCTL.run(['db-create', '--automatic', self.config.appid]) + elif ASK.confirm('Run db-create to create the system database ?'): + CWCTL.run(['db-create', '--config-level', str(inputlevel), + self.config.appid]) else: print ('-> nevermind, you can do it later with ' '"cubicweb-ctl db-create %s".' % self.config.appid) @@ -293,27 +304,30 @@ arguments = '' min_args = max_args = 1 options = ( + ('automatic', + {'short': 'a', 'action' : 'store_true', + 'default': False, + 'help': 'automatic mode: never ask and use default answer to every ' + 'question. this may require that your login match a database super ' + 'user (allowed to create database & all).', + }), + ('config-level', + {'short': 'l', 'type' : 'int', 'metavar': '', + 'default': 0, + 'help': 'configuration level (0..2): 0 will ask for essential ' + 'configuration parameters only while 2 will ask for all parameters', + }), ('create-db', {'short': 'c', 'type': 'yn', 'metavar': '', 'default': True, - 'help': 'create the database (yes by default)'}), - ('quiet', - {'short': 'q', 'action' : 'store_true', - 'default': False, - 'help': 'be quiet. Suppose database user in the sources file is a ' - 'super user and don\'t ask for alternate login.', + 'help': 'create the database (yes by default)' }), - ('automatic', - {'short': 'a', 'type' : 'yn', 'metavar': '', - 'default': 'n', - 'help': 'automatic mode: never ask and use default answer to every question', - } - ), ) + def run(self, args): """run the command with its specific arguments""" from logilab.database import get_db_helper - quiet = self.get('quiet') + check_options_consistency(self.config) automatic = self.get('automatic') appid = args.pop() config = ServerConfiguration.config_for(appid) @@ -330,7 +344,7 @@ print '\n'+underline_title('Creating the system database') # connect on the dbms system base to create our base dbcnx = _db_sys_cnx(source, 'CREATE/DROP DATABASE and / or USER', - interactive=not quiet) + interactive=not automatic) cursor = dbcnx.cursor() try: if helper.users_support: @@ -343,6 +357,8 @@ if automatic or ASK.confirm('Database %s already exists -- do you want to drop it ?' % dbname): cursor.execute('DROP DATABASE %s' % dbname) else: + print ('you may want to run "cubicweb-ctl db-init ' + '--drop %s" manually to continue.' % config.appid) return createdb(helper, source, dbcnx, cursor) dbcnx.commit() @@ -351,7 +367,7 @@ dbcnx.rollback() raise cnx = system_source_cnx(source, special_privs='CREATE LANGUAGE', - interactive=not quiet) + interactive=not automatic) cursor = cnx.cursor() helper.init_fti_extensions(cursor) # postgres specific stuff @@ -364,8 +380,12 @@ cnx.commit() print '-> database for instance %s created and necessary extensions installed.' % appid print - if automatic or ASK.confirm('Run db-init to initialize the system database ?'): - CWCTL.run(['db-init', config.appid]) + if automatic: + CWCTL.run(['db-init', '--automatic', '--config-level', '0', + config.appid]) + elif ASK.confirm('Run db-init to initialize the system database ?'): + CWCTL.run(['db-init', '--config-level', + str(self.config.config_level), config.appid]) else: print ('-> nevermind, you can do it later with ' '"cubicweb-ctl db-init %s".' % config.appid) @@ -384,18 +404,27 @@ arguments = '' min_args = max_args = 1 options = ( + ('automatic', + {'short': 'a', 'action' : 'store_true', + 'default': False, + 'help': 'automatic mode: never ask and use default answer to every ' + 'question.', + }), + ('config-level', + {'short': 'l', 'type': 'int', 'default': 1, + 'help': 'level threshold for questions asked when configuring ' + 'another source' + }), ('drop', {'short': 'd', 'action': 'store_true', 'default': False, - 'help': 'insert drop statements to remove previously existant \ -tables, indexes... (no by default)'}), - ('config-level', - {'short': 'l', 'type': 'int', 'default': 1, - 'help': 'level threshold for questions asked when configuring another source' + 'help': 'insert drop statements to remove previously existant ' + 'tables, indexes... (no by default)' }), ) def run(self, args): + check_options_consistency(self.config) print '\n'+underline_title('Initializing the system database') from cubicweb.server import init_repository from logilab.database import get_connection @@ -416,8 +445,10 @@ 'the %s file. Resolve this first (error: %s).' % (config.sources_file(), str(ex).strip())) init_repository(config, drop=self.config.drop) - while ASK.confirm('Enter another source ?', default_is_yes=False): - CWCTL.run(['add-source', '--config-level', self.config.config_level, config.appid]) + if not self.config.automatic: + while ASK.confirm('Enter another source ?', default_is_yes=False): + CWCTL.run(['add-source', '--config-level', + str(self.config.config_level), config.appid]) class AddSourceCommand(Command): diff -r 20807d3d7cf6 -r ba51dac1115d utils.py --- a/utils.py Wed Mar 30 11:08:15 2011 +0200 +++ b/utils.py Wed Mar 30 11:17:21 2011 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. diff -r 20807d3d7cf6 -r ba51dac1115d web/webctl.py --- a/web/webctl.py Wed Mar 30 11:08:15 2011 +0200 +++ b/web/webctl.py Wed Mar 30 11:17:21 2011 +0200 @@ -28,16 +28,18 @@ class WebCreateHandler(CommandHandler): cmdname = 'create' - def bootstrap(self, cubes, inputlevel=0): + def bootstrap(self, cubes, automatic=False, inputlevel=0): """bootstrap this configuration""" - print '\n' + underline_title('Generic web configuration') - config = self.config - if config.repo_method == 'pyro' or config.pyro_enabled(): - print '\n' + underline_title('Pyro configuration') - config.input_config('pyro', inputlevel) - if ASK.confirm('Allow anonymous access ?', False): - config.global_set_option('anonymous-user', 'anon') - config.global_set_option('anonymous-password', 'anon') + if not automatic: + print '\n' + underline_title('Generic web configuration') + config = self.config + if config.repo_method == 'pyro' or config.pyro_enabled(): + print '\n' + underline_title('Pyro configuration') + config.input_config('pyro', inputlevel) + config.input_config('web', inputlevel) + if ASK.confirm('Allow anonymous access ?', False): + config.global_set_option('anonymous-user', 'anon') + config.global_set_option('anonymous-password', 'anon') - def postcreate(self): + def postcreate(self, *args, **kwargs): """hooks called once instance's initialization has been completed"""