]>
Commit | Line | Data |
---|---|---|
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 |