Răsfoiți Sursa

More improvements to build_manpage

 * Move more stuff to the ManPageFormater class
 * Add auto build  option
oz123 10 ani în urmă
părinte
comite
7b51deaf43
1 a modificat fișierele cu 51 adăugiri și 112 ștergeri
  1. 51 112
      build_manpage.py

+ 51 - 112
build_manpage.py

@@ -26,15 +26,27 @@ You can then use the following setup command to produce a man page::
 
     $ python setup.py build_manpage --output=prog.1 --parser=yourmodule:argparser
 
+Alternatively, set the variable AUTO_BUILD to True, and just invoke::
+
+    $ python setup.py build
+
+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>
 """
 
 
 import datetime
 from distutils.core import Command
 from distutils.errors import DistutilsOptionError
+from distutils.command.build import build
 import argparse
 import re as _re
 
+AUTO_BUILD = False
 
 class BuildManPage(Command):
 
@@ -80,13 +92,8 @@ class BuildManPage(Command):
                                                           appname))
         description = self.distribution.get_description()
 
-        if description:
-            name = self._markup('%s - %s' % (self._markup(appname),
-                                             description.splitlines()[0]))
-        else:
-            name = self._markup(appname)
-        ret.append('.SH NAME\n%s\n' % name)
-
+        ret.append(self._parser.formatter_class._mk_name(self._parser._get_formatter(),
+                                                             self.distribution))
         self._parser._prog = appname
         ret.append(self._parser.formatter_class._mk_synopsis(self._parser._get_formatter(),
                                                              self._parser))
@@ -99,18 +106,23 @@ class BuildManPage(Command):
         return self._parser.formatter_class.format_options(self._parser)
 
     def _write_footer(self):
-        ret = []
+        """
+        Writing the footer allows one to add a lot of extra information.
+        Sections and and their content can be specified in the dictionary
+        sections which is passed to the formater method
+        """
         appname = self.distribution.get_name()
-        author = '%s <%s>' % (self.distribution.get_author(),
-                              self.distribution.get_author_email())
-        ret.append(('.SH AUTHORS\n.B %s\nwas written by %s.\n'
-                    % (self._markup(appname), self._markup(author))))
         homepage = self.distribution.get_url()
-        ret.append(('.SH DISTRIBUTION\nThe latest version of %s may '
-                    'be downloaded from\n'
-                    '%s\n\n'
-                    % (self._markup(appname), self._markup(homepage),)))
-        return ''.join(ret)
+        sections = {'authors': ("pwman3 was originally written by Ivan Kelly "
+                                "<ivan@ivankelly.net>. pwman3 is now maintained "
+                                "by Oz Nahum <nahumoz@gmail.com>."),
+                    'distribution': ("The latest version of {} may be "
+                                     "downloaded from {}".format(appname,
+                                                                 homepage))
+                    }
+
+        return self._parser.formatter_class._mk_footer(self._parser._get_formatter(),
+                                                       sections)
 
     def run(self):
         manpage = []
@@ -129,7 +141,9 @@ class ManPageFormatter(argparse.HelpFormatter):
                  indent_increment=2,
                  max_help_position=24,
                  width=None,
-                 section=1):
+                 section=1,
+                 authors=None,
+                 distribution=None):
 
         super(ManPageFormatter, self).__init__(prog)
 
@@ -153,8 +167,7 @@ class ManPageFormatter(argparse.HelpFormatter):
     def _mk_synopsis(self, parser):
         self.add_usage(parser.usage, parser._actions,
                        parser._mutually_exclusive_groups, prefix='')
-        # TODO: Override _fromat_usage, work in progress
-        usage = self._format_usage(parser._prog, parser._actions,
+        usage = self._format_usage(None, parser._actions,
                                    parser._mutually_exclusive_groups, '')
 
         usage = usage.replace('%s ' % parser._prog, '')
@@ -167,6 +180,14 @@ class ManPageFormatter(argparse.HelpFormatter):
         return '.TH {0} {1} {2}\n'.format(prog, self._section,
                                           self._today)
 
+    def _mk_name(self, distribution):
+        """
+        this method is in consitent with others ... it relies on
+        distribution
+        """
+        return '.SH NAME\n%s \\- %s\n' % (distribution.get_name(),
+                                          distribution.get_description())
+
     def _mk_description(self, distribution):
 
         long_desc = distribution.get_long_description()
@@ -177,6 +198,14 @@ class ManPageFormatter(argparse.HelpFormatter):
         else:
             return ''
 
+    def _mk_footer(self, sections):
+        footer = []
+        for section, value in sections.iteritems():
+            part = ".SH {}\n {}".format(section.upper(), value)
+            footer.append(part)
+
+        return '\n'.join(footer)
+
     @staticmethod
     def format_options(parser):
 
@@ -218,95 +247,5 @@ class ManPageFormatter(argparse.HelpFormatter):
 
             return ', '.join(parts)
 
-    def _format_usage(self, prog, actions, groups, prefix):
-
-        # if usage is specified, use that
-        # if usage is not None:
-        #    usage = usage % dict(prog=self._prog)
-
-        # if no optionals or positionals are available, usage is just prog
-        #elif usage is None and not actions:
-        #    usage = '%(prog)s' % dict(prog=self._prog)
-
-        # if optionals and positionals are available, calculate usage
-        #elif usage is None:
-        if True:
-            prog = '%(prog)s' % dict(prog=prog)
-
-            # split optionals from positionals
-            optionals = []
-            positionals = []
-            for action in actions:
-                if action.option_strings:
-                    optionals.append(action)
-                else:
-                    positionals.append(action)
-
-            # build full usage string
-            format = self._format_actions_usage
-            action_usage = format(optionals + positionals, groups)
-            usage = ' '.join([s for s in [prog, action_usage] if s])
-
-            # wrap the usage parts if it's too long
-            text_width = self._width - self._current_indent
-            if len(prefix) + len(usage) > text_width:
-
-                # break usage into wrappable parts
-                part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
-                opt_usage = format(optionals, groups)
-                pos_usage = format(positionals, groups)
-                opt_parts = _re.findall(part_regexp, opt_usage)
-                pos_parts = _re.findall(part_regexp, pos_usage)
-                assert ' '.join(opt_parts) == opt_usage
-                assert ' '.join(pos_parts) == pos_usage
-
-                # helper for wrapping lines
-                def get_lines(parts, indent, prefix=None):
-                    lines = []
-                    line = []
-                    if prefix is not None:
-                        line_len = len(prefix) - 1
-                    else:
-                        line_len = len(indent) - 1
-                    for part in parts:
-                        if line_len + 1 + len(part) > text_width:
-                            lines.append(indent + ' '.join(line))
-                            line = []
-                            line_len = len(indent) - 1
-                        line.append(part)
-                        line_len += len(part) + 1
-                    if line:
-                        lines.append(indent + ' '.join(line))
-                    if prefix is not None:
-                        lines[0] = lines[0][len(indent):]
-                    return lines
-
-                # if prog is short, follow it with optionals or positionals
-                if len(prefix) + len(prog) <= 0.75 * text_width:
-                    indent = ' ' * (len(prefix) + len(prog) + 1)
-                    if opt_parts:
-                        lines = get_lines([prog] + opt_parts, indent, prefix)
-                        lines.extend(get_lines(pos_parts, indent))
-                    elif pos_parts:
-                        lines = get_lines([prog] + pos_parts, indent, prefix)
-                    else:
-                        lines = [prog]
-
-                # if prog is long, put it on its own line
-                else:
-                    indent = ' ' * len(prefix)
-                    parts = opt_parts + pos_parts
-                    lines = get_lines(parts, indent)
-                    if len(lines) > 1:
-                        lines = []
-                        lines.extend(get_lines(opt_parts, indent))
-                        lines.extend(get_lines(pos_parts, indent))
-                    lines = [prog] + lines
-
-                # join lines into usage
-                usage = '\n'.join(lines)
-
-        # prefix with 'usage:'
-        return '%s%s\n\n' % (prefix, usage)
-
-#  build.sub_commands.append(('build_manpage', None))
+if AUTO_BUILD:
+    build.sub_commands.append(('build_manpage', None))