Statistics
| Branch: | Tag: | Revision:

root / autotools / build-bash-completion @ 63d44c55

History | View | Annotate | Download (15.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 imp
23 4f3d5b76 Michael Hanselmann
import optparse
24 4f3d5b76 Michael Hanselmann
import os
25 4f3d5b76 Michael Hanselmann
import sys
26 4f3d5b76 Michael Hanselmann
import re
27 4f3d5b76 Michael Hanselmann
from cStringIO import StringIO
28 4f3d5b76 Michael Hanselmann
29 4f3d5b76 Michael Hanselmann
from ganeti import constants
30 4f3d5b76 Michael Hanselmann
from ganeti import cli
31 4f3d5b76 Michael Hanselmann
from ganeti import utils
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 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_nodes() {")
85 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
86 4f3d5b76 Michael Hanselmann
  try:
87 4f3d5b76 Michael Hanselmann
    node_list_path = os.path.join(constants.DATA_DIR, "ssconf_node_list")
88 5a78e2e7 Michael Hanselmann
    sw.Write("cat %s 2>/dev/null || :", utils.ShellQuote(node_list_path))
89 4f3d5b76 Michael Hanselmann
  finally:
90 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
91 4f3d5b76 Michael Hanselmann
  sw.Write("}")
92 4f3d5b76 Michael Hanselmann
93 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_instances() {")
94 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
95 4f3d5b76 Michael Hanselmann
  try:
96 4f3d5b76 Michael Hanselmann
    instance_list_path = os.path.join(constants.DATA_DIR,
97 4f3d5b76 Michael Hanselmann
                                      "ssconf_instance_list")
98 5a78e2e7 Michael Hanselmann
    sw.Write("cat %s 2>/dev/null || :", utils.ShellQuote(instance_list_path))
99 4f3d5b76 Michael Hanselmann
  finally:
100 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
101 4f3d5b76 Michael Hanselmann
  sw.Write("}")
102 4f3d5b76 Michael Hanselmann
103 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_jobs() {")
104 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
105 4f3d5b76 Michael Hanselmann
  try:
106 4f3d5b76 Michael Hanselmann
    # FIXME: this is really going into the internals of the job queue
107 5a78e2e7 Michael Hanselmann
    sw.Write(("local jlist=$( shopt -s nullglob &&"
108 5a78e2e7 Michael Hanselmann
              " cd %s 2>/dev/null && echo job-* || : )"),
109 4f3d5b76 Michael Hanselmann
             utils.ShellQuote(constants.QUEUE_DIR))
110 5a78e2e7 Michael Hanselmann
    sw.Write('echo "${jlist//job-/}"')
111 4f3d5b76 Michael Hanselmann
  finally:
112 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
113 4f3d5b76 Michael Hanselmann
  sw.Write("}")
114 4f3d5b76 Michael Hanselmann
115 30d44392 Michael Hanselmann
  for (fnname, paths) in [
116 30d44392 Michael Hanselmann
      ("os", constants.OS_SEARCH_PATH),
117 30d44392 Michael Hanselmann
      ("iallocator", constants.IALLOCATOR_SEARCH_PATH),
118 30d44392 Michael Hanselmann
      ]:
119 30d44392 Michael Hanselmann
    sw.Write("_ganeti_%s() {", fnname)
120 30d44392 Michael Hanselmann
    sw.IncIndent()
121 30d44392 Michael Hanselmann
    try:
122 30d44392 Michael Hanselmann
      # FIXME: Make querying the master for all OSes cheap
123 30d44392 Michael Hanselmann
      for path in paths:
124 30d44392 Michael Hanselmann
        sw.Write("( shopt -s nullglob && cd %s 2>/dev/null && echo * || : )",
125 30d44392 Michael Hanselmann
                 utils.ShellQuote(path))
126 30d44392 Michael Hanselmann
    finally:
127 30d44392 Michael Hanselmann
      sw.DecIndent()
128 30d44392 Michael Hanselmann
    sw.Write("}")
129 4f3d5b76 Michael Hanselmann
130 4f3d5b76 Michael Hanselmann
  # Params: <offset> <options with values> <options without values>
131 4f3d5b76 Michael Hanselmann
  # Result variable: $first_arg_idx
132 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_find_first_arg() {")
133 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
134 4f3d5b76 Michael Hanselmann
  try:
135 4f3d5b76 Michael Hanselmann
    sw.Write("local w i")
136 4f3d5b76 Michael Hanselmann
137 4f3d5b76 Michael Hanselmann
    sw.Write("first_arg_idx=")
138 4f3d5b76 Michael Hanselmann
    sw.Write("for (( i=$1; i < COMP_CWORD; ++i )); do")
139 4f3d5b76 Michael Hanselmann
    sw.IncIndent()
140 4f3d5b76 Michael Hanselmann
    try:
141 4f3d5b76 Michael Hanselmann
      sw.Write("w=${COMP_WORDS[$i]}")
142 4f3d5b76 Michael Hanselmann
143 4f3d5b76 Michael Hanselmann
      # Skip option value
144 4f3d5b76 Michael Hanselmann
      sw.Write("""if [[ -n "$2" && "$w" == @($2) ]]; then let ++i""")
145 4f3d5b76 Michael Hanselmann
146 4f3d5b76 Michael Hanselmann
      # Skip
147 4f3d5b76 Michael Hanselmann
      sw.Write("""elif [[ -n "$3" && "$w" == @($3) ]]; then :""")
148 4f3d5b76 Michael Hanselmann
149 4f3d5b76 Michael Hanselmann
      # Ah, we found the first argument
150 4f3d5b76 Michael Hanselmann
      sw.Write("else first_arg_idx=$i; break;")
151 4f3d5b76 Michael Hanselmann
      sw.Write("fi")
152 4f3d5b76 Michael Hanselmann
    finally:
153 4f3d5b76 Michael Hanselmann
      sw.DecIndent()
154 4f3d5b76 Michael Hanselmann
    sw.Write("done")
155 4f3d5b76 Michael Hanselmann
  finally:
156 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
157 4f3d5b76 Michael Hanselmann
  sw.Write("}")
158 4f3d5b76 Michael Hanselmann
159 4f3d5b76 Michael Hanselmann
  # Params: <list of options separated by space>
160 4f3d5b76 Michael Hanselmann
  # Input variable: $first_arg_idx
161 4f3d5b76 Michael Hanselmann
  # Result variables: $arg_idx, $choices
162 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_list_options() {")
163 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
164 4f3d5b76 Michael Hanselmann
  try:
165 4f3d5b76 Michael Hanselmann
    sw.Write("""if [[ -z "$first_arg_idx" ]]; then""")
166 4f3d5b76 Michael Hanselmann
    sw.IncIndent()
167 4f3d5b76 Michael Hanselmann
    try:
168 4f3d5b76 Michael Hanselmann
      sw.Write("arg_idx=0")
169 4f3d5b76 Michael Hanselmann
      # Show options only if the current word starts with a dash
170 4f3d5b76 Michael Hanselmann
      sw.Write("""if [[ "$cur" == -* ]]; then""")
171 4f3d5b76 Michael Hanselmann
      sw.IncIndent()
172 4f3d5b76 Michael Hanselmann
      try:
173 4f3d5b76 Michael Hanselmann
        sw.Write("choices=$1")
174 4f3d5b76 Michael Hanselmann
      finally:
175 4f3d5b76 Michael Hanselmann
        sw.DecIndent()
176 4f3d5b76 Michael Hanselmann
      sw.Write("fi")
177 4f3d5b76 Michael Hanselmann
      sw.Write("return")
178 4f3d5b76 Michael Hanselmann
    finally:
179 4f3d5b76 Michael Hanselmann
      sw.DecIndent()
180 4f3d5b76 Michael Hanselmann
    sw.Write("fi")
181 4f3d5b76 Michael Hanselmann
182 4f3d5b76 Michael Hanselmann
    # Calculate position of current argument
183 4f3d5b76 Michael Hanselmann
    sw.Write("arg_idx=$(( COMP_CWORD - first_arg_idx ))")
184 4f3d5b76 Michael Hanselmann
    sw.Write("choices=")
185 4f3d5b76 Michael Hanselmann
  finally:
186 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
187 4f3d5b76 Michael Hanselmann
  sw.Write("}")
188 4f3d5b76 Michael Hanselmann
189 d4b94fe8 Michael Hanselmann
  # Params: <long options with equal sign> <all options>
190 d4b94fe8 Michael Hanselmann
  # Result variable: $optcur
191 d4b94fe8 Michael Hanselmann
  sw.Write("_ganeti_checkopt() {")
192 d4b94fe8 Michael Hanselmann
  sw.IncIndent()
193 d4b94fe8 Michael Hanselmann
  try:
194 d4b94fe8 Michael Hanselmann
    sw.Write("""if [[ -n "$1" && "$cur" == @($1) ]]; then""")
195 d4b94fe8 Michael Hanselmann
    sw.IncIndent()
196 d4b94fe8 Michael Hanselmann
    try:
197 d4b94fe8 Michael Hanselmann
      sw.Write("optcur=\"${cur#--*=}\"")
198 d4b94fe8 Michael Hanselmann
      sw.Write("return 0")
199 d4b94fe8 Michael Hanselmann
    finally:
200 d4b94fe8 Michael Hanselmann
      sw.DecIndent()
201 d4b94fe8 Michael Hanselmann
    sw.Write("""elif [[ -n "$2" && "$prev" == @($2) ]]; then""")
202 d4b94fe8 Michael Hanselmann
    sw.IncIndent()
203 d4b94fe8 Michael Hanselmann
    try:
204 d4b94fe8 Michael Hanselmann
      sw.Write("optcur=\"$cur\"")
205 d4b94fe8 Michael Hanselmann
      sw.Write("return 0")
206 d4b94fe8 Michael Hanselmann
    finally:
207 d4b94fe8 Michael Hanselmann
      sw.DecIndent()
208 d4b94fe8 Michael Hanselmann
    sw.Write("fi")
209 d4b94fe8 Michael Hanselmann
210 d4b94fe8 Michael Hanselmann
    sw.Write("return 1")
211 d4b94fe8 Michael Hanselmann
  finally:
212 d4b94fe8 Michael Hanselmann
    sw.DecIndent()
213 d4b94fe8 Michael Hanselmann
  sw.Write("}")
214 d4b94fe8 Michael Hanselmann
215 4f3d5b76 Michael Hanselmann
216 632d5090 Michael Hanselmann
def WriteCompReply(sw, args, cur="\"$cur\""):
217 632d5090 Michael Hanselmann
  sw.Write("""COMPREPLY=( $(compgen %s -- %s) )""", args, cur)
218 4f3d5b76 Michael Hanselmann
  sw.Write("return")
219 4f3d5b76 Michael Hanselmann
220 4f3d5b76 Michael Hanselmann
221 4f3d5b76 Michael Hanselmann
class CompletionWriter:
222 4f3d5b76 Michael Hanselmann
  """Command completion writer class.
223 4f3d5b76 Michael Hanselmann
224 4f3d5b76 Michael Hanselmann
  """
225 4f3d5b76 Michael Hanselmann
  def __init__(self, arg_offset, opts, args):
226 4f3d5b76 Michael Hanselmann
    self.arg_offset = arg_offset
227 4f3d5b76 Michael Hanselmann
    self.opts = opts
228 4f3d5b76 Michael Hanselmann
    self.args = args
229 4f3d5b76 Michael Hanselmann
230 4f3d5b76 Michael Hanselmann
    for opt in opts:
231 4f3d5b76 Michael Hanselmann
      opt.all_names = sorted(opt._short_opts + opt._long_opts)
232 4f3d5b76 Michael Hanselmann
233 4f3d5b76 Michael Hanselmann
  def _FindFirstArgument(self, sw):
234 4f3d5b76 Michael Hanselmann
    ignore = []
235 4f3d5b76 Michael Hanselmann
    skip_one = []
236 4f3d5b76 Michael Hanselmann
237 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
238 4f3d5b76 Michael Hanselmann
      if opt.takes_value():
239 4f3d5b76 Michael Hanselmann
        # Ignore value
240 4f3d5b76 Michael Hanselmann
        for i in opt.all_names:
241 580ef58d Michael Hanselmann
          if i.startswith("--"):
242 580ef58d Michael Hanselmann
            ignore.append("%s=*" % utils.ShellQuote(i))
243 4f3d5b76 Michael Hanselmann
          skip_one.append(utils.ShellQuote(i))
244 4f3d5b76 Michael Hanselmann
      else:
245 4f3d5b76 Michael Hanselmann
        ignore.extend([utils.ShellQuote(i) for i in opt.all_names])
246 4f3d5b76 Michael Hanselmann
247 4f3d5b76 Michael Hanselmann
    ignore = sorted(utils.UniqueSequence(ignore))
248 4f3d5b76 Michael Hanselmann
    skip_one = sorted(utils.UniqueSequence(skip_one))
249 4f3d5b76 Michael Hanselmann
250 4f3d5b76 Michael Hanselmann
    if ignore or skip_one:
251 4f3d5b76 Michael Hanselmann
      # Try to locate first argument
252 4f3d5b76 Michael Hanselmann
      sw.Write("_ganeti_find_first_arg %s %s %s",
253 4f3d5b76 Michael Hanselmann
               self.arg_offset + 1,
254 4f3d5b76 Michael Hanselmann
               utils.ShellQuote("|".join(skip_one)),
255 4f3d5b76 Michael Hanselmann
               utils.ShellQuote("|".join(ignore)))
256 4f3d5b76 Michael Hanselmann
    else:
257 4f3d5b76 Michael Hanselmann
      # When there are no options the first argument is always at position
258 4f3d5b76 Michael Hanselmann
      # offset + 1
259 4f3d5b76 Michael Hanselmann
      sw.Write("first_arg_idx=%s", self.arg_offset + 1)
260 4f3d5b76 Michael Hanselmann
261 4f3d5b76 Michael Hanselmann
  def _CompleteOptionValues(self, sw):
262 4f3d5b76 Michael Hanselmann
    # Group by values
263 4f3d5b76 Michael Hanselmann
    # "values" -> [optname1, optname2, ...]
264 4f3d5b76 Michael Hanselmann
    values = {}
265 4f3d5b76 Michael Hanselmann
266 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
267 4f3d5b76 Michael Hanselmann
      if not opt.takes_value():
268 4f3d5b76 Michael Hanselmann
        continue
269 4f3d5b76 Michael Hanselmann
270 4f3d5b76 Michael Hanselmann
      # Only static choices implemented so far (e.g. no node list)
271 4f3d5b76 Michael Hanselmann
      suggest = getattr(opt, "completion_suggest", None)
272 4f3d5b76 Michael Hanselmann
273 4f3d5b76 Michael Hanselmann
      if not suggest:
274 4f3d5b76 Michael Hanselmann
        suggest = opt.choices
275 4f3d5b76 Michael Hanselmann
276 63d44c55 Michael Hanselmann
      if (isinstance(suggest, (int, long)) and
277 63d44c55 Michael Hanselmann
          suggest in cli.OPT_COMPL_ALL):
278 63d44c55 Michael Hanselmann
        key = suggest
279 63d44c55 Michael Hanselmann
      elif suggest:
280 63d44c55 Michael Hanselmann
        key = " ".join(sorted(suggest))
281 4f3d5b76 Michael Hanselmann
      else:
282 63d44c55 Michael Hanselmann
        key = ""
283 4f3d5b76 Michael Hanselmann
284 63d44c55 Michael Hanselmann
      values.setdefault(key, []).extend(opt.all_names)
285 4f3d5b76 Michael Hanselmann
286 4f3d5b76 Michael Hanselmann
    # Don't write any code if there are no option values
287 4f3d5b76 Michael Hanselmann
    if not values:
288 4f3d5b76 Michael Hanselmann
      return
289 4f3d5b76 Michael Hanselmann
290 d4b94fe8 Michael Hanselmann
    cur = "\"$optcur\""
291 d4b94fe8 Michael Hanselmann
292 d4b94fe8 Michael Hanselmann
    wrote_opt = False
293 d4b94fe8 Michael Hanselmann
294 d4b94fe8 Michael Hanselmann
    for (suggest, allnames) in values.iteritems():
295 d4b94fe8 Michael Hanselmann
      longnames = [i for i in allnames if i.startswith("--")]
296 d4b94fe8 Michael Hanselmann
297 d4b94fe8 Michael Hanselmann
      if wrote_opt:
298 d4b94fe8 Michael Hanselmann
        condcmd = "elif"
299 d4b94fe8 Michael Hanselmann
      else:
300 d4b94fe8 Michael Hanselmann
        condcmd = "if"
301 d4b94fe8 Michael Hanselmann
302 d4b94fe8 Michael Hanselmann
      sw.Write("%s _ganeti_checkopt %s %s; then", condcmd,
303 d4b94fe8 Michael Hanselmann
               utils.ShellQuote("|".join(["%s=*" % i for i in longnames])),
304 d4b94fe8 Michael Hanselmann
               utils.ShellQuote("|".join(allnames)))
305 d4b94fe8 Michael Hanselmann
      sw.IncIndent()
306 d4b94fe8 Michael Hanselmann
      try:
307 63d44c55 Michael Hanselmann
        if suggest == cli.OPT_COMPL_MANY_NODES:
308 63d44c55 Michael Hanselmann
          # TODO: Implement comma-separated values
309 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W ''", cur=cur)
310 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_NODE:
311 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_nodes)\"", cur=cur)
312 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_INSTANCE:
313 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_instances)\"", cur=cur)
314 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_OS:
315 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_os)\"", cur=cur)
316 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_IALLOCATOR:
317 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_iallocator)\"", cur=cur)
318 63d44c55 Michael Hanselmann
        else:
