mirror of
				https://git.launchpad.net/~ubuntu-release/britney/+git/britney2-ubuntu
				synced 2025-11-04 10:34:05 +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
 | 
			
		||||
from collections import defaultdict
 | 
			
		||||
from contextlib import contextmanager
 | 
			
		||||
from itertools import product
 | 
			
		||||
 | 
			
		||||
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 = {}
 | 
			
		||||
 | 
			
		||||
            # We do not differentiate between depends and pre-depends
 | 
			
		||||
            if pkgdata.depends:
 | 
			
		||||
                depends.extend(apt_pkg.parse_depends(pkgdata.depends, False))
 | 
			
		||||
 | 
			
		||||
            if pkgdata.conflicts:
 | 
			
		||||
                conflicts = apt_pkg.parse_depends(pkgdata.conflicts, False)
 | 
			
		||||
 | 
			
		||||
            with builder.relation_builder(pkg_id) as relations:
 | 
			
		||||
 | 
			
		||||
                conflicts_parsed = apt_pkg.parse_depends(pkgdata.conflicts, False)
 | 
			
		||||
                # 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.
 | 
			
		||||
                if conflicts:
 | 
			
		||||
                    rels = []
 | 
			
		||||
                    for dep_suite in suite_info:
 | 
			
		||||
                        dep_binaries_s_a, dep_provides_s_a = dep_suite.binaries[arch]
 | 
			
		||||
                        for block in (relation for relation in conflicts):
 | 
			
		||||
                            # if a package satisfies its own conflicts relation, then it is using §7.6.2
 | 
			
		||||
                            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)
 | 
			
		||||
                for dep_suite in suite_info:
 | 
			
		||||
                    dep_binaries_s_a, dep_provides_s_a = dep_suite.binaries[arch]
 | 
			
		||||
                    for block in (relation for relation in conflicts_parsed):
 | 
			
		||||
                        # if a package satisfies its own conflicts relation, then it is using §7.6.2
 | 
			
		||||
                        conflicts.extend(s.pkg_id for s in solvers(block, dep_binaries_s_a, dep_provides_s_a)
 | 
			
		||||
                                         if s.pkg_id != pkg_id)
 | 
			
		||||
 | 
			
		||||
                dep_relations = []
 | 
			
		||||
                for block in depends:
 | 
			
		||||
            if pkgdata.depends:
 | 
			
		||||
                for block in apt_pkg.parse_depends(pkgdata.depends, False):
 | 
			
		||||
                    sat = set()
 | 
			
		||||
 | 
			
		||||
                    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))
 | 
			
		||||
 | 
			
		||||
                    if len(block) != 1:
 | 
			
		||||
                        dep_relations.append(sat)
 | 
			
		||||
                        depends.append(sat)
 | 
			
		||||
                    else:
 | 
			
		||||
                        # This dependency might be a part
 | 
			
		||||
                        # of a version-range a la:
 | 
			
		||||
@ -100,81 +90,13 @@ def build_installability_tester(suite_info, archs):
 | 
			
		||||
                            possible_dep_ranges[key] = sat
 | 
			
		||||
 | 
			
		||||
                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()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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):
 | 
			
		||||
    """Builder to create instances of InstallabilityTester"""
 | 
			
		||||
 | 
			
		||||
@ -185,7 +107,7 @@ class InstallabilityTesterBuilder(object):
 | 
			
		||||
        self._testing = set()
 | 
			
		||||
        self._internmap = {}
 | 
			
		||||
        self._broken = set()
 | 
			
		||||
 | 
			
		||||
        self._empty_set = self._intern_set(frozenset())
 | 
			
		||||
 | 
			
		||||
    def add_binary(self, binary, essential=False, in_testing=False,
 | 
			
		||||
                   frozenset=frozenset):
 | 
			
		||||
