|
|
|
@ -39,7 +39,7 @@ from britney2.consts import (VERSION, PROVIDES, DEPENDS, CONFLICTS,
|
|
|
|
|
SOURCE, MAINTAINER, MULTIARCH,
|
|
|
|
|
ESSENTIAL)
|
|
|
|
|
from britney2.migrationitem import MigrationItem, UnversionnedMigrationItem
|
|
|
|
|
from britney2.policies.policy import PolicyVerdict
|
|
|
|
|
from britney2.policies import PolicyVerdict
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def ifilter_except(container, iterable=None):
|
|
|
|
@ -258,7 +258,7 @@ def eval_uninst(architectures, nuninst):
|
|
|
|
|
return "".join(parts)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def write_heidi(filename, sources_t, packages_t, sorted=sorted):
|
|
|
|
|
def write_heidi(filename, sources_t, packages_t, *, outofsync_arches=frozenset(), sorted=sorted):
|
|
|
|
|
"""Write the output HeidiResult
|
|
|
|
|
|
|
|
|
|
This method write the output for Heidi, which contains all the
|
|
|
|
@ -271,6 +271,10 @@ def write_heidi(filename, sources_t, packages_t, sorted=sorted):
|
|
|
|
|
packages in "sources_t" and "packages_t" to be the packages in
|
|
|
|
|
"testing".
|
|
|
|
|
|
|
|
|
|
outofsync_arches: If given, it is a set of architectures marked
|
|
|
|
|
as "out of sync". The output file may exclude some out of date
|
|
|
|
|
arch:all packages for those architectures to reduce the noise.
|
|
|
|
|
|
|
|
|
|
The "X=X" parameters are optimizations to avoid "load global" in
|
|
|
|
|
the loops.
|
|
|
|
|
"""
|
|
|
|
@ -288,7 +292,8 @@ def write_heidi(filename, sources_t, packages_t, sorted=sorted):
|
|
|
|
|
# Faux package; not really a part of testing
|
|
|
|
|
continue
|
|
|
|
|
if pkg.source_version and pkgarch == 'all' and \
|
|
|
|
|
pkg.source_version != sources_t[pkg.source].version:
|
|
|
|
|
pkg.source_version != sources_t[pkg.source].version and \
|
|
|
|
|
arch in outofsync_arches:
|
|
|
|
|
# when architectures are marked as "outofsync", their binary
|
|
|
|
|
# versions may be lower than those of the associated
|
|
|
|
|
# source package in testing. the binary package list for
|
|
|
|
@ -721,27 +726,41 @@ def read_sources_file(filename, sources=None, intern=sys.intern):
|
|
|
|
|
section = get_field('Section')
|
|
|
|
|
if section:
|
|
|
|
|
section = intern(section.strip())
|
|
|
|
|
build_deps_arch = ", ".join(x for x in (get_field('Build-Depends'), get_field('Build-Depends-Arch'))
|
|
|
|
|
if x is not None)
|
|
|
|
|
if build_deps_arch != '':
|
|
|
|
|
build_deps_arch = sys.intern(build_deps_arch)
|
|
|
|
|
else:
|
|
|
|
|
build_deps_arch = None
|
|
|
|
|
sources[intern(pkg)] = SourcePackage(intern(ver),
|
|
|
|
|
section,
|
|
|
|
|
[],
|
|
|
|
|
maint,
|
|
|
|
|
False,
|
|
|
|
|
build_deps_arch,
|
|
|
|
|
get_field('Testsuite', '').split(),
|
|
|
|
|
get_field('Testsuite-Triggers', '').replace(',', '').split(),
|
|
|
|
|
)
|
|
|
|
|
return sources
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_dependency_solvers(block, binaries_s_a, provides_s_a, *, empty_set=frozenset()):
|
|
|
|
|
def get_dependency_solvers(block, binaries_s_a, provides_s_a, *, build_depends=False, empty_set=frozenset()):
|
|
|
|
|
"""Find the packages which satisfy a dependency block
|
|
|
|
|
|
|
|
|
|
This method returns the list of packages which satisfy a dependency
|
|
|
|
|
block (as returned by apt_pkg.parse_depends) in a package table
|
|
|
|
|
for a given suite and architecture (a la self.binaries[suite][arch])
|
|
|
|
|
|
|
|
|
|
:param block: The dependency block as parsed by apt_pkg.parse_depends
|
|
|
|
|
It can also handle build-dependency relations if the named parameter
|
|
|
|
|
"build_depends" is set to True. In this case, block should be based
|
|
|
|
|
on the return value from apt_pkg.parse_src_depends.
|
|
|
|
|
|
|
|
|
|
:param block: The dependency block as parsed by apt_pkg.parse_depends (or apt_pkg.parse_src_depends
|
|
|
|
|
if the "build_depends" is True)
|
|
|
|
|
:param binaries_s_a: A dict mapping package names to the relevant BinaryPackage
|
|
|
|
|
:param provides_s_a: A dict mapping package names to their providers (as generated by parse_provides)
|
|
|
|
|
:param build_depends: If True, treat the "block" parameter as a build-dependency relation rather than
|
|
|
|
|
a regular dependency relation.
|
|
|
|
|
:param empty_set: Internal implementation detail / optimisation
|
|
|
|
|
:return a list of package names solving the relation
|
|
|
|
|
"""
|
|
|
|
@ -760,7 +779,17 @@ def get_dependency_solvers(block, binaries_s_a, provides_s_a, *, empty_set=froze
|
|
|
|
|
# check the versioned dependency and architecture qualifier
|
|
|
|
|
# (if present)
|
|
|
|
|
if (op == '' and version == '') or apt_pkg.check_dep(package.version, op, version):
|
|
|
|
|
if archqual is None or (archqual == 'any' and package.multi_arch == 'allowed'):
|
|
|
|
|
if archqual is None:
|
|
|
|
|
packages.append(name)
|
|
|
|
|
elif build_depends:
|
|
|
|
|
# Multi-arch handling for build-dependencies
|
|
|
|
|
# - :native is ok iff the target is arch:any
|
|
|
|
|
if archqual == 'native' and package.architecture != 'all':
|
|
|
|
|
packages.append(name)
|
|
|
|
|
|
|
|
|
|
# Multi-arch handling for both build-dependencies and regular dependencies
|
|
|
|
|
# - :any is ok iff the target has "M-A: allowed"
|
|
|
|
|
if archqual == 'any' and package.multi_arch == 'allowed':
|
|
|
|
|
packages.append(name)
|
|
|
|
|
|
|
|
|
|
# look for the package in the virtual packages list and loop on them
|
|
|
|
@ -785,20 +814,23 @@ def invalidate_excuses(excuses, valid, invalid):
|
|
|
|
|
"""Invalidate impossible excuses
|
|
|
|
|
|
|
|
|
|
This method invalidates the impossible excuses, which depend
|
|
|
|
|
on invalid excuses. The two parameters contains the list of
|
|
|
|
|
on invalid excuses. The two parameters contains the sets of
|
|
|
|
|
`valid' and `invalid' excuses.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# build the reverse dependencies
|
|
|
|
|
revdeps = defaultdict(list)
|
|
|
|
|
revbuilddeps = defaultdict(list)
|
|
|
|
|
for exc in excuses.values():
|
|
|
|
|
for d in exc.deps:
|
|
|
|
|
revdeps[d].append(exc.name)
|
|
|
|
|
for d in exc.arch_build_deps:
|
|
|
|
|
revbuilddeps[d].append(exc.name)
|
|
|
|
|
|
|
|
|
|
# loop on the invalid excuses
|
|
|
|
|
for i, ename in enumerate(invalid):
|
|
|
|
|
for ename in iter_except(invalid.pop, KeyError):
|
|
|
|
|
# if there is no reverse dependency, skip the item
|
|
|
|
|
if ename not in revdeps:
|
|
|
|
|
if ename not in revdeps and ename not in revbuilddeps:
|
|
|
|
|
continue
|
|
|
|
|
# if the dependency can be satisfied by a testing-proposed-updates excuse, skip the item
|
|
|
|
|
if (ename + "_tpu") in valid:
|
|
|
|
@ -809,21 +841,34 @@ def invalidate_excuses(excuses, valid, invalid):
|
|
|
|
|
rdep_verdict = PolicyVerdict.REJECTED_BLOCKED_BY_ANOTHER_ITEM
|
|
|
|
|
|
|
|
|
|
# loop on the reverse dependencies
|
|
|
|
|
for x in revdeps[ename]:
|
|
|
|
|
if x in valid:
|
|
|
|
|
# if the item is valid and it is marked as `forced', skip the item
|
|
|
|
|
if excuses[x].forced:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
# otherwise, invalidate the dependency and mark as invalidated and
|
|
|
|
|
# remove the depending excuses
|
|
|
|
|
excuses[x].invalidate_dep(ename)
|
|
|
|
|
p = valid.index(x)
|
|
|
|
|
invalid.append(valid.pop(p))
|
|
|
|
|
excuses[x].addhtml("Invalidated by dependency")
|
|
|
|
|
excuses[x].addreason("depends")
|
|
|
|
|
if excuses[x].policy_verdict.value < rdep_verdict.value:
|
|
|
|
|
excuses[x].policy_verdict = rdep_verdict
|
|
|
|
|
if ename in revdeps:
|
|
|
|
|
for x in revdeps[ename]:
|
|
|
|
|
# if the item is valid and it is not marked as `forced', then we invalidate it
|
|
|
|
|
if x in valid and not excuses[x].forced:
|
|
|
|
|
|
|
|
|
|
# otherwise, invalidate the dependency and mark as invalidated and
|
|
|
|
|
# remove the depending excuses
|
|
|
|
|
excuses[x].invalidate_dep(ename)
|
|
|
|
|
valid.discard(x)
|
|
|
|
|
invalid.add(x)
|
|
|
|
|
excuses[x].addhtml("Invalidated by dependency")
|
|
|
|
|
excuses[x].addreason("depends")
|
|
|
|
|
if excuses[x].policy_verdict.value < rdep_verdict.value:
|
|
|
|
|
excuses[x].policy_verdict = rdep_verdict
|
|
|
|
|
|
|
|
|
|
if ename in revbuilddeps:
|
|
|
|
|
for x in revbuilddeps[ename]:
|
|
|
|
|
# if the item is valid and it is not marked as `forced', then we invalidate it
|
|
|
|
|
if x in valid and not excuses[x].forced:
|
|
|
|
|
|
|
|
|
|
# otherwise, invalidate the dependency and mark as invalidated and
|
|
|
|
|
# remove the depending excuses
|
|
|
|
|
excuses[x].invalidate_build_dep(ename)
|
|
|
|
|
valid.discard(x)
|
|
|
|
|
invalid.add(x)
|
|
|
|
|
excuses[x].addhtml("Invalidated by build-dependency")
|
|
|
|
|
if excuses[x].policy_verdict.value < rdep_verdict.value:
|
|
|
|
|
excuses[x].policy_verdict = rdep_verdict
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def compile_nuninst(binaries_t, inst_tester, architectures, nobreakall_arches):
|
|
|
|
|