diff --git a/britney.py b/britney.py index 5c4ddf8..363fb0e 100755 --- a/britney.py +++ b/britney.py @@ -1772,271 +1772,6 @@ class Britney: diff = diff + (len(new[arch]) - len(old[arch])) return diff <= 0 - def check_installable(self, pkg, arch, suite, excluded=[], conflicts=False): - """Check if a package is installable - - This method analyzes the dependencies of the binary package specified - by the parameter `pkg' for the architecture `arch' within the suite - `suite'. If the dependency can be satisfied in the given `suite` and - `conflicts` parameter is True, then the co-installability with - conflicts handling is checked. - - The dependency fields checked are Pre-Depends and Depends. - - The method returns a boolean which is True if the given package is - installable. - - NOTE: this method has been deprecated, actually we use is_installable - from the britney c extension called within a testing system. See - self.build_systems for more information. - """ - self.__log("WARNING: method check_installable is deprecated: use is_installable instead!", type="E") - - # retrieve the binary package from the specified suite and arch - binary_u = self.binaries[suite][arch][0][pkg] - - # local copies for better performances - parse_depends = apt_pkg.ParseDepends - get_dependency_solvers = self.get_dependency_solvers - - # analyze the dependency fields (if present) - for type in (PREDEPENDS, DEPENDS): - if not binary_u[type]: - continue - - # for every block of dependency (which is formed as conjunction of disconjunction) - for block in parse_depends(binary_u[type]): - # if the block is not satisfied, return False - solved, packages = get_dependency_solvers(block, arch, 'testing', excluded, strict=True) - if not solved: - return False - - # otherwise, the package is installable (not considering conflicts) - # if the conflicts handling is enabled, then check conflicts before - # saying that the package is really installable - if conflicts: - return self.check_conflicts(pkg, arch, excluded, {}, {}) - - return True - - def check_conflicts(self, pkg, arch, broken, system, conflicts): - """Check if a package can be installed satisfying the conflicts - - This method checks if the `pkg` package from the `arch` architecture - can be installed (excluding `broken` packages) within the system - `system` along with all its dependencies. This means that all the - conflicts relationships are checked in order to achieve the test - co-installability of the package. - - The method returns a boolean which is True if the given package is - co-installable in the given system. - """ - - # local copies for better performances - binaries = self.binaries['testing'][arch] - parse_depends = apt_pkg.ParseDepends - check_depends = apt_pkg.CheckDep - - # unregister conflicts, local method to remove conflicts - # registered from a given package. - def unregister_conflicts(pkg, conflicts): - for c in conflicts.keys(): - i = 0 - while i < len(conflicts[c]): - if conflicts[c][i][3] == pkg: - del conflicts[c][i] - else: i = i + 1 - if len(conflicts[c]) == 0: - del conflicts[c] - - def remove_package(pkg, system, conflicts): - for k in system: - if pkg in system[k][1]: - system[k][1].remove(pkg) - unregister_conflicts(pkg, conflicts) - - # handle a conflict, local method to solve a conflict which happened - # in the system; the behaviour of the conflict-solver is: - # 1. If there are alternatives for the package which must be removed, - # try them, and if one of them resolves the system return True; - # 2. If none of the alternatives can solve the conflict, then call - # itself for the package which depends on the conflicting package. - # 3. If the top of the dependency tree is reached, then the conflict - # can't be solved, so return False. - def handle_conflict(pkg, source, system, conflicts): - # skip packages which don't have reverse dependencies - if source not in system or system[source][1] == []: - remove_package(source, system, conflicts) - return (system, conflicts) - # reached the top of the tree - if not system[source][1][0]: - return False - # remove its conflicts - unregister_conflicts(source, conflicts) - # if there are alternatives, try them - alternatives = system[source][0] - for alt in alternatives: - if satisfy(alt, [x for x in alternatives if x != alt], pkg_from=system[source][1], - system=system, conflicts=conflicts, excluded=[source]): - remove_package(source, system, conflicts) - return (system, conflicts) - # there are no good alternatives, so remove the package which depends on it - for p in system[source][1]: - # the package does not exist, we reached the top of the tree - if not p: return False - # we are providing the package we conflict on (eg. exim4 and mail-transfer-agent), skip it - if p == pkg: continue - output = handle_conflict(pkg, p, system, conflicts) - if output: - system, conflicts = output - else: return False - remove_package(source, system, conflicts) - return (system, conflicts) - - # dependency tree satisfier, local method which tries to satisfy the dependency - # tree for a given package. It calls itself recursively in order to check the - # co-installability of the full tree of dependency of the starting package. - # If a conflict is detected, it tries to handle it calling the handle_conflict - # method; if it can't be resolved, then it returns False. - def satisfy(pkg, pkg_alt=None, pkg_from=None, system=system, conflicts=conflicts, excluded=[]): - # if it is a real package and it is already installed, skip it and return True - if pkg in binaries[0]: - if pkg in system: - if type(pkg_from) == list: - system[pkg][1].extend(pkg_from) - else: - system[pkg][1].append(pkg_from) - system[pkg] = (system[pkg][1], filter(lambda x: x in pkg_alt, system[pkg][0])) - return True - binary_u = binaries[0][pkg] - else: binary_u = None - - # if it is a virtual package - providers = [] - if pkg_from and pkg in binaries[1]: - providers = binaries[1][pkg] - # it is both real and virtual, so the providers are alternatives - if binary_u: - providers = filter(lambda x: (not pkg_alt or x not in pkg_alt) and x != pkg, providers) - if not pkg_alt: - pkg_alt = [] - pkg_alt.extend(providers) - # try all the alternatives and if none of them suits, give up and return False - else: - # if we already have a provider in the system, everything is ok and return True - if len(filter(lambda x: x in providers and x not in excluded, system)) > 0: - return True - for p in providers: - # try to install the providers skipping excluded packages, - # which we already tried but do not work - if p in excluded: continue - elif satisfy(p, [a for a in providers if a != p], pkg_from): - return True - # if none of them suits, return False - return False - - # if the package doesn't exist, return False - if not binary_u: return False - - # it is broken, but we have providers - if pkg in broken and pkg_from: - for p in providers: - # try to install the providers skipping excluded packages, - # which we already tried but do not work - if p in excluded: continue - elif satisfy(p, [a for a in providers if a != p], pkg_from): - return True - return False - - # install the package into the system, recording which package required it - if type(pkg_from) != list: - pkg_from = [pkg_from] - system[pkg] = (pkg_alt or [], pkg_from) - - # register provided packages - if binary_u[PROVIDES]: - for p in binary_u[PROVIDES]: - if p in system: - # do not consider packages providing the one which we are checking - if len(system[p][1]) == 1 and system[p][1][0] == None: continue - system[p][1].append(pkg) - else: - system[p] = ([], [pkg]) - - # check the conflicts - if pkg in conflicts: - for name, version, op, conflicting in conflicts[pkg]: - if conflicting in binary_u[PROVIDES] and system[conflicting][1] == [pkg]: continue - if op == '' and version == '' or check_depends(binary_u[VERSION], op, version): - # if conflict is found, check if it can be solved removing - # already-installed packages without breaking the system; if - # this is not possible, give up and return False - output = handle_conflict(pkg, conflicting, system.copy(), conflicts.copy()) - if output: - system, conflicts = output - else: - del system[pkg] - return False - - # register conflicts from the just-installed package - if binary_u[CONFLICTS]: - for block in map(operator.itemgetter(0), parse_depends(binary_u[CONFLICTS] or [])): - name, version, op = block - # skip conflicts for packages provided by itself - # if the conflicting package is in the system (and it is not a self-conflict) - if not (name in binary_u[PROVIDES] and system[name][1] == [pkg]) and \ - block[0] != pkg and block[0] in system: - if block[0] in binaries[0]: - binary_c = binaries[0][block[0]] - else: binary_c = None - if op == '' and version == '' or binary_c and check_depends(binary_c[VERSION], op, version): - # if conflict is found, check if it can be solved removing - # already-installed packages without breaking the system; if - # this is not possible, give up and return False - output = handle_conflict(pkg, name, system.copy(), conflicts.copy()) - if output: - system, conflicts = output - else: - del system[pkg] - unregister_conflicts(pkg, conflicts) - return False - # register the conflict - if block[0] not in conflicts: - conflicts[block[0]] = [] - conflicts[block[0]].append((name, version, op, pkg)) - - # list all its dependencies ... - dependencies = [] - for key in (PREDEPENDS, DEPENDS): - if not binary_u[key]: continue - dependencies.extend(parse_depends(binary_u[key])) - - # ... and go through them - for block in dependencies: - # list the possible alternatives, in case of a conflict - alternatives = map(operator.itemgetter(0), block) - valid = False - for name, version, op in block: - # otherwise, if it is already installed or it is installable, the block is satisfied - if name in system or satisfy(name, [a for a in alternatives if a != name], pkg): - valid = True - break - # if the block can't be satisfied, the package is not installable so - # we need to remove it, its conflicts and its provided packages and - # return False - if not valid: - del system[pkg] - unregister_conflicts(pkg, conflicts) - for p in providers: - if satisfy(p, [a for a in providers if a != p], pkg_from): - return True - return False - - # if all the blocks have been satisfied, the package is installable - return True - - # check the package at the top of the tree - return satisfy(pkg) def doop_source(self, item, hint_undo=[]): """Apply a change to the testing distribution as requested by `pkg`