diff options
author | René 'Necoro' Neumann <necoro@necoro.net> | 2008-06-08 18:24:44 +0200 |
---|---|---|
committer | René 'Necoro' Neumann <necoro@necoro.net> | 2008-06-08 18:24:44 +0200 |
commit | ee446ef74d1a1a63ce0fdc0b7076a3150e63352f (patch) | |
tree | 3c2284f39e4a802a7a91b069092df5ccead8bfac | |
parent | 40b5396e7c1a290461bbafb920f3961fd8ca5255 (diff) | |
download | portato-ee446ef74d1a1a63ce0fdc0b7076a3150e63352f.tar.gz portato-ee446ef74d1a1a63ce0fdc0b7076a3150e63352f.tar.bz2 portato-ee446ef74d1a1a63ce0fdc0b7076a3150e63352f.zip |
Make blocks way more intelligent
Diffstat (limited to '')
-rw-r--r-- | doc/AUTHORS | 3 | ||||
-rw-r--r-- | portato/backend/portage/package.py | 33 | ||||
-rw-r--r-- | portato/gui/queue.py | 116 |
3 files changed, 107 insertions, 45 deletions
diff --git a/doc/AUTHORS b/doc/AUTHORS index cdb99ab..5901f92 100644 --- a/doc/AUTHORS +++ b/doc/AUTHORS @@ -3,7 +3,8 @@ Main author: René 'Necoro' Neumann <necoro@necoro.net> Application icon: P4r4D0X (after an idea by wolfden) Shipped with code from: - - Philip Semanchuk (shm module) + - Nicola Larosa & Michael Foord (portato.odict) + see: http://www.voidspace.org.uk/python/odict.html Many thanks to the Porthole team which often inspired me or gave me hints. (And sometimes I even copied files ^^ ;)) diff --git a/portato/backend/portage/package.py b/portato/backend/portage/package.py index 424945e..b07dc93 100644 --- a/portato/backend/portage/package.py +++ b/portato/backend/portage/package.py @@ -202,7 +202,7 @@ class PortagePackage (Package): return [d for d in deps if d[0] != "!"] - def get_dep_packages (self, depvar = ["RDEPEND", "PDEPEND", "DEPEND"], with_criterions = False): + def get_dep_packages (self, depvar = ["RDEPEND", "PDEPEND", "DEPEND"], with_criterions = False, return_blocks = False): dep_pkgs = [] # the package list # change the useflags, because we have internally changed some, but not made them visible for portage @@ -234,30 +234,37 @@ class PortagePackage (Package): for dep in deps: if dep[0] == '!': # blocking sth - dep = dep[1:] - blocked = system.find_installed_packages(dep) - if blocked: - if blocked[0].get_slot_cp() != self.get_slot_cp(): # blocks in the same slot are harmless - raise BlockedException, (self.get_cpv(), blocked[0].get_cpv()) + blocked = system.find_installed_packages(dep[1:]) + if len(blocked) == 1: # only exact one match allowed to be harmless + if blocked[0].get_slot_cp() == self.get_slot_cp(): # blocks in the same slot are harmless + continue + + if return_blocks: + if with_criterions: + dep_pkgs.append((dep, dep)) + else: + dep_pkgs.append(dep) + else: + raise BlockedException, (self.get_cpv(), blocked[0].get_cpv()) + continue # finished with the blocking one -> next pkg = system.find_best_match(dep) if not pkg: # try to find masked ones - list = system.find_packages(dep, masked = True) - if not list: + pkgs = system.find_packages(dep, masked = True) + if not pkgs: raise PackageNotFoundException, dep - list = system.sort_package_list(list) - list.reverse() + pkgs = system.sort_package_list(pkgs) + pkgs.reverse() done = False - for i in range(len(list)): - p = list[i] + for p in pkgs: if not p.is_masked(): dep_pkgs.append(create_dep_pkgs_data(dep, p)) done = True break if not done: - dep_pkgs.append(create_dep_pkgs_data(dep, list[0])) + dep_pkgs.append(create_dep_pkgs_data(dep, pkgs[0])) else: dep_pkgs.append(create_dep_pkgs_data(dep, pkg)) diff --git a/portato/gui/queue.py b/portato/gui/queue.py index eb0a43e..be43e3a 100644 --- a/portato/gui/queue.py +++ b/portato/gui/queue.py @@ -15,13 +15,16 @@ from __future__ import absolute_import # some stuff needed import os, pty import signal, threading, time +import itertools as itt from subprocess import Popen # some backend things from .. import backend, plugin from ..backend import flags, system -from ..helper import debug, info, send_signal_to_group, unique_array +from ..backend.exceptions import BlockedException +from ..helper import debug, info, warning, send_signal_to_group, unique_array, flatten from ..waiting_queue import WaitingQueue +from ..odict import OrderedDict from .updater import Updater # the wrapper @@ -55,6 +58,7 @@ class EmergeQueue: # dictionaries with data about the packages in the queue self.iters = {"install" : {}, "uninstall" : {}, "update" : {}} # iterator in the tree self.deps = {"install" : {}, "update" : {}} # all the deps of the package + self.blocks = {"install" : OrderedDict(), "update" : OrderedDict()} # member vars self.tree = tree @@ -189,20 +193,21 @@ class EmergeQueue: # add iter subIt = self.tree.append(it, self.tree.build_append_value(cpv, oneshot = oneshot, update = update, downgrade = downgrade, version = uVersion, useChange = changedUse)) - self.iters[type].update({cpv: subIt}) + self.iters[type][cpv] = subIt # get dependencies - deps = pkg.get_dep_packages() # this might raise a BlockedException - self.deps[type].update({cpv : deps}) + deps = pkg.get_dep_packages(return_blocks = True) + self.deps[type][cpv] = deps - # recursive call for d in deps: - try: + if d[0] == "!": # block + dep = d[1:] + if not dep in self.blocks[type]: + self.blocks[type][dep] = set() + + self.blocks[type][dep].add(cpv) + else: # recursive call self.update_tree(subIt, d, unmask, type = type) - except backend.BlockedException, e: # BlockedException occured -> delete current tree and re-raise exception - debug("Something blocked: %s", e[0]) - self.remove_with_children(subIt) - raise def append (self, cpv, type = "install", update = False, forceUpdate = False, unmask = False, oneshot = False): """Appends a cpv either to the merge queue or to the unmerge-queue. @@ -226,7 +231,7 @@ class EmergeQueue: if type in ("install", "update"): # emerge if update: pkg = self._get_pkg_from_cpv(cpv, unmask) - deps = pkg.get_dep_packages() + deps = pkg.get_dep_packages(return_blocks = True) if not forceUpdate and cpv in self.deps[type] and deps == self.deps[type][cpv]: return # nothing changed - return @@ -248,6 +253,51 @@ class EmergeQueue: self.update_tree(self.tree.get_emerge_it(), cpv, unmask, type = type, oneshot = oneshot) elif type == "update" and self.tree: self.update_tree(self.tree.get_update_it(), cpv, unmask, type = type, oneshot = oneshot) + + # handle blocks + if self.blocks[type]: + # check whether anything blocks something in the queue + for block in self.blocks[type]: + for c in self.iters[type]: + if system.cpv_matches(c, block): + blocked = ", ".join(self.blocks[type][block]) + warning("'%s' is blocked by: %s", c, blocked) + self.remove_with_children(self.iters[type][c], False) + raise BlockedException(c, blocked) + + # + # check whether we block a version that we are going to replace nevertheless + # + + # get the blocks that block an installed package + inst = [] + for block in self.blocks[type]: + pkgs = system.find_installed_packages(block) + if pkgs: + inst.append((pkgs, block)) + + # the slot-cp's of the packages in the queue + slots = {} + for c in self.iters[type]: + slots[system.new_package(c).get_slot_cp()] = cpv + + # check the installed blocks against the slot-cp's + for pkgs, block in inst[:]: + done = False + for pkg in pkgs: + done = False + if pkg.get_slot_cp() in slots: + debug("Block '%s' can be ignored, because the blocking package is going to be replaced with '%s'.", block, slots[pkg.get_slot_cp()]) + done = True + if done: + inst.remove((pkgs,block)) + + if inst: # there is still something left to block + for pkgs, block in inst: + blocked = ", ".join(self.blocks[type][block]) + warning("'%s' blocks the installation of: %s", pkgs[0].get_cpv(), blocked) + self.remove_with_children(self.iters[type][cpv], False) + raise BlockedException(blocked, pkgs[0].get_cpv()) else: # unmerge self.unmergequeue.append(cpv) @@ -544,15 +594,32 @@ class EmergeQueue: @type it: Iterator @param removeNewFlags: True if new flags should be removed; False otherwise. Default: True. @type removeNewFlags: boolean""" + + def __remove (type, cpv): + del self.iters[type][cpv] + try: + del self.deps[type][cpv] + except KeyError: # this seems to be removed due to a BlockedException - so no deps here atm ;) + debug("Catched KeyError => %s seems not to be in self.deps. Should be no harm in normal cases.", cpv) + + for key in self.blocks[type].keys(): + if cpv in self.blocks[type][key]: + self.blocks[type][key].remove(cpv) + + if not self.blocks[type][key]: # list is empty -> remove the whole key + del self.blocks[type][key] + + if removeNewFlags: # remove the changed flags + flags.remove_new_use_flags(cpv) + flags.remove_new_masked(cpv) + flags.remove_new_testing(cpv) if self.tree.iter_has_parent(it): cpv = self.tree.get_value(it, self.tree.get_cpv_column()) if self.tree.is_in_emerge(it): # Emerge - del self.iters["install"][cpv] - try: - del self.deps["install"][cpv] - except KeyError: # this seems to be removed due to a BlockedException - so no deps here atm ;) - debug("Catched KeyError => %s seems not to be in self.deps. Should be no harm in normal cases.", cpv) + + __remove("install", cpv) + try: self.mergequeue.remove(cpv) except ValueError: # this is a dependency - ignore @@ -560,27 +627,14 @@ class EmergeQueue: self.oneshotmerge.remove(cpv) except ValueError: debug("Catched ValueError => %s seems not to be in merge-queue. Should be no harm.", cpv) - - if removeNewFlags: # remove the changed flags - flags.remove_new_use_flags(cpv) - flags.remove_new_masked(cpv) - flags.remove_new_testing(cpv) elif self.tree.is_in_unmerge(it): # in Unmerge del self.iters["uninstall"][cpv] self.unmergequeue.remove(cpv) elif self.tree.is_in_update(it): - del self.iters["update"][cpv] - try: - del self.deps["update"][cpv] - except KeyError: # this seems to be removed due to a BlockedException - so no deps here atm ;) - debug("Catched KeyError => %s seems not to be in self.deps. Should be no harm in normal cases.", cpv) - - if removeNewFlags: # remove the changed flags - flags.remove_new_use_flags(cpv) - flags.remove_new_masked(cpv) - flags.remove_new_testing(cpv) + __remove("update", cpv) + self.tree.remove(it) |