Best Python code snippet using lisa_python
build-bash-completion
Source:build-bash-completion  
1#!/usr/bin/python2#3# Copyright (C) 2009, 2010, 2011, 2012 Google Inc.4# All rights reserved.5#6# Redistribution and use in source and binary forms, with or without7# modification, are permitted provided that the following conditions are8# met:9#10# 1. Redistributions of source code must retain the above copyright notice,11# this list of conditions and the following disclaimer.12#13# 2. Redistributions in binary form must reproduce the above copyright14# notice, this list of conditions and the following disclaimer in the15# documentation and/or other materials provided with the distribution.16#17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS18# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED19# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR20# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR21# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,22# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,23# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR24# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF25# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING26# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS27# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.28"""Script to generate bash_completion script for Ganeti.29"""30# pylint: disable=C010331# [C0103] Invalid name build-bash-completion32import os33import os.path34import re35import itertools36import optparse37from cStringIO import StringIO38# _constants shouldn't be imported from anywhere except constants.py, but we're39# making an exception here because this script is only used at build time.40from ganeti import _constants41from ganeti import constants42from ganeti import cli43from ganeti import utils44from ganeti import build45from ganeti import pathutils46from ganeti.tools import burnin47#: Regular expression describing desired format of option names. Long names can48#: contain lowercase characters, numbers and dashes only.49_OPT_NAME_RE = re.compile(r"^-[a-zA-Z0-9]|--[a-z][-a-z0-9]+$")50def _WriteGntLog(sw, support_debug):51  if support_debug:52    sw.Write("_gnt_log() {")53    sw.IncIndent()54    try:55      sw.Write("if [[ -n \"$GANETI_COMPL_LOG\" ]]; then")56      sw.IncIndent()57      try:58        sw.Write("{")59        sw.IncIndent()60        try:61          sw.Write("echo ---")62          sw.Write("echo \"$@\"")63          sw.Write("echo")64        finally:65          sw.DecIndent()66        sw.Write("} >> $GANETI_COMPL_LOG")67      finally:68        sw.DecIndent()69      sw.Write("fi")70    finally:71      sw.DecIndent()72    sw.Write("}")73def _WriteNodes(sw):74  sw.Write("_ganeti_nodes() {")75  sw.IncIndent()76  try:77    node_list_path = os.path.join(pathutils.DATA_DIR, "ssconf_node_list")78    sw.Write("cat %s 2>/dev/null || :", utils.ShellQuote(node_list_path))79  finally:80    sw.DecIndent()81  sw.Write("}")82def _WriteInstances(sw):83  sw.Write("_ganeti_instances() {")84  sw.IncIndent()85  try:86    instance_list_path = os.path.join(pathutils.DATA_DIR,87                                      "ssconf_instance_list")88    sw.Write("cat %s 2>/dev/null || :", utils.ShellQuote(instance_list_path))89  finally:90    sw.DecIndent()91  sw.Write("}")92def _WriteJobs(sw):93  sw.Write("_ganeti_jobs() {")94  sw.IncIndent()95  try:96    # FIXME: this is really going into the internals of the job queue97    sw.Write(("local jlist=($( shopt -s nullglob &&"98              " cd %s 2>/dev/null && echo job-* || : ))"),99             utils.ShellQuote(pathutils.QUEUE_DIR))100    sw.Write('echo "${jlist[@]/job-/}"')101  finally:102    sw.DecIndent()103  sw.Write("}")104def _WriteOSAndIAllocator(sw):105  for (fnname, paths) in [106    ("os", pathutils.OS_SEARCH_PATH),107    ("iallocator", constants.IALLOCATOR_SEARCH_PATH),108    ]:109    sw.Write("_ganeti_%s() {", fnname)110    sw.IncIndent()111    try:112      # FIXME: Make querying the master for all OSes cheap113      for path in paths:114        sw.Write("( shopt -s nullglob && cd %s 2>/dev/null && echo * || : )",115                 utils.ShellQuote(path))116    finally:117      sw.DecIndent()118    sw.Write("}")119def _WriteNodegroup(sw):120  sw.Write("_ganeti_nodegroup() {")121  sw.IncIndent()122  try:123    nodegroups_path = os.path.join(pathutils.DATA_DIR, "ssconf_nodegroups")124    sw.Write("cat %s 2>/dev/null || :", utils.ShellQuote(nodegroups_path))125  finally:126    sw.DecIndent()127  sw.Write("}")128def _WriteNetwork(sw):129  sw.Write("_ganeti_network() {")130  sw.IncIndent()131  try:132    networks_path = os.path.join(pathutils.DATA_DIR, "ssconf_networks")133    sw.Write("cat %s 2>/dev/null || :", utils.ShellQuote(networks_path))134  finally:135    sw.DecIndent()136  sw.Write("}")137def _WriteFindFirstArg(sw):138  # Params: <offset> <options with values> <options without values>139  # Result variable: $first_arg_idx140  sw.Write("_ganeti_find_first_arg() {")141  sw.IncIndent()142  try:143    sw.Write("local w i")144    sw.Write("first_arg_idx=")145    sw.Write("for (( i=$1; i < COMP_CWORD; ++i )); do")146    sw.IncIndent()147    try:148      sw.Write("w=${COMP_WORDS[$i]}")149      # Skip option value150      sw.Write("""if [[ -n "$2" && "$w" == @($2) ]]; then let ++i""")151      # Skip152      sw.Write("""elif [[ -n "$3" && "$w" == @($3) ]]; then :""")153      # Ah, we found the first argument154      sw.Write("else first_arg_idx=$i; break;")155      sw.Write("fi")156    finally:157      sw.DecIndent()158    sw.Write("done")159  finally:160    sw.DecIndent()161  sw.Write("}")162def _WriteListOptions(sw):163  # Params: <list of options separated by space>164  # Input variable: $first_arg_idx165  # Result variables: $arg_idx, $choices166  sw.Write("_ganeti_list_options() {")167  sw.IncIndent()168  try:169    sw.Write("""if [[ -z "$first_arg_idx" ]]; then""")170    sw.IncIndent()171    try:172      sw.Write("arg_idx=0")173      # Show options only if the current word starts with a dash174      sw.Write("""if [[ "$cur" == -* ]]; then""")175      sw.IncIndent()176      try:177        sw.Write("choices=$1")178      finally:179        sw.DecIndent()180      sw.Write("fi")181      sw.Write("return")182    finally:183      sw.DecIndent()184    sw.Write("fi")185    # Calculate position of current argument186    sw.Write("arg_idx=$(( COMP_CWORD - first_arg_idx ))")187    sw.Write("choices=")188  finally:189    sw.DecIndent()190  sw.Write("}")191def _WriteGntCheckopt(sw, support_debug):192  # Params: <long options with equal sign> <all options>193  # Result variable: $optcur194  sw.Write("_gnt_checkopt() {")195  sw.IncIndent()196  try:197    sw.Write("""if [[ -n "$1" && "$cur" == @($1) ]]; then""")198    sw.IncIndent()199    try:200      sw.Write("optcur=\"${cur#--*=}\"")201      sw.Write("return 0")202    finally:203      sw.DecIndent()204    sw.Write("""elif [[ -n "$2" && "$prev" == @($2) ]]; then""")205    sw.IncIndent()206    try:207      sw.Write("optcur=\"$cur\"")208      sw.Write("return 0")209    finally:210      sw.DecIndent()211    sw.Write("fi")212    if support_debug:213      sw.Write("_gnt_log optcur=\"'$optcur'\"")214    sw.Write("return 1")215  finally:216    sw.DecIndent()217  sw.Write("}")218def _WriteGntCompgen(sw, support_debug):219  # Params: <compgen options>220  # Result variable: $COMPREPLY221  sw.Write("_gnt_compgen() {")222  sw.IncIndent()223  try:224    sw.Write("""COMPREPLY=( $(compgen "$@") )""")225    if support_debug:226      sw.Write("_gnt_log COMPREPLY=\"${COMPREPLY[@]}\"")227  finally:228    sw.DecIndent()229  sw.Write("}")230def WritePreamble(sw, support_debug):231  """Writes the script preamble.232  Helper functions should be written here.233  """234  sw.Write("# This script is automatically generated at build time.")235  sw.Write("# Do not modify manually.")236  _WriteGntLog(sw, support_debug)237  _WriteNodes(sw)238  _WriteInstances(sw)239  _WriteJobs(sw)240  _WriteOSAndIAllocator(sw)241  _WriteNodegroup(sw)242  _WriteNetwork(sw)243  _WriteFindFirstArg(sw)244  _WriteListOptions(sw)245  _WriteGntCheckopt(sw, support_debug)246  _WriteGntCompgen(sw, support_debug)247def WriteCompReply(sw, args, cur="\"$cur\""):248  sw.Write("_gnt_compgen %s -- %s", args, cur)249  sw.Write("return")250class CompletionWriter(object):251  """Command completion writer class.252  """253  def __init__(self, arg_offset, opts, args, support_debug):254    self.arg_offset = arg_offset255    self.opts = opts256    self.args = args257    self.support_debug = support_debug258    for opt in opts:259      # While documented, these variables aren't seen as public attributes by260      # pylint. pylint: disable=W0212261      opt.all_names = sorted(opt._short_opts + opt._long_opts)262      invalid = list(itertools.ifilterfalse(_OPT_NAME_RE.match, opt.all_names))263      if invalid:264        raise Exception("Option names don't match regular expression '%s': %s" %265                        (_OPT_NAME_RE.pattern, utils.CommaJoin(invalid)))266  def _FindFirstArgument(self, sw):267    ignore = []268    skip_one = []269    for opt in self.opts:270      if opt.takes_value():271        # Ignore value272        for i in opt.all_names:273          if i.startswith("--"):274            ignore.append("%s=*" % utils.ShellQuote(i))275          skip_one.append(utils.ShellQuote(i))276      else:277        ignore.extend([utils.ShellQuote(i) for i in opt.all_names])278    ignore = sorted(utils.UniqueSequence(ignore))279    skip_one = sorted(utils.UniqueSequence(skip_one))280    if ignore or skip_one:281      # Try to locate first argument282      sw.Write("_ganeti_find_first_arg %s %s %s",283               self.arg_offset + 1,284               utils.ShellQuote("|".join(skip_one)),285               utils.ShellQuote("|".join(ignore)))286    else:287      # When there are no options the first argument is always at position288      # offset + 1289      sw.Write("first_arg_idx=%s", self.arg_offset + 1)290  def _CompleteOptionValues(self, sw):291    # Group by values292    # "values" -> [optname1, optname2, ...]293    values = {}294    for opt in self.opts:295      if not opt.takes_value():296        continue297      # Only static choices implemented so far (e.g. no node list)298      suggest = getattr(opt, "completion_suggest", None)299      # our custom option type300      if opt.type == "bool":301        suggest = ["yes", "no"]302      if not suggest:303        suggest = opt.choices304      if (isinstance(suggest, (int, long)) and305          suggest in cli.OPT_COMPL_ALL):306        key = suggest307      elif suggest:308        key = " ".join(sorted(suggest))309      else:310        key = ""311      values.setdefault(key, []).extend(opt.all_names)312    # Don't write any code if there are no option values313    if not values:314      return315    cur = "\"$optcur\""316    wrote_opt = False317    for (suggest, allnames) in values.items():318      longnames = [i for i in allnames if i.startswith("--")]319      if wrote_opt:320        condcmd = "elif"321      else:322        condcmd = "if"323      sw.Write("%s _gnt_checkopt %s %s; then", condcmd,324               utils.ShellQuote("|".join(["%s=*" % i for i in longnames])),325               utils.ShellQuote("|".join(allnames)))326      sw.IncIndent()327      try:328        if suggest == cli.OPT_COMPL_MANY_NODES:329          # TODO: Implement comma-separated values330          WriteCompReply(sw, "-W ''", cur=cur)331        elif suggest == cli.OPT_COMPL_ONE_NODE:332          WriteCompReply(sw, "-W \"$(_ganeti_nodes)\"", cur=cur)333        elif suggest == cli.OPT_COMPL_ONE_INSTANCE:334          WriteCompReply(sw, "-W \"$(_ganeti_instances)\"", cur=cur)335        elif suggest == cli.OPT_COMPL_ONE_OS:336          WriteCompReply(sw, "-W \"$(_ganeti_os)\"", cur=cur)337        elif suggest == cli.OPT_COMPL_ONE_EXTSTORAGE:338          WriteCompReply(sw, "-W \"$(_ganeti_extstorage)\"", cur=cur)339        elif suggest == cli.OPT_COMPL_ONE_FILTER:340          WriteCompReply(sw, "-W \"$(_ganeti_filter)\"", cur=cur)341        elif suggest == cli.OPT_COMPL_ONE_IALLOCATOR:342          WriteCompReply(sw, "-W \"$(_ganeti_iallocator)\"", cur=cur)343        elif suggest == cli.OPT_COMPL_ONE_NODEGROUP:344          WriteCompReply(sw, "-W \"$(_ganeti_nodegroup)\"", cur=cur)345        elif suggest == cli.OPT_COMPL_ONE_NETWORK:346          WriteCompReply(sw, "-W \"$(_ganeti_network)\"", cur=cur)347        elif suggest == cli.OPT_COMPL_INST_ADD_NODES:348          sw.Write("local tmp= node1= pfx= curvalue=\"${optcur#*:}\"")349          sw.Write("if [[ \"$optcur\" == *:* ]]; then")350          sw.IncIndent()351          try:352            sw.Write("node1=\"${optcur%%:*}\"")353            sw.Write("if [[ \"$COMP_WORDBREAKS\" != *:* ]]; then")354            sw.IncIndent()355            try:356              sw.Write("pfx=\"$node1:\"")357            finally:358              sw.DecIndent()359            sw.Write("fi")360          finally:361            sw.DecIndent()362          sw.Write("fi")363          if self.support_debug:364            sw.Write("_gnt_log pfx=\"'$pfx'\" curvalue=\"'$curvalue'\""365                     " node1=\"'$node1'\"")366          sw.Write("for i in $(_ganeti_nodes); do")367          sw.IncIndent()368          try:369            sw.Write("if [[ -z \"$node1\" ]]; then")370            sw.IncIndent()371            try:372              sw.Write("tmp=\"$tmp $i $i:\"")373            finally:374              sw.DecIndent()375            sw.Write("elif [[ \"$i\" != \"$node1\" ]]; then")376            sw.IncIndent()377            try:378              sw.Write("tmp=\"$tmp $i\"")379            finally:380              sw.DecIndent()381            sw.Write("fi")382          finally:383            sw.DecIndent()384          sw.Write("done")385          WriteCompReply(sw, "-P \"$pfx\" -W \"$tmp\"", cur="\"$curvalue\"")386        else:387          WriteCompReply(sw, "-W %s" % utils.ShellQuote(suggest), cur=cur)388      finally:389        sw.DecIndent()390      wrote_opt = True391    if wrote_opt:392      sw.Write("fi")393    return394  def _CompleteArguments(self, sw):395    if not (self.opts or self.args):396      return397    all_option_names = []398    for opt in self.opts:399      all_option_names.extend(opt.all_names)400    all_option_names.sort()401    # List options if no argument has been specified yet402    sw.Write("_ganeti_list_options %s",403             utils.ShellQuote(" ".join(all_option_names)))404    if self.args:405      last_idx = len(self.args) - 1406      last_arg_end = 0407      varlen_arg_idx = None408      wrote_arg = False409      sw.Write("compgenargs=")410      for idx, arg in enumerate(self.args):411        assert arg.min is not None and arg.min >= 0412        assert not (idx < last_idx and arg.max is None)413        if arg.min != arg.max or arg.max is None:414          if varlen_arg_idx is not None:415            raise Exception("Only one argument can have a variable length")416          varlen_arg_idx = idx417        compgenargs = []418        if isinstance(arg, cli.ArgUnknown):419          choices = ""420        elif isinstance(arg, cli.ArgSuggest):421          choices = utils.ShellQuote(" ".join(arg.choices))422        elif isinstance(arg, cli.ArgInstance):423          choices = "$(_ganeti_instances)"424        elif isinstance(arg, cli.ArgNode):425          choices = "$(_ganeti_nodes)"426        elif isinstance(arg, cli.ArgGroup):427          choices = "$(_ganeti_nodegroup)"428        elif isinstance(arg, cli.ArgNetwork):429          choices = "$(_ganeti_network)"430        elif isinstance(arg, cli.ArgJobId):431          choices = "$(_ganeti_jobs)"432        elif isinstance(arg, cli.ArgOs):433          choices = "$(_ganeti_os)"434        elif isinstance(arg, cli.ArgExtStorage):435          choices = "$(_ganeti_extstorage)"436        elif isinstance(arg, cli.ArgFilter):437          choices = "$(_ganeti_filter)"438        elif isinstance(arg, cli.ArgFile):439          choices = ""440          compgenargs.append("-f")441        elif isinstance(arg, cli.ArgCommand):442          choices = ""443          compgenargs.append("-c")444        elif isinstance(arg, cli.ArgHost):445          choices = ""446          compgenargs.append("-A hostname")447        else:448          raise Exception("Unknown argument type %r" % arg)449        if arg.min == 1 and arg.max == 1:450          cmpcode = """"$arg_idx" == %d""" % (last_arg_end)451        elif arg.max is None:452          cmpcode = """"$arg_idx" -ge %d""" % (last_arg_end)453        elif arg.min <= arg.max:454          cmpcode = (""""$arg_idx" -ge %d && "$arg_idx" -lt %d""" %455                     (last_arg_end, last_arg_end + arg.max))456        else:457          raise Exception("Unable to generate argument position condition")458        last_arg_end += arg.min459        if choices or compgenargs:460          if wrote_arg:461            condcmd = "elif"462          else:463            condcmd = "if"464          sw.Write("""%s [[ %s ]]; then""", condcmd, cmpcode)465          sw.IncIndent()466          try:467            if choices:468              sw.Write("""choices="$choices "%s""", choices)469            if compgenargs:470              sw.Write("compgenargs=%s",471                       utils.ShellQuote(" ".join(compgenargs)))472          finally:473            sw.DecIndent()474          wrote_arg = True475      if wrote_arg:476        sw.Write("fi")477    if self.args:478      WriteCompReply(sw, """-W "$choices" $compgenargs""")479    else:480      # $compgenargs exists only if there are arguments481      WriteCompReply(sw, '-W "$choices"')482  def WriteTo(self, sw):483    self._FindFirstArgument(sw)484    self._CompleteOptionValues(sw)485    self._CompleteArguments(sw)486def WriteCompletion(sw, scriptname, funcname, support_debug,487                    commands=None,488                    opts=None, args=None):489  """Writes the completion code for one command.490  @type sw: ShellWriter491  @param sw: Script writer492  @type scriptname: string493  @param scriptname: Name of command line program494  @type funcname: string495  @param funcname: Shell function name496  @type commands: list497  @param commands: List of all subcommands in this program498  """499  sw.Write("%s() {", funcname)500  sw.IncIndent()501  try:502    sw.Write("local "503             ' cur="${COMP_WORDS[COMP_CWORD]}"'504             ' prev="${COMP_WORDS[COMP_CWORD-1]}"'505             ' i first_arg_idx choices compgenargs arg_idx optcur')506    if support_debug:507      sw.Write("_gnt_log cur=\"$cur\" prev=\"$prev\"")508      sw.Write("[[ -n \"$GANETI_COMPL_LOG\" ]] &&"509               " _gnt_log \"$(set | grep ^COMP_)\"")510    sw.Write("COMPREPLY=()")511    if opts is not None and args is not None:512      assert not commands513      CompletionWriter(0, opts, args, support_debug).WriteTo(sw)514    else:515      sw.Write("""if [[ "$COMP_CWORD" == 1 ]]; then""")516      sw.IncIndent()517      try:518        # Complete the command name519        WriteCompReply(sw,520                       ("-W %s" %521                        utils.ShellQuote(" ".join(sorted(commands.keys())))))522      finally:523        sw.DecIndent()524      sw.Write("fi")525      # Group commands by arguments and options526      grouped_cmds = {}527      for cmd, (_, argdef, optdef, _, _) in commands.items():528        if not (argdef or optdef):529          continue530        grouped_cmds.setdefault((tuple(argdef), tuple(optdef)), set()).add(cmd)531      # We're doing options and arguments to commands532      sw.Write("""case "${COMP_WORDS[1]}" in""")533      sort_grouped = sorted(grouped_cmds.items(),534                            key=lambda (_, y): sorted(y)[0])535      for ((argdef, optdef), cmds) in sort_grouped:536        assert argdef or optdef537        sw.Write("%s)", "|".join(map(utils.ShellQuote, sorted(cmds))))538        sw.IncIndent()539        try:540          CompletionWriter(1, optdef, argdef, support_debug).WriteTo(sw)541        finally:542          sw.DecIndent()543        sw.Write(";;")544      sw.Write("esac")545  finally:546    sw.DecIndent()547  sw.Write("}")548  sw.Write("complete -F %s -o filenames %s",549           utils.ShellQuote(funcname),550           utils.ShellQuote(scriptname))551def GetFunctionName(name):552  return "_" + re.sub(r"[^a-z0-9]+", "_", name.lower())553def GetCommands(filename, module):554  """Returns the commands defined in a module.555  Aliases are also added as commands.556  """557  try:558    commands = getattr(module, "commands")559  except AttributeError:560    raise Exception("Script %s doesn't have 'commands' attribute" %561                    filename)562  # Add the implicit "--help" option563  help_option = cli.cli_option("-h", "--help", default=False,564                               action="store_true")565  for name, (_, _, optdef, _, _) in commands.items():566    if help_option not in optdef:567      optdef.append(help_option)568    for opt in cli.COMMON_OPTS:569      if opt in optdef:570        raise Exception("Common option '%s' listed for command '%s' in %s" %571                        (opt, name, filename))572      optdef.append(opt)573  # Use aliases574  aliases = getattr(module, "aliases", {})575  if aliases:576    commands = commands.copy()577    for name, target in aliases.items():578      commands[name] = commands[target]579  return commands580def HaskellOptToOptParse(opts, kind):581  """Converts a Haskell options to Python cli_options.582  @type opts: string583  @param opts: comma-separated string with short and long options584  @type kind: string585  @param kind: type generated by Common.hs/complToText; needs to be586      kept in sync587  """588  # pylint: disable=W0142589  # since we pass *opts in a number of places590  opts = opts.split(",")591  if kind == "none":592    return cli.cli_option(*opts, action="store_true")593  elif kind in ["file", "string", "host", "dir", "inetaddr"]:594    return cli.cli_option(*opts, type="string")595  elif kind == "integer":596    return cli.cli_option(*opts, type="int")597  elif kind == "float":598    return cli.cli_option(*opts, type="float")599  elif kind == "onegroup":600    return cli.cli_option(*opts, type="string",601                           completion_suggest=cli.OPT_COMPL_ONE_NODEGROUP)602  elif kind == "onenode":603    return cli.cli_option(*opts, type="string",604                          completion_suggest=cli.OPT_COMPL_ONE_NODE)605  elif kind == "manyinstances":606    # FIXME: no support for many instances607    return cli.cli_option(*opts, type="string")608  elif kind.startswith("choices="):609    choices = kind[len("choices="):].split(",")610    return cli.cli_option(*opts, type="choice", choices=choices)611  else:612    # FIXME: there are many other currently unused completion types,613    # should be added on an as-needed basis614    raise Exception("Unhandled option kind '%s'" % kind)615#: serialised kind to arg type616_ARG_MAP = {617  "choices": cli.ArgChoice,618  "command": cli.ArgCommand,619  "file": cli.ArgFile,620  "host": cli.ArgHost,621  "jobid": cli.ArgJobId,622  "onegroup": cli.ArgGroup,623  "oneinstance": cli.ArgInstance,624  "onenode": cli.ArgNode,625  "oneos": cli.ArgOs,626  "string": cli.ArgUnknown,627  "suggests": cli.ArgSuggest,628  }629def HaskellArgToCliArg(kind, min_cnt, max_cnt):630  """Converts a Haskell options to Python _Argument.631  @type kind: string632  @param kind: type generated by Common.hs/argComplToText; needs to be633      kept in sync634  """635  min_cnt = int(min_cnt)636  if max_cnt == "none":637    max_cnt = None638  else:639    max_cnt = int(max_cnt)640  # pylint: disable=W0142641  # since we pass **kwargs642  kwargs = {"min": min_cnt, "max": max_cnt}643  if kind.startswith("choices=") or kind.startswith("suggest="):644    (kind, choices) = kind.split("=", 1)645    kwargs["choices"] = choices.split(",")646  if kind not in _ARG_MAP:647    raise Exception("Unhandled argument kind '%s'" % kind)648  else:649    return _ARG_MAP[kind](**kwargs)650def ParseHaskellOptsArgs(script, output):651  """Computes list of options/arguments from help-completion output.652  """653  cli_opts = []654  cli_args = []655  for line in output.splitlines():656    v = line.split(None)657    exc = lambda msg: Exception("Invalid %s output from %s: %s" %658                                (msg, script, v))659    if len(v) < 2:660      raise exc("help completion")661    if v[0].startswith("-"):662      if len(v) != 2:663        raise exc("option format")664      (opts, kind) = v665      cli_opts.append(HaskellOptToOptParse(opts, kind))666    else:667      if len(v) != 3:668        raise exc("argument format")669      (kind, min_cnt, max_cnt) = v670      cli_args.append(HaskellArgToCliArg(kind, min_cnt, max_cnt))671  return (cli_opts, cli_args)672def WriteHaskellCompletion(sw, script, htools=True, debug=True):673  """Generates completion information for a Haskell program.674  This converts completion info from a Haskell program into 'fake'675  cli_opts and then builds completion for them.676  """677  if htools:678    cmd = "./src/htools"679    env = {"HTOOLS": script}680    script_name = script681    func_name = "htools_%s" % script682  else:683    cmd = "./" + script684    env = {}685    script_name = os.path.basename(script)686    func_name = script_name687  func_name = GetFunctionName(func_name)688  output = utils.RunCmd([cmd, "--help-completion"], env=env, cwd=".").output689  (opts, args) = ParseHaskellOptsArgs(script_name, output)690  WriteCompletion(sw, script_name, func_name, debug, opts=opts, args=args)691def WriteHaskellCmdCompletion(sw, script, debug=True):692  """Generates completion information for a Haskell multi-command program.693  This gathers the list of commands from a Haskell program and694  computes the list of commands available, then builds the sub-command695  list of options/arguments for each command, using that for building696  a unified help output.697  """698  cmd = "./" + script699  script_name = os.path.basename(script)700  func_name = script_name701  func_name = GetFunctionName(func_name)702  output = utils.RunCmd([cmd, "--help-completion"], cwd=".").output703  commands = {}704  lines = output.splitlines()705  if len(lines) != 1:706    raise Exception("Invalid lines in multi-command mode: %s" % str(lines))707  v = lines[0].split(None)708  exc = lambda msg: Exception("Invalid %s output from %s: %s" %709                              (msg, script, v))710  if len(v) != 3:711    raise exc("help completion in multi-command mode")712  if not v[0].startswith("choices="):713    raise exc("invalid format in multi-command mode '%s'" % v[0])714  for subcmd in v[0][len("choices="):].split(","):715    output = utils.RunCmd([cmd, subcmd, "--help-completion"], cwd=".").output716    (opts, args) = ParseHaskellOptsArgs(script, output)717    commands[subcmd] = (None, args, opts, None, None)718  WriteCompletion(sw, script_name, func_name, debug, commands=commands)719def main():720  parser = optparse.OptionParser(usage="%prog [--compact]")721  parser.add_option("--compact", action="store_true",722                    help=("Don't indent output and don't include debugging"723                          " facilities"))724  options, args = parser.parse_args()725  if args:726    parser.error("Wrong number of arguments")727  # Whether to build debug version of completion script728  debug = not options.compact729  buf = StringIO()730  sw = utils.ShellWriter(buf, indent=debug)731  # Remember original state of extglob and enable it (required for pattern732  # matching; must be enabled while parsing script)733  sw.Write("gnt_shopt_extglob=$(shopt -p extglob || :)")734  sw.Write("shopt -s extglob")735  WritePreamble(sw, debug)736  # gnt-* scripts737  for scriptname in _constants.GNT_SCRIPTS:738    filename = "scripts/%s" % scriptname739    WriteCompletion(sw, scriptname, GetFunctionName(scriptname), debug,740                    commands=GetCommands(filename,741                                         build.LoadModule(filename)))742  # Burnin script743  WriteCompletion(sw, "%s/burnin" % pathutils.TOOLSDIR, "_ganeti_burnin",744                  debug,745                  opts=burnin.OPTIONS, args=burnin.ARGUMENTS)746  # ganeti-cleaner747  WriteHaskellCompletion(sw, "daemons/ganeti-cleaner", htools=False,748                         debug=not options.compact)749  # htools750  for script in _constants.HTOOLS_PROGS:751    WriteHaskellCompletion(sw, script, htools=True, debug=debug)752  # ganeti-confd, if enabled753  WriteHaskellCompletion(sw, "src/ganeti-confd", htools=False,754                         debug=debug)755  # mon-collector, if monitoring is enabled756  if _constants.ENABLE_MOND:757    WriteHaskellCmdCompletion(sw, "src/mon-collector", debug=debug)758  # Reset extglob to original value759  sw.Write("[[ -n \"$gnt_shopt_extglob\" ]] && $gnt_shopt_extglob")760  sw.Write("unset gnt_shopt_extglob")761  print buf.getvalue()762if __name__ == "__main__":...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
