]> git.ipfire.org Git - people/ms/pakfire.git/blob - src/pakfire/packages/installed.py
Add scriptlets to the database and actually execute them.
[people/ms/pakfire.git] / src / pakfire / packages / installed.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 os
23
24 import pakfire.downloader
25 import pakfire.filelist
26
27 from base import Package
28 from file import BinaryPackage
29
30 import pakfire.util as util
31 from pakfire.constants import *
32
33 class DatabasePackage(Package):
34 type = "db"
35
36 def __init__(self, pakfire, repo, db, data):
37 Package.__init__(self, pakfire, repo)
38
39 self.db = db
40
41 self._data = {}
42 self._filelist = None
43
44 for key in data.keys():
45 self._data[key] = data[key]
46
47 def __repr__(self):
48 return "<%s %s>" % (self.__class__.__name__, self.friendly_name)
49
50 @property
51 def metadata(self):
52 return self._data
53
54 @property
55 def id(self):
56 id = self.metadata.get("id")
57 if not id:
58 id = 0
59
60 return id
61
62 @property
63 def name(self):
64 return self.metadata.get("name")
65
66 @property
67 def version(self):
68 return self.metadata.get("version")
69
70 @property
71 def release(self):
72 return self.metadata.get("release")
73
74 @property
75 def epoch(self):
76 epoch = self.metadata.get("epoch", 0)
77
78 return int(epoch)
79
80 @property
81 def arch(self):
82 return self.metadata.get("arch")
83
84 @property
85 def maintainer(self):
86 return self.metadata.get("maintainer")
87
88 @property
89 def license(self):
90 return self.metadata.get("license")
91
92 @property
93 def summary(self):
94 return self.metadata.get("summary")
95
96 @property
97 def description(self):
98 return self.metadata.get("description")
99
100 @property
101 def groups(self):
102 groups = self.metadata.get("groups", "")
103
104 if groups:
105 return groups.split()
106
107 return []
108
109 @property
110 def build_date(self):
111 return self.metadata.get("build_date")
112
113 @property
114 def build_time(self):
115 build_time = self.metadata.get("build_time", 0)
116
117 try:
118 return int(build_time)
119 except TypeError:
120 return 0
121
122 @property
123 def build_host(self):
124 return self.metadata.get("build_host")
125
126 @property
127 def build_id(self):
128 return self.metadata.get("build_id")
129
130 @property
131 def vendor(self):
132 return self.metadata.get("vendor")
133
134 @property
135 def uuid(self):
136 return self.metadata.get("uuid")
137
138 @property
139 def size(self):
140 return self.metadata.get("size", 0)
141
142 @property
143 def inst_size(self):
144 inst_size = self.metadata.get("inst_size", None)
145
146 # As install size has not always been saved in the database
147 # use the package size instead.
148 if inst_size is None:
149 return self.size
150
151 return inst_size
152
153 @property
154 def dependencies(self):
155 if not hasattr(self, "__dependencies"):
156 self.__dependencies = {}
157
158 c = self.db.cursor()
159 c.execute("SELECT type, dependency FROM dependencies WHERE pkg = ?", (self.id,))
160
161 for type, dependency in c.fetchall():
162 try:
163 self.__dependencies[type].append(dependency)
164 except KeyError:
165 self.__dependencies[type] = [dependency,]
166
167 return self.__dependencies
168
169 @property
170 def provides(self):
171 return self.dependencies.get("provides", [])
172
173 @property
174 def requires(self):
175 return self.dependencies.get("requires", [])
176
177 @property
178 def conflicts(self):
179 return self.dependencies.get("conflicts", [])
180
181 @property
182 def obsoletes(self):
183 return self.dependencies.get("obsoletes", [])
184
185 @property
186 def recommends(self):
187 return self.dependencies.get("recommends", [])
188
189 @property
190 def suggests(self):
191 return self.dependencies.get("suggests", [])
192
193 @property
194 def hash1(self):
195 return self.metadata.get("hash1")
196
197 @property
198 def scriptlet(self):
199 return self.metadata.get("scriptlet")
200
201 def get_scriptlet(self, action):
202 c = self.db.cursor()
203 c.execute("SELECT scriptlet FROM scriptlets WHERE pkg = ? AND action = ? LIMIT 1", (self.id, action,))
204
205 try:
206 row = c.fetchone()
207
208 # If no row was returned, no scriptlet for this action
209 # does exist.
210 if row:
211 return row["scriptlet"]
212
213 finally:
214 c.close()
215
216 @property
217 def filename(self):
218 return self.metadata.get("filename")
219
220 @property
221 def filelist(self):
222 if self._filelist is None:
223 self._filelist = []
224
225 c = self.db.cursor()
226 c.execute("SELECT * FROM files WHERE pkg = ?", (self.id,))
227
228 for row in c.fetchall():
229 file = pakfire.filelist.FileDatabase(self.pakfire, self.db, row["id"], row)
230 self._filelist.append(file)
231
232 return self._filelist
233
234 @property
235 def configfiles(self):
236 ret = []
237
238 for file in self.filelist:
239 if not file.is_config():
240 continue
241
242 ret.append(file)
243
244 return ret
245
246 @property
247 def datafiles(self):
248 ret = []
249
250 for file in self.filelist:
251 if not file.is_datafile():
252 continue
253
254 ret.append(file)
255
256 return ret
257
258 def _does_provide_file(self, requires):
259 """
260 A faster version to find a file in the database.
261 """
262 c = self.db.cursor()
263 c.execute("SELECT * FROM files WHERE name GLOB ? AND pkg = ?",
264 (requires.requires, self.id))
265
266 ret = False
267 for pkg in c:
268 ret = True
269 break
270
271 c.close()
272
273 return ret
274
275 def download(self, text=""):
276 """
277 Downloads the package from repository and returns a new instance
278 of BinaryPackage.
279 """
280
281 # XXX a bit hacky, but InstalledRepository has no cache.
282 if self.repo.name == "installed":
283 return self
284
285 # Marker, if we need to download the package.
286 download = True
287
288 # Add shortcut for cache.
289 cache = self.repo.cache
290
291 cache_filename = "packages/%s" % os.path.basename(self.filename)
292
293 # Check if file already exists in cache.
294 if cache.exists(cache_filename):
295 # If the file does already exist, we check if the hash1 matches.
296 if cache.verify(cache_filename, self.hash1):
297 # We already got the right file. Skip download.
298 download = False
299 else:
300 # The file in cache has a wrong hash. Remove it and repeat download.
301 cache.remove(cache_filename)
302
303 if download:
304 # Make sure filename is of type string (and not unicode)
305 filename = str(self.filename)
306
307 # Get a package grabber and add mirror download capabilities to it.
308 grabber = pakfire.downloader.PackageDownloader(
309 text=text + os.path.basename(filename),
310 )
311 grabber = self.repo.mirrors.group(grabber)
312
313 i = grabber.urlopen(filename)
314
315 # Open input and output files and download the file.
316 o = cache.open(cache_filename, "w")
317
318 buf = i.read(BUFFER_SIZE)
319 while buf:
320 o.write(buf)
321 buf = i.read(BUFFER_SIZE)
322
323 i.close()
324 o.close()
325
326 # Verify if the download was okay.
327 if not cache.verify(cache_filename, self.hash1):
328 raise Exception, "XXX this should never happen..."
329
330 filename = os.path.join(cache.path, cache_filename)
331 return BinaryPackage(self.pakfire, self.repo, filename)
332
333 def cleanup(self, message, prefix):
334 c = self.db.cursor()
335
336 # Get all files, that are in this package and check for all of
337 # them if they need to be removed.
338 files = self.filelist
339
340 # Fetch the whole filelist of the system from the database and create
341 # a diff. Exclude files from this package - of course.
342 c.execute("SELECT DISTINCT name FROM files WHERE pkg != ?", (self.id,))
343
344 installed_files = set()
345 for row in c:
346 installed_files.add(row["name"])
347 c.close()
348
349 # List with files to be removed.
350 remove_files = []
351
352 for f in files:
353 # Try to find the if an other package owns the file.
354 # Handles packages that move files from / to /usr.
355 try:
356 filename = os.path.abspath(f.name)
357 except OSError:
358 filename = f.name
359
360 if filename in installed_files:
361 continue
362
363 remove_files.append(f)
364
365 self._remove_files(remove_files, message, prefix)
366
367 @property
368 def signatures(self):
369 # Database packages do not have any signatures.
370 return []
371
372
373 # XXX maybe we can remove this later?
374 class InstalledPackage(DatabasePackage):
375 type = "installed"
376