summaryrefslogtreecommitdiff
path: root/portato
diff options
context:
space:
mode:
Diffstat (limited to 'portato')
-rw-r--r--portato/gui/gtk/windows.py2
-rw-r--r--portato/gui/gtk/wrapper.py27
-rw-r--r--portato/gui/gui_helper.py47
-rw-r--r--portato/gui/updater.py107
-rw-r--r--portato/gui/wrapper.py24
5 files changed, 181 insertions, 26 deletions
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 += "<i>%s</i>" % " ".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, "<b>%s</b>" % _("(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, "<b>%s</b>" % _("(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, ["<b>%s</b>" % _("Install"), ""])
+ self.emergeIt = self.append(None, ["<b>%s</b>" % _("Install"), "", False])
return self.emergeIt
def get_unmerge_it (self):
if self.unmergeIt is None:
- self.unmergeIt = self.append(None, ["<b>%s</b>" % _("Uninstall"), ""])
+ self.unmergeIt = self.append(None, ["<b>%s</b>" % _("Uninstall"), "", False])
return self.unmergeIt
def get_update_it (self):
if self.updateIt is None:
- self.updateIt = self.append(None, ["<b>%s</b>" % _("Update"), ""])
+ self.updateIt = self.append(None, ["<b>%s</b>" % _("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 <necoro@necoro.net>
+
+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 = []):