# 02110-1301, USA.
-import optparse
+"""Script to generate bash_completion script for Ganeti.
+
+"""
+
+# pylint: disable-msg=C0103
+# [C0103] Invalid name build-bash-completion
+
import os
-import sys
import re
from cStringIO import StringIO
from ganeti import constants
from ganeti import cli
from ganeti import utils
+from ganeti import build
# _autoconf shouldn't be imported from anywhere except constants.py, but we're
# making an exception here because this script is only used at build time.
sw.DecIndent()
sw.Write("}")
+ # Params: <compgen options>
+ # Result variable: $COMPREPLY
+ sw.Write("_ganeti_compgen() {")
+ sw.IncIndent()
+ try:
+ sw.Write("""COMPREPLY=( $(compgen "$@") )""")
+ sw.Write("_ganeti_dbglog COMPREPLY=\"${COMPREPLY[@]}\"")
+ finally:
+ sw.DecIndent()
+ sw.Write("}")
+
def WriteCompReply(sw, args, cur="\"$cur\""):
- sw.Write("""COMPREPLY=( $(compgen %s -- %s) )""", args, cur)
- sw.Write("_ganeti_dbglog COMPREPLY=\"${COMPREPLY[@]}\"")
+ sw.Write("_ganeti_compgen %s -- %s", args, cur)
sw.Write("return")
self.args = args
for opt in opts:
+ # While documented, these variables aren't seen as public attributes by
+ # pylint. pylint: disable-msg=W0212
opt.all_names = sorted(opt._short_opts + opt._long_opts)
def _FindFirstArgument(self, sw):
# Only static choices implemented so far (e.g. no node list)
suggest = getattr(opt, "completion_suggest", None)
+ # our custom option type
+ if opt.type == "bool":
+ suggest = ["yes", "no"]
+
if not suggest:
suggest = opt.choices
WriteCompReply(sw, "-W \"$(_ganeti_os)\"", cur=cur)
elif suggest == cli.OPT_COMPL_ONE_IALLOCATOR:
WriteCompReply(sw, "-W \"$(_ganeti_iallocator)\"", cur=cur)
+ elif suggest == cli.OPT_COMPL_INST_ADD_NODES:
+ sw.Write("local tmp= node1= pfx= curvalue=\"${optcur#*:}\"")
+
+ sw.Write("if [[ \"$optcur\" == *:* ]]; then")
+ sw.IncIndent()
+ try:
+ sw.Write("node1=\"${optcur%%:*}\"")
+
+ sw.Write("if [[ \"$COMP_WORDBREAKS\" != *:* ]]; then")
+ sw.IncIndent()
+ try:
+ sw.Write("pfx=\"$node1:\"")
+ finally:
+ sw.DecIndent()
+ sw.Write("fi")
+ finally:
+ sw.DecIndent()
+ sw.Write("fi")
+
+ sw.Write("_ganeti_dbglog pfx=\"'$pfx'\" curvalue=\"'$curvalue'\""
+ " node1=\"'$node1'\"")
+
+ sw.Write("for i in $(_ganeti_nodes); do")
+ sw.IncIndent()
+ try:
+ sw.Write("if [[ -z \"$node1\" ]]; then")
+ sw.IncIndent()
+ try:
+ sw.Write("tmp=\"$tmp $i $i:\"")
+ finally:
+ sw.DecIndent()
+ sw.Write("elif [[ \"$i\" != \"$node1\" ]]; then")
+ sw.IncIndent()
+ try:
+ sw.Write("tmp=\"$tmp $i\"")
+ finally:
+ sw.DecIndent()
+ sw.Write("fi")
+ finally:
+ sw.DecIndent()
+ sw.Write("done")
+
+ WriteCompReply(sw, "-P \"$pfx\" -W \"$tmp\"", cur="\"$curvalue\"")
else:
WriteCompReply(sw, "-W %s" % utils.ShellQuote(suggest), cur=cur)
finally:
choices = "$(_ganeti_nodes)"
elif isinstance(arg, cli.ArgJobId):
choices = "$(_ganeti_jobs)"
+ elif isinstance(arg, cli.ArgOs):
+ choices = "$(_ganeti_os)"
elif isinstance(arg, cli.ArgFile):
choices = ""
compgenargs.append("-f")
if arg.min == 1 and arg.max == 1:
cmpcode = """"$arg_idx" == %d""" % (last_arg_end)
+ elif arg.max is None:
+ cmpcode = """"$arg_idx" -ge %d""" % (last_arg_end)
elif arg.min <= arg.max:
cmpcode = (""""$arg_idx" -ge %d && "$arg_idx" -lt %d""" %
(last_arg_end, last_arg_end + arg.max))
- elif arg.max is None:
- cmpcode = """"$arg_idx" -ge %d""" % (last_arg_end)
else:
raise Exception("Unable to generate argument position condition")
if choices:
sw.Write("""choices="$choices "%s""", choices)
if compgenargs:
- sw.Write("compgenargs=%s", utils.ShellQuote(" ".join(compgenargs)))
+ sw.Write("compgenargs=%s",
+ utils.ShellQuote(" ".join(compgenargs)))
finally:
sw.DecIndent()
"""
try:
commands = getattr(module, "commands")
- except AttributeError, err:
+ except AttributeError:
raise Exception("Script %s doesn't have 'commands' attribute" %
filename)
+ # Add the implicit "--help" option
+ help_option = cli.cli_option("-h", "--help", default=False,
+ action="store_true")
+
+ for (_, _, optdef, _, _) in commands.itervalues():
+ if help_option not in optdef:
+ optdef.append(help_option)
+ if cli.DEBUG_OPT not in optdef:
+ optdef.append(cli.DEBUG_OPT)
+
# Use aliases
aliases = getattr(module, "aliases", {})
if aliases:
WriteCompletion(sw, scriptname,
GetFunctionName(scriptname),
commands=GetCommands(filename,
- utils.LoadModule(filename)))
+ build.LoadModule(filename)))
# Burnin script
- burnin = utils.LoadModule("tools/burnin")
+ burnin = build.LoadModule("tools/burnin")
WriteCompletion(sw, "%s/burnin" % constants.TOOLSDIR, "_ganeti_burnin",
opts=burnin.OPTIONS, args=burnin.ARGUMENTS)