summaryrefslogtreecommitdiff
path: root/portato/db
diff options
context:
space:
mode:
Diffstat (limited to 'portato/db')
-rw-r--r--portato/db/__init__.py98
-rw-r--r--portato/db/database.py37
-rw-r--r--portato/db/eix_sql.py9
-rw-r--r--portato/db/exceptions.py24
-rw-r--r--portato/db/hash.py5
-rw-r--r--portato/db/sql.py32
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)