Statistics
| Branch: | Tag: | Revision:

root / autotools / build-bash-completion @ 1f4e391b

History | View | Annotate | Download (17.1 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 4f3d5b76 Michael Hanselmann
240 632d5090 Michael Hanselmann
def WriteCompReply(sw, args, cur="\"$cur\""):
241 632d5090 Michael Hanselmann
  sw.Write("""COMPREPLY=( $(compgen %s -- %s) )""", args, cur)
242 5b0ca9d4 Michael Hanselmann
  sw.Write("_ganeti_dbglog COMPREPLY=\"${COMPREPLY[@]}\"")
243 4f3d5b76 Michael Hanselmann
  sw.Write("return")
244 4f3d5b76 Michael Hanselmann
245 4f3d5b76 Michael Hanselmann
246 4f3d5b76 Michael Hanselmann
class CompletionWriter:
247 4f3d5b76 Michael Hanselmann
  """Command completion writer class.
248 4f3d5b76 Michael Hanselmann
249 4f3d5b76 Michael Hanselmann
  """
250 4f3d5b76 Michael Hanselmann
  def __init__(self, arg_offset, opts, args):
251 4f3d5b76 Michael Hanselmann
    self.arg_offset = arg_offset
252 4f3d5b76 Michael Hanselmann
    self.opts = opts
253 4f3d5b76 Michael Hanselmann
    self.args = args
254 4f3d5b76 Michael Hanselmann
255 4f3d5b76 Michael Hanselmann
    for opt in opts:
256 4f3d5b76 Michael Hanselmann
      opt.all_names = sorted(opt._short_opts + opt._long_opts)
257 4f3d5b76 Michael Hanselmann
258 4f3d5b76 Michael Hanselmann
  def _FindFirstArgument(self, sw):
259 4f3d5b76 Michael Hanselmann
    ignore = []
260 4f3d5b76 Michael Hanselmann
    skip_one = []
261 4f3d5b76 Michael Hanselmann
262 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
263 4f3d5b76 Michael Hanselmann
      if opt.takes_value():
264 4f3d5b76 Michael Hanselmann
        # Ignore value
265 4f3d5b76 Michael Hanselmann
        for i in opt.all_names:
266 580ef58d Michael Hanselmann
          if i.startswith("--"):
267 580ef58d Michael Hanselmann
            ignore.append("%s=*" % utils.ShellQuote(i))
268 4f3d5b76 Michael Hanselmann
          skip_one.append(utils.ShellQuote(i))
269 4f3d5b76 Michael Hanselmann
      else:
270 4f3d5b76 Michael Hanselmann
        ignore.extend([utils.ShellQuote(i) for i in opt.all_names])
271 4f3d5b76 Michael Hanselmann
272 4f3d5b76 Michael Hanselmann
    ignore = sorted(utils.UniqueSequence(ignore))
273 4f3d5b76 Michael Hanselmann
    skip_one = sorted(utils.UniqueSequence(skip_one))
274 4f3d5b76 Michael Hanselmann
275 4f3d5b76 Michael Hanselmann
    if ignore or skip_one:
276 4f3d5b76 Michael Hanselmann
      # Try to locate first argument
277 4f3d5b76 Michael Hanselmann
      sw.Write("_ganeti_find_first_arg %s %s %s",
278 4f3d5b76 Michael Hanselmann
               self.arg_offset + 1,
279 4f3d5b76 Michael Hanselmann
               utils.ShellQuote("|".join(skip_one)),
280 4f3d5b76 Michael Hanselmann
               utils.ShellQuote("|".join(ignore)))
281 4f3d5b76 Michael Hanselmann
    else:
282 4f3d5b76 Michael Hanselmann
      # When there are no options the first argument is always at position
283 4f3d5b76 Michael Hanselmann
      # offset + 1
284 4f3d5b76 Michael Hanselmann
      sw.Write("first_arg_idx=%s", self.arg_offset + 1)
285 4f3d5b76 Michael Hanselmann
286 4f3d5b76 Michael Hanselmann
  def _CompleteOptionValues(self, sw):
287 4f3d5b76 Michael Hanselmann
    # Group by values
288 4f3d5b76 Michael Hanselmann
    # "values" -> [optname1, optname2, ...]
289 4f3d5b76 Michael Hanselmann
    values = {}
290 4f3d5b76 Michael Hanselmann
291 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
292 4f3d5b76 Michael Hanselmann
      if not opt.takes_value():
293 4f3d5b76 Michael Hanselmann
        continue
294 4f3d5b76 Michael Hanselmann
295 4f3d5b76 Michael Hanselmann
      # Only static choices implemented so far (e.g. no node list)
296 4f3d5b76 Michael Hanselmann
      suggest = getattr(opt, "completion_suggest", None)
297 4f3d5b76 Michael Hanselmann
298 4f3d5b76 Michael Hanselmann
      if not suggest:
299 4f3d5b76 Michael Hanselmann
        suggest = opt.choices
300 4f3d5b76 Michael Hanselmann
301 63d44c55 Michael Hanselmann
      if (isinstance(suggest, (int, long)) and
302 63d44c55 Michael Hanselmann
          suggest in cli.OPT_COMPL_ALL):
303 63d44c55 Michael Hanselmann
        key = suggest
304 63d44c55 Michael Hanselmann
      elif suggest:
305 63d44c55 Michael Hanselmann
        key = " ".join(sorted(suggest))
306 4f3d5b76 Michael Hanselmann
      else:
307 63d44c55 Michael Hanselmann
        key = ""
308 4f3d5b76 Michael Hanselmann
309 63d44c55 Michael Hanselmann
      values.setdefault(key, []).extend(opt.all_names)
310 4f3d5b76 Michael Hanselmann
311 4f3d5b76 Michael Hanselmann
    # Don't write any code if there are no option values
312 4f3d5b76 Michael Hanselmann
    if not values:
313 4f3d5b76 Michael Hanselmann
      return
314 4f3d5b76 Michael Hanselmann
315 d4b94fe8 Michael Hanselmann
    cur = "\"$optcur\""
316 d4b94fe8 Michael Hanselmann
317 d4b94fe8 Michael Hanselmann
    wrote_opt = False
318 d4b94fe8 Michael Hanselmann
319 d4b94fe8 Michael Hanselmann
    for (suggest, allnames) in values.iteritems():
320 d4b94fe8 Michael Hanselmann
      longnames = [i for i in allnames if i.startswith("--")]
321 d4b94fe8 Michael Hanselmann
322 d4b94fe8 Michael Hanselmann
      if wrote_opt:
323 d4b94fe8 Michael Hanselmann
        condcmd = "elif"
324 d4b94fe8 Michael Hanselmann
      else:
325 d4b94fe8 Michael Hanselmann
        condcmd = "if"
326 d4b94fe8 Michael Hanselmann
327 d4b94fe8 Michael Hanselmann
      sw.Write("%s _ganeti_checkopt %s %s; then", condcmd,
328 d4b94fe8 Michael Hanselmann
               utils.ShellQuote("|".join(["%s=*" % i for i in longnames])),
329 d4b94fe8 Michael Hanselmann
               utils.ShellQuote("|".join(allnames)))
330 d4b94fe8 Michael Hanselmann
      sw.IncIndent()
331 d4b94fe8 Michael Hanselmann
      try:
332 63d44c55 Michael Hanselmann
        if suggest == cli.OPT_COMPL_MANY_NODES:
333 63d44c55 Michael Hanselmann
          # TODO: Implement comma-separated values
334 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W ''", cur=cur)
335 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_NODE:
336 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_nodes)\"", cur=cur)
337 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_INSTANCE:
338 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_instances)\"", cur=cur)
339 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_OS:
340 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_os)\"", cur=cur)
341 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_IALLOCATOR:
342 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_iallocator)\"", cur=cur)
343 2d3ed64b Michael Hanselmann
        elif suggest == cli.OPT_COMPL_INST_ADD_NODES:
