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