salt/tasks/loader.py
Pedro Algarvio 4d49013247 Update to isort 5.10.1
Signed-off-by: Pedro Algarvio <palgarvio@vmware.com>
2022-08-01 12:49:16 -06:00

103 lines
3.4 KiB
Python

"""
tasks.loader
~~~~~~~~~~~~
Salt loader checks
"""
import ast
import pathlib
from invoke import task # pylint: disable=3rd-party-module-not-gated
from salt.loader import SALT_INTERNAL_LOADERS_PATHS
from tasks import utils
CODE_DIR = pathlib.Path(__file__).resolve().parent.parent
SALT_CODE_DIR = CODE_DIR / "salt"
@task(iterable=["files"], positional=["files"])
def check_virtual(ctx, files, enforce_virtualname=False):
"""
Check Salt loader modules for a defined `__virtualname__` attribute and `__virtual__` function.
This is meant to replace:
https://github.com/saltstack/salt/blob/27ae8260983b11fe6e32a18e777d550be9fe1dc2/tests/unit/test_virtualname.py
"""
# CD into Salt's repo root directory
ctx.cd(CODE_DIR)
# Unfortunately invoke does not support nargs.
# We migth have been passed --files="foo.py bar.py"
# Turn that into a list of paths
_files = []
for path in files:
if not path:
continue
_files.extend(path.split())
if not _files:
_files = SALT_CODE_DIR.rglob("*.py")
else:
_files = [pathlib.Path(fname) for fname in _files]
_files = [path.resolve() for path in _files]
errors = 0
exitcode = 0
for path in _files:
strpath = str(path)
if path.name == "__init__.py":
continue
for loader in SALT_INTERNAL_LOADERS_PATHS:
try:
path.relative_to(loader)
break
except ValueError:
# Path doesn't start with the loader path, carry on
continue
module = ast.parse(path.read_text(), filename=str(path))
found_virtual_func = False
for funcdef in [
node for node in module.body if isinstance(node, ast.FunctionDef)
]:
if funcdef.name == "__virtual__":
found_virtual_func = True
break
if not found_virtual_func:
# If the module does not define a __virtual__() function, we don't require a __virtualname__ attribute
continue
found_virtualname_attr = False
for node in module.body:
if isinstance(node, ast.Assign):
if not found_virtualname_attr:
for target in node.targets:
if not isinstance(target, ast.Name):
continue
if target.id == "__virtualname__":
found_virtualname_attr = True
if node.value.s not in path.name:
errors += 1
exitcode = 1
utils.error(
'The value of the __virtualname__ attribute, "{}"'
" is not part of {}",
node.value.s,
path.name,
)
if found_virtualname_attr:
break
if not found_virtualname_attr and enforce_virtualname:
errors += 1
exitcode = 1
utils.error(
"The salt loader module {} defines a __virtual__() function but does"
" not define a __virtualname__ attribute",
path.relative_to(CODE_DIR),
)
if exitcode:
utils.error("Found {} errors", errors)
utils.exit_invoke(exitcode)