Statistics
| Branch: | Tag: | Revision:

root / autotools / build-bash-completion @ 8adfb141

History | View | Annotate | Download (17.4 kB)

1 4f3d5b76 Michael Hanselmann
#!/usr/bin/python
2 4f3d5b76 Michael Hanselmann
#
3 4f3d5b76 Michael Hanselmann
4 4f3d5b76 Michael Hanselmann
# Copyright (C) 2009 Google Inc.
5 4f3d5b76 Michael Hanselmann
#
6 4f3d5b76 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 4f3d5b76 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 4f3d5b76 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 4f3d5b76 Michael Hanselmann
# (at your option) any later version.
10 4f3d5b76 Michael Hanselmann
#
11 4f3d5b76 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 4f3d5b76 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 4f3d5b76 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 4f3d5b76 Michael Hanselmann
# General Public License for more details.
15 4f3d5b76 Michael Hanselmann
#
16 4f3d5b76 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 4f3d5b76 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 4f3d5b76 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 4f3d5b76 Michael Hanselmann
# 02110-1301, USA.
20 4f3d5b76 Michael Hanselmann
21 4f3d5b76 Michael Hanselmann
22 4f3d5b76 Michael Hanselmann
import optparse
23 4f3d5b76 Michael Hanselmann
import os
24 4f3d5b76 Michael Hanselmann
import sys
25 4f3d5b76 Michael Hanselmann
import re
26 4f3d5b76 Michael Hanselmann
from cStringIO import StringIO
27 4f3d5b76 Michael Hanselmann
28 4f3d5b76 Michael Hanselmann
from ganeti import constants
29 4f3d5b76 Michael Hanselmann
from ganeti import cli
30 4f3d5b76 Michael Hanselmann
from ganeti import utils
31 e948770c Michael Hanselmann
from ganeti import build
32 4f3d5b76 Michael Hanselmann
33 4f3d5b76 Michael Hanselmann
# _autoconf shouldn't be imported from anywhere except constants.py, but we're
34 4f3d5b76 Michael Hanselmann
# making an exception here because this script is only used at build time.
35 4f3d5b76 Michael Hanselmann
from ganeti import _autoconf
36 4f3d5b76 Michael Hanselmann
37 4f3d5b76 Michael Hanselmann
38 4f3d5b76 Michael Hanselmann
class ShellWriter:
39 4f3d5b76 Michael Hanselmann
  """Helper class to write scripts with indentation.
40 4f3d5b76 Michael Hanselmann
41 4f3d5b76 Michael Hanselmann
  """
42 4f3d5b76 Michael Hanselmann
  INDENT_STR = "  "
43 4f3d5b76 Michael Hanselmann
44 4f3d5b76 Michael Hanselmann
  def __init__(self, fh):
45 4f3d5b76 Michael Hanselmann
    self._fh = fh
46 4f3d5b76 Michael Hanselmann
    self._indent = 0
47 4f3d5b76 Michael Hanselmann
48 4f3d5b76 Michael Hanselmann
  def IncIndent(self):
49 4f3d5b76 Michael Hanselmann
    """Increase indentation level by 1.
50 4f3d5b76 Michael Hanselmann
51 4f3d5b76 Michael Hanselmann
    """
52 4f3d5b76 Michael Hanselmann
    self._indent += 1
53 4f3d5b76 Michael Hanselmann
54 4f3d5b76 Michael Hanselmann
  def DecIndent(self):
55 4f3d5b76 Michael Hanselmann
    """Decrease indentation level by 1.
56 4f3d5b76 Michael Hanselmann
57 4f3d5b76 Michael Hanselmann
    """
58 4f3d5b76 Michael Hanselmann
    assert self._indent > 0
59 4f3d5b76 Michael Hanselmann
    self._indent -= 1
60 4f3d5b76 Michael Hanselmann
61 4f3d5b76 Michael Hanselmann
  def Write(self, txt, *args):
62 4f3d5b76 Michael Hanselmann
    """Write line to output file.
63 4f3d5b76 Michael Hanselmann
64 4f3d5b76 Michael Hanselmann
    """
65 4f3d5b76 Michael Hanselmann
    self._fh.write(self._indent * self.INDENT_STR)
66 4f3d5b76 Michael Hanselmann
67 4f3d5b76 Michael Hanselmann
    if args:
68 4f3d5b76 Michael Hanselmann
      self._fh.write(txt % args)
69 4f3d5b76 Michael Hanselmann
    else:
70 4f3d5b76 Michael Hanselmann
      self._fh.write(txt)
71 4f3d5b76 Michael Hanselmann
72 4f3d5b76 Michael Hanselmann
    self._fh.write("\n")
73 4f3d5b76 Michael Hanselmann
74 4f3d5b76 Michael Hanselmann
75 4f3d5b76 Michael Hanselmann
def WritePreamble(sw):
76 4f3d5b76 Michael Hanselmann
  """Writes the script preamble.
77 4f3d5b76 Michael Hanselmann
78 4f3d5b76 Michael Hanselmann
  Helper functions should be written here.
79 4f3d5b76 Michael Hanselmann
80 4f3d5b76 Michael Hanselmann
  """
81 4f3d5b76 Michael Hanselmann
  sw.Write("# This script is automatically generated at build time.")
82 4f3d5b76 Michael Hanselmann
  sw.Write("# Do not modify manually.")
83 4f3d5b76 Michael Hanselmann
84 5b0ca9d4 Michael Hanselmann
  sw.Write("_ganeti_dbglog() {")
85 5b0ca9d4 Michael Hanselmann
  sw.IncIndent()
86 5b0ca9d4 Michael Hanselmann
  try:
87 5b0ca9d4 Michael Hanselmann
    sw.Write("if [[ -n \"$GANETI_COMPL_LOG\" ]]; then")
88 5b0ca9d4 Michael Hanselmann
    sw.IncIndent()
89 5b0ca9d4 Michael Hanselmann
    try:
90 5b0ca9d4 Michael Hanselmann
      sw.Write("{")
