Statistics
| Branch: | Tag: | Revision:

root / autotools / build-bash-completion @ 580ef58d

History | View | Annotate | Download (13.5 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 4f3d5b76 Michael Hanselmann
def WriteCompReply(sw, args):
187 4f3d5b76 Michael Hanselmann
  sw.Write("""COMPREPLY=( $(compgen %s -- "$cur") )""", args)
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 4f3d5b76 Michael Hanselmann
      sw.Write("""case "$prev" in""")
261 4f3d5b76 Michael Hanselmann
      for (choices, names) in values.iteritems():
262 4f3d5b76 Michael Hanselmann
        # TODO: Implement completion for --foo=bar form
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 4f3d5b76 Michael Hanselmann
  def _CompleteArguments(self, sw):
276 4f3d5b76 Michael Hanselmann
    if not (self.opts or self.args):
277 4f3d5b76 Michael Hanselmann
      return
278 4f3d5b76 Michael Hanselmann
279 4f3d5b76 Michael Hanselmann
    all_option_names = []
280 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
281 4f3d5b76 Michael Hanselmann
      all_option_names.extend(opt.all_names)
282 4f3d5b76 Michael Hanselmann
    all_option_names.sort()
283 4f3d5b76 Michael Hanselmann
284 4f3d5b76 Michael Hanselmann
    # List options if no argument has been specified yet
285 4f3d5b76 Michael Hanselmann
    sw.Write("_ganeti_list_options %s",
286 4f3d5b76 Michael Hanselmann
             utils.ShellQuote(" ".join(all_option_names)))
287 4f3d5b76 Michael Hanselmann
288 4f3d5b76 Michael Hanselmann
    if self.args:
289 4f3d5b76 Michael Hanselmann
      last_idx = len(self.args) - 1
290 4f3d5b76 Michael Hanselmann
      last_arg_end = 0
291 4f3d5b76 Michael Hanselmann
      varlen_arg_idx = None
292 4f3d5b76 Michael Hanselmann
      wrote_arg = False
293 4f3d5b76 Michael Hanselmann
294 4f3d5b76 Michael Hanselmann
      # Write some debug comments
295 4f3d5b76 Michael Hanselmann
      for idx, arg in enumerate(self.args):
296 4f3d5b76 Michael Hanselmann
        sw.Write("# %s: %r", idx, arg)
297 4f3d5b76 Michael Hanselmann
298 4f3d5b76 Michael Hanselmann
      sw.Write("compgenargs=")
299 4f3d5b76 Michael Hanselmann
300 4f3d5b76 Michael Hanselmann
      for idx, arg in enumerate(self.args):
301 4f3d5b76 Michael Hanselmann
        assert arg.min is not None and arg.min >= 0
302 4f3d5b76 Michael Hanselmann
        assert not (idx < last_idx and arg.max is None)
303 4f3d5b76 Michael Hanselmann
304 4f3d5b76 Michael Hanselmann
        if arg.min != arg.max or arg.max is None:
305 4f3d5b76 Michael Hanselmann
          if varlen_arg_idx is not None:
306 4f3d5b76 Michael Hanselmann
            raise Exception("Only one argument can have a variable length")
307 4f3d5b76 Michael Hanselmann
          varlen_arg_idx = idx
308 4f3d5b76 Michael Hanselmann
309 4f3d5b76 Michael Hanselmann
        compgenargs = []
310 4f3d5b76 Michael Hanselmann
311 4f3d5b76 Michael Hanselmann
        if isinstance(arg, cli.ArgUnknown):
312 4f3d5b76 Michael Hanselmann
          choices = ""
313 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgSuggest):
314 4f3d5b76 Michael Hanselmann
          choices = utils.ShellQuote(" ".join(arg.choices))
315 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgInstance):
316 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_instances)"
317 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgNode):
318 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_nodes)"
319 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgJobId):
320 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_jobs)"
321 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgFile):
322 4f3d5b76 Michael Hanselmann
          choices = ""
323 4f3d5b76 Michael Hanselmann
          compgenargs.append("-f")
324 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgCommand):
325 4f3d5b76 Michael Hanselmann
          choices = ""
326 4f3d5b76 Michael Hanselmann
          compgenargs.append("-c")
327 83ec7961 Michael Hanselmann
        elif isinstance(arg, cli.ArgHost):
328 83ec7961 Michael Hanselmann
          choices = ""
329 83ec7961 Michael Hanselmann
          compgenargs.append("-A hostname")
330 4f3d5b76 Michael Hanselmann
        else:
331 4f3d5b76 Michael Hanselmann
          raise Exception("Unknown argument type %r" % arg)
