12da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#!/usr/bin/env python 22da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 32da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Copyright (c) 2006, Google Inc. 42da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# All rights reserved. 52da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 62da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Redistribution and use in source and binary forms, with or without 72da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# modification, are permitted provided that the following conditions are 82da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# met: 92da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# * Redistributions of source code must retain the above copyright 112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# notice, this list of conditions and the following disclaimer. 122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# * Redistributions in binary form must reproduce the above 132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# copyright notice, this list of conditions and the following disclaimer 142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# in the documentation and/or other materials provided with the 152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# distribution. 162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# * Neither the name of Google Inc. nor the names of its 172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# contributors may be used to endorse or promote products derived from 182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# this software without specific prior written permission. 192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis"""gflags2man runs a Google flags base program and generates a man page. 342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 352da489cd246702bee5938545b18a6f710ed214bcJamie GennisRun the program, parse the output, and then format that into a man 362da489cd246702bee5938545b18a6f710ed214bcJamie Gennispage. 372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 382da489cd246702bee5938545b18a6f710ed214bcJamie GennisUsage: 392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis gflags2man <program> [program] ... 402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis""" 412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# TODO(csilvers): work with windows paths (\) as well as unix (/) 432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# This may seem a bit of an end run, but it: doesn't bloat flags, can 452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# support python/java/C++, supports older executables, and can be 462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# extended to other document formats. 472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Inspired by help2man. 482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 512da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport os 522da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport re 532da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport sys 542da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport stat 552da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport time 562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 572da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport gflags 582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis_VERSION = '0.1' 602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 622da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef _GetDefaultDestDir(): 632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis home = os.environ.get('HOME', '') 642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis homeman = os.path.join(home, 'man', 'man1') 652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if home and os.path.exists(homeman): 662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return homeman 672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return os.environ.get('TMPDIR', '/tmp') 692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 702da489cd246702bee5938545b18a6f710ed214bcJamie GennisFLAGS = gflags.FLAGS 712da489cd246702bee5938545b18a6f710ed214bcJamie Gennisgflags.DEFINE_string('dest_dir', _GetDefaultDestDir(), 722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'Directory to write resulting manpage to.' 732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis ' Specify \'-\' for stdout') 742da489cd246702bee5938545b18a6f710ed214bcJamie Gennisgflags.DEFINE_string('help_flag', '--help', 752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'Option to pass to target program in to get help') 762da489cd246702bee5938545b18a6f710ed214bcJamie Gennisgflags.DEFINE_integer('v', 0, 'verbosity level to use for output') 772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis_MIN_VALID_USAGE_MSG = 9 # if fewer lines than this, help is suspect 802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 822da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass Logging: 832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """A super-simple logging class""" 842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def error(self, msg): print >>sys.stderr, "ERROR: ", msg 852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def warn(self, msg): print >>sys.stderr, "WARNING: ", msg 862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def info(self, msg): print msg 872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def debug(self, msg): self.vlog(1, msg) 882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def vlog(self, level, msg): 892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if FLAGS.v >= level: print msg 902da489cd246702bee5938545b18a6f710ed214bcJamie Gennislogging = Logging() 912da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass App: 922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def usage(self, shorthelp=0): 932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis print >>sys.stderr, __doc__ 942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis print >>sys.stderr, "flags:" 952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis print >>sys.stderr, str(FLAGS) 962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def run(self): 972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis main(sys.argv) 982da489cd246702bee5938545b18a6f710ed214bcJamie Gennisapp = App() 992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1012da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef GetRealPath(filename): 1022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Given an executable filename, find in the PATH or find absolute path. 1032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 1042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis filename An executable filename (string) 1052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 1062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Absolute version of filename. 1072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis None if filename could not be found locally, absolutely, or in PATH 1082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 1092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if os.path.isabs(filename): # already absolute 1102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return filename 1112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if filename.startswith('./') or filename.startswith('../'): # relative 1132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return os.path.abspath(filename) 1142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis path = os.getenv('PATH', '') 1162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for directory in path.split(':'): 1172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis tryname = os.path.join(directory, filename) 1182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if os.path.exists(tryname): 1192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not os.path.isabs(directory): # relative directory 1202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return os.path.abspath(tryname) 1212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return tryname 1222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if os.path.exists(filename): 1232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return os.path.abspath(filename) 1242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return None # could not determine 1252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1262da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass Flag(object): 1272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """The information about a single flag.""" 1282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self, flag_desc, help): 1302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Create the flag object. 1312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 1322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag_desc The command line forms this could take. (string) 1332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis help The help text (string) 1342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 1352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.desc = flag_desc # the command line forms 1362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.help = help # the help text 1372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.default = '' # default value 1382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.tips = '' # parsing/syntax tips 1392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1412da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass ProgramInfo(object): 1422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """All the information gleaned from running a program with --help.""" 1432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Match a module block start, for python scripts --help 1452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # "goopy.logging:" 1462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis module_py_re = re.compile(r'(\S.+):$') 1472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # match the start of a flag listing 1482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # " -v,--verbosity: Logging verbosity" 1492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag_py_re = re.compile(r'\s+(-\S+):\s+(.*)$') 1502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # " (default: '0')" 1512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag_default_py_re = re.compile(r'\s+\(default:\s+\'(.*)\'\)$') 1522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # " (an integer)" 1532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag_tips_py_re = re.compile(r'\s+\((.*)\)$') 1542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Match a module block start, for c++ programs --help 1562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # "google/base/commandlineflags": 1572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis module_c_re = re.compile(r'\s+Flags from (\S.+):$') 1582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # match the start of a flag listing 1592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # " -v,--verbosity: Logging verbosity" 1602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag_c_re = re.compile(r'\s+(-\S+)\s+(.*)$') 1612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Match a module block start, for java programs --help 1632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # "com.google.common.flags" 1642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis module_java_re = re.compile(r'\s+Flags for (\S.+):$') 1652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # match the start of a flag listing 1662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # " -v,--verbosity: Logging verbosity" 1672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag_java_re = re.compile(r'\s+(-\S+)\s+(.*)$') 1682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self, executable): 1702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Create object with executable. 1712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 1722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis executable Program to execute (string) 1732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 1742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.long_name = executable 1752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.name = os.path.basename(executable) # name 1762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Get name without extension (PAR files) 1772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis (self.short_name, self.ext) = os.path.splitext(self.name) 1782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.executable = GetRealPath(executable) # name of the program 1792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.output = [] # output from the program. List of lines. 1802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.desc = [] # top level description. List of lines 1812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.modules = {} # { section_name(string), [ flags ] } 1822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.module_list = [] # list of module names in their original order 1832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.date = time.localtime(time.time()) # default date info 1842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Run(self): 1862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Run it and collect output. 1872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 1892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1 (true) If everything went well. 1902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 0 (false) If there were problems. 1912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 1922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not self.executable: 1932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.error('Could not locate "%s"' % self.long_name) 1942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return 0 1952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis finfo = os.stat(self.executable) 1972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.date = time.localtime(finfo[stat.ST_MTIME]) 1982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.info('Running: %s %s </dev/null 2>&1' 2002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis % (self.executable, FLAGS.help_flag)) 2012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # --help output is often routed to stderr, so we combine with stdout. 2022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Re-direct stdin to /dev/null to encourage programs that 2032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # don't understand --help to exit. 2042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis (child_stdin, child_stdout_and_stderr) = os.popen4( 2052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis [self.executable, FLAGS.help_flag]) 2062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis child_stdin.close() # '</dev/null' 2072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.output = child_stdout_and_stderr.readlines() 2082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis child_stdout_and_stderr.close() 2092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if len(self.output) < _MIN_VALID_USAGE_MSG: 2102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.error('Error: "%s %s" returned only %d lines: %s' 2112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis % (self.name, FLAGS.help_flag, 2122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis len(self.output), self.output)) 2132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return 0 2142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return 1 2152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Parse(self): 2172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Parse program output.""" 2182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis (start_line, lang) = self.ParseDesc() 2192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if start_line < 0: 2202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return 2212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if 'python' == lang: 2222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.ParsePythonFlags(start_line) 2232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif 'c' == lang: 2242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.ParseCFlags(start_line) 2252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif 'java' == lang: 2262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.ParseJavaFlags(start_line) 2272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def ParseDesc(self, start_line=0): 2292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Parse the initial description. 2302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis This could be Python or C++. 2322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 2342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis (start_line, lang_type) 2352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start_line Line to start parsing flags on (int) 2362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis lang_type Either 'python' or 'c' 2372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis (-1, '') if the flags start could not be found 2382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis exec_mod_start = self.executable + ':' 2402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis after_blank = 0 2422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start_line = 0 # ignore the passed-in arg for now (?) 2432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for start_line in range(start_line, len(self.output)): # collect top description 2442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis line = self.output[start_line].rstrip() 2452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Python flags start with 'flags:\n' 2462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if ('flags:' == line 2472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis and len(self.output) > start_line+1 2482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis and '' == self.output[start_line+1].rstrip()): 2492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start_line += 2 2502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Flags start (python): %s' % line) 2512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return (start_line, 'python') 2522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # SWIG flags just have the module name followed by colon. 2532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if exec_mod_start == line: 2542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Flags start (swig): %s' % line) 2552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return (start_line, 'python') 2562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # C++ flags begin after a blank line and with a constant string 2572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if after_blank and line.startswith(' Flags from '): 2582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Flags start (c): %s' % line) 2592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return (start_line, 'c') 2602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # java flags begin with a constant string 2612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if line == 'where flags are': 2622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Flags start (java): %s' % line) 2632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start_line += 2 # skip "Standard flags:" 2642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return (start_line, 'java') 2652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Desc: %s' % line) 2672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.desc.append(line) 2682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis after_blank = (line == '') 2692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 2702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.warn('Never found the start of the flags section for "%s"!' 2712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis % self.long_name) 2722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return (-1, '') 2732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def ParsePythonFlags(self, start_line=0): 2752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Parse python/swig style flags.""" 2762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modname = None # name of current module 2772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist = [] 2782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag = None 2792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for line_num in range(start_line, len(self.output)): # collect flags 2802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis line = self.output[line_num].rstrip() 2812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not line: # blank 2822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis continue 2832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis mobj = self.module_py_re.match(line) 2852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if mobj: # start of a new module 2862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modname = mobj.group(1) 2872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Module: %s' % line) 2882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: 2892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist.append(flag) 2902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.module_list.append(modname) 2912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.modules.setdefault(modname, []) 2922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist = self.modules[modname] 2932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag = None 2942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis continue 2952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis mobj = self.flag_py_re.match(line) 2972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if mobj: # start of a new flag 2982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: 2992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist.append(flag) 3002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Flag: %s' % line) 3012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag = Flag(mobj.group(1), mobj.group(2)) 3022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis continue 3032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not flag: # continuation of a flag 3052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.error('Flag info, but no current flag "%s"' % line) 3062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis mobj = self.flag_default_py_re.match(line) 3072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if mobj: # (default: '...') 3082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag.default = mobj.group(1) 3092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Fdef: %s' % line) 3102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis continue 3112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis mobj = self.flag_tips_py_re.match(line) 3122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if mobj: # (tips) 3132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag.tips = mobj.group(1) 3142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Ftip: %s' % line) 3152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis continue 3162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag and flag.help: 3172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag.help += line # multiflags tack on an extra line 3182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 3192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.info('Extra: %s' % line) 3202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: 3212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist.append(flag) 3222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def ParseCFlags(self, start_line=0): 3242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Parse C style flags.""" 3252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modname = None # name of current module 3262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist = [] 3272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag = None 3282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for line_num in range(start_line, len(self.output)): # collect flags 3292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis line = self.output[line_num].rstrip() 3302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not line: # blank lines terminate flags 3312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: # save last flag 3322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist.append(flag) 3332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag = None 3342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis continue 3352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis mobj = self.module_c_re.match(line) 3372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if mobj: # start of a new module 3382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modname = mobj.group(1) 3392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Module: %s' % line) 3402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: 3412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist.append(flag) 3422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.module_list.append(modname) 3432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.modules.setdefault(modname, []) 3442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist = self.modules[modname] 3452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag = None 3462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis continue 3472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis mobj = self.flag_c_re.match(line) 3492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if mobj: # start of a new flag 3502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: # save last flag 3512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist.append(flag) 3522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Flag: %s' % line) 3532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag = Flag(mobj.group(1), mobj.group(2)) 3542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis continue 3552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # append to flag help. type and default are part of the main text 3572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: 3582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag.help += ' ' + line.strip() 3592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 3602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.info('Extra: %s' % line) 3612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: 3622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist.append(flag) 3632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def ParseJavaFlags(self, start_line=0): 3652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Parse Java style flags (com.google.common.flags).""" 3662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # The java flags prints starts with a "Standard flags" "module" 3672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # that doesn't follow the standard module syntax. 3682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modname = 'Standard flags' # name of current module 3692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.module_list.append(modname) 3702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.modules.setdefault(modname, []) 3712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist = self.modules[modname] 3722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag = None 3732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for line_num in range(start_line, len(self.output)): # collect flags 3752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis line = self.output[line_num].rstrip() 3762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.vlog(2, 'Line: "%s"' % line) 3772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not line: # blank lines terminate module 3782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: # save last flag 3792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist.append(flag) 3802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag = None 3812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis continue 3822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis mobj = self.module_java_re.match(line) 3842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if mobj: # start of a new module 3852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modname = mobj.group(1) 3862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Module: %s' % line) 3872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: 3882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist.append(flag) 3892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.module_list.append(modname) 3902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.modules.setdefault(modname, []) 3912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist = self.modules[modname] 3922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag = None 3932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis continue 3942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis mobj = self.flag_java_re.match(line) 3962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if mobj: # start of a new flag 3972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: # save last flag 3982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist.append(flag) 3992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.debug('Flag: %s' % line) 4002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag = Flag(mobj.group(1), mobj.group(2)) 4012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis continue 4022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # append to flag help. type and default are part of the main text 4042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: 4052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag.help += ' ' + line.strip() 4062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 4072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.info('Extra: %s' % line) 4082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag: 4092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis modlist.append(flag) 4102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Filter(self): 4122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Filter parsed data to create derived fields.""" 4132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not self.desc: 4142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.short_desc = '' 4152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return 4162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for i in range(len(self.desc)): # replace full path with name 4182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.desc[i].find(self.executable) >= 0: 4192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.desc[i] = self.desc[i].replace(self.executable, self.name) 4202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.short_desc = self.desc[0] 4222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis word_list = self.short_desc.split(' ') 4232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis all_names = [ self.name, self.short_name, ] 4242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Since the short_desc is always listed right after the name, 4252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # trim it from the short_desc 4262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while word_list and (word_list[0] in all_names 4272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis or word_list[0].lower() in all_names): 4282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis del word_list[0] 4292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.short_desc = '' # signal need to reconstruct 4302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not self.short_desc and word_list: 4312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.short_desc = ' '.join(word_list) 4322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4342da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass GenerateDoc(object): 4352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Base class to output flags information.""" 4362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self, proginfo, directory='.'): 4382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Create base object. 4392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 4402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis proginfo A ProgramInfo object 4412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis directory Directory to write output into 4422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 4432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.info = proginfo 4442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.dirname = directory 4452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Output(self): 4472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Output all sections of the page.""" 4482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.Open() 4492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.Header() 4502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.Body() 4512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.Footer() 4522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Open(self): raise NotImplementedError # define in subclass 4542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Header(self): raise NotImplementedError # define in subclass 4552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Body(self): raise NotImplementedError # define in subclass 4562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Footer(self): raise NotImplementedError # define in subclass 4572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4592da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass GenerateMan(GenerateDoc): 4602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Output a man page.""" 4612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self, proginfo, directory='.'): 4632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Create base object. 4642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 4652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis proginfo A ProgramInfo object 4662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis directory Directory to write output into 4672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 4682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis GenerateDoc.__init__(self, proginfo, directory) 4692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Open(self): 4712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.dirname == '-': 4722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.info('Writing to stdout') 4732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp = sys.stdout 4742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 4752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.file_path = '%s.1' % os.path.join(self.dirname, self.info.name) 4762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis logging.info('Writing: %s' % self.file_path) 4772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp = open(self.file_path, 'w') 4782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Header(self): 4802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp.write( 4812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis '.\\" DO NOT MODIFY THIS FILE! It was generated by gflags2man %s\n' 4822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis % _VERSION) 4832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp.write( 4842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis '.TH %s "1" "%s" "%s" "User Commands"\n' 4852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis % (self.info.name, time.strftime('%x', self.info.date), self.info.name)) 4862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp.write( 4872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis '.SH NAME\n%s \\- %s\n' % (self.info.name, self.info.short_desc)) 4882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp.write( 4892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis '.SH SYNOPSIS\n.B %s\n[\\fIFLAGS\\fR]...\n' % self.info.name) 4902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Body(self): 4922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp.write( 4932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis '.SH DESCRIPTION\n.\\" Add any additional description here\n.PP\n') 4942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for ln in self.info.desc: 4952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp.write('%s\n' % ln) 4962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp.write( 4972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis '.SH OPTIONS\n') 4982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # This shows flags in the original order 4992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for modname in self.info.module_list: 5002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if modname.find(self.info.executable) >= 0: 5012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis mod = modname.replace(self.info.executable, self.info.name) 5022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 5032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis mod = modname 5042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp.write('\n.P\n.I %s\n' % mod) 5052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for flag in self.info.modules[modname]: 5062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis help_string = flag.help 5072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag.default or flag.tips: 5082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis help_string += '\n.br\n' 5092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag.default: 5102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis help_string += ' (default: \'%s\')' % flag.default 5112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag.tips: 5122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis help_string += ' (%s)' % flag.tips 5132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp.write( 5142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis '.TP\n%s\n%s\n' % (flag.desc, help_string)) 5152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Footer(self): 5172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp.write( 5182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis '.SH COPYRIGHT\nCopyright \(co %s Google.\n' 5192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis % time.strftime('%Y', self.info.date)) 5202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp.write('Gflags2man created this page from "%s %s" output.\n' 5212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis % (self.info.name, FLAGS.help_flag)) 5222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.fp.write('\nGflags2man was written by Dan Christian. ' 5232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis ' Note that the date on this' 5242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis ' page is the modification date of %s.\n' % self.info.name) 5252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5272da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef main(argv): 5282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis argv = FLAGS(argv) # handles help as well 5292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if len(argv) <= 1: 5302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis app.usage(shorthelp=1) 5312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return 1 5322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for arg in argv[1:]: 5342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis prog = ProgramInfo(arg) 5352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not prog.Run(): 5362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis continue 5372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis prog.Parse() 5382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis prog.Filter() 5392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis doc = GenerateMan(prog, FLAGS.dest_dir) 5402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis doc.Output() 5412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return 0 5422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5432da489cd246702bee5938545b18a6f710ed214bcJamie Gennisif __name__ == '__main__': 5442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis app.run() 545