]> git.ipfire.org Git - people/stevee/pakfire.git/blob - python/pakfire/repository/database.py
Merge branch 'master' of ssh://git.ipfire.org/pub/git/oddments/pakfire
[people/stevee/pakfire.git] / python / pakfire / repository / database.py
1 #!/usr/bin/python
2 ###############################################################################
3 # #
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
6 # #
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. #
11 # #
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. #
16 # #
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/>. #
19 # #
20 ###############################################################################
21
22 import logging
23 import os
24 import random
25 import shutil
26 import sqlite3
27 import time
28
29 import pakfire.packages as packages
30
31 from pakfire.constants import *
32
33 class Cursor(sqlite3.Cursor):
34 def execute(self, *args, **kwargs):
35 # For debugging of SQL queries.
36 #print args, kwargs
37
38 return sqlite3.Cursor.execute(self, *args, **kwargs)
39
40
41 class Database(object):
42 def __init__(self, pakfire, filename):
43 self.pakfire = pakfire
44 self.filename = filename
45
46 self._db = None
47
48 def __del__(self):
49 if self._db:
50 self._db.close()
51 self._db = None
52
53 def create(self):
54 pass
55
56 def open(self):
57 if self._db is None:
58 logging.debug("Open database %s" % self.filename)
59
60 dirname = os.path.dirname(self.filename)
61 if not os.path.exists(dirname):
62 os.makedirs(dirname)
63
64 database_exists = os.path.exists(self.filename)
65
66 # Make a connection to the database.
67 self._db = sqlite3.connect(self.filename)
68 self._db.row_factory = sqlite3.Row
69
70 # Create the database if it was not there, yet.
71 if not database_exists:
72 self.create()
73
74 def close(self):
75 self.__del__()
76
77 def commit(self):
78 self.open()
79 self._db.commit()
80
81 def cursor(self):
82 self.open()
83 return self._db.cursor(Cursor)
84
85 def executescript(self, *args, **kwargs):
86 self.open()
87 return self._db.executescript(*args, **kwargs)
88
89
90 class DatabaseLocal(Database):
91 def __init__(self, pakfire, repo):
92 self.repo = repo
93
94 # Generate filename for package database
95 filename = os.path.join(pakfire.path, PACKAGES_DB)
96
97 Database.__init__(self, pakfire, filename)
98
99 def __len__(self):
100 count = 0
101
102 c = self.cursor()
103 c.execute("SELECT COUNT(*) AS count FROM packages")
104 for row in c:
105 count = row["count"]
106 c.close()
107
108 return count
109
110 def create(self):
111 c = self.cursor()
112 c.executescript("""
113 CREATE TABLE settings(
114 key TEXT,
115 val TEXT
116 );
117 INSERT INTO settings(key, val) VALUES('version', '0');
118
119 CREATE TABLE files(
120 name TEXT,
121 pkg INTEGER,
122 size INTEGER,
123 type INTEGER,
124 hash1 TEXT
125 );
126
127 CREATE TABLE packages(
128 id INTEGER PRIMARY KEY,
129 name TEXT,
130 epoch INTEGER,
131 version TEXT,
132 release TEXT,
133 arch TEXT,
134 groups TEXT,
135 filename TEXT,
136 size INTEGER,
137 hash1 TEXT,
138 provides TEXT,
139 requires TEXT,
140 conflicts TEXT,
141 obsoletes TEXT,
142 license TEXT,
143 summary TEXT,
144 description TEXT,
145 uuid TEXT,
146 build_id TEXT,
147 build_host TEXT,
148 build_date TEXT,
149 build_time INTEGER,
150 installed INT,
151 reason TEXT,
152 repository TEXT
153 );
154
155 CREATE TABLE scriptlets(
156 id INTEGER PRIMARY KEY,
157 pkg INTEGER,
158 action TEXT,
159 scriptlet TEXT
160 );
161
162 CREATE TABLE triggers(
163 id INTEGER PRIMARY KEY,
164 pkg INTEGER,
165 dependency TEXT,
166 scriptlet TEXT
167 );
168 """)
169 # XXX add some indexes here
170 self.commit()
171 c.close()
172
173 def add_package(self, pkg, reason=None):
174 logging.debug("Adding package to database: %s" % pkg.friendly_name)
175
176 c = self.cursor()
177
178 try:
179 c.execute("""
180 INSERT INTO packages(
181 name,
182 epoch,
183 version,
184 release,
185 arch,
186 groups,
187 filename,
188 size,
189 hash1,
190 provides,
191 requires,
192 conflicts,
193 obsoletes,
194 license,
195 summary,
196 description,
197 uuid,
198 build_id,
199 build_host,
200 build_date,
201 build_time,
202 installed,
203 repository,
204 reason
205 ) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
206 (
207 pkg.name,
208 pkg.epoch,
209 pkg.version,
210 pkg.release,
211 pkg.arch,
212 " ".join(pkg.groups),
213 pkg.filename,
214 pkg.size,
215 pkg.hash1,
216 " ".join(pkg.provides),
217 " ".join(pkg.requires),
218 " ".join(pkg.conflicts),
219 " ".join(pkg.obsoletes),
220 pkg.license,
221 pkg.summary,
222 pkg.description,
223 pkg.uuid,
224 pkg.build_id,
225 pkg.build_host,
226 pkg.build_date,
227 pkg.build_time,
228 time.time(),
229 pkg.repo.name,
230 reason or "",
231 )
232 )
233
234 pkg_id = c.lastrowid
235
236 c.executemany("INSERT INTO files(name, pkg) VALUES(?, ?)",
237 ((file, pkg_id) for file in pkg.filelist))
238
239 except:
240 raise
241
242 else:
243 self.commit()
244
245 c.close()
246
247 def rem_package(self, pkg):
248 logging.debug("Removing package from database: %s" % pkg.friendly_name)
249
250 assert pkg.uuid
251
252 # Get the ID of the package in the database.
253 c = self.cursor()
254 c.execute("SELECT id FROM packages WHERE uuid = ? LIMIT 1", (pkg.uuid,))
255
256 id = None
257 for row in c:
258 id = row["id"]
259 break
260 assert id
261
262 # First, delete all files from the database and then delete the pkg itself.
263 c.execute("DELETE FROM files WHERE pkg = ?", (id,))
264 c.execute("DELETE FROM packages WHERE id = ?", (id,))
265
266 c.close()
267 self.commit()
268
269 @property
270 def packages(self):
271 c = self.cursor()
272
273 c.execute("SELECT * FROM packages ORDER BY name")
274
275 for row in c:
276 yield packages.DatabasePackage(self.pakfire, self.repo, self, row)
277
278 c.close()
279
280 def get_package_from_solv(self, solv_pkg):
281 c = self.cursor()
282 c.execute("SELECT * FROM packages WHERE uuid = ? LIMIT 1", (solv_pkg.uuid,))
283
284 try:
285 for row in c:
286 return packages.DatabasePackage(self.pakfire, self.repo, self, row)
287
288 finally:
289 c.close()