From e49c33d6114ddc8051c349aa325872bd7840289b Mon Sep 17 00:00:00 2001 From: Necoro <> Date: Fri, 18 Jan 2008 19:24:38 +0000 Subject: r661@Devoty: necoro | 2008-01-18 14:16:59 +0100 First support for interactive emerges r662@Devoty: necoro | 2008-01-18 20:22:58 +0100 Now finished interactive emerges --- doc/Changelog | 1 + doc/TODO | 2 - portato/backend/portage/system.py | 1 + portato/gui/gtk/windows.py | 9 +- portato/gui/gtk/wrapper.py | 5 +- portato/gui/gui_helper.py | 105 ++++++---- portato/gui/templates/portato.glade | 377 ++++++++++++++++++++---------------- portato/gui/wrapper.py | 4 +- 8 files changed, 293 insertions(+), 211 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index e017d05..d0c4e05 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -8,6 +8,7 @@ next: - allowed the permanent change of a plugin status - added "ALL" category - new design and handling +- allowed interactive emerges 0.8.6.2: - changed the pipe version and use shm instead (fixes issues with kdesu) diff --git a/doc/TODO b/doc/TODO index 6a959ca..a30b1ff 100644 --- a/doc/TODO +++ b/doc/TODO @@ -31,7 +31,6 @@ Main Point: user preferences: - colors and font sizes - rotating systray icon -- interactive emerges GTK: ---- @@ -41,7 +40,6 @@ GTK: - dependency tree out of the installed packages - better display for search results - Qt (stopped): --- - better terminal diff --git a/portato/backend/portage/system.py b/portato/backend/portage/system.py index 77004a7..0997bed 100644 --- a/portato/backend/portage/system.py +++ b/portato/backend/portage/system.py @@ -70,6 +70,7 @@ class PortageSystem (SystemInterface): default_opts = self.get_global_settings("EMERGE_DEFAULT_OPTS") opts = dict(os.environ) opts.update(TERM = "xterm") # emulate terminal :) + opts.update(PAGER = "less") # force less if default_opts: opt_list = default_opts.split() diff --git a/portato/gui/gtk/windows.py b/portato/gui/gtk/windows.py index d8366a0..4d25312 100644 --- a/portato/gui/gtk/windows.py +++ b/portato/gui/gtk/windows.py @@ -3,7 +3,7 @@ # File: portato/gui/gtk/windows.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2007 René 'Necoro' Neumann +# Copyright (C) 2006-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. @@ -458,6 +458,7 @@ class PackageTable: self.nameLabel = self.tree.get_widget("nameLabel") self.descLabel = self.tree.get_widget("descLabel") self.overlayLabel = self.tree.get_widget("overlayLabel") + self.licenseLabel = self.tree.get_widget("licenseLabel") self.overlayLL = self.tree.get_widget("overlayLabelLabel") self.linkBox = self.tree.get_widget("linkBox") self.notInSysLabel = self.tree.get_widget("notInSysLabel") @@ -532,7 +533,7 @@ class PackageTable: self.descLabel.set_label(desc) # overlay - if self.actual_package().is_overlay(): + if pkg.is_overlay(): self.overlayLabel.set_label(pkg.get_overlay_path()) self.overlayLabel.show() self.overlayLL.show() @@ -540,6 +541,9 @@ class PackageTable: self.overlayLabel.hide() self.overlayLL.hide() + # license + self.licenseLabel.set_label(pkg.get_package_settings("LICENSE")) + # link for c in self.linkBox.get_children(): self.linkBox.remove(c) @@ -1016,6 +1020,7 @@ class MainWindow (Window): # notebooks self.sysNotebook = self.tree.get_widget("systemNotebook") self.pkgNotebook = self.tree.get_widget("packageNotebook") + self.set_notebook_tabpos(map(PreferenceWindow.tabpos.get, map(int, (self.cfg.get("packageTabPos", "GTK"), self.cfg.get("systemTabPos", "GTK"))))) self.window.show_all() # the hidden stuff diff --git a/portato/gui/gtk/wrapper.py b/portato/gui/gtk/wrapper.py index cadec6a..e601f5d 100644 --- a/portato/gui/gtk/wrapper.py +++ b/portato/gui/gtk/wrapper.py @@ -3,7 +3,7 @@ # File: portato/gui/gtk/wrapper.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006 René 'Necoro' Neumann +# Copyright (C) 2006-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. @@ -12,9 +12,10 @@ from __future__ import absolute_import +import vte from gettext import lgettext as _ from ..wrapper import Tree, Console -import vte +from ...helper import debug class GtkTree (Tree): """The implementation of the abstract tree.""" diff --git a/portato/gui/gui_helper.py b/portato/gui/gui_helper.py index 0459d5b..b4878fc 100644 --- a/portato/gui/gui_helper.py +++ b/portato/gui/gui_helper.py @@ -3,7 +3,7 @@ # File: portato/gui/gui_helper.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2007 René 'Necoro' Neumann +# Copyright (C) 2006-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. @@ -14,7 +14,7 @@ from __future__ import absolute_import # some stuff needed import logging -import os, pty +import sys, os, pty import signal, threading, time from subprocess import Popen, PIPE, STDOUT @@ -219,7 +219,10 @@ class Database: if cat: del self._db[cat] - self.inst_cats.remove(cat) + try: + self.inst_cats.remove(cat) + except KeyError: # not in inst_cats - can be ignored + pass self.populate(cat+"/") else: self.__initialize() @@ -251,8 +254,8 @@ class EmergeQueue: self.pty = None # dictionaries with data about the packages in the queue - self.iters = {} # iterator in the tree - self.deps = {} # all the deps of the package + self.iters = {"install" : {}, "uninstall" : {}, "update" : {}} # iterator in the tree + self.deps = {"install" : {}, "update" : {}} # all the deps of the package # member vars self.tree = tree @@ -304,7 +307,7 @@ class EmergeQueue: return pkg - def update_tree (self, it, cpv, unmask = False, oneshot = False): + def update_tree (self, it, cpv, unmask = False, oneshot = False, type = "install"): """This updates the tree recursivly, or? Isn't it? Bjorn! @param it: iterator where to append @@ -315,11 +318,13 @@ class EmergeQueue: @type unmask: boolean @param oneshot: True if we want to emerge is oneshot @type oneshot: boolean + @param type: the type of the updating + @type type: string @raises backend.BlockedException: When occured during dependency-calculation. @raises backend.PackageNotFoundException: If no package could be found - normally it is existing but masked.""" - if cpv in self.deps: + if cpv in self.deps[type]: return # in list already and therefore it's already in the tree too # try to find an already installed instance @@ -368,11 +373,11 @@ 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.update({cpv: subIt}) + self.iters[type].update({cpv: subIt}) # get dependencies deps = pkg.get_dep_packages() # this might raise a BlockedException - self.deps.update({cpv : deps}) + self.deps[type].update({cpv : deps}) # recursive call for d in deps: @@ -408,14 +413,14 @@ class EmergeQueue: deps = pkg.get_dep_packages() if update: - if not forceUpdate and cpv in self.deps and deps == self.deps[cpv]: + if not forceUpdate and cpv in self.deps[type] and deps == self.deps[type][cpv]: return # nothing changed - return else: hasBeenInQueue = (cpv in self.mergequeue or cpv in self.oneshotmerge) - parentIt = self.tree.parent_iter(self.iters[cpv]) + parentIt = self.tree.parent_iter(self.iters[type][cpv]) # delete it out of the tree - but NOT the changed flags - self.remove_with_children(self.iters[cpv], removeNewFlags = False) + self.remove_with_children(self.iters[type][cpv], removeNewFlags = False) if hasBeenInQueue: # package has been in queue before self._queue_append(cpv, oneshot) @@ -425,14 +430,14 @@ class EmergeQueue: if type == "install": self._queue_append(cpv, oneshot) if self.tree: - self.update_tree(self.tree.get_emerge_it(), cpv, unmask, oneshot = oneshot) + 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, oneshot = oneshot) + self.update_tree(self.tree.get_update_it(), cpv, unmask, type = type, oneshot = oneshot) else: # unmerge self.unmergequeue.append(cpv) if self.tree: # update tree - self.tree.append(self.tree.get_unmerge_it(), self.tree.build_append_value(cpv)) + self.iters["uninstall"].update({cpv: self.tree.append(self.tree.get_unmerge_it(), self.tree.build_append_value(cpv))}) def _queue_append (self, cpv, oneshot = False): """Convenience function appending a cpv either to self.mergequeue or to self.oneshotmerge. @@ -473,27 +478,39 @@ class EmergeQueue: command = system.get_merge_command() # open tty - if not self.pty: - self.pty = pty.openpty() - self.console.set_pty(self.pty[0]) - else: - self.console.reset() + if self.console is not None: + if not self.pty: + self.pty = pty.openpty() + self.console.set_pty(self.pty[0]) + else: + self.console.reset() + def pre (): + os.setsid() # new session + if self.console: + import fcntl, termios + fcntl.ioctl(self.pty[1], termios.TIOCSCTTY, 0) # set pty-slave as session tty + os.dup2(self.pty[1], 0) + os.dup2(self.pty[1], 1) + os.dup2(self.pty[1], 2) + # start emerge - self.process = Popen(command+options+packages, stdout = self.pty[1], stderr = STDOUT, shell = False, env = system.get_environment(), preexec_fn = os.setsid) - + self.process = Popen(command+options+packages, shell = False, env = system.get_environment(), preexec_fn = pre) + # remove packages from queue - for i in it: - self.remove_with_children(i) + if self.tree: + for i in it: + self.remove_with_children(i) # update title - old_title = self.console.get_window_title() - while self.process and self.process.poll() is None: - if self.title_update : - title = self.console.get_window_title() - if title != old_title: - self.title_update(title) - time.sleep(0.5) + if self.console: + old_title = self.console.get_window_title() + while self.process and self.process.poll() is None: + if self.title_update : + title = self.console.get_window_title() + if title != old_title: + self.title_update(title) + time.sleep(0.5) if self.title_update: self.title_update(None) @@ -507,9 +524,10 @@ class EmergeQueue: @plugin.hook("after_emerge", packages = packages, retcode = ret) def update_packages(): - for cat in unique_array([system.split_cpv(p)[0] for p in packages if p not in ["world", "system"]]): - self.db.reload(cat) - debug("Category %s refreshed", cat) + if self.db: + for cat in unique_array([system.split_cpv(p)[0] for p in packages if p not in ["world", "system"]]): + self.db.reload(cat) + debug("Category %s refreshed", cat) update_packages() @@ -529,7 +547,7 @@ class EmergeQueue: its = [] for k in queue: list += ["="+k] - if self.tree: its.append(self.iters[k]) + if self.tree: its.append(self.iters["install"][k]) return list, its @@ -698,9 +716,9 @@ class EmergeQueue: 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[cpv] + del self.iters["install"][cpv] try: - del self.deps[cpv] + 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) try: @@ -717,8 +735,21 @@ class EmergeQueue: 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) + self.tree.remove(it) def is_empty (self): diff --git a/portato/gui/templates/portato.glade b/portato/gui/templates/portato.glade index 86e0c09..e9512a3 100644 --- a/portato/gui/templates/portato.glade +++ b/portato/gui/templates/portato.glade @@ -499,6 +499,9 @@ gtk-add + + False + @@ -510,6 +513,9 @@ gtk-remove + + False + @@ -521,6 +527,9 @@ gtk-undo + + False + @@ -546,10 +555,27 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 6 - 7 + 8 2 5 5 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + 0 + label + True + + + 1 + 2 + 3 + 4 + + + @@ -557,106 +583,96 @@ - + True - True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - Testing 0 - 0 - True - + <b>License:</b> + True + True - 5 - 6 + 3 + 4 GTK_FILL - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 + True + <b>Installed, but not in portage anymore</b> + True - 1 2 - 6 - 7 + 4 + 5 - + True - True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True - Masked - 0 - 0 - True - + <span foreground='red'><b>MISSING KEYWORD</b></span> + True - 6 - 7 - GTK_FILL + 2 + 4 + 5 - + True - True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - Installed - 0 - 0 - True - + 5 + + + - 4 - 5 - GTK_FILL + 1 + 2 + 2 + 3 - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 - <b>Homepage:</b> + <b>Description:</b> True True - 2 - 3 GTK_FILL - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True 0 - label + <b>Overlay:</b> + True True - 1 - 2 1 2 + GTK_FILL @@ -675,80 +691,106 @@ - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True 0 - <b>Overlay:</b> - True + label True + 1 + 2 1 2 - GTK_FILL - + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 - <b>Description:</b> + <b>Homepage:</b> True True + 2 + 3 GTK_FILL - + True + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - + True + Installed + 0 + 0 + True + - 1 - 2 - 2 - 3 + 5 + 6 + GTK_FILL - + True + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True - <span foreground='red'><b>MISSING KEYWORD</b></span> - True + Masked + 0 + 0 + True + + 7 + 8 + GTK_FILL + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + + + 1 2 - 3 - 4 + 7 + 8 - + True + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True - <b>Installed, but not in portage anymore</b> - True + Testing + 0 + 0 + True + - 2 - 3 - 4 + 6 + 7 + GTK_FILL @@ -1415,189 +1457,189 @@ - - True - 0 - 5 - <u><i>Masking Keywords</i></u> - True - True - - - 7 - 8 - 5 - - - - + True - 0 - 5 - <u><i>Testing Keywords</i></u> - True - True - 4 - 5 - 5 + 1 + 2 + 3 + 4 - + True 0 - 5 - <u><i>Use-Flags</i></u> - True + File name to use, if package.use is a directory: True - 1 - 2 - 6 + 3 + 4 - + True - - - True - 0 - GTK_SHADOW_OUT - - - True - 0 - <u>You may use the following placeholders:</u> - -<i>$(cat)</i>: category -<i>$(pkg)</i>: package name -<i>$(cat-1)/$(cat-2)</i>: first/second part of the category - True - - - - - - label_item - - - - + Add only exact version to package.use + 0 + True 2 + 2 + 3 - + True - Add only exact version to package.mask/package.unmask + Add only exact version to package.keywords 0 True 2 - 8 - 9 + 5 + 6 - + True 0 - File name to use, if package.mask/package.unmask is a directory: + File name to use, if package.keywords is a directory: True - 9 - 10 + 6 + 7 - + True 1 2 - 9 - 10 + 6 + 7 - + True 1 2 - 6 - 7 + 9 + 10 - + True 0 - File name to use, if package.keywords is a directory: + File name to use, if package.mask/package.unmask is a directory: True - 6 - 7 + 9 + 10 - + True - Add only exact version to package.keywords + Add only exact version to package.mask/package.unmask 0 True 2 - 5 - 6 + 8 + 9 - + True - Add only exact version to package.use - 0 - True + + + True + 0 + GTK_SHADOW_OUT + + + True + 0 + <u>You may use the following placeholders:</u> + +<i>$(cat)</i>: category +<i>$(pkg)</i>: package name +<i>$(cat-1)/$(cat-2)</i>: first/second part of the category + True + + + + + + label_item + + + + 2 - 2 - 3 - + True 0 - File name to use, if package.use is a directory: + 5 + <u><i>Use-Flags</i></u> + True True - 3 - 4 + 1 + 2 + 6 - + True + 0 + 5 + <u><i>Testing Keywords</i></u> + True + True - 1 - 2 - 3 - 4 + 4 + 5 + 5 + + + + + True + 0 + 5 + <u><i>Masking Keywords</i></u> + True + True + + + 7 + 8 + 5 @@ -2050,14 +2092,17 @@ True True False + Portato This software is licensed under the terms of the GPLv2. Copyright (C) 2006-2007 René 'Necoro' Neumann <necoro@necoro.net> A Portage GUI http://portato.necoro.net René 'Necoro' Neumann -Many thanks to the Porthole team which often inspired me or gave me hints. -(And sometimes I even copied files ^^ ;)) +Thanks goto: + - The Porthole team, which often inspired me and gave me hints :) + - franzf, who often tested and gave comments + - the Sabayon-Distro for making Portato the default Portage-GUI Catalan - Roger Calvó German - René 'Necoro' Neumann p4r4d0x (inspired by wolfden) diff --git a/portato/gui/wrapper.py b/portato/gui/wrapper.py index 011c819..2a88bdf 100644 --- a/portato/gui/wrapper.py +++ b/portato/gui/wrapper.py @@ -198,9 +198,9 @@ class Console: Each frontend _MUST_ define its own subclass and implement ALL of the methods, otherwise a NotImplementedError will be thrown.""" def set_pty (self, pty): - """This sets the pseudo-terminal where to print the incoming output to. + """This sets the pty master. - @param pty: the terminal to print to + @param pty: the pty master @type pty: file-descriptor""" raise NotImplementedError -- cgit v1.2.3