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