319 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W %s" % utils.ShellQuote(suggest), cur=cur)
320 d4b94fe8 Michael Hanselmann
      finally:
321 d4b94fe8 Michael Hanselmann
        sw.DecIndent()
322 d4b94fe8 Michael Hanselmann
323 d4b94fe8 Michael Hanselmann
      wrote_opt = True
324 d4b94fe8 Michael Hanselmann
325 d4b94fe8 Michael Hanselmann
    if wrote_opt:
326 d4b94fe8 Michael Hanselmann
      sw.Write("fi")
327 d4b94fe8 Michael Hanselmann
328 d4b94fe8 Michael Hanselmann
    return
329 632d5090 Michael Hanselmann
330 4f3d5b76 Michael Hanselmann
  def _CompleteArguments(self, sw):
331 4f3d5b76 Michael Hanselmann
    if not (self.opts or self.args):
332 4f3d5b76 Michael Hanselmann
      return
333 4f3d5b76 Michael Hanselmann
334 4f3d5b76 Michael Hanselmann
    all_option_names = []
335 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
336 4f3d5b76 Michael Hanselmann
      all_option_names.extend(opt.all_names)
337 4f3d5b76 Michael Hanselmann
    all_option_names.sort()
338 4f3d5b76 Michael Hanselmann
339 4f3d5b76 Michael Hanselmann
    # List options if no argument has been specified yet
