Statistics
| Branch: | Tag: | Revision:

root / autotools / build-bash-completion @ fad06963

History | View | Annotate | Download (23.2 kB)

1 4f3d5b76 Michael Hanselmann
#!/usr/bin/python
2 4f3d5b76 Michael Hanselmann
#
3 4f3d5b76 Michael Hanselmann
4 f5ce7613 Iustin Pop
# Copyright (C) 2009, 2010, 2011, 2012 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 b459a848 Andrea Spadaccini
# pylint: disable=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 49283373 Michael Hanselmann
import itertools
32 e80aeb89 Michael Hanselmann
import optparse
33 4f3d5b76 Michael Hanselmann
from cStringIO import StringIO
34 4f3d5b76 Michael Hanselmann
35 4f3d5b76 Michael Hanselmann
from ganeti import constants
36 4f3d5b76 Michael Hanselmann
from ganeti import cli
37 4f3d5b76 Michael Hanselmann
from ganeti import utils
38 e948770c Michael Hanselmann
from ganeti import build
39 13718ded Michael Hanselmann
from ganeti import pathutils
40 4f3d5b76 Michael Hanselmann
41 4f3d5b76 Michael Hanselmann
# _autoconf shouldn't be imported from anywhere except constants.py, but we're
42 4f3d5b76 Michael Hanselmann
# making an exception here because this script is only used at build time.
43 4f3d5b76 Michael Hanselmann
from ganeti import _autoconf
44 4f3d5b76 Michael Hanselmann
45 49283373 Michael Hanselmann
#: Regular expression describing desired format of option names. Long names can
46 49283373 Michael Hanselmann
#: contain lowercase characters, numbers and dashes only.
47 49283373 Michael Hanselmann
_OPT_NAME_RE = re.compile(r"^-[a-zA-Z0-9]|--[a-z][-a-z0-9]+$")
48 49283373 Michael Hanselmann
49 4f3d5b76 Michael Hanselmann
50 e80aeb89 Michael Hanselmann
def WritePreamble(sw, support_debug):
51 4f3d5b76 Michael Hanselmann
  """Writes the script preamble.
52 4f3d5b76 Michael Hanselmann
53 4f3d5b76 Michael Hanselmann
  Helper functions should be written here.
54 4f3d5b76 Michael Hanselmann
55 4f3d5b76 Michael Hanselmann
  """
56 4f3d5b76 Michael Hanselmann
  sw.Write("# This script is automatically generated at build time.")
57 4f3d5b76 Michael Hanselmann
  sw.Write("# Do not modify manually.")
58 4f3d5b76 Michael Hanselmann
59 e80aeb89 Michael Hanselmann
  if support_debug:
60 e80aeb89 Michael Hanselmann
    sw.Write("_gnt_log() {")
61 5b0ca9d4 Michael Hanselmann
    sw.IncIndent()
62 5b0ca9d4 Michael Hanselmann
    try:
63 e80aeb89 Michael Hanselmann
      sw.Write("if [[ -n \"$GANETI_COMPL_LOG\" ]]; then")
64 5b0ca9d4 Michael Hanselmann
      sw.IncIndent()
65 5b0ca9d4 Michael Hanselmann
      try:
66 e80aeb89 Michael Hanselmann
        sw.Write("{")
67 e80aeb89 Michael Hanselmann
        sw.IncIndent()
68 e80aeb89 Michael Hanselmann
        try:
69 e80aeb89 Michael Hanselmann
          sw.Write("echo ---")
70 e80aeb89 Michael Hanselmann
          sw.Write("echo \"$@\"")
71 e80aeb89 Michael Hanselmann
          sw.Write("echo")
72 e80aeb89 Michael Hanselmann
        finally:
73 e80aeb89 Michael Hanselmann
          sw.DecIndent()
74 e80aeb89 Michael Hanselmann
        sw.Write("} >> $GANETI_COMPL_LOG")
75 5b0ca9d4 Michael Hanselmann
      finally:
76 5b0ca9d4 Michael Hanselmann
        sw.DecIndent()
77 e80aeb89 Michael Hanselmann
      sw.Write("fi")
78 5b0ca9d4 Michael Hanselmann
    finally:
79 5b0ca9d4 Michael Hanselmann
      sw.DecIndent()
80 e80aeb89 Michael Hanselmann
    sw.Write("}")
