diff options
Diffstat (limited to 'portato')
62 files changed, 527 insertions, 264 deletions
diff --git a/portato/__init__.py b/portato/__init__.py index 98c019d..61d6a42 100644 --- a/portato/__init__.py +++ b/portato/__init__.py @@ -3,7 +3,7 @@ # File: portato/__init__.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/backend/__init__.py b/portato/backend/__init__.py index 4f20a18..5f32818 100644 --- a/portato/backend/__init__.py +++ b/portato/backend/__init__.py @@ -3,7 +3,7 @@ # File: portato/backend/__init__.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/backend/exceptions.py b/portato/backend/exceptions.py index f20a33e..dc2c7cd 100644 --- a/portato/backend/exceptions.py +++ b/portato/backend/exceptions.py @@ -3,7 +3,7 @@ # File: portato/backend/exceptions.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/backend/flags.py b/portato/backend/flags.py index 9c5b93d..810b607 100644 --- a/portato/backend/flags.py +++ b/portato/backend/flags.py @@ -3,7 +3,7 @@ # File: portato/backend/flags.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/backend/package.py b/portato/backend/package.py index 89d1528..56b910d 100644 --- a/portato/backend/package.py +++ b/portato/backend/package.py @@ -3,7 +3,7 @@ # File: portato/backend/package.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/backend/portage/__init__.py b/portato/backend/portage/__init__.py index 1daf51b..e559f9e 100644 --- a/portato/backend/portage/__init__.py +++ b/portato/backend/portage/__init__.py @@ -3,7 +3,7 @@ # File: portato/backend/portage/__init__.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/backend/portage/package.py b/portato/backend/portage/package.py index f108bde..7dbefb7 100644 --- a/portato/backend/portage/package.py +++ b/portato/backend/portage/package.py @@ -3,7 +3,7 @@ # File: portato/backend/portage/package.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/backend/portage/package_22.py b/portato/backend/portage/package_22.py index ed804ce..23e8ed5 100644 --- a/portato/backend/portage/package_22.py +++ b/portato/backend/portage/package_22.py @@ -3,7 +3,7 @@ # File: portato/backend/portage/package_22.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/backend/portage/sets.py b/portato/backend/portage/sets.py index 234047b..c1971b7 100644 --- a/portato/backend/portage/sets.py +++ b/portato/backend/portage/sets.py @@ -3,7 +3,7 @@ # File: portato/backend/portage/sets.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. @@ -102,7 +102,7 @@ class InstalledSet (Set): else: t = system.settings.vartree.dbapi.match(key) if not with_version: - t = itt.imap(portage.dep.dep_getkey, t) + t = itt.imap(portage.cpv_getkey, t) return set(t) diff --git a/portato/backend/portage/settings.py b/portato/backend/portage/settings.py index 8211f3b..2f3b780 100644 --- a/portato/backend/portage/settings.py +++ b/portato/backend/portage/settings.py @@ -3,7 +3,7 @@ # File: portato/backend/portage/settings.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/backend/portage/settings_22.py b/portato/backend/portage/settings_22.py index bae3424..ba4f1e8 100644 --- a/portato/backend/portage/settings_22.py +++ b/portato/backend/portage/settings_22.py @@ -3,7 +3,7 @@ # File: portato/backend/portage/settings_22.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/backend/portage/system.py b/portato/backend/portage/system.py index 4a08616..34d2b5c 100644 --- a/portato/backend/portage/system.py +++ b/portato/backend/portage/system.py @@ -3,7 +3,7 @@ # File: portato/backend/portage/system.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. @@ -249,7 +249,7 @@ class PortageSystem (SystemInterface): if not best: return - if not best.is_installed() and (best.is_masked() or best.is_testing(True)): # check to not update unnecessairily + if not best.is_installed() and (best.is_masked() or best.is_testing(True)): # check to not update unnecessarily for i in inst: if i.matches(crit): debug("The installed %s matches %s. Discarding upgrade to masked version %s.", i.get_cpv(), crit, best.get_version()) diff --git a/portato/backend/portage/system_22.py b/portato/backend/portage/system_22.py index d720a06..c3bfa5f 100644 --- a/portato/backend/portage/system_22.py +++ b/portato/backend/portage/system_22.py @@ -3,7 +3,7 @@ # File: portato/backend/portage/system_22.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/backend/system_interface.py b/portato/backend/system_interface.py index f0bfdf6..a156d2b 100644 --- a/portato/backend/system_interface.py +++ b/portato/backend/system_interface.py @@ -3,7 +3,7 @@ # File: portato/backend/system_interface.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/config_parser.py b/portato/config_parser.py index 39234a9..2ef52c5 100644 --- a/portato/config_parser.py +++ b/portato/config_parser.py @@ -3,7 +3,7 @@ # File: portato/config_parser.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/constants.py b/portato/constants.py index bce15d2..a8e930c 100644 --- a/portato/constants.py +++ b/portato/constants.py @@ -3,7 +3,7 @@ # File: portato/constants.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/db/__init__.py b/portato/db/__init__.py index 9d21d3b..850a84e 100644 --- a/portato/db/__init__.py +++ b/portato/db/__init__.py @@ -3,7 +3,7 @@ # File: portato/db/__init__.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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,66 +12,66 @@ from __future__ import absolute_import +from . import database as db +from .exceptions import UnknownDatabaseTypeError, DatabaseInstantiationError from ..session import Session, SectionDict from ..helper import debug, warning, error -class UnknownDatabaseTypeError (Exception): - pass - -_SESSION = None -_TYPE = None -_DEFAULT = "dict" -_DATABASE = None - types = { "sql": (_("SQLite"), _("Uses an SQLite-database to store package information.\nMay take longer to generate at the first time, but has advantages if portato is re-started with an unchanged portage tree. Additionally it allows to use fast SQL expressions for fetching the data.")), "dict": (_("Hashmap"), _("Uses an in-memory hashmap to store package information.\nHas been used since at least version 0.3.3, but all information has to be regenerated on each startup.")), - "eixsql" : (_("eix + SQLite"), _("Similar to SQLite, but now uses the eix database to get the package information.\nThis should be much faster on startup, but requires that your eix database is always up-to-date.")) + "eixsql" : (_("eix + SQLite"), _("Similar to SQLite, but now uses the eix database to get the package information.\nThis should be much faster on startup, but requires that your eix database is always up-to-date.\nAdditionally, this is the only database allowing searching in descriptions.")) } -def Database(type = None): - global _SESSION, _TYPE, _DATABASE +class Database(db.Database): + DEFAULT = "dict" - if type is None: - if _DATABASE is None: - warning("No database type specified! Falling back to default.") - return Database(_DEFAULT) - else: - return _DATABASE + def __new__ (cls, type = None): + if not '_the_instance' in cls.__dict__: + dbcls = cls._generate(type) + cls._the_instance = dbcls(cls._get_session()) + elif type is not None: + raise DatabaseInstantiationError("Database instantiation called with 'type' argument multiple times.") + return cls._the_instance - if _SESSION is None: - _SESSION = Session("db.cfg", name = "DB") - _SESSION.load() + @classmethod + def _generate(cls, type): - _TYPE = type + if type is None: + warning("No database type specified! Falling back to default.") + type = cls.DEFAULT + + cls.DB_TYPE = type - if type == "sql": - debug("Using SQLDatabase") - try: - from .sql import SQLDatabase - except ImportError: - warning(_("Cannot load %s."), "SQLDatabase") - _DATABASE = Database("dict") - else: - _DATABASE = SQLDatabase(SectionDict(_SESSION, type)) + if type == "sql": + debug("Using SQLDatabase") + try: + from .sql import SQLDatabase + except ImportError: + warning(_("Cannot load %s."), "SQLDatabase") + return cls._generate("dict") + else: + return SQLDatabase - elif type == "dict": - debug("Using HashDatabase") - from .hash import HashDatabase - _DATABASE = HashDatabase(SectionDict(_SESSION, type)) - - elif type == "eixsql": - debug("Using EixSQLDatabase") - try: - from .eix_sql import EixSQLDatabase - except ImportError: - warning(_("Cannot load %s."), "EixSQLDatabase.") - _DATABASE = Database("sql") - else: - _DATABASE = EixSQLDatabase(SectionDict(_SESSION, type)) + elif type == "dict": + debug("Using HashDatabase") + from .hash import HashDatabase + return HashDatabase + + elif type == "eixsql": + debug("Using EixSQLDatabase") + try: + from .eix_sql import EixSQLDatabase + except ImportError: + warning(_("Cannot load %s."), "EixSQLDatabase.") + return cls._generate("sql") + else: + return EixSQLDatabase - else: - error(_("Unknown database type: %s"), type) - raise UnknownDatabaseTypeError, type + else: + error(_("Unknown database type: %s"), type) + raise UnknownDatabaseTypeError, type - return _DATABASE + @classmethod + def _get_session(cls): + return SectionDict(Session("db.cfg", name = "DB"), cls.DB_TYPE) diff --git a/portato/db/database.py b/portato/db/database.py index 7a23e5e..c679d06 100644 --- a/portato/db/database.py +++ b/portato/db/database.py @@ -3,7 +3,7 @@ # File: portato/db/database.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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,6 +14,12 @@ from __future__ import absolute_import, with_statement from threading import RLock from functools import wraps +from ..helper import warning + +from .exceptions import UnsupportedSearchTypeError + +class UnsupportedSearchTypeError(Exception): + pass class PkgData (object): __slots__ = ("cat", "pkg", "inst", "disabled") @@ -37,8 +43,19 @@ class Database (object): ALL = _("ALL") + SEARCH_NAME = 1 + SEARCH_DESCRIPTION = 2 + + TYPES = { + SEARCH_NAME : _("Name"), + SEARCH_DESCRIPTION : _("Description"), + SEARCH_NAME | SEARCH_DESCRIPTION : "%s + %s" % (_("Name"), _("Description")) + } + + def __init__ (self): self._lock = RLock() + self.type = self.SEARCH_NAME @staticmethod def lock (f): @@ -51,6 +68,24 @@ class Database (object): return wrapper + def search_types (self): + """The types of search supported by the database. + + @return: type + @rtype: int""" + raise NotImplentedError + + def set_type (self, type): + if type & self.search_types() != type: + raise UnsupportedSearchTypeError, type + + self._type = type + + def get_type (self): + return self._type + + type = property(get_type, set_type) + def populate (self, category = None): """Populates the database. diff --git a/portato/db/eix_sql.py b/portato/db/eix_sql.py index c2d2292..75bcb1e 100644 --- a/portato/db/eix_sql.py +++ b/portato/db/eix_sql.py @@ -3,7 +3,7 @@ # File: portato/db/eix_sql.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. @@ -41,6 +41,9 @@ class EixSQLDatabase (SQLDatabase): SQLDatabase.__init__(self, session) + def search_types(self): + return self.SEARCH_NAME | self.SEARCH_DESCRIPTION + def updated (self): mtime = os.stat(self.cache).st_mtime old = self.session.get("mtime", 0) @@ -63,7 +66,7 @@ class EixSQLDatabase (SQLDatabase): if category is None or cat.name == category: for pkg in cat.packages: p = "%s/%s" % (cat.name, pkg.name) - yield (cat.name, pkg.name, p in inst, False) + yield (cat.name, pkg.name, pkg.description, p in inst, False) - connection.executemany("INSERT INTO packages (cat, name, inst, disabled) VALUES (?, ?, ?, ?)", _get()) + connection.executemany("INSERT INTO packages (cat, name, descr, inst, disabled) VALUES (?, ?, ?, ?, ?)", _get()) connection.commit() diff --git a/portato/db/exceptions.py b/portato/db/exceptions.py new file mode 100644 index 0000000..8a6e424 --- /dev/null +++ b/portato/db/exceptions.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# +# File: portato/db/exceptions.py +# This file is part of the Portato-Project, a graphical portage-frontend. +# +# Copyright (C) 2006-2010 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> + +class DatabaseError (Exception): + pass + +class UnknownDatabaseTypeError (DatabaseError): + pass + +class DatabaseInstantiationError (DatabaseError): + pass + +class UnsupportedSearchTypeError(DatabaseError): + pass + diff --git a/portato/db/hash.py b/portato/db/hash.py index 8cea6f2..4a6958b 100644 --- a/portato/db/hash.py +++ b/portato/db/hash.py @@ -3,7 +3,7 @@ # File: portato/db/hash.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. @@ -32,6 +32,9 @@ class HashDatabase (Database): self.__initialize() self.populate() + def search_types(self): + return Database.SEARCH_NAME + def __initialize (self): self._db = defaultdict(list) self.inst_cats = set([self.ALL]) diff --git a/portato/db/sql.py b/portato/db/sql.py index fbc01e6..f5dc257 100644 --- a/portato/db/sql.py +++ b/portato/db/sql.py @@ -3,7 +3,7 @@ # File: portato/db/sql.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. @@ -34,7 +34,7 @@ from .database import Database, PkgData class SQLDatabase (Database): - FORMAT = "1" + FORMAT = "2" FORBIDDEN = (".bzr", ".svn", ".git", "CVS", ".hg", "_darcs") lock = Database.lock @@ -47,6 +47,7 @@ class SQLDatabase (Database): updateFormat = False if "format" not in session or session["format"] != self.FORMAT: + debug("Need to update database format from '%s' to '%s'", session["format"], self.FORMAT) session["format"] = self.FORMAT updateFormat = True @@ -61,6 +62,7 @@ class SQLDatabase (Database): pkg_conn = sql.connect(pkgdb) pkg_conn.row_factory = sql.Row if pkgdb_existed and updateFormat: + debug("Dropping old table") pkg_conn.execute("DROP TABLE packages") pkg_conn.execute(""" @@ -68,6 +70,7 @@ class SQLDatabase (Database): ( name TEXT, cat TEXT, + descr TEXT DEFAULT "", inst INTEGER, disabled INTEGER )""") @@ -83,6 +86,9 @@ class SQLDatabase (Database): pkg_conn.close() + def search_types(self): + return self.SEARCH_NAME + def updated (self): changed = False @@ -114,7 +120,7 @@ class SQLDatabase (Database): os.remove(dbpath) db_existed = False - self.session["pickle"] = True # no need for a certain value + self.session["pickle"] = "1" # no need for a certain value if db_existed: debug("portdirs.db already existant") @@ -253,12 +259,22 @@ class SQLDatabase (Database): self._restrict = "" else: restrict = restrict.replace(".*","%").replace(".","_") + rest = "" + + if self._type & self.SEARCH_NAME: + if "/" in restrict: + rest = "(name LIKE '%s%%' AND cat LIKE '%s')" % (pkg, cat) + else: + rest = "(name LIKE '%%%(restrict)s%%' OR cat LIKE '%(restrict)s%%')" % {"restrict":restrict} - if "/" in restrict: - cat,pkg = restrict.split("/") - self._restrict = "AND name LIKE '%s%%' AND cat LIKE '%s'" % (pkg, cat) - else: - self._restrict = "AND (name LIKE '%%%(restrict)s%%' OR cat LIKE '%(restrict)s%%')" % {"restrict":restrict} + if self._type & self.SEARCH_DESCRIPTION: + r = "descr LIKE '%%%(restrict)s%%'" % {"restrict":restrict} + if rest: + rest = "(%s OR %s)" % (r, rest) + else: + rest = r + + self._restrict = "AND " + rest restrict = property(get_restrict, set_restrict) con = staticmethod(con) diff --git a/portato/dependency.py b/portato/dependency.py index bda20eb..4b505e6 100644 --- a/portato/dependency.py +++ b/portato/dependency.py @@ -3,7 +3,7 @@ # File: portato/dependency.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/eix/__init__.py b/portato/eix/__init__.py index 346fe82..8fa1da6 100644 --- a/portato/eix/__init__.py +++ b/portato/eix/__init__.py @@ -3,7 +3,7 @@ # File: portato/eix/__init__.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/eix/exceptions.py b/portato/eix/exceptions.py index 8145af4..1ca05e1 100644 --- a/portato/eix/exceptions.py +++ b/portato/eix/exceptions.py @@ -3,7 +3,7 @@ # File: portato/eix/exceptions.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/eix/parser.pyx b/portato/eix/parser.pyx index 01a673f..d4bd3af 100644 --- a/portato/eix/parser.pyx +++ b/portato/eix/parser.pyx @@ -3,7 +3,7 @@ # File: portato/eix/_parser.pyx # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. @@ -260,7 +260,7 @@ cdef class package: cdef LLong _offset cdef readonly object name - #cdef readonly object description + cdef readonly object description #cdef readonly object provide #cdef readonly object homepage #cdef readonly object license @@ -279,9 +279,9 @@ cdef class package: after_offset = ftell(cfile) self.name = string(file) + self.description = string(file) # skip the rest, as it is currently unneeded - #self.description = string(file) #self.provide = vector(file, number) #self.homepage = string(file) #self.license = number(file) diff --git a/portato/eix/py_parser.py b/portato/eix/py_parser.py index cc42553..231c206 100644 --- a/portato/eix/py_parser.py +++ b/portato/eix/py_parser.py @@ -3,7 +3,7 @@ # File: portato/eix/parser.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/__init__.py b/portato/gui/__init__.py index 0a584a8..bbe21d8 100644 --- a/portato/gui/__init__.py +++ b/portato/gui/__init__.py @@ -3,7 +3,7 @@ # File: portato/gui/__init__.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/dialogs.py b/portato/gui/dialogs.py index d7ac41b..2cc2d6b 100644 --- a/portato/gui/dialogs.py +++ b/portato/gui/dialogs.py @@ -3,7 +3,7 @@ # File: portato/gui/dialogs.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. @@ -20,6 +20,13 @@ def mail_failure_dialog(e): dialog.destroy() return ret +def no_email_dialog(p): + dialog = gtk.MessageDialog(p, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK_CANCEL, _("No email address given")) + dialog.format_secondary_text(_("You haven't specified an email address. Without it, it will not be possible for the developers to contact you for questions and thus it might be harder to fix the bug.\n\nDo you want to proceed nevertheless?")) + ret = dialog.run() + dialog.destroy() + return ret + def queue_not_empty_dialog(): dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_NONE, _("Do you really want to quit?")) dialog.format_secondary_text(_("There are some packages in the emerge queue and/or an emerge process is running.")) @@ -68,7 +75,18 @@ def nothing_found_dialog (): def changed_flags_dialog (what = "flags"): check = gtk.CheckButton(_("Do not show this dialog again.")) hintMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("Changed %s") % what) - hintMB.format_secondary_text(_("Portato will write these changes into the appropriate files.\nPlease backup them if you think it is necessairy.")) + hintMB.format_secondary_text(_("Portato will write these changes into the appropriate files.\nPlease backup them if you think it is necessary.")) + hintMB.vbox.add(check) + hintMB.vbox.show_all() + ret = hintMB.run() + hintMB.destroy() + + return ret, check.get_active() + +def update_world_warning_dialog (): + check = gtk.CheckButton(_("Do not show this dialog again.")) + hintMB = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, _("'Update World' may be giving errors")) + hintMB.format_secondary_text(_("Due to the fast changing portage, 'update world' might not work correctly or even throw errors.\nThis will be fixed (hopefully) in the next release.")) hintMB.vbox.add(check) hintMB.vbox.show_all() ret = hintMB.run() diff --git a/portato/gui/exception_handling.py b/portato/gui/exception_handling.py index 0ec1e9a..d9b133c 100644 --- a/portato/gui/exception_handling.py +++ b/portato/gui/exception_handling.py @@ -3,7 +3,7 @@ # File: portato/gui/exception_handling.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. @@ -99,7 +99,7 @@ def convert (version): def get_version_infos(): from ..constants import VERSION, REVISION from ..backend import system - from ..db import _TYPE as db_type + from ..db import Database if REVISION: VERSION = "%s (git: %s)" % (VERSION, REVISION) @@ -109,7 +109,7 @@ def get_version_infos(): "System: %s" % " ".join(get_runsystem()), "Python version: %s" % sys.version, "Used backend: %s" % system.get_version(), - "Used database type: %s" % db_type, + "Used database type: %s" % Database.DB_TYPE, "pygtk: %s (using GTK+: %s)" % (convert(gtk.pygtk_version), convert(gtk.gtk_version)), "pygobject: %s (using GLib: %s)" % (convert(gobject.pygobject_version), convert(gobject.glib_version)))) diff --git a/portato/gui/exceptions.py b/portato/gui/exceptions.py index 17041dc..3e35caa 100644 --- a/portato/gui/exceptions.py +++ b/portato/gui/exceptions.py @@ -3,7 +3,7 @@ # File: portato/gui/exceptions.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/queue.py b/portato/gui/queue.py index 6d3d19d..b18e4e7 100644 --- a/portato/gui/queue.py +++ b/portato/gui/queue.py @@ -3,7 +3,7 @@ # File: portato/gui/queue.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/session.py b/portato/gui/session.py index 7aa890d..549a2c9 100644 --- a/portato/gui/session.py +++ b/portato/gui/session.py @@ -3,7 +3,7 @@ # File: portato/gui/session.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/slots.py b/portato/gui/slots.py index c7f20e6..75f4d77 100644 --- a/portato/gui/slots.py +++ b/portato/gui/slots.py @@ -3,7 +3,7 @@ # File: portato/gui/slots.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/templates/AboutWindow.ui b/portato/gui/templates/AboutWindow.ui index ec3ed7e..a3f81cf 100644 --- a/portato/gui/templates/AboutWindow.ui +++ b/portato/gui/templates/AboutWindow.ui @@ -16,7 +16,7 @@ <property name="has_separator">False</property> <property name="program_name">Portato</property> <property name="copyright">This software is licensed under the terms of the GPLv2. -Copyright (C) 2006-2009 René 'Necoro' Neumann <necoro@necoro.net></property> +Copyright (C) 2006-2010 René 'Necoro' Neumann <necoro@necoro.net></property> <property name="comments">A Portage GUI</property> <property name="website">http://portato.necoro.net</property> <property name="authors">René 'Necoro' Neumann @@ -25,12 +25,6 @@ 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</property> - <property name="translator_credits">Catalan - Roger Calvó -German - René 'Necoro' Neumann -Polish - Tomasz Osiński -Portugese (Brazilian) - Alberto Federman Neto -Spanish - Daniel Halens -Turkish - Gürkan 'seqizz' Gür</property> <property name="artists">p4r4d0x (inspired by wolfden)</property> <signal name="response" handler="close"/> <child internal-child="vbox"> diff --git a/portato/gui/templates/MailInfoWindow.ui b/portato/gui/templates/MailInfoWindow.ui index 4551cdb..e3cdd1f 100644 --- a/portato/gui/templates/MailInfoWindow.ui +++ b/portato/gui/templates/MailInfoWindow.ui @@ -134,25 +134,39 @@ what did you do to hit the bug?</property> </packing> </child> <child> - <object class="GtkCheckButton" id="logCheck"> - <property name="label" translatable="yes">Attach _Logfile</property> + <object class="GtkFrame" id="frame1"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="tooltip_text" translatable="yes">Attaches the logfile to the mail. This log only contains debug information.</property> - <property name="use_underline">True</property> - <property name="active">True</property> - <property name="draw_indicator">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="left_padding">12</property> + <child> + <object class="GtkTreeView" id="fileList"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + <property name="headers_clickable">False</property> + <property name="enable_search">False</property> + <signal name="row_activated" handler="cb_file_clicked"/> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="label" translatable="yes">These files will be sent:</property> + </object> + </child> </object> <packing> + <property name="right_attach">2</property> <property name="top_attach">4</property> <property name="bottom_attach">5</property> - <property name="x_options">GTK_FILL</property> </packing> </child> - <child> - <placeholder/> - </child> </object> <packing> <property name="padding">5</property> diff --git a/portato/gui/templates/MainWindow.menu b/portato/gui/templates/MainWindow.menu index 5d8e8e0..5594aaf 100644 --- a/portato/gui/templates/MainWindow.menu +++ b/portato/gui/templates/MainWindow.menu @@ -16,7 +16,7 @@ <child> <object class="GtkAction" id="fileMenuAction"> <property name="name">fileMenuAction</property> - <property name="label" translatable="yes">_File</property> + <property name="label" translatable="yes">_General</property> </object> </child> <child> @@ -158,7 +158,7 @@ <object class="GtkAction" id="pluginsAction"> <property name="stock_id">gtk-connect</property> <property name="name">pluginsAction</property> - <property name="label" translatable="yes">_Plugins</property> + <property name="label" translatable="yes">Plu_gins</property> <signal handler="cb_plugins_clicked" name="activate"/> </object> </child> @@ -168,6 +168,7 @@ <menubar name="menubar"> <menu name="fileMenu" action="fileMenuAction"> <menuitem name="prefMenuItem" action="prefAction"/> + <menuitem name="pluginsMenuItem" action="pluginsAction"/> <menuitem name="reloadMenuItem" action="reloadAction"/> <separator/> <menuitem name="closeMenuItem" action="closeAction"/> @@ -176,6 +177,7 @@ <menuitem name="emergeMenuItem" action="emergeAction"/> <menuitem name="unmergeMenuItem" action="unmergeAction"/> <menuitem name="updateMenuItem" action="updateAction"/> + <separator/> <menuitem name="showUpdatesMenuItem" action="showUpdatesAction"/> <menuitem name="showWorldPkgsMenuItem" action="showWorldPkgsAction" /> <menuitem name="showInstalledMenuItem" action="showInstalledAction"/> @@ -189,7 +191,6 @@ <menu name="pluginMenu" action="pluginMenuAction"/> <menu name="helpMenu" action="helpMenuAction"> <menuitem name="aboutMenuItem" action="aboutAction"/> - <menuitem name="pluginsMenuItem" action="pluginsAction"/> </menu> </menubar> <popup name="systrayPopup"> diff --git a/portato/gui/templates/MainWindow.ui b/portato/gui/templates/MainWindow.ui index 8e8c3b4..05e9545 100644 --- a/portato/gui/templates/MainWindow.ui +++ b/portato/gui/templates/MainWindow.ui @@ -30,6 +30,16 @@ <property name="visible">True</property> <property name="border_width">3</property> <child> + <object class="GtkComboBox" id="typeCombo"> + <property name="visible">True</property> + <signal name="changed" handler="cb_type_combo_changed"/> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> <object class="GtkEntry" id="searchEntry"> <property name="visible">True</property> <signal name="changed" handler="cb_search_changed"/> @@ -38,12 +48,12 @@ </object> <packing> <property name="padding">5</property> - <property name="position">0</property> + <property name="position">1</property> </packing> </child> <child> <object class="GtkButton" id="deleteSearchButton"> - <property name="label">gtk-delete</property> + <property name="label">gtk-clear</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> @@ -54,7 +64,7 @@ <packing> <property name="expand">False</property> <property name="padding">5</property> - <property name="position">1</property> + <property name="position">2</property> </packing> </child> <child> @@ -69,7 +79,7 @@ <packing> <property name="expand">False</property> <property name="padding">5</property> - <property name="position">2</property> + <property name="position">3</property> </packing> </child> </object> diff --git a/portato/gui/templates/PreferenceWindow.ui b/portato/gui/templates/PreferenceWindow.ui index c7a00e0..d2135d0 100644 --- a/portato/gui/templates/PreferenceWindow.ui +++ b/portato/gui/templates/PreferenceWindow.ui @@ -784,8 +784,6 @@ <child> <object class="GtkHBox" id="hbox4"> <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="orientation">vertical</property> <property name="homogeneous">True</property> <child> <object class="GtkLabel" id="label21"> diff --git a/portato/gui/updater.py b/portato/gui/updater.py index 7ce7c51..6539913 100644 --- a/portato/gui/updater.py +++ b/portato/gui/updater.py @@ -3,7 +3,7 @@ # File: portato/gui/updater.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/utils.py b/portato/gui/utils.py index 47f6fb7..ce5971e 100644 --- a/portato/gui/utils.py +++ b/portato/gui/utils.py @@ -3,7 +3,7 @@ # File: portato/gui/utils.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/views.py b/portato/gui/views.py index 3fc965f..699a832 100644 --- a/portato/gui/views.py +++ b/portato/gui/views.py @@ -3,7 +3,7 @@ # File: portato/gui/views.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/windows/__init__.py b/portato/gui/windows/__init__.py index 6a4ac82..5be95ce 100644 --- a/portato/gui/windows/__init__.py +++ b/portato/gui/windows/__init__.py @@ -3,7 +3,7 @@ # File: portato/gui/gtk/__init__.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/windows/about.py b/portato/gui/windows/about.py index 6c6fec5..0d2ce1a 100644 --- a/portato/gui/windows/about.py +++ b/portato/gui/windows/about.py @@ -3,19 +3,20 @@ # File: portato/gui/windows/about.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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 __future__ import absolute_import, with_statement +import os import gtk from .basic import AbstractDialog -from ...constants import VERSION, REVISION, APP_ICON +from ...constants import VERSION, REVISION, DATA_DIR class AboutWindow (AbstractDialog): """A window showing the "about"-informations.""" @@ -24,11 +25,11 @@ class AboutWindow (AbstractDialog): AbstractDialog.__init__(self, parent) - img = gtk.Image() - img.set_from_file(APP_ICON) - self.window.set_version(VERSION) - self.window.set_logo(img.get_pixbuf()) + self.window.set_logo(None) + + with open(os.path.join(DATA_DIR, "TRANSLATORS")) as f: + self.window.set_translator_credits("".join(f.readlines())) if REVISION: gitlabel = self.tree.get_widget("gitLabel") diff --git a/portato/gui/windows/basic.py b/portato/gui/windows/basic.py index 20d8009..01d31e5 100644 --- a/portato/gui/windows/basic.py +++ b/portato/gui/windows/basic.py @@ -3,7 +3,7 @@ # File: portato/gui/windows/basic.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. @@ -151,6 +151,9 @@ class AbstractDialog (Window): self.window.set_transient_for(parent) self.parent = parent + # type hint + self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) + # catch the ESC-key self.window.connect("key-press-event", self.cb_key_pressed) diff --git a/portato/gui/windows/mailinfo.py b/portato/gui/windows/mailinfo.py index 0cc79f2..4367482 100644 --- a/portato/gui/windows/mailinfo.py +++ b/portato/gui/windows/mailinfo.py @@ -3,7 +3,7 @@ # File: portato/gui/windows/mailinfo.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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,34 +14,98 @@ from __future__ import absolute_import, with_statement import smtplib, socket import time +import gtk, pango, gobject from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText +from os.path import basename from .basic import AbstractDialog from ..utils import GtkThread -from ..dialogs import mail_failure_dialog +from .. import dialogs from ...helper import debug, info -from ...constants import VERSION +from ...constants import VERSION, CONFIG_LOCATION from ...log import LOGFILE +from ... import session + +def mail_failure_dialog(*a): + dialogs.mail_failure_dialog(*a) + return False + +class ShowDialog (gtk.Dialog): + + def __init__(self, parent, f): + gtk.Dialog.__init__(self, f, parent, buttons = (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)) + + textview = gtk.TextView() + textview.set_editable(False) + textview.modify_font(pango.FontDescription("Monospace")) + textview.set_size_request(gtk.gdk.screen_width()/2, gtk.gdk.screen_height()/3) + + sw = gtk.ScrolledWindow(); + sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + sw.add(textview) + + self.vbox.add(sw) + + textbuffer = textview.get_buffer() + + with open(f) as text: + textbuffer.set_text(text.read()) + + self.vbox.show_all() class MailInfoWindow (AbstractDialog): - TO = "bugs@portato.necoro.net" + TO = "bugs@necoro.eu" def __init__ (self, parent, tb): AbstractDialog.__init__(self, parent) + + self.files = [LOGFILE, CONFIG_LOCATION] + [s._file for s in session.sessionlist] + self.fileList = self.tree.get_widget("fileList") + self.build_file_list() + self.mailEntry = self.tree.get_widget("mailEntry") self.tb = tb self.window.show_all() + def build_file_list(self): + store = gtk.ListStore(bool, str) + + for f in self.files: + store.append((True, f)) + + self.fileList.set_model(store) + cell = gtk.CellRendererText() + tCell = gtk.CellRendererToggle() + tCell.set_property("activatable", True) + tCell.connect("toggled", self.cb_file_toggled) + + self.fileList.append_column(gtk.TreeViewColumn(None, tCell, active = 0)) + self.fileList.append_column(gtk.TreeViewColumn(None, cell, text = 1)) + + def cb_file_toggled(self, cell, path): + store = self.fileList.get_model() + store[path][0] = not store[path][0] + return True + + def cb_file_clicked(self, view, path, *args): + store = view.get_model() + f = store[path][1] + + dialog = ShowDialog(self.window, f) + dialog.run() + dialog.destroy() + def set_data (self): self.message = MIMEMultipart() self.message["Subject"] = "[Bug Report] Bug in Portato %s" % VERSION self.message["To"] = self.TO + self.message["X-Portato-Version"] = VERSION # TO and FROM name = self.tree.get_widget("nameEntry").get_text() - self.addr = self.tree.get_widget("mailEntry").get_text() + self.addr = self.mailEntry.get_text() if not self.addr: self.addr = self.TO @@ -63,40 +127,61 @@ class MailInfoWindow (AbstractDialog): txtmsg = MIMEText(text, "plain", "utf-8") self.message.attach(txtmsg) - # log - if self.tree.get_widget("logCheck").get_active(): - with open(LOGFILE, "r") as f: - log = MIMEText(f.read(), "plain", "utf-8") - log.add_header('Content-Disposition', 'attachment', filename='portato.log') + # logs + for (active, f) in self.fileList.get_model(): + if active: + debug("Attaching '%s'", f) + with open(f, "r") as text: + log = MIMEText(text.read(), "plain", "utf-8") + log.add_header('Content-Disposition', 'attachment', filename=basename(f)) - self.message.attach(log) + self.message.attach(log) def send (self): try: - debug("Connecting to server") - server = smtplib.SMTP("mail.necoro.eu") - debug("Sending mail") - try: + for i in range(5): # try 5 times at max + if i > 0: + info(_("Retrying after waiting %d seconds."), 300) + time.sleep(300) try: + debug("Connecting to server") + server = smtplib.SMTP("mail.necoro.eu") + debug("Sending mail") + + if smtplib._have_ssl: server.starttls() + else: debug("TLS not supported in Python. Continuing without it.") + server.sendmail(self.addr, self.TO, self.message.as_string()) except smtplib.SMTPRecipientsRefused, e: - info(_("An error occurred while sending. I think we were greylisted. The error: %s") % e) - info(_("Retrying after waiting 60 seconds.")) - time.sleep(60) - server.sendmail(self.addr, self.TO, self.message.as_string()) - debug("Sent") - finally: - server.quit() + if e.recipients[self.TO][0] < 500: + info(_("An error occurred while sending. I think we were greylisted. The error: %s") % e) + else: raise + else: + debug("Sent") + break + finally: + try: + server.quit() + except smtplib.SMTPServerDisconnected: + pass # ignore this except socket.error, e: - mail_failure_dialog("%s (Code: %s)" % (e.args[1], e.args[0])) + gobject.idle_add(mail_failure_dialog, "%s (Code: %s)" % (e.args[1], e.args[0])) + except smtplib.SMTPResponseException, e: + gobject.idle_add(mail_failure_dialog, "%s (Code: %s)" % (e.smtp_error, e.smtp_code)) + except smtplib.SMTPException, e: + gobject.idle_add(mail_failure_dialog, e.args) def cb_cancel_clicked (self, *args): - self.close() return True def cb_send_clicked (self, *args): - self.set_data() - GtkThread(target = self.send, name = "Mail Send Thread").start() - self.close() + if self.mailEntry.get_text() or dialogs.no_email_dialog(self.window) == gtk.RESPONSE_OK: + self.set_data() + GtkThread(target = self.send, name = "Mail Send Thread").start() + self.close() + else: + self.window.present() + self.mailEntry.grab_focus() + return True diff --git a/portato/gui/windows/main.py b/portato/gui/windows/main.py index ca88b04..3c868e8 100644 --- a/portato/gui/windows/main.py +++ b/portato/gui/windows/main.py @@ -3,7 +3,7 @@ # File: portato/gui/windows/main.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. @@ -29,7 +29,8 @@ from ... import get_listener from ...helper import debug, warning, error, info from ...session import Session from ...db import Database -from ...constants import CONFIG_LOCATION, VERSION, APP_ICON +from ...db.database import UnsupportedSearchTypeError +from ...constants import CONFIG_LOCATION, VERSION, APP_ICON, ICON_DIR from ...backend.exceptions import PackageNotFoundException, BlockedException, VersionsNotFoundException # plugin stuff @@ -434,18 +435,27 @@ class MainWindow (Window): self.window.set_geometry_hints (self.window, max_height = gtk.gdk.screen_height(), max_width = gtk.gdk.screen_width()) # app icon - self.window.set_icon_from_file(APP_ICON) - gtk.window_set_default_icon(self.window.get_icon()) + gtk.window_set_default_icon_from_file(APP_ICON) # booleans self.doUpdate = False self.showAll = True # show only installed or all packages? self.__searchChanged = False + # our own icon factory + fac = gtk.IconFactory() + iSet = gtk.IconSet() + iSource = gtk.IconSource() + iSource.set_filename(os.path.abspath(os.path.join(ICON_DIR, "better-package.svg"))) + iSet.add_source(iSource) + fac.add("portato-better-pkg", iSet) + fac.add_default() + # icons self.icons = {} self.icons["installed"] = self.window.render_icon(gtk.STOCK_YES, gtk.ICON_SIZE_MENU) self.icons["or"] = self.window.render_icon(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_MENU) + self.icons["better"] = self.window.render_icon("portato-better-pkg", gtk.ICON_SIZE_MENU) # get the logging window as soon as possible self.logView = LogView(self.tree.get_widget("logView")) @@ -556,6 +566,10 @@ class MainWindow (Window): splash(_("Finishing startup")) + # depends on session + self.typeCombo = self.tree.get_widget("typeCombo") + self.build_type_combo() + self.window.show_all() def show_package (self, pkg = None, cpv = None, cp = None, version = None, **kwargs): @@ -782,10 +796,14 @@ class MainWindow (Window): if not packages: raise VersionsNotFoundException(cp) + best = system.find_best_match(cp) + # append versions for vers, inst, slot in ((x.get_version(), x.is_installed(), get_slot(x)) for x in packages): if inst: icon = self.icons["installed"] + elif best is not None and vers == best.get_version(): + icon = self.icons["better"] else: icon = None @@ -871,6 +889,26 @@ class MainWindow (Window): else: # no selCatName -> so no category selected --> ignore debug("No category selected --> should be no harm.") + def build_type_combo (self): + model = gtk.ListStore(int, str) + for k,v in self.db.TYPES.iteritems(): + model.append((k,v)) + + self.typeCombo.set_model(model) + cell = gtk.CellRendererText() + self.typeCombo.pack_start(cell) + self.typeCombo.set_attributes(cell, text = 1) + + + for i, (k, v) in enumerate(model): + if k == self.db.type: break + + self.typeCombo.set_active(i) + + types = self.db.search_types() + if types == 1 or types % 2 == 0: + self.typeCombo.set_sensitive(False) + def load_session(self, sessionEx = None, defaults_only = False): """ Loads the session data. @@ -987,6 +1025,14 @@ class MainWindow (Window): return _save + # SEARCH TYPE + def load_search_type (t): + t = int(t) + try: + self.db.type = t + except UnsupportedSearchTypeError: + info("Cannot set search type. '%s' not supported by database '%s'.", t, self.db.__class__.__name__) + # SESSION VERSION def load_session_version (version): @@ -1015,7 +1061,8 @@ class MainWindow (Window): (["width", "height"], lambda w,h: self.window.resize(int(w), int(h)), self.window.get_size), (["vpanedpos", "hpanedpos"], load_paned, save_paned), (["catsel"], load_cat_selection, save_cat_selection, ["app-portage@0"]), - (["pkgsel"], load_pkg_selection, save_pkg_selection, ["portato@0"]) + (["pkgsel"], load_pkg_selection, save_pkg_selection, ["portato@0"]), + (["searchtype"], load_search_type, lambda: self.db.type) #([("merge", "queue"), ("unmerge", "queue"), ("oneshot", "queue")], load_queue, save_queue), ]) @@ -1023,7 +1070,7 @@ class MainWindow (Window): queue = plugin.get_plugin_queue() if queue: for p in queue.get_plugins(): - self.session.add_handler(([(p.name.replace(" ","_"), "plugins")], load_plugin(p), save_plugin(p))) + self.session.add_handler(([(p.name.replace(" ","_").replace(":","_"), "plugins")], load_plugin(p), save_plugin(p))) # the other things def load_cfg ((name, cat)): @@ -1387,8 +1434,8 @@ class MainWindow (Window): """Execute the current queue.""" if len(flags.newUseFlags) > 0: - if not self.session.get_boolean("useflags", "dialogs"): - self.session.set("useflags", dialogs.changed_flags_dialog(_("use flags"))[1], "dialogs") + if not self.session.get_bool("useflags", "dialogs"): + self.session.set("useflags", str(dialogs.changed_flags_dialog(_("use flags"))[1]), "dialogs") try: flags.write_use_flags() except IOError, e: @@ -1399,8 +1446,8 @@ class MainWindow (Window): debug("new masked: %s",flags.new_masked) debug("new unmasked: %s", flags.new_unmasked) debug("new testing: %s", flags.newTesting) - if not self.session.get_boolean("keywords", "dialogs"): - self.session.set("keywords", dialogs.changed_flags_dialog(_("masking keywords"))[1], "dialogs") + if not self.session.get_bool("keywords", "dialogs"): + self.session.set("keywords", str(dialogs.changed_flags_dialog(_("masking keywords"))[1]), "dialogs") try: flags.write_masked() flags.write_testing() @@ -1464,8 +1511,15 @@ class MainWindow (Window): gobject.idle_add(cb_idle_append, updating) finally: self.window.window.set_cursor(None) - - GtkThread(name="Update-Thread", target=__update).start() + + # for some reason, I have to create the thread before displaying the dialog + # else the GUI hangs + t = GtkThread(name="Update-Thread", target=__update) + + if not self.session.get_bool("update_world_warning", "dialogs"): + self.session.set("update_world_warning", str(dialogs.update_world_warning_dialog()[1]), "dialogs") + + t.start() return True @@ -1562,7 +1616,13 @@ class MainWindow (Window): return False # not again ;) - gobject.timeout_add(100, __update) + gobject.timeout_add(200, __update) + + def cb_type_combo_changed (self, *args): + model = self.typeCombo.get_model() + active = self.typeCombo.get_active() + + self.db.type = model[active][0] def cb_delete_search_clicked (self, *args): self.searchEntry.set_text("") diff --git a/portato/gui/windows/pkglist.py b/portato/gui/windows/pkglist.py index 90915cb..df3ef46 100644 --- a/portato/gui/windows/pkglist.py +++ b/portato/gui/windows/pkglist.py @@ -3,7 +3,7 @@ # File: portato/gui/windows/pkglist.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/windows/plugin.py b/portato/gui/windows/plugin.py index 755ad58..89d38f5 100644 --- a/portato/gui/windows/plugin.py +++ b/portato/gui/windows/plugin.py @@ -3,7 +3,7 @@ # File: portato/gui/windows/plugin.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/windows/preference.py b/portato/gui/windows/preference.py index 4bd7551..021788c 100644 --- a/portato/gui/windows/preference.py +++ b/portato/gui/windows/preference.py @@ -3,7 +3,7 @@ # File: portato/gui/windows/preference.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/windows/search.py b/portato/gui/windows/search.py index c531507..f9191d7 100644 --- a/portato/gui/windows/search.py +++ b/portato/gui/windows/search.py @@ -3,7 +3,7 @@ # File: portato/gui/windows/search.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/gui/windows/splash.py b/portato/gui/windows/splash.py index c9e1542..2e9d5a8 100644 --- a/portato/gui/windows/splash.py +++ b/portato/gui/windows/splash.py @@ -3,7 +3,7 @@ # File: portato/gui/windows/splash.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/helper.py b/portato/helper.py index d32aa82..eb8ae2d 100644 --- a/portato/helper.py +++ b/portato/helper.py @@ -3,7 +3,7 @@ # File: portato/helper.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/ipc.pxd b/portato/ipc.pxd index 64ca05d..38e6d30 100644 --- a/portato/ipc.pxd +++ b/portato/ipc.pxd @@ -3,7 +3,7 @@ # File: portato/ipc.pxd # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/ipc.pyx b/portato/ipc.pyx index f3fb4af..abb26fe 100644 --- a/portato/ipc.pyx +++ b/portato/ipc.pyx @@ -3,7 +3,7 @@ # File: portato/ipc.pyx # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/listener.py b/portato/listener.py index c96b637..b3a3ba0 100644 --- a/portato/listener.py +++ b/portato/listener.py @@ -3,7 +3,7 @@ # File: portato/listener.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/log.py b/portato/log.py index 486aa51..b6462e9 100644 --- a/portato/log.py +++ b/portato/log.py @@ -3,7 +3,7 @@ # File: portato/log.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. @@ -100,3 +100,13 @@ def start(file = True): def set_log_level (lvl): for h in streamhandlers: h.setLevel(lvl) + +# embed warnings in our logging functionality +import warnings +def showwarnings(msg, cat, filename, lineno, file = None, line = None): + msg = warnings.formatwarning(msg, cat, filename, lineno, line) + + record = logging.LogRecord("portatoLogger", logging.WARNING, filename, lineno, "Portage Warning: %s", (msg,), None) + logging.getLogger("portatoLogger").handle(record) + +warnings.showwarning = showwarnings diff --git a/portato/plugin.py b/portato/plugin.py index 052dcd0..ec52314 100644 --- a/portato/plugin.py +++ b/portato/plugin.py @@ -3,7 +3,7 @@ # File: portato/plugin.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/plugins/__init__.py b/portato/plugins/__init__.py index 22d98be..772be8c 100644 --- a/portato/plugins/__init__.py +++ b/portato/plugins/__init__.py @@ -3,7 +3,7 @@ # File: portato/plugins/__init__.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/session.py b/portato/session.py index 2017544..aadf6c4 100644 --- a/portato/session.py +++ b/portato/session.py @@ -3,7 +3,7 @@ # File: portato/session.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. @@ -15,10 +15,12 @@ from __future__ import absolute_import, with_statement import os from UserDict import DictMixin -from .config_parser import ConfigParser, SectionNotFoundException +from ConfigParser import SafeConfigParser, NoSectionError, NoOptionError from .constants import SESSION_DIR from .helper import debug, info +from .odict import OrderedDict +NoSuchThing = (NoSectionError, NoOptionError) sessionlist = [] class Session (object): @@ -26,9 +28,6 @@ class Session (object): A small class allowing to save certain states of a program. This class works in a quite abstract manner, as it works with handlers, which define what options to use out of the config file and how to apply them to the program. - - Note: This class currently does not work with boolean config options. If you - want to define boolean values, use 0 and 1. This is future proof. """ # the current session format version @@ -44,38 +43,32 @@ class Session (object): @param register: register in the global sessionlist, which is closed at the end """ - self._cfg = None + self._cfg = SafeConfigParser({}, OrderedDict) self._handlers = [] self._name = name if name else "MAIN" + self._file = os.path.join(SESSION_DIR, file) if not (os.path.exists(SESSION_DIR) and os.path.isdir(SESSION_DIR)): os.mkdir(SESSION_DIR) - file = os.path.join(SESSION_DIR, file) oldfiles = [os.path.join(SESSION_DIR, x) for x in oldfiles] - if not os.path.exists(file): + if not os.path.exists(self._file): for o in oldfiles: if os.path.exists(o): debug("Moving old session file '%s' to '%s'." % (o, file)) - os.rename(o,file) + os.rename(o,self._file) break - self._cfg = ConfigParser(file) + self._cfg.read([self._file]) if name: - i = _("Loading '%s' session from %s.") % (name, self._cfg.file) + i = _("Loading '%s' session from %s.") % (name, self._file) else: - i = _("Loading session from %s.") % self._cfg.file + i = _("Loading session from %s.") % self._file info(i) - try: - self._cfg.parse() - except IOError, e: - if e.errno == 2: pass - else: raise - # register if register: sessionlist.append(self) @@ -90,7 +83,8 @@ class Session (object): - a function returning the number of option return values - getting them out of the program """ - options = map(lambda x: (x, self._name) if not hasattr(x, "__iter__") else x, options) + convert = lambda (x,y): (unicode(y).upper(), unicode(x).lower()) + options = map(lambda x: (self._name, unicode(x).lower()) if not hasattr(x, "__iter__") else convert(x), options) self._handlers.append((options, load_fn, save_fn, default)) def load (self, defaults_only = False): @@ -109,7 +103,7 @@ class Session (object): else: try: loaded = [self._cfg.get(*x) for x in options] - except KeyError: # does not exist -> ignore + except NoSuchThing: # does not exist -> ignore debug("No values for %s.", options) ldefault(options, lfn, default) else: @@ -124,97 +118,91 @@ class Session (object): for options, lfn, sfn, default in self._handlers: vals = sfn() - # map into list if necessairy + # map into list if necessary if not hasattr(vals, "__iter__"): vals = [vals] debug("Saving %s with values %s", options, vals) - for value, (option, section) in zip(vals, options): + for value, (section, option) in zip(vals, options): self.set(option, str(value), section) - self._cfg.write() + with open(self._file, "w") as f: + self._cfg.write(f) @classmethod def close (cls): for s in sessionlist: if s._name != "MAIN": - info(_("Saving '%s' session to %s.") % (s._name, s._cfg.file)) + info(_("Saving '%s' session to %s.") % (s._name, s._file)) else: - info(_("Saving session to %s.") % s._cfg.file) + info(_("Saving session to %s.") % s._file) s.save() - def set (self, key, value, section = ""): - if not section: section = self._name + def set (self, key, value, section = None): + if section is None: section = self._name + section = unicode(section).upper() try: - self._cfg.add(key, value, section, with_blankline = False) - except SectionNotFoundException: + self._cfg.set(section, key, value) + except NoSectionError: self._cfg.add_section(section) - self._cfg.add(key, value, section, with_blankline = False) + self._cfg.set(section, key, value) - def get (self, key, section = ""): - if not section: section = self._name + def get (self, key, section = None): + if section is None: section = self._name + section = unicode(section).upper() try: - return self._cfg.get(key, section) - except KeyError: + return self._cfg.get(section, key) + except NoSuchThing: return None - - def get_boolean (self, key, section = ""): - if not section: section = self._name + + def get_bool (self, key, section = None): + if section is None: section = self._name + section = unicode(section).upper() try: - return self._cfg.get_boolean(key, section) - except KeyError: + return self._cfg.getboolean(section, key) + except NoSuchThing, ValueError: return None + + def remove (self, key, section = None): + if section is None: section = self._name + section = unicode(section).upper() - def remove (self, key, section = ""): - if not section: section = self._name - - section = section.upper() - key = key.lower() - - val = self._cfg._access(key, section) - del self._cfg.cache[val.line] - - self._cfg.write() + self._cfg.remove_option(section, key) def remove_section (self, section): - section = section.upper() + section = unicode(section).upper() + self._cfg.remove_section(section) - sline = self._cfg.sections[section] + def rename (self, old, new, section = None): + if section is None: section = self._name + section = unicode(section).upper() - try: - mline = max(v.line for v in self._cfg.vars[section].itervalues()) - except ValueError: # nothing in the section - mline = sline - - sline = max(sline - 1, 0) # remove blank line too - but only if there is one ;) - - del self._cfg.cache[sline:mline+1] - self._cfg.write() - - def rename (self, old, new, section = ""): - if not section: section = self._name - val = self.get(old, section) - self.remove(old, section) - self._cfg.add(new, val, section, with_blankline = False) + + if val is not None: + self.remove(old, section) + self.set(new, val, section) def rename_section (self, old, new): - old = old.upper() - line = self._cfg.sections[old] - self._cfg.cache[line] = "[%s]\n" % new.upper() - self._cfg.write() + new = unicode(new).upper() + + values = self._cfg.items(old) + self.remove_section(old) + for k,v in values: + self.set(k,v,new) def check_version (self, vers): pass # do nothing atm + class SectionDict (DictMixin): """A class, which maps a specific section of a session to a dictionary.""" def __init__ (self, session, section): - self._section = section.upper() + self._section = unicode(section).upper() self._session = session def __getitem__ (self, name): @@ -231,7 +219,7 @@ class SectionDict (DictMixin): self._session.remove(name, self._section) def keys (self): - return self._session._cfg.vars[self._section].keys() + return self._session._cfg.options(self._section) def __contains__ (self, name): - return self._session.get(name, self._section) is not None + return self._session._cfg.has_option(self._section, name) diff --git a/portato/su.py b/portato/su.py index b87c75b..eb1f031 100644 --- a/portato/su.py +++ b/portato/su.py @@ -3,7 +3,7 @@ # File: portato/su.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. diff --git a/portato/waiting_queue.py b/portato/waiting_queue.py index 33791a3..1e3f7ad 100644 --- a/portato/waiting_queue.py +++ b/portato/waiting_queue.py @@ -3,7 +3,7 @@ # File: portato/waiting_queue.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2006-2009 René 'Necoro' Neumann +# Copyright (C) 2006-2010 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. |