chiark / gitweb /
Make Series.refresh_patch automatically save the undo information
[stgit] / stgit / main.py
... / ...
CommitLineData
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
22from optparse import OptionParser
23
24import stgit.commands
25from stgit.out import *
26
27#
28# The commands map
29#
30class 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(1)
43 elif len(candidates) > 1:
44 out.error('Ambiguous command: %s' % key,
45 'Candidates are: %s' % ', '.join(candidates))
46 sys.exit(1)
47
48 return candidates[0]
49
50 def __getitem__(self, key):
51 """Return the command python module name based.
52 """
53 global prog
54
55 cmd_mod = self.get(key) or self.get(self.canonical_cmd(key))
56
57 __import__('stgit.commands.' + cmd_mod)
58 return getattr(stgit.commands, cmd_mod)
59
60commands = Commands({
61 'add': 'add',
62 'applied': 'applied',
63 'branch': 'branch',
64 'delete': 'delete',
65 'diff': 'diff',
66 'clean': 'clean',
67 'clone': 'clone',
68 'commit': 'commit',
69 'cp': 'copy',
70 'edit': 'edit',
71 'export': 'export',
72 'files': 'files',
73 'float': 'float',
74 'fold': 'fold',
75 'goto': 'goto',
76 'hide': 'hide',
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',
88 'rebase': 'rebase',
89 'refresh': 'refresh',
90 'rename': 'rename',
91 'repair': 'repair',
92 'resolved': 'resolved',
93 'rm': 'rm',
94 'series': 'series',
95 'show': 'show',
96 'sink': 'sink',
97 'status': 'status',
98 'sync': 'sync',
99 'top': 'top',
100 'unapplied': 'unapplied',
101 'uncommit': 'uncommit',
102 'unhide': 'unhide'
103 })
104
105# classification: repository, stack, patch, working copy
106repocommands = (
107 'clone',
108 'id',
109 )
110stackcommands = (
111 'applied',
112 'branch',
113 'clean',
114 'commit',
115 'float',
116 'goto',
117 'hide',
118 'init',
119 'patches',
120 'pop',
121 'pull',
122 'push',
123 'rebase',
124 'repair',
125 'series',
126 'sink',
127 'top',
128 'unapplied',
129 'uncommit',
130 'unhide',
131 )
132patchcommands = (
133 'delete',
134 'edit',
135 'export',
136 'files',
137 'fold',
138 'import',
139 'log',
140 'mail',
141 'new',
142 'pick',
143 'refresh',
144 'rename',
145 'show',
146 'sync',
147 )
148wccommands = (
149 'add',
150 'cp',
151 'diff',
152 'resolved',
153 'rm',
154 'status',
155 )
156
157def _print_helpstring(cmd):
158 print ' ' + cmd + ' ' * (12 - len(cmd)) + commands[cmd].help
159
160def print_help():
161 print 'usage: %s <command> [options]' % os.path.basename(sys.argv[0])
162 print
163 print 'Generic commands:'
164 print ' help print the detailed command usage'
165 print ' version display version information'
166 print ' copyright display copyright information'
167 # unclassified commands if any
168 cmds = commands.keys()
169 cmds.sort()
170 for cmd in cmds:
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)
194
195#
196# The main function (command dispatcher)
197#
198def main():
199 """The main function
200 """
201 global prog
202
203 prog = os.path.basename(sys.argv[0])
204
205 if len(sys.argv) < 2:
206 print >> sys.stderr, 'usage: %s <command>' % prog
207 print >> sys.stderr, \
208 ' Try "%s --help" for a list of supported commands' % prog
209 sys.exit(1)
210
211 cmd = sys.argv[1]
212
213 if cmd in ['-h', '--help']:
214 if len(sys.argv) >= 3:
215 cmd = commands.canonical_cmd(sys.argv[2])
216 sys.argv[2] = '--help'
217 else:
218 print_help()
219 sys.exit(0)
220 if cmd == 'help':
221 if len(sys.argv) == 3 and not sys.argv[2] in ['-h', '--help']:
222 cmd = commands.canonical_cmd(sys.argv[2])
223 if not cmd in commands:
224 out.error('%s help: "%s" command unknown' % (prog, cmd))
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)
231 from pydoc import pager
232 pager(parser.format_help())
233 else:
234 print_help()
235 sys.exit(0)
236 if cmd in ['-v', '--version', 'version']:
237 from stgit.version import version
238 print 'Stacked GIT %s' % version
239 os.system('git --version')
240 print 'Python version %s' % sys.version
241 sys.exit(0)
242 if cmd in ['copyright']:
243 print __copyright__
244 sys.exit(0)
245
246 # re-build the command line arguments
247 cmd = commands.canonical_cmd(cmd)
248 sys.argv[0] += ' %s' % cmd
249 del(sys.argv[1])
250
251 command = commands[cmd]
252 usage = command.usage.split('\n')[0].strip()
253 parser = OptionParser(usage = usage, option_list = command.options)
254 options, args = parser.parse_args()
255 directory = command.directory
256
257 # These modules are only used from this point onwards and do not
258 # need to be imported earlier
259 from stgit.exception import StgException
260 from stgit.config import config_setup
261 from ConfigParser import ParsingError, NoSectionError
262 from stgit.stack import Series
263
264 try:
265 debug_level = int(os.environ.get('STGIT_DEBUG_LEVEL', 0))
266 except ValueError:
267 out.error('Invalid STGIT_DEBUG_LEVEL environment variable')
268 sys.exit(1)
269
270 try:
271 directory.setup()
272 config_setup()
273
274 # Some commands don't (always) need an initialized series.
275 if directory.needs_current_series:
276 if hasattr(options, 'branch') and options.branch:
277 command.crt_series = Series(options.branch)
278 else:
279 command.crt_series = Series()
280
281 command.func(parser, options, args)
282 except (StgException, IOError, ParsingError, NoSectionError), err:
283 out.error(str(err), title = '%s %s' % (prog, cmd))
284 if debug_level > 0:
285 raise
286 else:
287 sys.exit(2)
288 except KeyboardInterrupt:
289 sys.exit(1)
290
291 sys.exit(0)