340 4f3d5b76 Michael Hanselmann
    sw.Write("_ganeti_list_options %s",
341 4f3d5b76 Michael Hanselmann
             utils.ShellQuote(" ".join(all_option_names)))
342 4f3d5b76 Michael Hanselmann
343 4f3d5b76 Michael Hanselmann
    if self.args:
344 4f3d5b76 Michael Hanselmann
      last_idx = len(self.args) - 1
345 4f3d5b76 Michael Hanselmann
      last_arg_end = 0
346 4f3d5b76 Michael Hanselmann
      varlen_arg_idx = None
347 4f3d5b76 Michael Hanselmann
      wrote_arg = False
348 4f3d5b76 Michael Hanselmann
349 4f3d5b76 Michael Hanselmann
      # Write some debug comments
350 4f3d5b76 Michael Hanselmann
      for idx, arg in enumerate(self.args):
351 4f3d5b76 Michael Hanselmann
        sw.Write("# %s: %r", idx, arg)
352 4f3d5b76 Michael Hanselmann
353 4f3d5b76 Michael Hanselmann
      sw.Write("compgenargs=")
354 4f3d5b76 Michael Hanselmann
355 4f3d5b76 Michael Hanselmann
      for idx, arg in enumerate(self.args):
356 4f3d5b76 Michael Hanselmann
        assert arg.min is not None and arg.min >= 0
