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