Index: tools/telemetry/third_party/gsutil/third_party/python-gflags/gflags2man.py |
diff --git a/tools/telemetry/third_party/gsutil/third_party/python-gflags/gflags2man.py b/tools/telemetry/third_party/gsutil/third_party/python-gflags/gflags2man.py |
deleted file mode 100644 |
index 3a50f9e19fcf0fb6e78ba24daf868bd2068c8bbb..0000000000000000000000000000000000000000 |
--- a/tools/telemetry/third_party/gsutil/third_party/python-gflags/gflags2man.py |
+++ /dev/null |
@@ -1,544 +0,0 @@ |
-#!/usr/bin/env python |
- |
-# Copyright (c) 2006, Google Inc. |
-# All rights reserved. |
-# |
-# Redistribution and use in source and binary forms, with or without |
-# modification, are permitted provided that the following conditions are |
-# met: |
-# |
-# * Redistributions of source code must retain the above copyright |
-# notice, this list of conditions and the following disclaimer. |
-# * Redistributions in binary form must reproduce the above |
-# copyright notice, this list of conditions and the following disclaimer |
-# in the documentation and/or other materials provided with the |
-# distribution. |
-# * Neither the name of Google Inc. nor the names of its |
-# contributors may be used to endorse or promote products derived from |
-# this software without specific prior written permission. |
-# |
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- |
- |
-"""gflags2man runs a Google flags base program and generates a man page. |
- |
-Run the program, parse the output, and then format that into a man |
-page. |
- |
-Usage: |
- gflags2man <program> [program] ... |
-""" |
- |
-# TODO(csilvers): work with windows paths (\) as well as unix (/) |
- |
-# This may seem a bit of an end run, but it: doesn't bloat flags, can |
-# support python/java/C++, supports older executables, and can be |
-# extended to other document formats. |
-# Inspired by help2man. |
- |
- |
- |
-import os |
-import re |
-import sys |
-import stat |
-import time |
- |
-import gflags |
- |
-_VERSION = '0.1' |
- |
- |
-def _GetDefaultDestDir(): |
- home = os.environ.get('HOME', '') |
- homeman = os.path.join(home, 'man', 'man1') |
- if home and os.path.exists(homeman): |
- return homeman |
- else: |
- return os.environ.get('TMPDIR', '/tmp') |
- |
-FLAGS = gflags.FLAGS |
-gflags.DEFINE_string('dest_dir', _GetDefaultDestDir(), |
- 'Directory to write resulting manpage to.' |
- ' Specify \'-\' for stdout') |
-gflags.DEFINE_string('help_flag', '--help', |
- 'Option to pass to target program in to get help') |
-gflags.DEFINE_integer('v', 0, 'verbosity level to use for output') |
- |
- |
-_MIN_VALID_USAGE_MSG = 9 # if fewer lines than this, help is suspect |
- |
- |
-class Logging: |
- """A super-simple logging class""" |
- def error(self, msg): print >>sys.stderr, "ERROR: ", msg |
- def warn(self, msg): print >>sys.stderr, "WARNING: ", msg |
- def info(self, msg): print msg |
- def debug(self, msg): self.vlog(1, msg) |
- def vlog(self, level, msg): |
- if FLAGS.v >= level: print msg |
-logging = Logging() |
-class App: |
- def usage(self, shorthelp=0): |
- print >>sys.stderr, __doc__ |
- print >>sys.stderr, "flags:" |
- print >>sys.stderr, str(FLAGS) |
- def run(self): |
- main(sys.argv) |
-app = App() |
- |
- |
-def GetRealPath(filename): |
- """Given an executable filename, find in the PATH or find absolute path. |
- Args: |
- filename An executable filename (string) |
- Returns: |
- Absolute version of filename. |
- None if filename could not be found locally, absolutely, or in PATH |
- """ |
- if os.path.isabs(filename): # already absolute |
- return filename |
- |
- if filename.startswith('./') or filename.startswith('../'): # relative |
- return os.path.abspath(filename) |
- |
- path = os.getenv('PATH', '') |
- for directory in path.split(':'): |
- tryname = os.path.join(directory, filename) |
- if os.path.exists(tryname): |
- if not os.path.isabs(directory): # relative directory |
- return os.path.abspath(tryname) |
- return tryname |
- if os.path.exists(filename): |
- return os.path.abspath(filename) |
- return None # could not determine |
- |
-class Flag(object): |
- """The information about a single flag.""" |
- |
- def __init__(self, flag_desc, help): |
- """Create the flag object. |
- Args: |
- flag_desc The command line forms this could take. (string) |
- help The help text (string) |
- """ |
- self.desc = flag_desc # the command line forms |
- self.help = help # the help text |
- self.default = '' # default value |
- self.tips = '' # parsing/syntax tips |
- |
- |
-class ProgramInfo(object): |
- """All the information gleaned from running a program with --help.""" |
- |
- # Match a module block start, for python scripts --help |
- # "goopy.logging:" |
- module_py_re = re.compile(r'(\S.+):$') |
- # match the start of a flag listing |
- # " -v,--verbosity: Logging verbosity" |
- flag_py_re = re.compile(r'\s+(-\S+):\s+(.*)$') |
- # " (default: '0')" |
- flag_default_py_re = re.compile(r'\s+\(default:\s+\'(.*)\'\)$') |
- # " (an integer)" |
- flag_tips_py_re = re.compile(r'\s+\((.*)\)$') |
- |
- # Match a module block start, for c++ programs --help |
- # "google/base/commandlineflags": |
- module_c_re = re.compile(r'\s+Flags from (\S.+):$') |
- # match the start of a flag listing |
- # " -v,--verbosity: Logging verbosity" |
- flag_c_re = re.compile(r'\s+(-\S+)\s+(.*)$') |
- |
- # Match a module block start, for java programs --help |
- # "com.google.common.flags" |
- module_java_re = re.compile(r'\s+Flags for (\S.+):$') |
- # match the start of a flag listing |
- # " -v,--verbosity: Logging verbosity" |
- flag_java_re = re.compile(r'\s+(-\S+)\s+(.*)$') |
- |
- def __init__(self, executable): |
- """Create object with executable. |
- Args: |
- executable Program to execute (string) |
- """ |
- self.long_name = executable |
- self.name = os.path.basename(executable) # name |
- # Get name without extension (PAR files) |
- (self.short_name, self.ext) = os.path.splitext(self.name) |
- self.executable = GetRealPath(executable) # name of the program |
- self.output = [] # output from the program. List of lines. |
- self.desc = [] # top level description. List of lines |
- self.modules = {} # { section_name(string), [ flags ] } |
- self.module_list = [] # list of module names in their original order |
- self.date = time.localtime(time.time()) # default date info |
- |
- def Run(self): |
- """Run it and collect output. |
- |
- Returns: |
- 1 (true) If everything went well. |
- 0 (false) If there were problems. |
- """ |
- if not self.executable: |
- logging.error('Could not locate "%s"' % self.long_name) |
- return 0 |
- |
- finfo = os.stat(self.executable) |
- self.date = time.localtime(finfo[stat.ST_MTIME]) |
- |
- logging.info('Running: %s %s </dev/null 2>&1' |
- % (self.executable, FLAGS.help_flag)) |
- # --help output is often routed to stderr, so we combine with stdout. |
- # Re-direct stdin to /dev/null to encourage programs that |
- # don't understand --help to exit. |
- (child_stdin, child_stdout_and_stderr) = os.popen4( |
- [self.executable, FLAGS.help_flag]) |
- child_stdin.close() # '</dev/null' |
- self.output = child_stdout_and_stderr.readlines() |
- child_stdout_and_stderr.close() |
- if len(self.output) < _MIN_VALID_USAGE_MSG: |
- logging.error('Error: "%s %s" returned only %d lines: %s' |
- % (self.name, FLAGS.help_flag, |
- len(self.output), self.output)) |
- return 0 |
- return 1 |
- |
- def Parse(self): |
- """Parse program output.""" |
- (start_line, lang) = self.ParseDesc() |
- if start_line < 0: |
- return |
- if 'python' == lang: |
- self.ParsePythonFlags(start_line) |
- elif 'c' == lang: |
- self.ParseCFlags(start_line) |
- elif 'java' == lang: |
- self.ParseJavaFlags(start_line) |
- |
- def ParseDesc(self, start_line=0): |
- """Parse the initial description. |
- |
- This could be Python or C++. |
- |
- Returns: |
- (start_line, lang_type) |
- start_line Line to start parsing flags on (int) |
- lang_type Either 'python' or 'c' |
- (-1, '') if the flags start could not be found |
- """ |
- exec_mod_start = self.executable + ':' |
- |
- after_blank = 0 |
- start_line = 0 # ignore the passed-in arg for now (?) |
- for start_line in range(start_line, len(self.output)): # collect top description |
- line = self.output[start_line].rstrip() |
- # Python flags start with 'flags:\n' |
- if ('flags:' == line |
- and len(self.output) > start_line+1 |
- and '' == self.output[start_line+1].rstrip()): |
- start_line += 2 |
- logging.debug('Flags start (python): %s' % line) |
- return (start_line, 'python') |
- # SWIG flags just have the module name followed by colon. |
- if exec_mod_start == line: |
- logging.debug('Flags start (swig): %s' % line) |
- return (start_line, 'python') |
- # C++ flags begin after a blank line and with a constant string |
- if after_blank and line.startswith(' Flags from '): |
- logging.debug('Flags start (c): %s' % line) |
- return (start_line, 'c') |
- # java flags begin with a constant string |
- if line == 'where flags are': |
- logging.debug('Flags start (java): %s' % line) |
- start_line += 2 # skip "Standard flags:" |
- return (start_line, 'java') |
- |
- logging.debug('Desc: %s' % line) |
- self.desc.append(line) |
- after_blank = (line == '') |
- else: |
- logging.warn('Never found the start of the flags section for "%s"!' |
- % self.long_name) |
- return (-1, '') |
- |
- def ParsePythonFlags(self, start_line=0): |
- """Parse python/swig style flags.""" |
- modname = None # name of current module |
- modlist = [] |
- flag = None |
- for line_num in range(start_line, len(self.output)): # collect flags |
- line = self.output[line_num].rstrip() |
- if not line: # blank |
- continue |
- |
- mobj = self.module_py_re.match(line) |
- if mobj: # start of a new module |
- modname = mobj.group(1) |
- logging.debug('Module: %s' % line) |
- if flag: |
- modlist.append(flag) |
- self.module_list.append(modname) |
- self.modules.setdefault(modname, []) |
- modlist = self.modules[modname] |
- flag = None |
- continue |
- |
- mobj = self.flag_py_re.match(line) |
- if mobj: # start of a new flag |
- if flag: |
- modlist.append(flag) |
- logging.debug('Flag: %s' % line) |
- flag = Flag(mobj.group(1), mobj.group(2)) |
- continue |
- |
- if not flag: # continuation of a flag |
- logging.error('Flag info, but no current flag "%s"' % line) |
- mobj = self.flag_default_py_re.match(line) |
- if mobj: # (default: '...') |
- flag.default = mobj.group(1) |
- logging.debug('Fdef: %s' % line) |
- continue |
- mobj = self.flag_tips_py_re.match(line) |
- if mobj: # (tips) |
- flag.tips = mobj.group(1) |
- logging.debug('Ftip: %s' % line) |
- continue |
- if flag and flag.help: |
- flag.help += line # multiflags tack on an extra line |
- else: |
- logging.info('Extra: %s' % line) |
- if flag: |
- modlist.append(flag) |
- |
- def ParseCFlags(self, start_line=0): |
- """Parse C style flags.""" |
- modname = None # name of current module |
- modlist = [] |
- flag = None |
- for line_num in range(start_line, len(self.output)): # collect flags |
- line = self.output[line_num].rstrip() |
- if not line: # blank lines terminate flags |
- if flag: # save last flag |
- modlist.append(flag) |
- flag = None |
- continue |
- |
- mobj = self.module_c_re.match(line) |
- if mobj: # start of a new module |
- modname = mobj.group(1) |
- logging.debug('Module: %s' % line) |
- if flag: |
- modlist.append(flag) |
- self.module_list.append(modname) |
- self.modules.setdefault(modname, []) |
- modlist = self.modules[modname] |
- flag = None |
- continue |
- |
- mobj = self.flag_c_re.match(line) |
- if mobj: # start of a new flag |
- if flag: # save last flag |
- modlist.append(flag) |
- logging.debug('Flag: %s' % line) |
- flag = Flag(mobj.group(1), mobj.group(2)) |
- continue |
- |
- # append to flag help. type and default are part of the main text |
- if flag: |
- flag.help += ' ' + line.strip() |
- else: |
- logging.info('Extra: %s' % line) |
- if flag: |
- modlist.append(flag) |
- |
- def ParseJavaFlags(self, start_line=0): |
- """Parse Java style flags (com.google.common.flags).""" |
- # The java flags prints starts with a "Standard flags" "module" |
- # that doesn't follow the standard module syntax. |
- modname = 'Standard flags' # name of current module |
- self.module_list.append(modname) |
- self.modules.setdefault(modname, []) |
- modlist = self.modules[modname] |
- flag = None |
- |
- for line_num in range(start_line, len(self.output)): # collect flags |
- line = self.output[line_num].rstrip() |
- logging.vlog(2, 'Line: "%s"' % line) |
- if not line: # blank lines terminate module |
- if flag: # save last flag |
- modlist.append(flag) |
- flag = None |
- continue |
- |
- mobj = self.module_java_re.match(line) |
- if mobj: # start of a new module |
- modname = mobj.group(1) |
- logging.debug('Module: %s' % line) |
- if flag: |
- modlist.append(flag) |
- self.module_list.append(modname) |
- self.modules.setdefault(modname, []) |
- modlist = self.modules[modname] |
- flag = None |
- continue |
- |
- mobj = self.flag_java_re.match(line) |
- if mobj: # start of a new flag |
- if flag: # save last flag |
- modlist.append(flag) |
- logging.debug('Flag: %s' % line) |
- flag = Flag(mobj.group(1), mobj.group(2)) |
- continue |
- |
- # append to flag help. type and default are part of the main text |
- if flag: |
- flag.help += ' ' + line.strip() |
- else: |
- logging.info('Extra: %s' % line) |
- if flag: |
- modlist.append(flag) |
- |
- def Filter(self): |
- """Filter parsed data to create derived fields.""" |
- if not self.desc: |
- self.short_desc = '' |
- return |
- |
- for i in range(len(self.desc)): # replace full path with name |
- if self.desc[i].find(self.executable) >= 0: |
- self.desc[i] = self.desc[i].replace(self.executable, self.name) |
- |
- self.short_desc = self.desc[0] |
- word_list = self.short_desc.split(' ') |
- all_names = [ self.name, self.short_name, ] |
- # Since the short_desc is always listed right after the name, |
- # trim it from the short_desc |
- while word_list and (word_list[0] in all_names |
- or word_list[0].lower() in all_names): |
- del word_list[0] |
- self.short_desc = '' # signal need to reconstruct |
- if not self.short_desc and word_list: |
- self.short_desc = ' '.join(word_list) |
- |
- |
-class GenerateDoc(object): |
- """Base class to output flags information.""" |
- |
- def __init__(self, proginfo, directory='.'): |
- """Create base object. |
- Args: |
- proginfo A ProgramInfo object |
- directory Directory to write output into |
- """ |
- self.info = proginfo |
- self.dirname = directory |
- |
- def Output(self): |
- """Output all sections of the page.""" |
- self.Open() |
- self.Header() |
- self.Body() |
- self.Footer() |
- |
- def Open(self): raise NotImplementedError # define in subclass |
- def Header(self): raise NotImplementedError # define in subclass |
- def Body(self): raise NotImplementedError # define in subclass |
- def Footer(self): raise NotImplementedError # define in subclass |
- |
- |
-class GenerateMan(GenerateDoc): |
- """Output a man page.""" |
- |
- def __init__(self, proginfo, directory='.'): |
- """Create base object. |
- Args: |
- proginfo A ProgramInfo object |
- directory Directory to write output into |
- """ |
- GenerateDoc.__init__(self, proginfo, directory) |
- |
- def Open(self): |
- if self.dirname == '-': |
- logging.info('Writing to stdout') |
- self.fp = sys.stdout |
- else: |
- self.file_path = '%s.1' % os.path.join(self.dirname, self.info.name) |
- logging.info('Writing: %s' % self.file_path) |
- self.fp = open(self.file_path, 'w') |
- |
- def Header(self): |
- self.fp.write( |
- '.\\" DO NOT MODIFY THIS FILE! It was generated by gflags2man %s\n' |
- % _VERSION) |
- self.fp.write( |
- '.TH %s "1" "%s" "%s" "User Commands"\n' |
- % (self.info.name, time.strftime('%x', self.info.date), self.info.name)) |
- self.fp.write( |
- '.SH NAME\n%s \\- %s\n' % (self.info.name, self.info.short_desc)) |
- self.fp.write( |
- '.SH SYNOPSIS\n.B %s\n[\\fIFLAGS\\fR]...\n' % self.info.name) |
- |
- def Body(self): |
- self.fp.write( |
- '.SH DESCRIPTION\n.\\" Add any additional description here\n.PP\n') |
- for ln in self.info.desc: |
- self.fp.write('%s\n' % ln) |
- self.fp.write( |
- '.SH OPTIONS\n') |
- # This shows flags in the original order |
- for modname in self.info.module_list: |
- if modname.find(self.info.executable) >= 0: |
- mod = modname.replace(self.info.executable, self.info.name) |
- else: |
- mod = modname |
- self.fp.write('\n.P\n.I %s\n' % mod) |
- for flag in self.info.modules[modname]: |
- help_string = flag.help |
- if flag.default or flag.tips: |
- help_string += '\n.br\n' |
- if flag.default: |
- help_string += ' (default: \'%s\')' % flag.default |
- if flag.tips: |
- help_string += ' (%s)' % flag.tips |
- self.fp.write( |
- '.TP\n%s\n%s\n' % (flag.desc, help_string)) |
- |
- def Footer(self): |
- self.fp.write( |
- '.SH COPYRIGHT\nCopyright \(co %s Google.\n' |
- % time.strftime('%Y', self.info.date)) |
- self.fp.write('Gflags2man created this page from "%s %s" output.\n' |
- % (self.info.name, FLAGS.help_flag)) |
- self.fp.write('\nGflags2man was written by Dan Christian. ' |
- ' Note that the date on this' |
- ' page is the modification date of %s.\n' % self.info.name) |
- |
- |
-def main(argv): |
- argv = FLAGS(argv) # handles help as well |
- if len(argv) <= 1: |
- app.usage(shorthelp=1) |
- return 1 |
- |
- for arg in argv[1:]: |
- prog = ProgramInfo(arg) |
- if not prog.Run(): |
- continue |
- prog.Parse() |
- prog.Filter() |
- doc = GenerateMan(prog, FLAGS.dest_dir) |
- doc.Output() |
- return 0 |
- |
-if __name__ == '__main__': |
- app.run() |