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