summaryrefslogtreecommitdiff
path: root/cliapp/genman.py
diff options
context:
space:
mode:
authorEdward Cragg <edward.cragg@codethink.co.uk>2016-03-27 11:56:15 +0100
committerSam Thursfield <sam.thursfield@codethink.co.uk>2016-03-31 11:43:55 +0100
commite36043737201a645897d366ba0eb44e91748d16e (patch)
tree0b7fb836cf84b8ef8c15fe91907c37ab71aec947 /cliapp/genman.py
parenta7f12476d4e7b2025a60be58027b67b9e551f31b (diff)
downloadmorph-e36043737201a645897d366ba0eb44e91748d16e.tar.gz
Add local cliapp module
Add a copy of the specific version of the cliapp module required by morph, a known version of which can't otherwise be guaranteed to be available on general Linux systems, or via PyPi. Including the module directly allows for continued development in line with morph, until a time when it may become desirable to move away from dependence on this module. With a local copy of cliapp added to morph, it has been shown that morph is capable of building Baserock images without depending on an existing Baserock system. Change-Id: Iab1f7037c7afff054a2404c0552d9b5e4d2d141f
Diffstat (limited to 'cliapp/genman.py')
-rw-r--r--cliapp/genman.py148
1 files changed, 148 insertions, 0 deletions
diff --git a/cliapp/genman.py b/cliapp/genman.py
new file mode 100644
index 00000000..e81fcfee
--- /dev/null
+++ b/cliapp/genman.py
@@ -0,0 +1,148 @@
+# Copyright (C) 2011 Lars Wirzenius
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+import optparse
+import re
+
+
+class ManpageGenerator(object):
+
+ '''Fill in a manual page template from an OptionParser instance.'''
+
+ def __init__(self, template, parser, arg_synopsis, cmd_synopsis):
+ self.template = template
+ self.parser = parser
+ self.arg_synopsis = arg_synopsis
+ self.cmd_synopsis = cmd_synopsis
+
+ def sort_options(self, options):
+ return sorted(options,
+ key=lambda o: (o._long_opts + o._short_opts)[0])
+
+ def option_list(self, container):
+ return self.sort_options(container.option_list)
+
+ @property
+ def options(self):
+ return self.option_list(self.parser)
+
+ def format_template(self):
+ sections = (('SYNOPSIS', self.format_synopsis()),
+ ('OPTIONS', self.format_options()))
+ text = self.template
+ for section, contents in sections:
+ pattern = '\n.SH %s\n' % section
+ text = text.replace(pattern, pattern + contents)
+ return text
+
+ def format_synopsis(self):
+ lines = []
+ lines += ['.nh']
+ lines += ['.B %s' % self.esc_dashes(self.parser.prog)]
+
+ all_options = self.option_list(self.parser)
+ for group in self.parser.option_groups:
+ all_options += self.option_list(group)
+ for option in self.sort_options(all_options):
+ for spec in self.format_option_for_synopsis(option):
+ lines += ['.RB [ %s ]' % spec]
+
+ if self.cmd_synopsis:
+ lines += ['.PP']
+ for cmd in sorted(self.cmd_synopsis):
+ lines += ['.br',
+ '.B %s' % self.esc_dashes(self.parser.prog),
+ '.RI [ options ]',
+ self.esc_dashes(cmd)]
+ lines += self.format_argspec(self.cmd_synopsis[cmd])
+ elif self.arg_synopsis:
+ lines += self.format_argspec(self.arg_synopsis)
+
+ lines += ['.hy']
+ return ''.join('%s\n' % line for line in lines)
+
+ def format_option_for_synopsis(self, option):
+ if option.metavar:
+ suffix = '\\fR=\\fI%s' % self.esc_dashes(option.metavar)
+ else:
+ suffix = ''
+ for name in option._short_opts + option._long_opts:
+ yield '%s%s' % (self.esc_dashes(name), suffix)
+
+ def format_options(self):
+ lines = []
+
+ for option in self.sort_options(self.parser.option_list):
+ lines += self.format_option_for_options(option)
+
+ for group in self.parser.option_groups:
+ lines += ['.SS "%s"' % group.title]
+ for option in self.sort_options(group.option_list):
+ lines += self.format_option_for_options(option)
+
+ return ''.join('%s\n' % line for line in lines)
+
+ def format_option_for_options(self, option):
+ lines = []
+ lines += ['.TP']
+ shorts = [self.esc_dashes(x) for x in option._short_opts]
+ if option.metavar:
+ longs = ['%s =\\fI%s' % (self.esc_dashes(x), option.metavar)
+ for x in option._long_opts]
+ else:
+ longs = ['%s' % self.esc_dashes(x)
+ for x in option._long_opts]
+ lines += ['.BR ' + ' ", " '.join(shorts + longs)]
+ lines += [self.esc_dots(self.expand_default(option).strip())]
+ return lines
+
+ def expand_default(self, option):
+ default = self.parser.defaults.get(option.dest)
+ if default is optparse.NO_DEFAULT or default is None:
+ default = 'none'
+ else:
+ default = str(default)
+ return option.help.replace('%default', default)
+
+ def esc_dashes(self, optname):
+ return '\\-'.join(optname.split('-'))
+
+ def esc_dots(self, line):
+ if line.startswith('.'):
+ return '\\' + line
+ else:
+ return line
+
+ def format_argspec(self, argspec):
+ roman = re.compile(r'[^A-Z]+')
+ italic = re.compile(r'[A-Z]+')
+ words = ['.RI']
+ while argspec:
+ m = roman.match(argspec)
+ if m:
+ words += [self.esc_dashes(m.group(0))]
+ argspec = argspec[m.end():]
+ else:
+ words += ['""']
+ m = italic.match(argspec)
+ if m:
+ words += [self.esc_dashes(m.group(0))]
+ argspec = argspec[m.end():]
+ else:
+ words += ['""']
+ return [' '.join(words)]
+