gcloud 0.0.2 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +2 -3
- data/CHANGELOG +4 -0
- data/LICENSE +674 -0
- data/Manifest +111 -0
- data/README.md +4 -3
- data/bin/gcutil +53 -0
- data/gcloud.gemspec +4 -3
- data/packages/gcutil-1.7.1/CHANGELOG +197 -0
- data/packages/gcutil-1.7.1/LICENSE +202 -0
- data/packages/gcutil-1.7.1/VERSION +1 -0
- data/packages/gcutil-1.7.1/gcutil +53 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/LICENSE +23 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/__init__.py +1 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/discovery.py +743 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/errors.py +123 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/ext/__init__.py +0 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/http.py +1443 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/mimeparse.py +172 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/model.py +385 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/schema.py +303 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/__init__.py +1 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/anyjson.py +32 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/appengine.py +528 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/client.py +1139 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/clientsecrets.py +105 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/crypt.py +244 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/django_orm.py +124 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/file.py +107 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/locked_file.py +343 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/multistore_file.py +379 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/tools.py +174 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/uritemplate/__init__.py +147 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/LICENSE +202 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/__init__.py +3 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/__init__.py +3 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/app.py +356 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/appcommands.py +783 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/basetest.py +1260 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/datelib.py +421 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/debug.py +60 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/file_util.py +181 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/resources.py +67 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/run_script_module.py +217 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/setup_command.py +159 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/shellutil.py +49 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/stopwatch.py +204 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/__init__.py +0 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper.py +140 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper_test.py +149 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth.py +130 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth_test.py +75 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds.py +128 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds_test.py +111 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base.py +1808 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base_test.py +1651 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta13.json +2851 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta14.json +3361 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds.py +342 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds_test.py +474 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds.py +344 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds_test.py +231 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/flags_cache.py +274 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil +89 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil_logging.py +69 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds.py +262 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds_test.py +172 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds.py +1506 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds_test.py +1904 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds.py +91 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds_test.py +56 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds.py +106 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds_test.py +59 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata.py +96 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_lib.py +357 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_test.py +84 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_api.py +420 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_metadata.py +58 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.py +824 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds_test.py +307 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds.py +178 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds_test.py +133 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds.py +181 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds_test.py +196 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/path_initializer.py +38 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds.py +173 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds_test.py +111 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes.py +61 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes_test.py +50 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds.py +276 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds_test.py +260 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys.py +266 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys_test.py +128 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/table_formatter.py +563 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool.py +188 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool_test.py +88 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils.py +208 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils_test.py +193 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version.py +17 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker.py +246 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker_test.py +271 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds.py +151 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds_test.py +60 -0
- data/packages/gcutil-1.7.1/lib/httplib2/LICENSE +21 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/__init__.py +1630 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/cacerts.txt +714 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/iri2uri.py +110 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/socks.py +438 -0
- data/packages/gcutil-1.7.1/lib/iso8601/LICENSE +20 -0
- data/packages/gcutil-1.7.1/lib/iso8601/iso8601/__init__.py +1 -0
- data/packages/gcutil-1.7.1/lib/iso8601/iso8601/iso8601.py +102 -0
- data/packages/gcutil-1.7.1/lib/iso8601/iso8601/test_iso8601.py +111 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/AUTHORS +2 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/LICENSE +28 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/gflags.py +2862 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/gflags2man.py +544 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/gflags_validators.py +187 -0
- metadata +118 -5
- metadata.gz.sig +0 -0
@@ -0,0 +1,544 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
# Copyright (c) 2006, Google Inc.
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are
|
8
|
+
# met:
|
9
|
+
#
|
10
|
+
# * Redistributions of source code must retain the above copyright
|
11
|
+
# notice, this list of conditions and the following disclaimer.
|
12
|
+
# * Redistributions in binary form must reproduce the above
|
13
|
+
# copyright notice, this list of conditions and the following disclaimer
|
14
|
+
# in the documentation and/or other materials provided with the
|
15
|
+
# distribution.
|
16
|
+
# * Neither the name of Google Inc. nor the names of its
|
17
|
+
# contributors may be used to endorse or promote products derived from
|
18
|
+
# this software without specific prior written permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
21
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
22
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
23
|
+
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
24
|
+
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
25
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
26
|
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
27
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
28
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
29
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
30
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
|
32
|
+
|
33
|
+
"""gflags2man runs a Google flags base program and generates a man page.
|
34
|
+
|
35
|
+
Run the program, parse the output, and then format that into a man
|
36
|
+
page.
|
37
|
+
|
38
|
+
Usage:
|
39
|
+
gflags2man <program> [program] ...
|
40
|
+
"""
|
41
|
+
|
42
|
+
# TODO(user): work with windows paths (\) as well as unix (/)
|
43
|
+
|
44
|
+
# This may seem a bit of an end run, but it: doesn't bloat flags, can
|
45
|
+
# support python/java/C++, supports older executables, and can be
|
46
|
+
# extended to other document formats.
|
47
|
+
# Inspired by help2man.
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
import os
|
52
|
+
import re
|
53
|
+
import sys
|
54
|
+
import stat
|
55
|
+
import time
|
56
|
+
|
57
|
+
import gflags
|
58
|
+
|
59
|
+
_VERSION = '0.1'
|
60
|
+
|
61
|
+
|
62
|
+
def _GetDefaultDestDir():
|
63
|
+
home = os.environ.get('HOME', '')
|
64
|
+
homeman = os.path.join(home, 'man', 'man1')
|
65
|
+
if home and os.path.exists(homeman):
|
66
|
+
return homeman
|
67
|
+
else:
|
68
|
+
return os.environ.get('TMPDIR', '/tmp')
|
69
|
+
|
70
|
+
FLAGS = gflags.FLAGS
|
71
|
+
gflags.DEFINE_string('dest_dir', _GetDefaultDestDir(),
|
72
|
+
'Directory to write resulting manpage to.'
|
73
|
+
' Specify \'-\' for stdout')
|
74
|
+
gflags.DEFINE_string('help_flag', '--help',
|
75
|
+
'Option to pass to target program in to get help')
|
76
|
+
gflags.DEFINE_integer('v', 0, 'verbosity level to use for output')
|
77
|
+
|
78
|
+
|
79
|
+
_MIN_VALID_USAGE_MSG = 9 # if fewer lines than this, help is suspect
|
80
|
+
|
81
|
+
|
82
|
+
class Logging:
|
83
|
+
"""A super-simple logging class"""
|
84
|
+
def error(self, msg): print >>sys.stderr, "ERROR: ", msg
|
85
|
+
def warn(self, msg): print >>sys.stderr, "WARNING: ", msg
|
86
|
+
def info(self, msg): print msg
|
87
|
+
def debug(self, msg): self.vlog(1, msg)
|
88
|
+
def vlog(self, level, msg):
|
89
|
+
if FLAGS.v >= level: print msg
|
90
|
+
logging = Logging()
|
91
|
+
class App:
|
92
|
+
def usage(self, shorthelp=0):
|
93
|
+
print >>sys.stderr, __doc__
|
94
|
+
print >>sys.stderr, "flags:"
|
95
|
+
print >>sys.stderr, str(FLAGS)
|
96
|
+
def run(self):
|
97
|
+
main(sys.argv)
|
98
|
+
app = App()
|
99
|
+
|
100
|
+
|
101
|
+
def GetRealPath(filename):
|
102
|
+
"""Given an executable filename, find in the PATH or find absolute path.
|
103
|
+
Args:
|
104
|
+
filename An executable filename (string)
|
105
|
+
Returns:
|
106
|
+
Absolute version of filename.
|
107
|
+
None if filename could not be found locally, absolutely, or in PATH
|
108
|
+
"""
|
109
|
+
if os.path.isabs(filename): # already absolute
|
110
|
+
return filename
|
111
|
+
|
112
|
+
if filename.startswith('./') or filename.startswith('../'): # relative
|
113
|
+
return os.path.abspath(filename)
|
114
|
+
|
115
|
+
path = os.getenv('PATH', '')
|
116
|
+
for directory in path.split(':'):
|
117
|
+
tryname = os.path.join(directory, filename)
|
118
|
+
if os.path.exists(tryname):
|
119
|
+
if not os.path.isabs(directory): # relative directory
|
120
|
+
return os.path.abspath(tryname)
|
121
|
+
return tryname
|
122
|
+
if os.path.exists(filename):
|
123
|
+
return os.path.abspath(filename)
|
124
|
+
return None # could not determine
|
125
|
+
|
126
|
+
class Flag(object):
|
127
|
+
"""The information about a single flag."""
|
128
|
+
|
129
|
+
def __init__(self, flag_desc, help):
|
130
|
+
"""Create the flag object.
|
131
|
+
Args:
|
132
|
+
flag_desc The command line forms this could take. (string)
|
133
|
+
help The help text (string)
|
134
|
+
"""
|
135
|
+
self.desc = flag_desc # the command line forms
|
136
|
+
self.help = help # the help text
|
137
|
+
self.default = '' # default value
|
138
|
+
self.tips = '' # parsing/syntax tips
|
139
|
+
|
140
|
+
|
141
|
+
class ProgramInfo(object):
|
142
|
+
"""All the information gleaned from running a program with --help."""
|
143
|
+
|
144
|
+
# Match a module block start, for python scripts --help
|
145
|
+
# "goopy.logging:"
|
146
|
+
module_py_re = re.compile(r'(\S.+):$')
|
147
|
+
# match the start of a flag listing
|
148
|
+
# " -v,--verbosity: Logging verbosity"
|
149
|
+
flag_py_re = re.compile(r'\s+(-\S+):\s+(.*)$')
|
150
|
+
# " (default: '0')"
|
151
|
+
flag_default_py_re = re.compile(r'\s+\(default:\s+\'(.*)\'\)$')
|
152
|
+
# " (an integer)"
|
153
|
+
flag_tips_py_re = re.compile(r'\s+\((.*)\)$')
|
154
|
+
|
155
|
+
# Match a module block start, for c++ programs --help
|
156
|
+
# "google/base/commandlineflags":
|
157
|
+
module_c_re = re.compile(r'\s+Flags from (\S.+):$')
|
158
|
+
# match the start of a flag listing
|
159
|
+
# " -v,--verbosity: Logging verbosity"
|
160
|
+
flag_c_re = re.compile(r'\s+(-\S+)\s+(.*)$')
|
161
|
+
|
162
|
+
# Match a module block start, for java programs --help
|
163
|
+
# "com.google.common.flags"
|
164
|
+
module_java_re = re.compile(r'\s+Flags for (\S.+):$')
|
165
|
+
# match the start of a flag listing
|
166
|
+
# " -v,--verbosity: Logging verbosity"
|
167
|
+
flag_java_re = re.compile(r'\s+(-\S+)\s+(.*)$')
|
168
|
+
|
169
|
+
def __init__(self, executable):
|
170
|
+
"""Create object with executable.
|
171
|
+
Args:
|
172
|
+
executable Program to execute (string)
|
173
|
+
"""
|
174
|
+
self.long_name = executable
|
175
|
+
self.name = os.path.basename(executable) # name
|
176
|
+
# Get name without extension (PAR files)
|
177
|
+
(self.short_name, self.ext) = os.path.splitext(self.name)
|
178
|
+
self.executable = GetRealPath(executable) # name of the program
|
179
|
+
self.output = [] # output from the program. List of lines.
|
180
|
+
self.desc = [] # top level description. List of lines
|
181
|
+
self.modules = {} # { section_name(string), [ flags ] }
|
182
|
+
self.module_list = [] # list of module names in their original order
|
183
|
+
self.date = time.localtime(time.time()) # default date info
|
184
|
+
|
185
|
+
def Run(self):
|
186
|
+
"""Run it and collect output.
|
187
|
+
|
188
|
+
Returns:
|
189
|
+
1 (true) If everything went well.
|
190
|
+
0 (false) If there were problems.
|
191
|
+
"""
|
192
|
+
if not self.executable:
|
193
|
+
logging.error('Could not locate "%s"' % self.long_name)
|
194
|
+
return 0
|
195
|
+
|
196
|
+
finfo = os.stat(self.executable)
|
197
|
+
self.date = time.localtime(finfo[stat.ST_MTIME])
|
198
|
+
|
199
|
+
logging.info('Running: %s %s </dev/null 2>&1'
|
200
|
+
% (self.executable, FLAGS.help_flag))
|
201
|
+
# --help output is often routed to stderr, so we combine with stdout.
|
202
|
+
# Re-direct stdin to /dev/null to encourage programs that
|
203
|
+
# don't understand --help to exit.
|
204
|
+
(child_stdin, child_stdout_and_stderr) = os.popen4(
|
205
|
+
[self.executable, FLAGS.help_flag])
|
206
|
+
child_stdin.close() # '</dev/null'
|
207
|
+
self.output = child_stdout_and_stderr.readlines()
|
208
|
+
child_stdout_and_stderr.close()
|
209
|
+
if len(self.output) < _MIN_VALID_USAGE_MSG:
|
210
|
+
logging.error('Error: "%s %s" returned only %d lines: %s'
|
211
|
+
% (self.name, FLAGS.help_flag,
|
212
|
+
len(self.output), self.output))
|
213
|
+
return 0
|
214
|
+
return 1
|
215
|
+
|
216
|
+
def Parse(self):
|
217
|
+
"""Parse program output."""
|
218
|
+
(start_line, lang) = self.ParseDesc()
|
219
|
+
if start_line < 0:
|
220
|
+
return
|
221
|
+
if 'python' == lang:
|
222
|
+
self.ParsePythonFlags(start_line)
|
223
|
+
elif 'c' == lang:
|
224
|
+
self.ParseCFlags(start_line)
|
225
|
+
elif 'java' == lang:
|
226
|
+
self.ParseJavaFlags(start_line)
|
227
|
+
|
228
|
+
def ParseDesc(self, start_line=0):
|
229
|
+
"""Parse the initial description.
|
230
|
+
|
231
|
+
This could be Python or C++.
|
232
|
+
|
233
|
+
Returns:
|
234
|
+
(start_line, lang_type)
|
235
|
+
start_line Line to start parsing flags on (int)
|
236
|
+
lang_type Either 'python' or 'c'
|
237
|
+
(-1, '') if the flags start could not be found
|
238
|
+
"""
|
239
|
+
exec_mod_start = self.executable + ':'
|
240
|
+
|
241
|
+
after_blank = 0
|
242
|
+
start_line = 0 # ignore the passed-in arg for now (?)
|
243
|
+
for start_line in range(start_line, len(self.output)): # collect top description
|
244
|
+
line = self.output[start_line].rstrip()
|
245
|
+
# Python flags start with 'flags:\n'
|
246
|
+
if ('flags:' == line
|
247
|
+
and len(self.output) > start_line+1
|
248
|
+
and '' == self.output[start_line+1].rstrip()):
|
249
|
+
start_line += 2
|
250
|
+
logging.debug('Flags start (python): %s' % line)
|
251
|
+
return (start_line, 'python')
|
252
|
+
# SWIG flags just have the module name followed by colon.
|
253
|
+
if exec_mod_start == line:
|
254
|
+
logging.debug('Flags start (swig): %s' % line)
|
255
|
+
return (start_line, 'python')
|
256
|
+
# C++ flags begin after a blank line and with a constant string
|
257
|
+
if after_blank and line.startswith(' Flags from '):
|
258
|
+
logging.debug('Flags start (c): %s' % line)
|
259
|
+
return (start_line, 'c')
|
260
|
+
# java flags begin with a constant string
|
261
|
+
if line == 'where flags are':
|
262
|
+
logging.debug('Flags start (java): %s' % line)
|
263
|
+
start_line += 2 # skip "Standard flags:"
|
264
|
+
return (start_line, 'java')
|
265
|
+
|
266
|
+
logging.debug('Desc: %s' % line)
|
267
|
+
self.desc.append(line)
|
268
|
+
after_blank = (line == '')
|
269
|
+
else:
|
270
|
+
logging.warn('Never found the start of the flags section for "%s"!'
|
271
|
+
% self.long_name)
|
272
|
+
return (-1, '')
|
273
|
+
|
274
|
+
def ParsePythonFlags(self, start_line=0):
|
275
|
+
"""Parse python/swig style flags."""
|
276
|
+
modname = None # name of current module
|
277
|
+
modlist = []
|
278
|
+
flag = None
|
279
|
+
for line_num in range(start_line, len(self.output)): # collect flags
|
280
|
+
line = self.output[line_num].rstrip()
|
281
|
+
if not line: # blank
|
282
|
+
continue
|
283
|
+
|
284
|
+
mobj = self.module_py_re.match(line)
|
285
|
+
if mobj: # start of a new module
|
286
|
+
modname = mobj.group(1)
|
287
|
+
logging.debug('Module: %s' % line)
|
288
|
+
if flag:
|
289
|
+
modlist.append(flag)
|
290
|
+
self.module_list.append(modname)
|
291
|
+
self.modules.setdefault(modname, [])
|
292
|
+
modlist = self.modules[modname]
|
293
|
+
flag = None
|
294
|
+
continue
|
295
|
+
|
296
|
+
mobj = self.flag_py_re.match(line)
|
297
|
+
if mobj: # start of a new flag
|
298
|
+
if flag:
|
299
|
+
modlist.append(flag)
|
300
|
+
logging.debug('Flag: %s' % line)
|
301
|
+
flag = Flag(mobj.group(1), mobj.group(2))
|
302
|
+
continue
|
303
|
+
|
304
|
+
if not flag: # continuation of a flag
|
305
|
+
logging.error('Flag info, but no current flag "%s"' % line)
|
306
|
+
mobj = self.flag_default_py_re.match(line)
|
307
|
+
if mobj: # (default: '...')
|
308
|
+
flag.default = mobj.group(1)
|
309
|
+
logging.debug('Fdef: %s' % line)
|
310
|
+
continue
|
311
|
+
mobj = self.flag_tips_py_re.match(line)
|
312
|
+
if mobj: # (tips)
|
313
|
+
flag.tips = mobj.group(1)
|
314
|
+
logging.debug('Ftip: %s' % line)
|
315
|
+
continue
|
316
|
+
if flag and flag.help:
|
317
|
+
flag.help += line # multiflags tack on an extra line
|
318
|
+
else:
|
319
|
+
logging.info('Extra: %s' % line)
|
320
|
+
if flag:
|
321
|
+
modlist.append(flag)
|
322
|
+
|
323
|
+
def ParseCFlags(self, start_line=0):
|
324
|
+
"""Parse C style flags."""
|
325
|
+
modname = None # name of current module
|
326
|
+
modlist = []
|
327
|
+
flag = None
|
328
|
+
for line_num in range(start_line, len(self.output)): # collect flags
|
329
|
+
line = self.output[line_num].rstrip()
|
330
|
+
if not line: # blank lines terminate flags
|
331
|
+
if flag: # save last flag
|
332
|
+
modlist.append(flag)
|
333
|
+
flag = None
|
334
|
+
continue
|
335
|
+
|
336
|
+
mobj = self.module_c_re.match(line)
|
337
|
+
if mobj: # start of a new module
|
338
|
+
modname = mobj.group(1)
|
339
|
+
logging.debug('Module: %s' % line)
|
340
|
+
if flag:
|
341
|
+
modlist.append(flag)
|
342
|
+
self.module_list.append(modname)
|
343
|
+
self.modules.setdefault(modname, [])
|
344
|
+
modlist = self.modules[modname]
|
345
|
+
flag = None
|
346
|
+
continue
|
347
|
+
|
348
|
+
mobj = self.flag_c_re.match(line)
|
349
|
+
if mobj: # start of a new flag
|
350
|
+
if flag: # save last flag
|
351
|
+
modlist.append(flag)
|
352
|
+
logging.debug('Flag: %s' % line)
|
353
|
+
flag = Flag(mobj.group(1), mobj.group(2))
|
354
|
+
continue
|
355
|
+
|
356
|
+
# append to flag help. type and default are part of the main text
|
357
|
+
if flag:
|
358
|
+
flag.help += ' ' + line.strip()
|
359
|
+
else:
|
360
|
+
logging.info('Extra: %s' % line)
|
361
|
+
if flag:
|
362
|
+
modlist.append(flag)
|
363
|
+
|
364
|
+
def ParseJavaFlags(self, start_line=0):
|
365
|
+
"""Parse Java style flags (com.google.common.flags)."""
|
366
|
+
# The java flags prints starts with a "Standard flags" "module"
|
367
|
+
# that doesn't follow the standard module syntax.
|
368
|
+
modname = 'Standard flags' # name of current module
|
369
|
+
self.module_list.append(modname)
|
370
|
+
self.modules.setdefault(modname, [])
|
371
|
+
modlist = self.modules[modname]
|
372
|
+
flag = None
|
373
|
+
|
374
|
+
for line_num in range(start_line, len(self.output)): # collect flags
|
375
|
+
line = self.output[line_num].rstrip()
|
376
|
+
logging.vlog(2, 'Line: "%s"' % line)
|
377
|
+
if not line: # blank lines terminate module
|
378
|
+
if flag: # save last flag
|
379
|
+
modlist.append(flag)
|
380
|
+
flag = None
|
381
|
+
continue
|
382
|
+
|
383
|
+
mobj = self.module_java_re.match(line)
|
384
|
+
if mobj: # start of a new module
|
385
|
+
modname = mobj.group(1)
|
386
|
+
logging.debug('Module: %s' % line)
|
387
|
+
if flag:
|
388
|
+
modlist.append(flag)
|
389
|
+
self.module_list.append(modname)
|
390
|
+
self.modules.setdefault(modname, [])
|
391
|
+
modlist = self.modules[modname]
|
392
|
+
flag = None
|
393
|
+
continue
|
394
|
+
|
395
|
+
mobj = self.flag_java_re.match(line)
|
396
|
+
if mobj: # start of a new flag
|
397
|
+
if flag: # save last flag
|
398
|
+
modlist.append(flag)
|
399
|
+
logging.debug('Flag: %s' % line)
|
400
|
+
flag = Flag(mobj.group(1), mobj.group(2))
|
401
|
+
continue
|
402
|
+
|
403
|
+
# append to flag help. type and default are part of the main text
|
404
|
+
if flag:
|
405
|
+
flag.help += ' ' + line.strip()
|
406
|
+
else:
|
407
|
+
logging.info('Extra: %s' % line)
|
408
|
+
if flag:
|
409
|
+
modlist.append(flag)
|
410
|
+
|
411
|
+
def Filter(self):
|
412
|
+
"""Filter parsed data to create derived fields."""
|
413
|
+
if not self.desc:
|
414
|
+
self.short_desc = ''
|
415
|
+
return
|
416
|
+
|
417
|
+
for i in range(len(self.desc)): # replace full path with name
|
418
|
+
if self.desc[i].find(self.executable) >= 0:
|
419
|
+
self.desc[i] = self.desc[i].replace(self.executable, self.name)
|
420
|
+
|
421
|
+
self.short_desc = self.desc[0]
|
422
|
+
word_list = self.short_desc.split(' ')
|
423
|
+
all_names = [ self.name, self.short_name, ]
|
424
|
+
# Since the short_desc is always listed right after the name,
|
425
|
+
# trim it from the short_desc
|
426
|
+
while word_list and (word_list[0] in all_names
|
427
|
+
or word_list[0].lower() in all_names):
|
428
|
+
del word_list[0]
|
429
|
+
self.short_desc = '' # signal need to reconstruct
|
430
|
+
if not self.short_desc and word_list:
|
431
|
+
self.short_desc = ' '.join(word_list)
|
432
|
+
|
433
|
+
|
434
|
+
class GenerateDoc(object):
|
435
|
+
"""Base class to output flags information."""
|
436
|
+
|
437
|
+
def __init__(self, proginfo, directory='.'):
|
438
|
+
"""Create base object.
|
439
|
+
Args:
|
440
|
+
proginfo A ProgramInfo object
|
441
|
+
directory Directory to write output into
|
442
|
+
"""
|
443
|
+
self.info = proginfo
|
444
|
+
self.dirname = directory
|
445
|
+
|
446
|
+
def Output(self):
|
447
|
+
"""Output all sections of the page."""
|
448
|
+
self.Open()
|
449
|
+
self.Header()
|
450
|
+
self.Body()
|
451
|
+
self.Footer()
|
452
|
+
|
453
|
+
def Open(self): raise NotImplementedError # define in subclass
|
454
|
+
def Header(self): raise NotImplementedError # define in subclass
|
455
|
+
def Body(self): raise NotImplementedError # define in subclass
|
456
|
+
def Footer(self): raise NotImplementedError # define in subclass
|
457
|
+
|
458
|
+
|
459
|
+
class GenerateMan(GenerateDoc):
|
460
|
+
"""Output a man page."""
|
461
|
+
|
462
|
+
def __init__(self, proginfo, directory='.'):
|
463
|
+
"""Create base object.
|
464
|
+
Args:
|
465
|
+
proginfo A ProgramInfo object
|
466
|
+
directory Directory to write output into
|
467
|
+
"""
|
468
|
+
GenerateDoc.__init__(self, proginfo, directory)
|
469
|
+
|
470
|
+
def Open(self):
|
471
|
+
if self.dirname == '-':
|
472
|
+
logging.info('Writing to stdout')
|
473
|
+
self.fp = sys.stdout
|
474
|
+
else:
|
475
|
+
self.file_path = '%s.1' % os.path.join(self.dirname, self.info.name)
|
476
|
+
logging.info('Writing: %s' % self.file_path)
|
477
|
+
self.fp = open(self.file_path, 'w')
|
478
|
+
|
479
|
+
def Header(self):
|
480
|
+
self.fp.write(
|
481
|
+
'.\\" DO NOT MODIFY THIS FILE! It was generated by gflags2man %s\n'
|
482
|
+
% _VERSION)
|
483
|
+
self.fp.write(
|
484
|
+
'.TH %s "1" "%s" "%s" "User Commands"\n'
|
485
|
+
% (self.info.name, time.strftime('%x', self.info.date), self.info.name))
|
486
|
+
self.fp.write(
|
487
|
+
'.SH NAME\n%s \\- %s\n' % (self.info.name, self.info.short_desc))
|
488
|
+
self.fp.write(
|
489
|
+
'.SH SYNOPSIS\n.B %s\n[\\fIFLAGS\\fR]...\n' % self.info.name)
|
490
|
+
|
491
|
+
def Body(self):
|
492
|
+
self.fp.write(
|
493
|
+
'.SH DESCRIPTION\n.\\" Add any additional description here\n.PP\n')
|
494
|
+
for ln in self.info.desc:
|
495
|
+
self.fp.write('%s\n' % ln)
|
496
|
+
self.fp.write(
|
497
|
+
'.SH OPTIONS\n')
|
498
|
+
# This shows flags in the original order
|
499
|
+
for modname in self.info.module_list:
|
500
|
+
if modname.find(self.info.executable) >= 0:
|
501
|
+
mod = modname.replace(self.info.executable, self.info.name)
|
502
|
+
else:
|
503
|
+
mod = modname
|
504
|
+
self.fp.write('\n.P\n.I %s\n' % mod)
|
505
|
+
for flag in self.info.modules[modname]:
|
506
|
+
help_string = flag.help
|
507
|
+
if flag.default or flag.tips:
|
508
|
+
help_string += '\n.br\n'
|
509
|
+
if flag.default:
|
510
|
+
help_string += ' (default: \'%s\')' % flag.default
|
511
|
+
if flag.tips:
|
512
|
+
help_string += ' (%s)' % flag.tips
|
513
|
+
self.fp.write(
|
514
|
+
'.TP\n%s\n%s\n' % (flag.desc, help_string))
|
515
|
+
|
516
|
+
def Footer(self):
|
517
|
+
self.fp.write(
|
518
|
+
'.SH COPYRIGHT\nCopyright \(co %s Google.\n'
|
519
|
+
% time.strftime('%Y', self.info.date))
|
520
|
+
self.fp.write('Gflags2man created this page from "%s %s" output.\n'
|
521
|
+
% (self.info.name, FLAGS.help_flag))
|
522
|
+
self.fp.write('\nGflags2man was written by Dan Christian. '
|
523
|
+
' Note that the date on this'
|
524
|
+
' page is the modification date of %s.\n' % self.info.name)
|
525
|
+
|
526
|
+
|
527
|
+
def main(argv):
|
528
|
+
argv = FLAGS(argv) # handles help as well
|
529
|
+
if len(argv) <= 1:
|
530
|
+
app.usage(shorthelp=1)
|
531
|
+
return 1
|
532
|
+
|
533
|
+
for arg in argv[1:]:
|
534
|
+
prog = ProgramInfo(arg)
|
535
|
+
if not prog.Run():
|
536
|
+
continue
|
537
|
+
prog.Parse()
|
538
|
+
prog.Filter()
|
539
|
+
doc = GenerateMan(prog, FLAGS.dest_dir)
|
540
|
+
doc.Output()
|
541
|
+
return 0
|
542
|
+
|
543
|
+
if __name__ == '__main__':
|
544
|
+
app.run()
|