Enable bash completion for htools scripts
authorIustin Pop <iustin@google.com>
Tue, 25 Sep 2012 10:30:07 +0000 (12:30 +0200)
committerIustin Pop <iustin@google.com>
Wed, 26 Sep 2012 11:19:35 +0000 (13:19 +0200)
This patch ties together the previous commits, by extending
build-bash-completion to call all htools scripts and get their
completion information, then use that to build fake cli_options
representing them and finally generate the bash completion
information.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Michael Hanselmann <hansmi@google.com>

Makefile.am
autotools/build-bash-completion

index 7ae24ef..b1f3ab8 100644 (file)
@@ -173,6 +173,14 @@ GENERATED_FILES = \
        $(BUILT_PYTHON_SOURCES) \
        $(PYTHON_BOOTSTRAP)
 
+HTOOLS_GENERATED_FILES =
+if WANT_HTOOLS
+HTOOLS_GENERATED_FILES += $(HS_PROGS)
+if HS_CONFD
+HTOOLS_GENERATED_FILES += htools/hconfd
+endif
+endif
+
 built_base_sources = \
        stamp-directories \
        stamp-srclinks
@@ -370,6 +378,7 @@ docrst = \
 
 HS_PROGS = htools/htools
 HS_BIN_ROLES = hbal hscan hspace hinfo hcheck
+HS_HTOOLS_PROGS = $(HS_BIN_ROLES) hail
 
 HS_ALL_PROGS = $(HS_PROGS) htest/test htest/hpc-htools htools/hconfd
 HS_PROG_SRCS = $(patsubst %,%.hs,$(HS_ALL_PROGS))
@@ -1055,7 +1064,7 @@ doc/examples/bash_completion-debug: BC_ARGS =
 doc/examples/bash_completion doc/examples/bash_completion-debug: \
        $(BUILD_BASH_COMPLETION) $(RUN_IN_TEMPDIR) \
        lib/cli.py $(gnt_scripts) $(client_PYTHON) tools/burnin \
-       $(GENERATED_FILES)
+       $(GENERATED_FILES) $(HTOOLS_GENERATED_FILES)
        PYTHONPATH=. $(RUN_IN_TEMPDIR) \
          $(CURDIR)/$(BUILD_BASH_COMPLETION) $(BC_ARGS) > $@
 
@@ -1199,6 +1208,7 @@ lib/_autoconf.py: Makefile | stamp-directories
          echo "LVM_STRIPECOUNT = $(LVM_STRIPECOUNT)"; \
          echo "TOOLSDIR = '$(toolsdir)'"; \
          echo "GNT_SCRIPTS = [$(foreach i,$(notdir $(gnt_scripts)),'$(i)',)]"; \
+         echo "HTOOLS_PROGS = [$(foreach i,$(HS_HTOOLS_PROGS),'$(i)',)]"; \
          echo "PKGLIBDIR = '$(pkglibdir)'"; \
          echo "DRBD_BARRIERS = '$(DRBD_BARRIERS)'"; \
          echo "DRBD_NO_META_FLUSH = $(DRBD_NO_META_FLUSH)"; \
index 8687254..c0295cc 100755 (executable)
@@ -626,6 +626,74 @@ def GetCommands(filename, module):
   return commands
 
 
+def HaskellOptToOptParse(opts, kind):
+  """Converts a Haskell options to Python cli_options.
+
+  @type opts: string
+  @param opts: comma-separated string with short and long options
+  @type kind: string
+  @param kind: type generated by Common.hs/complToText; needs to be
+      kept in sync
+
+  """
+  # pylint: disable=W0142
+  # since we pass *opts in a number of places
+  opts = opts.split(",")
+  if kind == "none":
+    return cli.cli_option(*opts, action="store_true")
+  elif kind in ["file", "string", "host", "dir"]:
+    return cli.cli_option(*opts, type="string")
+  elif kind == "numeric":
+    # FIXME: float values here
+    return cli.cli_option(*opts, type="string")
+  elif kind == "onegroup":
+    return cli.cli_option(*opts, type="string",
+                           completion_suggest=cli.OPT_COMPL_ONE_NODEGROUP)
+  elif kind == "onenode":
+    return cli.cli_option(*opts, type="string",
+                          completion_suggest=cli.OPT_COMPL_ONE_NODE)
+  elif kind == "manyinstances":
+    # FIXME: no support for many instances
+    return cli.cli_option(*opts, type="string")
+  elif kind.startswith("choices "):
+    choices = kind[len("choices "):].split(",")
+    return cli.cli_option(*opts, type="choice", choices=choices)
+  else:
+    # FIXME: there are many other currently unused completion types,
+    # should be added on an as-needed basis
+    raise Exception("Unhnadled option kind '%s'" % kind)
+
+
+def WriteHaskellCompletion(sw, script, htools=True, debug=True):
+  """Generates completion information for a Haskell program.
+
+  This Converts completion info from a Haskell program into 'fake'
+  cli_opts and then builds completion for them.
+
+  """
+  if htools:
+    cmd = "./htools/htools"
+    env = {"HTOOLS": script}
+    script_name = script
+    func_name = "htools_%s" % script
+  else:
+    # note: this is not yet used (daemons)
+    cmd = script
+    env = {}
+    script_name = script
+    func_name = script
+  output = utils.RunCmd([cmd, "--help-completion"], env=env, cwd=".").output
+  cli_opts = []
+  for line in output.splitlines():
+    v = line.split(None, 1)
+    if len(v) != 2:
+      raise Exception("Invalid help completion output from %s: %s" %
+                      (script, v))
+    (opts, kind) = v
+    cli_opts.append(HaskellOptToOptParse(opts, kind))
+  WriteCompletion(sw, script_name, func_name, debug, opts=cli_opts, args=[])
+
+
 def main():
   parser = optparse.OptionParser(usage="%prog [--compact]")
   parser.add_option("--compact", action="store_true",
@@ -661,6 +729,12 @@ def main():
                   not options.compact,
                   opts=burnin.OPTIONS, args=burnin.ARGUMENTS)
 
+  # htools, if enabled
+  if _autoconf.HTOOLS:
+    for script in _autoconf.HTOOLS_PROGS:
+      WriteHaskellCompletion(sw, script, htools=True,
+                             debug=not options.compact)
+
   # Reset extglob to original value
   sw.Write("[[ -n \"$gnt_shopt_extglob\" ]] && $gnt_shopt_extglob")
   sw.Write("unset gnt_shopt_extglob")