From 1ec14ec5dce235e76f24a73cf01d23e092bf858b Mon Sep 17 00:00:00 2001 From: Yu Ming Zhu Date: Thu, 28 Feb 2019 09:59:20 +0000 Subject: [PATCH] adjust cli plugin config description --- cli/koji | 61 ++++++++++--------- cli/koji.conf | 3 +- .../{plugins => cli_plugins1}/not_plugin.omg | 0 .../data/{plugins => cli_plugins1}/plugin1.py | 5 ++ .../data/{plugins => cli_plugins1}/plugin2.py | 0 .../{plugins2 => cli_plugins2}/plugin2.py | 1 + .../{plugins2 => cli_plugins2}/plugin3.py | 1 + tests/test_cli/test_load_plugins.py | 17 ++++-- 8 files changed, 52 insertions(+), 36 deletions(-) rename tests/test_cli/data/{plugins => cli_plugins1}/not_plugin.omg (100%) rename tests/test_cli/data/{plugins => cli_plugins1}/plugin1.py (97%) rename tests/test_cli/data/{plugins => cli_plugins1}/plugin2.py (100%) rename tests/test_cli/data/{plugins2 => cli_plugins2}/plugin2.py (98%) rename tests/test_cli/data/{plugins2 => cli_plugins2}/plugin3.py (99%) diff --git a/cli/koji b/cli/koji index fc83745c..d87653f2 100755 --- a/cli/koji +++ b/cli/koji @@ -65,24 +65,40 @@ def register_plugin(plugin): globals()[name] = v -def load_plugins(options, paths): - """Load plugins specified by our configuration plus system plugins. Order - is that system plugins are first, so they can be overridden by - user-specified ones with same name.""" +def load_plugins(plugin_paths): + """Load plugins specified by input paths, ~/.koji/plugins, system plugins. + Loading order is descending, so they can be overridden by user-specified + ones. + Notice that: + - plugin file should end with .py extension + - non-directory is not acceptable by plugin_paths + - all plugin files and the exported handlers inside will be loaded, and + handler with the same name will override the one has already been loaded + before""" + logger = logging.getLogger('koji.plugins') - tracker = koji.plugin.PluginTracker(path=paths) - names = set() + paths = [] + # first, always load plugins from koji_cli_plugins module + paths.append( + '%s/lib/python%s.%s/site-packages/koji_cli_plugins' % + (sys.prefix, sys.version_info[0], sys.version_info[1])) + # second, always load plugins from ~/.koji/plugins + paths.append(os.path.expanduser('~/.koji/plugins')) + # finally, update plugin_paths to the list + if plugin_paths: + if not isinstance(plugin_paths, (list, tuple)): + plugin_paths = plugin_paths.split(':') + paths.extend([os.path.expanduser(p) for p in reversed(plugin_paths)]) + tracker = koji.plugin.PluginTracker() for path in paths: - if os.path.exists(path): + if os.path.exists(path) and os.path.isdir(path): for name in sorted(os.listdir(path)): - if not name.endswith('.py'): + fullname = os.path.join(path, name) + if not (os.path.isfile(fullname) and name.endswith('.py')): continue name = name[:-3] - names.add(name) - for name in names: - logger.info('Loading plugin: %s', name) - tracker.load(name) - register_plugin(tracker.get(name)) + logger.info('Loading plugin: %s', fullname) + register_plugin(tracker.load(name, path=path, reload=True)) def get_options(): @@ -130,7 +146,8 @@ def get_options(): parser.add_option("--pkgurl", help=SUPPRESS_HELP) parser.add_option("--plugin-paths", metavar='PATHS', help=_("specify plugin paths with format as the same as the shell's PATH, " - "'~/.koji/plugins', koji_cli_plugins module are always appended")) + "koji_cli_plugins module and '~/.koji/plugins' are always loaded in advance, " + "and then overridden by this option.")) parser.add_option("--help-commands", action="store_true", default=False, help=_("list commands")) (options, args) = parser.parse_args() @@ -170,21 +187,7 @@ def get_options(): else: warn("Warning: The pkgurl option is obsolete, please use topurl instead") - # update plugin_paths to list - plugin_paths = options.plugin_paths - if plugin_paths: - plugin_paths = [os.path.expanduser(p) for p in - plugin_paths.split(':')] - else: - plugin_paths = [] - # always load plugins from ~/.koji/plugins - plugin_paths.append(os.path.expanduser('~/.koji/plugins')) - # always load plugins from koji_cli_plugins module - plugin_paths.append( - '%s/lib/python%s.%s/site-packages/koji_cli_plugins' % - (sys.prefix, sys.version_info[0], sys.version_info[1])) - setattr(options, 'plugin_paths', plugin_paths) - load_plugins(options, plugin_paths) + load_plugins(options.plugin_paths) if not args: options.help_commands = True diff --git a/cli/koji.conf b/cli/koji.conf index 70aa5432..0a278107 100644 --- a/cli/koji.conf +++ b/cli/koji.conf @@ -38,7 +38,8 @@ ;serverca = ~/.koji/serverca.crt ;plugin paths, separated by ':' as the same as the shell's PATH -;~/.koji/plugins and koji_cli_plugins module are always be appended +;koji_cli_plugins module and ~/.koji/plugins are always loaded in advance, +;and then be overridden by this option ;plugin_paths = ~/.koji/plugins ;[not_implemented_yet] diff --git a/tests/test_cli/data/plugins/not_plugin.omg b/tests/test_cli/data/cli_plugins1/not_plugin.omg similarity index 100% rename from tests/test_cli/data/plugins/not_plugin.omg rename to tests/test_cli/data/cli_plugins1/not_plugin.omg diff --git a/tests/test_cli/data/plugins/plugin1.py b/tests/test_cli/data/cli_plugins1/plugin1.py similarity index 97% rename from tests/test_cli/data/plugins/plugin1.py rename to tests/test_cli/data/cli_plugins1/plugin1.py index 41d876e2..12622a8b 100644 --- a/tests/test_cli/data/plugins/plugin1.py +++ b/tests/test_cli/data/cli_plugins1/plugin1.py @@ -1,20 +1,25 @@ from __future__ import absolute_import from koji.plugin import export_cli, export_as + @export_as('foobar') @export_cli def foo(): pass + @export_cli def foo2(): pass + def foo3(): pass + foo4 = 'foo4' + class bar(): pass diff --git a/tests/test_cli/data/plugins/plugin2.py b/tests/test_cli/data/cli_plugins1/plugin2.py similarity index 100% rename from tests/test_cli/data/plugins/plugin2.py rename to tests/test_cli/data/cli_plugins1/plugin2.py diff --git a/tests/test_cli/data/plugins2/plugin2.py b/tests/test_cli/data/cli_plugins2/plugin2.py similarity index 98% rename from tests/test_cli/data/plugins2/plugin2.py rename to tests/test_cli/data/cli_plugins2/plugin2.py index 336aaf4e..38a2e413 100644 --- a/tests/test_cli/data/plugins2/plugin2.py +++ b/tests/test_cli/data/cli_plugins2/plugin2.py @@ -1,5 +1,6 @@ from koji.plugin import export_cli + @export_cli def foo5(): pass diff --git a/tests/test_cli/data/plugins2/plugin3.py b/tests/test_cli/data/cli_plugins2/plugin3.py similarity index 99% rename from tests/test_cli/data/plugins2/plugin3.py rename to tests/test_cli/data/cli_plugins2/plugin3.py index 304db206..253be594 100644 --- a/tests/test_cli/data/plugins2/plugin3.py +++ b/tests/test_cli/data/cli_plugins2/plugin3.py @@ -1,5 +1,6 @@ from koji.plugin import export_cli, export_as + @export_as('foo6') @export_cli def foo(): diff --git a/tests/test_cli/test_load_plugins.py b/tests/test_cli/test_load_plugins.py index f9368b9b..7e7e7b11 100644 --- a/tests/test_cli/test_load_plugins.py +++ b/tests/test_cli/test_load_plugins.py @@ -1,6 +1,7 @@ from __future__ import absolute_import import os + try: import unittest2 as unittest except ImportError: @@ -9,20 +10,24 @@ except ImportError: import mock from . import loadcli + cli = loadcli.cli class TestLoadPlugins(unittest.TestCase): @mock.patch('logging.getLogger') - def test_load_plugins(self, getLogger): - options = mock.MagicMock() - cli.load_plugins(options, [os.path.dirname(__file__) + '/data/plugins', - os.path.dirname( - __file__) + '/data/plugins2']) + @mock.patch('os.path.isdir') + def test_load_plugins(self, isdir, getLogger): + # skip system path and default user plugin directory check + isdir.side_effect = lambda path: False if path.startswith('/usr') \ + or path == os.path.expanduser("~/.koji/plugins") \ + else True + cli.load_plugins(os.path.dirname(__file__) + '/data/cli_plugins1:' + + os.path.dirname(__file__) + '/data/cli_plugins2') self.assertTrue(callable(cli.foobar)) self.assertTrue(callable(cli.foo2)) self.assertTrue(hasattr(cli, 'foo6')) self.assertFalse(hasattr(cli, 'foo3')) self.assertFalse(hasattr(cli, 'foo4')) - self.assertFalse(hasattr(cli, 'foo5')) + self.assertTrue(hasattr(cli, 'foo5')) self.assertFalse(hasattr(cli, 'sth'))