Statistics
| Branch: | Tag: | Revision:

root / autotools / build-bash-completion @ 632d5090

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