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