From 6a9034fb7a161e441934969553ffff63e49348ee Mon Sep 17 00:00:00 2001 From: Necoro <> Date: Fri, 18 Jan 2008 21:19:42 +0000 Subject: r664@Devoty: necoro | 2008-01-18 21:40:29 +0100 First support for 'delete on demand' r665@Devoty: necoro | 2008-01-18 22:18:05 +0100 Finished the 'on demand removal' --- portato/gui/gtk/windows.py | 2 +- portato/gui/gtk/wrapper.py | 27 ++++++++---- portato/gui/gui_helper.py | 47 +++++++++++++------- portato/gui/updater.py | 107 +++++++++++++++++++++++++++++++++++++++++++++ portato/gui/wrapper.py | 24 +++++++++- 5 files changed, 181 insertions(+), 26 deletions(-) create mode 100644 portato/gui/updater.py (limited to 'portato/gui') diff --git a/portato/gui/gtk/windows.py b/portato/gui/gtk/windows.py index 4d25312..3115ac1 100644 --- a/portato/gui/gtk/windows.py +++ b/portato/gui/gtk/windows.py @@ -1061,7 +1061,7 @@ class MainWindow (Window): def build_queue_list (self): """Builds the queue list.""" - store = gtk.TreeStore(str,str) + store = gtk.TreeStore(str,str,bool) self.queueList.set_model(store) diff --git a/portato/gui/gtk/wrapper.py b/portato/gui/gtk/wrapper.py index e601f5d..007970c 100644 --- a/portato/gui/gtk/wrapper.py +++ b/portato/gui/gtk/wrapper.py @@ -60,31 +60,42 @@ class GtkTree (Tree): useChange.sort() string += "%s" % " ".join(useChange) - return [cpv, string] + return [cpv, string, False] + + def set_in_progress (self, it, to = True): + iter = self.first_iter(it) + if to: + self.tree.set_value(iter, 1, "%s" % _("(In Progress)")) + else: + self.tree.set_value(iter, 1, "") + + self.tree.set_value(iter, 2, to) - def set_in_progress (self, it): - iter = self.tree.get_iter_from_string(self.tree.get_string_from_iter(it).split(":")[0]) - self.tree.set_value(iter, 1, "%s" % _("(In Progress)")) + def is_in_progress (self, it): + return self.tree.get_value(it, 2) def get_emerge_it (self): if self.emergeIt is None: - self.emergeIt = self.append(None, ["%s" % _("Install"), ""]) + self.emergeIt = self.append(None, ["%s" % _("Install"), "", False]) return self.emergeIt def get_unmerge_it (self): if self.unmergeIt is None: - self.unmergeIt = self.append(None, ["%s" % _("Uninstall"), ""]) + self.unmergeIt = self.append(None, ["%s" % _("Uninstall"), "", False]) return self.unmergeIt def get_update_it (self): if self.updateIt is None: - self.updateIt = self.append(None, ["%s" % _("Update"), ""]) + self.updateIt = self.append(None, ["%s" % _("Update"), "", False]) return self.updateIt + def first_iter (self, it): + return self.tree.get_iter_from_string(self.tree.get_string_from_iter(it).split(":")[0]) + def is_in (self, it, in_it): - return in_it and self.tree.get_string_from_iter(it).split(":")[0] == self.tree.get_string_from_iter(in_it) + return in_it and self.iter_equal(self.first_iter(it), in_it) def is_in_emerge (self, it): return self.is_in(it, self.emergeIt) diff --git a/portato/gui/gui_helper.py b/portato/gui/gui_helper.py index b4878fc..62dd755 100644 --- a/portato/gui/gui_helper.py +++ b/portato/gui/gui_helper.py @@ -26,6 +26,7 @@ from ..backend import flags, system, set_system from ..helper import debug, info, send_signal_to_group, set_log_level, unique_array from ..constants import USE_CATAPULT from ..waiting_queue import WaitingQueue +from .updater import Updater # parser from ..config_parser import ConfigParser @@ -266,6 +267,7 @@ class EmergeQueue: self.db = db self.title_update = title_update + self.threadClass = threadClass def _get_pkg_from_cpv (self, cpv, unmask = False): """Gets a L{backend.Package}-object from a cpv. @@ -455,12 +457,16 @@ class EmergeQueue: self.oneshotmerge.append(cpv) def doEmerge (self, options, packages, it, *args, **kwargs): + top = None if self.tree and it: - self.tree.set_in_progress(it[0]) + for v in it.itervalues(): + self.tree.set_in_progress(v) + top = self.tree.first_iter(v) + break - self.threadQueue.put(self.__emerge, options, packages, it, *args, **kwargs) + self.threadQueue.put(self.__emerge, options, packages, it, top, *args, **kwargs) - def __emerge (self, options, packages, it, command = None): + def __emerge (self, options, packages, it, top, command = None): """Calls emerge and updates the terminal. @param options: options to send to emerge @@ -468,7 +474,9 @@ class EmergeQueue: @param packages: packages to emerge @type packages: string[] @param it: Iterators which point to these entries whose children will be removed after completion. - @type it: Iterator[] + @type it: dict(string -> Iterator) + @param top: The top iterator + @type top: Iterator @param command: the command to execute - default is "/usr/bin/python /usr/bin/emerge" @type command: string[]""" @@ -498,9 +506,10 @@ class EmergeQueue: self.process = Popen(command+options+packages, shell = False, env = system.get_environment(), preexec_fn = pre) # remove packages from queue - if self.tree: - for i in it: - self.remove_with_children(i) + if self.tree and it: + self.up = Updater(self, it, self.threadClass) + else: + self.up = None # update title if self.console: @@ -512,6 +521,13 @@ class EmergeQueue: self.title_update(title) time.sleep(0.5) + if self.up: + self.up.stop() + if it: + self.tree.set_in_progress(top, False) + else: + self.remove(top) + if self.title_update: self.title_update(None) if self.process is None: # someone resetted this @@ -544,17 +560,18 @@ class EmergeQueue: def prepare(queue): """Prepares the list of iterators and the list of packages.""" list = [] - its = [] + its = {} for k in queue: list += ["="+k] - if self.tree: its.append(self.iters["install"][k]) + if self.tree: + its.update({k : self.iters["install"][k]}) return list, its if self.tree: - ownit = [self.tree.get_emerge_it()] + ownit = self.iters["install"] else: - ownit = [] + ownit = {} # oneshot-queue if self.oneshotmerge: @@ -600,9 +617,9 @@ class EmergeQueue: if options is not None: s += options if self.tree: - it = [self.tree.get_unmerge_it()] + it = self.iters["uninstall"] else: - it = [] + it = {} self.doEmerge(s,list, it, caller = self.unmerge) @@ -626,9 +643,9 @@ class EmergeQueue: if options is not None: opts += options if self.tree: - it = [self.tree.get_update_it()] + it = self.iters["update"] else: - it = [] + it = {} self.doEmerge(opts, ["world"], it, caller = self.update_world) diff --git a/portato/gui/updater.py b/portato/gui/updater.py new file mode 100644 index 0000000..e468691 --- /dev/null +++ b/portato/gui/updater.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +# +# File: portato/gui/updater.py +# This file is part of the Portato-Project, a graphical portage-frontend. +# +# Copyright (C) 2008 René 'Necoro' Neumann +# This is free software. You may redistribute copies of it under the terms of +# the GNU General Public License version 2. +# There is NO WARRANTY, to the extent permitted by law. +# +# Written by René 'Necoro' Neumann + +from __future__ import absolute_import + +from ..backend import system + +import threading, subprocess, time +from ..helper import debug + +class Updater (object): + """ + This class is intended to check what package is currently being installed and remove this one from the queue. + + @cvar SED_EXP: The sed expression to strip the package name out of the qlop call. + """ + + SED_EXP = r""" +/\*/{ +s/ \* // +q +}""" + + def __init__ (self, queue, iterators, threadClass = threading.Thread): + """ + Constructor. + Also directly initializes the thread. + + @param queue: an emerge queue instance + @type queue: EmergeQueue + @param iterators: a dictionary of iterators in the current queue + @type iterators: dict(string->Iterator) + """ + + if not issubclass(threadClass, threading.Thread): + raise ValueError, "Only subclasses of threading.Thread are allowed." + + self.queue = queue + self.iterators = iterators + self.threadClass = threadClass + self.stopEvent = threading.Event() + + t = threadClass(name = "Queue Updater Thread", target = self.run) + t.setDaemon(True) + t.start() + + def run (self): + """ + Run and run and run ... + Checks the packages until being stopped. + """ + + curr = None + while not self.stopEvent.isSet(): + + # this = $(qlop -cCq | sed $SED_EXP) + p1 = subprocess.Popen(["qlop", "--current", "--nocolor", "--quiet"], stdout = subprocess.PIPE) + this = subprocess.Popen(["sed", self.SED_EXP], stdout = subprocess.PIPE, stdin = p1.stdout).communicate()[0] + + if this: + this = this.strip() + if this != curr: # changed package + curr = this + self.remove(self.find(curr)) # remove it + + time.sleep(2.0) + + def stop (self): + """ + Stops the current updater. + """ + self.stopEvent.set() + + def find (self, pv): + """ + As qlop only returns 'package-version' we need to assign it to a cpv. + This is done here. + """ + + pkgs = [l.get_cpv() for l in system.find_packages("=%s" % pv)] + + if len(pkgs) > 1: # ambigous - try to find the one which is also in the iterators + for p in pkgs: + if p in self.iterators: + return p + elif not pkgs: # nothing found =| + error(_("Trying to remove package '%s' from queue which does not exist in system."), pv) + else: # only one choice =) + return pkgs[0] + + def remove (self, cpv): + """ + Remove a package from the queue. + """ + try: + self.queue.remove(self.iterators[cpv]) + except KeyError: + debug("'%s' should be removed, but is not in queue.", cpv) diff --git a/portato/gui/wrapper.py b/portato/gui/wrapper.py index 2a88bdf..78a03ab 100644 --- a/portato/gui/wrapper.py +++ b/portato/gui/wrapper.py @@ -145,6 +145,15 @@ class Tree: @rtype boolean""" raise NotImplementedError + def first_iter (self, it): + """Returns the iterator at the top. + + @param it: the iterator + @type it: Iterator + @returns: the top iterator + @rtype: Iterator""" + raise NotImplementedError + def get_emerge_it (self): """Returns an iterator signaling the top of the emerge section. @@ -166,11 +175,22 @@ class Tree: @rtype: Iterator""" raise NotImplementedError - def set_in_progress (self, it): + def set_in_progress (self, it, to = True): """Marks the queue where the given iterator belongs as being in progress. @param it: one iterator of the queue to mark to - @type it: Iterator""" + @type it: Iterator + @param to: whether to enable or disable + @type to: boolean""" + raise NotImplementedError + + def get_in_progress (self, it): + """Returns whether the queue where the given iterator belongs to, is marked as "being in progress". + + @param it: the iterator + @type it: Iterator + @returns: whether the queue is marked "in progress" + @rtype: boolean""" raise NotImplementedError def build_append_value (self, cpv, oneshot = False, update = False, downgrade = False, version = None, useChange = []): -- cgit v1.2.3-54-g00ecf