qvm-template: factor filter_version() out of get_dl_list()

This allows reusing version filtering (getting only a single version per
template) in other places.

For equal versions packages, prefer the one from non-testing repository.
This commit is contained in:
Marek Marczykowski-Górecki 2021-02-06 03:34:39 +01:00
parent 10bea1b77e
commit 86326b53c4
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724

View File

@ -263,6 +263,11 @@ class Template(typing.NamedTuple):
summary: str summary: str
description: str description: str
@property
def evr(self):
"""Return a tuple of (EPOCH, VERSION, RELEASE)"""
return self.epoch, self.version, self.release
class DlEntry(typing.NamedTuple): class DlEntry(typing.NamedTuple):
"""Information about a template to be downloaded.""" """Information about a template to be downloaded."""
evr: typing.Tuple[str, str, str] evr: typing.Tuple[str, str, str]
@ -634,6 +639,50 @@ def extract_rpm(name: str, path: str, target: str) -> bool:
], stdin=rpm2cpio.stdout, stdout=subprocess.DEVNULL) ], stdin=rpm2cpio.stdout, stdout=subprocess.DEVNULL)
return rpm2cpio.wait() == 0 and cpio.wait() == 0 return rpm2cpio.wait() == 0 and cpio.wait() == 0
def filter_version(
query_res,
app: qubesadmin.app.QubesBase,
version_selector: VersionSelector = VersionSelector.LATEST):
"""Select only one version for given template name"""
# We only select one package for each distinct package name
results: typing.Dict[str, Template] = {}
for entry in query_res:
evr = (entry.epoch, entry.version, entry.release)
insert = False
if version_selector == VersionSelector.LATEST:
if entry.name not in results:
insert = True
if entry.name in results \
and rpm.labelCompare(results[entry.name].evr, evr) < 0:
insert = True
if entry.name in results \
and rpm.labelCompare(results[entry.name].evr, evr) == 0 \
and 'testing' not in entry.reponame:
# for the same-version matches, prefer non-testing one
insert = True
elif version_selector == VersionSelector.REINSTALL:
vm = get_managed_template_vm(app, entry.name)
cur_ver = query_local_evr(vm)
if rpm.labelCompare(evr, cur_ver) == 0:
insert = True
elif version_selector in [VersionSelector.LATEST_LOWER,
VersionSelector.LATEST_HIGHER]:
vm = get_managed_template_vm(app, entry.name)
cur_ver = query_local_evr(vm)
cmp_res = -1 \
if version_selector == VersionSelector.LATEST_LOWER \
else 1
if rpm.labelCompare(evr, cur_ver) == cmp_res:
if entry.name not in results \
or rpm.labelCompare(results[entry.name].evr, evr) < 0:
insert = True
if insert:
results[entry.name] = entry
return results.values()
def get_dl_list( def get_dl_list(
args: argparse.Namespace, args: argparse.Namespace,
app: qubesadmin.app.QubesBase, app: qubesadmin.app.QubesBase,
@ -651,10 +700,6 @@ def get_dl_list(
""" """
full_candid: typing.Dict[str, DlEntry] = {} full_candid: typing.Dict[str, DlEntry] = {}
for template in args.templates: for template in args.templates:
# This will be merged into `full_candid` later.
# It is separated so that we can check whether it is empty.
candid: typing.Dict[str, DlEntry] = {}
# Skip local RPMs # Skip local RPMs
if template.endswith('.rpm'): if template.endswith('.rpm'):
continue continue
@ -662,35 +707,10 @@ def get_dl_list(
query_res = qrexec_repoquery(args, app, PACKAGE_NAME_PREFIX + template) query_res = qrexec_repoquery(args, app, PACKAGE_NAME_PREFIX + template)
# We only select one package for each distinct package name # We only select one package for each distinct package name
for entry in query_res: query_res = filter_version(query_res, app, version_selector)
ver = (entry.epoch, entry.version, entry.release)
insert = False
if version_selector == VersionSelector.LATEST:
if entry.name not in candid \
or rpm.labelCompare(candid[entry.name][0], ver) < 0:
insert = True
elif version_selector == VersionSelector.REINSTALL:
vm = get_managed_template_vm(app, entry.name)
cur_ver = query_local_evr(vm)
if rpm.labelCompare(ver, cur_ver) == 0:
insert = True
elif version_selector in [VersionSelector.LATEST_LOWER,
VersionSelector.LATEST_HIGHER]:
vm = get_managed_template_vm(app, entry.name)
cur_ver = query_local_evr(vm)
cmp_res = -1 \
if version_selector == VersionSelector.LATEST_LOWER \
else 1
if rpm.labelCompare(ver, cur_ver) == cmp_res:
if entry.name not in candid \
or rpm.labelCompare(candid[entry.name][0], ver) < 0:
insert = True
if insert:
candid[entry.name] = DlEntry(ver, entry.reponame, entry.dlsize)
# XXX: As it's possible to include version information in `template`, # XXX: As it's possible to include version information in `template`,
# perhaps the messages can be improved # perhaps the messages can be improved
if len(candid) == 0: if len(query_res) == 0:
if version_selector == VersionSelector.LATEST: if version_selector == VersionSelector.LATEST:
parser.error('Template \'%s\' not found.' % template) parser.error('Template \'%s\' not found.' % template)
elif version_selector == VersionSelector.REINSTALL: elif version_selector == VersionSelector.REINSTALL:
@ -707,10 +727,12 @@ def get_dl_list(
file=sys.stderr) file=sys.stderr)
# Merge & choose the template with the highest version # Merge & choose the template with the highest version
for name, dlentry in candid.items(): for entry in query_res:
if name not in full_candid \ if entry.name not in full_candid \
or rpm.labelCompare(full_candid[name].evr, dlentry.evr) < 0: or rpm.labelCompare(full_candid[entry.name].evr,
full_candid[name] = dlentry entry.evr) < 0:
full_candid[entry.name] = \
DlEntry(entry.evr, entry.reponame, entry.dlsize)
return full_candid return full_candid