1 """Command line argument parsing for StGit subcommands.
3 This module provides a layer on top of the standard library's :mod:`optparse` to
4 facilitate generation of both interactive help and asciidoc documentation (such as man
14 from stgit
import utils
15 from stgit
.config
import config
16 from stgit
.lib
.git
import Date
17 from stgit
.out
import out
20 def _splitlist(lst
, split_on
):
21 """Split list using provided predicate."""
33 """Split a string s into a list of paragraphs, each of which is a list of lines."""
34 lines
= [line
.rstrip() for line
in textwrap
.dedent(s
).strip().splitlines()]
35 return [p
for p
in _splitlist(lines
, lambda line
: not line
.strip()) if p
]
39 """Represents a command-line flag."""
41 def __init__(self
, *pargs
, **kwargs
):
46 kwargs
= dict(self
.kwargs
)
47 kwargs
['help'] = kwargs
['short']
48 for k
in ['short', 'long', 'args']:
50 return optparse
.make_option(*self
.pargs
, **kwargs
)
54 if not o
.takes_value():
58 for flag
in self
.pargs
:
59 if flag
.startswith('--'):
60 return utils
.strip_prefix('--', flag
).upper()
61 raise Exception('Cannot determine metavar')
63 def write_asciidoc(self
, f
):
64 for flag
in self
.pargs
:
70 paras
= _paragraphs(self
.kwargs
.get('long', self
.kwargs
['short'] + '.'))
72 f
.write(' ' * 8 + line
+ '\n')
73 for para
in paras
[1:]:
84 if self
.kwargs
.get('action', None) in ['store_true', 'store_false']:
88 return self
.kwargs
.get('args', default
)
91 def _cmd_name(cmd_mod
):
92 return getattr(cmd_mod
, 'name', cmd_mod
.__name
__.split('.')[-1])
95 def make_option_parser(cmd
):
96 pad
= ' ' * len('Usage: ')
97 return optparse
.OptionParser(
98 prog
='stg %s' % _cmd_name(cmd
),
100 ('\n' + pad
).join('%%prog %s' % u
for u
in cmd
.usage
) + '\n\n' + cmd
.help
102 option_list
=[o
.get_option() for o
in cmd
.options
],
106 def _write_underlined(s
, u
, f
):
108 f
.write(u
* len(s
) + '\n')
111 def write_asciidoc(cmd
, f
):
112 _write_underlined('stg-%s(1)' % _cmd_name(cmd
), '=', f
)
114 _write_underlined('NAME', '-', f
)
115 f
.write('stg-%s - %s\n\n' % (_cmd_name(cmd
), cmd
.help))
116 _write_underlined('SYNOPSIS', '-', f
)
119 f
.write("'stg %s' %s\n" % (_cmd_name(cmd
), u
))
121 _write_underlined('DESCRIPTION', '-', f
)
122 f
.write('\n%s\n\n' % cmd
.description
.strip('\n'))
124 _write_underlined('OPTIONS', '-', f
)
125 for o
in cmd
.options
:
128 _write_underlined('StGit', '-', f
)
129 f
.write('Part of the StGit suite - see linkman:stg[1]\n')
132 def trailer_options():
133 def callback(option
, opt_str
, value
, parser
, trailer
):
134 parser
.values
.trailers
.append((trailer
, None))
136 def by_callback(option
, opt_str
, value
, parser
, trailer
):
137 parser
.values
.trailers
.append((trailer
, value
))
146 callback_args
=('Signed-off-by',),
147 short
='Add "Signed-off-by:" trailer',
149 'Add a "Signed-off-by:" trailer to the end of the message using the '
150 'committer name and email for the trailer value.'
158 callback
=by_callback
,
159 callback_args
=('Signed-off-by',),
162 short
='Add "Signed-off-by:" trailer with custom VALUE',
164 'Add a "Signed-off-by:" trailer with a custom VALUE to the end of the '
174 callback_args
=('Acked-by',),
175 short
='Add "Acked-by:" trailer',
177 'Add an "Acked-by:" trailer to the end of the message using the '
178 'commiter name and email for the trailer value.'
186 callback
=by_callback
,
187 callback_args
=('Acked-by',),
190 short
='Add "Acked-by:" trailer with custom VALUE',
192 'Add an "Acked-by:" trailer with a custom VALUE to the end of the '
202 callback_args
=('Reviewed-by',),
203 short
='Add "Reviewed-by:" trailer',
205 'Add a "Reviewed-by:" trailer to the end of the message using the '
206 'commiter name and email for the trailer value.'
214 callback
=by_callback
,
215 callback_args
=('Reviewed-by',),
218 short
='Add "Reviewed-by:" trailer with custom VALUE',
220 'Add a "Reviewed-by:" trailer with custom VALUE to the end of the '
234 short
='Disable commit-msg hook',
235 long="This option bypasses the commit-msg hook.",
240 def message_options(save_template
):
242 if parser
.values
.message
is not None:
243 raise optparse
.OptionValueError(
244 'Cannot give more than one --message or --file'
247 def no_combine(parser
):
250 and parser
.values
.message
is not None
251 and parser
.values
.save_template
is not None
253 raise optparse
.OptionValueError(
254 'Cannot give both --message/--file and --save-template'
257 def msg_callback(option
, opt_str
, value
, parser
):
259 if value
and not value
.endswith('\n'):
261 parser
.values
.message
= value
264 def file_callback(option
, opt_str
, value
, parser
):
267 parser
.values
.message
= sys
.stdin
.read()
269 with
open(value
) as f
:
270 parser
.values
.message
= f
.read()
273 def templ_callback(option
, opt_str
, value
, parser
):
275 parser
.values
.save_template
= out
.stdout_bytes
279 with io
.open(value
, 'wb') as f
:
282 parser
.values
.save_template
= write_file
290 callback
=msg_callback
,
293 short
='Use MESSAGE instead of invoking the editor',
299 callback
=file_callback
,
304 short
='Use FILE instead of invoking the editor',
306 Use the contents of FILE instead of invoking the editor.
307 (If FILE is "-", write to stdout.)""",
315 dest
='save_template',
316 callback
=templ_callback
,
319 short
='Save the message template to FILE and exit',
321 Instead of running the command, just write the message
322 template to FILE, and exit. (If FILE is "-", write to
325 When driving StGit from another program, it is often
326 useful to first call a command with '--save-template',
327 then let the user edit the message, and then call the
328 same command with '--file'.""",
334 def diff_opts_option():
335 def diff_opts_callback(option
, opt_str
, value
, parser
):
337 parser
.values
.diff_flags
.extend(value
.split())
339 parser
.values
.diff_flags
= []
346 default
=(config
.get('stgit.diff-opts') or '').split(),
348 callback
=diff_opts_callback
,
351 args
=[strings('-M', '-C')],
352 short
='Extra options to pass to "git diff"',
357 def author_options():
358 """Create command line options for setting author information.
360 The ``opts.author`` destination variable is a callback function that modifies a
361 :class:`Person` according to the these command line options.
365 def short_callback(option
, opt_str
, value
, parser
, field
):
366 f
= parser
.values
.author
369 parser
.values
.author
= lambda p
: getattr(f(p
), 'set_' + field
)(value
)
371 def full_callback(option
, opt_str
, value
, parser
):
372 ne
= utils
.parse_name_email(value
)
374 raise optparse
.OptionValueError(
375 'Bad %s specification: %r' % (opt_str
, value
)
378 short_callback(option
, opt_str
, name
, parser
, 'name')
379 short_callback(option
, opt_str
, email
, parser
, 'email')
384 metavar
='"NAME <EMAIL>"',
387 callback
=full_callback
,
390 short
='Set the author details',
395 metavar
=field
.upper(),
398 callback
=short_callback
,
400 callback_args
=(field
,),
401 short
='Set the author %s' % field
,
403 for field
in ['name', 'email', 'date']
413 short
='Keep the local changes',
414 default
=config
.get('stgit.autokeep') == 'yes',
425 short
='Check for patches merged upstream',
431 def __init__(self
, *args
):
432 super().__init
__(args
)
435 class patch_range(list):
436 def __init__(self
, *args
):
437 super().__init
__(args
)