diff options
Diffstat (limited to '')
-rw-r--r-- | portato/db/__init__.py | 98 | ||||
-rw-r--r-- | portato/db/database.py | 37 | ||||
-rw-r--r-- | portato/db/eix_sql.py | 9 | ||||
-rw-r--r-- | portato/db/exceptions.py | 24 | ||||
-rw-r--r-- | portato/db/hash.py | 5 | ||||
-rw-r--r-- | portato/db/sql.py | 32 |
6 files changed, 143 insertions, 62 deletions
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) |