81 5b0ca9d4 Michael Hanselmann
82 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_nodes() {")
83 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
84 4f3d5b76 Michael Hanselmann
  try:
85 13718ded Michael Hanselmann
    node_list_path = os.path.join(pathutils.DATA_DIR, "ssconf_node_list")
86 5a78e2e7 Michael Hanselmann
    sw.Write("cat %s 2>/dev/null || :", utils.ShellQuote(node_list_path))
87 4f3d5b76 Michael Hanselmann
  finally:
88 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
89 4f3d5b76 Michael Hanselmann
  sw.Write("}")
90 4f3d5b76 Michael Hanselmann
91 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_instances() {")
92 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
93 4f3d5b76 Michael Hanselmann
  try:
94 13718ded Michael Hanselmann
    instance_list_path = os.path.join(pathutils.DATA_DIR,
95 4f3d5b76 Michael Hanselmann
                                      "ssconf_instance_list")
96 5a78e2e7 Michael Hanselmann
    sw.Write("cat %s 2>/dev/null || :", utils.ShellQuote(instance_list_path))
97 4f3d5b76 Michael Hanselmann
  finally:
98 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
99 4f3d5b76 Michael Hanselmann
  sw.Write("}")
100 4f3d5b76 Michael Hanselmann
101 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_jobs() {")
102 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
103 4f3d5b76 Michael Hanselmann
  try:
104 4f3d5b76 Michael Hanselmann
    # FIXME: this is really going into the internals of the job queue
105 5a78e2e7 Michael Hanselmann
    sw.Write(("local jlist=$( shopt -s nullglob &&"
106 5a78e2e7 Michael Hanselmann
              " cd %s 2>/dev/null && echo job-* || : )"),
107 13718ded Michael Hanselmann
             utils.ShellQuote(pathutils.QUEUE_DIR))
108 5a78e2e7 Michael Hanselmann
    sw.Write('echo "${jlist//job-/}"')
109 4f3d5b76 Michael Hanselmann
  finally:
110 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
111 4f3d5b76 Michael Hanselmann
  sw.Write("}")
112 4f3d5b76 Michael Hanselmann
113 30d44392 Michael Hanselmann
  for (fnname, paths) in [
114 13718ded Michael Hanselmann
    ("os", pathutils.OS_SEARCH_PATH),
115 5ae4945a Iustin Pop
    ("iallocator", constants.IALLOCATOR_SEARCH_PATH),
116 5ae4945a Iustin Pop
    ]:
117 30d44392 Michael Hanselmann
    sw.Write("_ganeti_%s() {", fnname)
118 30d44392 Michael Hanselmann
    sw.IncIndent()
119 30d44392 Michael Hanselmann
    try:
120 30d44392 Michael Hanselmann
      # FIXME: Make querying the master for all OSes cheap
121 30d44392 Michael Hanselmann
      for path in paths:
122 30d44392 Michael Hanselmann
        sw.Write("( shopt -s nullglob && cd %s 2>/dev/null && echo * || : )",
123 30d44392 Michael Hanselmann
                 utils.ShellQuote(path))
124 30d44392 Michael Hanselmann
    finally:
125 30d44392 Michael Hanselmann
      sw.DecIndent()
126 30d44392 Michael Hanselmann
    sw.Write("}")
127 4f3d5b76 Michael Hanselmann
128 36e247e1 Guido Trotter
  sw.Write("_ganeti_nodegroup() {")
129 36e247e1 Guido Trotter
  sw.IncIndent()
130 36e247e1 Guido Trotter
  try:
131 13718ded Michael Hanselmann
    nodegroups_path = os.path.join(pathutils.DATA_DIR, "ssconf_nodegroups")
132 36e247e1 Guido Trotter
    sw.Write("cat %s 2>/dev/null || :", utils.ShellQuote(nodegroups_path))
133 36e247e1 Guido Trotter
  finally:
134 36e247e1 Guido Trotter
    sw.DecIndent()
135 36e247e1 Guido Trotter
  sw.Write("}")
136 36e247e1 Guido Trotter
137 4f3d5b76 Michael Hanselmann
  # Params: <offset> <options with values> <options without values>
138 4f3d5b76 Michael Hanselmann
  # Result variable: $first_arg_idx
139 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_find_first_arg() {")
140 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
141 4f3d5b76 Michael Hanselmann
  try:
142 4f3d5b76 Michael Hanselmann
    sw.Write("local w i")
143 4f3d5b76 Michael Hanselmann
144 4f3d5b76 Michael Hanselmann
    sw.Write("first_arg_idx=")
145 4f3d5b76 Michael Hanselmann
    sw.Write("for (( i=$1; i < COMP_CWORD; ++i )); do")
146 4f3d5b76 Michael Hanselmann
    sw.IncIndent()
147 4f3d5b76 Michael Hanselmann
    try:
148 4f3d5b76 Michael Hanselmann
      sw.Write("w=${COMP_WORDS[$i]}")
149 4f3d5b76 Michael Hanselmann
150 4f3d5b76 Michael Hanselmann
      # Skip option value
151 4f3d5b76 Michael Hanselmann
      sw.Write("""if [[ -n "$2" && "$w" == @($2) ]]; then let ++i""")
152 4f3d5b76 Michael Hanselmann
153 4f3d5b76 Michael Hanselmann
      # Skip
154 4f3d5b76 Michael Hanselmann
      sw.Write("""elif [[ -n "$3" && "$w" == @($3) ]]; then :""")
155 4f3d5b76 Michael Hanselmann
156 4f3d5b76 Michael Hanselmann
      # Ah, we found the first argument
157 4f3d5b76 Michael Hanselmann
      sw.Write("else first_arg_idx=$i; break;")
158 4f3d5b76 Michael Hanselmann
      sw.Write("fi")
159 4f3d5b76 Michael Hanselmann
    finally:
160 4f3d5b76 Michael Hanselmann
      sw.DecIndent()
161 4f3d5b76 Michael Hanselmann
    sw.Write("done")
162 4f3d5b76 Michael Hanselmann
  finally:
163 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
164 4f3d5b76 Michael Hanselmann
  sw.Write("}")
165 4f3d5b76 Michael Hanselmann
166 4f3d5b76 Michael Hanselmann
  # Params: <list of options separated by space>
167 4f3d5b76 Michael Hanselmann
  # Input variable: $first_arg_idx
168 4f3d5b76 Michael Hanselmann
  # Result variables: $arg_idx, $choices
169 4f3d5b76 Michael Hanselmann
  sw.Write("_ganeti_list_options() {")
170 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
171 4f3d5b76 Michael Hanselmann
  try:
172 4f3d5b76 Michael Hanselmann
    sw.Write("""if [[ -z "$first_arg_idx" ]]; then""")
173 4f3d5b76 Michael Hanselmann
    sw.IncIndent()
174 4f3d5b76 Michael Hanselmann
    try:
175 4f3d5b76 Michael Hanselmann
      sw.Write("arg_idx=0")
176 4f3d5b76 Michael Hanselmann
      # Show options only if the current word starts with a dash
177 4f3d5b76 Michael Hanselmann
      sw.Write("""if [[ "$cur" == -* ]]; then""")
178 4f3d5b76 Michael Hanselmann
      sw.IncIndent()
179 4f3d5b76 Michael Hanselmann
      try:
180 4f3d5b76 Michael Hanselmann
        sw.Write("choices=$1")
181 4f3d5b76 Michael Hanselmann
      finally:
182 4f3d5b76 Michael Hanselmann
        sw.DecIndent()
183 4f3d5b76 Michael Hanselmann
      sw.Write("fi")
184 4f3d5b76 Michael Hanselmann
      sw.Write("return")
185 4f3d5b76 Michael Hanselmann
    finally:
186 4f3d5b76 Michael Hanselmann
      sw.DecIndent()
187 4f3d5b76 Michael Hanselmann
    sw.Write("fi")
188 4f3d5b76 Michael Hanselmann
189 4f3d5b76 Michael Hanselmann
    # Calculate position of current argument
190 4f3d5b76 Michael Hanselmann
    sw.Write("arg_idx=$(( COMP_CWORD - first_arg_idx ))")
191 4f3d5b76 Michael Hanselmann
    sw.Write("choices=")
192 4f3d5b76 Michael Hanselmann
  finally:
193 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
194 4f3d5b76 Michael Hanselmann
  sw.Write("}")
195 4f3d5b76 Michael Hanselmann
196 d4b94fe8 Michael Hanselmann
  # Params: <long options with equal sign> <all options>
197 d4b94fe8 Michael Hanselmann
  # Result variable: $optcur
198 3db199ea Michael Hanselmann
  sw.Write("_gnt_checkopt() {")
199 d4b94fe8 Michael Hanselmann
  sw.IncIndent()
200 d4b94fe8 Michael Hanselmann
  try:
201 d4b94fe8 Michael Hanselmann
    sw.Write("""if [[ -n "$1" && "$cur" == @($1) ]]; then""")
202 d4b94fe8 Michael Hanselmann
    sw.IncIndent()
203 d4b94fe8 Michael Hanselmann
    try:
204 d4b94fe8 Michael Hanselmann
      sw.Write("optcur=\"${cur#--*=}\"")
205 d4b94fe8 Michael Hanselmann
      sw.Write("return 0")
206 d4b94fe8 Michael Hanselmann
    finally:
207 d4b94fe8 Michael Hanselmann
      sw.DecIndent()
208 d4b94fe8 Michael Hanselmann
    sw.Write("""elif [[ -n "$2" && "$prev" == @($2) ]]; then""")
209 d4b94fe8 Michael Hanselmann
    sw.IncIndent()
210 d4b94fe8 Michael Hanselmann
    try:
211 d4b94fe8 Michael Hanselmann
      sw.Write("optcur=\"$cur\"")
212 d4b94fe8 Michael Hanselmann
      sw.Write("return 0")
213 d4b94fe8 Michael Hanselmann
    finally:
214 d4b94fe8 Michael Hanselmann
      sw.DecIndent()
215 d4b94fe8 Michael Hanselmann
    sw.Write("fi")
216 d4b94fe8 Michael Hanselmann
217 e80aeb89 Michael Hanselmann
    if support_debug:
218 e80aeb89 Michael Hanselmann
      sw.Write("_gnt_log optcur=\"'$optcur'\"")
219 5b0ca9d4 Michael Hanselmann
220 d4b94fe8 Michael Hanselmann
    sw.Write("return 1")
221 d4b94fe8 Michael Hanselmann
  finally:
222 d4b94fe8 Michael Hanselmann
    sw.DecIndent()
223 d4b94fe8 Michael Hanselmann
  sw.Write("}")
224 d4b94fe8 Michael Hanselmann
225 a10caf87 Michael Hanselmann
  # Params: <compgen options>
226 a10caf87 Michael Hanselmann
  # Result variable: $COMPREPLY
227 3db199ea Michael Hanselmann
  sw.Write("_gnt_compgen() {")
228 a10caf87 Michael Hanselmann
  sw.IncIndent()
229 a10caf87 Michael Hanselmann
  try:
230 a10caf87 Michael Hanselmann
    sw.Write("""COMPREPLY=( $(compgen "$@") )""")
231 e80aeb89 Michael Hanselmann
    if support_debug:
232 e80aeb89 Michael Hanselmann
      sw.Write("_gnt_log COMPREPLY=\"${COMPREPLY[@]}\"")
233 a10caf87 Michael Hanselmann
  finally:
234 a10caf87 Michael Hanselmann
    sw.DecIndent()
235 a10caf87 Michael Hanselmann
  sw.Write("}")
236 a10caf87 Michael Hanselmann
237 4f3d5b76 Michael Hanselmann
238 632d5090 Michael Hanselmann
def WriteCompReply(sw, args, cur="\"$cur\""):
239 3db199ea Michael Hanselmann
  sw.Write("_gnt_compgen %s -- %s", args, cur)
240 4f3d5b76 Michael Hanselmann
  sw.Write("return")
241 4f3d5b76 Michael Hanselmann
242 4f3d5b76 Michael Hanselmann
243 4f3d5b76 Michael Hanselmann
class CompletionWriter:
244 4f3d5b76 Michael Hanselmann
  """Command completion writer class.
245 4f3d5b76 Michael Hanselmann
246 4f3d5b76 Michael Hanselmann
  """
247 e80aeb89 Michael Hanselmann
  def __init__(self, arg_offset, opts, args, support_debug):
248 4f3d5b76 Michael Hanselmann
    self.arg_offset = arg_offset
249 4f3d5b76 Michael Hanselmann
    self.opts = opts
250 4f3d5b76 Michael Hanselmann
    self.args = args
251 e80aeb89 Michael Hanselmann
    self.support_debug = support_debug
252 4f3d5b76 Michael Hanselmann
253 4f3d5b76 Michael Hanselmann
    for opt in opts:
254 f59418db Michael Hanselmann
      # While documented, these variables aren't seen as public attributes by
255 b459a848 Andrea Spadaccini
      # pylint. pylint: disable=W0212
256 4f3d5b76 Michael Hanselmann
      opt.all_names = sorted(opt._short_opts + opt._long_opts)
257 4f3d5b76 Michael Hanselmann
258 49283373 Michael Hanselmann
      invalid = list(itertools.ifilterfalse(_OPT_NAME_RE.match, opt.all_names))
259 49283373 Michael Hanselmann
      if invalid:
260 49283373 Michael Hanselmann
        raise Exception("Option names don't match regular expression '%s': %s" %
261 49283373 Michael Hanselmann
                        (_OPT_NAME_RE.pattern, utils.CommaJoin(invalid)))
262 49283373 Michael Hanselmann
263 4f3d5b76 Michael Hanselmann
  def _FindFirstArgument(self, sw):
264 4f3d5b76 Michael Hanselmann
    ignore = []
265 4f3d5b76 Michael Hanselmann
    skip_one = []
266 4f3d5b76 Michael Hanselmann
267 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
268 4f3d5b76 Michael Hanselmann
      if opt.takes_value():
269 4f3d5b76 Michael Hanselmann
        # Ignore value
270 4f3d5b76 Michael Hanselmann
        for i in opt.all_names:
271 580ef58d Michael Hanselmann
          if i.startswith("--"):
272 580ef58d Michael Hanselmann
            ignore.append("%s=*" % utils.ShellQuote(i))
273 4f3d5b76 Michael Hanselmann
          skip_one.append(utils.ShellQuote(i))
274 4f3d5b76 Michael Hanselmann
      else:
275 4f3d5b76 Michael Hanselmann
        ignore.extend([utils.ShellQuote(i) for i in opt.all_names])
276 4f3d5b76 Michael Hanselmann
277 4f3d5b76 Michael Hanselmann
    ignore = sorted(utils.UniqueSequence(ignore))
278 4f3d5b76 Michael Hanselmann
    skip_one = sorted(utils.UniqueSequence(skip_one))
279 4f3d5b76 Michael Hanselmann
280 4f3d5b76 Michael Hanselmann
    if ignore or skip_one:
281 4f3d5b76 Michael Hanselmann
      # Try to locate first argument
282 4f3d5b76 Michael Hanselmann
      sw.Write("_ganeti_find_first_arg %s %s %s",
283 4f3d5b76 Michael Hanselmann
               self.arg_offset + 1,
284 4f3d5b76 Michael Hanselmann
               utils.ShellQuote("|".join(skip_one)),
285 4f3d5b76 Michael Hanselmann
               utils.ShellQuote("|".join(ignore)))
286 4f3d5b76 Michael Hanselmann
    else:
287 4f3d5b76 Michael Hanselmann
      # When there are no options the first argument is always at position
288 4f3d5b76 Michael Hanselmann
      # offset + 1
289 4f3d5b76 Michael Hanselmann
      sw.Write("first_arg_idx=%s", self.arg_offset + 1)
290 4f3d5b76 Michael Hanselmann
291 4f3d5b76 Michael Hanselmann
  def _CompleteOptionValues(self, sw):
292 4f3d5b76 Michael Hanselmann
    # Group by values
293 4f3d5b76 Michael Hanselmann
    # "values" -> [optname1, optname2, ...]
294 4f3d5b76 Michael Hanselmann
    values = {}
295 4f3d5b76 Michael Hanselmann
296 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
297 4f3d5b76 Michael Hanselmann
      if not opt.takes_value():
298 4f3d5b76 Michael Hanselmann
        continue
299 4f3d5b76 Michael Hanselmann
300 4f3d5b76 Michael Hanselmann
      # Only static choices implemented so far (e.g. no node list)
301 4f3d5b76 Michael Hanselmann
      suggest = getattr(opt, "completion_suggest", None)
302 4f3d5b76 Michael Hanselmann
303 e7b61bb0 Iustin Pop
      # our custom option type
304 e7b61bb0 Iustin Pop
      if opt.type == "bool":
305 e7b61bb0 Iustin Pop
        suggest = ["yes", "no"]
306 e7b61bb0 Iustin Pop
307 4f3d5b76 Michael Hanselmann
      if not suggest:
308 4f3d5b76 Michael Hanselmann
        suggest = opt.choices
309 4f3d5b76 Michael Hanselmann
310 63d44c55 Michael Hanselmann
      if (isinstance(suggest, (int, long)) and
311 63d44c55 Michael Hanselmann
          suggest in cli.OPT_COMPL_ALL):
312 63d44c55 Michael Hanselmann
        key = suggest
313 63d44c55 Michael Hanselmann
      elif suggest:
314 63d44c55 Michael Hanselmann
        key = " ".join(sorted(suggest))
315 4f3d5b76 Michael Hanselmann
      else:
316 63d44c55 Michael Hanselmann
        key = ""
317 4f3d5b76 Michael Hanselmann
318 63d44c55 Michael Hanselmann
      values.setdefault(key, []).extend(opt.all_names)
319 4f3d5b76 Michael Hanselmann
320 4f3d5b76 Michael Hanselmann
    # Don't write any code if there are no option values
321 4f3d5b76 Michael Hanselmann
    if not values:
322 4f3d5b76 Michael Hanselmann
      return
323 4f3d5b76 Michael Hanselmann
324 d4b94fe8 Michael Hanselmann
    cur = "\"$optcur\""
325 d4b94fe8 Michael Hanselmann
326 d4b94fe8 Michael Hanselmann
    wrote_opt = False
327 d4b94fe8 Michael Hanselmann
328 f5ce7613 Iustin Pop
    for (suggest, allnames) in values.items():
329 d4b94fe8 Michael Hanselmann
      longnames = [i for i in allnames if i.startswith("--")]
330 d4b94fe8 Michael Hanselmann
331 d4b94fe8 Michael Hanselmann
      if wrote_opt:
332 d4b94fe8 Michael Hanselmann
        condcmd = "elif"
333 d4b94fe8 Michael Hanselmann
      else:
334 d4b94fe8 Michael Hanselmann
        condcmd = "if"
335 d4b94fe8 Michael Hanselmann
336 3db199ea Michael Hanselmann
      sw.Write("%s _gnt_checkopt %s %s; then", condcmd,
337 d4b94fe8 Michael Hanselmann
               utils.ShellQuote("|".join(["%s=*" % i for i in longnames])),
338 d4b94fe8 Michael Hanselmann
               utils.ShellQuote("|".join(allnames)))
339 d4b94fe8 Michael Hanselmann
      sw.IncIndent()
340 d4b94fe8 Michael Hanselmann
      try:
341 63d44c55 Michael Hanselmann
        if suggest == cli.OPT_COMPL_MANY_NODES:
342 63d44c55 Michael Hanselmann
          # TODO: Implement comma-separated values
343 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W ''", cur=cur)
344 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_NODE:
345 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_nodes)\"", cur=cur)
346 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_INSTANCE:
347 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_instances)\"", cur=cur)
348 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_OS:
349 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_os)\"", cur=cur)
350 63d44c55 Michael Hanselmann
        elif suggest == cli.OPT_COMPL_ONE_IALLOCATOR:
351 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W \"$(_ganeti_iallocator)\"", cur=cur)
352 36e247e1 Guido Trotter
        elif suggest == cli.OPT_COMPL_ONE_NODEGROUP:
353 36e247e1 Guido Trotter
          WriteCompReply(sw, "-W \"$(_ganeti_nodegroup)\"", cur=cur)
354 2d3ed64b Michael Hanselmann
        elif suggest == cli.OPT_COMPL_INST_ADD_NODES:
355 2d3ed64b Michael Hanselmann
          sw.Write("local tmp= node1= pfx= curvalue=\"${optcur#*:}\"")
356 2d3ed64b Michael Hanselmann
357 2d3ed64b Michael Hanselmann
          sw.Write("if [[ \"$optcur\" == *:* ]]; then")
358 2d3ed64b Michael Hanselmann
          sw.IncIndent()
359 2d3ed64b Michael Hanselmann
          try:
360 2d3ed64b Michael Hanselmann
            sw.Write("node1=\"${optcur%%:*}\"")
361 2d3ed64b Michael Hanselmann
362 2d3ed64b Michael Hanselmann
            sw.Write("if [[ \"$COMP_WORDBREAKS\" != *:* ]]; then")
363 2d3ed64b Michael Hanselmann
            sw.IncIndent()
