2 ###############################################################################
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
29 log
= logging
.getLogger("pakfire")
31 import pakfire
.packages
as packages
33 from pakfire
.constants
import *
34 from pakfire
.errors
import *
35 from pakfire
.i18n
import _
37 class Cursor(sqlite3
.Cursor
):
38 def execute(self
, *args
, **kwargs
):
39 # For debugging of SQL queries.
42 return sqlite3
.Cursor
.execute(self
, *args
, **kwargs
)
45 class Database(object):
46 def __init__(self
, pakfire
, filename
):
47 self
.pakfire
= pakfire
48 self
.filename
= filename
72 log
.debug("Open database %s" % self
.filename
)
74 dirname
= os
.path
.dirname(self
.filename
)
75 if not os
.path
.exists(dirname
):
78 database_exists
= os
.path
.exists(self
.filename
)
80 # Make a connection to the database.
81 self
._db
= sqlite3
.connect(self
.filename
)
82 self
._db
.row_factory
= sqlite3
.Row
84 # In the case, the database was not existant, it is
85 # filled with content. In case it has been there
86 # we call the migrate method to update it if neccessary.
103 return self
._db
.cursor(Cursor
)
105 def executescript(self
, *args
, **kwargs
):
107 return self
._db
.executescript(*args
, **kwargs
)
110 class DatabaseLocal(Database
):
111 def __init__(self
, pakfire
, repo
):
114 # Generate filename for package database
115 filename
= os
.path
.join(pakfire
.path
, PACKAGES_DB
)
117 # Cache format number.
120 Database
.__init
__(self
, pakfire
, filename
)
122 def initialize(self
):
126 # Check if we actually can open the database.
127 if not self
.format
in DATABASE_FORMATS_SUPPORTED
:
128 raise DatabaseFormatError
, _("The format of the database is not supported by this version of pakfire.")
134 c
.execute("SELECT COUNT(*) AS count FROM packages")
143 if self
.__format
is None:
146 c
.execute("SELECT val FROM settings WHERE key = 'version' LIMIT 1")
149 self
.__format
= int(row
["val"])
161 CREATE TABLE settings(
165 INSERT INTO settings(key, val) VALUES('version', '%s');
168 id INTEGER PRIMARY KEY,
183 CREATE TABLE packages(
184 id INTEGER PRIMARY KEY,
215 CREATE TABLE scriptlets(
216 id INTEGER PRIMARY KEY,
222 CREATE TABLE triggers(
223 id INTEGER PRIMARY KEY,
228 """ % DATABASE_FORMAT
)
229 # XXX add some indexes here
234 # If we have already the latest version, there is nothing to do.
235 if self
.format
== DATABASE_FORMAT
:
238 # Check if database version is supported.
239 if self
.format
> DATABASE_FORMAT
:
240 raise DatabaseError
, _("Cannot use database with version greater than %s.") % DATABASE_FORMAT
242 log
.info(_("Migrating database from format %(old)s to %(new)s.") % \
243 { "old" : self
.format
, "new" : DATABASE_FORMAT
})
245 # Get a database cursor.
248 # 1) The vendor column was added.
250 c
.execute("ALTER TABLE packages ADD COLUMN vendor TEXT AFTER uuid")
253 c
.execute("ALTER TABLE files ADD COLUMN `config` INTEGER")
254 c
.execute("ALTER TABLE files ADD COLUMN `mode` INTEGER")
255 c
.execute("ALTER TABLE files ADD COLUMN `user` TEXT")
256 c
.execute("ALTER TABLE files ADD COLUMN `group` TEXT")
257 c
.execute("ALTER TABLE files ADD COLUMN `mtime` INTEGER")
260 c
.execute("ALTER TABLE files ADD COLUMN `capabilities` TEXT")
263 c
.execute("ALTER TABLE packages ADD COLUMN recommends TEXT AFTER obsoletes")
264 c
.execute("ALTER TABLE packages ADD COLUMN suggests TEXT AFTER recommends")
267 c
.execute("ALTER TABLE files ADD COLUMN datafile INTEGER AFTER config")
270 c
.execute("ALTER TABLE packages ADD COLUMN inst_size INTEGER AFTER size")
272 # In the end, we can easily update the version of the database.
273 c
.execute("UPDATE settings SET val = ? WHERE key = 'version'", (DATABASE_FORMAT
,))
274 self
.__format
= DATABASE_FORMAT
279 def add_package(self
, pkg
, reason
=None):
280 log
.debug("Adding package to database: %s" % pkg
.friendly_name
)
286 INSERT INTO packages(
315 ) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
322 " ".join(pkg
.groups
),
327 "\n".join(pkg
.provides
),
328 "\n".join(pkg
.requires
),
329 "\n".join(pkg
.conflicts
),
330 "\n".join(pkg
.obsoletes
),
331 "\n".join(pkg
.recommends
),
332 "\n".join(pkg
.suggests
),
350 c
.executemany("INSERT INTO files(`name`, `pkg`, `size`, `config`, `datafile`, `type`, `hash1`, `mode`, `user`, `group`, `mtime`, `capabilities`)"
351 " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
352 ((f
.name
, pkg_id
, f
.size
, f
.is_config(), f
.is_datafile(), f
.type, f
.hash1
, f
.mode
, f
.user
, f
.group
, f
.mtime
, f
.capabilities
or "") for f
in pkg
.filelist
))
362 def rem_package(self
, pkg
):
363 log
.debug("Removing package from database: %s" % pkg
.friendly_name
)
367 # Get the ID of the package in the database.
369 c
.execute("SELECT id FROM packages WHERE uuid = ? LIMIT 1", (pkg
.uuid
,))
370 #c.execute("SELECT id FROM packages WHERE name = ? AND epoch = ? AND version = ?"
371 # " AND release = ? LIMIT 1", (pkg.name, pkg.epoch, pkg.version, pkg.release,))
379 # First, delete all files from the database and then delete the pkg itself.
380 c
.execute("DELETE FROM files WHERE pkg = ?", (id,))
381 c
.execute("DELETE FROM packages WHERE id = ?", (id,))
386 def get_package_by_id(self
, id):
388 c
.execute("SELECT * FROM packages WHERE id = ?", (id,))
392 return packages
.DatabasePackage(self
.pakfire
, self
.repo
, self
, row
)
399 c
= self
.db
.execute("SELECT * FROM packages ORDER BY name")
401 for row
in c
.fetchall():
402 yield packages
.DatabasePackage(self
.pakfire
, self
.repo
, self
, row
)
406 def get_filelist(self
):
407 c
= self
.db
.execute("SELECT name FROM files")
409 return [r
["name"] for r
in c
.fetchall()]
411 def get_package_from_solv(self
, solv_pkg
):
414 c
= self
.db
.execute("SELECT * FROM packages WHERE uuid = ? LIMIT 1", (solv_pkg
.uuid
,))
421 return packages
.DatabasePackage(self
.pakfire
, self
.repo
, self
, row
)