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,
214 CREATE TABLE scriptlets(
215 id INTEGER PRIMARY KEY,
221 CREATE TABLE triggers(
222 id INTEGER PRIMARY KEY,
227 """ % DATABASE_FORMAT
)
228 # XXX add some indexes here
233 # If we have already the latest version, there is nothing to do.
234 if self
.format
== DATABASE_FORMAT
:
237 # Check if database version is supported.
238 if self
.format
> DATABASE_FORMAT
:
239 raise DatabaseError
, _("Cannot use database with version greater than %s.") % DATABASE_FORMAT
241 log
.info(_("Migrating database from format %(old)s to %(new)s.") % \
242 { "old" : self
.format
, "new" : DATABASE_FORMAT
})
244 # Get a database cursor.
247 # 1) The vendor column was added.
249 c
.execute("ALTER TABLE packages ADD COLUMN vendor TEXT AFTER uuid")
252 c
.execute("ALTER TABLE files ADD COLUMN `config` INTEGER")
253 c
.execute("ALTER TABLE files ADD COLUMN `mode` INTEGER")
254 c
.execute("ALTER TABLE files ADD COLUMN `user` TEXT")
255 c
.execute("ALTER TABLE files ADD COLUMN `group` TEXT")
256 c
.execute("ALTER TABLE files ADD COLUMN `mtime` INTEGER")
259 c
.execute("ALTER TABLE files ADD COLUMN `capabilities` TEXT")
262 c
.execute("ALTER TABLE packages ADD COLUMN recommends TEXT AFTER obsoletes")
263 c
.execute("ALTER TABLE packages ADD COLUMN suggests TEXT AFTER recommends")
266 c
.execute("ALTER TABLE files ADD COLUMN datafile INTEGER AFTER config")
269 c
.execute("ALTER TABLE packages ADD COLUMN inst_size INTEGER AFTER size")
271 # In the end, we can easily update the version of the database.
272 c
.execute("UPDATE settings SET val = ? WHERE key = 'version'", (DATABASE_FORMAT
,))
273 self
.__format
= DATABASE_FORMAT
278 def add_package(self
, pkg
, reason
=None):
279 log
.debug("Adding package to database: %s" % pkg
.friendly_name
)
285 INSERT INTO packages(
314 ) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
321 " ".join(pkg
.groups
),
326 "\n".join(pkg
.provides
),
327 "\n".join(pkg
.requires
),
328 "\n".join(pkg
.conflicts
),
329 "\n".join(pkg
.obsoletes
),
330 "\n".join(pkg
.recommends
),
331 "\n".join(pkg
.suggests
),
349 c
.executemany("INSERT INTO files(`name`, `pkg`, `size`, `config`, `datafile`, `type`, `hash1`, `mode`, `user`, `group`, `mtime`, `capabilities`)"
350 " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
351 ((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
))
361 def rem_package(self
, pkg
):
362 log
.debug("Removing package from database: %s" % pkg
.friendly_name
)
366 # Get the ID of the package in the database.
368 c
.execute("SELECT id FROM packages WHERE uuid = ? LIMIT 1", (pkg
.uuid
,))
369 #c.execute("SELECT id FROM packages WHERE name = ? AND epoch = ? AND version = ?"
370 # " AND release = ? LIMIT 1", (pkg.name, pkg.epoch, pkg.version, pkg.release,))
378 # First, delete all files from the database and then delete the pkg itself.
379 c
.execute("DELETE FROM files WHERE pkg = ?", (id,))
380 c
.execute("DELETE FROM packages WHERE id = ?", (id,))
385 def get_package_by_id(self
, id):
387 c
.execute("SELECT * FROM packages WHERE id = ?", (id,))
391 return packages
.DatabasePackage(self
.pakfire
, self
.repo
, self
, row
)
398 c
= self
.db
.execute("SELECT * FROM packages ORDER BY name")
400 for row
in c
.fetchall():
401 yield packages
.DatabasePackage(self
.pakfire
, self
.repo
, self
, row
)
405 def get_filelist(self
):
406 c
= self
.db
.execute("SELECT name FROM files")
408 return [r
["name"] for r
in c
.fetchall()]
410 def get_package_from_solv(self
, solv_pkg
):
413 c
= self
.db
.execute("SELECT * FROM packages WHERE uuid = ? LIMIT 1", (solv_pkg
.uuid
,))
420 return packages
.DatabasePackage(self
.pakfire
, self
.repo
, self
, row
)