| OLD | NEW | 
|---|
| 1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 
| 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | 
| 3 # | 3 # | 
| 4 # This file is part of logilab-common. | 4 # This file is part of logilab-common. | 
| 5 # | 5 # | 
| 6 # logilab-common is free software: you can redistribute it and/or modify it unde
     r | 6 # logilab-common is free software: you can redistribute it and/or modify it unde
     r | 
| 7 # the terms of the GNU Lesser General Public License as published by the Free | 7 # the terms of the GNU Lesser General Public License as published by the Free | 
| 8 # Software Foundation, either version 2.1 of the License, or (at your option) an
     y | 8 # Software Foundation, either version 2.1 of the License, or (at your option) an
     y | 
| 9 # later version. | 9 # later version. | 
| 10 # | 10 # | 
| 11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT | 11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT | 
| 12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
| 13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more | 13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more | 
| 14 # details. | 14 # details. | 
| 15 # | 15 # | 
| 16 # You should have received a copy of the GNU Lesser General Public License along | 16 # You should have received a copy of the GNU Lesser General Public License along | 
| 17 # with logilab-common.  If not, see <http://www.gnu.org/licenses/>. | 17 # with logilab-common.  If not, see <http://www.gnu.org/licenses/>. | 
| 18 """Helper functions to support command line tools providing more than | 18 """Helper functions to support command line tools providing more than | 
| 19 one command. | 19 one command. | 
| 20 | 20 | 
| 21 e.g called as "tool command [options] args..." where <options> and <args> are | 21 e.g called as "tool command [options] args..." where <options> and <args> are | 
| 22 command'specific | 22 command'specific | 
| 23 """ | 23 """ | 
| 24 | 24 | 
|  | 25 from __future__ import print_function | 
|  | 26 | 
| 25 __docformat__ = "restructuredtext en" | 27 __docformat__ = "restructuredtext en" | 
| 26 | 28 | 
| 27 import sys | 29 import sys | 
| 28 import logging | 30 import logging | 
| 29 from os.path import basename | 31 from os.path import basename | 
| 30 | 32 | 
| 31 from logilab.common.configuration import Configuration | 33 from logilab.common.configuration import Configuration | 
| 32 from logilab.common.logging_ext import init_log, get_threshold | 34 from logilab.common.logging_ext import init_log, get_threshold | 
| 33 from logilab.common.deprecation import deprecated | 35 from logilab.common.deprecation import deprecated | 
| 34 | 36 | 
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 108         init_log(debug=True, # so that we use StreamHandler | 110         init_log(debug=True, # so that we use StreamHandler | 
| 109                  logthreshold=self.logthreshold, | 111                  logthreshold=self.logthreshold, | 
| 110                  logformat='%(levelname)s: %(message)s') | 112                  logformat='%(levelname)s: %(message)s') | 
| 111         try: | 113         try: | 
| 112             arg = args.pop(0) | 114             arg = args.pop(0) | 
| 113         except IndexError: | 115         except IndexError: | 
| 114             self.usage_and_exit(1) | 116             self.usage_and_exit(1) | 
| 115         if arg in ('-h', '--help'): | 117         if arg in ('-h', '--help'): | 
| 116             self.usage_and_exit(0) | 118             self.usage_and_exit(0) | 
| 117         if self.version is not None and arg in ('--version'): | 119         if self.version is not None and arg in ('--version'): | 
| 118             print self.version | 120             print(self.version) | 
| 119             sys.exit(0) | 121             sys.exit(0) | 
| 120         rcfile = self.rcfile | 122         rcfile = self.rcfile | 
| 121         if rcfile is not None and arg in ('-C', '--rc-file'): | 123         if rcfile is not None and arg in ('-C', '--rc-file'): | 
| 122             try: | 124             try: | 
| 123                 rcfile = args.pop(0) | 125                 rcfile = args.pop(0) | 
| 124                 arg = args.pop(0) | 126                 arg = args.pop(0) | 
| 125             except IndexError: | 127             except IndexError: | 
| 126                 self.usage_and_exit(1) | 128                 self.usage_and_exit(1) | 
| 127         try: | 129         try: | 
| 128             command = self.get_command(arg) | 130             command = self.get_command(arg) | 
| 129         except KeyError: | 131         except KeyError: | 
| 130             print 'ERROR: no %s command' % arg | 132             print('ERROR: no %s command' % arg) | 
| 131             print | 133             print() | 
| 132             self.usage_and_exit(1) | 134             self.usage_and_exit(1) | 
| 133         try: | 135         try: | 
| 134             sys.exit(command.main_run(args, rcfile)) | 136             sys.exit(command.main_run(args, rcfile)) | 
| 135         except KeyboardInterrupt, exc: | 137         except KeyboardInterrupt as exc: | 
| 136             print 'Interrupted', | 138             print('Interrupted', end=' ') | 
| 137             if str(exc): | 139             if str(exc): | 
| 138                 print ': %s' % exc, | 140                 print(': %s' % exc, end=' ') | 
| 139             print | 141             print() | 
| 140             sys.exit(4) | 142             sys.exit(4) | 
| 141         except BadCommandUsage, err: | 143         except BadCommandUsage as err: | 
| 142             print 'ERROR:', err | 144             print('ERROR:', err) | 
| 143             print | 145             print() | 
| 144             print command.help() | 146             print(command.help()) | 
| 145             sys.exit(1) | 147             sys.exit(1) | 
| 146 | 148 | 
| 147     def create_logger(self, handler, logthreshold=None): | 149     def create_logger(self, handler, logthreshold=None): | 
| 148         logger = logging.Logger(self.pgm) | 150         logger = logging.Logger(self.pgm) | 
| 149         logger.handlers = [handler] | 151         logger.handlers = [handler] | 
| 150         if logthreshold is None: | 152         if logthreshold is None: | 
| 151             logthreshold = get_threshold(self.logthreshold) | 153             logthreshold = get_threshold(self.logthreshold) | 
| 152         logger.setLevel(logthreshold) | 154         logger.setLevel(logthreshold) | 
| 153         return logger | 155         return logger | 
| 154 | 156 | 
| 155     def get_command(self, cmd, logger=None): | 157     def get_command(self, cmd, logger=None): | 
| 156         if logger is None: | 158         if logger is None: | 
| 157             logger = self.logger | 159             logger = self.logger | 
| 158         if logger is None: | 160         if logger is None: | 
| 159             logger = self.logger = logging.getLogger(self.pgm) | 161             logger = self.logger = logging.getLogger(self.pgm) | 
| 160             logger.setLevel(get_threshold(self.logthreshold)) | 162             logger.setLevel(get_threshold(self.logthreshold)) | 
| 161         return self[cmd](logger) | 163         return self[cmd](logger) | 
| 162 | 164 | 
| 163     def usage(self): | 165     def usage(self): | 
| 164         """display usage for the main program (i.e. when no command supplied) | 166         """display usage for the main program (i.e. when no command supplied) | 
| 165         and exit | 167         and exit | 
| 166         """ | 168         """ | 
| 167         print 'usage:', self.pgm, | 169         print('usage:', self.pgm, end=' ') | 
| 168         if self.rcfile: | 170         if self.rcfile: | 
| 169             print '[--rc-file=<configuration file>]', | 171             print('[--rc-file=<configuration file>]', end=' ') | 
| 170         print '<command> [options] <command argument>...' | 172         print('<command> [options] <command argument>...') | 
| 171         if self.doc: | 173         if self.doc: | 
| 172             print '\n%s' % self.doc | 174             print('\n%s' % self.doc) | 
| 173         print  ''' | 175         print(''' | 
| 174 Type "%(pgm)s <command> --help" for more information about a specific | 176 Type "%(pgm)s <command> --help" for more information about a specific | 
| 175 command. Available commands are :\n''' % self.__dict__ | 177 command. Available commands are :\n''' % self.__dict__) | 
| 176         max_len = max([len(cmd) for cmd in self]) | 178         max_len = max([len(cmd) for cmd in self]) | 
| 177         padding = ' ' * max_len | 179         padding = ' ' * max_len | 
| 178         for cmdname, cmd in sorted(self.items()): | 180         for cmdname, cmd in sorted(self.items()): | 
| 179             if not cmd.hidden: | 181             if not cmd.hidden: | 
| 180                 print ' ', (cmdname + padding)[:max_len], cmd.short_description(
     ) | 182                 print(' ', (cmdname + padding)[:max_len], cmd.short_description(
     )) | 