364 2d3ed64b Michael Hanselmann
            try:
365 2d3ed64b Michael Hanselmann
              sw.Write("pfx=\"$node1:\"")
366 2d3ed64b Michael Hanselmann
            finally:
367 2d3ed64b Michael Hanselmann
              sw.DecIndent()
368 2d3ed64b Michael Hanselmann
            sw.Write("fi")
369 2d3ed64b Michael Hanselmann
          finally:
370 2d3ed64b Michael Hanselmann
            sw.DecIndent()
371 2d3ed64b Michael Hanselmann
          sw.Write("fi")
372 2d3ed64b Michael Hanselmann
373 e80aeb89 Michael Hanselmann
          if self.support_debug:
374 e80aeb89 Michael Hanselmann
            sw.Write("_gnt_log pfx=\"'$pfx'\" curvalue=\"'$curvalue'\""
375 e80aeb89 Michael Hanselmann
                     " node1=\"'$node1'\"")
376 2d3ed64b Michael Hanselmann
377 2d3ed64b Michael Hanselmann
          sw.Write("for i in $(_ganeti_nodes); do")
378 2d3ed64b Michael Hanselmann
          sw.IncIndent()
379 2d3ed64b Michael Hanselmann
          try:
380 2d3ed64b Michael Hanselmann
            sw.Write("if [[ -z \"$node1\" ]]; then")
381 2d3ed64b Michael Hanselmann
            sw.IncIndent()
382 2d3ed64b Michael Hanselmann
            try:
383 2d3ed64b Michael Hanselmann
              sw.Write("tmp=\"$tmp $i $i:\"")
384 2d3ed64b Michael Hanselmann
            finally:
385 2d3ed64b Michael Hanselmann
              sw.DecIndent()
386 2d3ed64b Michael Hanselmann
            sw.Write("elif [[ \"$i\" != \"$node1\" ]]; then")
387 2d3ed64b Michael Hanselmann
            sw.IncIndent()
388 2d3ed64b Michael Hanselmann
            try:
389 2d3ed64b Michael Hanselmann
              sw.Write("tmp=\"$tmp $i\"")
390 2d3ed64b Michael Hanselmann
            finally:
391 2d3ed64b Michael Hanselmann
              sw.DecIndent()
392 2d3ed64b Michael Hanselmann
            sw.Write("fi")
393 2d3ed64b Michael Hanselmann
          finally:
394 2d3ed64b Michael Hanselmann
            sw.DecIndent()
395 2d3ed64b Michael Hanselmann
          sw.Write("done")
396 2d3ed64b Michael Hanselmann
397 2d3ed64b Michael Hanselmann
          WriteCompReply(sw, "-P \"$pfx\" -W \"$tmp\"", cur="\"$curvalue\"")
398 63d44c55 Michael Hanselmann
        else:
399 63d44c55 Michael Hanselmann
          WriteCompReply(sw, "-W %s" % utils.ShellQuote(suggest), cur=cur)
400 d4b94fe8 Michael Hanselmann
      finally:
401 d4b94fe8 Michael Hanselmann
        sw.DecIndent()
402 d4b94fe8 Michael Hanselmann
403 d4b94fe8 Michael Hanselmann
      wrote_opt = True
404 d4b94fe8 Michael Hanselmann
405 d4b94fe8 Michael Hanselmann
    if wrote_opt:
406 d4b94fe8 Michael Hanselmann
      sw.Write("fi")
407 d4b94fe8 Michael Hanselmann
408 d4b94fe8 Michael Hanselmann
    return
409 632d5090 Michael Hanselmann
410 4f3d5b76 Michael Hanselmann
  def _CompleteArguments(self, sw):
411 4f3d5b76 Michael Hanselmann
    if not (self.opts or self.args):
