Statistics
| Branch: | Tag: | Revision:

root / autotools / build-bash-completion @ 858905fb

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