357 4f3d5b76 Michael Hanselmann
        assert not (idx < last_idx and arg.max is None)
358 4f3d5b76 Michael Hanselmann
359 4f3d5b76 Michael Hanselmann
        if arg.min != arg.max or arg.max is None:
360 4f3d5b76 Michael Hanselmann
          if varlen_arg_idx is not None:
361 4f3d5b76 Michael Hanselmann
            raise Exception("Only one argument can have a variable length")
362 4f3d5b76 Michael Hanselmann
          varlen_arg_idx = idx
363 4f3d5b76 Michael Hanselmann
364 4f3d5b76 Michael Hanselmann
        compgenargs = []
365 4f3d5b76 Michael Hanselmann
366 4f3d5b76 Michael Hanselmann
        if isinstance(arg, cli.ArgUnknown):
367 4f3d5b76 Michael Hanselmann
          choices = ""
368 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgSuggest):
369 4f3d5b76 Michael Hanselmann
          choices = utils.ShellQuote(" ".join(arg.choices))
370 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgInstance):
371 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_instances)"
372 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgNode):
373 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_nodes)"
374 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgJobId):
375 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_jobs)"
376 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgFile):
377 4f3d5b76 Michael Hanselmann
          choices = ""
378 4f3d5b76 Michael Hanselmann
          compgenargs.append("-f")
