1 | import argparse |
||
2 | import datetime |
||
3 | from distutils.core import Command |
||
4 | from distutils.errors import DistutilsOptionError |
||
5 | |||
6 | |||
7 | class BuildManPage(Command): |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
![]() |
|||
8 | """ |
||
9 | Add a ``build_manpage`` command to your setup.py. |
||
10 | To use this Command class add a command to call this class:: |
||
11 | |||
12 | # For setuptools |
||
13 | setup( |
||
14 | entry_points={ |
||
15 | "distutils.commands": [ |
||
16 | "build_manpage = coalib.misc.BuildManPage:BuildManPage" |
||
17 | ] |
||
18 | } |
||
19 | ) |
||
20 | |||
21 | # For distutils |
||
22 | from coalib.misc.BuildManPage import BuildManPage |
||
23 | setup( |
||
24 | cmdclass={'build_manpage': BuildManPage} |
||
25 | ) |
||
26 | |||
27 | You can then use the following setup command to produce a man page:: |
||
28 | |||
29 | $ python setup.py build_manpage --output=coala.1 \ |
||
30 | --parser=coalib.parsing.DefaultArgParser:default_arg_parser |
||
31 | |||
32 | If automatically want to build the man page every time you invoke |
||
33 | your build, add to your ```setup.cfg``` the following:: |
||
34 | |||
35 | [build_manpage] |
||
36 | output = <appname>.1 |
||
37 | parser = <path_to_your_parser> |
||
38 | """ |
||
39 | user_options = [ |
||
40 | ('output=', 'O', 'output file'), |
||
41 | ('parser=', None, 'module path to an ArgumentParser instance' |
||
42 | '(e.g. mymod:func, where func is a method or function which return' |
||
43 | 'an arparse.ArgumentParser instance.'), |
||
44 | ] |
||
45 | |||
46 | def initialize_options(self): |
||
47 | self.output = None |
||
48 | self.parser = None |
||
49 | |||
50 | def finalize_options(self): |
||
51 | if self.output is None: |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
52 | raise DistutilsOptionError('\'output\' option is required') |
||
53 | if self.parser is None: |
||
54 | raise DistutilsOptionError('\'parser\' option is required') |
||
55 | mod_name, func_name = self.parser.split(':') |
||
56 | fromlist = mod_name.split('.') |
||
57 | mod = __import__(mod_name, fromlist=fromlist) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
|
|||
58 | self._parser = ( |
||
59 | getattr(mod, func_name)(formatter_class=ManPageFormatter)) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
60 | |||
61 | self.announce('Writing man page %s' % self.output) |
||
62 | self._today = datetime.date.today() |
||
63 | |||
64 | def run(self): |
||
65 | dist = self.distribution |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
66 | homepage = dist.get_url() |
||
67 | maintainer = dist.get_maintainer() |
||
68 | _license = dist.get_license() |
||
69 | appname = self._parser.prog |
||
70 | |||
71 | sections = {"see also": ("Online documentation: {}".format(homepage)), |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
72 | "maintainer(s)": maintainer, |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
73 | "license": _license} |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
74 | |||
75 | dist = self.distribution |
||
76 | mpf = ManPageFormatter(appname, |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
77 | desc=dist.get_description(), |
||
78 | long_desc=dist.get_long_description(), |
||
79 | ext_sections=sections, |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
80 | parser=self._parser) |
||
81 | |||
82 | formatted_man_page = mpf.format_man_page() |
||
83 | |||
84 | with open(self.output, 'w') as man_file: |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
85 | man_file.write(formatted_man_page) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
86 | |||
87 | |||
88 | class ManPageFormatter(argparse.HelpFormatter): |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
89 | |||
90 | def __init__(self, |
||
91 | prog, |
||
92 | indent_increment=2, |
||
93 | max_help_position=24, |
||
94 | width=None, |
||
95 | desc=None, |
||
96 | long_desc=None, |
||
97 | ext_sections=None, |
||
98 | parser=None): |
||
99 | argparse.HelpFormatter.__init__(self, prog) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
|
|||
100 | |||
101 | self._prog = prog |
||
102 | self._section = 1 |
||
103 | self._today = datetime.date.today().strftime('%Y\\-%m\\-%d') |
||
104 | self._desc = desc |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
105 | self._long_desc = long_desc |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
106 | self._ext_sections = ext_sections |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
107 | self._parser = parser |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
108 | |||
109 | def _format_action_invocation(self, action): |
||
110 | if not action.option_strings: |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
111 | metavar, = self._metavar_formatter(action, action.dest)(1) |
||
112 | return metavar |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
113 | |||
114 | else: |
||
115 | # if the Optional doesn't take a value, format is: |
||
116 | # -s, --long |
||
117 | if action.nargs == 0: |
||
118 | parts = [ManPageFormatter._bold(action_str) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
119 | for action_str in action.option_strings] |
||
120 | |||
121 | # if the Optional takes a value, format is: |
||
122 | # -s ARGS, --long ARGS |
||
123 | else: |
||
124 | default = ManPageFormatter._underline(action.dest.upper()) |
||
125 | args_string = self._format_args(action, default) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
126 | parts = ['%s %s' % (self._bold(option_string), args_string) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
|
|||
127 | for option_string in action.option_strings] |
||
128 | |||
129 | return ', '.join(parts) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
130 | |||
131 | @staticmethod |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
132 | def _markup(string): |
||
133 | return string.replace('-', '\\-') |
||
134 | |||
135 | @staticmethod |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
136 | def _add_format(string, front, back): |
||
137 | if not string.strip().startswith(front): |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
138 | string = front + string |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
139 | if not string.strip().endswith(back): |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
140 | string = string + back |
||
141 | return string |
||
142 | |||
143 | @staticmethod |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
144 | def _underline(string): |
||
145 | return ManPageFormatter._add_format(string, "\\fI", "\\fR") |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
146 | |||
147 | @staticmethod |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
148 | def _bold(string): |
||
149 | return ManPageFormatter._add_format(string, "\\fB", "\\fR") |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
150 | |||
151 | def _mk_title(self): |
||
152 | return '.TH {0} {1} {2}\n'.format(self._prog, |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
153 | self._section, |
||
154 | self._today) |
||
155 | |||
156 | def _mk_name(self): |
||
157 | return '.SH NAME\n%s\n' % (self._parser.prog) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
158 | |||
159 | def _mk_synopsis(self): |
||
160 | self.add_usage(self._parser.usage, |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
161 | self._parser._actions, |
||
162 | self._parser._mutually_exclusive_groups, |
||
163 | prefix='') |
||
164 | usage = self._format_usage(None, |
||
165 | self._parser._actions, |
||
166 | self._parser._mutually_exclusive_groups, |
||
167 | '') |
||
168 | |||
169 | usage = usage.replace('%s ' % self._prog, '') |
||
170 | usage = ('.SH SYNOPSIS\n \\fB%s\\fR %s\n' |
||
171 | % (ManPageFormatter._markup(self._prog), usage)) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
172 | return usage |
||
173 | |||
174 | def _mk_description(self): |
||
175 | if self._long_desc: |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
176 | long_desc = self._long_desc.replace('\n', '\n.br\n') |
||
177 | return '.SH DESCRIPTION\n%s\n' % self._markup(long_desc) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
178 | else: |
||
179 | return '' |
||
180 | |||
181 | def _mk_options(self): |
||
182 | formatter = self._parser._get_formatter() |
||
183 | |||
184 | # positionals, optionals and user-defined groups |
||
185 | for action_group in self._parser._action_groups: |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
186 | formatter.start_section(None) |
||
187 | formatter.add_text(None) |
||
188 | formatter.add_arguments(action_group._group_actions) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
189 | formatter.end_section() |
||
190 | |||
191 | # epilog |
||
192 | formatter.add_text(self._parser.epilog) |
||
193 | |||
194 | # determine help from format above |
||
195 | return '.SH OPTIONS\n' + formatter.format_help() |
||
196 | |||
197 | def _mk_footer(self): |
||
198 | sections = self._ext_sections |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
199 | if not hasattr(sections, '__iter__'): |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
200 | return '' |
||
201 | |||
202 | footer = [] |
||
203 | |||
204 | for section in sorted(sections.keys()): |
||
205 | part = ".SH {}\n {}".format(section.upper(), sections[section]) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
206 | footer.append(part) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
207 | |||
208 | return '\n'.join(footer) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
209 | |||
210 | def format_man_page(self): |
||
211 | page = [] |
||
212 | page.append(self._mk_title()) |
||
213 | page.append(self._mk_name()) |
||
214 | page.append(self._mk_synopsis()) |
||
215 | page.append(self._mk_description()) |
||
216 | page.append(self._mk_options()) |
||
217 | page.append(self._mk_footer()) |
||
218 | |||
219 | return ''.join(page) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
220 |