chiark / gitweb /
48d8dbb608d06e70a4d0a4aa341d75e7173ebc8a
[stgit] / stgit / main.py
1 """Basic quilt-like functionality
2 """
3
4 __copyright__ = """
5 Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 """
20
21 import sys, os, traceback
22
23 import stgit.commands
24 from stgit.out import *
25 from stgit import argparse, run, utils
26
27 #
28 # The commands map
29 #
30 class Commands(dict):
31     """Commands class. It performs on-demand module loading
32     """
33     def canonical_cmd(self, key):
34         """Return the canonical name for a possibly-shortenned
35         command name.
36         """
37         candidates = [cmd for cmd in self.keys() if cmd.startswith(key)]
38
39         if not candidates:
40             out.error('Unknown command: %s' % key,
41                       'Try "%s help" for a list of supported commands' % prog)
42             sys.exit(utils.STGIT_GENERAL_ERROR)
43         elif len(candidates) > 1:
44             out.error('Ambiguous command: %s' % key,
45                       'Candidates are: %s' % ', '.join(candidates))
46             sys.exit(utils.STGIT_GENERAL_ERROR)
47
48         return candidates[0]
49         
50     def __getitem__(self, key):
51         cmd_mod = self.get(key) or self.get(self.canonical_cmd(key))
52         return stgit.commands.get_command(cmd_mod)
53
54 cmd_list = stgit.commands.get_commands()
55 commands = Commands((cmd, mod) for cmd, (mod, kind, help)
56                     in cmd_list.iteritems())
57
58 def print_help():
59     print 'usage: %s <command> [options]' % os.path.basename(sys.argv[0])
60     print
61     print 'Generic commands:'
62     print '  help        print the detailed command usage'
63     print '  version     display version information'
64     print '  copyright   display copyright information'
65     print
66     stgit.commands.pretty_command_list(cmd_list, sys.stdout)
67
68 #
69 # The main function (command dispatcher)
70 #
71 def _main():
72     """The main function
73     """
74     global prog
75
76     prog = os.path.basename(sys.argv[0])
77
78     if len(sys.argv) < 2:
79         print >> sys.stderr, 'usage: %s <command>' % prog
80         print >> sys.stderr, \
81               '  Try "%s --help" for a list of supported commands' % prog
82         sys.exit(utils.STGIT_GENERAL_ERROR)
83
84     cmd = sys.argv[1]
85
86     if cmd in ['-h', '--help']:
87         if len(sys.argv) >= 3:
88             cmd = commands.canonical_cmd(sys.argv[2])
89             sys.argv[2] = '--help'
90         else:
91             print_help()
92             sys.exit(utils.STGIT_SUCCESS)
93     if cmd == 'help':
94         if len(sys.argv) == 3 and not sys.argv[2] in ['-h', '--help']:
95             cmd = commands.canonical_cmd(sys.argv[2])
96             if not cmd in commands:
97                 out.error('%s help: "%s" command unknown' % (prog, cmd))
98                 sys.exit(utils.STGIT_GENERAL_ERROR)
99
100             sys.argv[0] += ' %s' % cmd
101             command = commands[cmd]
102             parser = argparse.make_option_parser(command)
103             from pydoc import pager
104             pager(parser.format_help())
105         else:
106             print_help()
107         sys.exit(utils.STGIT_SUCCESS)
108     if cmd in ['-v', '--version', 'version']:
109         from stgit.version import version
110         print 'Stacked GIT %s' % version
111         os.system('git --version')
112         print 'Python version %s' % sys.version
113         sys.exit(utils.STGIT_SUCCESS)
114     if cmd in ['copyright']:
115         print __copyright__
116         sys.exit(utils.STGIT_SUCCESS)
117
118     # re-build the command line arguments
119     cmd = commands.canonical_cmd(cmd)
120     sys.argv[0] += ' %s' % cmd
121     del(sys.argv[1])
122
123     command = commands[cmd]
124     parser = argparse.make_option_parser(command)
125     options, args = parser.parse_args()
126     directory = command.directory
127
128     # These modules are only used from this point onwards and do not
129     # need to be imported earlier
130     from stgit.exception import StgException
131     from stgit.config import config_setup
132     from ConfigParser import ParsingError, NoSectionError
133     from stgit.stack import Series
134
135     try:
136         debug_level = int(os.environ.get('STGIT_DEBUG_LEVEL', 0))
137     except ValueError:
138         out.error('Invalid STGIT_DEBUG_LEVEL environment variable')
139         sys.exit(utils.STGIT_GENERAL_ERROR)
140
141     try:
142         directory.setup()
143         config_setup()
144
145         # Some commands don't (always) need an initialized series.
146         if directory.needs_current_series:
147             if hasattr(options, 'branch') and options.branch:
148                 command.crt_series = Series(options.branch)
149             else:
150                 command.crt_series = Series()
151
152         ret = command.func(parser, options, args)
153     except (StgException, IOError, ParsingError, NoSectionError), err:
154         out.error(str(err), title = '%s %s' % (prog, cmd))
155         if debug_level > 0:
156             traceback.print_exc()
157         sys.exit(utils.STGIT_COMMAND_ERROR)
158     except SystemExit:
159         # Triggered by the option parser when it finds bad commandline
160         # parameters.
161         sys.exit(utils.STGIT_COMMAND_ERROR)
162     except KeyboardInterrupt:
163         sys.exit(utils.STGIT_GENERAL_ERROR)
164     except:
165         out.error('Unhandled exception:')
166         traceback.print_exc()
167         sys.exit(utils.STGIT_BUG_ERROR)
168
169     sys.exit(ret or utils.STGIT_SUCCESS)
170
171 def main():
172     try:
173         _main()
174     finally:
175         run.finish_logging()