]>
Commit | Line | Data |
---|---|---|
47a4cb89 | 1 | #!/usr/bin/python |
b792d887 MT |
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 | ############################################################################### | |
47a4cb89 | 21 | |
4f91860e MT |
22 | import os |
23 | ||
14ea3228 | 24 | import pakfire.downloader |
862bea4d | 25 | import pakfire.filelist |
14ea3228 | 26 | |
47a4cb89 | 27 | from base import Package |
e0636b31 | 28 | from file import BinaryPackage |
4f91860e | 29 | |
e871a081 | 30 | import pakfire.util as util |
4f91860e | 31 | from pakfire.constants import * |
47a4cb89 | 32 | |
fa6d335b MT |
33 | class DatabasePackage(Package): |
34 | type = "db" | |
47a4cb89 | 35 | |
4f91860e MT |
36 | def __init__(self, pakfire, repo, db, data): |
37 | Package.__init__(self, pakfire, repo) | |
3723913b | 38 | |
47a4cb89 MT |
39 | self.db = db |
40 | ||
41 | self._data = {} | |
9b68f47c | 42 | self._filelist = None |
47a4cb89 MT |
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 | |
8537c16d | 101 | def groups(self): |
e74f185d MT |
102 | groups = self.metadata.get("groups", "") |
103 | ||
104 | if groups: | |
105 | return groups.split() | |
106 | ||
107 | return [] | |
47a4cb89 MT |
108 | |
109 | @property | |
0c665250 MT |
110 | def build_date(self): |
111 | return self.metadata.get("build_date") | |
112 | ||
113 | @property | |
114 | def build_time(self): | |
b566f7e3 MT |
115 | build_time = self.metadata.get("build_time", 0) |
116 | ||
6b151a68 MT |
117 | try: |
118 | return int(build_time) | |
119 | except TypeError: | |
120 | return 0 | |
47a4cb89 MT |
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 | ||
85a1120f MT |
130 | @property |
131 | def vendor(self): | |
132 | return self.metadata.get("vendor") | |
133 | ||
1317485d MT |
134 | @property |
135 | def uuid(self): | |
136 | return self.metadata.get("uuid") | |
137 | ||
e399ad3a MT |
138 | @property |
139 | def size(self): | |
a5f5fced | 140 | return self.metadata.get("size", 0) |
e399ad3a | 141 | |
0304200a MT |
142 | @property |
143 | def inst_size(self): | |
ba5dc639 MT |
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 | |
0304200a | 152 | |
87da3448 MT |
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 | ||
47a4cb89 MT |
169 | @property |
170 | def provides(self): | |
87da3448 | 171 | return self.dependencies.get("provides", []) |
47a4cb89 MT |
172 | |
173 | @property | |
174 | def requires(self): | |
87da3448 | 175 | return self.dependencies.get("requires", []) |
47a4cb89 MT |
176 | |
177 | @property | |
178 | def conflicts(self): | |
87da3448 | 179 | return self.dependencies.get("conflicts", []) |
ae20b05f MT |
180 | |
181 | @property | |
182 | def obsoletes(self): | |
87da3448 | 183 | return self.dependencies.get("obsoletes", []) |
47a4cb89 | 184 | |
a60f0f7d MT |
185 | @property |
186 | def recommends(self): | |
87da3448 | 187 | return self.dependencies.get("recommends", []) |
a60f0f7d MT |
188 | |
189 | @property | |
190 | def suggests(self): | |
87da3448 | 191 | return self.dependencies.get("suggests", []) |
a60f0f7d | 192 | |
4f91860e MT |
193 | @property |
194 | def hash1(self): | |
195 | return self.metadata.get("hash1") | |
196 | ||
a5f5fced MT |
197 | @property |
198 | def scriptlet(self): | |
199 | return self.metadata.get("scriptlet") | |
200 | ||
4f91860e MT |
201 | @property |
202 | def filename(self): | |
9b68f47c | 203 | return self.metadata.get("filename") |
4f91860e | 204 | |
47a4cb89 MT |
205 | @property |
206 | def filelist(self): | |
9b68f47c MT |
207 | if self._filelist is None: |
208 | self._filelist = [] | |
862bea4d | 209 | |
9b68f47c MT |
210 | c = self.db.cursor() |
211 | c.execute("SELECT * FROM files WHERE pkg = ?", (self.id,)) | |
862bea4d | 212 | |
9b68f47c MT |
213 | for row in c.fetchall(): |
214 | file = pakfire.filelist.FileDatabase(self.pakfire, self.db, row["id"], row) | |
215 | self._filelist.append(file) | |
47a4cb89 | 216 | |
9b68f47c | 217 | return self._filelist |
47a4cb89 | 218 | |
6ee3d6b9 MT |
219 | @property |
220 | def configfiles(self): | |
482d1ada MT |
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 | |
6ee3d6b9 | 230 | |
3c5a85f3 MT |
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 | ||
a88d2cdc MT |
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() | |
311ce792 | 248 | c.execute("SELECT * FROM files WHERE name GLOB ? AND pkg = ?", |
a2d1644c | 249 | (requires.requires, self.id)) |
a88d2cdc MT |
250 | |
251 | ret = False | |
252 | for pkg in c: | |
a2d1644c MT |
253 | ret = True |
254 | break | |
a88d2cdc MT |
255 | |
256 | c.close() | |
257 | ||
258 | return ret | |
259 | ||
14ea3228 | 260 | def download(self, text=""): |
4f91860e MT |
261 | """ |
262 | Downloads the package from repository and returns a new instance | |
263 | of BinaryPackage. | |
264 | """ | |
d4c94aa5 MT |
265 | |
266 | # XXX a bit hacky, but InstalledRepository has no cache. | |
267 | if self.repo.name == "installed": | |
268 | return self | |
269 | ||
4f91860e MT |
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: | |
4f91860e MT |
289 | # Make sure filename is of type string (and not unicode) |
290 | filename = str(self.filename) | |
291 | ||
14ea3228 MT |
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") | |
4f91860e MT |
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) | |
fa6d335b | 317 | |
e871a081 MT |
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. | |
9999260a | 327 | c.execute("SELECT DISTINCT name FROM files WHERE pkg != ?", (self.id,)) |
e871a081 | 328 | |
9999260a | 329 | installed_files = set() |
e871a081 | 330 | for row in c: |
9999260a | 331 | installed_files.add(row["name"]) |
e871a081 MT |
332 | c.close() |
333 | ||
9999260a MT |
334 | # List with files to be removed. |
335 | remove_files = [] | |
336 | ||
337 | for f in files: | |
eb93662e MT |
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: | |
9999260a MT |
346 | continue |
347 | ||
348 | remove_files.append(f) | |
349 | ||
350 | self._remove_files(remove_files, message, prefix) | |
e871a081 | 351 | |
0f8d6745 MT |
352 | @property |
353 | def signatures(self): | |
354 | # Database packages do not have any signatures. | |
355 | return [] | |
356 | ||
e871a081 | 357 | |
fa6d335b MT |
358 | # XXX maybe we can remove this later? |
359 | class InstalledPackage(DatabasePackage): | |
360 | type = "installed" | |
361 |