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