1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 Command line interface
19 ======================
20
21 The svnmailer provides two different command line interfaces. On the one hand
22 there's the compatibility command line to the mailer.py script, which has some
23 limitations and problems because of its unflexibility. On the other hand
24 you'll find the new-style command line, which contains no subcommands and
25 fixed parameters at all.
26
27 The CLI simply transforms old-style command lines to the new format internally
28 and processes these further using the optparse module::
29
30 svn-mailer commit <rep> <rev> [<config>]
31 -> svn-mailer --commit --repository <rep> --revision <rev>
32 [--config <config>]
33
34 svn-mailer propchange <rep> <rev> <author> <prop> [<conf>]
35 -> svn-mailer --propchange --repository <rep> --revision <rev>
36 --author <author> --propname <prop>
37 [--config <conf>]
38
39 # (useful with svn 1.2 and later)
40 svn-mailer propchange2 <rep> <rev> <author> <prop> <action> [<conf>]
41 -> svn-mailer --propchange --repository <rep> --revision <rev>
42 --author <author> --propname <prop> --action <action>
43 [--config <conf>]
44
45 svn-mailer lock <rep> <author> [<conf>]
46 -> svn-mailer --lock --repository <rep> --author <author>
47 [--config <conf>]
48
49 svn-mailer unlock <rep> <author> [<conf>]
50 -> svn-mailer --unlock --repository <rep> --author <author>
51 [--config <conf>]
52 """
53 __author__ = "André Malo"
54 __docformat__ = "epytext en"
55 __all__ = ['getOptions', 'CommandlineError']
56
57
58 import optparse
59
60
62 """ Base exception for this module """
63 pass
64
66 """ Error in commandline """
67 pass
68
69
71 """ Parse commandline options
72
73 @param argv: Command line list. If argv is None,
74 sys.argv[1:] is evaluated instead
75 @type argv: C{list}
76
77 @return: option object
78 @rtype: C{optparse.OptionParser}
79
80 @exception CommandlineError: Error in command line options
81 """
82 from svnmailer import util
83 from svnmailer.settings import modes
84
85 usage = """%prog <options>"""
86 parser = SvnmailerOptionParser(usage = usage, version = True)
87 options, args = parser.parse_args(argv)
88
89
90 if args:
91 raise CommandlineError("Too much arguments")
92
93 if not options.repository:
94 raise CommandlineError("Missing repository path")
95
96 if not options.revision:
97 if options.mode in (modes.commit, modes.propchange):
98 raise CommandlineError("Missing revision number")
99
100 if not options.author:
101 if options.mode in (modes.propchange, modes.lock, modes.unlock):
102 raise CommandlineError("Missing author parameter")
103
104 if not options.propname:
105 if options.mode == modes.propchange:
106 raise CommandlineError("Missing property name parameter")
107
108
109 try:
110 options.repository = util.filename.fromLocale(
111 options.repository, options.path_encoding
112 )
113 except UnicodeError, exc:
114 raise CommandlineError("--repository recode problem: %s" % str(exc))
115
116 if options.config:
117 try:
118 options.config = util.filename.fromLocale(
119 options.config, options.path_encoding
120 )
121 except UnicodeError, exc:
122 raise CommandlineError("--config recode problem: %s" % str(exc))
123
124 return options
125
126
128 """ Fully initialized option parser
129
130 @ivar _svn: The svn version
131 @type _svn: C{tuple}
132 """
133
141
142
143 - def parse_args(self, args = None, *other_args, **kwargs):
144 """ Accepts also the old command line """
145 args = self._transformSvnmailerOldStyle(args)
146 if not args:
147 raise CommandlineError(
148 "Type '%s --help' for usage" % self.get_prog_name()
149 )
150
151 options, fixed = optparse.OptionParser.parse_args(
152 self, args, *other_args, **kwargs
153 )
154
155
156 if not self._svn.min_1_2:
157 options.action = None
158
159 return (options, fixed)
160
161
163 """ We raise an exception instead of exiting
164
165 @param msg: The error message
166 @type msg: C{str}
167
168 @exception CommandlineError: command line error
169 """
170 raise CommandlineError(str(msg))
171
172
174 """ Returns the version string """
175 from svnmailer import version
176
177 return "svnmailer-%s\nwith svn %d.%d.%d%s" % (
178 version, self._svn.major, self._svn.minor, self._svn.patch,
179 self._svn.tag
180 )
181
182
184 """ Returns the program name """
185 try:
186
187 return optparse.OptionParser.get_prog_name(self)
188 except AttributeError:
189 try:
190
191 return optparse.OptionParser._get_prog_name(self)
192 except AttributeError:
193
194 if self.prog:
195 return self.prog
196 else:
197 import os, sys
198 return os.path.basename(sys.argv[0])
199
200
246
247
249 """ Returns terminal width if determined, None otherwise
250
251 @return: The width
252 @rtype: C{int}
253 """
254 try:
255 import errno, fcntl, struct, sys, termios
256
257 def getwidth(fd):
258 """ Returns the width for descriptor fd """
259
260
261
262
263
264
265 return struct.unpack("4H", fcntl.ioctl(
266 fd, termios.TIOCGWINSZ, struct.pack("4H", 0, 0, 0, 0)
267 ))[1]
268
269 try:
270 return getwidth(sys.stdout.fileno())
271 except IOError, exc:
272 if exc[0] == errno.EINVAL:
273 return getwidth(sys.stdin.fileno())
274 raise
275
276 except (SystemExit, KeyboardInterrupt):
277 raise
278
279 except:
280
281 pass
282
283 return None
284
285
291
292
294 """ Adds the common options group """
295 common_options = optparse.OptionGroup(
296 self, 'COMMON PARAMETERS'
297 )
298 common_options.add_option('--debug',
299 action = 'store_true',
300 default = False,
301 help = "Run in debug mode (means basically that all messages "
302 "are sent to STDOUT)",
303 )
304 common_options.add_option('-d', '--repository',
305 help = 'The repository directory',
306 )
307 common_options.add_option('-f', '--config',
308 help = 'The configuration file',
309 )
310 common_options.add_option('-e', '--path-encoding',
311 help = 'Specifies the character encoding to be used for '
312 'filenames. By default the encoding is tried to be '
313 'determined automatically depending on the locale.'
314 )
315 self.add_option_group(common_options)
316
317
319 """ Adds the behaviour options group """
320 from svnmailer.settings import modes
321
322 behaviour_options = optparse.OptionGroup(
323 self, 'BEHAVIOUR OPTIONS',
324 description = "The behaviour options are mutually exclusive, "
325 "i.e. the last one wins."
326 )
327 behaviour_options.add_option('-c', '--commit',
328 dest = 'mode',
329 action = 'store_const',
330 const = modes.commit,
331 default = modes.commit,
332 help = 'This is a regular commit of versioned data '
333 '(post-commit hook). This is default.',
334 )
335 behaviour_options.add_option('-p', '--propchange',
336 dest = 'mode',
337 action = 'store_const',
338 const = modes.propchange,
339 help = 'This is a modification of unversioned properties '
340 '(post-revprop-change hook)',
341 )
342
343 if self._svn.min_1_2:
344 behaviour_options.add_option('-l', '--lock',
345 dest = 'mode',
346 action = 'store_const',
347 const = modes.lock,
348 help = '(svn 1.2 and later) This is a locking call '
349 '(post-lock hook)',
350 )
351 behaviour_options.add_option('-u', '--unlock',
352 dest = 'mode',
353 action = 'store_const',
354 const = modes.unlock,
355 help = '(svn 1.2 and later) This is a unlocking call '
356 '(post-unlock hook)',
357 )
358
359 self.add_option_group(behaviour_options)
360
361
363 """ Adds the supplemental options """
364 supp_options = optparse.OptionGroup(
365 self, 'SUPPLEMENTAL PARAMETERS'
366 )
367
368 supp_options.add_option('-r', '--revision',
369 action = 'store',
370 type = 'int',
371 help = 'The modified/committed revision number',
372 )
373 supp_options.add_option('-a', '--author',
374 help = 'The author of the modification',
375 )
376 supp_options.add_option('-n', '--propname',
377 help = 'The name of the modified property',
378 )
379
380 if self._svn.min_1_2:
381 supp_options.add_option('-o', '--action',
382 help = '(svn 1.2 and later) The property change action',
383 )
384
385 self.add_option_group(supp_options)
386
387
449