412 4f3d5b76 Michael Hanselmann
      return
413 4f3d5b76 Michael Hanselmann
414 4f3d5b76 Michael Hanselmann
    all_option_names = []
415 4f3d5b76 Michael Hanselmann
    for opt in self.opts:
416 4f3d5b76 Michael Hanselmann
      all_option_names.extend(opt.all_names)
417 4f3d5b76 Michael Hanselmann
    all_option_names.sort()
418 4f3d5b76 Michael Hanselmann
419 4f3d5b76 Michael Hanselmann
    # List options if no argument has been specified yet
420 4f3d5b76 Michael Hanselmann
    sw.Write("_ganeti_list_options %s",
421 4f3d5b76 Michael Hanselmann
             utils.ShellQuote(" ".join(all_option_names)))
422 4f3d5b76 Michael Hanselmann
423 4f3d5b76 Michael Hanselmann
    if self.args:
424 4f3d5b76 Michael Hanselmann
      last_idx = len(self.args) - 1
425 4f3d5b76 Michael Hanselmann
      last_arg_end = 0
426 4f3d5b76 Michael Hanselmann
      varlen_arg_idx = None
427 4f3d5b76 Michael Hanselmann
      wrote_arg = False
428 4f3d5b76 Michael Hanselmann
429 4f3d5b76 Michael Hanselmann
      sw.Write("compgenargs=")
430 4f3d5b76 Michael Hanselmann
431 4f3d5b76 Michael Hanselmann
      for idx, arg in enumerate(self.args):
432 4f3d5b76 Michael Hanselmann
        assert arg.min is not None and arg.min >= 0
433 4f3d5b76 Michael Hanselmann
        assert not (idx < last_idx and arg.max is None)
434 4f3d5b76 Michael Hanselmann
435 4f3d5b76 Michael Hanselmann
        if arg.min != arg.max or arg.max is None:
436 4f3d5b76 Michael Hanselmann
          if varlen_arg_idx is not None:
437 4f3d5b76 Michael Hanselmann
            raise Exception("Only one argument can have a variable length")
438 4f3d5b76 Michael Hanselmann
          varlen_arg_idx = idx
439 4f3d5b76 Michael Hanselmann
440 4f3d5b76 Michael Hanselmann
        compgenargs = []
441 4f3d5b76 Michael Hanselmann
442 4f3d5b76 Michael Hanselmann
        if isinstance(arg, cli.ArgUnknown):
443 4f3d5b76 Michael Hanselmann
          choices = ""
444 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgSuggest):
445 4f3d5b76 Michael Hanselmann
          choices = utils.ShellQuote(" ".join(arg.choices))
446 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgInstance):
447 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_instances)"
448 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgNode):
449 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_nodes)"
450 667dbd6b Adeodato Simo
        elif isinstance(arg, cli.ArgGroup):
451 667dbd6b Adeodato Simo
          choices = "$(_ganeti_nodegroup)"
452 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgJobId):
453 4f3d5b76 Michael Hanselmann
          choices = "$(_ganeti_jobs)"
454 f9faf9c3 Renรฉ Nussbaumer
        elif isinstance(arg, cli.ArgOs):
455 f9faf9c3 Renรฉ Nussbaumer
          choices = "$(_ganeti_os)"
456 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgFile):
457 4f3d5b76 Michael Hanselmann
          choices = ""
458 4f3d5b76 Michael Hanselmann
          compgenargs.append("-f")
459 4f3d5b76 Michael Hanselmann
        elif isinstance(arg, cli.ArgCommand):
460 4f3d5b76 Michael Hanselmann
          choices = ""
461 4f3d5b76 Michael Hanselmann
          compgenargs.append("-c")
462 83ec7961 Michael Hanselmann
        elif isinstance(arg, cli.ArgHost):
463 83ec7961 Michael Hanselmann
          choices = ""
464 83ec7961 Michael Hanselmann
          compgenargs.append("-A hostname")
465 4f3d5b76 Michael Hanselmann
        else:
466 4f3d5b76 Michael Hanselmann
          raise Exception("Unknown argument type %r" % arg)
467 4f3d5b76 Michael Hanselmann
468 4f3d5b76 Michael Hanselmann
        if arg.min == 1 and arg.max == 1:
469 4f3d5b76 Michael Hanselmann
          cmpcode = """"$arg_idx" == %d""" % (last_arg_end)
470 8adfb141 Michael Hanselmann
        elif arg.max is None:
471 8adfb141 Michael Hanselmann
          cmpcode = """"$arg_idx" -ge %d""" % (last_arg_end)
472 5431eff1 Michael Hanselmann
        elif arg.min <= arg.max:
473 4f3d5b76 Michael Hanselmann
          cmpcode = (""""$arg_idx" -ge %d && "$arg_idx" -lt %d""" %
474 4f3d5b76 Michael Hanselmann
                     (last_arg_end, last_arg_end + arg.max))
475 4f3d5b76 Michael Hanselmann
        else:
476 4f3d5b76 Michael Hanselmann
          raise Exception("Unable to generate argument position condition")
477 4f3d5b76 Michael Hanselmann
478 4f3d5b76 Michael Hanselmann
        last_arg_end += arg.min
479 4f3d5b76 Michael Hanselmann
480 4f3d5b76 Michael Hanselmann
        if choices or compgenargs:
481 4f3d5b76 Michael Hanselmann
          if wrote_arg:
482 4f3d5b76 Michael Hanselmann
            condcmd = "elif"
483 4f3d5b76 Michael Hanselmann
          else:
484 4f3d5b76 Michael Hanselmann
            condcmd = "if"
485 4f3d5b76 Michael Hanselmann
486 4f3d5b76 Michael Hanselmann
          sw.Write("""%s [[ %s ]]; then""", condcmd, cmpcode)
487 4f3d5b76 Michael Hanselmann
          sw.IncIndent()
488 4f3d5b76 Michael Hanselmann
          try:
489 4f3d5b76 Michael Hanselmann
            if choices:
490 4f3d5b76 Michael Hanselmann
              sw.Write("""choices="$choices "%s""", choices)
491 4f3d5b76 Michael Hanselmann
            if compgenargs:
492 8adfb141 Michael Hanselmann
              sw.Write("compgenargs=%s",
493 8adfb141 Michael Hanselmann
                       utils.ShellQuote(" ".join(compgenargs)))
494 4f3d5b76 Michael Hanselmann
          finally:
495 4f3d5b76 Michael Hanselmann
            sw.DecIndent()
496 4f3d5b76 Michael Hanselmann
497 4f3d5b76 Michael Hanselmann
          wrote_arg = True
498 4f3d5b76 Michael Hanselmann
499 4f3d5b76 Michael Hanselmann
      if wrote_arg:
500 4f3d5b76 Michael Hanselmann
        sw.Write("fi")
501 4f3d5b76 Michael Hanselmann
502 4f3d5b76 Michael Hanselmann
    if self.args:
503 4f3d5b76 Michael Hanselmann
      WriteCompReply(sw, """-W "$choices" $compgenargs""")
504 4f3d5b76 Michael Hanselmann
    else:
505 4f3d5b76 Michael Hanselmann
      # $compgenargs exists only if there are arguments
506 4f3d5b76 Michael Hanselmann
      WriteCompReply(sw, '-W "$choices"')
