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 |