91 5b0ca9d4 Michael Hanselmann
      sw.IncIndent()
92 5b0ca9d4 Michael Hanselmann
      try:
93 5b0ca9d4 Michael Hanselmann
        sw.Write("echo ---")
94 5b0ca9d4 Michael Hanselmann
        sw.Write("echo \"$@\"")
95 5b0ca9d4 Michael Hanselmann
        sw.Write("echo")
96 5b0ca9d4 Michael Hanselmann
      finally:
97 5b0ca9d4 Michael Hanselmann
        sw.DecIndent()
98 5b0ca9d4 Michael Hanselmann
      sw.Write("} >> $GANETI_COMPL_LOG")
99 5b0ca9d4 Michael Hanselmann
    finally:
100 5b0ca9d4 Michael Hanselmann
      sw.DecIndent()
101 5b0ca9d4 Michael Hanselmann
    sw.Write("fi")
102 5b0ca9d4 Michael Hanselmann
  finally:
103 5b0ca9d4 Michael Hanselmann
    sw.DecIndent()
104 5b0ca9d4 Michael Hanselmann
  sw.Write("}")
105 5b0ca9d4 Michael Hanselmann
106 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_nodes() {")
107 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
108 4f3d5b76 Michael Hanselmann
  try:
109 4f3d5b76 Michael Hanselmann
    node_list_path = os.path.join(constants.DATA_DIR, "ssconf_node_list")
110 5a78e2e7 Michael Hanselmann
    sw.Write("cat %s 2>/dev/null || :", utils.ShellQuote(node_list_path))
111 4f3d5b76 Michael Hanselmann
  finally:
112 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
113 4f3d5b76 Michael Hanselmann
  sw.Write("}")
114 4f3d5b76 Michael Hanselmann
115 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_instances() {")
116 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
117 4f3d5b76 Michael Hanselmann
  try:
118 4f3d5b76 Michael Hanselmann
    instance_list_path = os.path.join(constants.DATA_DIR,
119 4f3d5b76 Michael Hanselmann
                                      "ssconf_instance_list")
120 5a78e2e7 Michael Hanselmann
    sw.Write("cat %s 2>/dev/null || :", utils.ShellQuote(instance_list_path))
121 4f3d5b76 Michael Hanselmann
  finally:
122 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
123 4f3d5b76 Michael Hanselmann
  sw.Write("}")
124 4f3d5b76 Michael Hanselmann
125 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_jobs() {")
126 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
127 4f3d5b76 Michael Hanselmann
  try:
128 4f3d5b76 Michael Hanselmann
    # FIXME: this is really going into the internals of the job queue
129 5a78e2e7 Michael Hanselmann
    sw.Write(("local jlist=$( shopt -s nullglob &&"
130 5a78e2e7 Michael Hanselmann
              " cd %s 2>/dev/null && echo job-* || : )"),
131 4f3d5b76 Michael Hanselmann
             utils.ShellQuote(constants.QUEUE_DIR))
132 5a78e2e7 Michael Hanselmann
    sw.Write('echo "${jlist//job-/}"')
133 4f3d5b76 Michael Hanselmann
  finally:
134 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
135 4f3d5b76 Michael Hanselmann
  sw.Write("}")
136 4f3d5b76 Michael Hanselmann
137 30d44392 Michael Hanselmann
  for (fnname, paths) in [
138 30d44392 Michael Hanselmann
      ("os", constants.OS_SEARCH_PATH),
139 30d44392 Michael Hanselmann
      ("iallocator", constants.IALLOCATOR_SEARCH_PATH),
140 30d44392 Michael Hanselmann
      ]:
141 30d44392 Michael Hanselmann
    sw.Write("_ganeti_%s() {", fnname)
142 30d44392 Michael Hanselmann
    sw.IncIndent()
143 30d44392 Michael Hanselmann
    try:
144 30d44392 Michael Hanselmann
      # FIXME: Make querying the master for all OSes cheap
145 30d44392 Michael Hanselmann
      for path in paths:
146 30d44392 Michael Hanselmann
        sw.Write("( shopt -s nullglob && cd %s 2>/dev/null && echo * || : )",
147 30d44392 Michael Hanselmann
                 utils.ShellQuote(path))
148 30d44392 Michael Hanselmann
    finally:
149 30d44392 Michael Hanselmann
      sw.DecIndent()
150 30d44392 Michael Hanselmann
    sw.Write("}")
151 4f3d5b76 Michael Hanselmann
152 4f3d5b76 Michael Hanselmann
  # Params: <offset> <options with values> <options without values>
153 4f3d5b76 Michael Hanselmann
  # Result variable: $first_arg_idx
154 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_find_first_arg() {")
155 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
156 4f3d5b76 Michael Hanselmann
  try:
157 4f3d5b76 Michael Hanselmann
    sw.Write("local w i")
158 4f3d5b76 Michael Hanselmann
159 4f3d5b76 Michael Hanselmann
    sw.Write("first_arg_idx=")
160 4f3d5b76 Michael Hanselmann
    sw.Write("for (( i=$1; i < COMP_CWORD; ++i )); do")
161 4f3d5b76 Michael Hanselmann
    sw.IncIndent()
162 4f3d5b76 Michael Hanselmann
    try:
163 4f3d5b76 Michael Hanselmann
      sw.Write("w=${COMP_WORDS[$i]}")
164 4f3d5b76 Michael Hanselmann
165 4f3d5b76 Michael Hanselmann
      # Skip option value
166 4f3d5b76 Michael Hanselmann
      sw.Write("""if [[ -n "$2" && "$w" == @($2) ]]; then let ++i""")
167 4f3d5b76 Michael Hanselmann
168 4f3d5b76 Michael Hanselmann
      # Skip
169 4f3d5b76 Michael Hanselmann
      sw.Write("""elif [[ -n "$3" && "$w" == @($3) ]]; then :""")
170 4f3d5b76 Michael Hanselmann
171 4f3d5b76 Michael Hanselmann
      # Ah, we found the first argument
172 4f3d5b76 Michael Hanselmann
      sw.Write("else first_arg_idx=$i; break;")
173 4f3d5b76 Michael Hanselmann
      sw.Write("fi")
174 4f3d5b76 Michael Hanselmann
    finally:
175 4f3d5b76 Michael Hanselmann
      sw.DecIndent()
176 4f3d5b76 Michael Hanselmann
    sw.Write("done")
177 4f3d5b76 Michael Hanselmann
  finally:
178 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
179 4f3d5b76 Michael Hanselmann
  sw.Write("}")
180 4f3d5b76 Michael Hanselmann
181 4f3d5b76 Michael Hanselmann
  # Params: <list of options separated by space>
182 4f3d5b76 Michael Hanselmann
  # Input variable: $first_arg_idx
183 4f3d5b76 Michael Hanselmann
  # Result variables: $arg_idx, $choices
184 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_list_options() {")
185 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
186 4f3d5b76 Michael Hanselmann
  try:
187 4f3d5b76 Michael Hanselmann
    sw.Write("""if [[ -z "$first_arg_idx" ]]; then""")
188 4f3d5b76 Michael Hanselmann
    sw.IncIndent()
189 4f3d5b76 Michael Hanselmann
    try:
190 4f3d5b76 Michael Hanselmann
      sw.Write("arg_idx=0")
191 4f3d5b76 Michael Hanselmann
      # Show options only if the current word starts with a dash
192 4f3d5b76 Michael Hanselmann
      sw.Write("""if [[ "$cur" == -* ]]; then""")
193 4f3d5b76 Michael Hanselmann
      sw.IncIndent()
194 4f3d5b76 Michael Hanselmann
      try:
195 4f3d5b76 Michael Hanselmann
        sw.Write("choices=$1")
196 4f3d5b76 Michael Hanselmann
      finally:
197 4f3d5b76 Michael Hanselmann
        sw.DecIndent()
198 4f3d5b76 Michael Hanselmann
      sw.Write("fi")
199 4f3d5b76 Michael Hanselmann
      sw.Write("return")
200 4f3d5b76 Michael Hanselmann
    finally:
201 4f3d5b76 Michael Hanselmann
      sw.DecIndent()
202 4f3d5b76 Michael Hanselmann
    sw.Write("fi")
203 4f3d5b76 Michael Hanselmann
204 4f3d5b76 Michael Hanselmann
    # Calculate position of current argument
205 4f3d5b76 Michael Hanselmann
    sw.Write("arg_idx=$(( COMP_CWORD - first_arg_idx ))")
206 4f3d5b76 Michael Hanselmann
    sw.Write("choices=")
207 4f3d5b76 Michael Hanselmann
  finally:
208 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
209 4f3d5b76 Michael Hanselmann
  sw.Write("}")
210 4f3d5b76 Michael Hanselmann
211 d4b94fe8 Michael Hanselmann
  # Params: <long options with equal sign> <all options>
212 d4b94fe8 Michael Hanselmann
  # Result variable: $optcur
213 d4b94fe8 Michael Hanselmann
  sw.Write("_ganeti_checkopt() {")
214 d4b94fe8 Michael Hanselmann
  sw.IncIndent()
215 d4b94fe8 Michael Hanselmann
  try:
216 d4b94fe8 Michael Hanselmann
    sw.Write("""if [[ -n "$1" && "$cur" == @($1) ]]; then""")
217 d4b94fe8 Michael Hanselmann
    sw.IncIndent()
218 d4b94fe8 Michael Hanselmann
    try:
219 d4b94fe8 Michael Hanselmann
      sw.Write("optcur=\"${cur#--*=}\"")
220 d4b94fe8 Michael Hanselmann
      sw.Write("return 0")
221 d4b94fe8 Michael Hanselmann
    finally:
222 d4b94fe8 Michael Hanselmann
      sw.DecIndent()
223 d4b94fe8 Michael Hanselmann
    sw.Write("""elif [[ -n "$2" && "$prev" == @($2) ]]; then""")
224 d4b94fe8 Michael Hanselmann
    sw.IncIndent()
225 d4b94fe8 Michael Hanselmann
    try:
226 d4b94fe8 Michael Hanselmann
      sw.Write("optcur=\"$cur\"")
227 d4b94fe8 Michael Hanselmann
      sw.Write("return 0")
228 d4b94fe8 Michael Hanselmann
    finally:
229 d4b94fe8 Michael Hanselmann
      sw.DecIndent()
230 d4b94fe8 Michael Hanselmann
    sw.Write("fi")
231 d4b94fe8 Michael Hanselmann
232 5b0ca9d4 Michael Hanselmann
    sw.Write("_ganeti_dbglog optcur=\"'$optcur'\"")
233 5b0ca9d4 Michael Hanselmann
234 d4b94fe8 Michael Hanselmann
    sw.Write("return 1")
235 d4b94fe8 Michael Hanselmann
  finally:
236 d4b94fe8 Michael Hanselmann
    sw.DecIndent()
237 d4b94fe8 Michael Hanselmann
  sw.Write("}")
238 d4b94fe8 Michael Hanselmann
239 a10caf87 Michael Hanselmann
  # Params: <compgen options>
240 a10caf87 Michael Hanselmann
  # Result variable: $COMPREPLY
241 a10caf87 Michael Hanselmann
  sw.Write("_ganeti_compgen() {")
242 a10caf87 Michael Hanselmann
  sw.IncIndent()
243 a10caf87 Michael Hanselmann
  try:
244 a10caf87 Michael Hanselmann
    sw.Write("""COMPREPLY=( $(compgen "$@") )""")
245 a10caf87 Michael Hanselmann
    sw.Write("_ganeti_dbglog COMPREPLY=\"${COMPREPLY[@]}\"")
246 a10caf87 Michael Hanselmann
  finally:
247 a10caf87 Michael Hanselmann
    sw.DecIndent()
248 a10caf87 Michael Hanselmann
  sw.Write("}")
249 a10caf87 Michael Hanselmann
250 4f3d5b76 Michael Hanselmann
251 632d5090 Michael Hanselmann
def WriteCompReply(sw, args, cur="\"$cur\""):
252 a10caf87 Michael Hanselmann
  sw.Write("_ganeti_compgen %s -- %s", args, cur)
253 4f3d5b76 Michael Hanselmann
  sw.Write("return")
254 4f3d5b76 Michael Hanselmann
255 4f3d5b76 Michael Hanselmann
256 4f3d5b76 Michael Hanselmann
class CompletionWriter:
257 4f3d5b76 Michael Hanselmann
  """Command completion writer class.
258 4f3d5b76 Michael Hanselmann
259 4f3d5b76 Michael Hanselmann
  """
260 4f3d5b76 Michael Hanselmann
  def __init__(self, arg_offset, opts, args):
261 4f3d5b76 Michael Hanselmann
    self.arg_offset = arg_offset
262 4f3d5b76 Michael Hanselmann
    self.opts = opts
263 4f3d5b76 Michael Hanselmann
    self.args = args
264 4f3d5b76 Michael Hanselmann
265 4f3d5b76 Michael Hanselmann
    for opt in opts:
266 4f3d5b76 Michael Hanselmann
      opt.all_names = sorted(opt._short_opts + opt._long_opts)
267 4f3d5b76 Michael Hanselmann
268 4f3d5b76 Michael Hanselmann
  def _FindFirstArgument(self, sw):
269 4f3d5b76 Michael Hanselmann
    ignore = []
270 4f3d5b76 Michael Hanselmann
    skip_one = []
271 4f3d5b76 Michael Hanselmann
272 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
273 4f3d5b76 Michael Hanselmann
      if opt.takes_value():
274 4f3d5b76 Michael Hanselmann
        # Ignore value
275 4f3d5b76 Michael Hanselmann
        for i in opt.all_names:
276 580ef58d Michael Hanselmann
          if i.startswith("--"):
277 580ef58d Michael Hanselmann
            ignore.append("%s=*" % utils.ShellQuote(i))
278 4f3d5b76 Michael Hanselmann
          skip_one.append(utils.ShellQuote(i))
279 4f3d5b76 Michael Hanselmann
      else:
280 4f3d5b76 Michael Hanselmann
        ignore.extend([utils.ShellQuote(i) for i in opt.all_names])
281 4f3d5b76 Michael Hanselmann
282 4f3d5b76 Michael Hanselmann
    ignore = sorted(utils.UniqueSequence(ignore))
283 4f3d5b76 Michael Hanselmann
    skip_one = sorted(utils.UniqueSequence(skip_one))
284 4f3d5b76 Michael Hanselmann
285 4f3d5b76 Michael Hanselmann
    if ignore or skip_one:
286 4f3d5b76 Michael Hanselmann
      # Try to locate first argument
287 4f3d5b76 Michael Hanselmann
      sw.Write("_ganeti_find_first_arg %s %s %s",
288 4f3d5b76 Michael Hanselmann
               self.arg_offset + 1,
289 4f3d5b76 Michael Hanselmann
               utils.ShellQuote("|".join(skip_one)),
290 4f3d5b76 Michael Hanselmann
               utils.ShellQuote("|".join(ignore)))
291 4f3d5b76 Michael Hanselmann
    else:
292 4f3d5b76 Michael Hanselmann
      # When there are no options the first argument is always at position
293 4f3d5b76 Michael Hanselmann
      # offset + 1
294 4f3d5b76 Michael Hanselmann
      sw.Write("first_arg_idx=%s", self.arg_offset + 1)
295 4f3d5b76 Michael Hanselmann
296 4f3d5b76 Michael Hanselmann
  def _CompleteOptionValues(self, sw):
297 4f3d5b76 Michael Hanselmann
    # Group by values
298 4f3d5b76 Michael Hanselmann
    # "values" -> [optname1, optname2, ...]
299 4f3d5b76 Michael Hanselmann
    values = {}
300 4f3d5b76 Michael Hanselmann
301 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
302 4f3d5b76 Michael Hanselmann
      if not opt.takes_value():
303 4f3d5b76 Michael Hanselmann
        continue
304 4f3d5b76 Michael Hanselmann
305 4f3d5b76 Michael Hanselmann
      # Only static choices implemented so far (e.g. no node list)
306 4f3d5b76 Michael Hanselmann
      suggest = getattr(opt, "completion_suggest", None)
307 4f3d5b76 Michael Hanselmann
308 4f3d5b76 Michael Hanselmann
      if not suggest:
309 4f3d5b76 Michael Hanselmann
        suggest = opt.choices
310 4f3d5b76 Michael Hanselmann
311 63d44c55 Michael Hanselmann
      if (isinstance(suggest, (int, long)) and
312 63d44c55 Michael Hanselmann
          suggest in cli.OPT_COMPL_ALL):
313 63d44c55 Michael Hanselmann
        key = suggest
314 63d44c55 Michael Hanselmann
      elif suggest:
315 63d44c55 Michael Hanselmann
        key = " ".join(sorted(suggest))
316 4f3d5b76 Michael Hanselmann
      else:
317 63d44c55 Michael Hanselmann
        key = ""
318 4f3d5b76 Michael Hanselmann
319 63d44c55 Michael Hanselmann
      values.setdefault(key, []).extend(opt.all_names)
320 4f3d5b76 Michael Hanselmann
321 4f3d5b76 Michael Hanselmann
    # Don't write any code if there are no option values
322 4f3d5b76 Michael Hanselmann
    if not values:
323 4f3d5b76 Michael Hanselmann
      return
324 4f3d5b76 Michael Hanselmann
325 d4b94fe8 Michael Hanselmann
    cur = "\"$optcur\""
326 d4b94fe8 Michael Hanselmann
327 d4b94fe8 Michael Hanselmann
    wrote_opt = False
328 d4b94fe8 Michael Hanselmann
329 d4b94fe8 Michael Hanselmann
    for (suggest, allnames) in values.iteritems():
330 d4b94fe8 Michael Hanselmann
      longnames = [i for i in allnames if i.startswith("--")]
331 d4b94fe8 Michael Hanselmann
332 d4b94fe8 Michael Hanselmann
      if wrote_opt:
333 d4b94fe8 Michael Hanselmann
        condcmd = "elif"
334 d4b94fe8 Michael Hanselmann
      else:
335 d4b94fe8 Michael Hanselmann
        condcmd = "if"
336 d4b94fe8 Michael Hanselmann
337 d4b94fe8 Michael Hanselmann
      sw.Write("%s _ganeti_checkopt %s %s; then", condcmd,
338 d4b94fe8 Michael Hanselmann
               utils.ShellQuote("|".join(["%s=*" % i for i in longnames])),
339 d4b94fe8 Michael Hanselmann
               utils.ShellQuote("|".join(allnames)))
340 d4b94fe8 Michael Hanselmann
      sw.IncIndent()
341 d4b94fe8 Michael Hanselmann
      try:
342 63d44c55 Michael Hanselmann
        if suggest == cli.OPT_COMPL_MANY_NODES:
343 63d44c55 Michael Hanselmann
          # TODO: Implement comma-separated values
344 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W ''", cur=cur)
345 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_NODE:
346 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_nodes)\"", cur=cur)
347 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_INSTANCE:
348 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_instances)\"", cur=cur)
349 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_OS:
350 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_os)\"", cur=cur)
351 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_IALLOCATOR:
352 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_iallocator)\"", cur=cur)
353 2d3ed64b Michael Hanselmann
        elif suggest == cli.OPT_COMPL_INST_ADD_NODES:
354 2d3ed64b Michael Hanselmann
          sw.Write("local tmp= node1= pfx= curvalue=\"${optcur#*:}\"")
355 2d3ed64b Michael Hanselmann
356 2d3ed64b Michael Hanselmann
          sw.Write("if [[ \"$optcur\" == *:* ]]; then")
357 2d3ed64b Michael Hanselmann
          sw.IncIndent()
358 2d3ed64b Michael Hanselmann
          try:
359 2d3ed64b Michael Hanselmann
            sw.Write("node1=\"${optcur%%:*}\"")
360 2d3ed64b Michael Hanselmann
361 2d3ed64b Michael Hanselmann
            sw.Write("if [[ \"$COMP_WORDBREAKS\" != *:* ]]; then")
362 2d3ed64b Michael Hanselmann
            sw.IncIndent()
363 2d3ed64b Michael Hanselmann
            try:
364 2d3ed64b Michael Hanselmann
              sw.Write("pfx=\"$node1:\"")
365 2d3ed64b Michael Hanselmann
            finally:
366 2d3ed64b Michael Hanselmann
              sw.DecIndent()
367 2d3ed64b Michael Hanselmann
            sw.Write("fi")
368 2d3ed64b Michael Hanselmann
          finally:
369 2d3ed64b Michael Hanselmann
            sw.DecIndent()
