From b1d64c287c4346d2c5be5fe4cee278914ea86042 Mon Sep 17 00:00:00 2001 From: Darren J Moffat Date: Mon, 29 Apr 2019 17:14:00 +0100 Subject: [PATCH] PSARC/2019/061 pkglint extension_path 29704610 pkglint extension_path --- src/man/pkglint.1 | 19 ++++++++++++++++--- src/modules/lint/engine.py | 28 +++++++++++++++++++++++++--- src/util/publish/pkglint.py | 10 +++++++--- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/man/pkglint.1 b/src/man/pkglint.1 index ebb945793..dbab667ef 100644 --- a/src/man/pkglint.1 +++ b/src/man/pkglint.1 @@ -10,7 +10,7 @@ &man1; &release; generic -Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. pkglintImage Packaging System package lint @@ -18,7 +18,7 @@ /usr/bin/pkglint [-c cache_dir] [-r repo_uri]... [-p regexp] - [-f config_file] [-b branch] + [-e extension_path] [-f config_file] [-b branch] [-v] [-l lint_uri]... | manifest ... /usr/bin/pkglint -L [-v] @@ -101,6 +101,11 @@ display the method that implements the check instead of the description. config_file configuration file. + extension_path +Directroy to add to the Python search path when loading +pkglint extensions. + + regexp Specify a regular expression used to narrow the list of packages to be checked from the lint repository. All manifests from the reference repository @@ -143,7 +148,15 @@ make sense for published packages. The default value is True. The plugin mechanism of pkglint allows for additional lint modules to be added at runtime. Any key that starts with pkglint.ext. takes a value that must be a fully-specified Python -module. See the “Developers” section for more information. +module. See the “Developers” section for more information. +The extension_path option specifies additional directory +locations to search when loading extensions + + +extension_path +An list of directories, separated by ':' no most platforms, to search +for extension modules. If the -e flag is specified on the CLI it is added higher +in the search order than this config file option. pkglint.exclude diff --git a/src/modules/lint/engine.py b/src/modules/lint/engine.py index d3c0a7d1c..b2fe3585a 100644 --- a/src/modules/lint/engine.py +++ b/src/modules/lint/engine.py @@ -21,7 +21,7 @@ # # -# Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. # import pkg.client.api @@ -289,7 +289,7 @@ class LintEngine(object): see the comment for .execute()""" def __init__(self, formatter, verbose=False, config_file=None, - use_tracker=None): + use_tracker=None, extension_path=[]): """Creates a lint engine a given pkg.lint.log.LogFormatter. 'verbose' overrides any log_level settings in the config file to DEBUG @@ -329,8 +329,14 @@ def __init__(self, formatter, verbose=False, config_file=None, # whether to ignore publisher differences when comparing vers self.ignore_pubs = True + # Ensure extension_path is always a list even if empty + self.extension_path = extension_path + if not self.extension_path: + self.extension_path = [] + self.conf = self.load_config(config_file, verbose=verbose) - # overrides config_file entry + + # override config_file entry if use_tracker is not None: self.use_tracker = use_tracker @@ -359,8 +365,15 @@ def _load_checker_module(self, name, config): instances of the checker classes the module declares, assuming they haven't been excluded by the config object.""" + # Make a copy of sys.path so we can revert it after module load + _preserved_sys_path = list(sys.path) try: self.logger.debug("Loading module {0}".format(name)) + # Temporarily add the extension paths to sys.path + # Any paths specified in the init call take precedence + # over the config file. + sys.path.extend(self.extension_path) + # the fifth parameter is 'level', which defautls to -1 # in Python 2 and 0 in Python 3. __import__(name, None, None, []) @@ -369,6 +382,9 @@ def _load_checker_module(self, name, config): return (checkers, excluded) except (KeyError, ImportError) as err: raise base.LintException(err) + finally: + # Reset sys.path + sys.path = _preserved_sys_path def _unique_checkers(self): """Ensure that the engine has unique names for all of the loaded @@ -426,6 +442,12 @@ def load_config(self, config, verbose=False): except configparser.NoOptionError: pass + try: + self.extension_path.extend(conf.get("pkglint", + "extension_path").split(os.pathsep)) + except configparser.NoOptionError: + pass + for key, value in conf.items("pkglint"): if "pkglint.ext" in key: if value in excl: diff --git a/src/util/publish/pkglint.py b/src/util/publish/pkglint.py index 50aca6bd8..a174c38b3 100755 --- a/src/util/publish/pkglint.py +++ b/src/util/publish/pkglint.py @@ -29,6 +29,7 @@ import logging import six import sys +import os import gettext import locale import traceback @@ -72,6 +73,7 @@ def main_func(): _("\n" " %prog [-b branch] [-c cache_dir] [-f file]\n" " [-l uri ...] [-p regexp] [-r uri ...] [-v]\n" + " [-e extension_path ...]\n" " manifest ...\n" " %prog -L") parser = OptionParser(usage=usage) @@ -91,9 +93,10 @@ def main_func(): help=_("pattern to match FMRIs in lint URI")) parser.add_option("-r", dest="ref_uris", metavar="uri", action="append", help=_("reference repository URI")) + parser.add_option("-e", dest="extension_path", metavar="dir", + action="append", help=_("extension_path")) parser.add_option("-v", dest="verbose", action="store_true", - help=_("produce verbose output, overriding settings in pkglintrc") - ) + help=_("produce verbose output, overriding settings in pkglintrc")) opts, args = parser.parse_args(sys.argv[1:]) @@ -126,7 +129,8 @@ def main_func(): if not opts.list_checks: msg(_("Lint engine setup...")) lint_engine = engine.LintEngine(lint_logger, - config_file=opts.config, verbose=opts.verbose) + config_file=opts.config, verbose=opts.verbose, + extension_path=opts.extension_path) if opts.list_checks: list_checks(lint_engine.checkers,