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')
133 def callback(option
, opt_str
, value
, parser
, sign_str
):
134 if parser
.values
.sign_str
not in [None, sign_str
]:
135 raise optparse
.OptionValueError(
136 'Cannot give more than one of --ack, --sign, --review'
138 parser
.values
.sign_str
= sign_str
147 callback_args
=('Signed-off-by',),
148 short
='Add "Signed-off-by:" line',
149 long='Add a "Signed-off-by:" to the end of the patch.',
157 callback_args
=('Acked-by',),
158 short
='Add "Acked-by:" line',
159 long='Add an "Acked-by:" line to the end of the patch.',
167 callback_args
=('Reviewed-by',),
168 short
='Add "Reviewed-by:" line',
169 long='Add a "Reviewed-by:" line to the end of the patch.',
181 short
='Disable commit-msg hook',
182 long="This option bypasses the commit-msg hook.",
187 def message_options(save_template
):
189 if parser
.values
.message
is not None:
190 raise optparse
.OptionValueError(
191 'Cannot give more than one --message or --file'
194 def no_combine(parser
):
197 and parser
.values
.message
is not None
198 and parser
.values
.save_template
is not None
200 raise optparse
.OptionValueError(
201 'Cannot give both --message/--file and --save-template'
204 def msg_callback(option
, opt_str
, value
, parser
):
206 if value
and not value
.endswith('\n'):
208 parser
.values
.message
= value
211 def file_callback(option
, opt_str
, value
, parser
):
214 parser
.values
.message
= sys
.stdin
.read()
216 with
open(value
) as f
:
217 parser
.values
.message
= f
.read()
220 def templ_callback(option
, opt_str
, value
, parser
):
222 parser
.values
.save_template
= out
.stdout_bytes
226 with io
.open(value
, 'wb') as f
:
229 parser
.values
.save_template
= write_file
237 callback
=msg_callback
,
240 short
='Use MESSAGE instead of invoking the editor',
246 callback
=file_callback
,
251 short
='Use FILE instead of invoking the editor',
253 Use the contents of FILE instead of invoking the editor.
254 (If FILE is "-", write to stdout.)""",
262 dest
='save_template',
263 callback
=templ_callback
,
266 short
='Save the message template to FILE and exit',
268 Instead of running the command, just write the message
269 template to FILE, and exit. (If FILE is "-", write to
272 When driving StGit from another program, it is often
273 useful to first call a command with '--save-template',
274 then let the user edit the message, and then call the
275 same command with '--file'.""",
281 def diff_opts_option():
282 def diff_opts_callback(option
, opt_str
, value
, parser
):
284 parser
.values
.diff_flags
.extend(value
.split())
286 parser
.values
.diff_flags
= []
293 default
=(config
.get('stgit.diff-opts') or '').split(),
295 callback
=diff_opts_callback
,
298 args
=[strings('-M', '-C')],
299 short
='Extra options to pass to "git diff"',
304 def author_options():
305 """Create command line options for setting author information.
307 The ``opts.author`` destination variable is a callback function that modifies a
308 :class:`Person` according to the these command line options.
312 def short_callback(option
, opt_str
, value
, parser
, field
):
313 f
= parser
.values
.author
316 parser
.values
.author
= lambda p
: getattr(f(p
), 'set_' + field
)(value
)
318 def full_callback(option
, opt_str
, value
, parser
):
319 ne
= utils
.parse_name_email(value
)
321 raise optparse
.OptionValueError(
322 'Bad %s specification: %r' % (opt_str
, value
)
325 short_callback(option
, opt_str
, name
, parser
, 'name')
326 short_callback(option
, opt_str
, email
, parser
, 'email')
331 metavar
='"NAME <EMAIL>"',
334 callback
=full_callback
,
337 short
='Set the author details',
342 metavar
=field
.upper(),
345 callback
=short_callback
,
347 callback_args
=(field
,),
348 short
='Set the author %s' % field
,
350 for field
in ['name', 'email', 'date']
360 short
='Keep the local changes',
361 default
=config
.get('stgit.autokeep') == 'yes',
372 short
='Check for patches merged upstream',
378 def __init__(self
, *args
):
379 super().__init
__(args
)
382 class patch_range(list):
383 def __init__(self
, *args
):
384 super().__init
__(args
)