| 181         if self.rcfile: | 183         if self.rcfile: | 
| 182             print ''' | 184             print(''' | 
| 183 Use --rc-file=<configuration file> / -C <configuration file> before the command | 185 Use --rc-file=<configuration file> / -C <configuration file> before the command | 
| 184 to specify a configuration file. Default to %s. | 186 to specify a configuration file. Default to %s. | 
| 185 ''' % self.rcfile | 187 ''' % self.rcfile) | 
| 186         print  '''%(pgm)s -h/--help | 188         print('''%(pgm)s -h/--help | 
| 187       display this usage information and exit''' % self.__dict__ | 189       display this usage information and exit''' % self.__dict__) | 
| 188         if self.version: | 190         if self.version: | 
| 189             print  '''%(pgm)s -v/--version | 191             print('''%(pgm)s -v/--version | 
| 190       display version configuration and exit''' % self.__dict__ | 192       display version configuration and exit''' % self.__dict__) | 
| 191         if self.copyright: | 193         if self.copyright: | 
| 192             print '\n', self.copyright | 194             print('\n', self.copyright) | 
| 193 | 195 | 
| 194     def usage_and_exit(self, status): | 196     def usage_and_exit(self, status): | 
| 195         self.usage() | 197         self.usage() | 
| 196         sys.exit(status) | 198         sys.exit(status) | 
| 197 | 199 | 
| 198 | 200 | 
| 199 # base command classes ######################################################### | 201 # base command classes ######################################################### | 
| 200 | 202 | 
| 201 class Command(Configuration): | 203 class Command(Configuration): | 
| 202     """Base class for command line commands. | 204     """Base class for command line commands. | 
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 254 | 256 | 
| 255         Any other exceptions, including :exc:`BadCommandUsage` will be | 257         Any other exceptions, including :exc:`BadCommandUsage` will be | 
| 256         propagated. | 258         propagated. | 
| 257         """ | 259         """ | 
| 258         if rcfile: | 260         if rcfile: | 
| 259             self.load_file_configuration(rcfile) | 261             self.load_file_configuration(rcfile) | 
| 260         args = self.load_command_line_configuration(args) | 262         args = self.load_command_line_configuration(args) | 
| 261         try: | 263         try: | 
| 262             self.check_args(args) | 264             self.check_args(args) | 
| 263             self.run(args) | 265             self.run(args) | 
| 264         except CommandError, err: | 266         except CommandError as err: | 
| 265             self.logger.error(err) | 267             self.logger.error(err) | 
| 266             return 2 | 268             return 2 | 
| 267         return 0 | 269         return 0 | 
| 268 | 270 | 
| 269     def run(self, args): | 271     def run(self, args): | 
| 270         """run the command with its specific arguments""" | 272         """run the command with its specific arguments""" | 
| 271         raise NotImplementedError() | 273         raise NotImplementedError() | 
| 272 | 274 | 
| 273 | 275 | 
| 274 class ListCommandsCommand(Command): | 276 class ListCommandsCommand(Command): | 
| 275     """list available commands, useful for bash completion.""" | 277     """list available commands, useful for bash completion.""" | 
| 276     name = 'listcommands' | 278     name = 'listcommands' | 
| 277     arguments = '[command]' | 279     arguments = '[command]' | 
| 278     hidden = True | 280     hidden = True | 
| 279 | 281 | 
| 280     def run(self, args): | 282     def run(self, args): | 
| 281         """run the command with its specific arguments""" | 283         """run the command with its specific arguments""" | 
| 282         if args: | 284         if args: | 
| 283             command = args.pop() | 285             command = args.pop() | 
| 284             cmd = _COMMANDS[command] | 286             cmd = _COMMANDS[command] | 
| 285             for optname, optdict in cmd.options: | 287             for optname, optdict in cmd.options: | 
| 286                 print '--help' | 288                 print('--help') | 
| 287                 print '--' + optname | 289                 print('--' + optname) | 
| 288         else: | 290         else: | 
| 289             commands = sorted(_COMMANDS.keys()) | 291             commands = sorted(_COMMANDS.keys()) | 
| 290             for command in commands: | 292             for command in commands: | 
| 291                 cmd = _COMMANDS[command] | 293                 cmd = _COMMANDS[command] | 
| 292                 if not cmd.hidden: | 294                 if not cmd.hidden: | 
| 293                     print command | 295                     print(command) | 
| 294 | 296 | 
| 295 | 297 | 
| 296 # deprecated stuff ############################################################# | 298 # deprecated stuff ############################################################# | 
| 297 | 299 | 
| 298 _COMMANDS = CommandLine() | 300 _COMMANDS = CommandLine() | 
| 299 | 301 | 
| 300 DEFAULT_COPYRIGHT = '''\ | 302 DEFAULT_COPYRIGHT = '''\ | 
| 301 Copyright (c) 2004-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 303 Copyright (c) 2004-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 
| 302 http://www.logilab.fr/ -- mailto:contact@logilab.fr''' | 304 http://www.logilab.fr/ -- mailto:contact@logilab.fr''' | 
| 303 | 305 | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
| 323 def pop_arg(args_list, expected_size_after=None, msg="Missing argument"): | 325 def pop_arg(args_list, expected_size_after=None, msg="Missing argument"): | 
| 324     """helper function to get and check command line arguments""" | 326     """helper function to get and check command line arguments""" | 
| 325     try: | 327     try: | 
| 326         value = args_list.pop(0) | 328         value = args_list.pop(0) | 
| 327     except IndexError: | 329     except IndexError: | 
| 328         raise BadCommandUsage(msg) | 330         raise BadCommandUsage(msg) | 
| 329     if expected_size_after is not None and len(args_list) > expected_size_after: | 331     if expected_size_after is not None and len(args_list) > expected_size_after: | 
| 330         raise BadCommandUsage('too many arguments') | 332         raise BadCommandUsage('too many arguments') | 
| 331     return value | 333     return value | 
| 332 | 334 | 
| OLD | NEW | 
|---|