379 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgCommand):
380 4f3d5b76 Michael Hanselmann
          choices = ""
381 4f3d5b76 Michael Hanselmann
          compgenargs.append("-c")
382 83ec7961 Michael Hanselmann
        elif isinstance(arg, cli.ArgHost):
383 83ec7961 Michael Hanselmann
          choices = ""
384 83ec7961 Michael Hanselmann
          compgenargs.append("-A hostname")
385 4f3d5b76 Michael Hanselmann
        else:
386 4f3d5b76 Michael Hanselmann
          raise Exception("Unknown argument type %r" % arg)
387 4f3d5b76 Michael Hanselmann
388 4f3d5b76 Michael Hanselmann
        if arg.min == 1 and arg.max == 1:
389 4f3d5b76 Michael Hanselmann
          cmpcode = """"$arg_idx" == %d""" % (last_arg_end)
390 5431eff1 Michael Hanselmann
        elif arg.min <= arg.max:
391 4f3d5b76 Michael Hanselmann
          cmpcode = (""""$arg_idx" -ge %d && "$arg_idx" -lt %d""" %
392 4f3d5b76 Michael Hanselmann
                     (last_arg_end, last_arg_end + arg.max))
393 4f3d5b76 Michael Hanselmann
        elif arg.max is None:
394 4f3d5b76 Michael Hanselmann
          cmpcode = """"$arg_idx" -ge %d""" % (last_arg_end)
