Auto-generate man pages for all StGit commands
[stgit] / stgit / main.py
CommitLineData
41a6d859
CM
1"""Basic quilt-like functionality
2"""
3
4__copyright__ = """
5Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License version 2 as
9published by the Free Software Foundation.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19"""
20
08986eda 21import sys, os, traceback
41a6d859 22
c333afcf 23import stgit.commands
5e888f30 24from stgit.out import *
575bbdae 25from stgit import argparse, run, utils
41a6d859 26
41a6d859
CM
27#
28# The commands map
29#
c333afcf
CM
30class Commands(dict):
31 """Commands class. It performs on-demand module loading
32 """
78340ff1
YD
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:
27ac2b7e
KH
40 out.error('Unknown command: %s' % key,
41 'Try "%s help" for a list of supported commands' % prog)
5be69cd8 42 sys.exit(utils.STGIT_GENERAL_ERROR)
78340ff1 43 elif len(candidates) > 1:
27ac2b7e
KH
44 out.error('Ambiguous command: %s' % key,
45 'Candidates are: %s' % ', '.join(candidates))
5be69cd8 46 sys.exit(utils.STGIT_GENERAL_ERROR)
78340ff1
YD
47
48 return candidates[0]
49
c333afcf 50 def __getitem__(self, key):
514dd4f2
CM
51 """Return the command python module name based.
52 """
53 global prog
54
78340ff1 55 cmd_mod = self.get(key) or self.get(self.canonical_cmd(key))
514dd4f2 56
c333afcf
CM
57 __import__('stgit.commands.' + cmd_mod)
58 return getattr(stgit.commands, cmd_mod)
59
60commands = Commands({
c333afcf
CM
61 'branch': 'branch',
62 'delete': 'delete',
63 'diff': 'diff',
64 'clean': 'clean',
65 'clone': 'clone',
48b209cd 66 'coalesce': 'coalesce',
c333afcf 67 'commit': 'commit',
ed60fdae 68 'edit': 'edit',
c333afcf
CM
69 'export': 'export',
70 'files': 'files',
71 'float': 'float',
72 'fold': 'fold',
73 'goto': 'goto',
841c7b2a 74 'hide': 'hide',
c333afcf
CM
75 'id': 'id',
76 'import': 'imprt',
77 'init': 'init',
78 'log': 'log',
79 'mail': 'mail',
80 'new': 'new',
81 'patches': 'patches',
82 'pick': 'pick',
83 'pop': 'pop',
84 'pull': 'pull',
85 'push': 'push',
22037590 86 'rebase': 'rebase',
c333afcf
CM
87 'refresh': 'refresh',
88 'rename': 'rename',
051090dd 89 'repair': 'repair',
c333afcf 90 'resolved': 'resolved',
c333afcf
CM
91 'series': 'series',
92 'show': 'show',
6f1c5e3c 93 'sink': 'sink',
c333afcf 94 'status': 'status',
06848fab 95 'sync': 'sync',
c333afcf 96 'top': 'top',
841c7b2a
CM
97 'uncommit': 'uncommit',
98 'unhide': 'unhide'
c333afcf 99 })
41a6d859 100
5dc51fea
YD
101# classification: repository, stack, patch, working copy
102repocommands = (
5dc51fea
YD
103 'clone',
104 'id',
5dc51fea
YD
105 )
106stackcommands = (
4ec67741 107 'branch',
5dc51fea 108 'clean',
48b209cd 109 'coalesce',
5dc51fea 110 'commit',
d98a499c 111 'float',
5dc51fea 112 'goto',
841c7b2a 113 'hide',
5dc51fea 114 'init',
4ec67741 115 'patches',
5dc51fea 116 'pop',
4ec67741 117 'pull',
5dc51fea 118 'push',
22037590 119 'rebase',
051090dd 120 'repair',
5dc51fea 121 'series',
6f1c5e3c 122 'sink',
5dc51fea 123 'top',
841c7b2a 124 'uncommit',
4ec67741 125 'unhide',
5dc51fea
YD
126 )
127patchcommands = (
128 'delete',
d8b2e601 129 'edit',
5dc51fea
YD
130 'export',
131 'files',
132 'fold',
133 'import',
64354a2d 134 'log',
5dc51fea
YD
135 'mail',
136 'new',
137 'pick',
138 'refresh',
139 'rename',
06848fab 140 'show',
4ec67741 141 'sync',
5dc51fea
YD
142 )
143wccommands = (
5dc51fea 144 'diff',
5dc51fea 145 'resolved',
4ec67741 146 'status',
5dc51fea
YD
147 )
148
149def _print_helpstring(cmd):
150 print ' ' + cmd + ' ' * (12 - len(cmd)) + commands[cmd].help
151
41a6d859
CM
152def print_help():
153 print 'usage: %s <command> [options]' % os.path.basename(sys.argv[0])
154 print
5dc51fea 155 print 'Generic commands:'
f0699cc7 156 print ' help print the detailed command usage'
1e0bdf2a 157 print ' version display version information'
22ea9102 158 print ' copyright display copyright information'
5dc51fea 159 # unclassified commands if any
41a6d859
CM
160 cmds = commands.keys()
161 cmds.sort()
162 for cmd in cmds:
5dc51fea
YD
163 if not cmd in repocommands and not cmd in stackcommands \
164 and not cmd in patchcommands and not cmd in wccommands:
165 _print_helpstring(cmd)
166 print
167
168 print 'Repository commands:'
169 for cmd in repocommands:
170 _print_helpstring(cmd)
171 print
172
173 print 'Stack commands:'
174 for cmd in stackcommands:
175 _print_helpstring(cmd)
176 print
177
178 print 'Patch commands:'
179 for cmd in patchcommands:
180 _print_helpstring(cmd)
181 print
182
183 print 'Working-copy commands:'
184 for cmd in wccommands:
185 _print_helpstring(cmd)
41a6d859
CM
186
187#
188# The main function (command dispatcher)
189#
36a06e01 190def _main():
41a6d859
CM
191 """The main function
192 """
514dd4f2
CM
193 global prog
194
41a6d859
CM
195 prog = os.path.basename(sys.argv[0])
196
197 if len(sys.argv) < 2:
d00e708a 198 print >> sys.stderr, 'usage: %s <command>' % prog
41a6d859 199 print >> sys.stderr, \
f0699cc7 200 ' Try "%s --help" for a list of supported commands' % prog
5be69cd8 201 sys.exit(utils.STGIT_GENERAL_ERROR)
41a6d859
CM
202
203 cmd = sys.argv[1]
204
f0699cc7 205 if cmd in ['-h', '--help']:
78340ff1
YD
206 if len(sys.argv) >= 3:
207 cmd = commands.canonical_cmd(sys.argv[2])
f0699cc7 208 sys.argv[2] = '--help'
31c5abf2
PR
209 else:
210 print_help()
5be69cd8 211 sys.exit(utils.STGIT_SUCCESS)
f0699cc7
CM
212 if cmd == 'help':
213 if len(sys.argv) == 3 and not sys.argv[2] in ['-h', '--help']:
78340ff1 214 cmd = commands.canonical_cmd(sys.argv[2])
f0699cc7 215 if not cmd in commands:
27ac2b7e 216 out.error('%s help: "%s" command unknown' % (prog, cmd))
5be69cd8 217 sys.exit(utils.STGIT_GENERAL_ERROR)
f0699cc7
CM
218
219 sys.argv[0] += ' %s' % cmd
220 command = commands[cmd]
575bbdae 221 parser = argparse.make_option_parser(command)
0d4cd7ce
CM
222 from pydoc import pager
223 pager(parser.format_help())
f0699cc7 224 else:
4fe42e63 225 print_help()
5be69cd8 226 sys.exit(utils.STGIT_SUCCESS)
1e0bdf2a 227 if cmd in ['-v', '--version', 'version']:
c333afcf 228 from stgit.version import version
4df2f866 229 print 'Stacked GIT %s' % version
50725547 230 os.system('git --version')
1e0bdf2a 231 print 'Python version %s' % sys.version
5be69cd8 232 sys.exit(utils.STGIT_SUCCESS)
22ea9102
CM
233 if cmd in ['copyright']:
234 print __copyright__
5be69cd8 235 sys.exit(utils.STGIT_SUCCESS)
41a6d859
CM
236
237 # re-build the command line arguments
3faeaeb1
CM
238 cmd = commands.canonical_cmd(cmd)
239 sys.argv[0] += ' %s' % cmd
41a6d859
CM
240 del(sys.argv[1])
241
242 command = commands[cmd]
575bbdae 243 parser = argparse.make_option_parser(command)
41a6d859 244 options, args = parser.parse_args()
6dd8fafa 245 directory = command.directory
22d87516
CM
246
247 # These modules are only used from this point onwards and do not
248 # need to be imported earlier
87c93eab 249 from stgit.exception import StgException
eee7283e 250 from stgit.config import config_setup
9e3f506f 251 from ConfigParser import ParsingError, NoSectionError
87c93eab 252 from stgit.stack import Series
22d87516 253
41a6d859 254 try:
4200335f 255 debug_level = int(os.environ.get('STGIT_DEBUG_LEVEL', 0))
b2017c38 256 except ValueError:
27ac2b7e 257 out.error('Invalid STGIT_DEBUG_LEVEL environment variable')
5be69cd8 258 sys.exit(utils.STGIT_GENERAL_ERROR)
b2017c38
CM
259
260 try:
6dd8fafa 261 directory.setup()
eee7283e
CM
262 config_setup()
263
44a01a58
KH
264 # Some commands don't (always) need an initialized series.
265 if directory.needs_current_series:
98290387 266 if hasattr(options, 'branch') and options.branch:
c333afcf 267 command.crt_series = Series(options.branch)
98290387 268 else:
c333afcf 269 command.crt_series = Series()
9ac09909 270
f9cc5e69 271 ret = command.func(parser, options, args)
87c93eab 272 except (StgException, IOError, ParsingError, NoSectionError), err:
762f6c8c 273 out.error(str(err), title = '%s %s' % (prog, cmd))
fe104619 274 if debug_level > 0:
08986eda
KH
275 traceback.print_exc()
276 sys.exit(utils.STGIT_COMMAND_ERROR)
f3167489
KH
277 except SystemExit:
278 # Triggered by the option parser when it finds bad commandline
279 # parameters.
280 sys.exit(utils.STGIT_COMMAND_ERROR)
4d9fc826 281 except KeyboardInterrupt:
5be69cd8 282 sys.exit(utils.STGIT_GENERAL_ERROR)
08986eda
KH
283 except:
284 out.error('Unhandled exception:')
285 traceback.print_exc()
286 sys.exit(utils.STGIT_BUG_ERROR)
41a6d859 287
f9cc5e69 288 sys.exit(ret or utils.STGIT_SUCCESS)
36a06e01
KH
289
290def main():
291 try:
292 _main()
293 finally:
294 run.finish_logging()