507 4f3d5b76 Michael Hanselmann
508 4f3d5b76 Michael Hanselmann
  def WriteTo(self, sw):
509 4f3d5b76 Michael Hanselmann
    self._FindFirstArgument(sw)
510 4f3d5b76 Michael Hanselmann
    self._CompleteOptionValues(sw)
511 4f3d5b76 Michael Hanselmann
    self._CompleteArguments(sw)
512 4f3d5b76 Michael Hanselmann
513 4f3d5b76 Michael Hanselmann
514 e80aeb89 Michael Hanselmann
def WriteCompletion(sw, scriptname, funcname, support_debug,
515 4f3d5b76 Michael Hanselmann
                    commands=None,
516 4f3d5b76 Michael Hanselmann
                    opts=None, args=None):
517 4f3d5b76 Michael Hanselmann
  """Writes the completion code for one command.
518 4f3d5b76 Michael Hanselmann
519 4f3d5b76 Michael Hanselmann
  @type sw: ShellWriter
520 4f3d5b76 Michael Hanselmann
  @param sw: Script writer
521 4f3d5b76 Michael Hanselmann
  @type scriptname: string
522 4f3d5b76 Michael Hanselmann
  @param scriptname: Name of command line program
523 4f3d5b76 Michael Hanselmann
  @type funcname: string
524 4f3d5b76 Michael Hanselmann
  @param funcname: Shell function name
525 4f3d5b76 Michael Hanselmann
  @type commands: list
526 4f3d5b76 Michael Hanselmann
  @param commands: List of all subcommands in this program
527 4f3d5b76 Michael Hanselmann
528 4f3d5b76 Michael Hanselmann
  """
529 34dfced1 Michael Hanselmann
  sw.Write("%s() {", funcname)
530 4f3d5b76 Michael Hanselmann
  sw.IncIndent()
531 4f3d5b76 Michael Hanselmann
  try:
532 34dfced1 Michael Hanselmann
    sw.Write("local "
533 632d5090 Michael Hanselmann
             ' cur="${COMP_WORDS[COMP_CWORD]}"'
534 34dfced1 Michael Hanselmann
             ' prev="${COMP_WORDS[COMP_CWORD-1]}"'
535 34dfced1 Michael Hanselmann
             ' i first_arg_idx choices compgenargs arg_idx optcur')
536 580ef58d Michael Hanselmann
537 e80aeb89 Michael Hanselmann
    if support_debug:
538 e80aeb89 Michael Hanselmann
      sw.Write("_gnt_log cur=\"$cur\" prev=\"$prev\"")
539 e80aeb89 Michael Hanselmann
      sw.Write("[[ -n \"$GANETI_COMPL_LOG\" ]] &&"
540 e80aeb89 Michael Hanselmann
               " _gnt_log \"$(set | grep ^COMP_)\"")
541 4f3d5b76 Michael Hanselmann
542 4f3d5b76 Michael Hanselmann
    sw.Write("COMPREPLY=()")
543 4f3d5b76 Michael Hanselmann
544 4f3d5b76 Michael Hanselmann
    if opts is not None and args is not None:
545 4f3d5b76 Michael Hanselmann
      assert not commands
546 e80aeb89 Michael Hanselmann
      CompletionWriter(0, opts, args, support_debug).WriteTo(sw)
547 4f3d5b76 Michael Hanselmann
548 4f3d5b76 Michael Hanselmann
    else:
549 4f3d5b76 Michael Hanselmann
      sw.Write("""if [[ "$COMP_CWORD" == 1 ]]; then""")
550 4f3d5b76 Michael Hanselmann
      sw.IncIndent()
551 4f3d5b76 Michael Hanselmann
      try:
552 4f3d5b76 Michael Hanselmann
        # Complete the command name
553 4f3d5b76 Michael Hanselmann
        WriteCompReply(sw,
554 4f3d5b76 Michael Hanselmann
                       ("-W %s" %
555 4f3d5b76 Michael Hanselmann
                        utils.ShellQuote(" ".join(sorted(commands.keys())))))
556 4f3d5b76 Michael Hanselmann
      finally:
557 4f3d5b76 Michael Hanselmann
        sw.DecIndent()
558 4f3d5b76 Michael Hanselmann
      sw.Write("fi")
559 4f3d5b76 Michael Hanselmann
560 b33cad4a Michael Hanselmann
      # Group commands by arguments and options
561 b33cad4a Michael Hanselmann
      grouped_cmds = {}
562 f5ce7613 Iustin Pop
      for cmd, (_, argdef, optdef, _, _) in commands.items():
563 4f3d5b76 Michael Hanselmann
        if not (argdef or optdef):
564 4f3d5b76 Michael Hanselmann
          continue
565 b33cad4a Michael Hanselmann
        grouped_cmds.setdefault((tuple(argdef), tuple(optdef)), set()).add(cmd)
566 4f3d5b76 Michael Hanselmann
567 b33cad4a Michael Hanselmann
      # We're doing options and arguments to commands
568 b33cad4a Michael Hanselmann
      sw.Write("""case "${COMP_WORDS[1]}" in""")
569 f5ce7613 Iustin Pop
      sort_grouped = sorted(grouped_cmds.items(),
570 f5ce7613 Iustin Pop
                            key=lambda (_, y): sorted(y)[0])
571 f5ce7613 Iustin Pop
      for ((argdef, optdef), cmds) in sort_grouped:
572 b33cad4a Michael Hanselmann
        assert argdef or optdef
573 b33cad4a Michael Hanselmann
        sw.Write("%s)", "|".join(map(utils.ShellQuote, sorted(cmds))))
574 4f3d5b76 Michael Hanselmann
        sw.IncIndent()
575 4f3d5b76 Michael Hanselmann
        try:
576 e80aeb89 Michael Hanselmann
          CompletionWriter(1, optdef, argdef, support_debug).WriteTo(sw)
577 4f3d5b76 Michael Hanselmann
        finally:
578 4f3d5b76 Michael Hanselmann
          sw.DecIndent()
579 4f3d5b76 Michael Hanselmann
        sw.Write(";;")
580 4f3d5b76 Michael Hanselmann
      sw.Write("esac")
581 4f3d5b76 Michael Hanselmann
  finally:
582 4f3d5b76 Michael Hanselmann
    sw.DecIndent()
583 4f3d5b76 Michael Hanselmann
  sw.Write("}")
584 4f3d5b76 Michael Hanselmann
585 4f3d5b76 Michael Hanselmann
  sw.Write("complete -F %s -o filenames %s",
586 4f3d5b76 Michael Hanselmann
           utils.ShellQuote(funcname),
587 4f3d5b76 Michael Hanselmann
           utils.ShellQuote(scriptname))
588 4f3d5b76 Michael Hanselmann
589 4f3d5b76 Michael Hanselmann
590 4f3d5b76 Michael Hanselmann
def GetFunctionName(name):
591 4f3d5b76 Michael Hanselmann
  return "_" + re.sub(r"[^a-z0-9]+", "_", name.lower())
592 4f3d5b76 Michael Hanselmann
593 4f3d5b76 Michael Hanselmann
594 4f3d5b76 Michael Hanselmann
def GetCommands(filename, module):
595 4f3d5b76 Michael Hanselmann
  """Returns the commands defined in a module.
596 4f3d5b76 Michael Hanselmann
597 4f3d5b76 Michael Hanselmann
  Aliases are also added as commands.
598 4f3d5b76 Michael Hanselmann
599 4f3d5b76 Michael Hanselmann
  """