332 4f3d5b76 Michael Hanselmann
333 4f3d5b76 Michael Hanselmann
        if arg.min == 1 and arg.max == 1:
334 4f3d5b76 Michael Hanselmann
          cmpcode = """"$arg_idx" == %d""" % (last_arg_end)
335 5431eff1 Michael Hanselmann
        elif arg.min <= arg.max:
336 4f3d5b76 Michael Hanselmann
          cmpcode = (""""$arg_idx" -ge %d && "$arg_idx" -lt %d""" %
337 4f3d5b76 Michael Hanselmann
                     (last_arg_end, last_arg_end + arg.max))
338 4f3d5b76 Michael Hanselmann
        elif arg.max is None:
339 4f3d5b76 Michael Hanselmann
          cmpcode = """"$arg_idx" -ge %d""" % (last_arg_end)
340 4f3d5b76 Michael Hanselmann
        else:
341 4f3d5b76 Michael Hanselmann
          raise Exception("Unable to generate argument position condition")
342 4f3d5b76 Michael Hanselmann
343 4f3d5b76 Michael Hanselmann
        last_arg_end += arg.min
344 4f3d5b76 Michael Hanselmann
345 4f3d5b76 Michael Hanselmann
        if choices or compgenargs:
346 4f3d5b76 Michael Hanselmann
          if wrote_arg:
347 4f3d5b76 Michael Hanselmann
            condcmd = "elif"
348 4f3d5b76 Michael Hanselmann
          else:
349 4f3d5b76 Michael Hanselmann
            condcmd = "if"
350 4f3d5b76 Michael Hanselmann
351 4f3d5b76 Michael Hanselmann
          sw.Write("""%s [[ %s ]]; then""", condcmd, cmpcode)
352 4f3d5b76 Michael Hanselmann
          sw.IncIndent()
353 4f3d5b76 Michael Hanselmann
          try:
354 4f3d5b76 Michael Hanselmann
            if choices:
355 4f3d5b76 Michael Hanselmann
              sw.Write("""choices="$choices "%s""", choices)
356 4f3d5b76 Michael Hanselmann
            if compgenargs:
357 4f3d5b76 Michael Hanselmann
              sw.Write("compgenargs=%s", utils.ShellQuote(" ".join(compgenargs)))
358 4f3d5b76 Michael Hanselmann
          finally:
359 4f3d5b76 Michael Hanselmann
            sw.DecIndent()
360 4f3d5b76 Michael Hanselmann
361 4f3d5b76 Michael Hanselmann
          wrote_arg = True
362 4f3d5b76 Michael Hanselmann
363 4f3d5b76 Michael Hanselmann
      if wrote_arg:
364 4f3d5b76 Michael Hanselmann
        sw.Write("fi")
365 4f3d5b76 Michael Hanselmann
366 4f3d5b76 Michael Hanselmann
    if self.args:
367 4f3d5b76 Michael Hanselmann
      WriteCompReply(sw, """-W "$choices" $compgenargs""")
368 4f3d5b76 Michael Hanselmann
    else:
369 4f3d5b76 Michael Hanselmann
      # $compgenargs exists only if there are arguments
370 4f3d5b76 Michael Hanselmann
      WriteCompReply(sw, '-W "$choices"')
371 4f3d5b76 Michael Hanselmann
372 4f3d5b76 Michael Hanselmann
  def WriteTo(self, sw):
373 4f3d5b76 Michael Hanselmann
    self._FindFirstArgument(sw)
374 4f3d5b76 Michael Hanselmann
    self._CompleteOptionValues(sw)
375 4f3d5b76 Michael Hanselmann
    self._CompleteArguments(sw)
376 4f3d5b76 Michael Hanselmann
377 4f3d5b76 Michael Hanselmann
378 4f3d5b76 Michael Hanselmann
def WriteCompletion(sw, scriptname, funcname,
379 4f3d5b76 Michael Hanselmann
                    commands=None,
380 4f3d5b76 Michael Hanselmann
                    opts=None, args=None):
381 4f3d5b76 Michael Hanselmann
  """Writes the completion code for one command.
382 4f3d5b76 Michael Hanselmann
383 4f3d5b76 Michael Hanselmann
  @type sw: ShellWriter
384 4f3d5b76 Michael Hanselmann
  @param sw: Script writer
385 4f3d5b76 Michael Hanselmann
  @type scriptname: string
386 4f3d5b76 Michael Hanselmann
  @param scriptname: Name of command line program
387 4f3d5b76 Michael Hanselmann
  @type funcname: string
388 4f3d5b76 Michael Hanselmann
  @param funcname: Shell function name
389 4f3d5b76 Michael Hanselmann
  @type commands: list
390 4f3d5b76 Michael Hanselmann
  @param commands: List of all subcommands in this program
391 4f3d5b76 Michael Hanselmann
392 4f3d5b76 Michael Hanselmann
  """