395 4f3d5b76 Michael Hanselmann
        else:
396 4f3d5b76 Michael Hanselmann
          raise Exception("Unable to generate argument position condition")
397 4f3d5b76 Michael Hanselmann
398 4f3d5b76 Michael Hanselmann
        last_arg_end += arg.min
399 4f3d5b76 Michael Hanselmann
400 4f3d5b76 Michael Hanselmann
        if choices or compgenargs:
401 4f3d5b76 Michael Hanselmann
          if wrote_arg:
402 4f3d5b76 Michael Hanselmann
            condcmd = "elif"
403 4f3d5b76 Michael Hanselmann
          else:
404 4f3d5b76 Michael Hanselmann
            condcmd = "if"
405 4f3d5b76 Michael Hanselmann
406 4f3d5b76 Michael Hanselmann
          sw.Write("""%s [[ %s ]]; then""", condcmd, cmpcode)
407 4f3d5b76 Michael Hanselmann
          sw.IncIndent()
408 4f3d5b76 Michael Hanselmann
          try:
409 4f3d5b76 Michael Hanselmann
            if choices:
410 4f3d5b76 Michael Hanselmann
              sw.Write("""choices="$choices "%s""", choices)
411 4f3d5b76 Michael Hanselmann
            if compgenargs:
412 4f3d5b76 Michael Hanselmann
              sw.Write("compgenargs=%s", utils.ShellQuote(" ".join(compgenargs)))
413 4f3d5b76 Michael Hanselmann
          finally:
414 4f3d5b76 Michael Hanselmann
            sw.DecIndent()
415 4f3d5b76 Michael Hanselmann
416 4f3d5b76 Michael Hanselmann
          wrote_arg = True
417 4f3d5b76 Michael Hanselmann
418 4f3d5b76 Michael Hanselmann
      if wrote_arg:
419 4f3d5b76 Michael Hanselmann
        sw.Write("fi")
420 4f3d5b76 Michael Hanselmann
421 4f3d5b76 Michael Hanselmann
    if self.args:
422 4f3d5b76 Michael Hanselmann
      WriteCompReply(sw, """-W "$choices" $compgenargs""")
423 4f3d5b76 Michael Hanselmann
    else:
424 4f3d5b76 Michael Hanselmann
      # $compgenargs exists only if there are arguments
425 4f3d5b76 Michael Hanselmann
      WriteCompReply(sw, '-W "$choices"')
426 4f3d5b76 Michael Hanselmann
427 4f3d5b76 Michael Hanselmann
  def WriteTo(self, sw):
428 4f3d5b76 Michael Hanselmann
    self._FindFirstArgument(sw)
429 4f3d5b76 Michael Hanselmann
    self._CompleteOptionValues(sw)
430 4f3d5b76 Michael Hanselmann
    self._CompleteArguments(sw)
431 4f3d5b76 Michael Hanselmann
432 4f3d5b76 Michael Hanselmann
433 4f3d5b76 Michael Hanselmann
def WriteCompletion(sw, scriptname, funcname,
434 4f3d5b76 Michael Hanselmann
                    commands=None,
435 4f3d5b76 Michael Hanselmann
                    opts=None, args=None):
436 4f3d5b76 Michael Hanselmann
  """Writes the completion code for one command.
437 4f3d5b76 Michael Hanselmann
438 4f3d5b76 Michael Hanselmann
  @type sw: ShellWriter
439 4f3d5b76 Michael Hanselmann
  @param sw: Script writer
440 4f3d5b76 Michael Hanselmann
  @type scriptname: string
441 4f3d5b76 Michael Hanselmann
  @param scriptname: Name of command line program
442 4f3d5b76 Michael Hanselmann
  @type funcname: string
443 4f3d5b76 Michael Hanselmann
  @param funcname: Shell function name
444 4f3d5b76 Michael Hanselmann
  @type commands: list
445 4f3d5b76 Michael Hanselmann
  @param commands: List of all subcommands in this program
446 4f3d5b76 Michael Hanselmann
447 4f3d5b76 Michael Hanselmann
  """
