Have 'stg branch --create' record parent information.
[stgit] / stgit / main.py
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
21 import sys, os
22 from optparse import OptionParser
23
24 import stgit.commands
25
26 #
27 # The commands map
28 #
29 class Commands(dict):
30 """Commands class. It performs on-demand module loading
31 """
32 def __getitem__(self, key):
33 """Return the command python module name based.
34 """
35 global prog
36
37 cmd_mod = self.get(key)
38 if not cmd_mod:
39 candidates = [cmd for cmd in self.keys() if cmd.startswith(key)]
40
41 if not candidates:
42 print >> sys.stderr, 'Unknown command: %s' % key
43 print >> sys.stderr, ' Try "%s help" for a list of ' \
44 'supported commands' % prog
45 sys.exit(1)
46 elif len(candidates) > 1:
47 print >> sys.stderr, 'Ambiguous command: %s' % key
48 print >> sys.stderr, ' Candidates are: %s' \
49 % ', '.join(candidates)
50 sys.exit(1)
51
52 cmd_mod = self.get(candidates[0])
53
54 __import__('stgit.commands.' + cmd_mod)
55 return getattr(stgit.commands, cmd_mod)
56
57 commands = Commands({
58 'add': 'add',
59 'applied': 'applied',
60 'assimilate': 'assimilate',
61 'branch': 'branch',
62 'delete': 'delete',
63 'diff': 'diff',
64 'clean': 'clean',
65 'clone': 'clone',
66 'commit': 'commit',
67 'export': 'export',
68 'files': 'files',
69 'float': 'float',
70 'fold': 'fold',
71 'goto': 'goto',
72 'hide': 'hide',
73 'id': 'id',
74 'import': 'imprt',
75 'init': 'init',
76 'log': 'log',
77 'mail': 'mail',
78 'new': 'new',
79 'patches': 'patches',
80 'pick': 'pick',
81 'pop': 'pop',
82 'pull': 'pull',
83 'push': 'push',
84 'rebase': 'rebase',
85 'refresh': 'refresh',
86 'rename': 'rename',
87 'resolved': 'resolved',
88 'rm': 'rm',
89 'series': 'series',
90 'show': 'show',
91 'status': 'status',
92 'sync': 'sync',
93 'top': 'top',
94 'unapplied': 'unapplied',
95 'uncommit': 'uncommit',
96 'unhide': 'unhide'
97 })
98
99 # classification: repository, stack, patch, working copy
100 repocommands = (
101 'branch',
102 'clone',
103 'id',
104 'pull'
105 )
106 stackcommands = (
107 'applied',
108 'assimilate',
109 'clean',
110 'commit',
111 'float',
112 'goto',
113 'hide',
114 'init',
115 'pop',
116 'push',
117 'rebase',
118 'series',
119 'top',
120 'unapplied',
121 'uncommit',
122 'unhide'
123 )
124 patchcommands = (
125 'delete',
126 'export',
127 'files',
128 'fold',
129 'import',
130 'log',
131 'mail',
132 'new',
133 'pick',
134 'refresh',
135 'rename',
136 'show',
137 'sync'
138 )
139 wccommands = (
140 'add',
141 'diff',
142 'patches',
143 'resolved',
144 'rm',
145 'status'
146 )
147
148 def _print_helpstring(cmd):
149 print ' ' + cmd + ' ' * (12 - len(cmd)) + commands[cmd].help
150
151 def print_help():
152 print 'usage: %s <command> [options]' % os.path.basename(sys.argv[0])
153 print
154 print 'Generic commands:'
155 print ' help print the detailed command usage'
156 print ' version display version information'
157 print ' copyright display copyright information'
158 # unclassified commands if any
159 cmds = commands.keys()
160 cmds.sort()
161 for cmd in cmds:
162 if not cmd in repocommands and not cmd in stackcommands \
163 and not cmd in patchcommands and not cmd in wccommands:
164 _print_helpstring(cmd)
165 print
166
167 print 'Repository commands:'
168 for cmd in repocommands:
169 _print_helpstring(cmd)
170 print
171
172 print 'Stack commands:'
173 for cmd in stackcommands:
174 _print_helpstring(cmd)
175 print
176
177 print 'Patch commands:'
178 for cmd in patchcommands:
179 _print_helpstring(cmd)
180 print
181
182 print 'Working-copy commands:'
183 for cmd in wccommands:
184 _print_helpstring(cmd)
185
186 #
187 # The main function (command dispatcher)
188 #
189 def main():
190 """The main function
191 """
192 global prog
193
194 prog = os.path.basename(sys.argv[0])
195
196 if len(sys.argv) < 2:
197 print >> sys.stderr, 'usage: %s <command>' % prog
198 print >> sys.stderr, \
199 ' Try "%s --help" for a list of supported commands' % prog
200 sys.exit(1)
201
202 cmd = sys.argv[1]
203
204 if cmd in ['-h', '--help']:
205 if len(sys.argv) >= 3 and sys.argv[2] in commands:
206 cmd = sys.argv[2]
207 sys.argv[2] = '--help'
208 else:
209 print_help()
210 sys.exit(0)
211 if cmd == 'help':
212 if len(sys.argv) == 3 and not sys.argv[2] in ['-h', '--help']:
213 cmd = sys.argv[2]
214 if not cmd in commands:
215 print >> sys.stderr, '%s help: "%s" command unknown' \
216 % (prog, cmd)
217 sys.exit(1)
218
219 sys.argv[0] += ' %s' % cmd
220 command = commands[cmd]
221 parser = OptionParser(usage = command.usage,
222 option_list = command.options)
223 from pydoc import pager
224 pager(parser.format_help())
225 else:
226 print_help()
227 sys.exit(0)
228 if cmd in ['-v', '--version', 'version']:
229 from stgit.version import version
230 print 'Stacked GIT %s' % version
231 os.system('git --version')
232 print 'Python version %s' % sys.version
233 sys.exit(0)
234 if cmd in ['copyright']:
235 print __copyright__
236 sys.exit(0)
237
238 # re-build the command line arguments
239 sys.argv[0] += ' %s' % cmd
240 del(sys.argv[1])
241
242 command = commands[cmd]
243 usage = command.usage.split('\n')[0].strip()
244 parser = OptionParser(usage = usage, option_list = command.options)
245 options, args = parser.parse_args()
246
247 # These modules are only used from this point onwards and do not
248 # need to be imported earlier
249 from stgit.config import config_setup
250 from ConfigParser import ParsingError, NoSectionError
251 from stgit.stack import Series, StackException
252 from stgit.git import GitException
253 from stgit.commands.common import CmdException
254 from stgit.gitmergeonefile import GitMergeException
255
256 try:
257 config_setup()
258
259 # 'clone' doesn't expect an already initialised GIT tree. A Series
260 # object will be created after the GIT tree is cloned
261 if cmd != 'clone':
262 if hasattr(options, 'branch') and options.branch:
263 command.crt_series = Series(options.branch)
264 else:
265 command.crt_series = Series()
266 stgit.commands.common.crt_series = command.crt_series
267
268 command.func(parser, options, args)
269 except (IOError, ParsingError, NoSectionError, CmdException,
270 StackException, GitException, GitMergeException), err:
271 print >> sys.stderr, '%s %s: %s' % (prog, cmd, err)
272 sys.exit(2)
273 except KeyboardInterrupt:
274 sys.exit(1)
275
276 sys.exit(0)