]> git.ipfire.org Git - pakfire.git/blob - src/pakfire/packages/installed.py
6210c888748f30ab637629979b04ebde3c6775df
[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 @property
202 def filename(self):
203 return self.metadata.get("filename")
204
205 @property
206 def filelist(self):
207 if self._filelist is None:
208 self._filelist = []
209
210 c = self.db.cursor()
211 c.execute("SELECT * FROM files WHERE pkg = ?", (self.id,))
212
213 for row in c.fetchall():
214 file = pakfire.filelist.FileDatabase(self.pakfire, self.db, row["id"], row)
215 self._filelist.append(file)
216
217 return self._filelist
218
219 @property
220 def configfiles(self):
221 ret = []
222
223 for file in self.filelist:
224 if not file.is_config():
225 continue
226
227 ret.append(file)
228
229 return ret
230
231 @property
232 def datafiles(self):
233 ret = []
234
235 for file in self.filelist:
236 if not file.is_datafile():
237 continue
238
239 ret.append(file)
240
241 return ret
242
243 def _does_provide_file(self, requires):
244 """
245 A faster version to find a file in the database.
246 """
247 c = self.db.cursor()
248 c.execute("SELECT * FROM files WHERE name GLOB ? AND pkg = ?",
249 (requires.requires, self.id))
250
251 ret = False
252 for pkg in c:
253 ret = True
254 break
255
256 c.close()
257
258 return ret
259
260 def download(self, text=""):
261 """
262 Downloads the package from repository and returns a new instance
263 of BinaryPackage.
264 """
265
266 # XXX a bit hacky, but InstalledRepository has no cache.
267 if self.repo.name == "installed":
268 return self
269
270 # Marker, if we need to download the package.
271 download = True
272
273 # Add shortcut for cache.
274 cache = self.repo.cache
275
276 cache_filename = "packages/%s" % os.path.basename(self.filename)
277
278 # Check if file already exists in cache.
279 if cache.exists(cache_filename):
280 # If the file does already exist, we check if the hash1 matches.
281 if cache.verify(cache_filename, self.hash1):
282 # We already got the right file. Skip download.
283 download = False
284 else:
285 # The file in cache has a wrong hash. Remove it and repeat download.
286 cache.remove(cache_filename)
287
288 if download:
289 # Make sure filename is of type string (and not unicode)
290 filename = str(self.filename)
291
292 # Get a package grabber and add mirror download capabilities to it.
293 grabber = pakfire.downloader.PackageDownloader(
294 text=text + os.path.basename(filename),
295 )
296 grabber = self.repo.mirrors.group(grabber)
297
298 i = grabber.urlopen(filename)
299
300 # Open input and output files and download the file.
301 o = cache.open(cache_filename, "w")
302
303 buf = i.read(BUFFER_SIZE)
304 while buf:
305 o.write(buf)
306 buf = i.read(BUFFER_SIZE)
307
308 i.close()
309 o.close()
310
311 # Verify if the download was okay.
312 if not cache.verify(cache_filename, self.hash1):
313 raise Exception, "XXX this should never happen..."
314
315 filename = os.path.join(cache.path, cache_filename)
316 return BinaryPackage(self.pakfire, self.repo, filename)
317
318 def cleanup(self, message, prefix):
319 c = self.db.cursor()
320
321 # Get all files, that are in this package and check for all of
322 # them if they need to be removed.
323 files = self.filelist
324
325 # Fetch the whole filelist of the system from the database and create
326 # a diff. Exclude files from this package - of course.
327 c.execute("SELECT DISTINCT name FROM files WHERE pkg != ?", (self.id,))
328
329 installed_files = set()
330 for row in c:
331 installed_files.add(row["name"])
332 c.close()
333
334 # List with files to be removed.
335 remove_files = []
336
337 for f in files:
338 # Try to find the if an other package owns the file.
339 # Handles packages that move files from / to /usr.
340 try:
341 filename = os.path.abspath(f.name)
342 except OSError:
343 filename = f.name
344
345 if filename in installed_files:
346 continue
347
348 remove_files.append(f)
349
350 self._remove_files(remove_files, message, prefix)
351
352 @property
353 def signatures(self):
354 # Database packages do not have any signatures.
355 return []
356
357
358 # XXX maybe we can remove this later?
359 class InstalledPackage(DatabasePackage):
360 type = "installed"
361