448 4f3d5b76 Michael Hanselmann
  sw.Write("%s() {", funcname)
449 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
450 4f3d5b76 Michael Hanselmann
  try:
451 580ef58d Michael Hanselmann
    sw.Write("local "
452 632d5090 Michael Hanselmann
             ' cur="${COMP_WORDS[COMP_CWORD]}"'
453 580ef58d Michael Hanselmann
             ' prev="${COMP_WORDS[COMP_CWORD-1]}"'
454 d4b94fe8 Michael Hanselmann
             ' i first_arg_idx choices compgenargs arg_idx optcur')
455 580ef58d Michael Hanselmann
456 580ef58d Michael Hanselmann
    # Useful for debugging:
457 580ef58d Michael Hanselmann
    #sw.Write("echo cur=\"$cur\" prev=\"$prev\"")
458 580ef58d Michael Hanselmann
    #sw.Write("set | grep ^COMP_")
459 4f3d5b76 Michael Hanselmann
460 4f3d5b76 Michael Hanselmann
    sw.Write("COMPREPLY=()")
461 4f3d5b76 Michael Hanselmann
462 4f3d5b76 Michael Hanselmann
    if opts is not None and args is not None:
463 4f3d5b76 Michael Hanselmann
      assert not commands
464 4f3d5b76 Michael Hanselmann
      CompletionWriter(0, opts, args).WriteTo(sw)
465 4f3d5b76 Michael Hanselmann
466 4f3d5b76 Michael Hanselmann
    else:
467 4f3d5b76 Michael Hanselmann
      sw.Write("""if [[ "$COMP_CWORD" == 1 ]]; then""")
468 4f3d5b76 Michael Hanselmann
      sw.IncIndent()
469 4f3d5b76 Michael Hanselmann
      try:
470 4f3d5b76 Michael Hanselmann
        # Complete the command name
471 4f3d5b76 Michael Hanselmann
        WriteCompReply(sw,
472 4f3d5b76 Michael Hanselmann
                       ("-W %s" %
473 4f3d5b76 Michael Hanselmann
                        utils.ShellQuote(" ".join(sorted(commands.keys())))))
474 4f3d5b76 Michael Hanselmann
      finally:
475 4f3d5b76 Michael Hanselmann
        sw.DecIndent()
476 4f3d5b76 Michael Hanselmann
      sw.Write("fi")
477 4f3d5b76 Michael Hanselmann
478 4f3d5b76 Michael Hanselmann
      # We're doing options and arguments to commands
479 4f3d5b76 Michael Hanselmann
      sw.Write("""case "${COMP_WORDS[1]}" in""")
480 4f3d5b76 Michael Hanselmann
      for cmd, (_, argdef, optdef, _, _) in commands.iteritems():
481 4f3d5b76 Michael Hanselmann
        if not (argdef or optdef):
482 4f3d5b76 Michael Hanselmann
          continue
483 4f3d5b76 Michael Hanselmann
484 4f3d5b76 Michael Hanselmann
        # TODO: Group by arguments and options
485 4f3d5b76 Michael Hanselmann
        sw.Write("%s)", utils.ShellQuote(cmd))
486 4f3d5b76 Michael Hanselmann
        sw.IncIndent()
487 4f3d5b76 Michael Hanselmann
        try:
488 4f3d5b76 Michael Hanselmann
          CompletionWriter(1, optdef, argdef).WriteTo(sw)
489 4f3d5b76 Michael Hanselmann
        finally:
490 4f3d5b76 Michael Hanselmann
          sw.DecIndent()
491 4f3d5b76 Michael Hanselmann
492 4f3d5b76 Michael Hanselmann
        sw.Write(";;")
493 4f3d5b76 Michael Hanselmann
      sw.Write("esac")
494 4f3d5b76 Michael Hanselmann
  finally:
495 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
496 4f3d5b76 Michael Hanselmann
  sw.Write("}")
497 4f3d5b76 Michael Hanselmann
498 4f3d5b76 Michael Hanselmann
  sw.Write("complete -F %s -o filenames %s",
499 4f3d5b76 Michael Hanselmann
           utils.ShellQuote(funcname),
500 4f3d5b76 Michael Hanselmann
           utils.ShellQuote(scriptname))
501 4f3d5b76 Michael Hanselmann
502 4f3d5b76 Michael Hanselmann
503 4f3d5b76 Michael Hanselmann
def GetFunctionName(name):
504 4f3d5b76 Michael Hanselmann
  return "_" + re.sub(r"[^a-z0-9]+", "_", name.lower())
