# Copyright (C) 2009-2012 Chris Ball # Phil Schumm # Robert Lehmann # W. Trevor King # # This file is part of Bugs Everywhere. # # Bugs Everywhere is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation, either version 2 of the License, or (at your option) any # later version. # # Bugs Everywhere is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # Bugs Everywhere. If not, see . import codecs import optparse import os.path import StringIO import sys import urlparse import libbe import libbe.storage import libbe.storage.util.mapfile import libbe.ui.util.user import libbe.util.encoding import libbe.util.http import libbe.util.plugin class UserError (Exception): "An error due to improper BE usage." pass class UsageError (UserError): """A serious parsing error due to invalid BE command construction. The distinction between `UserError`\s and the more specific `UsageError`\s is that when displaying a `UsageError` to the user, the user is pointed towards the command usage information. Use the more general `UserError` if you feel that usage information would not be particularly enlightening. """ def __init__(self, command=None, command_name=None, message=None): super(UsageError, self).__init__(message) self.command = command if command_name is None and command is not None: command_name = command.name self.command_name = command_name self.message = message class UnknownCommand (UsageError): def __init__(self, command_name, message=None): uc_message = "Unknown command '%s'" % command_name if message is None: message = uc_message else: message = '%s\n(%s)' % (uc_message, message) super(UnknownCommand, self).__init__( command_name=command_name, message=message) def get_command(command_name): """Retrieves the module for a user command >>> try: ... get_command('asdf') ... except UnknownCommand, e: ... print e Unknown command 'asdf' (No module named asdf) >>> repr(get_command('list')).startswith(">> import_xml_mod = get_command('import-xml') >>> import_xml = get_command_class(import_xml_mod, 'import-xml') >>> repr(import_xml) "" >>> import_xml = get_command_class(command_name='import-xml') >>> repr(import_xml) "" """ if module == None: module = get_command(command_name) try: cname = command_name.capitalize().replace('-', '_') cmd = getattr(module, cname) except ImportError, e: raise UnknownCommand(command_name) return cmd def modname_to_command_name(modname): """Little hack to replicate >>> import sys >>> def real_modname_to_command_name(modname): ... mod = libbe.util.plugin.import_by_name( ... 'libbe.command.%s' % modname) ... attrs = [getattr(mod, name) for name in dir(mod)] ... commands = [] ... for attr_name in dir(mod): ... attr = getattr(mod, attr_name) ... try: ... if issubclass(attr, Command): ... commands.append(attr) ... except TypeError, e: ... pass ... if len(commands) == 0: ... raise Exception('No Command classes in %s' % dir(mod)) ... return commands[0].name >>> real_modname_to_command_name('new') 'new' >>> real_modname_to_command_name('import_xml') 'import-xml' """ return modname.replace('_', '-') def commands(command_names=False): for modname in libbe.util.plugin.modnames('libbe.command'): if modname not in ['base', 'util']: if command_names == False: yield modname else: yield modname_to_command_name(modname) class CommandInput (object): def __init__(self, name, help=''): self.name = name self.help = help def __str__(self): return '<%s %s>' % (self.__class__.__name__, self.name) def __repr__(self): return self.__str__() class Argument (CommandInput): def __init__(self, metavar=None, default=None, type='string', optional=False, repeatable=False, completion_callback=None, *args, **kwargs): CommandInput.__init__(self, *args, **kwargs) self.metavar = metavar self.default = default self.type = type self.optional = optional self.repeatable = repeatable self.completion_callback = completion_callback if self.metavar == None: self.metavar = self.name.upper() class Option (CommandInput): def __init__(self, callback=None, short_name=None, arg=None, *args, **kwargs): CommandInput.__init__(self, *args, **kwargs) self.callback = callback self.short_name = short_name self.arg = arg if self.arg == None and self.callback == None: # use an implicit boolean argument self.arg = Argument(name=self.name, help=self.help, default=False, type='bool') self.validate() def validate(self): if self.arg == None: assert self.callback != None, self.name return assert self.callback == None, '%s: %s' (self.name, self.callback) assert self.arg.name == self.name, \ 'Name missmatch: %s != %s' % (self.arg.name, self.name) assert self.arg.optional == False, self.name assert self.arg.repeatable == False, self.name def __str__(self): return '--%s' % self.name def __repr__(self): return '