600 4f3d5b76 Michael Hanselmann
  try:
601 4f3d5b76 Michael Hanselmann
    commands = getattr(module, "commands")
602 f59418db Michael Hanselmann
  except AttributeError:
603 4f3d5b76 Michael Hanselmann
    raise Exception("Script %s doesn't have 'commands' attribute" %
604 4f3d5b76 Michael Hanselmann
                    filename)
605 4f3d5b76 Michael Hanselmann
606 1f4e391b Michael Hanselmann
  # Add the implicit "--help" option
607 1f4e391b Michael Hanselmann
  help_option = cli.cli_option("-h", "--help", default=False,
608 1f4e391b Michael Hanselmann
                               action="store_true")
609 1f4e391b Michael Hanselmann
610 5786c087 Michael Hanselmann
  for name, (_, _, optdef, _, _) in commands.items():
611 1f4e391b Michael Hanselmann
    if help_option not in optdef:
612 1f4e391b Michael Hanselmann
      optdef.append(help_option)
613 5786c087 Michael Hanselmann
    for opt in cli.COMMON_OPTS:
614 5786c087 Michael Hanselmann
      if opt in optdef:
615 5786c087 Michael Hanselmann
        raise Exception("Common option '%s' listed for command '%s' in %s" %
616 5786c087 Michael Hanselmann
                        (opt, name, filename))
617 5786c087 Michael Hanselmann
      optdef.append(opt)
618 1f4e391b Michael Hanselmann
619 4f3d5b76 Michael Hanselmann
  # Use aliases
620 4f3d5b76 Michael Hanselmann
  aliases = getattr(module, "aliases", {})
621 4f3d5b76 Michael Hanselmann
  if aliases:
622 4f3d5b76 Michael Hanselmann
    commands = commands.copy()
623 f5ce7613 Iustin Pop
    for name, target in aliases.items():
624 4f3d5b76 Michael Hanselmann
      commands[name] = commands[target]
625 4f3d5b76 Michael Hanselmann
626 4f3d5b76 Michael Hanselmann
  return commands
627 4f3d5b76 Michael Hanselmann
628 4f3d5b76 Michael Hanselmann
629 ada0e680 Iustin Pop
def HaskellOptToOptParse(opts, kind):
630 ada0e680 Iustin Pop
  """Converts a Haskell options to Python cli_options.
631 ada0e680 Iustin Pop
632 ada0e680 Iustin Pop
  @type opts: string
633 ada0e680 Iustin Pop
  @param opts: comma-separated string with short and long options
634 ada0e680 Iustin Pop
  @type kind: string
635 ada0e680 Iustin Pop
  @param kind: type generated by Common.hs/complToText; needs to be
636 ada0e680 Iustin Pop
      kept in sync
637 ada0e680 Iustin Pop
638 ada0e680 Iustin Pop
  """
639 ada0e680 Iustin Pop
  # pylint: disable=W0142
640 ada0e680 Iustin Pop
  # since we pass *opts in a number of places
641 ada0e680 Iustin Pop
  opts = opts.split(",")
642 ada0e680 Iustin Pop
  if kind == "none":
643 ada0e680 Iustin Pop
    return cli.cli_option(*opts, action="store_true")
644 ada0e680 Iustin Pop
  elif kind in ["file", "string", "host", "dir"]:
645 ada0e680 Iustin Pop
    return cli.cli_option(*opts, type="string")
646 ada0e680 Iustin Pop
  elif kind == "numeric":
647 ada0e680 Iustin Pop
    # FIXME: float values here
648 ada0e680 Iustin Pop
    return cli.cli_option(*opts, type="string")
649 ada0e680 Iustin Pop
  elif kind == "onegroup":
650 ada0e680 Iustin Pop
    return cli.cli_option(*opts, type="string",
651 ada0e680 Iustin Pop
                           completion_suggest=cli.OPT_COMPL_ONE_NODEGROUP)
652 ada0e680 Iustin Pop
  elif kind == "onenode":
653 ada0e680 Iustin Pop
    return cli.cli_option(*opts, type="string",
654 ada0e680 Iustin Pop
                          completion_suggest=cli.OPT_COMPL_ONE_NODE)
655 ada0e680 Iustin Pop
  elif kind == "manyinstances":
656 ada0e680 Iustin Pop
    # FIXME: no support for many instances
657 ada0e680 Iustin Pop
    return cli.cli_option(*opts, type="string")
658 fad06963 Iustin Pop
  elif kind.startswith("choices="):
659 fad06963 Iustin Pop
    choices = kind[len("choices="):].split(",")
660 ada0e680 Iustin Pop
    return cli.cli_option(*opts, type="choice", choices=choices)
661 ada0e680 Iustin Pop
  else:
662 ada0e680 Iustin Pop
    # FIXME: there are many other currently unused completion types,
663 ada0e680 Iustin Pop
    # should be added on an as-needed basis
664 fad06963 Iustin Pop
    raise Exception("Unhandled option kind '%s'" % kind)
665 fad06963 Iustin Pop
666 fad06963 Iustin Pop
667 fad06963 Iustin Pop
#: serialised kind to arg type
668 fad06963 Iustin Pop
_ARG_MAP = {
669 fad06963 Iustin Pop
  "command": cli.ArgCommand,
670 fad06963 Iustin Pop
  "file": cli.ArgFile,
671 fad06963 Iustin Pop
  "host": cli.ArgHost,
672 fad06963 Iustin Pop
  "jobid": cli.ArgJobId,
673 fad06963 Iustin Pop
  "onegroup": cli.ArgGroup,
674 fad06963 Iustin Pop
  "oneinstance": cli.ArgInstance,
675 fad06963 Iustin Pop
  "onenode": cli.ArgNode,
676 fad06963 Iustin Pop
  "oneos": cli.ArgOs,
677 fad06963 Iustin Pop
  "string": cli.ArgUnknown,
678 fad06963 Iustin Pop
  }
679 fad06963 Iustin Pop
680 fad06963 Iustin Pop
681 fad06963 Iustin Pop
def HaskellArgToCliArg(kind, min_cnt, max_cnt):
682 fad06963 Iustin Pop
  """Converts a Haskell options to Python _Argument.
683 fad06963 Iustin Pop
684 fad06963 Iustin Pop
  @type kind: string
685 fad06963 Iustin Pop
  @param kind: type generated by Common.hs/argComplToText; needs to be
686 fad06963 Iustin Pop
      kept in sync
687 fad06963 Iustin Pop
688 fad06963 Iustin Pop
  """
689 fad06963 Iustin Pop
  min_cnt = int(min_cnt)
690 fad06963 Iustin Pop
  if max_cnt == "none":
691 fad06963 Iustin Pop
    max_cnt = None
692 fad06963 Iustin Pop
  else:
693 fad06963 Iustin Pop
    max_cnt = int(max_cnt)
694 fad06963 Iustin Pop
  # pylint: disable=W0142
695 fad06963 Iustin Pop
  # since we pass **kwargs
696 fad06963 Iustin Pop
  kwargs = {"min": min_cnt, "max": max_cnt}
697 fad06963 Iustin Pop
698 fad06963 Iustin Pop
  if kind.startswith("choices=") or kind.startswith("suggest="):
699 fad06963 Iustin Pop
    (kind, choices) = kind.split("=", 1)
