Statistics
| Branch: | Tag: | Revision:

root / autotools / build-bash-completion @ 5431eff1

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