370 2d3ed64b Michael Hanselmann
          sw.Write("fi")
371 2d3ed64b Michael Hanselmann
372 2d3ed64b Michael Hanselmann
          sw.Write("_ganeti_dbglog pfx=\"'$pfx'\" curvalue=\"'$curvalue'\""
373 2d3ed64b Michael Hanselmann
                   " node1=\"'$node1'\"")
374 2d3ed64b Michael Hanselmann
375 2d3ed64b Michael Hanselmann
          sw.Write("for i in $(_ganeti_nodes); do")
376 2d3ed64b Michael Hanselmann
          sw.IncIndent()
377 2d3ed64b Michael Hanselmann
          try:
378 2d3ed64b Michael Hanselmann
            sw.Write("if [[ -z \"$node1\" ]]; then")
379 2d3ed64b Michael Hanselmann
            sw.IncIndent()
380 2d3ed64b Michael Hanselmann
            try:
381 2d3ed64b Michael Hanselmann
              sw.Write("tmp=\"$tmp $i $i:\"")
382 2d3ed64b Michael Hanselmann
            finally:
383 2d3ed64b Michael Hanselmann
              sw.DecIndent()
384 2d3ed64b Michael Hanselmann
            sw.Write("elif [[ \"$i\" != \"$node1\" ]]; then")
