debian/rules should be producing architecture independent packages
[stgit/dwhite.git] / stgit / main.py
bloba98fe49d90f26560a2667d432010c1a2320d1c7c
1 """Basic quilt-like functionality
2 """
4 __copyright__ = """
5 Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
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.
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.
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 """
21 import sys, os, traceback
22 from optparse import OptionParser
24 import stgit.commands
25 from stgit.out import *
26 from stgit import run, utils
29 # The commands map
31 class Commands(dict):
32 """Commands class. It performs on-demand module loading
33 """
34 def canonical_cmd(self, key):
35 """Return the canonical name for a possibly-shortenned
36 command name.
37 """
38 candidates = [cmd for cmd in self.keys() if cmd.startswith(key)]
40 if not candidates:
41 out.error('Unknown command: %s' % key,
42 'Try "%s help" for a list of supported commands' % prog)
43 sys.exit(utils.STGIT_GENERAL_ERROR)
44 elif len(candidates) > 1:
45 out.error('Ambiguous command: %s' % key,
46 'Candidates are: %s' % ', '.join(candidates))
47 sys.exit(utils.STGIT_GENERAL_ERROR)
49 return candidates[0]
51 def __getitem__(self, key):
52 """Return the command python module name based.
53 """
54 global prog
56 cmd_mod = self.get(key) or self.get(self.canonical_cmd(key))
58 __import__('stgit.commands.' + cmd_mod)
59 return getattr(stgit.commands, cmd_mod)
61 commands = Commands({
62 'branch': 'branch',
63 'delete': 'delete',
64 'diff': 'diff',
65 'clean': 'clean',
66 'clone': 'clone',
67 'coalesce': 'coalesce',
68 'commit': 'commit',
69 'edit': 'edit',
70 'export': 'export',
71 'files': 'files',
72 'float': 'float',
73 'fold': 'fold',
74 'goto': 'goto',
75 'hide': 'hide',
76 'id': 'id',
77 'import': 'imprt',
78 'init': 'init',
79 'log': 'log',
80 'mail': 'mail',
81 'new': 'new',
82 'patches': 'patches',
83 'pick': 'pick',
84 'pop': 'pop',
85 'pull': 'pull',
86 'push': 'push',
87 'rebase': 'rebase',
88 'refresh': 'refresh',
89 'rename': 'rename',
90 'repair': 'repair',
91 'resolved': 'resolved',
92 'series': 'series',
93 'show': 'show',
94 'sink': 'sink',
95 'status': 'status',
96 'sync': 'sync',
97 'top': 'top',
98 'uncommit': 'uncommit',
99 'unhide': 'unhide'
102 # classification: repository, stack, patch, working copy
103 repocommands = (
104 'clone',
105 'id',
107 stackcommands = (
108 'branch',
109 'clean',
110 'coalesce',
111 'commit',
112 'float',
113 'goto',
114 'hide',
115 'init',
116 'patches',
117 'pop',
118 'pull',
119 'push',
120 'rebase',
121 'repair',
122 'series',
123 'sink',
124 'top',
125 'uncommit',
126 'unhide',
128 patchcommands = (
129 'delete',
130 'edit',
131 'export',
132 'files',
133 'fold',
134 'import',
135 'log',
136 'mail',
137 'new',
138 'pick',
139 'refresh',
140 'rename',
141 'show',
142 'sync',
144 wccommands = (
145 'diff',
146 'resolved',
147 'status',
150 def _print_helpstring(cmd):
151 print ' ' + cmd + ' ' * (12 - len(cmd)) + commands[cmd].help
153 def print_help():
154 print 'usage: %s <command> [options]' % os.path.basename(sys.argv[0])
155 print
156 print 'Generic commands:'
157 print ' help print the detailed command usage'
158 print ' version display version information'
159 print ' copyright display copyright information'
160 # unclassified commands if any
161 cmds = commands.keys()
162 cmds.sort()
163 for cmd in cmds:
164 if not cmd in repocommands and not cmd in stackcommands \
165 and not cmd in patchcommands and not cmd in wccommands:
166 _print_helpstring(cmd)
167 print
169 print 'Repository commands:'
170 for cmd in repocommands:
171 _print_helpstring(cmd)
172 print
174 print 'Stack commands:'
175 for cmd in stackcommands:
176 _print_helpstring(cmd)
177 print
179 print 'Patch commands:'
180 for cmd in patchcommands:
181 _print_helpstring(cmd)
182 print
184 print 'Working-copy commands:'
185 for cmd in wccommands:
186 _print_helpstring(cmd)
189 # The main function (command dispatcher)
191 def _main():
192 """The main function
194 global prog
196 prog = os.path.basename(sys.argv[0])
198 if len(sys.argv) < 2:
199 print >> sys.stderr, 'usage: %s <command>' % prog
200 print >> sys.stderr, \
201 ' Try "%s --help" for a list of supported commands' % prog
202 sys.exit(utils.STGIT_GENERAL_ERROR)
204 cmd = sys.argv[1]
206 if cmd in ['-h', '--help']:
207 if len(sys.argv) >= 3:
208 cmd = commands.canonical_cmd(sys.argv[2])
209 sys.argv[2] = '--help'
210 else:
211 print_help()
212 sys.exit(utils.STGIT_SUCCESS)
213 if cmd == 'help':
214 if len(sys.argv) == 3 and not sys.argv[2] in ['-h', '--help']:
215 cmd = commands.canonical_cmd(sys.argv[2])
216 if not cmd in commands:
217 out.error('%s help: "%s" command unknown' % (prog, cmd))
218 sys.exit(utils.STGIT_GENERAL_ERROR)
220 sys.argv[0] += ' %s' % cmd
221 command = commands[cmd]
222 parser = OptionParser(usage = command.usage,
223 option_list = command.options)
224 from pydoc import pager
225 pager(parser.format_help())
226 else:
227 print_help()
228 sys.exit(utils.STGIT_SUCCESS)
229 if cmd in ['-v', '--version', 'version']:
230 from stgit.version import version
231 print 'Stacked GIT %s' % version
232 os.system('git --version')
233 print 'Python version %s' % sys.version
234 sys.exit(utils.STGIT_SUCCESS)
235 if cmd in ['copyright']:
236 print __copyright__
237 sys.exit(utils.STGIT_SUCCESS)
239 # re-build the command line arguments
240 cmd = commands.canonical_cmd(cmd)
241 sys.argv[0] += ' %s' % cmd
242 del(sys.argv[1])
244 command = commands[cmd]
245 usage = command.usage.split('\n')[0].strip()
246 parser = OptionParser(usage = usage, option_list = command.options)
247 options, args = parser.parse_args()
248 directory = command.directory
250 # These modules are only used from this point onwards and do not
251 # need to be imported earlier
252 from stgit.exception import StgException
253 from stgit.config import config_setup
254 from ConfigParser import ParsingError, NoSectionError
255 from stgit.stack import Series
257 try:
258 debug_level = int(os.environ.get('STGIT_DEBUG_LEVEL', 0))
259 except ValueError:
260 out.error('Invalid STGIT_DEBUG_LEVEL environment variable')
261 sys.exit(utils.STGIT_GENERAL_ERROR)
263 try:
264 directory.setup()
265 config_setup()
267 # Some commands don't (always) need an initialized series.
268 if directory.needs_current_series:
269 if hasattr(options, 'branch') and options.branch:
270 command.crt_series = Series(options.branch)
271 else:
272 command.crt_series = Series()
274 ret = command.func(parser, options, args)
275 except (StgException, IOError, ParsingError, NoSectionError), err:
276 out.error(str(err), title = '%s %s' % (prog, cmd))
277 if debug_level > 0:
278 traceback.print_exc()
279 sys.exit(utils.STGIT_COMMAND_ERROR)
280 except SystemExit:
281 # Triggered by the option parser when it finds bad commandline
282 # parameters.
283 sys.exit(utils.STGIT_COMMAND_ERROR)
284 except KeyboardInterrupt:
285 sys.exit(utils.STGIT_GENERAL_ERROR)
286 except:
287 out.error('Unhandled exception:')
288 traceback.print_exc()
289 sys.exit(utils.STGIT_BUG_ERROR)
291 sys.exit(ret or utils.STGIT_SUCCESS)
293 def main():
294 try:
295 _main()
296 finally:
297 run.finish_logging()