344 2d3ed64b Michael Hanselmann
          sw.Write("local tmp= node1= pfx= curvalue=\"${optcur#*:}\"")
345 2d3ed64b Michael Hanselmann
346 2d3ed64b Michael Hanselmann
          sw.Write("if [[ \"$optcur\" == *:* ]]; then")
347 2d3ed64b Michael Hanselmann
          sw.IncIndent()
348 2d3ed64b Michael Hanselmann
          try:
349 2d3ed64b Michael Hanselmann
            sw.Write("node1=\"${optcur%%:*}\"")
350 2d3ed64b Michael Hanselmann
351 2d3ed64b Michael Hanselmann
            sw.Write("if [[ \"$COMP_WORDBREAKS\" != *:* ]]; then")
352 2d3ed64b Michael Hanselmann
            sw.IncIndent()
353 2d3ed64b Michael Hanselmann
            try:
354 2d3ed64b Michael Hanselmann
              sw.Write("pfx=\"$node1:\"")
355 2d3ed64b Michael Hanselmann
            finally:
356 2d3ed64b Michael Hanselmann
              sw.DecIndent()
357 2d3ed64b Michael Hanselmann
            sw.Write("fi")
358 2d3ed64b Michael Hanselmann
          finally:
359 2d3ed64b Michael Hanselmann
            sw.DecIndent()
