]>
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 | |
c07a3ca7 | 22 | import logging |
47a4cb89 | 23 | import os |
5dda54e4 | 24 | import re |
c07a3ca7 MT |
25 | import shutil |
26 | import socket | |
47a4cb89 MT |
27 | import tarfile |
28 | ||
29 | from urlgrabber.grabber import URLGrabber, URLGrabError | |
30 | from urlgrabber.progress import TextMeter | |
31 | ||
c07a3ca7 | 32 | import lexer |
47a4cb89 MT |
33 | import packager |
34 | ||
5dda54e4 | 35 | import pakfire.chroot as chroot |
c07a3ca7 MT |
36 | import pakfire.util as util |
37 | ||
47a4cb89 | 38 | from base import Package |
e0636b31 MT |
39 | from file import SourcePackage |
40 | ||
47a4cb89 | 41 | from pakfire.constants import * |
c07a3ca7 | 42 | from pakfire.i18n import _ |
47a4cb89 | 43 | |
c07a3ca7 | 44 | # XXX to be moved to pakfire.downloader |
47a4cb89 | 45 | class SourceDownloader(object): |
c07a3ca7 | 46 | def __init__(self, pakfire, mirrors=None): |
47a4cb89 | 47 | self.pakfire = pakfire |
c07a3ca7 | 48 | self.mirrors = mirrors |
47a4cb89 | 49 | |
80104a80 | 50 | # XXX need to use downloader.py |
47a4cb89 MT |
51 | self.grabber = URLGrabber( |
52 | prefix = self.pakfire.config.get("source_download_url"), | |
53 | progress_obj = TextMeter(), | |
54 | quote = 0, | |
55 | ) | |
56 | ||
57 | def download(self, filename): | |
58 | filename = os.path.join(SOURCE_CACHE_DIR, filename) | |
59 | ||
60 | if os.path.exists(filename): | |
61 | return filename | |
62 | ||
63 | dirname = os.path.dirname(filename) | |
64 | if not os.path.exists(dirname): | |
65 | os.makedirs(dirname) | |
66 | ||
67 | try: | |
68 | self.grabber.urlgrab(os.path.basename(filename), filename=filename) | |
69 | except URLGrabError, e: | |
70 | raise DownloadError, "%s %s" % (os.path.basename(filename), e) | |
71 | ||
72 | return filename | |
73 | ||
74 | ||
c07a3ca7 | 75 | class MakefileBase(Package): |
3723913b | 76 | def __init__(self, pakfire, filename): |
a2d1644c | 77 | Package.__init__(self, pakfire) |
47a4cb89 | 78 | |
c07a3ca7 MT |
79 | # Save the filename of the makefile. |
80 | self.filename = os.path.abspath(filename) | |
47a4cb89 | 81 | |
c07a3ca7 | 82 | # Open and parse the makefile. |
c07a3ca7 MT |
83 | self.lexer = lexer.RootLexer.open(self.filename, |
84 | environ=self.pakfire.environ) | |
47a4cb89 MT |
85 | |
86 | @property | |
87 | def package_filename(self): | |
88 | return PACKAGE_FILENAME_FMT % { | |
89 | "arch" : self.arch, | |
90 | "ext" : PACKAGE_EXTENSION, | |
91 | "name" : self.name, | |
92 | "release" : self.release, | |
93 | "version" : self.version, | |
94 | } | |
95 | ||
c07a3ca7 MT |
96 | def lint(self): |
97 | errors = [] | |
98 | ||
99 | if not self.name: | |
100 | errors.append(_("Package name is undefined.")) | |
101 | ||
102 | if not self.version: | |
103 | errors.append(_("Package version is undefined.")) | |
104 | ||
105 | # XXX to do... | |
106 | ||
107 | return errors | |
108 | ||
109 | @property | |
110 | def name(self): | |
111 | return self.lexer.get_var("name") | |
112 | ||
113 | @property | |
114 | def epoch(self): | |
115 | epoch = self.lexer.get_var("epoch") | |
116 | if not epoch: | |
117 | return 0 | |
118 | ||
119 | return int(epoch) | |
120 | ||
121 | @property | |
122 | def version(self): | |
123 | return self.lexer.get_var("version") | |
124 | ||
125 | @property | |
126 | def release(self): | |
127 | release = self.lexer.get_var("release") | |
128 | assert release | |
129 | ||
130 | tag = self.lexer.get_var("DISTRO_DISTTAG") | |
131 | assert tag | |
132 | ||
133 | return ".".join((release, tag)) | |
134 | ||
135 | @property | |
136 | def summary(self): | |
137 | return self.lexer.get_var("summary") | |
138 | ||
139 | @property | |
140 | def description(self): | |
c4c528f7 MT |
141 | description = self.lexer.get_var("description") |
142 | ||
143 | # Replace all backslashes at the end of a line. | |
144 | return description.replace("\\\n", "\n") | |
c07a3ca7 MT |
145 | |
146 | @property | |
147 | def groups(self): | |
148 | groups = self.lexer.get_var("groups").split() | |
149 | ||
150 | return sorted(groups) | |
151 | ||
152 | @property | |
153 | def url(self): | |
154 | return self.lexer.get_var("url") | |
155 | ||
156 | @property | |
157 | def license(self): | |
158 | return self.lexer.get_var("license") | |
159 | ||
160 | @property | |
161 | def maintainer(self): | |
162 | maintainer = self.lexer.get_var("maintainer") | |
163 | ||
164 | if not maintainer: | |
165 | maintainer = self.lexer.get_var("DISTRO_MAINTAINER") | |
166 | ||
167 | return maintainer | |
168 | ||
169 | @property | |
170 | def vendor(self): | |
171 | return self.lexer.get_var("DISTRO_VENDOR") | |
172 | ||
0d96815e MT |
173 | @property |
174 | def buildroot(self): | |
175 | return self.lexer.get_var("BUILDROOT") | |
176 | ||
c07a3ca7 MT |
177 | @property |
178 | def build_host(self): | |
179 | return socket.gethostname() | |
180 | ||
181 | # XXX build_id and build_time are used to create a source package | |
182 | ||
183 | @property | |
184 | def build_id(self): | |
185 | # XXX todo | |
186 | # Not existant for Makefiles | |
187 | return None | |
188 | ||
189 | @property | |
190 | def build_time(self): | |
191 | # XXX todo | |
192 | # Not existant for Makefiles | |
193 | return None | |
194 | ||
195 | ||
196 | class Makefile(MakefileBase): | |
197 | @property | |
198 | def uuid(self): | |
199 | hash1 = util.calc_hash1(self.filename) | |
200 | ||
201 | # Return UUID version 5 (SHA1 hash) | |
202 | return "%8s-%4s-5%3s-%4s-%11s" % \ | |
203 | (hash1[0:8], hash1[9:13], hash1[14:17], hash1[18:22], hash1[23:34]) | |
204 | ||
205 | @property | |
206 | def path(self): | |
207 | return os.path.dirname(self.filename) | |
208 | ||
47a4cb89 MT |
209 | @property |
210 | def arch(self): | |
211 | """ | |
212 | This is only used to create the name of the source package. | |
213 | """ | |
214 | return "src" | |
215 | ||
c07a3ca7 MT |
216 | @property |
217 | def packages(self): | |
218 | pkgs = [] | |
219 | ||
220 | for lexer in self.lexer.packages: | |
f0618326 | 221 | name = lexer.get_var("_name") |
c07a3ca7 MT |
222 | |
223 | pkg = MakefilePackage(self.pakfire, name, lexer) | |
224 | pkgs.append(pkg) | |
225 | ||
afe4e55c | 226 | return pkgs |
c07a3ca7 MT |
227 | |
228 | @property | |
229 | def source_dl(self): | |
230 | dls = [] | |
231 | ||
232 | if self.pakfire.distro.source_dl: | |
233 | dls.append(self.pakfire.distro.source_dl) | |
234 | ||
235 | dl = self.lexer.get_var("source_dl") | |
236 | if dl: | |
237 | dls.append(dl) | |
238 | ||
239 | return dls | |
240 | ||
241 | def download(self): | |
242 | """ | |
243 | Download all external sources and return a list with the local | |
244 | copies. | |
47a4cb89 | 245 | """ |
c07a3ca7 MT |
246 | # Download source files. |
247 | # XXX need to implement mirrors | |
248 | downloader = SourceDownloader(self.pakfire, mirrors=self.source_dl) | |
249 | ||
250 | files = [] | |
251 | for filename in self.sources: | |
252 | filename = downloader.download(filename) | |
253 | files.append(filename) | |
47a4cb89 | 254 | |
c07a3ca7 MT |
255 | return files |
256 | ||
257 | def dist(self, resultdirs): | |
47a4cb89 | 258 | """ |
c07a3ca7 MT |
259 | Create a source package. |
260 | ||
261 | We assume that all required files are in /build. | |
262 | """ | |
263 | #dump = self.dump() | |
264 | #for line in dump.splitlines(): | |
265 | # logging.info(line) | |
266 | ||
267 | p = packager.SourcePackager(self.pakfire, self) | |
268 | p.run(resultdirs) | |
269 | ||
270 | def dump(self, *args, **kwargs): | |
271 | dump = MakefileBase.dump(self, *args, **kwargs) | |
272 | dump = dump.splitlines() | |
273 | ||
274 | #dump += ["", _("Containing the following binary packages:"),] | |
275 | # | |
276 | #for pkg in self.packages: | |
277 | # _dump = pkg.dump(*args, **kwargs) | |
278 | # | |
279 | # for line in _dump.splitlines(): | |
280 | # dump.append(" %s" % line) | |
281 | # dump.append("") | |
282 | ||
283 | return "\n".join(dump) | |
284 | ||
285 | def get_buildscript(self, stage): | |
286 | return self.lexer.build.get_var("_%s" % stage) | |
287 | ||
288 | @property | |
289 | def prerequires(self): | |
290 | return [] | |
291 | ||
292 | @property | |
293 | def requires(self): | |
f0618326 | 294 | return self.lexer.build.get_var("requires", "").split() |
c07a3ca7 MT |
295 | |
296 | @property | |
297 | def provides(self): | |
298 | return [] | |
299 | ||
300 | @property | |
301 | def obsoletes(self): | |
302 | return [] | |
303 | ||
304 | @property | |
305 | def conflicts(self): | |
306 | return [] | |
307 | ||
308 | @property | |
309 | def files(self): | |
310 | files = [] | |
311 | basedir = os.path.dirname(self.filename) | |
312 | ||
313 | for dirs, subdirs, _files in os.walk(basedir): | |
314 | for f in _files: | |
315 | files.append(os.path.join(dirs, f)) | |
316 | ||
317 | return files | |
318 | ||
319 | @property | |
320 | def sources(self): | |
321 | return self.lexer.get_var("sources").split() | |
322 | ||
3c45a6af MT |
323 | @property |
324 | def exports(self): | |
325 | exports = {} | |
326 | ||
4d5abec7 MT |
327 | # Include quality agent exports. |
328 | exports.update(self.lexer.quality_agent.exports) | |
329 | ||
3c45a6af MT |
330 | for export in self.lexer.build.exports: |
331 | exports[export] = self.lexer.build.get_var(export) | |
332 | ||
333 | return exports | |
334 | ||
c07a3ca7 MT |
335 | def extract(self, message=None, prefix=None): |
336 | # XXX neeed to make this waaaaaaaaaay better. | |
337 | ||
338 | files = self.files | |
339 | ||
340 | # Load progressbar. | |
341 | pb = None | |
342 | if message: | |
343 | message = "%-10s : %s" % (message, self.friendly_name) | |
344 | pb = util.make_progress(message, len(files), eta=False) | |
345 | ||
346 | dir_len = len(os.path.dirname(self.filename)) | |
347 | ||
348 | # Copy all files that belong to the package | |
349 | i = 0 | |
350 | for f in files: | |
351 | if pb: | |
352 | i += 1 | |
353 | pb.update(i) | |
47a4cb89 | 354 | |
c07a3ca7 MT |
355 | _f = f[dir_len:] |
356 | logging.debug("%s/%s" % (prefix, _f)) | |
357 | ||
358 | path = "%s/%s" % (prefix, _f) | |
359 | ||
360 | path_dir = os.path.dirname(path) | |
361 | if not os.path.exists(path_dir): | |
362 | os.makedirs(path_dir) | |
363 | ||
364 | shutil.copy2(f, path) | |
365 | ||
366 | if pb: | |
367 | pb.finish() | |
368 | ||
369 | # Download source files. | |
370 | downloader = SourceDownloader(self.pakfire, mirrors=self.source_dl) | |
371 | for filename in self.sources: | |
372 | _filename = downloader.download(filename) | |
373 | assert _filename | |
374 | ||
375 | filename = "%s/files/%s" % (prefix, os.path.basename(_filename)) | |
376 | dirname = os.path.dirname(filename) | |
377 | ||
378 | if not os.path.exists(dirname): | |
379 | os.makedirs(dirname) | |
380 | ||
381 | shutil.copy2(_filename, filename) | |
382 | ||
56f5e5ff MT |
383 | @property |
384 | def inst_size(self): | |
385 | return 0 | |
386 | ||
c07a3ca7 MT |
387 | |
388 | class MakefilePackage(MakefileBase): | |
389 | def __init__(self, pakfire, name, lexer): | |
390 | Package.__init__(self, pakfire) | |
391 | ||
392 | self._name = name | |
393 | self.lexer = lexer | |
394 | ||
5dda54e4 MT |
395 | # Store additional dependencies in here. |
396 | self._dependencies = {} | |
397 | ||
c07a3ca7 MT |
398 | @property |
399 | def name(self): | |
400 | return self._name | |
401 | ||
402 | @property | |
403 | def arch(self): | |
404 | return self.lexer.get_var("arch", "%{DISTRO_ARCH}") | |
405 | ||
406 | @property | |
407 | def configfiles(self): | |
408 | return self.lexer.get_var("configfiles").split() | |
409 | ||
410 | @property | |
411 | def files(self): | |
412 | return self.lexer.get_var("files").split() | |
413 | ||
414 | @property | |
415 | def uuid(self): | |
416 | return None | |
417 | ||
5dda54e4 | 418 | def track_dependencies(self, builder, path): |
a1388014 | 419 | result = builder.do("/usr/lib/pakfire/dependency-tracker %s" \ |
5dda54e4 MT |
420 | % path, returnOutput=True) |
421 | ||
422 | for line in result.splitlines(): | |
423 | m = re.match(r"^(\w+)=(.*)$", line) | |
424 | if m is None: | |
425 | continue | |
426 | ||
427 | key, val = m.groups() | |
428 | ||
429 | if not key in ("prerequires", "requires", "provides", "conflicts", "obsoletes",): | |
430 | continue | |
431 | ||
432 | val = val.strip("\"") | |
433 | val = val.split() | |
434 | ||
435 | self._dependencies[key] = sorted(val) | |
436 | ||
437 | def get_deps(self, key): | |
438 | # Collect all dependencies that were set in the makefile by the user. | |
439 | deps = self.lexer.get_var(key).split() | |
440 | ||
441 | # Collect all dependencies that were discovered by the tracker. | |
442 | deps += self._dependencies.get(key, []) | |
443 | ||
444 | # Remove duplicates. | |
445 | deps = set(deps) | |
446 | deps = list(deps) | |
447 | ||
448 | return sorted(deps) | |
c07a3ca7 MT |
449 | |
450 | @property | |
451 | def prerequires(self): | |
5dda54e4 | 452 | return self.get_deps("prerequires") |
c07a3ca7 MT |
453 | |
454 | @property | |
455 | def requires(self): | |
5dda54e4 | 456 | return self.get_deps("requires") |
c07a3ca7 MT |
457 | |
458 | @property | |
459 | def provides(self): | |
5dda54e4 | 460 | return self.get_deps("provides") |
c07a3ca7 MT |
461 | |
462 | @property | |
463 | def obsoletes(self): | |
5dda54e4 | 464 | return self.get_deps("obsoletes") |
c07a3ca7 MT |
465 | |
466 | @property | |
467 | def conflicts(self): | |
5dda54e4 | 468 | return self.get_deps("conflicts") |
47a4cb89 | 469 | |
c07a3ca7 MT |
470 | def get_scriptlet(self, type): |
471 | return self.lexer.scriptlets.get(type, None) | |
0304200a MT |
472 | |
473 | @property | |
474 | def inst_size(self): | |
475 | # The size of this is unknown. | |
476 | return 0 |