505 4f3d5b76 Michael Hanselmann
506 4f3d5b76 Michael Hanselmann
507 4f3d5b76 Michael Hanselmann
def LoadModule(filename):
508 4f3d5b76 Michael Hanselmann
  """Loads an external module by filename.
509 4f3d5b76 Michael Hanselmann
510 4f3d5b76 Michael Hanselmann
  """
511 4f3d5b76 Michael Hanselmann
  (name, ext) = os.path.splitext(filename)
512 4f3d5b76 Michael Hanselmann
513 4f3d5b76 Michael Hanselmann
  fh = open(filename, "U")
514 4f3d5b76 Michael Hanselmann
  try:
515 4f3d5b76 Michael Hanselmann
    return imp.load_module(name, fh, filename, (ext, "U", imp.PY_SOURCE))
516 4f3d5b76 Michael Hanselmann
  finally:
517 4f3d5b76 Michael Hanselmann
    fh.close()
518 4f3d5b76 Michael Hanselmann
519 4f3d5b76 Michael Hanselmann
520 4f3d5b76 Michael Hanselmann
def GetCommands(filename, module):
521 4f3d5b76 Michael Hanselmann
  """Returns the commands defined in a module.
522 4f3d5b76 Michael Hanselmann
523 4f3d5b76 Michael Hanselmann
  Aliases are also added as commands.
524 4f3d5b76 Michael Hanselmann
525 4f3d5b76 Michael Hanselmann
  """
526 4f3d5b76 Michael Hanselmann
  try:
527 4f3d5b76 Michael Hanselmann
    commands = getattr(module, "commands")
528 4f3d5b76 Michael Hanselmann
  except AttributeError, err:
529 4f3d5b76 Michael Hanselmann
    raise Exception("Script %s doesn't have 'commands' attribute" %
530 4f3d5b76 Michael Hanselmann
                    filename)
531 4f3d5b76 Michael Hanselmann
532 4f3d5b76 Michael Hanselmann
  # Use aliases
533 4f3d5b76 Michael Hanselmann
  aliases = getattr(module, "aliases", {})
534 4f3d5b76 Michael Hanselmann
  if aliases:
535 4f3d5b76 Michael Hanselmann
    commands = commands.copy()
536 4f3d5b76 Michael Hanselmann
    for name, target in aliases.iteritems():
537 4f3d5b76 Michael Hanselmann
      commands[name] = commands[target]
538 4f3d5b76 Michael Hanselmann
539 4f3d5b76 Michael Hanselmann
  return commands
540 4f3d5b76 Michael Hanselmann
541 4f3d5b76 Michael Hanselmann
542 4f3d5b76 Michael Hanselmann
def main():
543 4f3d5b76 Michael Hanselmann
  buf = StringIO()
544 4f3d5b76 Michael Hanselmann
  sw = ShellWriter(buf)
545 4f3d5b76 Michael Hanselmann
546 4f3d5b76 Michael Hanselmann
  WritePreamble(sw)
547 4f3d5b76 Michael Hanselmann
548 4f3d5b76 Michael Hanselmann
  # gnt-* scripts
549 4f3d5b76 Michael Hanselmann
  for scriptname in _autoconf.GNT_SCRIPTS:
550 4f3d5b76 Michael Hanselmann
    filename = "scripts/%s" % scriptname
551 4f3d5b76 Michael Hanselmann
552 4f3d5b76 Michael Hanselmann
    WriteCompletion(sw, scriptname,
553 4f3d5b76 Michael Hanselmann
                    GetFunctionName(scriptname),
554 4f3d5b76 Michael Hanselmann
                    commands=GetCommands(filename, LoadModule(filename)))
555 4f3d5b76 Michael Hanselmann
556 4f3d5b76 Michael Hanselmann
  # Burnin script
557 4f3d5b76 Michael Hanselmann
  burnin = LoadModule("tools/burnin")
558 4f3d5b76 Michael Hanselmann
  WriteCompletion(sw, "%s/burnin" % constants.TOOLSDIR, "_ganeti_burnin",
559 4f3d5b76 Michael Hanselmann
                  opts=burnin.OPTIONS, args=burnin.ARGUMENTS)
560 4f3d5b76 Michael Hanselmann
561 4f3d5b76 Michael Hanselmann
  print buf.getvalue()
562 4f3d5b76 Michael Hanselmann
563 4f3d5b76 Michael Hanselmann
564 4f3d5b76 Michael Hanselmann
if __name__ == "__main__":
565 4f3d5b76 Michael Hanselmann
  main()