]> git.ipfire.org Git - pakfire.git/blame - pakfire/repository/database.py
Remove database if it is equal to an existing one.
[pakfire.git] / pakfire / repository / database.py
CommitLineData
47a4cb89
MT
1#!/usr/bin/python
2
3import logging
4import os
5cc35aa4 5import random
2568a6d1 6import shutil
47a4cb89 7import sqlite3
66af936c 8import time
47a4cb89 9
a2d1644c 10from pakfire.constants import *
66af936c 11
b6da0663
MT
12class Cursor(sqlite3.Cursor):
13 def execute(self, *args, **kwargs):
14 # For debugging of SQL queries.
15 #print args, kwargs
16
17 return sqlite3.Cursor.execute(self, *args, **kwargs)
18
19
47a4cb89 20class Database(object):
3723913b
MT
21 def __init__(self, pakfire, filename):
22 self.pakfire = pakfire
47a4cb89
MT
23 self._db = None
24
5cc35aa4
MT
25 self._tmp = False
26
27 if filename == ":memory:":
28 self._tmp = True
29
86973935 30 filename = "/tmp/.%s-db" % random.randint(0, 1024**2)
5cc35aa4
MT
31
32 self.filename = filename
33
47a4cb89
MT
34 self.open()
35
36 def __del__(self):
37 if self._db:
fa6d335b 38 #self._db.commit()
47a4cb89
MT
39 self._db.close()
40
41 def create(self):
42 pass
43
44 def open(self):
45 if not self._db:
46 logging.debug("Open database %s" % self.filename)
47
5cc35aa4
MT
48 dirname = os.path.dirname(self.filename)
49 if not os.path.exists(dirname):
50 os.makedirs(dirname)
47a4cb89 51
5cc35aa4 52 database_exists = os.path.exists(self.filename)
47a4cb89
MT
53
54 # Make a connection to the database.
55 self._db = sqlite3.connect(self.filename)
56 self._db.row_factory = sqlite3.Row
57
58 # Create the database if it was not there, yet.
59 if not database_exists:
60 self.create()
61
62 def close(self):
63 self._db.close()
2568a6d1 64 self._db = None
47a4cb89 65
5cc35aa4
MT
66 if self._tmp:
67 os.unlink(self.filename)
68
47a4cb89
MT
69 def commit(self):
70 self._db.commit()
71
72 def cursor(self):
b6da0663 73 return self._db.cursor(Cursor)
47a4cb89 74
a2d1644c
MT
75 def executescript(self, *args, **kwargs):
76 return self._db.executescript(*args, **kwargs)
77
2568a6d1
MT
78 def save(self, path):
79 """
a2d1644c 80 Save a copy of this database to a new one located at path.
2568a6d1 81 """
5cc35aa4 82 self.commit()
2568a6d1 83
5cc35aa4 84 shutil.copy2(self.filename, path)
2568a6d1 85
47a4cb89 86
fa6d335b 87class PackageDatabase(Database):
47a4cb89
MT
88 def create(self):
89 c = self.cursor()
90
91 c.executescript("""
92 CREATE TABLE files(
93 name TEXT,
94 pkg INTEGER,
95 size INTEGER,
96 type INTEGER,
66af936c 97 hash1 TEXT
47a4cb89
MT
98 );
99
100 CREATE TABLE packages(
101 id INTEGER PRIMARY KEY,
102 name TEXT,
103 epoch INTEGER,
104 version TEXT,
105 release TEXT,
c560c27a 106 arch TEXT,
fa6d335b 107 filename TEXT,
ba8c383d 108 size INTEGER,
47a4cb89
MT
109 hash1 TEXT,
110 provides TEXT,
111 requires TEXT,
112 conflicts TEXT,
113 obsoletes TEXT,
114 license TEXT,
115 summary TEXT,
116 description TEXT,
1317485d 117 uuid TEXT,
47a4cb89
MT
118 build_id TEXT,
119 build_host TEXT,
ba8c383d 120 build_date INTEGER
47a4cb89
MT
121 );
122 """)
123 # XXX add some indexes here
124
125 self.commit()
126 c.close()
127
128 def list_packages(self):
129 c = self.cursor()
130 c.execute("SELECT DISTINCT name FROM packages ORDER BY name")
131
132 for pkg in c:
133 yield pkg["name"]
134
135 c.close()
136
fa6d335b
MT
137 def package_exists(self, pkg):
138 return not self.get_id_by_pkg(pkg) is None
139
140 def get_id_by_pkg(self, pkg):
141 c = self.cursor()
142
143 c.execute("SELECT id FROM packages WHERE name = ? AND version = ? AND \
144 release = ? AND epoch = ? LIMIT 1", (pkg.name, pkg.version, pkg.release, pkg.epoch))
145
146 ret = None
147 for i in c:
148 ret = i["id"]
149 break
66af936c 150
fa6d335b
MT
151 c.close()
152
153 return ret
154
155 def add_package(self, pkg):
66af936c
MT
156 raise NotImplementedError
157
158
159class RemotePackageDatabase(PackageDatabase):
160 def add_package(self, pkg, reason=None):
fa6d335b
MT
161 if self.package_exists(pkg):
162 logging.debug("Skipping package which already exists in database: %s" % pkg.friendly_name)
163 return
164
165 logging.debug("Adding package to database: %s" % pkg.friendly_name)
166
66af936c
MT
167 filename = ""
168 if pkg.repo.local:
ab86bec4
MT
169 # Get the path relatively to the repository.
170 filename = pkg.filename[len(pkg.repo.path):]
171 # Strip leading / if any.
172 if filename.startswith("/"):
173 filename = filename[1:]
66af936c 174
fa6d335b
MT
175 c = self.cursor()
176 c.execute("""
177 INSERT INTO packages(
178 name,
179 epoch,
180 version,
181 release,
c560c27a 182 arch,
fa6d335b 183 filename,
e399ad3a 184 size,
66af936c 185 hash1,
fa6d335b 186 provides,
66af936c
MT
187 requires,
188 conflicts,
189 obsoletes,
190 license,
191 summary,
192 description,
1317485d 193 uuid,
66af936c
MT
194 build_id,
195 build_host,
196 build_date
1317485d 197 ) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
fa6d335b
MT
198 (
199 pkg.name,
200 pkg.epoch,
201 pkg.version,
202 pkg.release,
c560c27a 203 pkg.arch,
66af936c 204 filename,
e399ad3a 205 pkg.size,
66af936c 206 pkg.hash1,
fa6d335b
MT
207 " ".join(pkg.provides),
208 " ".join(pkg.requires),
66af936c
MT
209 " ".join(pkg.conflicts),
210 " ".join(pkg.obsoletes),
211 pkg.license,
212 pkg.summary,
213 pkg.description,
1317485d 214 pkg.uuid,
66af936c
MT
215 pkg.build_id,
216 pkg.build_host,
217 pkg.build_date
fa6d335b
MT
218 )
219 )
fa6d335b 220 self.commit()
66af936c 221 c.close()
fa6d335b
MT
222
223 pkg_id = self.get_id_by_pkg(pkg)
224
225 c = self.cursor()
226 for file in pkg.filelist:
227 c.execute("INSERT INTO files(name, pkg) VALUES(?, ?)", (file, pkg_id))
228
66af936c 229 self.commit()
fa6d335b 230 c.close()
66af936c
MT
231
232 return pkg_id
233
234
235class LocalPackageDatabase(RemotePackageDatabase):
236 def __init__(self, pakfire):
237 # Generate filename for package database
238 filename = os.path.join(pakfire.path, PACKAGES_DB)
239
240 RemotePackageDatabase.__init__(self, pakfire, filename)
241
242 def create(self):
243 RemotePackageDatabase.create(self)
244
245 # Alter the database layout to store additional local information.
246 logging.debug("Altering database table for local information.")
247 c = self.cursor()
248 c.executescript("""
249 ALTER TABLE packages ADD COLUMN installed INT;
250 ALTER TABLE packages ADD COLUMN reason TEXT;
251 ALTER TABLE packages ADD COLUMN repository TEXT;
a5f5fced 252 ALTER TABLE packages ADD COLUMN scriptlet TEXT;
9c75e8ed 253 ALTER TABLE packages ADD COLUMN triggers TEXT;
66af936c 254 """)
fa6d335b 255 self.commit()
66af936c 256 c.close()
fa6d335b 257
66af936c
MT
258 def add_package(self, pkg, reason=None):
259 # Insert all the information to the database we have in the remote database
260 pkg_id = RemotePackageDatabase.add_package(self, pkg)
fa6d335b 261
66af936c 262 # then: add some more information
47a4cb89
MT
263 c = self.cursor()
264
66af936c
MT
265 # Save timestamp when the package was installed.
266 c.execute("UPDATE packages SET installed = ? WHERE id = ?", (time.time(), pkg_id))
47a4cb89 267
66af936c
MT
268 # Add repository information.
269 c.execute("UPDATE packages SET repository = ? WHERE id = ?", (pkg.repo.name, pkg_id))
47a4cb89 270
66af936c
MT
271 # Save reason of installation (if any).
272 if reason:
273 c.execute("UPDATE packages SET reason = ? WHERE id = ?", (reason, pkg_id))
47a4cb89 274
66af936c
MT
275 # Update the filename information.
276 c.execute("UPDATE packages SET filename = ? WHERE id = ?", (pkg.filename, pkg_id))
47a4cb89 277
a5f5fced
MT
278 # Add the scriptlet to database (needed to update or uninstall packages).
279 c.execute("UPDATE packages SET scriptlet = ? WHERE id = ?", (pkg.scriptlet, pkg_id))
280
9c75e8ed
MT
281 # Add triggers to the database.
282 triggers = " ".join(pkg.triggers)
283 c.execute("UPDATE packages SET triggers = ? WHERE id = ?", (triggers, pkg_id))
284
66af936c
MT
285 self.commit()
286 c.close()