]> git.ipfire.org Git - pakfire.git/blame - python/pakfire/packages/make.py
Fix include of helper functions in dependency-tracker.
[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
c07a3ca7
MT
36import pakfire.util as util
37
47a4cb89 38from base import Package
e0636b31
MT
39from file import SourcePackage
40
47a4cb89 41from pakfire.constants import *
c07a3ca7 42from pakfire.i18n import _
47a4cb89 43
c07a3ca7 44# XXX to be moved to pakfire.downloader
47a4cb89 45class 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 75class 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
196class 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
388class 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