@ -226,31 +148,43 @@ class InstallabilityTesterBuilder(object):
 | 
			
		||||
            return True
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def set_relations(self, pkg_id, dependency_clauses, breaks):
 | 
			
		||||
        """The dependency and breaks realtions for a given package
 | 
			
		||||
 | 
			
		||||
    @contextmanager
 | 
			
		||||
    def relation_builder(self, binary):
 | 
			
		||||
        """Returns a _RelationBuilder for a given binary [context]
 | 
			
		||||
 | 
			
		||||
        This method returns a context-managed _RelationBuilder for a
 | 
			
		||||
        given binary.  So it should be used in a "with"-statment,
 | 
			
		||||
        like:
 | 
			
		||||
 | 
			
		||||
            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.
 | 
			
		||||
        :param pkg_id: BinaryPackageID determining which package will have its relations set
 | 
			
		||||
        :param dependency_clauses: A list/set of OR clauses (i.e. CNF with each element in
 | 
			
		||||
          dependency_clauses being a disjunction).  Each OR cause (disjunction) should be a
 | 
			
		||||
          set/list of BinaryPackageIDs that satisfy that relation.
 | 
			
		||||
        :param breaks: An list/set of BinaryPackageIDs that has a Breaks/Conflicts relation
 | 
			
		||||
            on the current package.  Can be None
 | 
			
		||||
        :return: No return value
 | 
			
		||||
        """
 | 
			
		||||
        if binary not in self._package_table:  # pragma: no cover
 | 
			
		||||
            raise ValueError("Binary %s/%s/%s does not exist" % binary)
 | 
			
		||||
        rel = _RelationBuilder(self, binary)
 | 
			
		||||
        yield rel
 | 
			
		||||
        rel._commit()
 | 
			
		||||
        if dependency_clauses is not None:
 | 
			
		||||
            interned_or_clauses = self._intern_set(self._intern_set(c) for c in dependency_clauses)
 | 
			
		||||
            satisfiable = True
 | 
			
		||||
            for or_clause in interned_or_clauses:
 | 
			
		||||
                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):
 | 
			
		||||
        """Freeze and intern a given sequence (set variant of intern())
 | 
			
		||||
@ -273,7 +207,6 @@ class InstallabilityTesterBuilder(object):
 | 
			
		||||
        self._internmap[fset] = fset
 | 
			
		||||
        return fset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def _reverse_relations(self, binary, set=set):
 | 
			
		||||
        """Return the reverse relations for a binary
 | 
			
		||||
 | 
			
		||||
@ -312,7 +245,6 @@ class InstallabilityTesterBuilder(object):
 | 
			
		||||
                    return False
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        # Merge reverse conflicts with conflicts - this saves some
 | 
			
		||||
        # operations in _check_loop since we only have to check one
 | 
			
		||||
        # set (instead of two) and we remove a few duplicates here
 | 
			
		||||
@ -410,7 +342,6 @@ class InstallabilityTesterBuilder(object):
 | 
			
		||||
                                    self._essentials, safe_set,
 | 
			
		||||
                                    eqv_table)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def _build_eqv_packages_table(self, package_table,
 | 
			
		||||
                                  reverse_package_table,
 | 
			
		||||
                                  frozenset=frozenset):
 | 
			
		||||
 | 
			
		||||
@ -131,9 +131,8 @@ class UniverseBuilder(object):
 | 
			
		||||
                               essential=pkg_builder._is_essential,
 | 
			
		||||
                               in_testing=pkg_builder._in_testing,
 | 
			
		||||
                               )
 | 
			
		||||
            with builder.relation_builder(pkg_id) as rel:
 | 
			
		||||
                rel.add_dependency_clauses(pkg_builder._dependencies)
 | 
			
		||||
                rel.add_breaks(pkg_builder._conflicts)
 | 
			
		||||
 | 
			
		||||
            builder.set_relations(pkg_id, pkg_builder._dependencies, pkg_builder._conflicts)
 | 
			
		||||
        return builder.build()
 | 
			
		||||
 | 
			
		||||
    def pkg_id(self, pkgish):
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user