360 2d3ed64b Michael Hanselmann
          sw.Write("fi")
361 2d3ed64b Michael Hanselmann
362 2d3ed64b Michael Hanselmann
          sw.Write("_ganeti_dbglog pfx=\"'$pfx'\" curvalue=\"'$curvalue'\""
363 2d3ed64b Michael Hanselmann
                   " node1=\"'$node1'\"")
364 2d3ed64b Michael Hanselmann
365 2d3ed64b Michael Hanselmann
          sw.Write("for i in $(_ganeti_nodes); do")
366 2d3ed64b Michael Hanselmann
          sw.IncIndent()
367 2d3ed64b Michael Hanselmann
          try:
368 2d3ed64b Michael Hanselmann
            sw.Write("if [[ -z \"$node1\" ]]; then")
369 2d3ed64b Michael Hanselmann
            sw.IncIndent()
370 2d3ed64b Michael Hanselmann
            try:
371 2d3ed64b Michael Hanselmann
              sw.Write("tmp=\"$tmp $i $i:\"")
372 2d3ed64b Michael Hanselmann
            finally:
373 2d3ed64b Michael Hanselmann
              sw.DecIndent()
374 2d3ed64b Michael Hanselmann
            sw.Write("elif [[ \"$i\" != \"$node1\" ]]; then")
375 2d3ed64b Michael Hanselmann
            sw.IncIndent()
376 2d3ed64b Michael Hanselmann
            try:
377 2d3ed64b Michael Hanselmann
              sw.Write("tmp=\"$tmp $i\"")
378 2d3ed64b Michael Hanselmann
            finally:
379 2d3ed64b Michael Hanselmann
              sw.DecIndent()
380 2d3ed64b Michael Hanselmann
            sw.Write("fi")
381 2d3ed64b Michael Hanselmann
          finally:
382 2d3ed64b Michael Hanselmann
            sw.DecIndent()
383 2d3ed64b Michael Hanselmann
          sw.Write("done")
384 2d3ed64b Michael Hanselmann
385 2d3ed64b Michael Hanselmann
          WriteCompReply(sw, "-P \"$pfx\" -W \"$tmp\"", cur="\"$curvalue\"")
386 63d44c55 Michael Hanselmann
        else:
387 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W %s" % utils.ShellQuote(suggest), cur=cur)
388 d4b94fe8 Michael Hanselmann
      finally:
389 d4b94fe8 Michael Hanselmann
        sw.DecIndent()
390 d4b94fe8 Michael Hanselmann
391 d4b94fe8 Michael Hanselmann
      wrote_opt = True
392 d4b94fe8 Michael Hanselmann
393 d4b94fe8 Michael Hanselmann
    if wrote_opt:
394 d4b94fe8 Michael Hanselmann
      sw.Write("fi")
395 d4b94fe8 Michael Hanselmann
396 d4b94fe8 Michael Hanselmann
    return
397 632d5090 Michael Hanselmann
398 4f3d5b76 Michael Hanselmann
  def _CompleteArguments(self, sw):
399 4f3d5b76 Michael Hanselmann
    if not (self.opts or self.args):
400 4f3d5b76 Michael Hanselmann
      return
401 4f3d5b76 Michael Hanselmann
402 4f3d5b76 Michael Hanselmann
    all_option_names = []
403 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
404 4f3d5b76 Michael Hanselmann
      all_option_names.extend(opt.all_names)
405 4f3d5b76 Michael Hanselmann
    all_option_names.sort()