385 2d3ed64b Michael Hanselmann
            sw.IncIndent()
386 2d3ed64b Michael Hanselmann
            try:
387 2d3ed64b Michael Hanselmann
              sw.Write("tmp=\"$tmp $i\"")
388 2d3ed64b Michael Hanselmann
            finally:
389 2d3ed64b Michael Hanselmann
              sw.DecIndent()
390 2d3ed64b Michael Hanselmann
            sw.Write("fi")
391 2d3ed64b Michael Hanselmann
          finally:
392 2d3ed64b Michael Hanselmann
            sw.DecIndent()
393 2d3ed64b Michael Hanselmann
          sw.Write("done")
394 2d3ed64b Michael Hanselmann
395 2d3ed64b Michael Hanselmann
          WriteCompReply(sw, "-P \"$pfx\" -W \"$tmp\"", cur="\"$curvalue\"")
396 63d44c55 Michael Hanselmann
        else:
397 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W %s" % utils.ShellQuote(suggest), cur=cur)
398 d4b94fe8 Michael Hanselmann
      finally:
399 d4b94fe8 Michael Hanselmann
        sw.DecIndent()
400 d4b94fe8 Michael Hanselmann
401 d4b94fe8 Michael Hanselmann
      wrote_opt = True
402 d4b94fe8 Michael Hanselmann
403 d4b94fe8 Michael Hanselmann
    if wrote_opt:
404 d4b94fe8 Michael Hanselmann
      sw.Write("fi")
405 d4b94fe8 Michael Hanselmann
406 d4b94fe8 Michael Hanselmann
    return