393 4f3d5b76 Michael Hanselmann
  sw.Write("%s() {", funcname)
394 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
395 4f3d5b76 Michael Hanselmann
  try:
396 580ef58d Michael Hanselmann
    sw.Write("local "
397 580ef58d Michael Hanselmann
             ' cur="${COMP_WORDS[$COMP_CWORD]}"'
398 580ef58d Michael Hanselmann
             ' prev="${COMP_WORDS[COMP_CWORD-1]}"'
399 580ef58d Michael Hanselmann
             ' i first_arg_idx choices compgenargs arg_idx')
400 580ef58d Michael Hanselmann
401 580ef58d Michael Hanselmann
    # Useful for debugging:
402 580ef58d Michael Hanselmann
    #sw.Write("echo cur=\"$cur\" prev=\"$prev\"")
403 580ef58d Michael Hanselmann
    #sw.Write("set | grep ^COMP_")
404 4f3d5b76 Michael Hanselmann
405 4f3d5b76 Michael Hanselmann
    sw.Write("COMPREPLY=()")
406 4f3d5b76 Michael Hanselmann
407 4f3d5b76 Michael Hanselmann
    if opts is not None and args is not None:
408 4f3d5b76 Michael Hanselmann
      assert not commands
409 4f3d5b76 Michael Hanselmann
      CompletionWriter(0, opts, args).WriteTo(sw)
410 4f3d5b76 Michael Hanselmann
411 4f3d5b76 Michael Hanselmann
    else:
412 4f3d5b76 Michael Hanselmann
      sw.Write("""if [[ "$COMP_CWORD" == 1 ]]; then""")
413 4f3d5b76 Michael Hanselmann
      sw.IncIndent()
414 4f3d5b76 Michael Hanselmann
      try:
415 4f3d5b76 Michael Hanselmann
        # Complete the command name
416 4f3d5b76 Michael Hanselmann
        WriteCompReply(sw,
417 4f3d5b76 Michael Hanselmann
                       ("-W %s" %
418 4f3d5b76 Michael Hanselmann
                        utils.ShellQuote(" ".join(sorted(commands.keys())))))
419 4f3d5b76 Michael Hanselmann
      finally:
420 4f3d5b76 Michael Hanselmann
        sw.DecIndent()
421 4f3d5b76 Michael Hanselmann
      sw.Write("fi")
422 4f3d5b76 Michael Hanselmann
423 4f3d5b76 Michael Hanselmann
      # We're doing options and arguments to commands
424 4f3d5b76 Michael Hanselmann
      sw.Write("""case "${COMP_WORDS[1]}" in""")
425 4f3d5b76 Michael Hanselmann
      for cmd, (_, argdef, optdef, _, _) in commands.iteritems():
426 4f3d5b76 Michael Hanselmann
        if not (argdef or optdef):
427 4f3d5b76 Michael Hanselmann
          continue
428 4f3d5b76 Michael Hanselmann
429 4f3d5b76 Michael Hanselmann
        # TODO: Group by arguments and options
430 4f3d5b76 Michael Hanselmann
        sw.Write("%s)", utils.ShellQuote(cmd))
431 4f3d5b76 Michael Hanselmann
        sw.IncIndent()
432 4f3d5b76 Michael Hanselmann
        try:
433 4f3d5b76 Michael Hanselmann
          CompletionWriter(1, optdef, argdef).WriteTo(sw)
434 4f3d5b76 Michael Hanselmann
        finally:
435 4f3d5b76 Michael Hanselmann
          sw.DecIndent()
436 4f3d5b76 Michael Hanselmann
437 4f3d5b76 Michael Hanselmann
        sw.Write(";;")
438 4f3d5b76 Michael Hanselmann
      sw.Write("esac")
439 4f3d5b76 Michael Hanselmann
  finally:
440 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
441 4f3d5b76 Michael Hanselmann
  sw.Write("}")
442 4f3d5b76 Michael Hanselmann
443 4f3d5b76 Michael Hanselmann
  sw.Write("complete -F %s -o filenames %s",
444 4f3d5b76 Michael Hanselmann
           utils.ShellQuote(funcname),
445 4f3d5b76 Michael Hanselmann
           utils.ShellQuote(scriptname))
446 4f3d5b76 Michael Hanselmann
447 4f3d5b76 Michael Hanselmann
448 4f3d5b76 Michael Hanselmann
def GetFunctionName(name):
449 4f3d5b76 Michael Hanselmann
  return "_" + re.sub(r"[^a-z0-9]+", "_", name.lower())
