You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kg...@apache.org on 2019/10/16 14:40:46 UTC

[qpid-dispatch] branch master updated: DISPATCH-1441: optparse to argparse migration. Readme also updated. Some unittests created for the parsing. All refactor is related to the library migration, as many features from argparse as possible have been used.

This is an automated email from the ASF dual-hosted git repository.

kgiusti pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git


The following commit(s) were added to refs/heads/master by this push:
     new 93ea048  DISPATCH-1441: optparse to argparse migration. Readme also updated. Some unittests created for the parsing. All refactor is related to the library migration, as many features from argparse as possible have been used.
93ea048 is described below

commit 93ea0487ba3ec2b6d7db06815768fac8f0e8af87
Author: Nicolas Brignone <nb...@redhat.com>
AuthorDate: Fri Oct 11 17:50:18 2019 -0300

    DISPATCH-1441: optparse to argparse migration.
    Readme also updated.
    Some unittests created for the parsing.
    All refactor is related to the library migration, as many features from argparse
    as possible have been used.
---
 README                                         |  12 +-
 python/qpid_dispatch_internal/tools/command.py | 174 +++++++++++++++++--------
 tests/CMakeLists.txt                           |   1 +
 tests/system_tests_edge_router.py              |   4 +-
 tests/test_command.py                          | 149 +++++++++++++++++++++
 tools/qdmanage.in                              |  29 +----
 tools/qdstat.in                                | 121 +++--------------
 7 files changed, 305 insertions(+), 185 deletions(-)

diff --git a/README b/README
index 329a0eb..412dd68 100644
--- a/README
+++ b/README
@@ -22,13 +22,19 @@ packages installed:
 - asciidoctor (for building docs)
 
 The unit tests are implemented using Python's unittest library.
-Versions of Python versions prior to 2.7 do not have this library.  In
+Python versions prior to 2.7 do not have this library.  In
 order to run the unit tests using older versions of python the
-"python-unittest2" module must be installed.
+"unittest2" module must be installed.
 
 This may be available from your Linux distribution or via pip:
 
-  pip install python-unittest2
+  pip install unittest2
+
+The command line arguments parsing is done using Python's argparse library.
+Python versions prior to 2.7 do not have this library. Similar to what happend
+with unittest2, this may be fixed via pip:
+
+  pip install argparse
 
 Dispatch will not build on Windows.
 
diff --git a/python/qpid_dispatch_internal/tools/command.py b/python/qpid_dispatch_internal/tools/command.py
index b7da384..2b4ae81 100644
--- a/python/qpid_dispatch_internal/tools/command.py
+++ b/python/qpid_dispatch_internal/tools/command.py
@@ -25,7 +25,7 @@ from __future__ import division
 from __future__ import absolute_import
 from __future__ import print_function
 
-import sys, json, optparse, os
+import sys, json, argparse, os
 try:
     from collections.abc import Mapping, Sequence
 except ImportError:
@@ -41,10 +41,10 @@ class UsageError(Exception):
     """
     pass
 
-def main(run, argv=sys.argv, op=None):
+def main(run, argv=sys.argv, parser=None):
     """
     Call run(argv) with exception handling, do appropriate sys.exit().
