Commit | Line | Data |
---|---|---|
41a6d859 CM |
1 | """Basic quilt-like functionality |
2 | """ | |
3 | ||
4 | __copyright__ = """ | |
5 | Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com> | |
6 | ||
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. | |
10 | ||
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. | |
15 | ||
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 | """ | |
20 | ||
08986eda | 21 | import sys, os, traceback |
41a6d859 | 22 | |
c333afcf | 23 | import stgit.commands |
5e888f30 | 24 | from stgit.out import * |
575bbdae | 25 | from stgit import argparse, run, utils |
41a6d859 | 26 | |
41a6d859 CM |
27 | # |
28 | # The commands map | |
29 | # | |
c333afcf CM |
30 | class 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 | ||
60 | commands = 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 |
102 | repocommands = ( | |
5dc51fea YD |
103 | 'clone', |
104 | 'id', | |
5dc51fea YD |
105 | ) |
106 | stackcommands = ( | |
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 | ) |
127 | patchcommands = ( | |
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 | ) |
143 | wccommands = ( | |
5dc51fea | 144 | 'diff', |
5dc51fea | 145 | 'resolved', |
4ec67741 | 146 | 'status', |
5dc51fea YD |
147 | ) |
148 | ||
149 | def _print_helpstring(cmd): | |
150 | print ' ' + cmd + ' ' * (12 - len(cmd)) + commands[cmd].help | |
151 | ||
41a6d859 CM |
152 | def print_help(): |
153 | print 'usage: %s <command> [options]' % os.path.basename(sys.argv[0]) | |
154 | ||
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 | ||
167 | ||
168 | print 'Repository commands:' | |
169 | for cmd in repocommands: | |
170 | _print_helpstring(cmd) | |
171 | ||
172 | ||
173 | print 'Stack commands:' | |
174 | for cmd in stackcommands: | |
175 | _print_helpstring(cmd) | |
176 | ||
177 | ||
178 | print 'Patch commands:' | |
179 | for cmd in patchcommands: | |
180 | _print_helpstring(cmd) | |
181 | ||
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 | 190 | def _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 | |
290 | def main(): | |
291 | try: | |
292 | _main() | |
293 | finally: | |
294 | run.finish_logging() |