2020-04-23 13:51:03 +01:00
|
|
|
"""
|
2023-11-15 16:14:39 +00:00
|
|
|
Salt loader checks
|
2020-04-23 13:51:03 +01:00
|
|
|
"""
|
|
|
|
|
|
|
|
import ast
|
|
|
|
import pathlib
|
|
|
|
|
2023-11-15 16:14:39 +00:00
|
|
|
from ptscripts import Context, command_group
|
|
|
|
|
|
|
|
import tools.utils
|
|
|
|
from tools.precommit import SALT_INTERNAL_LOADERS_PATHS
|
2022-07-20 10:42:30 +01:00
|
|
|
|
2023-11-15 16:14:39 +00:00
|
|
|
SALT_CODE_DIR = tools.utils.REPO_ROOT / "salt"
|
2020-04-23 13:51:03 +01:00
|
|
|
|
2023-11-15 16:14:39 +00:00
|
|
|
cgroup = command_group(name="salt-loaders", help=__doc__, parent="pre-commit")
|
2020-04-23 13:51:03 +01:00
|
|
|
|
|
|
|
|
2023-11-15 16:14:39 +00:00
|
|
|
@cgroup.command(
|
|
|
|
name="check-virtual",
|
|
|
|
arguments={
|
|
|
|
"files": {
|
|
|
|
"help": "List of files to check",
|
|
|
|
"nargs": "*",
|
|
|
|
},
|
|
|
|
"enforce_virtualname": {
|
|
|
|
"help": "Enforce the usage of `__virtualname__`",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
def check_virtual(
|
|
|
|
ctx: Context, files: list[pathlib.Path], enforce_virtualname: bool = False
|
|
|
|
) -> None:
|
2020-04-23 13:51:03 +01:00
|
|
|
"""
|
|
|
|
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
|
|
|
|
"""
|
2023-11-15 16:14:39 +00:00
|
|
|
if not files:
|
|
|
|
_files = list(SALT_CODE_DIR.rglob("*.py"))
|
2020-04-23 13:51:03 +01:00
|
|
|
else:
|
2023-11-15 16:14:39 +00:00
|
|
|
_files = [fpath.resolve() for fpath in files if fpath.suffix == ".py"]
|
2020-04-23 13:51:03 +01:00
|
|
|
|
|
|
|
errors = 0
|
|
|
|
exitcode = 0
|
|
|
|
for path in _files:
|
|
|
|
strpath = str(path)
|
2021-06-28 16:26:33 +01:00
|
|
|
if path.name == "__init__.py":
|
2020-04-23 13:51:03 +01:00
|
|
|
continue
|
2021-08-04 07:35:34 +01:00
|
|
|
for loader in SALT_INTERNAL_LOADERS_PATHS:
|
2020-04-23 13:51:03 +01:00
|
|
|
try:
|
|
|
|
path.relative_to(loader)
|
|
|
|
break
|
|
|
|
except ValueError:
|
|
|
|
# Path doesn't start with the loader path, carry on
|
|
|
|
continue
|
2021-06-28 16:26:33 +01:00
|
|
|
module = ast.parse(path.read_text(), filename=str(path))
|
2020-04-23 13:51:03 +01:00
|
|
|
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
|
2023-11-15 16:14:39 +00:00
|
|
|
if node.value.s not in path.name: # type: ignore[attr-defined]
|
2020-04-23 13:51:03 +01:00
|
|
|
errors += 1
|
|
|
|
exitcode = 1
|
2023-11-15 16:14:39 +00:00
|
|
|
ctx.error(
|
2021-08-03 08:40:21 +01:00
|
|
|
'The value of the __virtualname__ attribute, "{}"'
|
2023-11-15 16:14:39 +00:00
|
|
|
" is not part of {}".format(
|
|
|
|
node.value.s, # type: ignore[attr-defined]
|
|
|
|
path.name,
|
|
|
|
)
|
2020-04-23 13:51:03 +01:00
|
|
|
)
|
|
|
|
if found_virtualname_attr:
|
|
|
|
break
|
|
|
|
|
2021-06-28 16:27:57 +01:00
|
|
|
if not found_virtualname_attr and enforce_virtualname:
|
2020-04-23 13:51:03 +01:00
|
|
|
errors += 1
|
|
|
|
exitcode = 1
|
2023-11-15 16:14:39 +00:00
|
|
|
ctx.error(
|
|
|
|
f"The salt loader module {path.relative_to(tools.utils.REPO_ROOT)} defines "
|
|
|
|
"a __virtual__() function but does not define a __virtualname__ attribute"
|
2020-04-23 13:51:03 +01:00
|
|
|
)
|
|
|
|
if exitcode:
|
2023-11-15 16:14:39 +00:00
|
|
|
ctx.error(f"Found {errors} errors")
|
|
|
|
ctx.exit(exitcode)
|