-    @param op: an OptionParser to use for usage related error messages.
+    @param parser: a Parser to use for usage related error messages.
     @return: exit value for sys.exit
     """
     try:
@@ -53,7 +53,7 @@ def main(run, argv=sys.argv, op=None):
     except KeyboardInterrupt:
         print()
     except UsageError as e:
-        op.error(e)
+        parser.error(e)
     except Exception as e:
         if "_QPID_DISPATCH_TOOLS_DEBUG_" in os.environ:
             raise
@@ -73,42 +73,139 @@ def check_args(args, maxargs=0, minargs=0):
         raise UsageError("Unexpected arguments: %s" % (" ".join(args[maxargs:])))
     return args + [None] * (maxargs - len(args))
 
-def connection_options(options, title="Connection Options"):
-    """Return an OptionGroup for connection options."""
-    group = optparse.OptionGroup(options, title)
-    group.add_option("-b", "--bus", action="store", type="string", default="0.0.0.0",
-                     metavar="URL", help="URL of the messaging bus to connect to (default %default)")
-    group.add_option("-r", "--router", action="store", type="string", default=None,
-                     metavar="ROUTER-ID", help="Router to be queried")
-    group.add_option("-t", "--timeout", action="store", type="float", default=5, metavar="SECS",
-                      help="Maximum time to wait for connection in seconds (default %default)")
-    group.add_option("--ssl-certificate", action="store", type="string", metavar="CERT",
+def parse_args_qdstat(BusManager, argv=None):
+    parser = _qdstat_parser(BusManager)
+    return parser.parse_args(args=argv)
+
+def parse_args_qdmanage(operations, argv=None):
+    parser = _qdmanage_parser(operations)
+    return parser.parse_known_args(args=argv)
+
+common_parser = argparse.ArgumentParser(add_help=False)
+common_parser.add_argument('--version', action='version', version=VERSION)
+common_parser.add_argument("-v", "--verbose", help="Show maximum detail",
+                           action="count") # support -vvv
+
+def _custom_optional_arguments_parser(*args, **kwargs):
+    parser = argparse.ArgumentParser(*args, **kwargs)
+    parser._optionals.title = "Optional Arguments"
+    return parser
+
+def add_connection_options(parser):
+    group = parser.add_argument_group('Connection Options')
+    group.add_argument("-b", "--bus", default="0.0.0.0",
+                     metavar="URL", help="URL of the messaging bus to connect to default %(default)s")
+    group.add_argument("-t", "--timeout", type=float, default=5, metavar="SECS",
+                      help="Maximum time to wait for connection in seconds default %(default)s")
+    group.add_argument("--ssl-certificate", metavar="CERT",
                      help="Client SSL certificate (PEM Format)")
-    group.add_option("--ssl-key", action="store", type="string", metavar="KEY",
+    group.add_argument("--ssl-key", metavar="KEY",
                      help="Client SSL private key (PEM Format)")
-    group.add_option("--ssl-trustfile", action="store", type="string", metavar="TRUSTED-CA-DB",
+    group.add_argument("--ssl-trustfile", metavar="TRUSTED-CA-DB",
                      help="Trusted Certificate Authority Database file (PEM Format)")
-    group.add_option("--ssl-password", action="store", type="string", metavar="PASSWORD",
+    group.add_argument("--ssl-password", metavar="PASSWORD",
                      help="Certificate password, will be prompted if not specifed.")
     # Use the --ssl-password-file option to avoid having the --ssl-password in history or scripts.
-    group.add_option("--ssl-password-file", action="store", type="string", metavar="SSL-PASSWORD-FILE",
+    group.add_argument("--ssl-password-file", metavar="SSL-PASSWORD-FILE",
                      help="Certificate password, will be prompted if not specifed.")
 
-    group.add_option("--sasl-mechanisms", action="store", type="string", metavar="SASL-MECHANISMS",
+    group.add_argument("--sasl-mechanisms", metavar="SASL-MECHANISMS",
                      help="Allowed sasl mechanisms to be supplied during the sasl handshake.")
-    group.add_option("--sasl-username", action="store", type="string", metavar="SASL-USERNAME",
+    group.add_argument("--sasl-username", metavar="SASL-USERNAME",
                      help="User name for SASL plain authentication")
-    group.add_option("--sasl-password", action="store", type="string", metavar="SASL-PASSWORD",
+    group.add_argument("--sasl-password", metavar="SASL-PASSWORD",
                      help="Password for SASL plain authentication")
     # Use the --sasl-password-file option to avoid having the --sasl-password in history or scripts.
-    group.add_option("--sasl-password-file", action="store", type="string", metavar="SASL-PASSWORD-FILE",
+    group.add_argument("--sasl-password-file", metavar="SASL-PASSWORD-FILE",
                      help="Password for SASL plain authentication")
-    group.add_option("--ssl-disable-peer-name-verify", action="store_true", default=False,
+    group.add_argument("--ssl-disable-peer-name-verify", action="store_true",
                      help="Disables SSL peer name verification. WARNING - This option is insecure and must not be used "
                           "in production environments")
 
-    return group
+def _qdstat_add_display_args(parser, BusManager):
+    _group = parser.add_argument_group('Display', 'Choose what kind of \
+                                                   information you want to be displayed')
+    display = _group.add_mutually_exclusive_group(required=False)
+    display.add_argument("-g", "--general", action="store_const", dest="show",
+                         help="Show General Router Stats",
+                         const=BusManager.displayGeneral.__name__)
+    display.add_argument("-c", "--connections", action="store_const", dest="show",
+                         help="Show Connections",
+                         const=BusManager.displayConnections.__name__)
+    display.add_argument("-l", "--links", action="store_const", dest="show",
+                         help="Show Router Links",
+                         const=BusManager.displayRouterLinks.__name__)
+    display.add_argument("-n", "--nodes", action="store_const", dest="show",
+                         help="Show Router Nodes",
+                         const=BusManager.displayRouterNodes.__name__)
+    display.add_argument("-e", "--edge", action="store_const", dest="show",
+                         help="Show edge connections",
+                         const=BusManager.displayEdges.__name__)
+    display.add_argument("-a", "--address", action="store_const", dest="show",
+                         help="Show Router Addresses",
+                         const=BusManager.displayAddresses.__name__)
+    display.add_argument("-m", "--memory", action="store_const", dest="show",
+                         help="Show Router Memory Stats",
+                         const=BusManager.displayMemory.__name__)
+    display.add_argument("--autolinks", action="store_const", dest="show",
+                         help="Show Auto Links",
+                         const=BusManager.displayAutolinks.__name__)
+    display.add_argument("--linkroutes", action="store_const", dest="show",
+                         help="Show Link Routes",
+                         const=BusManager.displayLinkRoutes.__name__)
+    display.add_argument("--log", action="store_const", dest="show",
+                         help="Show recent log entries",
+                         const=BusManager.displayLog.__name__)
+    display.add_argument("--all-entities", action="store_const", dest="show",
+                         help="Show all router entities. Can be combined with --all-routers option",
+                         const=BusManager.show_all.__name__)
+
+    display.set_defaults(show=BusManager.displayGeneral.__name__)
+
+def _qdstat_parser(BusManager):
+    parser = _custom_optional_arguments_parser(prog="qdstat", parents=[common_parser])
+    _qdstat_add_display_args(parser, BusManager)
 
+    _group = parser.add_argument_group('Target', 'Choose destination router to \
+                                                  required, default the one you connect to.')
+    target = _group.add_mutually_exclusive_group(required=False)
+    target.add_argument("--all-routers", action="store_true",
+                        help="Show entities for all routers in network. \
+                        Can also be used in combination with other options")
+    target.add_argument("-r", "--router",
+                        metavar="ROUTER-ID", help="Router to be queried")
+
+    # This limit can be used to limit the number of output rows and
+    # can be used in conjunction with options
+    # like -c, -l, -a, --autolinks, --linkroutes and --log.
+    # By default, the limit is not set, which means the limit is unlimited.
+    parser.add_argument("--limit", help="Limit number of output rows", type=int, default=None)
+
+    add_connection_options(parser)
+    return parser
+
+def _qdmanage_add_args(parser):
+    parser.add_argument("-r", "--router",
+                     metavar="ROUTER-ID", help="Router to be queried")
+    parser.add_argument('--type', help='Type of entity to operate on.') # add choices
+    parser.add_argument('--name', help='Name of entity to operate on.')
+    parser.add_argument('--identity', help='Identity of entity to operate on.',
+                        metavar="ID")
+    parser.add_argument("--indent", type=int, default=2,
+                 help="Pretty-printing indent. -1 means don't pretty-print (default %(default)s)")
+    parser.add_argument('--stdin', action='store_true',
+                  help='Read attributes as JSON map or list of maps from stdin.')
+    parser.add_argument('--body', help='JSON value to use as body of a non-standard operation call.')
+    parser.add_argument('--properties', help='JSON map to use as properties for a non-standard operation call.')
+
+def _qdmanage_parser(operations):
+    description = "Standard operations: %s. Use GET-OPERATIONS to find additional operations." % (", ".join(operations))
+    parser = _custom_optional_arguments_parser(prog="qdmanage <operation>",
+                                     parents=[common_parser],
+                                     description=description)
+    _qdmanage_add_args(parser)
+    add_connection_options(parser)
+    return parser
 
 def get_password(file=None):
     if file:
@@ -178,32 +275,3 @@ def opts_ssl_domain(opts, mode=SSLDomain.MODE_CLIENT):
         domain.set_credentials(str(certificate), str(key), str(password))
     return domain
 
-class Option(optparse.Option):
-    """Addes two new types to optparse.Option: json_map, json_list"""
-
-    def check_json(option, opt, value):
-        """Validate a json value, for use with L{Option}"""
-        try:
-            result = json.loads(value)
-            if option.type == 'json_list' and not isinstance(result, Sequence) or \
-               option.type == 'json_map' and not isinstance(result, Mapping):
-                raise ValueError()
-            return result
-        except ValueError:
-            raise optparse.OptionValueError("%s: invalid %s: %r" % (opt, option.type, value))
-
-    TYPES = optparse.Option.TYPES + ("json_list", "json_map")
-    TYPE_CHECKER = dict(optparse.Option.TYPE_CHECKER, json_list=check_json, json_map=check_json)
-
-
-class OptionParser(optparse.OptionParser):
-    """Adds standard --version option to optparse.OptionParser"""
-    def __init__(self, *args, **kwargs):
-        optparse.OptionParser.__init__(self, *args, **kwargs)
-        def version_cb(*args):
-            print("%s" % VERSION)
-            exit(0)
-
-        self.add_option("--version", help="Print version and exit.",
-                        action="callback", callback=version_cb)
-
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 43b8a02..f36d05b 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -75,6 +75,7 @@ add_test(unit_tests            ${TEST_WRAP} unit_tests ${CMAKE_CURRENT_SOURCE_DI
 add_test(router_engine_test    ${TEST_WRAP} ${PYTHON_TEST_COMMAND} -v router_engine_test)
 add_test(management_test       ${TEST_WRAP} ${PYTHON_TEST_COMMAND} -v management)
 add_test(router_policy_test    ${TEST_WRAP} ${PYTHON_TEST_COMMAND} -v router_policy_test)
+add_test(test_command    ${TEST_WRAP} ${PYTHON_TEST_COMMAND} -v test_command)
 
 if(USE_LIBWEBSOCKETS)
   set(SYSTEM_TESTS_HTTP system_tests_http)
diff --git a/tests/system_tests_edge_router.py b/tests/system_tests_edge_router.py
index 8c6c9e6..84d56e2 100644
--- a/tests/system_tests_edge_router.py
+++ b/tests/system_tests_edge_router.py
@@ -1313,7 +1313,7 @@ class RouterTest(TestCase):
             outs = self.run_qdstat(['-c', '--all-entities'],
                                address=self.routers[0].addresses[0])
         except Exception as e:
-            if "--all-entities cannot be combined with specific entity option -c" in str(e):
+            if "error: argument --all-entities: not allowed with argument -c/--connections" in str(e):
                 has_error=True
 
         self.assertTrue(has_error)
@@ -1334,7 +1334,7 @@ class RouterTest(TestCase):
             outs = self.run_qdstat(['-r', 'INT.A', '--all-routers'],
                                    address=self.routers[0].addresses[0])
         except Exception as e:
-            if "--all-routers cannot be combined with single router option" in str(e):
+            if "error: argument --all-routers: not allowed with argument -r/--router" in str(e):
                 has_error=True
 
         self.assertTrue(has_error)
diff --git a/tests/test_command.py b/tests/test_command.py
new file mode 100644
index 0000000..85ea935
--- /dev/null
+++ b/tests/test_command.py
@@ -0,0 +1,149 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import unittest, argparse, sys
+from itertools import combinations
+
+from qpid_dispatch_internal.tools.command import (main,
+                                                  UsageError,
+                                                  parse_args_qdstat,
+                                                  parse_args_qdmanage,
+                                                  _qdmanage_parser,
+                                                  _qdstat_parser)
+
+def mock_error(self, message):
+    raise ValueError(message)
+
+argparse.ArgumentParser.error = mock_error
+
+# Since BusManager file is definded in tools/qdmanage.in -> tools/qdmanage
+# otherwise it could be just imported
+class FakeBusManager:
+    def displayGeneral(self): pass
+    def displayConnections(self): pass
+    def displayRouterLinks(self): pass
+    def displayRouterNodes(self): pass
+    def displayEdges(self): pass
+    def displayAddresses(self): pass
+    def displayMemory(self): pass
+    def displayAutolinks(self): pass
+    def displayLinkRoutes(self): pass
+    def displayLog(self): pass
+    def show_all(self): pass
+
+FBM = FakeBusManager
+
+class TestParseArgsQdstat(unittest.TestCase):
+    def setUp(self):
+        self.parser = _qdstat_parser(BusManager=FBM)
+
+    def test_parse_args_qdstat_print_help(self):
+        self.parser.print_help()
+
+    def test_parse_args_qdstat_mutually_exclusive(self):
+        options1 = ["-g", "-c",
+                    "-l","-n","-e","-a","-m","--autolinks","--linkroutes","--log",
+                    "--all-entities"]
+        options2 = ["-r", "--all-routers"]
+
+        def _call_pairs(options):
+            for options_pair in combinations(options, 2):
+                with self.assertRaises(ValueError):
+                    self.parser.parse_args(options_pair)
+
+        _call_pairs(options1)
+        _call_pairs(options2)
+
+    def test_parse_args_qdstat_default(self):
+        args = parse_args_qdstat(FBM, argv = [])
+        self.assertEqual(FBM.displayGeneral.__name__, args.show)
+
+    def test_parse_args_qdstat_method_show_matching(self):
+        matching = [("-g", FBM.displayGeneral.__name__),
+                    ("-c", FBM.displayConnections.__name__),
+                    ("-l", FBM.displayRouterLinks.__name__),
+                    ("-n", FBM.displayRouterNodes.__name__),
+                    ("-e", FBM.displayEdges.__name__),
+                    ("-a", FBM.displayAddresses.__name__),
+                    ("-m", FBM.displayMemory.__name__),
+                    ("--autolinks", FBM.displayAutolinks.__name__),
+                    ("--linkroutes", FBM.displayLinkRoutes.__name__),
+                    ("--log", FBM.displayLog.__name__),
+                    ("--all-entities", FBM.show_all.__name__),
+                    ]
+        for option, expected in matching:
+            args = self.parser.parse_args([option])
+            self.assertEqual(expected, args.show)
+
+    def test_parse_args_qdstat_limit(self):
+        args = self.parser.parse_args([])
+        self.assertEqual(None, args.limit)
+
+        args = self.parser.parse_args(["--limit", "1"])
+        self.assertEqual(1, args.limit)
+
+class TestParseArgsQdmanage(unittest.TestCase):
+    def setUp(self):
+        self.operations = ["HERE", "SOME", "OPERATIONS"]
+        self.parser = _qdmanage_parser(operations=self.operations)
+
+    def test_parse_args_qdmanage_print_help(self):
+        self.parser.print_help()
+
+    def test_parse_args_qdmanage_operation_no_args(self):
+        argv = "-r r1 QUERY --type some --name the_name -b 127.0.0.1:5672"
+        opts, args = self.parser.parse_known_args(argv.split())
+        self.assertEqual("QUERY", args[0])
+
+    def test_parse_args_qdmanage_operation_and_args(self):
+        argv = "-r r1 QUERY arg1=val1 --type some other=argument --name the_name -b 127.0.0.1:5672"
+        opts, args = self.parser.parse_known_args(argv.split())
+        self.assertEqual(["QUERY", "arg1=val1", "other=argument"], args)
+
+
+class TestMain(unittest.TestCase):
+    def test_main(self):
+        def run_success(argv):
+            self.assertEqual(sys.argv, argv)
+
+        def run_raises(argv, _Exception):
+            run_success(argv)
+            raise _Exception("some")
+
+        def run_raises_UsageError(argv):
+            run_raises(argv, UsageError)
+
+        def run_raises_Exception(argv):
+            run_raises(argv, Exception)
+
+        def run_raises_KeyboardInterrupt(argv):
+            run_raises(argv, KeyboardInterrupt)
+
+        self.assertEqual(0, main(run_success))
+        failed_runs = [
+            #run_raises_UsageError, ##uncomment this exposes bug
+            run_raises_Exception,
+            run_raises_KeyboardInterrupt,
+        ]
+        for run in failed_runs:
+            self.assertEqual(1, main(run))
+
+if __name__ == '__main__':
+    unittest.main()
+
diff --git a/tools/qdmanage.in b/tools/qdmanage.in
index b1480e3..0d41d01 100755
--- a/tools/qdmanage.in
+++ b/tools/qdmanage.in
@@ -26,14 +26,15 @@ from __future__ import print_function
 
 import sys, json, re
 import  qpid_dispatch_site
-from qpid_dispatch.management.client import Node, Url
+import argparse
 try:
     from collections.abc import Mapping, Sequence
 except ImportError:
     from collections import Mapping, Sequence
-from optparse import OptionGroup
-from qpid_dispatch_internal.tools.command import OptionParser, Option, UsageError, connection_options, check_args, \
-    main, opts_ssl_domain, opts_url, opts_sasl
+
+from qpid_dispatch.management.client import Node, Url
+from qpid_dispatch_internal.tools.command import (UsageError, _qdmanage_parser, check_args,
+                                                  main, opts_ssl_domain, opts_url, opts_sasl)
 from qpid_dispatch_internal.management.qdrouter import QdSchema
 from qpid_dispatch_internal.compat import PY_TEXT_TYPE
 from qpid_dispatch_internal.compat import PY_STRING_TYPE
@@ -63,23 +64,7 @@ class QdManage():
         self.operations = ['QUERY', 'CREATE', 'READ', 'UPDATE', 'DELETE',
                            'GET-TYPES', 'GET-OPERATIONS', 'GET-ATTRIBUTES', 'GET-ANNOTATIONS',
                            'GET-MGMT-NODES', 'GET-SCHEMA', 'GET-LOG']
-
-        usage = "%prog <operation> [options...] [arguments...]"
-        description = "Standard operations: %s. Use GET-OPERATIONS to find additional operations." \
-                      % (", ".join(self.operations))
-
-        op = OptionParser(usage=usage, option_class=Option, description=description)
-        op.add_option('--type', help='Type of entity to operate on.')
-        op.add_option('--name', help='Name of entity to operate on.')
-        op.add_option('--identity', help='Identity of entity to operate on.', metavar="ID")
-        op.add_option("--indent", type="int", default=2,
-                     help="Pretty-printing indent. -1 means don't pretty-print (default %default)")
-        op.add_option('--stdin', action='store_true',
-                      help='Read attributes as JSON map or list of maps from stdin.')
-        op.add_option('--body', help='JSON value to use as body of a non-standard operation call.')
-        op.add_option('--properties', help='JSON map to use as properties for a non-standard operation call.')
-        op.add_option_group(connection_options(op))
-        self.op = op
+        self.op = _qdmanage_parser(self.operations)
 
     def clean_opts(self):
         attr_type = self.opts.type
@@ -90,7 +75,7 @@ class QdManage():
         # Make all args unicode to avoid encoding arg values as AMQP bytes.
         al = [x.decode() if not isinstance(x, PY_TEXT_TYPE) else x
               for x in argv[1:]]
-        self.opts, self.args = self.op.parse_args(al)
+        self.opts, self.args = self.op.parse_known_args(al)
         self.clean_opts()
         if self.opts.indent == -1:
             self.opts.indent = None
diff --git a/tools/qdstat.in b/tools/qdstat.in
index b7e412f..02b61a8 100755
--- a/tools/qdstat.in
+++ b/tools/qdstat.in
@@ -25,72 +25,23 @@ from __future__ import absolute_import
 from __future__ import print_function
 
 import os
-from optparse import OptionGroup
 import sys
 import locale
 import socket
 import re
 from datetime import datetime
 from time import ctime, strftime, gmtime
-import  qpid_dispatch_site
+import qpid_dispatch_site
 from qpid_dispatch.management.client import Url, Node, Entity
 from qpid_dispatch_internal.management.qdrouter import QdSchema
 from qpid_dispatch_internal.tools import Display, Header, Sorter, YN, Commas, TimeLong
-from qpid_dispatch_internal.tools.command import connection_options, main, OptionParser, opts_ssl_domain, opts_sasl, \
-        opts_url
+from qpid_dispatch_internal.tools.command import (parse_args_qdstat, main,
+                                                  opts_ssl_domain, opts_sasl,
+                                                  opts_url)
 from qpid_dispatch_internal.compat import UNICODE
 
-def parse_args(argv):
-    """ Set global variables for options, return arguments """
-
-    usage = "%prog [options]"
-    parser = OptionParser(usage=usage)
-
-    parser.add_option_group(connection_options(parser))
-
-    parser.add_option("-g", "--general", help="Show General Router Stats",  action="store_const", const="g",   dest="show")
-    parser.add_option("-c", "--connections", help="Show Connections",       action="store_const", const="c",   dest="show")
-    parser.add_option("-l", "--links", help="Show Router Links",            action="store_const", const="l",   dest="show")
-    parser.add_option("-n", "--nodes", help="Show Router Nodes",            action="store_const", const="n",   dest="show")
-    parser.add_option("-e", "--edge", help="Show edge connections",         action="store_const", const="e",   dest="show")
-    parser.add_option("-a", "--address", help="Show Router Addresses",      action="store_const", const="a",   dest="show")
-    parser.add_option("-m", "--memory", help="Show Router Memory Stats",    action="store_const", const="m",   dest="show")
-    parser.add_option("--autolinks", help="Show Auto Links",                action="store_const", const="autolinks",  dest="show")
-    parser.add_option("--linkroutes", help="Show Link Routes",              action="store_const", const="linkroutes", dest="show")
-
-    parser.add_option("--all-routers", help="Show entities for all routers in network. Can also be used in combination with other options",  action="store_const", const="all_routers",  dest="all_routers")
-    parser.add_option("--all-entities", help="Show all router entities. Can be combined with --all-routers option", action="store_const", const="all_entities", dest="all_entities")
-
-    parser.add_option("-v", "--verbose", help="Show maximum detail",        action="store_true", dest="verbose")
-    parser.add_option("--log", help="Show recent log entries", action="store_const", const="log", dest="show")
-
-    # This limit can be used to limit the number of output rows and
-    # can be used in conjunction with options
-    # like -c, -l, -a, --autolinks, --linkroutes and --log.
-    # By default, the limit is not set, which means the limit is unlimited.
-    parser.add_option("--limit", help="Limit number of output rows", type="int", default=None)
-
-    opts, args = parser.parse_args(args=argv)
-
-    if opts.router and opts.all_routers:
-        parser.error("--all-routers cannot be combined with single router option -r " + opts.router)
-
-    if opts.all_entities and opts.show:
-           parser.error("--all-entities cannot be combined with specific entity option -" + opts.show)
-
-    if not opts.show and not opts.all_entities and opts.all_routers:
-        opts.show = u'g'
-
-    if not opts.all_routers and not opts.all_entities and not opts.show:
-        opts.show = u'g'
-
-    return opts, args
-
 def get(obj, attr):
-    if attr in obj.__dict__:
-        return obj.__dict__[attr]
-    return None
-
+    return getattr(obj, attr, None)
 
 class BusManager(Node):
 
@@ -102,7 +53,8 @@ class BusManager(Node):
             Node.connection(opts_url(opts), opts.router,
                             timeout=opts.timeout,
                             ssl_domain=opts_ssl_domain(opts),
-                            sasl=opts_sasl(self.opts)))
+                            sasl=opts_sasl(opts)))
+        self.show = getattr(self, opts.show)
 
     def query(self, entity_type, attribute_names=None, limit=None):
         if attribute_names:
@@ -687,67 +639,26 @@ class BusManager(Node):
 
         return has_nodes, all_nodes
 
-    def show_entity(self, main):
-        if   main == 'l': self.displayRouterLinks()
-        elif main == 'n': self.displayRouterNodes()
-        elif main == 'a': self.displayAddresses()
-        elif main == 'm': self.displayMemory()
-        elif main == 'g': self.displayGeneral()
-        elif main == 'e': self.displayEdges()
-        elif main == 'c': self.displayConnections()
-        elif main == 'autolinks': self.displayAutolinks()
-        elif main == 'linkroutes': self.displayLinkRoutes()
-        elif main == 'log': self.displayLog()
-
-    def all_routers_entities(self):
+    def display(self):
         has_nodes, nodes = self.has_nodes()
-        if has_nodes:
+        if self.opts.all_routers and has_nodes:
+            print (str(datetime.now()))
             for node in nodes:
                 super(BusManager, self).set_client(node[6:])
                 parts = node.split("/")
                 print ("Router ", parts[3])
-                self.show_all()
+                self.show()
                 print("")
         else:
-            self.show_all()
-
-    def displayMain(self, identitys, opts):
-        main = opts.show
-        if opts.all_routers and main:
-            print (str(datetime.now()))
-            has_nodes, nodes = self.has_nodes()
-            if has_nodes:
-                for node in nodes:
-                    super(BusManager, self).set_client(node[6:])
-                    parts = node.split("/")
-                    print ("Router ", parts[3])
-                    self.show_entity(main)
-                    print("")
-            else:
-                self.show_entity(main)
-        elif opts.all_routers and opts.all_entities:
-            print (str(datetime.now()))
-            self.all_routers_entities()
-        elif opts.all_entities:
-            print (str(datetime.now()))
-            # Display all the relevant entities from the one router that
-            # qdstat is connecting to.
-            self.show_all()
-        elif main:
-            self.show_entity(main)
-
-    def display(self, identitys):
-        self.displayMain(identitys, self.opts)
+            self.show()
 
 def run(argv):
-    opts, args = parse_args(argv)
-    if args[1:]:
-        raise Exception("Unexpected arguments: %s" % " ".join(args[1:]))
-    bm = BusManager(opts)
+    args = parse_args_qdstat(BusManager)
+    bm = BusManager(args)
     try:
-        bm.display(args)
+        bm.display()
     finally:
         bm.close()
 
 if __name__ == "__main__":
-        sys.exit(main(run, sys.argv))
+        sys.exit(main(run))


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org