stgit.el: Use forward-line instead of goto-line non-interactively
[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, traceback
22
23 import stgit.commands
24 from stgit.out import *
25 from stgit import argparse, run, utils
26 from stgit.config import config
27
28 class CommandAlias(object):
29 def __init__(self, name, command):
30 self.__command = command
31 self.__name__ = name
32 self.usage = ['<arguments>']
33 self.help = 'Alias for "%s <arguments>".' % self.__command
34 self.options = []
35
36 def func(self, args):
37 cmd = self.__command.split() + args
38 p = run.Run(*cmd)
39 p.discard_exitcode().run()
40 return p.exitcode
41
42 def is_cmd_alias(cmd):
43 return isinstance(cmd, CommandAlias)
44
45 def append_alias_commands(cmd_list):
46 for (name, command) in config.getstartswith('stgit.alias.'):
47 name = utils.strip_prefix('stgit.alias.', name)
48 cmd_list[name] = (CommandAlias(name, command),
49 'Alias commands', command)
50
51 #
52 # The commands map
53 #
54 class Commands(dict):
55 """Commands class. It performs on-demand module loading
56 """
57 def canonical_cmd(self, key):
58 """Return the canonical name for a possibly-shortenned
59 command name.
60 """
61 candidates = [cmd for cmd in self.keys() if cmd.startswith(key)]
62
63 if not candidates:
64 out.error('Unknown command: %s' % key,
65 'Try "%s help" for a list of supported commands' % prog)
66 sys.exit(utils.STGIT_GENERAL_ERROR)
67 elif len(candidates) > 1:
68 out.error('Ambiguous command: %s' % key,
69 'Candidates are: %s' % ', '.join(candidates))
70 sys.exit(utils.STGIT_GENERAL_ERROR)
71
72 return candidates[0]
73
74 def __getitem__(self, key):
75 cmd_mod = self.get(key) or self.get(self.canonical_cmd(key))
76 if is_cmd_alias(cmd_mod):
77 return cmd_mod
78 else:
79 return stgit.commands.get_command(cmd_mod)
80
81 cmd_list = stgit.commands.get_commands()
82 append_alias_commands(cmd_list)
83 commands = Commands((cmd, mod) for cmd, (mod, kind, help)
84 in cmd_list.iteritems())
85
86 def print_help():
87 print 'usage: %s <command> [options]' % os.path.basename(sys.argv[0])
88 print
89 print 'Generic commands:'
90 print ' help print the detailed command usage'
91 print ' version display version information'
92 print ' copyright display copyright information'
93 print
94 stgit.commands.pretty_command_list(cmd_list, sys.stdout)
95
96 #
97 # The main function (command dispatcher)
98 #
99 def _main():
100 """The main function
101 """
102 global prog
103
104 prog = os.path.basename(sys.argv[0])
105
106 if len(sys.argv) < 2:
107 print >> sys.stderr, 'usage: %s <command>' % prog
108 print >> sys.stderr, \
109 ' Try "%s --help" for a list of supported commands' % prog
110 sys.exit(utils.STGIT_GENERAL_ERROR)
111
112 cmd = sys.argv[1]
113
114 if cmd in ['-h', '--help']:
115 if len(sys.argv) >= 3:
116 cmd = commands.canonical_cmd(sys.argv[2])
117 sys.argv[2] = '--help'
118 else:
119 print_help()
120 sys.exit(utils.STGIT_SUCCESS)
121 if cmd == 'help':
122 if len(sys.argv) == 3 and not sys.argv[2] in ['-h', '--help']:
123 cmd = commands.canonical_cmd(sys.argv[2])
124 if not cmd in commands:
125 out.error('%s help: "%s" command unknown' % (prog, cmd))
126 sys.exit(utils.STGIT_GENERAL_ERROR)
127
128 sys.argv[0] += ' %s' % cmd
129 command = commands[cmd]
130 parser = argparse.make_option_parser(command)
131 if is_cmd_alias(command):
132 parser.remove_option('-h')
133 from pydoc import pager
134 pager(parser.format_help())
135 else:
136 print_help()
137 sys.exit(utils.STGIT_SUCCESS)
138 if cmd in ['-v', '--version', 'version']:
139 from stgit.version import version
140 print 'Stacked GIT %s' % version
141 os.system('git --version')
142 print 'Python version %s' % sys.version
143 sys.exit(utils.STGIT_SUCCESS)
144 if cmd in ['copyright']:
145 print __copyright__
146 sys.exit(utils.STGIT_SUCCESS)
147
148 # re-build the command line arguments
149 cmd = commands.canonical_cmd(cmd)
150 sys.argv[0] += ' %s' % cmd
151 del(sys.argv[1])
152
153 command = commands[cmd]
154 if is_cmd_alias(command):
155 sys.exit(command.func(sys.argv[1:]))
156
157 parser = argparse.make_option_parser(command)
158 options, args = parser.parse_args()
159 directory = command.directory
160
161 # These modules are only used from this point onwards and do not
162 # need to be imported earlier
163 from stgit.exception import StgException
164 from stgit.config import config_setup
165 from ConfigParser import ParsingError, NoSectionError
166 from stgit.stack import Series
167
168 try:
169 debug_level = int(os.environ.get('STGIT_DEBUG_LEVEL', 0))
170 except ValueError:
171 out.error('Invalid STGIT_DEBUG_LEVEL environment variable')
172 sys.exit(utils.STGIT_GENERAL_ERROR)
173
174 try:
175 directory.setup()
176 config_setup()
177
178 # Some commands don't (always) need an initialized series.
179 if directory.needs_current_series:
180 if hasattr(options, 'branch') and options.branch:
181 command.crt_series = Series(options.branch)
182 else:
183 command.crt_series = Series()
184
185 ret = command.func(parser, options, args)
186 except (StgException, IOError, ParsingError, NoSectionError), err:
187 directory.write_log(cmd)
188 out.error(str(err), title = '%s %s' % (prog, cmd))
189 if debug_level > 0:
190 traceback.print_exc()
191 sys.exit(utils.STGIT_COMMAND_ERROR)
192 except SystemExit:
193 # Triggered by the option parser when it finds bad commandline
194 # parameters.
195 sys.exit(utils.STGIT_COMMAND_ERROR)
196 except KeyboardInterrupt:
197 sys.exit(utils.STGIT_GENERAL_ERROR)
198 except:
199 out.error('Unhandled exception:')
200 traceback.print_exc()
201 sys.exit(utils.STGIT_BUG_ERROR)
202
203 directory.write_log(cmd)
204 sys.exit(ret or utils.STGIT_SUCCESS)
205
206 def main():
207 try:
208 _main()
209 finally:
210 run.finish_logging()