1 """This module provides a layer on top of the standard library's
2 C{optparse} module, so that we can easily generate both interactive
3 help and asciidoc documentation (such as man pages)."""
5 import optparse
, sys
, textwrap
6 from stgit
import utils
7 from stgit
.config
import config
9 def _splitlist(lst
, split_on
):
10 """Iterate over the sublists of lst that are separated by an element e
11 such that split_on(e) is true."""
22 """Split a string s into a list of paragraphs, each of which is a list
24 lines
= [line
.rstrip() for line
in textwrap
.dedent(s
).strip().splitlines()]
25 return [p
for p
in _splitlist(lines
, lambda line
: not line
.strip()) if p
]
28 """Represents a command-line flag."""
29 def __init__(self
, *args
, **kwargs
):
33 kwargs
= dict(self
.kwargs
)
34 kwargs
['help'] = kwargs
['short']
38 return optparse
.make_option(*self
.args
, **kwargs
)
45 for flag
in self
.args
:
46 if flag
.startswith('--'):
47 return utils
.strip_prefix('--', flag
).upper()
48 raise Exception('Cannot determine metavar')
49 def write_asciidoc(self
, f
):
50 for flag
in self
.args
:
56 paras
= _paragraphs(self
.kwargs
.get('long', self
.kwargs
['short'] + '.'))
58 f
.write(' '*8 + line
+ '\n')
59 for para
in paras
[1:]:
64 def _cmd_name(cmd_mod
):
65 return getattr(cmd_mod
, 'name', cmd_mod
.__name__
.split('.')[-1])
67 def make_option_parser(cmd
):
68 pad
= ' '*len('Usage: ')
69 return optparse
.OptionParser(
70 prog
= 'stg %s' %
_cmd_name(cmd
),
71 usage
= (('\n' + pad
).join('%%prog %s' % u for u in cmd
.usage
) +
73 option_list
= [o
.get_option() for o
in cmd
.options
])
75 def _write_underlined(s
, u
, f
):
77 f
.write(u
*len(s
) + '\n')
79 def write_asciidoc(cmd
, f
):
80 _write_underlined('stg-%s(1)' %
_cmd_name(cmd
), '=', f
)
82 _write_underlined('NAME', '-', f
)
83 f
.write('stg-%s - %s\n\n' %
(_cmd_name(cmd
), cmd
.help))
84 _write_underlined('SYNOPSIS', '-', f
)
87 f
.write("'stg' %s %s\n" %
(_cmd_name(cmd
), u
))
89 _write_underlined('DESCRIPTION', '-', f
)
90 f
.write('\n%s\n\n' % cmd
.description
.strip('\n'))
92 _write_underlined('OPTIONS', '-', f
)
96 _write_underlined('StGit', '-', f
)
97 f
.write('Part of the StGit suite - see link:stg[1]\n')
100 def callback(option
, opt_str
, value
, parser
, sign_str
):
101 if parser
.values
.sign_str
not in [None, sign_str
]:
102 raise optparse
.OptionValueError(
103 '--ack and --sign were both specified')
104 parser
.values
.sign_str
= sign_str
106 opt('--sign', action
= 'callback', dest
= 'sign_str',
107 callback
= callback
, callback_args
= ('Signed-off-by',),
108 short
= 'Add "Signed-off-by:" line', long = """
109 Add a "Signed-off-by:" to the end of the patch."""),
110 opt('--ack', action
= 'callback', dest
= 'sign_str',
111 callback
= callback
, callback_args
= ('Acked-by',),
112 short
= 'Add "Acked-by:" line', long = """
113 Add an "Acked-by:" line to the end of the patch.""")]
115 def message_options(save_template
):
117 if parser
.values
.message
!= None:
118 raise optparse
.OptionValueError(
119 'Cannot give more than one --message or --file')
120 def no_combine(parser
):
121 if (save_template
and parser
.values
.message
!= None
122 and parser
.values
.save_template
!= None):
123 raise optparse
.OptionValueError(
124 'Cannot give both --message/--file and --save-template')
125 def msg_callback(option
, opt_str
, value
, parser
):
127 parser
.values
.message
= value
129 def file_callback(option
, opt_str
, value
, parser
):
132 parser
.values
.message
= sys
.stdin
.read()
135 parser
.values
.message
= f
.read()
138 def templ_callback(option
, opt_str
, value
, parser
):
144 f
= file(value
, 'w+')
147 parser
.values
.save_template
= w
150 opt('-m', '--message', action
= 'callback',
151 callback
= msg_callback
, dest
= 'message', type = 'string',
152 short
= 'Use MESSAGE instead of invoking the editor'),
153 opt('-f', '--file', action
= 'callback', callback
= file_callback
,
154 dest
= 'message', type = 'string',
155 short
= 'Use FILE instead of invoking the editor', long = """
156 Use the contents of FILE instead of invoking the editor.
157 (If FILE is "-", write to stdout.)""")]
160 opt('--save-template', action
= 'callback', dest
= 'save_template',
161 callback
= templ_callback
, metavar
= 'FILE', type = 'string',
162 short
= 'Save the message template to FILE and exit', long = """
163 Instead of running the command, just write the message
164 template to FILE, and exit. (If FILE is "-", write to
167 When driving StGit from another program, it is often
168 useful to first call a command with '--save-template',
169 then let the user edit the message, and then call the
170 same command with '--file'."""))
173 def diff_opts_option():
174 def diff_opts_callback(option
, opt_str
, value
, parser
):
176 parser
.values
.diff_flags
.extend(value
.split())
178 parser
.values
.diff_flags
= []
180 opt('-O', '--diff-opts', dest
= 'diff_flags',
181 default
= (config
.get('stgit.diff-opts') or '').split(),
182 action
= 'callback', callback
= diff_opts_callback
,
183 type = 'string', metavar
= 'OPTIONS',
184 short
= 'Extra options to pass to "git diff"')]
186 def _person_opts(person
, short
):
187 """Sets options.<person> to a function that modifies a Person
188 according to the commandline options."""
189 def short_callback(option
, opt_str
, value
, parser
, field
):
190 f
= getattr(parser
.values
, person
)
191 setattr(parser
.values
, person
,
192 lambda p
: getattr(f(p
), 'set_' + field
)(value
))
193 def full_callback(option
, opt_str
, value
, parser
):
194 ne
= utils
.parse_name_email(value
)
196 raise optparse
.OptionValueError(
197 'Bad %s specification: %r' %
(opt_str
, value
))
199 short_callback(option
, opt_str
, name
, parser
, 'name')
200 short_callback(option
, opt_str
, email
, parser
, 'email')
202 [opt('--%s' % person
, metavar
= '"NAME <EMAIL>"', type = 'string',
203 action
= 'callback', callback
= full_callback
, dest
= person
,
204 default
= lambda p
: p
, short
= 'Set the %s details' % person
)] +
205 [opt('--%s%s' %
(short
, f
), metavar
= f
.upper(), type = 'string',
206 action
= 'callback', callback
= short_callback
, dest
= person
,
207 callback_args
= (f
,), short
= 'Set the %s %s' %
(person
, f
))
208 for f
in ['name', 'email', 'date']])
210 def author_options():
211 return _person_opts('author', 'auth')
213 def author_committer_options():
214 return _person_opts('author', 'auth') + _person_opts('committer', 'comm')