407 632d5090 Michael Hanselmann
408 4f3d5b76 Michael Hanselmann
  def _CompleteArguments(self, sw):
409 4f3d5b76 Michael Hanselmann
    if not (self.opts or self.args):
410 4f3d5b76 Michael Hanselmann
      return
411 4f3d5b76 Michael Hanselmann
412 4f3d5b76 Michael Hanselmann
    all_option_names = []
413 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
414 4f3d5b76 Michael Hanselmann
      all_option_names.extend(opt.all_names)
415 4f3d5b76 Michael Hanselmann
    all_option_names.sort()
416 4f3d5b76 Michael Hanselmann
417 4f3d5b76 Michael Hanselmann
    # List options if no argument has been specified yet
418 4f3d5b76 Michael Hanselmann
    sw.Write("_ganeti_list_options %s",
419 4f3d5b76 Michael Hanselmann
             utils.ShellQuote(" ".join(all_option_names)))
420 4f3d5b76 Michael Hanselmann
421 4f3d5b76 Michael Hanselmann
    if self.args:
422 4f3d5b76 Michael Hanselmann
      last_idx = len(self.args) - 1
423 4f3d5b76 Michael Hanselmann
      last_arg_end = 0
424 4f3d5b76 Michael Hanselmann
      varlen_arg_idx = None
425 4f3d5b76 Michael Hanselmann
      wrote_arg = False
426 4f3d5b76 Michael Hanselmann
427 4f3d5b76 Michael Hanselmann
      # Write some debug comments
428 4f3d5b76 Michael Hanselmann
      for idx, arg in enumerate(self.args):
429 4f3d5b76 Michael Hanselmann
        sw.Write("# %s: %r", idx, arg)
430 4f3d5b76 Michael Hanselmann
431 4f3d5b76 Michael Hanselmann
      sw.Write("compgenargs=")
432 4f3d5b76 Michael Hanselmann
433 4f3d5b76 Michael Hanselmann
      for idx, arg in enumerate(self.args):
434 4f3d5b76 Michael Hanselmann
        assert arg.min is not None and arg.min >= 0
435 4f3d5b76 Michael Hanselmann
        assert not (idx < last_idx and arg.max is None)
436 4f3d5b76 Michael Hanselmann
437 4f3d5b76 Michael Hanselmann
        if arg.min != arg.max or arg.max is None:
438 4f3d5b76 Michael Hanselmann
          if varlen_arg_idx is not None:
439 4f3d5b76 Michael Hanselmann
            raise Exception("Only one argument can have a variable length")
440 4f3d5b76 Michael Hanselmann
          varlen_arg_idx = idx
441 4f3d5b76 Michael Hanselmann
442 4f3d5b76 Michael Hanselmann
        compgenargs = []
443 4f3d5b76 Michael Hanselmann
444 4f3d5b76 Michael Hanselmann
        if isinstance(arg, cli.ArgUnknown):
445 4f3d5b76 Michael Hanselmann
          choices = ""
446 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgSuggest):
447 4f3d5b76 Michael Hanselmann
          choices = utils.ShellQuote(" ".join(arg.choices))
448 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgInstance):
449 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_instances)"
450 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgNode):
451 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_nodes)"
452 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgJobId):
453 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_jobs)"
454 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgFile):
455 4f3d5b76 Michael Hanselmann
          choices = ""
456 4f3d5b76 Michael Hanselmann
          compgenargs.append("-f")
457 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgCommand):
458 4f3d5b76 Michael Hanselmann
          choices = ""
459 4f3d5b76 Michael Hanselmann
          compgenargs.append("-c")
460 83ec7961 Michael Hanselmann
        elif isinstance(arg, cli.ArgHost):
461 83ec7961 Michael Hanselmann
          choices = ""
462 83ec7961 Michael Hanselmann
          compgenargs.append("-A hostname")
463 4f3d5b76 Michael Hanselmann
        else:
464 4f3d5b76 Michael Hanselmann
          raise Exception("Unknown argument type %r" % arg)
465 4f3d5b76 Michael Hanselmann
466 4f3d5b76 Michael Hanselmann
        if arg.min == 1 and arg.max == 1:
467 4f3d5b76 Michael Hanselmann
          cmpcode = """"$arg_idx" == %d""" % (last_arg_end)
468 8adfb141 Michael Hanselmann
        elif arg.max is None:
469 8adfb141 Michael Hanselmann
          cmpcode = """"$arg_idx" -ge %d""" % (last_arg_end)
470 5431eff1 Michael Hanselmann
        elif arg.min <= arg.max:
471 4f3d5b76 Michael Hanselmann
          cmpcode = (""""$arg_idx" -ge %d && "$arg_idx" -lt %d""" %
472 4f3d5b76 Michael Hanselmann
                     (last_arg_end, last_arg_end + arg.max))
473 4f3d5b76 Michael Hanselmann
        else:
474 4f3d5b76 Michael Hanselmann
          raise Exception("Unable to generate argument position condition")
475 4f3d5b76 Michael Hanselmann
476 4f3d5b76 Michael Hanselmann
        last_arg_end += arg.min
477 4f3d5b76 Michael Hanselmann
478 4f3d5b76 Michael Hanselmann
        if choices or compgenargs:
479 4f3d5b76 Michael Hanselmann
          if wrote_arg:
480 4f3d5b76 Michael Hanselmann
            condcmd = "elif"
481 4f3d5b76 Michael Hanselmann
          else:
482 4f3d5b76 Michael Hanselmann
            condcmd = "if"
483 4f3d5b76 Michael Hanselmann
484 4f3d5b76 Michael Hanselmann
          sw.Write("""%s [[ %s ]]; then""", condcmd, cmpcode)
485 4f3d5b76 Michael Hanselmann
          sw.IncIndent()
486 4f3d5b76 Michael Hanselmann
          try:
487 4f3d5b76 Michael Hanselmann
            if choices:
488 4f3d5b76 Michael Hanselmann
              sw.Write("""choices="$choices "%s""", choices)
