chiark / gitweb /
Make a common superclass for all StGit exceptions
[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
21import sys, os
c333afcf 22from optparse import OptionParser
41a6d859 23
c333afcf 24import stgit.commands
5e888f30 25from stgit.out import *
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)
78340ff1
YD
42 sys.exit(1)
43 elif len(candidates) > 1:
27ac2b7e
KH
44 out.error('Ambiguous command: %s' % key,
45 'Candidates are: %s' % ', '.join(candidates))
78340ff1
YD
46 sys.exit(1)
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({
61 'add': 'add',
62 'applied': 'applied',
63 'assimilate': 'assimilate',
64 'branch': 'branch',
65 'delete': 'delete',
66 'diff': 'diff',
67 'clean': 'clean',
68 'clone': 'clone',
69 'commit': 'commit',
d5ae2173 70 'cp': 'copy',
ed60fdae 71 'edit': 'edit',
c333afcf
CM
72 'export': 'export',
73 'files': 'files',
74 'float': 'float',
75 'fold': 'fold',
76 'goto': 'goto',
841c7b2a 77 'hide': 'hide',
c333afcf
CM
78 'id': 'id',
79 'import': 'imprt',
80 'init': 'init',
81 'log': 'log',
82 'mail': 'mail',
83 'new': 'new',
84 'patches': 'patches',
85 'pick': 'pick',
86 'pop': 'pop',
87 'pull': 'pull',
88 'push': 'push',
22037590 89 'rebase': 'rebase',
c333afcf
CM
90 'refresh': 'refresh',
91 'rename': 'rename',
92 'resolved': 'resolved',
93 'rm': 'rm',
94 'series': 'series',
95 'show': 'show',
6f1c5e3c 96 'sink': 'sink',
c333afcf 97 'status': 'status',
06848fab 98 'sync': 'sync',
c333afcf
CM
99 'top': 'top',
100 'unapplied': 'unapplied',
841c7b2a
CM
101 'uncommit': 'uncommit',
102 'unhide': 'unhide'
c333afcf 103 })
41a6d859 104
5dc51fea
YD
105# classification: repository, stack, patch, working copy
106repocommands = (
5dc51fea
YD
107 'clone',
108 'id',
5dc51fea
YD
109 )
110stackcommands = (
111 'applied',
4d0ba818 112 'assimilate',
4ec67741 113 'branch',
5dc51fea
YD
114 'clean',
115 'commit',
d98a499c 116 'float',
5dc51fea 117 'goto',
841c7b2a 118 'hide',
5dc51fea 119 'init',
4ec67741 120 'patches',
5dc51fea 121 'pop',
4ec67741 122 'pull',
5dc51fea 123 'push',
22037590 124 'rebase',
5dc51fea 125 'series',
6f1c5e3c 126 'sink',
5dc51fea
YD
127 'top',
128 'unapplied',
841c7b2a 129 'uncommit',
4ec67741 130 'unhide',
5dc51fea
YD
131 )
132patchcommands = (
133 'delete',
d8b2e601 134 'edit',
5dc51fea
YD
135 'export',
136 'files',
137 'fold',
138 'import',
64354a2d 139 'log',
5dc51fea
YD
140 'mail',
141 'new',
142 'pick',
143 'refresh',
144 'rename',
06848fab 145 'show',
4ec67741 146 'sync',
5dc51fea
YD
147 )
148wccommands = (
149 'add',
d5ae2173 150 'cp',
5dc51fea 151 'diff',
5dc51fea
YD
152 'resolved',
153 'rm',
4ec67741 154 'status',
5dc51fea
YD
155 )
156
157def _print_helpstring(cmd):
158 print ' ' + cmd + ' ' * (12 - len(cmd)) + commands[cmd].help
159
41a6d859
CM
160def print_help():
161 print 'usage: %s <command> [options]' % os.path.basename(sys.argv[0])
162 print
5dc51fea 163 print 'Generic commands:'
f0699cc7 164 print ' help print the detailed command usage'
1e0bdf2a 165 print ' version display version information'
22ea9102 166 print ' copyright display copyright information'
5dc51fea 167 # unclassified commands if any
41a6d859
CM
168 cmds = commands.keys()
169 cmds.sort()
170 for cmd in cmds:
5dc51fea
YD
171 if not cmd in repocommands and not cmd in stackcommands \
172 and not cmd in patchcommands and not cmd in wccommands:
173 _print_helpstring(cmd)
174 print
175
176 print 'Repository commands:'
177 for cmd in repocommands:
178 _print_helpstring(cmd)
179 print
180
181 print 'Stack commands:'
182 for cmd in stackcommands:
183 _print_helpstring(cmd)
184 print
185
186 print 'Patch commands:'
187 for cmd in patchcommands:
188 _print_helpstring(cmd)
189 print
190
191 print 'Working-copy commands:'
192 for cmd in wccommands:
193 _print_helpstring(cmd)
41a6d859
CM
194
195#
196# The main function (command dispatcher)
197#
198def main():
199 """The main function
200 """
514dd4f2
CM
201 global prog
202
41a6d859
CM
203 prog = os.path.basename(sys.argv[0])
204
205 if len(sys.argv) < 2:
d00e708a 206 print >> sys.stderr, 'usage: %s <command>' % prog
41a6d859 207 print >> sys.stderr, \
f0699cc7 208 ' Try "%s --help" for a list of supported commands' % prog
41a6d859
CM
209 sys.exit(1)
210
211 cmd = sys.argv[1]
212
f0699cc7 213 if cmd in ['-h', '--help']:
78340ff1
YD
214 if len(sys.argv) >= 3:
215 cmd = commands.canonical_cmd(sys.argv[2])
f0699cc7 216 sys.argv[2] = '--help'
31c5abf2
PR
217 else:
218 print_help()
219 sys.exit(0)
f0699cc7
CM
220 if cmd == 'help':
221 if len(sys.argv) == 3 and not sys.argv[2] in ['-h', '--help']:
78340ff1 222 cmd = commands.canonical_cmd(sys.argv[2])
f0699cc7 223 if not cmd in commands:
27ac2b7e 224 out.error('%s help: "%s" command unknown' % (prog, cmd))
f0699cc7
CM
225 sys.exit(1)
226
227 sys.argv[0] += ' %s' % cmd
228 command = commands[cmd]
229 parser = OptionParser(usage = command.usage,
230 option_list = command.options)
0d4cd7ce
CM
231 from pydoc import pager
232 pager(parser.format_help())
f0699cc7 233 else:
4fe42e63 234 print_help()
f0699cc7 235 sys.exit(0)
1e0bdf2a 236 if cmd in ['-v', '--version', 'version']:
c333afcf 237 from stgit.version import version
4df2f866 238 print 'Stacked GIT %s' % version
50725547 239 os.system('git --version')
1e0bdf2a 240 print 'Python version %s' % sys.version
41a6d859 241 sys.exit(0)
22ea9102
CM
242 if cmd in ['copyright']:
243 print __copyright__
244 sys.exit(0)
41a6d859
CM
245
246 # re-build the command line arguments
3faeaeb1
CM
247 cmd = commands.canonical_cmd(cmd)
248 sys.argv[0] += ' %s' % cmd
41a6d859
CM
249 del(sys.argv[1])
250
251 command = commands[cmd]
f0699cc7
CM
252 usage = command.usage.split('\n')[0].strip()
253 parser = OptionParser(usage = usage, option_list = command.options)
41a6d859 254 options, args = parser.parse_args()
22d87516
CM
255
256 # These modules are only used from this point onwards and do not
257 # need to be imported earlier
87c93eab 258 from stgit.exception import StgException
eee7283e 259 from stgit.config import config_setup
9e3f506f 260 from ConfigParser import ParsingError, NoSectionError
87c93eab 261 from stgit.stack import Series
22d87516 262
b2017c38
CM
263 try:
264 debug_level = int(os.environ['STGIT_DEBUG_LEVEL'])
265 except KeyError:
266 debug_level = 0
267 except ValueError:
27ac2b7e 268 out.error('Invalid STGIT_DEBUG_LEVEL environment variable')
b2017c38
CM
269 sys.exit(1)
270
41a6d859 271 try:
eee7283e
CM
272 config_setup()
273
98290387
CM
274 # 'clone' doesn't expect an already initialised GIT tree. A Series
275 # object will be created after the GIT tree is cloned
276 if cmd != 'clone':
277 if hasattr(options, 'branch') and options.branch:
c333afcf 278 command.crt_series = Series(options.branch)
98290387 279 else:
c333afcf 280 command.crt_series = Series()
98290387 281 stgit.commands.common.crt_series = command.crt_series
9ac09909 282
41a6d859 283 command.func(parser, options, args)
87c93eab 284 except (StgException, IOError, ParsingError, NoSectionError), err:
41a6d859 285 print >> sys.stderr, '%s %s: %s' % (prog, cmd, err)
fe104619 286 if debug_level > 0:
b2017c38
CM
287 raise
288 else:
289 sys.exit(2)
4d9fc826
CM
290 except KeyboardInterrupt:
291 sys.exit(1)
41a6d859
CM
292
293 sys.exit(0)