450 4f3d5b76 Michael Hanselmann
451 4f3d5b76 Michael Hanselmann
452 4f3d5b76 Michael Hanselmann
def LoadModule(filename):
453 4f3d5b76 Michael Hanselmann
  """Loads an external module by filename.
454 4f3d5b76 Michael Hanselmann
455 4f3d5b76 Michael Hanselmann
  """
456 4f3d5b76 Michael Hanselmann
  (name, ext) = os.path.splitext(filename)
457 4f3d5b76 Michael Hanselmann
458 4f3d5b76 Michael Hanselmann
  fh = open(filename, "U")
459 4f3d5b76 Michael Hanselmann
  try:
460 4f3d5b76 Michael Hanselmann
    return imp.load_module(name, fh, filename, (ext, "U", imp.PY_SOURCE))
461 4f3d5b76 Michael Hanselmann
  finally:
462 4f3d5b76 Michael Hanselmann
    fh.close()
463 4f3d5b76 Michael Hanselmann
464 4f3d5b76 Michael Hanselmann
465 4f3d5b76 Michael Hanselmann
def GetCommands(filename, module):
466 4f3d5b76 Michael Hanselmann
  """Returns the commands defined in a module.
467 4f3d5b76 Michael Hanselmann
468 4f3d5b76 Michael Hanselmann
  Aliases are also added as commands.
469 4f3d5b76 Michael Hanselmann
470 4f3d5b76 Michael Hanselmann
  """
471 4f3d5b76 Michael Hanselmann
  try:
472 4f3d5b76 Michael Hanselmann
    commands = getattr(module, "commands")
473 4f3d5b76 Michael Hanselmann
  except AttributeError, err:
474 4f3d5b76 Michael Hanselmann
    raise Exception("Script %s doesn't have 'commands' attribute" %
475 4f3d5b76 Michael Hanselmann
                    filename)
476 4f3d5b76 Michael Hanselmann
477 4f3d5b76 Michael Hanselmann
  # Use aliases
478 4f3d5b76 Michael Hanselmann
  aliases = getattr(module, "aliases", {})
479 4f3d5b76 Michael Hanselmann
  if aliases:
480 4f3d5b76 Michael Hanselmann
    commands = commands.copy()
481 4f3d5b76 Michael Hanselmann
    for name, target in aliases.iteritems():
482 4f3d5b76 Michael Hanselmann
      commands[name] = commands[target]
483 4f3d5b76 Michael Hanselmann
484 4f3d5b76 Michael Hanselmann
  return commands
485 4f3d5b76 Michael Hanselmann
486 4f3d5b76 Michael Hanselmann
487 4f3d5b76 Michael Hanselmann
def main():
488 4f3d5b76 Michael Hanselmann
  buf = StringIO()
489 4f3d5b76 Michael Hanselmann
  sw = ShellWriter(buf)
490 4f3d5b76 Michael Hanselmann
491 4f3d5b76 Michael Hanselmann
  WritePreamble(sw)
492 4f3d5b76 Michael Hanselmann
493 4f3d5b76 Michael Hanselmann
  # gnt-* scripts
494 4f3d5b76 Michael Hanselmann
  for scriptname in _autoconf.GNT_SCRIPTS:
495 4f3d5b76 Michael Hanselmann
    filename = "scripts/%s" % scriptname
496 4f3d5b76 Michael Hanselmann
497 4f3d5b76 Michael Hanselmann
    WriteCompletion(sw, scriptname,
498 4f3d5b76 Michael Hanselmann
                    GetFunctionName(scriptname),
499 4f3d5b76 Michael Hanselmann
                    commands=GetCommands(filename, LoadModule(filename)))
500 4f3d5b76 Michael Hanselmann
501 4f3d5b76 Michael Hanselmann
  # Burnin script
502 4f3d5b76 Michael Hanselmann
  burnin = LoadModule("tools/burnin")
503 4f3d5b76 Michael Hanselmann
  WriteCompletion(sw, "%s/burnin" % constants.TOOLSDIR, "_ganeti_burnin",
504 4f3d5b76 Michael Hanselmann
                  opts=burnin.OPTIONS, args=burnin.ARGUMENTS)
505 4f3d5b76 Michael Hanselmann
506 4f3d5b76 Michael Hanselmann
  print buf.getvalue()
507 4f3d5b76 Michael Hanselmann
508 4f3d5b76 Michael Hanselmann
509 4f3d5b76 Michael Hanselmann
if __name__ == "__main__":
510 4f3d5b76 Michael Hanselmann
  main()