489 4f3d5b76 Michael Hanselmann
            if compgenargs:
490 8adfb141 Michael Hanselmann
              sw.Write("compgenargs=%s",
491 8adfb141 Michael Hanselmann
                       utils.ShellQuote(" ".join(compgenargs)))
492 4f3d5b76 Michael Hanselmann
          finally:
493 4f3d5b76 Michael Hanselmann
            sw.DecIndent()
494 4f3d5b76 Michael Hanselmann
495 4f3d5b76 Michael Hanselmann
          wrote_arg = True
496 4f3d5b76 Michael Hanselmann
497 4f3d5b76 Michael Hanselmann
      if wrote_arg:
498 4f3d5b76 Michael Hanselmann
        sw.Write("fi")
499 4f3d5b76 Michael Hanselmann
500 4f3d5b76 Michael Hanselmann
    if self.args:
501 4f3d5b76 Michael Hanselmann
      WriteCompReply(sw, """-W "$choices" $compgenargs""")
502 4f3d5b76 Michael Hanselmann
    else:
503 4f3d5b76 Michael Hanselmann
      # $compgenargs exists only if there are arguments
504 4f3d5b76 Michael Hanselmann
      WriteCompReply(sw, '-W "$choices"')
505 4f3d5b76 Michael Hanselmann
506 4f3d5b76 Michael Hanselmann
  def WriteTo(self, sw):
507 4f3d5b76 Michael Hanselmann
    self._FindFirstArgument(sw)
508 4f3d5b76 Michael Hanselmann
    self._CompleteOptionValues(sw)
509 4f3d5b76 Michael Hanselmann
    self._CompleteArguments(sw)
510 4f3d5b76 Michael Hanselmann
511 4f3d5b76 Michael Hanselmann
512 4f3d5b76 Michael Hanselmann
def WriteCompletion(sw, scriptname, funcname,
513 4f3d5b76 Michael Hanselmann
                    commands=None,
514 4f3d5b76 Michael Hanselmann
                    opts=None, args=None):
515 4f3d5b76 Michael Hanselmann
  """Writes the completion code for one command.
516 4f3d5b76 Michael Hanselmann
517 4f3d5b76 Michael Hanselmann
  @type sw: ShellWriter
518 4f3d5b76 Michael Hanselmann
  @param sw: Script writer
519 4f3d5b76 Michael Hanselmann
  @type scriptname: string
520 4f3d5b76 Michael Hanselmann
  @param scriptname: Name of command line program
521 4f3d5b76 Michael Hanselmann
  @type funcname: string
522 4f3d5b76 Michael Hanselmann
  @param funcname: Shell function name
523 4f3d5b76 Michael Hanselmann
  @type commands: list
524 4f3d5b76 Michael Hanselmann
  @param commands: List of all subcommands in this program
525 4f3d5b76 Michael Hanselmann
526 4f3d5b76 Michael Hanselmann
  """
527 4f3d5b76 Michael Hanselmann
  sw.Write("%s() {", funcname)
528 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
529 4f3d5b76 Michael Hanselmann
  try:
530 580ef58d Michael Hanselmann
    sw.Write("local "
531 632d5090 Michael Hanselmann
             ' cur="${COMP_WORDS[COMP_CWORD]}"'
532 580ef58d Michael Hanselmann
             ' prev="${COMP_WORDS[COMP_CWORD-1]}"'
533 d4b94fe8 Michael Hanselmann
             ' i first_arg_idx choices compgenargs arg_idx optcur')
534 580ef58d Michael Hanselmann
535 5b0ca9d4 Michael Hanselmann
    sw.Write("_ganeti_dbglog cur=\"$cur\" prev=\"$prev\"")
536 5b0ca9d4 Michael Hanselmann
    sw.Write("[[ -n \"$GANETI_COMPL_LOG\" ]] &&"
537 5b0ca9d4 Michael Hanselmann
             " _ganeti_dbglog \"$(set | grep ^COMP_)\"")
538 4f3d5b76 Michael Hanselmann
539 4f3d5b76 Michael Hanselmann
    sw.Write("COMPREPLY=()")
540 4f3d5b76 Michael Hanselmann
541 4f3d5b76 Michael Hanselmann
    if opts is not None and args is not None:
542 4f3d5b76 Michael Hanselmann
      assert not commands
543 4f3d5b76 Michael Hanselmann
      CompletionWriter(0, opts, args).WriteTo(sw)
544 4f3d5b76 Michael Hanselmann
545 4f3d5b76 Michael Hanselmann
    else:
546 4f3d5b76 Michael Hanselmann
      sw.Write("""if [[ "$COMP_CWORD" == 1 ]]; then""")
547 4f3d5b76 Michael Hanselmann
      sw.IncIndent()
548 4f3d5b76 Michael Hanselmann
      try:
549 4f3d5b76 Michael Hanselmann
        # Complete the command name
550 4f3d5b76 Michael Hanselmann
        WriteCompReply(sw,
551 4f3d5b76 Michael Hanselmann
                       ("-W %s" %
552 4f3d5b76 Michael Hanselmann
                        utils.ShellQuote(" ".join(sorted(commands.keys())))))
553 4f3d5b76 Michael Hanselmann
      finally:
554 4f3d5b76 Michael Hanselmann
        sw.DecIndent()
555 4f3d5b76 Michael Hanselmann
      sw.Write("fi")
556 4f3d5b76 Michael Hanselmann
557 4f3d5b76 Michael Hanselmann
      # We're doing options and arguments to commands
558 4f3d5b76 Michael Hanselmann
      sw.Write("""case "${COMP_WORDS[1]}" in""")
559 4f3d5b76 Michael Hanselmann
      for cmd, (_, argdef, optdef, _, _) in commands.iteritems():
560 4f3d5b76 Michael Hanselmann
        if not (argdef or optdef):
561 4f3d5b76 Michael Hanselmann
          continue
562 4f3d5b76 Michael Hanselmann
563 4f3d5b76 Michael Hanselmann
        # TODO: Group by arguments and options
