X-Git-Url: https://git.distorted.org.uk/~mdw/stgit/blobdiff_plain/78340ff10ec8fe964a6d9b3d2ad8b7d3edd717cc..f0b6dda7e20f9ea0d6cf9719bcea3cbc12281a2d:/stgit/main.py diff --git a/stgit/main.py b/stgit/main.py index 49089e6..d5be70b 100644 --- a/stgit/main.py +++ b/stgit/main.py @@ -18,10 +18,35 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -import sys, os -from optparse import OptionParser +import sys, os, traceback import stgit.commands +from stgit.out import * +from stgit import argparse, run, utils +from stgit.config import config + +class CommandAlias(object): + def __init__(self, name, command): + self.__command = command + self.__name__ = name + self.usage = [''] + self.help = 'Alias for "%s ".' % self.__command + self.options = [] + + def func(self, args): + cmd = self.__command.split() + args + p = run.Run(*cmd) + p.discard_exitcode().run() + return p.exitcode + +def is_cmd_alias(cmd): + return isinstance(cmd, CommandAlias) + +def append_alias_commands(cmd_list): + for (name, command) in config.getstartswith('stgit.alias.'): + name = utils.strip_prefix('stgit.alias.', name) + cmd_list[name] = (CommandAlias(name, command), + 'Alias commands', command) # # The commands map @@ -36,122 +61,28 @@ class Commands(dict): candidates = [cmd for cmd in self.keys() if cmd.startswith(key)] if not candidates: - print >> sys.stderr, 'Unknown command: %s' % key - print >> sys.stderr, ' Try "%s help" for a list of ' \ - 'supported commands' % prog - sys.exit(1) + out.error('Unknown command: %s' % key, + 'Try "%s help" for a list of supported commands' % prog) + sys.exit(utils.STGIT_GENERAL_ERROR) elif len(candidates) > 1: - print >> sys.stderr, 'Ambiguous command: %s' % key - print >> sys.stderr, ' Candidates are: %s' \ - % ', '.join(candidates) - sys.exit(1) + out.error('Ambiguous command: %s' % key, + 'Candidates are: %s' % ', '.join(candidates)) + sys.exit(utils.STGIT_GENERAL_ERROR) return candidates[0] def __getitem__(self, key): - """Return the command python module name based. - """ - global prog - cmd_mod = self.get(key) or self.get(self.canonical_cmd(key)) - - __import__('stgit.commands.' + cmd_mod) - return getattr(stgit.commands, cmd_mod) - -commands = Commands({ - 'add': 'add', - 'applied': 'applied', - 'assimilate': 'assimilate', - 'branch': 'branch', - 'delete': 'delete', - 'diff': 'diff', - 'clean': 'clean', - 'clone': 'clone', - 'commit': 'commit', - 'export': 'export', - 'files': 'files', - 'float': 'float', - 'fold': 'fold', - 'goto': 'goto', - 'hide': 'hide', - 'id': 'id', - 'import': 'imprt', - 'init': 'init', - 'log': 'log', - 'mail': 'mail', - 'new': 'new', - 'patches': 'patches', - 'pick': 'pick', - 'pop': 'pop', - 'pull': 'pull', - 'push': 'push', - 'rebase': 'rebase', - 'refresh': 'refresh', - 'rename': 'rename', - 'resolved': 'resolved', - 'rm': 'rm', - 'series': 'series', - 'show': 'show', - 'status': 'status', - 'sync': 'sync', - 'top': 'top', - 'unapplied': 'unapplied', - 'uncommit': 'uncommit', - 'unhide': 'unhide' - }) + if is_cmd_alias(cmd_mod): + return cmd_mod + else: + return stgit.commands.get_command(cmd_mod) -# classification: repository, stack, patch, working copy -repocommands = ( - 'branch', - 'clone', - 'id', - 'pull' - ) -stackcommands = ( - 'applied', - 'assimilate', - 'clean', - 'commit', - 'float', - 'goto', - 'hide', - 'init', - 'pop', - 'push', - 'rebase', - 'series', - 'top', - 'unapplied', - 'uncommit', - 'unhide' - ) -patchcommands = ( - 'delete', - 'export', - 'files', - 'fold', - 'import', - 'log', - 'mail', - 'new', - 'pick', - 'refresh', - 'rename', - 'show', - 'sync' - ) -wccommands = ( - 'add', - 'diff', - 'patches', - 'resolved', - 'rm', - 'status' - ) +cmd_list = stgit.commands.get_commands() +append_alias_commands(cmd_list) +commands = Commands((cmd, mod) for cmd, (mod, kind, help) + in cmd_list.iteritems()) -def _print_helpstring(cmd): - print ' ' + cmd + ' ' * (12 - len(cmd)) + commands[cmd].help - def print_help(): print 'usage: %s [options]' % os.path.basename(sys.argv[0]) print @@ -159,38 +90,13 @@ def print_help(): print ' help print the detailed command usage' print ' version display version information' print ' copyright display copyright information' - # unclassified commands if any - cmds = commands.keys() - cmds.sort() - for cmd in cmds: - if not cmd in repocommands and not cmd in stackcommands \ - and not cmd in patchcommands and not cmd in wccommands: - _print_helpstring(cmd) - print - - print 'Repository commands:' - for cmd in repocommands: - _print_helpstring(cmd) - print - - print 'Stack commands:' - for cmd in stackcommands: - _print_helpstring(cmd) - print - - print 'Patch commands:' - for cmd in patchcommands: - _print_helpstring(cmd) print - - print 'Working-copy commands:' - for cmd in wccommands: - _print_helpstring(cmd) + stgit.commands.pretty_command_list(cmd_list, sys.stdout) # # The main function (command dispatcher) # -def main(): +def _main(): """The main function """ global prog @@ -201,7 +107,7 @@ def main(): print >> sys.stderr, 'usage: %s ' % prog print >> sys.stderr, \ ' Try "%s --help" for a list of supported commands' % prog - sys.exit(1) + sys.exit(utils.STGIT_GENERAL_ERROR) cmd = sys.argv[1] @@ -211,70 +117,94 @@ def main(): sys.argv[2] = '--help' else: print_help() - sys.exit(0) + sys.exit(utils.STGIT_SUCCESS) if cmd == 'help': if len(sys.argv) == 3 and not sys.argv[2] in ['-h', '--help']: cmd = commands.canonical_cmd(sys.argv[2]) if not cmd in commands: - print >> sys.stderr, '%s help: "%s" command unknown' \ - % (prog, cmd) - sys.exit(1) + out.error('%s help: "%s" command unknown' % (prog, cmd)) + sys.exit(utils.STGIT_GENERAL_ERROR) sys.argv[0] += ' %s' % cmd command = commands[cmd] - parser = OptionParser(usage = command.usage, - option_list = command.options) + parser = argparse.make_option_parser(command) + if is_cmd_alias(command): + parser.remove_option('-h') from pydoc import pager pager(parser.format_help()) else: print_help() - sys.exit(0) + sys.exit(utils.STGIT_SUCCESS) if cmd in ['-v', '--version', 'version']: from stgit.version import version print 'Stacked GIT %s' % version os.system('git --version') print 'Python version %s' % sys.version - sys.exit(0) + sys.exit(utils.STGIT_SUCCESS) if cmd in ['copyright']: print __copyright__ - sys.exit(0) + sys.exit(utils.STGIT_SUCCESS) # re-build the command line arguments - sys.argv[0] += ' %s' % commands.canonical_cmd(cmd) + cmd = commands.canonical_cmd(cmd) + sys.argv[0] += ' %s' % cmd del(sys.argv[1]) command = commands[cmd] - usage = command.usage.split('\n')[0].strip() - parser = OptionParser(usage = usage, option_list = command.options) + if is_cmd_alias(command): + sys.exit(command.func(sys.argv[1:])) + + parser = argparse.make_option_parser(command) options, args = parser.parse_args() + directory = command.directory # These modules are only used from this point onwards and do not # need to be imported earlier + from stgit.exception import StgException from stgit.config import config_setup from ConfigParser import ParsingError, NoSectionError - from stgit.stack import Series, StackException - from stgit.git import GitException - from stgit.commands.common import CmdException - from stgit.gitmergeonefile import GitMergeException + from stgit.stack import Series + + try: + debug_level = int(os.environ.get('STGIT_DEBUG_LEVEL', 0)) + except ValueError: + out.error('Invalid STGIT_DEBUG_LEVEL environment variable') + sys.exit(utils.STGIT_GENERAL_ERROR) try: + directory.setup() config_setup() - # 'clone' doesn't expect an already initialised GIT tree. A Series - # object will be created after the GIT tree is cloned - if cmd != 'clone': + # Some commands don't (always) need an initialized series. + if directory.needs_current_series: if hasattr(options, 'branch') and options.branch: command.crt_series = Series(options.branch) else: command.crt_series = Series() - stgit.commands.common.crt_series = command.crt_series - command.func(parser, options, args) - except (IOError, ParsingError, NoSectionError, CmdException, - StackException, GitException, GitMergeException), err: - print >> sys.stderr, '%s %s: %s' % (prog, cmd, err) - sys.exit(2) + ret = command.func(parser, options, args) + except (StgException, IOError, ParsingError, NoSectionError), err: + directory.write_log(cmd) + out.error(str(err), title = '%s %s' % (prog, cmd)) + if debug_level > 0: + traceback.print_exc() + sys.exit(utils.STGIT_COMMAND_ERROR) + except SystemExit: + # Triggered by the option parser when it finds bad commandline + # parameters. + sys.exit(utils.STGIT_COMMAND_ERROR) except KeyboardInterrupt: - sys.exit(1) + sys.exit(utils.STGIT_GENERAL_ERROR) + except: + out.error('Unhandled exception:') + traceback.print_exc() + sys.exit(utils.STGIT_BUG_ERROR) + + directory.write_log(cmd) + sys.exit(ret or utils.STGIT_SUCCESS) - sys.exit(0) +def main(): + try: + _main() + finally: + run.finish_logging()