If there are no special fmf features used, fmf is a plain yaml. Which is case here so there is no need to use 'fmf' to parse plan.fmf
90 lines
3.3 KiB
Python
Executable file
90 lines
3.3 KiB
Python
Executable file
#!/usr/bin/python3
|
|
"""
|
|
Several packages with various Python interpreters *Supplement* tox.
|
|
*Supplements* is a reverse dependency to *Recommends*.
|
|
|
|
See https://lists.fedoraproject.org/archives/list/python-devel@lists.fedoraproject.org/thread/NVVUXSVSPFQOWIGBE2JNI67HEO7R63ZQ/
|
|
|
|
This script:
|
|
|
|
1) figures out all packages in the enabled repositories supplementing tox
|
|
2) ensures there is a venv.sh test for each of them in plan.fmf
|
|
|
|
That way, when we change tox (update, patch, etc.),
|
|
we will always test it with all Pythons that supplement it.
|
|
"""
|
|
|
|
import shlex
|
|
import subprocess
|
|
import sys
|
|
import yaml
|
|
|
|
|
|
def parse_python_test_arg(command):
|
|
tokens = shlex.split(command)
|
|
for token in tokens:
|
|
if token.startswith('PYTHON='):
|
|
return token.removeprefix('PYTHON=')
|
|
# only check VERSION if PYTHON was not found
|
|
for token in tokens:
|
|
if token.startswith('VERSION='):
|
|
return 'python' + token.removeprefix('VERSION=')
|
|
raise RuntimeError(f'Could not determine the Python version from `{command}`')
|
|
|
|
|
|
# First, construct a set of various Pythons we test, e.g. {python3.10, python3.7, pypy3.6, ...}
|
|
tested_pythons = set()
|
|
with open('plan.fmf') as f:
|
|
plan_fmf = yaml.safe_load(f)
|
|
# this nested structure access is quite fragile,
|
|
# but at least it should fail the test if we reach to a wrong place
|
|
for discover_section in plan_fmf['discover']:
|
|
if discover_section['name'] != 'tests_python':
|
|
continue
|
|
for test in discover_section['tests']:
|
|
test_cmd = test['test']
|
|
if test_cmd.endswith('./venv.sh'):
|
|
tested_pythons.add(parse_python_test_arg(test_cmd))
|
|
print('Tested Pythons found in plan.fmf:', file=sys.stderr)
|
|
for python in sorted(tested_pythons):
|
|
print(' ', python, file=sys.stderr)
|
|
|
|
|
|
# Get all packages that supplement tox,
|
|
# no repo explicitly specified means we use the enabled repos on the CI system which should be what we want
|
|
repoquery_result = subprocess.check_output(['dnf-3', 'repoquery', '--whatsupplements', 'tox'], text=True)
|
|
supplementing_pkgs = set(repoquery_result.splitlines())
|
|
|
|
|
|
# It gets quite tricky, since packages like "pypy" can supplement tox, we get a set of provides for all of them
|
|
supplementing_pkgs_provides = {}
|
|
for nvra in supplementing_pkgs:
|
|
repoquery_result = subprocess.check_output(['dnf-3', '-q', 'repoquery', '--provides', nvra], text=True)
|
|
provides = set(repoquery_result.splitlines())
|
|
unversioned_provides = {provide.split(' ')[0] for provide in provides}
|
|
supplementing_pkgs_provides[nvra.rsplit('-', 2)[0]] = unversioned_provides
|
|
|
|
|
|
# We use this hack to treat -devel and -libs packages as if they were not such
|
|
def normalize_name(pkgname):
|
|
for suffix in '-devel', '-libs':
|
|
if pkgname.endswith(suffix):
|
|
return pkgname.removesuffix(suffix)
|
|
return pkgname
|
|
|
|
|
|
# Now, for each package that supplements tox, we check if there is a tested Python that *is* it
|
|
exit_code = 0
|
|
for pkg, provides in supplementing_pkgs_provides.items():
|
|
if normalize_name(pkg) in tested_pythons:
|
|
print(f'{pkg} is tested', file=sys.stderr)
|
|
continue
|
|
for provide in provides:
|
|
if normalize_name(provide) in tested_pythons:
|
|
print(f'{pkg} is tested (via {provide})', file=sys.stderr)
|
|
break
|
|
else:
|
|
print(f'{pkg} is NOT tested', file=sys.stderr)
|
|
exit_code = 1
|
|
|
|
sys.exit(exit_code)
|