298 print 'is not installed, but required by %s' % src |
298 print 'is not installed, but required by %s' % src |
299 else: |
299 else: |
300 print '* cube %s version %s is installed, but version %s is required by %s' % ( |
300 print '* cube %s version %s is installed, but version %s is required by %s' % ( |
301 cube, cfgpb.cubes[cube], version, src) |
301 cube, cfgpb.cubes[cube], version, src) |
302 |
302 |
|
303 def check_options_consistency(config): |
|
304 if config.automatic and config.config_level > 0: |
|
305 raise BadCommandUsage('--automatic and --config-level should not be ' |
|
306 'used together') |
|
307 |
303 class CreateInstanceCommand(Command): |
308 class CreateInstanceCommand(Command): |
304 """Create an instance from a cube. This is an unified |
309 """Create an instance from a cube. This is an unified |
305 command which can handle web / server / all-in-one installation |
310 command which can handle web / server / all-in-one installation |
306 according to available parts of the software library and of the |
311 according to available parts of the software library and of the |
307 desired cube. |
312 desired cube. |
308 |
313 |
309 <cube> |
314 <cube> |
310 the name of cube to use (list available cube names using |
315 the name of cube to use (list available cube names using |
311 the "list" command). You can use several cubes by separating |
316 the "list" command). You can use several cubes by separating |
312 them using comma (e.g. 'jpl,eemail') |
317 them using comma (e.g. 'jpl,email') |
313 <instance> |
318 <instance> |
314 an identifier for the instance to create |
319 an identifier for the instance to create |
315 """ |
320 """ |
316 name = 'create' |
321 name = 'create' |
317 arguments = '<cube> <instance>' |
322 arguments = '<cube> <instance>' |
318 min_args = max_args = 2 |
323 min_args = max_args = 2 |
319 options = ( |
324 options = ( |
320 ("config-level", |
325 ('automatic', |
|
326 {'short': 'a', 'action' : 'store_true', |
|
327 'default': False, |
|
328 'help': 'automatic mode: never ask and use default answer to every ' |
|
329 'question. this may require that your login match a database super ' |
|
330 'user (allowed to create database & all).', |
|
331 }), |
|
332 ('config-level', |
321 {'short': 'l', 'type' : 'int', 'metavar': '<level>', |
333 {'short': 'l', 'type' : 'int', 'metavar': '<level>', |
322 'default': 0, |
334 'default': 0, |
323 'help': 'configuration level (0..2): 0 will ask for essential \ |
335 'help': 'configuration level (0..2): 0 will ask for essential ' |
324 configuration parameters only while 2 will ask for all parameters', |
336 'configuration parameters only while 2 will ask for all parameters', |
325 } |
337 }), |
326 ), |
338 ('config', |
327 ("config", |
|
328 {'short': 'c', 'type' : 'choice', 'metavar': '<install type>', |
339 {'short': 'c', 'type' : 'choice', 'metavar': '<install type>', |
329 'choices': ('all-in-one', 'repository', 'twisted'), |
340 'choices': ('all-in-one', 'repository', 'twisted'), |
330 'default': 'all-in-one', |
341 'default': 'all-in-one', |
331 'help': 'installation type, telling which part of an instance \ |
342 'help': 'installation type, telling which part of an instance ' |
332 should be installed. You can list available configurations using the "list" \ |
343 'should be installed. You can list available configurations using the' |
333 command. Default to "all-in-one", e.g. an installation embedding both the RQL \ |
344 ' "list" command. Default to "all-in-one", e.g. an installation ' |
334 repository and the web server.', |
345 'embedding both the RQL repository and the web server.', |
335 } |
346 }), |
336 ), |
|
337 ) |
347 ) |
338 |
348 |
339 def run(self, args): |
349 def run(self, args): |
340 """run the command with its specific arguments""" |
350 """run the command with its specific arguments""" |
341 from logilab.common.textutils import splitstrip |
351 from logilab.common.textutils import splitstrip |
|
352 check_options_consistency(self.config) |
342 configname = self.config.config |
353 configname = self.config.config |
343 cubes, appid = args |
354 cubes, appid = args |
344 cubes = splitstrip(cubes) |
355 cubes = splitstrip(cubes) |
345 # get the configuration and helper |
356 # get the configuration and helper |
346 config = cwcfg.config_for(appid, configname, creating=True) |
357 config = cwcfg.config_for(appid, configname, creating=True) |
358 return |
369 return |
359 # create the registry directory for this instance |
370 # create the registry directory for this instance |
360 print '\n'+underline_title('Creating the instance %s' % appid) |
371 print '\n'+underline_title('Creating the instance %s' % appid) |
361 create_dir(config.apphome) |
372 create_dir(config.apphome) |
362 # cubicweb-ctl configuration |
373 # cubicweb-ctl configuration |
363 print '\n'+underline_title('Configuring the instance (%s.conf)' % configname) |
374 if not self.config.automatic: |
364 config.input_config('main', self.config.config_level) |
375 print '\n'+underline_title('Configuring the instance (%s.conf)' |
|
376 % configname) |
|
377 config.input_config('main', self.config.config_level) |
365 # configuration'specific stuff |
378 # configuration'specific stuff |
366 print |
379 print |
367 helper.bootstrap(cubes, self.config.config_level) |
380 helper.bootstrap(cubes, self.config.automatic, self.config.config_level) |
368 # input for cubes specific options |
381 # input for cubes specific options |
369 sections = set(sect.lower() for sect, opt, odict in config.all_options() |
382 sections = set(sect.lower() for sect, opt, odict in config.all_options() |
370 if 'type' in odict |
383 if 'type' in odict |
371 and odict.get('level') <= self.config.config_level) |
384 and odict.get('level') <= self.config.config_level) |
372 for section in sections: |
385 for section in sections: |
373 if section not in ('main', 'email', 'pyro'): |
386 if section not in ('main', 'email', 'pyro', 'web'): |
374 print '\n' + underline_title('%s options' % section) |
387 print '\n' + underline_title('%s options' % section) |
375 config.input_config(section, self.config.config_level) |
388 config.input_config(section, self.config.config_level) |
376 # write down configuration |
389 # write down configuration |
377 config.save() |
390 config.save() |
378 self._handle_win32(config, appid) |
391 self._handle_win32(config, appid) |
383 from cubicweb import i18n |
396 from cubicweb import i18n |
384 langs = [lang for lang, _ in i18n.available_catalogs(join(templdirs[0], 'i18n'))] |
397 langs = [lang for lang, _ in i18n.available_catalogs(join(templdirs[0], 'i18n'))] |
385 errors = config.i18ncompile(langs) |
398 errors = config.i18ncompile(langs) |
386 if errors: |
399 if errors: |
387 print '\n'.join(errors) |
400 print '\n'.join(errors) |
388 if not ASK.confirm('error while compiling message catalogs, ' |
401 if self.config.automatic \ |
389 'continue anyway ?'): |
402 or not ASK.confirm('error while compiling message catalogs, ' |
|
403 'continue anyway ?'): |
390 print 'creation not completed' |
404 print 'creation not completed' |
391 return |
405 return |
392 # create the additional data directory for this instance |
406 # create the additional data directory for this instance |
393 if config.appdatahome != config.apphome: # true in dev mode |
407 if config.appdatahome != config.apphome: # true in dev mode |
394 create_dir(config.appdatahome) |
408 create_dir(config.appdatahome) |
397 from logilab.common.shellutils import chown |
411 from logilab.common.shellutils import chown |
398 # this directory should be owned by the uid of the server process |
412 # this directory should be owned by the uid of the server process |
399 print 'set %s as owner of the data directory' % config['uid'] |
413 print 'set %s as owner of the data directory' % config['uid'] |
400 chown(config.appdatahome, config['uid']) |
414 chown(config.appdatahome, config['uid']) |
401 print '\n-> creation done for %r.\n' % config.apphome |
415 print '\n-> creation done for %r.\n' % config.apphome |
402 helper.postcreate() |
416 helper.postcreate(self.config.automatic) |
403 |
417 |
404 def _handle_win32(self, config, appid): |
418 def _handle_win32(self, config, appid): |
405 if sys.platform != 'win32': |
419 if sys.platform != 'win32': |
406 return |
420 return |
407 service_template = """ |
421 service_template = """ |