Source code for coalib.misc.BuildManPage

import argparse
import datetime
from distutils.core import Command
from distutils.errors import DistutilsOptionError


[docs]class BuildManPage(Command): """ Add a ``build_manpage`` command to your setup.py. To use this Command class add a command to call this class:: # For setuptools setup( entry_points={ "distutils.commands": [ "build_manpage = coalib.misc.BuildManPage:BuildManPage" ] } ) # For distutils from coalib.misc.BuildManPage import BuildManPage setup( cmdclass={'build_manpage': BuildManPage} ) You can then use the following setup command to produce a man page:: $ python setup.py build_manpage --output=coala.1 \ --parser=coalib.parsing.DefaultArgParser:default_arg_parser If automatically want to build the man page every time you invoke your build, add to your ``setup.cfg`` the following:: [build_manpage] output = <appname>.1 parser = <path_to_your_parser> """ user_options = [ ('output=', 'O', 'output file'), ('parser=', None, 'module path to an ArgumentParser instance' '(e.g. mymod:func, where func is a method or function which return' 'an arparse.ArgumentParser instance.'), ]
[docs] def initialize_options(self): self.output = None self.parser = None
[docs] def finalize_options(self): if self.output is None: raise DistutilsOptionError('\'output\' option is required') if self.parser is None: raise DistutilsOptionError('\'parser\' option is required') mod_name, func_name = self.parser.split(':') fromlist = mod_name.split('.') mod = __import__(mod_name, fromlist=fromlist) self._parser = ( getattr(mod, func_name)(formatter_class=ManPageFormatter)) self.announce('Writing man page %s' % self.output) self._today = datetime.date.today()
[docs] def run(self): dist = self.distribution homepage = dist.get_url() maintainer = dist.get_maintainer() _license = dist.get_license() appname = self._parser.prog sections = {'see also': ('Online documentation: {}'.format(homepage)), 'maintainer(s)': maintainer, 'license': _license} dist = self.distribution mpf = ManPageFormatter(appname, desc=dist.get_description(), long_desc=dist.get_long_description(), ext_sections=sections, parser=self._parser) formatted_man_page = mpf.format_man_page() with open(self.output, 'w') as man_file: man_file.write(formatted_man_page)
[docs]class ManPageFormatter(argparse.HelpFormatter): def __init__(self, prog, indent_increment=2, max_help_position=24, width=None, desc=None, long_desc=None, ext_sections=None, parser=None): argparse.HelpFormatter.__init__(self, prog) self._prog = prog self._section = 1 self._today = datetime.date.today().strftime('%Y\\-%m\\-%d') self._desc = desc self._long_desc = long_desc self._ext_sections = ext_sections self._parser = parser def _format_action_invocation(self, action): if not action.option_strings: metavar, = self._metavar_formatter(action, action.dest)(1) return metavar else: # if the Optional doesn't take a value, format is: # -s, --long if action.nargs == 0: parts = [ManPageFormatter._bold(action_str) for action_str in action.option_strings] # if the Optional takes a value, format is: # -s ARGS, --long ARGS else: default = ManPageFormatter._underline(action.dest.upper()) args_string = self._format_args(action, default) parts = ['%s %s' % (self._bold(option_string), args_string) for option_string in action.option_strings] return ', '.join(parts) @staticmethod def _markup(string): return string.replace('-', '\\-') @staticmethod def _add_format(string, front, back): if not string.strip().startswith(front): string = front + string if not string.strip().endswith(back): string = string + back return string @staticmethod def _underline(string): return ManPageFormatter._add_format(string, '\\fI', '\\fR') @staticmethod def _bold(string): return ManPageFormatter._add_format(string, '\\fB', '\\fR') def _mk_title(self): return '.TH {0} {1} {2}\n'.format(self._prog, self._section, self._today) def _mk_name(self): return '.SH NAME\n%s\n' % (self._parser.prog) def _mk_synopsis(self): self.add_usage(self._parser.usage, self._parser._actions, self._parser._mutually_exclusive_groups, prefix='') usage = self._format_usage(None, self._parser._actions, self._parser._mutually_exclusive_groups, '') usage = usage.replace('%s ' % self._prog, '') usage = ('.SH SYNOPSIS\n \\fB%s\\fR %s\n' % (ManPageFormatter._markup(self._prog), usage)) return usage def _mk_description(self): if self._long_desc: long_desc = self._long_desc.replace('\n', '\n.br\n') return '.SH DESCRIPTION\n%s\n' % self._markup(long_desc) else: return '' def _mk_options(self): formatter = self._parser._get_formatter() # positionals, optionals and user-defined groups for action_group in self._parser._action_groups: formatter.start_section(None) formatter.add_text(None) formatter.add_arguments(action_group._group_actions) formatter.end_section() # epilog formatter.add_text(self._parser.epilog) # determine help from format above return '.SH OPTIONS\n' + formatter.format_help() def _mk_footer(self): sections = self._ext_sections if not hasattr(sections, '__iter__'): return '' footer = [] for section in sorted(sections.keys()): part = '.SH {}\n {}'.format(section.upper(), sections[section]) footer.append(part) return '\n'.join(footer)
[docs] def format_man_page(self): page = [] page.append(self._mk_title()) page.append(self._mk_name()) page.append(self._mk_synopsis()) page.append(self._mk_description()) page.append(self._mk_options()) page.append(self._mk_footer()) return ''.join(page)