406 4f3d5b76 Michael Hanselmann
407 4f3d5b76 Michael Hanselmann
    # List options if no argument has been specified yet
408 4f3d5b76 Michael Hanselmann
    sw.Write("_ganeti_list_options %s",
409 4f3d5b76 Michael Hanselmann
             utils.ShellQuote(" ".join(all_option_names)))
410 4f3d5b76 Michael Hanselmann
411 4f3d5b76 Michael Hanselmann
    if self.args:
412 4f3d5b76 Michael Hanselmann
      last_idx = len(self.args) - 1
413 4f3d5b76 Michael Hanselmann
      last_arg_end = 0
414 4f3d5b76 Michael Hanselmann
      varlen_arg_idx = None
415 4f3d5b76 Michael Hanselmann
      wrote_arg = False
416 4f3d5b76 Michael Hanselmann
417 4f3d5b76 Michael Hanselmann
      # Write some debug comments
418 4f3d5b76 Michael Hanselmann
      for idx, arg in enumerate(self.args):
419 4f3d5b76 Michael Hanselmann
        sw.Write("# %s: %r", idx, arg)
420 4f3d5b76 Michael Hanselmann
421 4f3d5b76 Michael Hanselmann
      sw.Write("compgenargs=")
422 4f3d5b76 Michael Hanselmann
423 4f3d5b76 Michael Hanselmann
      for idx, arg in enumerate(self.args):
424 4f3d5b76 Michael Hanselmann
        assert arg.min is not None and arg.min >= 0
425 4f3d5b76 Michael Hanselmann
        assert not (idx < last_idx and arg.max is None)
426 4f3d5b76 Michael Hanselmann
427 4f3d5b76 Michael Hanselmann
        if arg.min != arg.max or arg.max is None:
428 4f3d5b76 Michael Hanselmann
          if varlen_arg_idx is not None:
429 4f3d5b76 Michael Hanselmann
            raise Exception("Only one argument can have a variable length")
430 4f3d5b76 Michael Hanselmann
          varlen_arg_idx = idx
431 4f3d5b76 Michael Hanselmann
432 4f3d5b76 Michael Hanselmann
        compgenargs = []
433 4f3d5b76 Michael Hanselmann
434 4f3d5b76 Michael Hanselmann
        if isinstance(arg, cli.ArgUnknown):
435 4f3d5b76 Michael Hanselmann
          choices = ""
436 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgSuggest):
437 4f3d5b76 Michael Hanselmann
          choices = utils.ShellQuote(" ".join(arg.choices))
438 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgInstance):
439 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_instances)"
440 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgNode):
441 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_nodes)"
442 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgJobId):
443 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_jobs)"
444 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgFile):
445 4f3d5b76 Michael Hanselmann
          choices = ""
446 4f3d5b76 Michael Hanselmann
          compgenargs.append("-f")
447 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgCommand):
448 4f3d5b76 Michael Hanselmann
          choices = ""
449 4f3d5b76 Michael Hanselmann
          compgenargs.append("-c")
450 83ec7961 Michael Hanselmann
        elif isinstance(arg, cli.ArgHost):
451 83ec7961 Michael Hanselmann
          choices = ""
452 83ec7961 Michael Hanselmann
          compgenargs.append("-A hostname")
453 4f3d5b76 Michael Hanselmann
        else:
454 4f3d5b76 Michael Hanselmann
          raise Exception("Unknown argument type %r" % arg)
455 4f3d5b76 Michael Hanselmann
456 4f3d5b76 Michael Hanselmann
        if arg.min == 1 and arg.max == 1:
457 4f3d5b76 Michael Hanselmann
          cmpcode = """"$arg_idx" == %d""" % (last_arg_end)
458 5431eff1 Michael Hanselmann
        elif arg.min <= arg.max:
459 4f3d5b76 Michael Hanselmann
          cmpcode = (""""$arg_idx" -ge %d && "$arg_idx" -lt %d""" %
460 4f3d5b76 Michael Hanselmann
                     (last_arg_end, last_arg_end + arg.max))
461 4f3d5b76 Michael Hanselmann
        elif arg.max is None:
462 4f3d5b76 Michael Hanselmann
          cmpcode = """"$arg_idx" -ge %d""" % (last_arg_end)
463 4f3d5b76 Michael Hanselmann
        else:
464 4f3d5b76 Michael Hanselmann
          raise Exception("Unable to generate argument position condition")
465 4f3d5b76 Michael Hanselmann
466 4f3d5b76 Michael Hanselmann
        last_arg_end += arg.min
467 4f3d5b76 Michael Hanselmann
468 4f3d5b76 Michael Hanselmann
        if choices or compgenargs:
469 4f3d5b76 Michael Hanselmann
          if wrote_arg:
470 4f3d5b76 Michael Hanselmann
            condcmd = "elif"
471 4f3d5b76 Michael Hanselmann
          else:
472 4f3d5b76 Michael Hanselmann
            condcmd = "if"
473 4f3d5b76 Michael Hanselmann
474 4f3d5b76 Michael Hanselmann
          sw.Write("""%s [[ %s ]]; then""", condcmd, cmpcode)
475 4f3d5b76 Michael Hanselmann
          sw.IncIndent()
476 4f3d5b76 Michael Hanselmann
          try:
477 4f3d5b76 Michael Hanselmann
            if choices:
478 4f3d5b76 Michael Hanselmann
              sw.Write("""choices="$choices "%s""", choices)
479 4f3d5b76 Michael Hanselmann
            if compgenargs:
480 4f3d5b76 Michael Hanselmann
              sw.Write("compgenargs=%s", utils.ShellQuote(" ".join(compgenargs)))
481 4f3d5b76 Michael Hanselmann
          finally:
482 4f3d5b76 Michael Hanselmann
            sw.DecIndent()
483 4f3d5b76 Michael Hanselmann
484 4f3d5b76 Michael Hanselmann
          wrote_arg = True
485 4f3d5b76 Michael Hanselmann
486 4f3d5b76 Michael Hanselmann
      if wrote_arg:
487 4f3d5b76 Michael Hanselmann
        sw.Write("fi")
488 4f3d5b76 Michael Hanselmann
489 4f3d5b76 Michael Hanselmann
    if self.args:
490 4f3d5b76 Michael Hanselmann
      WriteCompReply(sw, """-W "$choices" $compgenargs""")
491 4f3d5b76 Michael Hanselmann
    else:
492 4f3d5b76 Michael Hanselmann
      # $compgenargs exists only if there are arguments
493 4f3d5b76 Michael Hanselmann
      WriteCompReply(sw, '-W "$choices"')
494 4f3d5b76 Michael Hanselmann
495 4f3d5b76 Michael Hanselmann
  def WriteTo(self, sw):
496 4f3d5b76 Michael Hanselmann
    self._FindFirstArgument(sw)
497 4f3d5b76 Michael Hanselmann
    self._CompleteOptionValues(sw)
498 4f3d5b76 Michael Hanselmann
    self._CompleteArguments(sw)
499 4f3d5b76 Michael Hanselmann
500 4f3d5b76 Michael Hanselmann
501 4f3d5b76 Michael Hanselmann
def WriteCompletion(sw, scriptname, funcname,
502 4f3d5b76 Michael Hanselmann
                    commands=None,
503 4f3d5b76 Michael Hanselmann
                    opts=None, args=None):
504 4f3d5b76 Michael Hanselmann
  """Writes the completion code for one command.
505 4f3d5b76 Michael Hanselmann
506 4f3d5b76 Michael Hanselmann
  @type sw: ShellWriter
507 4f3d5b76 Michael Hanselmann
  @param sw: Script writer
508 4f3d5b76 Michael Hanselmann
  @type scriptname: string
509 4f3d5b76 Michael Hanselmann
  @param scriptname: Name of command line program
510 4f3d5b76 Michael Hanselmann
  @type funcname: string
511 4f3d5b76 Michael Hanselmann
  @param funcname: Shell function name
512 4f3d5b76 Michael Hanselmann
  @type commands: list
513 4f3d5b76 Michael Hanselmann
  @param commands: List of all subcommands in this program
514 4f3d5b76 Michael Hanselmann
515 4f3d5b76 Michael Hanselmann
  """
516 4f3d5b76 Michael Hanselmann
  sw.Write("%s() {", funcname)
517 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
518 4f3d5b76 Michael Hanselmann
  try:
