cubicweb/cwctl.py
changeset 12685 84a8a8915512
parent 12585 933c2b3839ab
child 12692 8673da7c2f85
equal deleted inserted replaced
12684:d464495452aa 12685:84a8a8915512
    21 # *ctl module should limit the number of import to be imported as quickly as
    21 # *ctl module should limit the number of import to be imported as quickly as
    22 # possible (for cubicweb-ctl reactivity, necessary for instance for usable bash
    22 # possible (for cubicweb-ctl reactivity, necessary for instance for usable bash
    23 # completion). So import locally in command helpers.
    23 # completion). So import locally in command helpers.
    24 import sys
    24 import sys
    25 from warnings import filterwarnings
    25 from warnings import filterwarnings
    26 from os import listdir, system
    26 from os import listdir
    27 from os.path import exists, join, isdir
    27 from os.path import exists, join, isdir
    28 
    28 
    29 try:
    29 try:
    30     from os import kill, getpgid
    30     from os import kill, getpgid
    31 except ImportError:
    31 except ImportError:
    96 
    96 
    97     return [drop_prefix(cube) for cube in cwcfg.available_cubes()]
    97     return [drop_prefix(cube) for cube in cwcfg.available_cubes()]
    98 
    98 
    99 
    99 
   100 class InstanceCommand(Command):
   100 class InstanceCommand(Command):
   101     """base class for command taking 0 to n instance id as arguments
   101     """base class for command taking one instance id as arguments"""
   102     (0 meaning all registered instances)
   102     arguments = '<instance>'
   103     """
   103 
   104     arguments = '[<instance>...]'
   104     # enforce having one instance
       
   105     min_args = max_args = 1
       
   106 
   105     options = (
   107     options = (
   106         ("force",
   108         ("force",
   107          {'short': 'f', 'action': 'store_true',
   109          {'short': 'f', 'action': 'store_true',
   108           'default': False,
   110           'default': False,
   109           'help': 'force command without asking confirmation',
   111           'help': 'force command without asking confirmation',
   114 
   116 
   115     def run(self, args):
   117     def run(self, args):
   116         """run the <command>_method on each argument (a list of instance
   118         """run the <command>_method on each argument (a list of instance
   117         identifiers)
   119         identifiers)
   118         """
   120         """
   119         if not args:
   121         appid = args[0]
   120             args = list_instances(cwcfg.instances_dir())
       
   121             try:
       
   122                 askconfirm = not self.config.force
       
   123             except AttributeError:
       
   124                 # no force option
       
   125                 askconfirm = False
       
   126         else:
       
   127             askconfirm = False
       
   128         self.run_args(args, askconfirm)
       
   129 
       
   130     def run_args(self, args, askconfirm):
       
   131         status = 0
       
   132         for appid in args:
       
   133             if askconfirm:
       
   134                 print('*' * 72)
       
   135                 if not ASK.confirm('%s instance %r ?' % (self.name, appid)):
       
   136                     continue
       
   137             try:
       
   138                 status = max(status, self.run_arg(appid))
       
   139             except (KeyboardInterrupt, SystemExit):
       
   140                 sys.stderr.write('%s aborted\n' % self.name)
       
   141                 return 2  # specific error code
       
   142         sys.exit(status)
       
   143 
       
   144     def run_arg(self, appid):
       
   145         cmdmeth = getattr(self, '%s_instance' % self.name)
   122         cmdmeth = getattr(self, '%s_instance' % self.name)
       
   123 
   146         try:
   124         try:
   147             status = cmdmeth(appid) or 0
   125             status = cmdmeth(appid) or 0
   148         except (ExecutionError, ConfigurationError) as ex:
   126         except (ExecutionError, ConfigurationError) as ex:
   149             sys.stderr.write('instance %s not %s: %s\n' % (
   127             sys.stderr.write('instance %s not %s: %s\n' % (
   150                 appid, self.actionverb, ex))
   128                 appid, self.actionverb, ex))
   153             import traceback
   131             import traceback
   154             traceback.print_exc()
   132             traceback.print_exc()
   155             sys.stderr.write('instance %s not %s: %s\n' % (
   133             sys.stderr.write('instance %s not %s: %s\n' % (
   156                 appid, self.actionverb, ex))
   134                 appid, self.actionverb, ex))
   157             status = 8
   135             status = 8
   158         return status
   136 
   159 
   137         except (KeyboardInterrupt, SystemExit):
   160 
   138             sys.stderr.write('%s aborted\n' % self.name)
   161 class InstanceCommandFork(InstanceCommand):
   139             status = 2  # specific error code
   162     """Same as `InstanceCommand`, but command is forked in a new environment
   140 
   163     for each argument
   141         sys.exit(status)
   164     """
       
   165 
       
   166     def run_args(self, args, askconfirm):
       
   167         if len(args) > 1:
       
   168             forkcmd = ' '.join(w for w in sys.argv if w not in args)
       
   169         else:
       
   170             forkcmd = None
       
   171         for appid in args:
       
   172             if askconfirm:
       
   173                 print('*' * 72)
       
   174                 if not ASK.confirm('%s instance %r ?' % (self.name, appid)):
       
   175                     continue
       
   176             if forkcmd:
       
   177                 status = system('%s %s' % (forkcmd, appid))
       
   178                 if status:
       
   179                     print('%s exited with status %s' % (forkcmd, status))
       
   180             else:
       
   181                 self.run_arg(appid)
       
   182 
   142 
   183 
   143 
   184 # base commands ###############################################################
   144 # base commands ###############################################################
   185 
   145 
   186 class ListCommand(Command):
   146 class ListCommand(Command):
   463     if loglevel is not None:
   423     if loglevel is not None:
   464         config.global_set_option('log-threshold', loglevel.upper())
   424         config.global_set_option('log-threshold', loglevel.upper())
   465         config.init_log(config['log-threshold'], force=True)
   425         config.init_log(config['log-threshold'], force=True)
   466 
   426 
   467 
   427 
   468 class UpgradeInstanceCommand(InstanceCommandFork):
   428 class UpgradeInstanceCommand(InstanceCommand):
   469     """Upgrade an instance after cubicweb and/or component(s) upgrade.
   429     """Upgrade an instance after cubicweb and/or component(s) upgrade.
   470 
   430 
   471     For repository update, you will be prompted for a login / password to use
   431     For repository update, you will be prompted for a login / password to use
   472     to connect to the system database.  For some upgrades, the given user
   432     to connect to the system database.  For some upgrades, the given user
   473     should have create or alter table permissions.
   433     should have create or alter table permissions.
   474 
   434 
   475     <instance>...
   435     <instance>
   476       identifiers of the instances to upgrade. If no instance is
   436       identifier of the instance to upgrade.
   477       given, upgrade them all.
       
   478     """
   437     """
   479     name = 'upgrade'
   438     name = 'upgrade'
   480     actionverb = 'upgraded'
   439     actionverb = 'upgraded'
   481     options = InstanceCommand.options + (
   440     options = InstanceCommand.options + (
   482         ('force-cube-version',
   441         ('force-cube-version',
   636       the identifier of the instance to connect.
   595       the identifier of the instance to connect.
   637     """
   596     """
   638     name = 'shell'
   597     name = 'shell'
   639     arguments = '<instance> [batch command file(s)] [-- <script arguments>]'
   598     arguments = '<instance> [batch command file(s)] [-- <script arguments>]'
   640     min_args = 1
   599     min_args = 1
       
   600     max_args = None
   641     options = (
   601     options = (
   642         ('system-only',
   602         ('system-only',
   643          {'short': 'S', 'action': 'store_true',
   603          {'short': 'S', 'action': 'store_true',
   644           'help': 'only connect to the system source when the instance is '
   604           'help': 'only connect to the system source when the instance is '
   645           'using multiple sources. You can\'t use this option and the '
   605           'using multiple sources. You can\'t use this option and the '
   699 
   659 
   700 
   660 
   701 class RecompileInstanceCatalogsCommand(InstanceCommand):
   661 class RecompileInstanceCatalogsCommand(InstanceCommand):
   702     """Recompile i18n catalogs for instances.
   662     """Recompile i18n catalogs for instances.
   703 
   663 
   704     <instance>...
   664     <instance>
   705       identifiers of the instances to consider. If no instance is
   665       identifier of the instance to consider.
   706       given, recompile for all registered instances.
       
   707     """
   666     """
   708     name = 'i18ninstance'
   667     name = 'i18ninstance'
   709 
   668 
   710     @staticmethod
   669     @staticmethod
   711     def i18ninstance_instance(appid):
   670     def i18ninstance_instance(appid):
   745 
   704 
   746 
   705 
   747 class ConfigureInstanceCommand(InstanceCommand):
   706 class ConfigureInstanceCommand(InstanceCommand):
   748     """Configure instance.
   707     """Configure instance.
   749 
   708 
   750     <instance>...
   709     <instance>
   751       identifier of the instance to configure.
   710       identifier of the instance to configure.
   752     """
   711     """
   753     name = 'configure'
   712     name = 'configure'
   754     actionverb = 'configured'
   713     actionverb = 'configured'
   755 
   714