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