519 580ef58d Michael Hanselmann
    sw.Write("local "
520 632d5090 Michael Hanselmann
             ' cur="${COMP_WORDS[COMP_CWORD]}"'
521 580ef58d Michael Hanselmann
             ' prev="${COMP_WORDS[COMP_CWORD-1]}"'
522 d4b94fe8 Michael Hanselmann
             ' i first_arg_idx choices compgenargs arg_idx optcur')
523 580ef58d Michael Hanselmann
524 5b0ca9d4 Michael Hanselmann
    sw.Write("_ganeti_dbglog cur=\"$cur\" prev=\"$prev\"")
525 5b0ca9d4 Michael Hanselmann
    sw.Write("[[ -n \"$GANETI_COMPL_LOG\" ]] &&"
526 5b0ca9d4 Michael Hanselmann
             " _ganeti_dbglog \"$(set | grep ^COMP_)\"")
527 4f3d5b76 Michael Hanselmann
528 4f3d5b76 Michael Hanselmann
    sw.Write("COMPREPLY=()")
529 4f3d5b76 Michael Hanselmann
530 4f3d5b76 Michael Hanselmann
    if opts is not None and args is not None:
531 4f3d5b76 Michael Hanselmann
      assert not commands
532 4f3d5b76 Michael Hanselmann
      CompletionWriter(0, opts, args).WriteTo(sw)
533 4f3d5b76 Michael Hanselmann
534 4f3d5b76 Michael Hanselmann
    else:
535 4f3d5b76 Michael Hanselmann
      sw.Write("""if [[ "$COMP_CWORD" == 1 ]]; then""")
536 4f3d5b76 Michael Hanselmann
      sw.IncIndent()
537 4f3d5b76 Michael Hanselmann
      try:
538 4f3d5b76 Michael Hanselmann
        # Complete the command name
539 4f3d5b76 Michael Hanselmann
        WriteCompReply(sw,
540 4f3d5b76 Michael Hanselmann
                       ("-W %s" %
541 4f3d5b76 Michael Hanselmann
                        utils.ShellQuote(" ".join(sorted(commands.keys())))))
542 4f3d5b76 Michael Hanselmann
      finally:
543 4f3d5b76 Michael Hanselmann
        sw.DecIndent()
544 4f3d5b76 Michael Hanselmann
      sw.Write("fi")
545 4f3d5b76 Michael Hanselmann
546 4f3d5b76 Michael Hanselmann
      # We're doing options and arguments to commands
547 4f3d5b76 Michael Hanselmann
      sw.Write("""case "${COMP_WORDS[1]}" in""")
548 4f3d5b76 Michael Hanselmann
      for cmd, (_, argdef, optdef, _, _) in commands.iteritems():
549 4f3d5b76 Michael Hanselmann
        if not (argdef or optdef):
550 4f3d5b76 Michael Hanselmann
          continue
551 4f3d5b76 Michael Hanselmann
552 4f3d5b76 Michael Hanselmann
        # TODO: Group by arguments and options
553 4f3d5b76 Michael Hanselmann
        sw.Write("%s)", utils.ShellQuote(cmd))
554 4f3d5b76 Michael Hanselmann
        sw.IncIndent()
555 4f3d5b76 Michael Hanselmann
        try:
556 4f3d5b76 Michael Hanselmann
          CompletionWriter(1, optdef, argdef).WriteTo(sw)
557 4f3d5b76 Michael Hanselmann
        finally:
558 4f3d5b76 Michael Hanselmann
          sw.DecIndent()
559 4f3d5b76 Michael Hanselmann
560 4f3d5b76 Michael Hanselmann
        sw.Write(";;")
561 4f3d5b76 Michael Hanselmann
      sw.Write("esac")
562 4f3d5b76 Michael Hanselmann
  finally:
563 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
564 4f3d5b76 Michael Hanselmann
  sw.Write("}")
565 4f3d5b76 Michael Hanselmann
566 4f3d5b76 Michael Hanselmann
  sw.Write("complete -F %s -o filenames %s",
567 4f3d5b76 Michael Hanselmann
           utils.ShellQuote(funcname),
568 4f3d5b76 Michael Hanselmann
           utils.ShellQuote(scriptname))
569 4f3d5b76 Michael Hanselmann
570 4f3d5b76 Michael Hanselmann
571 4f3d5b76 Michael Hanselmann
def GetFunctionName(name):
572 4f3d5b76 Michael Hanselmann
  return "_" + re.sub(r"[^a-z0-9]+", "_", name.lower())
