X-Git-Url: https://git.distorted.org.uk/~mdw/stgit/blobdiff_plain/7b1ba1a6f8c89f551377b3b3791bfee7b01d3350..841c7b2a6b015e3ab3331713cf10caf7a4fd0b49:/stgit/main.py diff --git a/stgit/main.py b/stgit/main.py index 07bc7d4..8694acd 100644 --- a/stgit/main.py +++ b/stgit/main.py @@ -19,92 +19,169 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ import sys, os -from optparse import OptionParser, make_option - -from stgit.utils import * -from stgit import stack, git -from stgit.version import version -from stgit.config import config -from stgit.commands.common import * - -# The commands -import stgit.commands.add -import stgit.commands.applied -import stgit.commands.branch -import stgit.commands.delete -import stgit.commands.diff -import stgit.commands.clean -import stgit.commands.clone -import stgit.commands.commit -import stgit.commands.export -import stgit.commands.files -import stgit.commands.fold -import stgit.commands.id -import stgit.commands.imprt -import stgit.commands.init -import stgit.commands.mail -import stgit.commands.new -import stgit.commands.pick -import stgit.commands.pop -import stgit.commands.pull -import stgit.commands.push -import stgit.commands.refresh -import stgit.commands.rename -import stgit.commands.resolved -import stgit.commands.rm -import stgit.commands.series -import stgit.commands.status -import stgit.commands.top -import stgit.commands.unapplied +from optparse import OptionParser +import stgit.commands # # The commands map # -commands = { - 'add': stgit.commands.add, - 'applied': stgit.commands.applied, - 'branch': stgit.commands.branch, - 'delete': stgit.commands.delete, - 'diff': stgit.commands.diff, - 'clean': stgit.commands.clean, - 'clone': stgit.commands.clone, - 'commit': stgit.commands.commit, - 'export': stgit.commands.export, - 'files': stgit.commands.files, - 'fold': stgit.commands.fold, - 'id': stgit.commands.id, - 'import': stgit.commands.imprt, - 'init': stgit.commands.init, - 'mail': stgit.commands.mail, - 'new': stgit.commands.new, - 'pick': stgit.commands.pick, - 'pop': stgit.commands.pop, - 'pull': stgit.commands.pull, - 'push': stgit.commands.push, - 'refresh': stgit.commands.refresh, - 'rename': stgit.commands.rename, - 'resolved': stgit.commands.resolved, - 'rm': stgit.commands.rm, - 'series': stgit.commands.series, - 'status': stgit.commands.status, - 'top': stgit.commands.top, - 'unapplied':stgit.commands.unapplied, - } +class Commands(dict): + """Commands class. It performs on-demand module loading + """ + def __getitem__(self, key): + """Return the command python module name based. + """ + global prog + + cmd_mod = self.get(key) + if not cmd_mod: + 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) + elif len(candidates) > 1: + print >> sys.stderr, 'Ambiguous command: %s' % key + print >> sys.stderr, ' Candidates are: %s' \ + % ', '.join(candidates) + sys.exit(1) + + cmd_mod = self.get(candidates[0]) + + __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' + }) + +# 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' + ) + +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 - print 'commands:' - print ' help print this message' + print 'Generic commands:' + print ' help print the detailed command usage' print ' version display version information' print ' copyright display copyright information' - print - + # unclassified commands if any cmds = commands.keys() cmds.sort() for cmd in cmds: - print ' ' + cmd + ' ' * (12 - len(cmd)) + commands[cmd].help + 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) # # The main function (command dispatcher) @@ -112,56 +189,88 @@ def print_help(): def main(): """The main function """ + global prog + prog = os.path.basename(sys.argv[0]) if len(sys.argv) < 2: - print >> sys.stderr, 'Unknown command' + print >> sys.stderr, 'usage: %s ' % prog print >> sys.stderr, \ - ' Try "%s help" for a list of supported commands' % prog + ' Try "%s --help" for a list of supported commands' % prog sys.exit(1) cmd = sys.argv[1] - if cmd in ['-h', '--help', 'help']: - print_help() + if cmd in ['-h', '--help']: + if len(sys.argv) >= 3 and sys.argv[2] in commands: + cmd = sys.argv[2] + sys.argv[2] = '--help' + else: + print_help() + sys.exit(0) + if cmd == 'help': + if len(sys.argv) == 3 and not sys.argv[2] in ['-h', '--help']: + cmd = sys.argv[2] + if not cmd in commands: + print >> sys.stderr, '%s help: "%s" command unknown' \ + % (prog, cmd) + sys.exit(1) + + sys.argv[0] += ' %s' % cmd + command = commands[cmd] + parser = OptionParser(usage = command.usage, + option_list = command.options) + from pydoc import pager + pager(parser.format_help()) + else: + print_help() sys.exit(0) 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) if cmd in ['copyright']: print __copyright__ sys.exit(0) - if not cmd in commands: - print >> sys.stderr, 'Unknown command: %s' % cmd - print >> sys.stderr, ' Try "%s help" for a list of supported ' \ - 'commands' % prog - sys.exit(1) # re-build the command line arguments sys.argv[0] += ' %s' % cmd del(sys.argv[1]) command = commands[cmd] - parser = OptionParser(usage = command.usage, - option_list = command.options) + usage = command.usage.split('\n')[0].strip() + parser = OptionParser(usage = usage, option_list = command.options) options, args = parser.parse_args() + + # These modules are only used from this point onwards and do not + # need to be imported earlier + 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 + try: - # 'clone' doesn't expect an already initialised GIT tree - if cmd == 'clone': - stgit.commands.common.crt_series = stack.Series('master') - elif hasattr(options, 'branch') and options.branch: - stgit.commands.common.crt_series = stack.Series(options.branch) - else: - stgit.commands.common.crt_series = stack.Series() - # the line below is a simple way to avoid an exception when - # stgit is run outside an initialised tree - setattr(command, 'crt_series', stgit.commands.common.crt_series) + 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': + 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, CmdException, stack.StackException, git.GitException), \ - err: + except (IOError, ParsingError, NoSectionError, CmdException, + StackException, GitException, GitMergeException), err: print >> sys.stderr, '%s %s: %s' % (prog, cmd, err) sys.exit(2) + except KeyboardInterrupt: + sys.exit(1) sys.exit(0)