From a5549505460ee3d595e5d81cc9175087daa30641 Mon Sep 17 00:00:00 2001
From: Frank Winklmeier <frank.winklmeier@cern.ch>
Date: Wed, 15 May 2019 11:38:50 +0200
Subject: [PATCH] acmd: Remove dependency on extensions module

Implement a trivial plugin registration to remove the dependency on the
`extensions` module. Also remove some unused code and options. Add
dependency on `requests` module (from LCG) to ensure the jira plugin
works correctly.
---
 Tools/PyUtils/CMakeLists.txt             |   1 +
 Tools/PyUtils/bin/acmd.py                |  37 ++-------
 Tools/PyUtils/python/acmdlib.py          | 101 +++++++----------------
 Tools/PyUtils/python/scripts/__init__.py |  33 ++++----
 4 files changed, 55 insertions(+), 117 deletions(-)

diff --git a/Tools/PyUtils/CMakeLists.txt b/Tools/PyUtils/CMakeLists.txt
index b372e3c30ea..4742e0f294c 100644
--- a/Tools/PyUtils/CMakeLists.txt
+++ b/Tools/PyUtils/CMakeLists.txt
@@ -12,6 +12,7 @@ atlas_depends_on_subdirs( PUBLIC
 
 # External dependencies:
 find_package( PythonLibs )
+find_package( requests )
 find_package( ROOT COMPONENTS Core PyROOT Tree MathCore Hist RIO pthread )
 
 # Install files from the package:
diff --git a/Tools/PyUtils/bin/acmd.py b/Tools/PyUtils/bin/acmd.py
index 7c3f0e78694..eca71801e94 100755
--- a/Tools/PyUtils/bin/acmd.py
+++ b/Tools/PyUtils/bin/acmd.py
@@ -1,41 +1,24 @@
 #!/usr/bin/env python
 
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 # @file PyUtils.acmd
 # @purpose main command line script for the general purpose athena scripts
 # @author Sebastien Binet
 # @date January 2010
 
-from __future__ import with_statement
-
-__version__ = "$Revision: 276499 $"
 __author__ = "Sebastien Binet"
 __doc__ = "main command line script for the general purpose athena scripts"
 
 import PyUtils.acmdlib as acmdlib
+import sys
 
 def main():
-    import PyUtils.scripts
+    import PyUtils.scripts   # noqa: F401  (register all plugins)
     import PyUtils.Logging as L
     msg = L.logging.getLogger('Acmd')
     msg.setLevel(L.logging.INFO)
     
-    ## if 0:
-    ##     acmdlib.register_file('acmd_plugins.cfg')
-    ## else:
-    ##     import os
-    ##     if os.path.exists('acmd_plugins.py'):
-    ##         execfile('acmd_plugins.py')
-            
-    commands = {}
-    plugins = list(acmdlib.ext_plugins.get(group=acmdlib.ACMD_GROUPNAME))
-    #print plugins
-    for i, plugin in enumerate(plugins):
-        #print i, plugin.name
-        commands[plugin.name] = plugin
-
-    if 1:
-        acmdlib._load_commands()
+    acmdlib.Plugins.loadAll()
 
     parser = acmdlib.ACMD_PARSER
     args = parser.parse_args()
@@ -43,7 +26,6 @@ def main():
     msg.info('running sub-command [%s]...', args.command)
     cmd_name = args.command
 
-    import sys
     sys_args = sys.argv[1:]
     if sys_args[0] != cmd_name:
         # special case of a sub(sub,...) command:
@@ -52,21 +34,18 @@ def main():
         idx = sys_args.index(cmd_name)
         cmd_name = '.'.join(sys_args[:idx+1])
 
-    cmd = commands[cmd_name].load()
+    cmd = acmdlib.Plugins.load(cmd_name)
     exitcode = 1
     try:
-        exitcode = cmd(args)
+        exitcode = cmd.main(args)
     except Exception:
         exitcode = 1
-        import sys
-        print sys.exc_info()[0]
-        print sys.exc_info()[1]
+        print(sys.exc_info()[0])
+        print(sys.exc_info()[1])
         raise
     
     return exitcode
 
 
 if __name__ == "__main__":
-    import sys
     sys.exit(main())
-    
diff --git a/Tools/PyUtils/python/acmdlib.py b/Tools/PyUtils/python/acmdlib.py
index dee104d6bf8..d8120d792dc 100644
--- a/Tools/PyUtils/python/acmdlib.py
+++ b/Tools/PyUtils/python/acmdlib.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 
 # @file PyUtils.acmdlib
 # @purpose a library to ease the writing of sub-command scripts
@@ -16,14 +16,12 @@ __all__ = [
     'command',
     'argument',
     'register',
-    'register_file',
     ]
 
 ### imports -------------------------------------------------------------------
-import sys
-import extensions as ext_plugins
 import argparse
 import textwrap
+import importlib
 
 ### globals -------------------------------------------------------------------
 ACMD_GROUPNAME = 'acmdlib.commands'
@@ -60,11 +58,7 @@ class Command(object):
         self.parser = self._make_parser(**kwargs)
         self._init_arguments()
         plugin_name = kwargs.get('name') or self.name
-        register(
-            plugin_name,
-            '%s:%s' % (self.fct.__module__, self.fct.__name__)
-            )
-        return
+        register(plugin_name, self.fct.__module__)
 
     @property
     def name(self):
@@ -110,7 +104,6 @@ class Command(object):
             name = names[idx]
             if name in node.choices:
                 return node.choices[name]
-            full_name = ' '.join(names[:idx+1])
             args = {
                 'name' : name,
                 'help' : 'a group of sub-commands',
@@ -137,6 +130,33 @@ class Command(object):
         
     pass # Command
 
+class Plugins(object):
+    """A simple plugin registration.
+    """
+    _plugins = {}
+
+    @classmethod
+    def register(cls, name, value):
+        """Register plugin
+        """
+        cls._plugins[name] = value
+
+    @classmethod
+    def load(cls, name):
+        """Load given plugin and return it
+        """
+        try:
+            return importlib.import_module(cls._plugins[name])
+        except Exception as err:
+            print("** could not load command [%s]:\n%s" % (name, err))
+
+    @classmethod
+    def loadAll(cls):
+        """Load all plugins
+        """
+        for k in cls._plugins.keys():
+            cls.load(k)
+
 ### functions -----------------------------------------------------------------
 
 def command(*args, **kwargs):
@@ -168,63 +188,4 @@ def register(name, value):
 
     ex: register('check-file', 'PyUtils.CheckFileLib:fct')
     """
-    group = ACMD_GROUPNAME
-    return ext_plugins.register(group, name, value)
-
-def register_file(path):
-    """Registers a config-like file"""
-    from ConfigParser import ConfigParser
-    parser = ConfigParser()
-    parser.read([path])
-    for group in parser.sections():
-        for name in parser.options(group):
-            value = parser.get(group, name)
-            ext_plugins.register(group, name, value)
-
-# add a special command to list all registered commands
-@command
-@argument('-d','--detailed', action='store_true', default=False,
-          help='print full help of each command')
-def list_commands(args):
-    """a special command to list all the commands 'acmd' can run
-    """
-    cmds = list(ext_plugins.get(group=ACMD_GROUPNAME))
-    if len(cmds) == 0:
-        print "::: no command found in registry"
-        return 1
-    print "::: found [%i] command%s" % (len(cmds),
-                                        "s" if len(cmds)>1 else "")
-    cmds.sort(cmp=lambda x,y: cmp(x.name, y.name))
-    cmds = [cmd for cmd in cmds if cmd.name != 'list-commands']
-    for i, cmd in enumerate(cmds):
-        if args.detailed:
-            print "="*80
-        print " - %s" % (' '.join(cmd.name.split('.')),)
-        if args.detailed:
-            try:
-                cmd.load().parser.print_help()
-            except Exception,err:
-                print "** could not inspect command [%s]:\n%s" % (
-                    cmd.name,
-                    err)
-            print "="*80
-            print ""
-    return 0
-#acmdlib.register('list-commands', 'PyUtils.acmdlib:list_commands')
-
-# an argument to force the loading of all available commands
-ACMD_PARSER.add_argument(
-    '--load-commands',
-    action='store_true',
-    default=False,
-    help='force the loading of all available commands')
-def _load_commands():
-    cmds = list(ext_plugins.get(group=ACMD_GROUPNAME))
-    for cmd in cmds:
-        try:
-            cmd.load()
-        except Exception,err:
-            print "** could not load command [%s]:\n%s" % (
-                cmd.name,
-                err)
-
+    return Plugins.register(name, value)
diff --git a/Tools/PyUtils/python/scripts/__init__.py b/Tools/PyUtils/python/scripts/__init__.py
index fac15a1bbcc..b0c5d373f70 100644
--- a/Tools/PyUtils/python/scripts/__init__.py
+++ b/Tools/PyUtils/python/scripts/__init__.py
@@ -1,26 +1,23 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 
 # hook for PyUtils.scripts package
 
-# FIXME: waiting for a proper declarative file
 import PyUtils.acmdlib as acmdlib
-acmdlib.register('chk-file', 'PyUtils.scripts.check_file:main')
-acmdlib.register('diff-pool', 'PyUtils.scripts.diff_pool_files:main')
-acmdlib.register('diff-root', 'PyUtils.scripts.diff_root_files:main')
-acmdlib.register('dump-root', 'PyUtils.scripts.dump_root_file:main')
-acmdlib.register('chk-sg', 'PyUtils.scripts.check_sg:main')
-acmdlib.register('ath-dump', 'PyUtils.scripts.ath_dump:main')
-acmdlib.register('chk-rflx', 'PyUtils.scripts.check_reflex:main')
-acmdlib.register('gen-klass', 'PyUtils.scripts.gen_klass:main')
+acmdlib.register('chk-file', 'PyUtils.scripts.check_file')
+acmdlib.register('diff-pool', 'PyUtils.scripts.diff_pool_files')
+acmdlib.register('diff-root', 'PyUtils.scripts.diff_root_files')
+acmdlib.register('dump-root', 'PyUtils.scripts.dump_root_file')
+acmdlib.register('chk-sg', 'PyUtils.scripts.check_sg')
+acmdlib.register('ath-dump', 'PyUtils.scripts.ath_dump')
+acmdlib.register('chk-rflx', 'PyUtils.scripts.check_reflex')
+acmdlib.register('gen-klass', 'PyUtils.scripts.gen_klass')
 
-acmdlib.register('merge-files', 'PyUtils.scripts.merge_files:main')
-acmdlib.register('filter-files', 'PyUtils.scripts.filter_files:main')
+acmdlib.register('merge-files', 'PyUtils.scripts.merge_files')
+acmdlib.register('filter-files', 'PyUtils.scripts.filter_files')
 
-acmdlib.register('cmake.new-skeleton', 'PyUtils.scripts.cmake_newskeleton:main')
-acmdlib.register('cmake.new-pkg', 'PyUtils.scripts.cmake_newpkg:main')
-acmdlib.register('cmake.new-analysisalg', 'PyUtils.scripts.cmake_newanalysisalg:main')
+acmdlib.register('cmake.new-skeleton', 'PyUtils.scripts.cmake_newskeleton')
+acmdlib.register('cmake.new-pkg', 'PyUtils.scripts.cmake_newpkg')
+acmdlib.register('cmake.new-analysisalg', 'PyUtils.scripts.cmake_newanalysisalg')
 
-acmdlib.register('jira.issues', 'PyUtils.scripts.jira_issues:main')
-# acmdlib.register('jira.issue', 'PyUtils.scripts.jira_issue:main')
+acmdlib.register('jira.issues', 'PyUtils.scripts.jira_issues')
 ##
-
-- 
GitLab