573 4f3d5b76 Michael Hanselmann
574 4f3d5b76 Michael Hanselmann
575 4f3d5b76 Michael Hanselmann
def GetCommands(filename, module):
576 4f3d5b76 Michael Hanselmann
  """Returns the commands defined in a module.
577 4f3d5b76 Michael Hanselmann
578 4f3d5b76 Michael Hanselmann
  Aliases are also added as commands.
579 4f3d5b76 Michael Hanselmann
580 4f3d5b76 Michael Hanselmann
  """
581 4f3d5b76 Michael Hanselmann
  try:
582 4f3d5b76 Michael Hanselmann
    commands = getattr(module, "commands")
583 4f3d5b76 Michael Hanselmann
  except AttributeError, err:
584 4f3d5b76 Michael Hanselmann
    raise Exception("Script %s doesn't have 'commands' attribute" %
585 4f3d5b76 Michael Hanselmann
                    filename)
586 4f3d5b76 Michael Hanselmann
587 1f4e391b Michael Hanselmann
  # Add the implicit "--help" option
588 1f4e391b Michael Hanselmann
  help_option = cli.cli_option("-h", "--help", default=False,
589 1f4e391b Michael Hanselmann
                               action="store_true")
590 1f4e391b Michael Hanselmann
591 1f4e391b Michael Hanselmann
  for (_, _, optdef, _, _) in commands.itervalues():
592 1f4e391b Michael Hanselmann
    if help_option not in optdef:
593 1f4e391b Michael Hanselmann
      optdef.append(help_option)
594 1f4e391b Michael Hanselmann
595 4f3d5b76 Michael Hanselmann
  # Use aliases
596 4f3d5b76 Michael Hanselmann
  aliases = getattr(module, "aliases", {})
597 4f3d5b76 Michael Hanselmann
  if aliases:
598 4f3d5b76 Michael Hanselmann
    commands = commands.copy()
599 4f3d5b76 Michael Hanselmann
    for name, target in aliases.iteritems():
600 4f3d5b76 Michael Hanselmann
      commands[name] = commands[target]
601 4f3d5b76 Michael Hanselmann
602 4f3d5b76 Michael Hanselmann
  return commands
603 4f3d5b76 Michael Hanselmann
604 4f3d5b76 Michael Hanselmann
605 4f3d5b76 Michael Hanselmann
def main():
606 4f3d5b76 Michael Hanselmann
  buf = StringIO()
607 4f3d5b76 Michael Hanselmann
  sw = ShellWriter(buf)
608 4f3d5b76 Michael Hanselmann
609 4f3d5b76 Michael Hanselmann
  WritePreamble(sw)
610 4f3d5b76 Michael Hanselmann
611 4f3d5b76 Michael Hanselmann
  # gnt-* scripts
612 4f3d5b76 Michael Hanselmann
  for scriptname in _autoconf.GNT_SCRIPTS:
613 4f3d5b76 Michael Hanselmann
    filename = "scripts/%s" % scriptname
614 4f3d5b76 Michael Hanselmann
615 4f3d5b76 Michael Hanselmann
    WriteCompletion(sw, scriptname,
616 4f3d5b76 Michael Hanselmann
                    GetFunctionName(scriptname),
617 d6f5892b Michael Hanselmann
                    commands=GetCommands(filename,
618 e948770c Michael Hanselmann
                                         build.LoadModule(filename)))
619 4f3d5b76 Michael Hanselmann
620 4f3d5b76 Michael Hanselmann
  # Burnin script
621 e948770c Michael Hanselmann
  burnin = build.LoadModule("tools/burnin")
622 4f3d5b76 Michael Hanselmann
  WriteCompletion(sw, "%s/burnin" % constants.TOOLSDIR, "_ganeti_burnin",
623 4f3d5b76 Michael Hanselmann
                  opts=burnin.OPTIONS, args=burnin.ARGUMENTS)
624 4f3d5b76 Michael Hanselmann
625 4f3d5b76 Michael Hanselmann
  print buf.getvalue()
626 4f3d5b76 Michael Hanselmann
627 4f3d5b76 Michael Hanselmann
628 4f3d5b76 Michael Hanselmann
if __name__ == "__main__":
629 4f3d5b76 Michael Hanselmann
  main()