[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
--- 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 @@
<cube>
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')
<instance>
an identifier for the instance to create
"""
@@ -317,28 +322,34 @@
arguments = '<cube> <instance>'
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': '<level>',
'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': '<install type>',
'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':
--- 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.
--- 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'
--- 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 = '<instance>'
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': '<level>',
+ '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': '<y or n>',
'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': '<auto>',
- '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 = '<instance>'
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):
--- 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.
--- 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"""