700 fad06963 Iustin Pop
    kwargs["choices"] = choices.split(",")
701 fad06963 Iustin Pop
702 fad06963 Iustin Pop
  if kind not in _ARG_MAP:
703 fad06963 Iustin Pop
    raise Exception("Unhandled argument kind '%s'" % kind)
704 fad06963 Iustin Pop
  else:
705 fad06963 Iustin Pop
    return _ARG_MAP[kind](**kwargs)
706 ada0e680 Iustin Pop
707 ada0e680 Iustin Pop
708 ada0e680 Iustin Pop
def WriteHaskellCompletion(sw, script, htools=True, debug=True):
709 ada0e680 Iustin Pop
  """Generates completion information for a Haskell program.
710 ada0e680 Iustin Pop
711 ada0e680 Iustin Pop
  This Converts completion info from a Haskell program into 'fake'
712 ada0e680 Iustin Pop
  cli_opts and then builds completion for them.
713 ada0e680 Iustin Pop
714 ada0e680 Iustin Pop
  """
715 ada0e680 Iustin Pop
  if htools:
716 ada0e680 Iustin Pop
    cmd = "./htools/htools"
717 ada0e680 Iustin Pop
    env = {"HTOOLS": script}
718 ada0e680 Iustin Pop
    script_name = script
719 ada0e680 Iustin Pop
    func_name = "htools_%s" % script
720 ada0e680 Iustin Pop
  else:
721 ada0e680 Iustin Pop
    # note: this is not yet used (daemons)
722 ada0e680 Iustin Pop
    cmd = script
723 ada0e680 Iustin Pop
    env = {}
724 ada0e680 Iustin Pop
    script_name = script
725 ada0e680 Iustin Pop
    func_name = script
726 ada0e680 Iustin Pop
  output = utils.RunCmd([cmd, "--help-completion"], env=env, cwd=".").output
727 ada0e680 Iustin Pop
  cli_opts = []
728 fad06963 Iustin Pop
  args = []
729 ada0e680 Iustin Pop
  for line in output.splitlines():
730 fad06963 Iustin Pop
    v = line.split(None)
731 fad06963 Iustin Pop
    exc = lambda msg: Exception("Invalid %s output from %s: %s" %
732 fad06963 Iustin Pop
                                (msg, script, v))
733 fad06963 Iustin Pop
    if len(v) < 2:
734 fad06963 Iustin Pop
      raise exc("help completion")
735 fad06963 Iustin Pop
    if v[0].startswith("-"):
736 fad06963 Iustin Pop
      if len(v) != 2:
737 fad06963 Iustin Pop
        raise exc("option format")
738 fad06963 Iustin Pop
      (opts, kind) = v
739 fad06963 Iustin Pop
      cli_opts.append(HaskellOptToOptParse(opts, kind))
740 fad06963 Iustin Pop
    else:
741 fad06963 Iustin Pop
      if len(v) != 3:
742 fad06963 Iustin Pop
        raise exc("argument format")
743 fad06963 Iustin Pop
      (kind, min_cnt, max_cnt) = v
744 fad06963 Iustin Pop
      args.append(HaskellArgToCliArg(kind, min_cnt, max_cnt))
745 fad06963 Iustin Pop
  WriteCompletion(sw, script_name, func_name, debug, opts=cli_opts, args=args)
746 ada0e680 Iustin Pop
747 ada0e680 Iustin Pop
748 4f3d5b76 Michael Hanselmann
def main():
749 e80aeb89 Michael Hanselmann
  parser = optparse.OptionParser(usage="%prog [--compact]")
750 e80aeb89 Michael Hanselmann
  parser.add_option("--compact", action="store_true",
751 e80aeb89 Michael Hanselmann
                    help=("Don't indent output and don't include debugging"
752 e80aeb89 Michael Hanselmann
                          " facilities"))
753 e80aeb89 Michael Hanselmann
754 e80aeb89 Michael Hanselmann
  options, args = parser.parse_args()
755 e80aeb89 Michael Hanselmann
  if args:
756 e80aeb89 Michael Hanselmann
    parser.error("Wrong number of arguments")
757 e80aeb89 Michael Hanselmann
758 4f3d5b76 Michael Hanselmann
  buf = StringIO()
759 e80aeb89 Michael Hanselmann
  sw = utils.ShellWriter(buf, indent=not options.compact)
760 4f3d5b76 Michael Hanselmann
761 893ad76d Michael Hanselmann
  # Remember original state of extglob and enable it (required for pattern
762 893ad76d Michael Hanselmann
  # matching; must be enabled while parsing script)
763 893ad76d Michael Hanselmann
  sw.Write("gnt_shopt_extglob=$(shopt -p extglob || :)")
764 893ad76d Michael Hanselmann
  sw.Write("shopt -s extglob")
765 893ad76d Michael Hanselmann
766 e80aeb89 Michael Hanselmann
  WritePreamble(sw, not options.compact)
767 4f3d5b76 Michael Hanselmann
768 4f3d5b76 Michael Hanselmann
  # gnt-* scripts
769 4f3d5b76 Michael Hanselmann
  for scriptname in _autoconf.GNT_SCRIPTS:
770 4f3d5b76 Michael Hanselmann
    filename = "scripts/%s" % scriptname
771 4f3d5b76 Michael Hanselmann
772 e80aeb89 Michael Hanselmann
    WriteCompletion(sw, scriptname, GetFunctionName(scriptname),
773 e80aeb89 Michael Hanselmann
                    not options.compact,
774 d6f5892b Michael Hanselmann
                    commands=GetCommands(filename,
775 e948770c Michael Hanselmann
                                         build.LoadModule(filename)))
776 4f3d5b76 Michael Hanselmann
777 4f3d5b76 Michael Hanselmann
  # Burnin script
778 e948770c Michael Hanselmann
  burnin = build.LoadModule("tools/burnin")
779 13718ded Michael Hanselmann
  WriteCompletion(sw, "%s/burnin" % pathutils.TOOLSDIR, "_ganeti_burnin",
780 e80aeb89 Michael Hanselmann
                  not options.compact,
781 4f3d5b76 Michael Hanselmann
                  opts=burnin.OPTIONS, args=burnin.ARGUMENTS)
782 4f3d5b76 Michael Hanselmann
783 ada0e680 Iustin Pop
  # htools, if enabled
784 ada0e680 Iustin Pop
  if _autoconf.HTOOLS:
785 ada0e680 Iustin Pop
    for script in _autoconf.HTOOLS_PROGS:
786 ada0e680 Iustin Pop
      WriteHaskellCompletion(sw, script, htools=True,
787 ada0e680 Iustin Pop
                             debug=not options.compact)
788 ada0e680 Iustin Pop
789 893ad76d Michael Hanselmann
  # Reset extglob to original value
790 893ad76d Michael Hanselmann
  sw.Write("[[ -n \"$gnt_shopt_extglob\" ]] && $gnt_shopt_extglob")
791 893ad76d Michael Hanselmann
  sw.Write("unset gnt_shopt_extglob")
792 893ad76d Michael Hanselmann
793 4f3d5b76 Michael Hanselmann
  print buf.getvalue()
794 4f3d5b76 Michael Hanselmann
795 4f3d5b76 Michael Hanselmann
796 4f3d5b76 Michael Hanselmann
if __name__ == "__main__":
797 4f3d5b76 Michael Hanselmann
  main()