]> git.ipfire.org Git - pakfire.git/blob - pakfire/database.py
Improve repository handling.
[pakfire.git] / pakfire / database.py
1 #!/usr/bin/python
2
3 import logging
4 import os
5 import sqlite3
6 import time
7
8 import packages
9
10 from constants import *
11
12 class Database(object):
13 def __init__(self, pakfire, filename):
14 self.pakfire = pakfire
15 self.filename = filename
16 self._db = None
17
18 self.open()
19
20 def __del__(self):
21 if self._db:
22 #self._db.commit()
23 self._db.close()
24
25 def create(self):
26 pass
27
28 def open(self):
29 if not self._db:
30 logging.debug("Open database %s" % self.filename)
31
32 dirname = os.path.dirname(self.filename)
33 if not os.path.exists(dirname):
34 os.makedirs(dirname)
35
36 database_exists = os.path.exists(self.filename)
37
38 # Make a connection to the database.
39 self._db = sqlite3.connect(self.filename)
40 self._db.row_factory = sqlite3.Row
41
42 # Create the database if it was not there, yet.
43 if not database_exists:
44 self.create()
45
46 def close(self):
47 self._db.close()
48
49 def commit(self):
50 self._db.commit()
51
52 def cursor(self):
53 return self._db.cursor()
54
55
56 class PackageDatabase(Database):
57 def create(self):
58 c = self.cursor()
59
60 c.executescript("""
61 CREATE TABLE files(
62 name TEXT,
63 pkg INTEGER,
64 size INTEGER,
65 type INTEGER,
66 hash1 TEXT
67 );
68
69 CREATE TABLE packages(
70 id INTEGER PRIMARY KEY,
71 name TEXT,
72 epoch INTEGER,
73 version TEXT,
74 release TEXT,
75 filename TEXT,
76 hash1 TEXT,
77 provides TEXT,
78 requires TEXT,
79 conflicts TEXT,
80 obsoletes TEXT,
81 license TEXT,
82 summary TEXT,
83 description TEXT,
84 build_id TEXT,
85 build_host TEXT,
86 build_date INT
87 );
88 """)
89 # XXX add some indexes here
90
91 self.commit()
92 c.close()
93
94 def list_packages(self):
95 c = self.cursor()
96 c.execute("SELECT DISTINCT name FROM packages ORDER BY name")
97
98 for pkg in c:
99 yield pkg["name"]
100
101 c.close()
102
103 def package_exists(self, pkg):
104 return not self.get_id_by_pkg(pkg) is None
105
106 def get_id_by_pkg(self, pkg):
107 c = self.cursor()
108
109 c.execute("SELECT id FROM packages WHERE name = ? AND version = ? AND \
110 release = ? AND epoch = ? LIMIT 1", (pkg.name, pkg.version, pkg.release, pkg.epoch))
111
112 ret = None
113 for i in c:
114 ret = i["id"]
115 break
116
117 c.close()
118
119 return ret
120
121 def add_package(self, pkg):
122 raise NotImplementedError
123
124
125 class RemotePackageDatabase(PackageDatabase):
126 def add_package(self, pkg, reason=None):
127 if self.package_exists(pkg):
128 logging.debug("Skipping package which already exists in database: %s" % pkg.friendly_name)
129 return
130
131 logging.debug("Adding package to database: %s" % pkg.friendly_name)
132
133 filename = ""
134 if pkg.repo.local:
135 filename = pkg.filename[len(pkg.repo.path) + 1:]
136
137 c = self.cursor()
138 c.execute("""
139 INSERT INTO packages(
140 name,
141 epoch,
142 version,
143 release,
144 filename,
145 hash1,
146 provides,
147 requires,
148 conflicts,
149 obsoletes,
150 license,
151 summary,
152 description,
153 build_id,
154 build_host,
155 build_date
156 ) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
157 (
158 pkg.name,
159 pkg.epoch,
160 pkg.version,
161 pkg.release,
162 filename,
163 pkg.hash1,
164 " ".join(pkg.provides),
165 " ".join(pkg.requires),
166 " ".join(pkg.conflicts),
167 " ".join(pkg.obsoletes),
168 pkg.license,
169 pkg.summary,
170 pkg.description,
171 pkg.build_id,
172 pkg.build_host,
173 pkg.build_date
174 )
175 )
176 self.commit()
177 c.close()
178
179 pkg_id = self.get_id_by_pkg(pkg)
180
181 c = self.cursor()
182 for file in pkg.filelist:
183 c.execute("INSERT INTO files(name, pkg) VALUES(?, ?)", (file, pkg_id))
184
185 self.commit()
186 c.close()
187
188 return pkg_id
189
190
191 class LocalPackageDatabase(RemotePackageDatabase):
192 def __init__(self, pakfire):
193 # Generate filename for package database
194 filename = os.path.join(pakfire.path, PACKAGES_DB)
195
196 RemotePackageDatabase.__init__(self, pakfire, filename)
197
198 def create(self):
199 RemotePackageDatabase.create(self)
200
201 # Alter the database layout to store additional local information.
202 logging.debug("Altering database table for local information.")
203 c = self.cursor()
204 c.executescript("""
205 ALTER TABLE packages ADD COLUMN installed INT;
206 ALTER TABLE packages ADD COLUMN reason TEXT;
207 ALTER TABLE packages ADD COLUMN repository TEXT;
208 """)
209 self.commit()
210 c.close()
211
212 def add_package(self, pkg, reason=None):
213 # Insert all the information to the database we have in the remote database
214 pkg_id = RemotePackageDatabase.add_package(self, pkg)
215
216 # then: add some more information
217 c = self.cursor()
218
219 # Save timestamp when the package was installed.
220 c.execute("UPDATE packages SET installed = ? WHERE id = ?", (time.time(), pkg_id))
221
222 # Add repository information.
223 c.execute("UPDATE packages SET repository = ? WHERE id = ?", (pkg.repo.name, pkg_id))
224
225 # Save reason of installation (if any).
226 if reason:
227 c.execute("UPDATE packages SET reason = ? WHERE id = ?", (reason, pkg_id))
228
229 # Update the filename information.
230 c.execute("UPDATE packages SET filename = ? WHERE id = ?", (pkg.filename, pkg_id))
231
232 self.commit()
233 c.close()