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