mirror of
https://git.launchpad.net/~ubuntu-release/britney/+git/britney2-ubuntu
synced 2025-03-07 01:01:15 +00:00
inst-builder: Replace RelationBuilder with a set_relations method
Signed-off-by: Niels Thykier <niels@thykier.net>
This commit is contained in:
parent
ab6b2ef953
commit
0446ead9e8
@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
import apt_pkg
|
import apt_pkg
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from contextlib import contextmanager
|
|
||||||
from itertools import product
|
from itertools import product
|
||||||
|
|
||||||
from britney2.utils import ifilter_except, iter_except, get_dependency_solvers
|
from britney2.utils import ifilter_except, iter_except, get_dependency_solvers
|
||||||
@ -42,29 +41,20 @@ def build_installability_tester(suite_info, archs):
|
|||||||
possible_dep_ranges = {}
|
possible_dep_ranges = {}
|
||||||
|
|
||||||
# We do not differentiate between depends and pre-depends
|
# We do not differentiate between depends and pre-depends
|
||||||
if pkgdata.depends:
|
|
||||||
depends.extend(apt_pkg.parse_depends(pkgdata.depends, False))
|
|
||||||
|
|
||||||
if pkgdata.conflicts:
|
if pkgdata.conflicts:
|
||||||
conflicts = apt_pkg.parse_depends(pkgdata.conflicts, False)
|
conflicts_parsed = apt_pkg.parse_depends(pkgdata.conflicts, False)
|
||||||
|
|
||||||
with builder.relation_builder(pkg_id) as relations:
|
|
||||||
|
|
||||||
# Breaks/Conflicts are so simple that we do not need to keep align the relation
|
# Breaks/Conflicts are so simple that we do not need to keep align the relation
|
||||||
# with the suite. This enables us to do a few optimizations.
|
# with the suite. This enables us to do a few optimizations.
|
||||||
if conflicts:
|
for dep_suite in suite_info:
|
||||||
rels = []
|
dep_binaries_s_a, dep_provides_s_a = dep_suite.binaries[arch]
|
||||||
for dep_suite in suite_info:
|
for block in (relation for relation in conflicts_parsed):
|
||||||
dep_binaries_s_a, dep_provides_s_a = dep_suite.binaries[arch]
|
# if a package satisfies its own conflicts relation, then it is using §7.6.2
|
||||||
for block in (relation for relation in conflicts):
|
conflicts.extend(s.pkg_id for s in solvers(block, dep_binaries_s_a, dep_provides_s_a)
|
||||||
# if a package satisfies its own conflicts relation, then it is using §7.6.2
|
if s.pkg_id != pkg_id)
|
||||||
rels.extend(s.pkg_id for s in solvers(block, dep_binaries_s_a, dep_provides_s_a)
|
|
||||||
if s.pkg_id != pkg_id)
|
|
||||||
if rels:
|
|
||||||
relations.add_breaks(rels)
|
|
||||||
|
|
||||||
dep_relations = []
|
if pkgdata.depends:
|
||||||
for block in depends:
|
for block in apt_pkg.parse_depends(pkgdata.depends, False):
|
||||||
sat = set()
|
sat = set()
|
||||||
|
|
||||||
for dep_suite in suite_info:
|
for dep_suite in suite_info:
|
||||||
@ -72,7 +62,7 @@ def build_installability_tester(suite_info, archs):
|
|||||||
sat.update(s.pkg_id for s in solvers(block, dep_binaries_s_a, dep_provides_s_a))
|
sat.update(s.pkg_id for s in solvers(block, dep_binaries_s_a, dep_provides_s_a))
|
||||||
|
|
||||||
if len(block) != 1:
|
if len(block) != 1:
|
||||||
dep_relations.append(sat)
|
depends.append(sat)
|
||||||
else:
|
else:
|
||||||
# This dependency might be a part
|
# This dependency might be a part
|
||||||
# of a version-range a la:
|
# of a version-range a la:
|
||||||
@ -100,81 +90,13 @@ def build_installability_tester(suite_info, archs):
|
|||||||
possible_dep_ranges[key] = sat
|
possible_dep_ranges[key] = sat
|
||||||
|
|
||||||
if possible_dep_ranges:
|
if possible_dep_ranges:
|
||||||
dep_relations.extend(possible_dep_ranges.values())
|
depends.extend(possible_dep_ranges.values())
|
||||||
|
|
||||||
relations.add_dependency_clauses(dep_relations)
|
builder.set_relations(pkg_id, depends, conflicts)
|
||||||
|
|
||||||
return builder.build()
|
return builder.build()
|
||||||
|
|
||||||
|
|
||||||
class _RelationBuilder(object):
|
|
||||||
"""Private helper class to "build" relations"""
|
|
||||||
|
|
||||||
def __init__(self, itbuilder, binary):
|
|
||||||
self._itbuilder = itbuilder
|
|
||||||
self._binary = binary
|
|
||||||
binary_data = itbuilder._package_table[binary]
|
|
||||||
self._new_deps = set(binary_data[0])
|
|
||||||
self._new_breaks = set(binary_data[1])
|
|
||||||
|
|
||||||
def add_dependency_clauses(self, or_clauses):
|
|
||||||
"""Add a dependency clauses
|
|
||||||
|
|
||||||
Each clause must be a sequence BinaryPackageIDs. The clause
|
|
||||||
is an OR clause, i.e. any BinaryPackageID in the
|
|
||||||
sequence can satisfy the relation. It is irrelevant if the
|
|
||||||
dependency is from the "Depends" or the "Pre-Depends" field.
|
|
||||||
|
|
||||||
Note that is the sequence is empty, the dependency is assumed
|
|
||||||
to be unsatisfiable.
|
|
||||||
|
|
||||||
The binaries in the clause are not required to have been added
|
|
||||||
to the InstallabilityTesterBuilder when this method is called.
|
|
||||||
However, they must be added before the "build()" method is
|
|
||||||
called.
|
|
||||||
"""
|
|
||||||
itbuilder = self._itbuilder
|
|
||||||
binary = self._binary
|
|
||||||
interned_or_clauses = [itbuilder._intern_set(c) for c in or_clauses]
|
|
||||||
okay = True
|
|
||||||
for or_clause in interned_or_clauses:
|
|
||||||
if not or_clause:
|
|
||||||
okay = False
|
|
||||||
for dep_tuple in or_clause:
|
|
||||||
rdeps, _, rdep_relations = itbuilder._reverse_relations(dep_tuple)
|
|
||||||
rdeps.add(binary)
|
|
||||||
rdep_relations.add(or_clause)
|
|
||||||
|
|
||||||
self._new_deps.update(interned_or_clauses)
|
|
||||||
if not okay:
|
|
||||||
itbuilder._broken.add(binary)
|
|
||||||
|
|
||||||
def add_breaks(self, breaks_relations):
|
|
||||||
"""Add a Breaks/Conflict-clauses
|
|
||||||
|
|
||||||
Marks the given binary as being broken by any of the packages.
|
|
||||||
That is, the given package satisfies a relation
|
|
||||||
in either the "Breaks" or the "Conflicts" field for any of the
|
|
||||||
listed packages.
|
|
||||||
|
|
||||||
:param breaks_relations: An list/set of BinaryPackageIDs that has a Breaks/Conflicts relation
|
|
||||||
on the current package
|
|
||||||
:return: None
|
|
||||||
"""
|
|
||||||
itbuilder = self._itbuilder
|
|
||||||
self._new_breaks.update(breaks_relations)
|
|
||||||
this_package = self._binary
|
|
||||||
for broken_binary in breaks_relations:
|
|
||||||
reverse_relations = itbuilder._reverse_relations(broken_binary)
|
|
||||||
reverse_relations[1].add(this_package)
|
|
||||||
|
|
||||||
def _commit(self):
|
|
||||||
itbuilder = self._itbuilder
|
|
||||||
data = (itbuilder._intern_set(self._new_deps),
|
|
||||||
itbuilder._intern_set(self._new_breaks))
|
|
||||||
itbuilder._package_table[self._binary] = data
|
|
||||||
|
|
||||||
|
|
||||||
class InstallabilityTesterBuilder(object):
|
class InstallabilityTesterBuilder(object):
|
||||||
"""Builder to create instances of InstallabilityTester"""
|
"""Builder to create instances of InstallabilityTester"""
|
||||||
|
|
||||||
@ -185,7 +107,7 @@ class InstallabilityTesterBuilder(object):
|
|||||||
self._testing = set()
|
self._testing = set()
|
||||||
self._internmap = {}
|
self._internmap = {}
|
||||||
self._broken = set()
|
self._broken = set()
|
||||||
|
self._empty_set = self._intern_set(frozenset())
|
||||||
|
|
||||||
def add_binary(self, binary, essential=False, in_testing=False,
|
def add_binary(self, binary, essential=False, in_testing=False,
|
||||||
frozenset=frozenset):
|
frozenset=frozenset):
|
||||||
@ -226,31 +148,43 @@ class InstallabilityTesterBuilder(object):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def set_relations(self, pkg_id, dependency_clauses, breaks):
|
||||||
|
"""The dependency and breaks realtions for a given package
|
||||||
|
|
||||||
@contextmanager
|
:param pkg_id: BinaryPackageID determining which package will have its relations set
|
||||||
def relation_builder(self, binary):
|
:param dependency_clauses: A list/set of OR clauses (i.e. CNF with each element in
|
||||||
"""Returns a _RelationBuilder for a given binary [context]
|
dependency_clauses being a disjunction). Each OR cause (disjunction) should be a
|
||||||
|
set/list of BinaryPackageIDs that satisfy that relation.
|
||||||
This method returns a context-managed _RelationBuilder for a
|
:param breaks: An list/set of BinaryPackageIDs that has a Breaks/Conflicts relation
|
||||||
given binary. So it should be used in a "with"-statment,
|
on the current package. Can be None
|
||||||
like:
|
:return: No return value
|
||||||
|
|
||||||
with it.relation_builder(binary) as rel:
|
|
||||||
rel.add_dependency_clause(dependency_clause)
|
|
||||||
rel.add_breaks(pkgtuple)
|
|
||||||
...
|
|
||||||
|
|
||||||
The binary given must be a (name, version, architecture)-tuple.
|
|
||||||
|
|
||||||
Note, this method is optimised to be called at most once per
|
|
||||||
binary.
|
|
||||||
"""
|
"""
|
||||||
if binary not in self._package_table: # pragma: no cover
|
if dependency_clauses is not None:
|
||||||
raise ValueError("Binary %s/%s/%s does not exist" % binary)
|
interned_or_clauses = self._intern_set(self._intern_set(c) for c in dependency_clauses)
|
||||||
rel = _RelationBuilder(self, binary)
|
satisfiable = True
|
||||||
yield rel
|
for or_clause in interned_or_clauses:
|
||||||
rel._commit()
|
if not or_clause:
|
||||||
|
satisfiable = False
|
||||||
|
for dep_tuple in or_clause:
|
||||||
|
rdeps, _, rdep_relations = self._reverse_relations(dep_tuple)
|
||||||
|
rdeps.add(pkg_id)
|
||||||
|
rdep_relations.add(or_clause)
|
||||||
|
|
||||||
|
if not satisfiable:
|
||||||
|
self._broken.add(pkg_id)
|
||||||
|
else:
|
||||||
|
interned_or_clauses = self._empty_set
|
||||||
|
|
||||||
|
if breaks is not None:
|
||||||
|
# Breaks
|
||||||
|
breaks_relations = self._intern_set(breaks)
|
||||||
|
for broken_binary in breaks_relations:
|
||||||
|
reverse_relations = self._reverse_relations(broken_binary)
|
||||||
|
reverse_relations[1].add(pkg_id)
|
||||||
|
else:
|
||||||
|
breaks_relations = self._empty_set
|
||||||
|
|
||||||
|
self._package_table[pkg_id] = (interned_or_clauses, breaks_relations)
|
||||||
|
|
||||||
def _intern_set(self, s, frozenset=frozenset):
|
def _intern_set(self, s, frozenset=frozenset):
|
||||||
"""Freeze and intern a given sequence (set variant of intern())
|
"""Freeze and intern a given sequence (set variant of intern())
|
||||||
@ -273,7 +207,6 @@ class InstallabilityTesterBuilder(object):
|
|||||||
self._internmap[fset] = fset
|
self._internmap[fset] = fset
|
||||||
return fset
|
return fset
|
||||||
|
|
||||||
|
|
||||||
def _reverse_relations(self, binary, set=set):
|
def _reverse_relations(self, binary, set=set):
|
||||||
"""Return the reverse relations for a binary
|
"""Return the reverse relations for a binary
|
||||||
|
|
||||||
@ -312,7 +245,6 @@ class InstallabilityTesterBuilder(object):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# Merge reverse conflicts with conflicts - this saves some
|
# Merge reverse conflicts with conflicts - this saves some
|
||||||
# operations in _check_loop since we only have to check one
|
# operations in _check_loop since we only have to check one
|
||||||
# set (instead of two) and we remove a few duplicates here
|
# set (instead of two) and we remove a few duplicates here
|
||||||
@ -410,7 +342,6 @@ class InstallabilityTesterBuilder(object):
|
|||||||
self._essentials, safe_set,
|
self._essentials, safe_set,
|
||||||
eqv_table)
|
eqv_table)
|
||||||
|
|
||||||
|
|
||||||
def _build_eqv_packages_table(self, package_table,
|
def _build_eqv_packages_table(self, package_table,
|
||||||
reverse_package_table,
|
reverse_package_table,
|
||||||
frozenset=frozenset):
|
frozenset=frozenset):
|
||||||
|
@ -131,9 +131,8 @@ class UniverseBuilder(object):
|
|||||||
essential=pkg_builder._is_essential,
|
essential=pkg_builder._is_essential,
|
||||||
in_testing=pkg_builder._in_testing,
|
in_testing=pkg_builder._in_testing,
|
||||||
)
|
)
|
||||||
with builder.relation_builder(pkg_id) as rel:
|
|
||||||
rel.add_dependency_clauses(pkg_builder._dependencies)
|
builder.set_relations(pkg_id, pkg_builder._dependencies, pkg_builder._conflicts)
|
||||||
rel.add_breaks(pkg_builder._conflicts)
|
|
||||||
return builder.build()
|
return builder.build()
|
||||||
|
|
||||||
def pkg_id(self, pkgish):
|
def pkg_id(self, pkgish):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user