]> www.infradead.org Git - users/dhowells/kafs-utils.git/commitdiff
Implement "x help" and "x apropos" for all command sets (bos, vos, ...)
authorDavid Howells <dhowells@redhat.com>
Tue, 29 Apr 2014 21:44:46 +0000 (22:44 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 29 Apr 2014 21:44:46 +0000 (22:44 +0100)
Signed-off-by: David Howells <dhowells@redhat.com>
suite/apropos.py [new file with mode: 0644]
suite/argparse.py
suite/commands/bos/restart.py
suite/commands/vos/examine.py
suite/exception.py
suite/help.py [new file with mode: 0644]
suite/lib/output.py
suite/main.py

diff --git a/suite/apropos.py b/suite/apropos.py
new file mode 100644 (file)
index 0000000..04d1198
--- /dev/null
@@ -0,0 +1,71 @@
+#
+# AFS Server management toolkit: Command line help search
+# -*- coding: utf-8 -*-
+#
+
+__copyright__ = """
+Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+Written by David Howells (dhowells@redhat.com)
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public Licence version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public Licence for more details.
+
+You should have received a copy of the GNU General Public Licence
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+from afs.exception import AFSException
+from afs.argparse import *
+from afs.lib.output import *
+
+help = "Search by help text"
+
+command_arguments = [
+    [ "topic",          get_string,             "rs",         "<help string>" ],
+]
+
+description = r"""
+Search by help text
+"""
+
+def search_help(prog, cmdsetmod, commands, topic):
+    matches = dict()
+    for i in commands:
+        if i == "help":
+            command = __import__("afs.help", globals(), locals(), ['*'])
+            if topic in command.help.casefold():
+                matches["help"] = command.help
+            continue
+
+        if i == "apropos":
+            if topic in help.casefold():
+                matches["apropos"] = help
+            continue
+
+        command = cmdsetmod.get_command(i)
+        if hasattr(command, "help"):
+            if topic in command.help.casefold():
+                matches[i] = command.help
+    return matches
+
+###############################################################################
+#
+#
+#
+###############################################################################
+def main(params):
+    matches = search_help(params["_prog"], params["_cmdsetmod"], params["_commands"],
+                          params["topic"].casefold())
+
+    if not matches:
+        output("Sorry, no commands found\n")
+    else:
+        for i in sorted(matches.keys()):
+            output(i, ": ", matches[i], "\n")
index 01a70b35e19309dc8fa6c9a97a8960bd4d34858d..66c55130e296e26bb337af81fbb0fa15f543b452 100644 (file)
@@ -13,7 +13,7 @@ as published by the Free Software Foundation; either version
 2 of the Licence, or (at your option) any later version.
 """
 
-from exception import AFSArgumentError
+from exception import AFSArgumentError, AFSHelpFlag
 from afs.lib.output import set_verbosity
 
 def get_cell(switch, params):
@@ -185,7 +185,7 @@ def parse_arguments(args, available_arguments, argument_size_limits,
             i = i + 1
 
             if switch == "help":
-                raise AFSArgumentError("Print help message")
+                raise AFSHelpFlag
             if switch == "":
                 raise AFSArgumentError("Missing switch name")
 
index 47f9411e2403378744a8ecb221e2e2d6465c59d0..5ffbf65654a8d0a16f405641809599479874b67d 100644 (file)
@@ -26,7 +26,7 @@ from afs.argparse import *
 from afs.lib.output import *
 import kafs
 
-help = "Restarts a server process"
+help = "Restart a server process"
 
 command_arguments = [
     [ "server",         get_bosserver,          "rs",         "<machine name>" ],
@@ -53,7 +53,7 @@ argument_size_limits = {
 }
 
 description = r"""
-Restarts a server process
+Restart a server process
 """
 
 def main(params):
index 7743c5d75fefcd62d4dd842b3b50f7ee63faccaf..253fbd92a4ff73c4a273fb0525627934c902fc47 100644 (file)
@@ -61,7 +61,7 @@ def display_vldb(params, vldb):
     if vldb.volumeId[kafs.ROVOL] != 0:
         outputf("    ROnly: {:<10d}", vldb.volumeId[kafs.ROVOL])
     if vldb.volumeId[kafs.BACKVOL] != 0:
-        outputf "    Backup: {:<10d}", vldb.volumeId[kafs.BACKVOL])
+        outputf("    Backup: {:<10d}", vldb.volumeId[kafs.BACKVOL])
     output("\n")
 
     display_vldb_site_list(params, vldb, "    ")
index 88bba149dee147e2a973d781459bb7a21d87066f..7d90a8c8d127f2cd8f6d1ea7e268e64e37a49184 100644 (file)
@@ -3,5 +3,10 @@ class AFSException(Exception):
     pass
 
 class AFSArgumentError(AFSException):
-    """Base class for all AFS Toolkit exceptions."""
+    """An argument parsing error was encountered"""
+    pass
+
+class AFSHelpFlag(AFSException):
+    """The -help flag was specified to a command."""
     pass
+
diff --git a/suite/help.py b/suite/help.py
new file mode 100644 (file)
index 0000000..068c0b7
--- /dev/null
@@ -0,0 +1,173 @@
+#
+# AFS Server management toolkit: Command line help
+# -*- coding: utf-8 -*-
+#
+
+__copyright__ = """
+Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+Written by David Howells (dhowells@redhat.com)
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public Licence version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public Licence for more details.
+
+You should have received a copy of the GNU General Public Licence
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+from afs.exception import AFSException
+from afs.argparse import *
+from afs.lib.output import *
+
+help = "Get help on commandsw"
+
+command_arguments = [
+    [ "topic",          get_strings,            "om",         "<help string>+" ],
+    [ "help",           get_dummy,              "fn" ],
+]
+
+description = r"""
+Display the server encryption keys from the KeyFile file
+"""
+
+###############################################################################
+#
+# Basic command list
+#
+###############################################################################
+def display_command_list(prog, cmdsetmod, commands):
+    output(prog, ": Commands are:\n")
+    for i in sorted(commands):
+        if i == "help":
+            desc = "Get help on commands"
+        elif i == "apropos":
+            desc = "Search by help text"
+        else:
+            command = cmdsetmod.get_command(i)
+            if hasattr(command, "alias"):
+                desc = "Alias for '" + command.alias + "'"
+            elif not hasattr(command, "help"):
+                desc = "** no help **"
+            else:
+                desc = command.help
+        outputf("{:<15s} {:s}\n", i, desc)
+
+###############################################################################
+#
+# Print a topic
+#
+###############################################################################
+def display_command_arguments(args):
+    for arg in args:
+        if arg[2] == "fn" or arg[2][0] == "o":
+            opt_o = "["
+            opt_c = "]"
+        else:
+            opt_o = ""
+            opt_c = ""
+        output(" ", opt_o, "-", arg[0])
+        if arg[2] != "fn":
+            output(" ", arg[3])
+        output(opt_c)
+    output(" [-help]")
+
+def display_aliases(prog, cmdsetmod, commands, topic):
+    aliases = []
+    for i in commands:
+        if i == "help" or i == "apropos":
+            continue
+        command = cmdsetmod.get_command(i)
+        if hasattr(command, "alias"):
+            if command.alias == topic:
+                aliases.append(i)
+    if aliases:
+        output("aliases: ", aliases[0])
+        if len(aliases) > 1:
+            for i in range(1, len(aliases)):
+                output(", ", aliases[i])
+        output("\n")
+
+def display_help_on_topics(prog, cmdsetmod, commands, topics):
+    for topic in topics:
+        if topic == "help":
+            output("bos help: ", help, "\n")
+            display_command_arguments(command_arguments)
+            continue
+
+        if topic == "apropos":
+            command = __import__("afs.apropos", globals(), locals(), ['*'])
+            output("bos apropos: ", command.help, "\n")
+            display_command_arguments(command.command_arguments)
+            continue
+
+        # See if the command is in the set
+        try:
+            found = False
+            for i in commands:
+                if i == topic:
+                    found = topic
+                    break
+                if i.startswith(topic):
+                    if found:
+                         raise RuntimeError("Ambiguous topic '" + topic + "'; use 'apropos' to list\n")
+                    found = i
+            if not found:
+                raise RuntimeError("Unknown topic '" + topic + "'\n")
+            topic = found
+        except RuntimeError as e:
+            error(e)
+            set_exitcode(5)
+            continue
+
+        # Load the command module
+        command = cmdsetmod.get_command(topic)
+
+        # If it's an alias, then switch to the real module
+        if hasattr(command, "alias"):
+            alias = " (alias for " + command.alias + ")"
+            command = cmdsetmod.get_command(command.alias)
+        else:
+            alias = ""
+
+        output(prog, " ", topic, ": ", command.help, alias, "\n")
+        display_aliases(prog, cmdsetmod, commands, topic)
+        output("Usage: ", prog, " ", topic)
+        display_command_arguments(command.command_arguments)
+        output("\n")
+        desc = command.description
+        if desc[0] == "\n":
+            desc = desc[1:]
+        output(desc)
+
+###############################################################################
+#
+#
+#
+###############################################################################
+def main(params):
+    prog = params["_prog"]
+    cmdsetmod = params["_cmdsetmod"]
+    commands = params["_commands"]
+
+    if "help" in params:
+        display_help_on_topics(prog, cmdsetmod, commands, [ "help" ])
+    elif "topic" in params:
+        display_help_on_topics(prog, cmdsetmod, commands, params["topic"])
+    else:
+        display_command_list(prog, cmdsetmod, commands)
+
+###############################################################################
+#
+# Handle the -help flag being applied to a command
+#
+###############################################################################
+def helpflag(prog, cmdsetmod, topic, command):
+    output("Usage: ", prog, " ", topic)
+    display_command_arguments(command.command_arguments)
+    output("\n")
index 6ad42db46a33ccacf1d6d5568aa2bb54589169d3..17906f70b5502d168648fe2b0e9a74767e99ac48 100644 (file)
@@ -67,6 +67,10 @@ def get_exitcode():
     global exitcode
     return exitcode
 
+def set_exitcode(n):
+    global exitcode
+    exitcode = n
+
 def verbose(*args, **kwargs):
     global verbosity
     if verbosity:
index 063499571b62dbd46f2406002cbaa03f562ab50d..b4b936fab647a55833f16e46319d7589388e1bf8 100644 (file)
@@ -29,55 +29,13 @@ import sys, os, traceback
 
 import afs.commands
 from afs.lib.output import *
-from exception import AFSArgumentError
-
-#
-# The commands map
-#
-class Commands(dict):
-    """Commands class. It performs on-demand module loading
-    """
-    def canonical_cmd(self, key):
-        """Return the canonical name for a possibly-shortened
-        command name.
-        """
-        candidates = [cmd for cmd in self.keys() if cmd.startswith(key)]
-
-        if not candidates:
-            out.error('Unknown command: %s' % key,
-                      'Try "%s help" for a list of supported commands' % prog)
-            sys.exit(2)
-
-        if len(candidates) > 1:
-            out.error('Ambiguous command: %s' % key,
-                      'Candidates are: %s' % ', '.join(candidates))
-            sys.exit(2)
-
-        return candidates[0]
-        
-    def __getitem__(self, key):
-        cmd_mod = self.get(key) or self.get(self.canonical_cmd(key))
-        return afs.commands.get_command(cmd_mod)
-
-#cmd_list = afs.commands.get_commands()
-#print(cmd_list);
-
-#commands = Commands((cmd, mod) for cmd, (mod, kind, help)
-#                    in cmd_list.iteritems())
-
-def print_help():
-    print('usage: %s <command> [options]' % os.path.basename(sys.argv[0]))
-    print()
-    print('Generic commands:')
-    print('  help        print the detailed command usage')
-    print('  version     display version information')
-    print('  copyright   display copyright information')
-    print()
-    afs.commands.pretty_command_list(cmd_list, sys.stdout)
+from exception import AFSArgumentError, AFSHelpFlag
 
+###############################################################################
 #
 # The main function (command dispatcher)
 #
+###############################################################################
 def _main():
     """The main function
     """
@@ -122,7 +80,8 @@ def _main():
     # Import the command set
     cmdsetmod = afs.commands.import_command_set(cmdset)
     commands = cmdsetmod.get_command_list()
-    #print("CMDS:", commands)
+    commands.append("help")
+    commands.append("apropos")
 
     # See if the command is in the set
     found = False
@@ -133,7 +92,7 @@ def _main():
         if i.startswith(cmd):
             if found:
                 raise RuntimeError("Command '" + cmd + "' is ambiguous")
-            found = cmd
+            found = i
     if not found:
         raise RuntimeError("Command '" + cmd + "' is unknown")
     cmd = found
@@ -144,12 +103,21 @@ def _main():
     else:
         sys.argv[0] += ' {:s}'.format(cmd)
 
-    command = cmdsetmod.get_command(cmd)
-
-    # If it's an alias, then switch to the real module
-    if hasattr(command, "alias"):
-        cmd = command.alias
+    if cmd == "help":
+        command = __import__("afs.help", globals(), locals(), ['*'])
+    elif cmd == "apropos":
+        command = __import__("afs.apropos", globals(), locals(), ['*'])
+    else:
         command = cmdsetmod.get_command(cmd)
+        # If it's an alias, then switch to the real module
+        if hasattr(command, "alias"):
+            cmd = command.alias
+            command = cmdsetmod.get_command(cmd)
+
+    if hasattr(command, "cant_combine_arguments"):
+        cant_combine_arguments = command.cant_combine_arguments
+    else:
+        cant_combine_arguments = {}
 
     if hasattr(command, "argument_size_limits"):
         argument_size_limits = command.argument_size_limits
@@ -161,16 +129,24 @@ def _main():
         params = afs.argparse.parse_arguments(sys.argv[1:],
                                               command.command_arguments,
                                               argument_size_limits,
-                                              command.cant_combine_arguments)
+                                              cant_combine_arguments)
     except AFSArgumentError as e:
         print(prog + ":", e, file=sys.stderr)
         sys.exit(2)
+    except AFSHelpFlag:
+        helper = __import__("afs.help", globals(), locals(), ['*'])
+        helper.helpflag(prog, cmdsetmod, cmd, command)
+        sys.exit(0)
 
     # Stick in the default cell if there isn't one
     if "cell" not in params:
         from afs.lib.cell import cell
         params["cell"] = cell()
 
+    params["_prog"] = prog
+    params["_cmdsetmod"] = cmdsetmod
+    params["_commands"] = commands
+
     # These modules are only used from this point onwards and do not
     # need to be imported earlier
     from afs.exception import AFSException