564 4f3d5b76 Michael Hanselmann
        sw.Write("%s)", utils.ShellQuote(cmd))
565 4f3d5b76 Michael Hanselmann
        sw.IncIndent()
566 4f3d5b76 Michael Hanselmann
        try:
567 4f3d5b76 Michael Hanselmann
          CompletionWriter(1, optdef, argdef).WriteTo(sw)
568 4f3d5b76 Michael Hanselmann
        finally:
569 4f3d5b76 Michael Hanselmann
          sw.DecIndent()
570 4f3d5b76 Michael Hanselmann
571 4f3d5b76 Michael Hanselmann
        sw.Write(";;")
572 4f3d5b76 Michael Hanselmann
      sw.Write("esac")
573 4f3d5b76 Michael Hanselmann
  finally:
574 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
575 4f3d5b76 Michael Hanselmann
  sw.Write("}")
576 4f3d5b76 Michael Hanselmann
577 4f3d5b76 Michael Hanselmann
  sw.Write("complete -F %s -o filenames %s",
578 4f3d5b76 Michael Hanselmann
           utils.ShellQuote(funcname),
579 4f3d5b76 Michael Hanselmann
           utils.ShellQuote(scriptname))
580 4f3d5b76 Michael Hanselmann
581 4f3d5b76 Michael Hanselmann
582 4f3d5b76 Michael Hanselmann
def GetFunctionName(name):
583 4f3d5b76 Michael Hanselmann
  return "_" + re.sub(r"[^a-z0-9]+", "_", name.lower())
584 4f3d5b76 Michael Hanselmann
585 4f3d5b76 Michael Hanselmann
586 4f3d5b76 Michael Hanselmann
def GetCommands(filename, module):
587 4f3d5b76 Michael Hanselmann
  """Returns the commands defined in a module.
588 4f3d5b76 Michael Hanselmann
589 4f3d5b76 Michael Hanselmann
  Aliases are also added as commands.
590 4f3d5b76 Michael Hanselmann
591 4f3d5b76 Michael Hanselmann
  """
592 4f3d5b76 Michael Hanselmann
  try:
593 4f3d5b76 Michael Hanselmann
    commands = getattr(module, "commands")
594 4f3d5b76 Michael Hanselmann
  except AttributeError, err:
595 4f3d5b76 Michael Hanselmann
    raise Exception("Script %s doesn't have 'commands' attribute" %
596 4f3d5b76 Michael Hanselmann
                    filename)
597 4f3d5b76 Michael Hanselmann
598 1f4e391b Michael Hanselmann
  # Add the implicit "--help" option
599 1f4e391b Michael Hanselmann
  help_option = cli.cli_option("-h", "--help", default=False,
600 1f4e391b Michael Hanselmann
                               action="store_true")
601 1f4e391b Michael Hanselmann
602 1f4e391b Michael Hanselmann
  for (_, _, optdef, _, _) in commands.itervalues():
603 1f4e391b Michael Hanselmann
    if help_option not in optdef:
604 1f4e391b Michael Hanselmann
      optdef.append(help_option)
605 064c21f8 Iustin Pop
    if cli.DEBUG_OPT not in optdef:
606 064c21f8 Iustin Pop
      optdef.append(cli.DEBUG_OPT)
607 1f4e391b Michael Hanselmann
608 4f3d5b76 Michael Hanselmann
  # Use aliases
609 4f3d5b76 Michael Hanselmann
  aliases = getattr(module, "aliases", {})
610 4f3d5b76 Michael Hanselmann
  if aliases:
611 4f3d5b76 Michael Hanselmann
    commands = commands.copy()
612 4f3d5b76 Michael Hanselmann
    for name, target in aliases.iteritems():
613 4f3d5b76 Michael Hanselmann
      commands[name] = commands[target]
614 4f3d5b76 Michael Hanselmann
615 4f3d5b76 Michael Hanselmann
  return commands
616 4f3d5b76 Michael Hanselmann
617 4f3d5b76 Michael Hanselmann
618 4f3d5b76 Michael Hanselmann
def main():
619 4f3d5b76 Michael Hanselmann
  buf = StringIO()
620 4f3d5b76 Michael Hanselmann
  sw = ShellWriter(buf)
621 4f3d5b76 Michael Hanselmann
622 4f3d5b76 Michael Hanselmann
  WritePreamble(sw)
623 4f3d5b76 Michael Hanselmann
624 4f3d5b76 Michael Hanselmann
  # gnt-* scripts
625 4f3d5b76 Michael Hanselmann
  for scriptname in _autoconf.GNT_SCRIPTS:
626 4f3d5b76 Michael Hanselmann
    filename = "scripts/%s" % scriptname
627 4f3d5b76 Michael Hanselmann
628 4f3d5b76 Michael Hanselmann
    WriteCompletion(sw, scriptname,
629 4f3d5b76 Michael Hanselmann
                    GetFunctionName(scriptname),
630 d6f5892b Michael Hanselmann
                    commands=GetCommands(filename,
631 e948770c Michael Hanselmann
                                         build.LoadModule(filename)))
632 4f3d5b76 Michael Hanselmann
633 4f3d5b76 Michael Hanselmann
  # Burnin script
634 e948770c Michael Hanselmann
  burnin = build.LoadModule("tools/burnin")
635 4f3d5b76 Michael Hanselmann
  WriteCompletion(sw, "%s/burnin" % constants.TOOLSDIR, "_ganeti_burnin",
636 4f3d5b76 Michael Hanselmann
                  opts=burnin.OPTIONS, args=burnin.ARGUMENTS)
637 4f3d5b76 Michael Hanselmann
638 4f3d5b76 Michael Hanselmann
  print buf.getvalue()
639 4f3d5b76 Michael Hanselmann
640 4f3d5b76 Michael Hanselmann
641 4f3d5b76 Michael Hanselmann
if __name__ == "__main__":
642 4f3d5b76 Michael Hanselmann
  main()