]>
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 MT |
21 | |
22 | import fcntl | |
23 | import grp | |
d59bde4c | 24 | import math |
47a4cb89 MT |
25 | import os |
26 | import re | |
27 | import shutil | |
2b6cc06d | 28 | import signal |
fc4d4177 | 29 | import socket |
0184de6e | 30 | import tempfile |
47a4cb89 | 31 | import time |
f02283bb | 32 | import uuid |
47a4cb89 | 33 | |
7c8f2953 | 34 | import base |
2b6cc06d | 35 | import cgroup |
9eac53ba | 36 | import logger |
47a4cb89 | 37 | import packages |
3817ae8e | 38 | import packages.file |
e0636b31 | 39 | import packages.packager |
fa6d335b | 40 | import repository |
64ffcd37 | 41 | import shell |
47a4cb89 | 42 | import util |
3817ae8e | 43 | import _pakfire |
47a4cb89 | 44 | |
8b6bc023 MT |
45 | import logging |
46 | log = logging.getLogger("pakfire") | |
47 | ||
854d8ccf | 48 | from config import ConfigBuilder |
c62d93f1 | 49 | from system import system |
47a4cb89 | 50 | from constants import * |
4496b160 | 51 | from i18n import _ |
e9c20259 | 52 | from errors import BuildError, BuildRootLocked, Error |
47a4cb89 MT |
53 | |
54 | ||
9eac53ba MT |
55 | BUILD_LOG_HEADER = """ |
56 | ____ _ __ _ _ _ _ _ | |
57 | | _ \ __ _| | __/ _(_)_ __ ___ | |__ _ _(_) | __| | ___ _ __ | |
58 | | |_) / _` | |/ / |_| | '__/ _ \ | '_ \| | | | | |/ _` |/ _ \ '__| | |
59 | | __/ (_| | <| _| | | | __/ | |_) | |_| | | | (_| | __/ | | |
60 | |_| \__,_|_|\_\_| |_|_| \___| |_.__/ \__,_|_|_|\__,_|\___|_| | |
61 | ||
9eac53ba | 62 | Version : %(version)s |
c62d93f1 MT |
63 | Host : %(hostname)s (%(host_arch)s) |
64 | Time : %(time)s | |
9eac53ba MT |
65 | |
66 | """ | |
67 | ||
c07a3ca7 | 68 | class BuildEnviron(object): |
47a4cb89 MT |
69 | # The version of the kernel this machine is running. |
70 | kernel_version = os.uname()[2] | |
71 | ||
392371f7 | 72 | def __init__(self, pakfire, filename=None, distro_name=None, build_id=None, logfile=None, release_build=True, **kwargs): |
36b328f2 | 73 | self.pakfire = pakfire |
f22069bb | 74 | |
36b328f2 MT |
75 | # Check if the given pakfire instance is of the correct type. |
76 | assert isinstance(self.pakfire, base.PakfireBuilder) | |
9eac53ba | 77 | |
36b328f2 MT |
78 | # Check if this host can build the requested architecture. |
79 | if not system.host_supports_arch(self.arch): | |
80 | raise BuildError, _("Cannot build for %s on this host.") % self.arch | |
9eac53ba | 81 | |
013eb9f2 MT |
82 | # Save the build id and generate one if no build id was provided. |
83 | if not build_id: | |
84 | build_id = "%s" % uuid.uuid4() | |
85 | ||
86 | self.build_id = build_id | |
87 | ||
88 | # Setup the logging. | |
89 | self.init_logging(logfile) | |
90 | ||
91 | # Initialize a cgroup (if supported). | |
92 | self.init_cgroup() | |
93 | ||
36b328f2 MT |
94 | # This build is a release build? |
95 | self.release_build = release_build | |
2b6cc06d | 96 | |
36b328f2 MT |
97 | if self.release_build: |
98 | # Disable the local build repository in release mode. | |
99 | self.pakfire.repos.disable_repo("build") | |
2b6cc06d | 100 | |
36b328f2 MT |
101 | # Log information about pakfire and some more information, when we |
102 | # are running in release mode. | |
8330691a | 103 | logdata = { |
c62d93f1 MT |
104 | "host_arch" : system.arch, |
105 | "hostname" : system.hostname, | |
106 | "time" : time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()), | |
107 | "version" : "Pakfire %s" % PAKFIRE_VERSION, | |
8330691a MT |
108 | } |
109 | ||
110 | for line in BUILD_LOG_HEADER.splitlines(): | |
111 | self.log.info(line % logdata) | |
9eac53ba | 112 | |
992b09d6 | 113 | # Settings array. |
36b328f2 | 114 | self.settings = { |
992b09d6 MT |
115 | "enable_loop_devices" : self.config.get_bool("builder", "use_loop_devices", True), |
116 | "enable_ccache" : self.config.get_bool("builder", "use_ccache", True), | |
117 | "enable_icecream" : self.config.get_bool("builder", "use_icecream", False), | |
118 | "sign_packages" : False, | |
119 | "buildroot_tmpfs" : self.config.get_bool("builder", "use_tmpfs", False), | |
392371f7 | 120 | "private_network" : self.config.get_bool("builder", "private_network", False), |
36b328f2 | 121 | } |
7c8f2953 | 122 | |
27f55929 MT |
123 | # Get ccache settings. |
124 | if self.settings.get("enable_ccache", False): | |
125 | self.settings.update({ | |
126 | "ccache_compress" : self.config.get_bool("ccache", "compress", True), | |
127 | }) | |
128 | ||
36b328f2 MT |
129 | # Try to get the configured host key. If it is available, |
130 | # we will automatically sign all packages with it. | |
131 | if self.keyring.get_host_key(secret=True): | |
132 | self.settings["sign_packages"] = True | |
cd6a9920 | 133 | |
392371f7 MT |
134 | # Add settings from keyword arguments. |
135 | self.settings.update(kwargs) | |
136 | ||
0db30904 | 137 | # Where do we put the result? |
36b328f2 | 138 | self.resultdir = os.path.join(self.pakfire.path, "result") |
0db30904 | 139 | |
3817ae8e MT |
140 | # Open package. |
141 | # If we have a plain makefile, we first build a source package and go with that. | |
142 | if filename: | |
3817ae8e MT |
143 | # Open source package. |
144 | self.pkg = packages.SourcePackage(self.pakfire, None, filename) | |
145 | assert self.pkg, filename | |
146 | ||
147 | # Log the package information. | |
148 | self.log.info(_("Package information:")) | |
149 | for line in self.pkg.dump(long=True).splitlines(): | |
150 | self.log.info(" %s" % line) | |
151 | self.log.info("") | |
152 | ||
153 | # Path where we extract the package and put all the source files. | |
3ce6a8ad | 154 | self.build_dir = os.path.join(self.path, "usr/src/packages", self.pkg.friendly_name) |
3817ae8e MT |
155 | else: |
156 | # No package :( | |
157 | self.pkg = None | |
062699ee | 158 | |
47a4cb89 MT |
159 | # Lock the buildroot |
160 | self._lock = None | |
47a4cb89 | 161 | |
fc4d4177 | 162 | # Save the build time. |
36b328f2 | 163 | self.build_time = time.time() |
f02283bb | 164 | |
96ccd5d5 MT |
165 | def setup_signal_handlers(self): |
166 | pass | |
167 | ||
8930b228 | 168 | def start(self): |
36b328f2 MT |
169 | assert not self.pakfire.initialized, "Pakfire has already been initialized" |
170 | ||
392371f7 MT |
171 | # Unshare namepsace. |
172 | # If this fails because the kernel has no support for CLONE_NEWIPC or CLONE_NEWUTS, | |
173 | # we try to fall back to just set CLONE_NEWNS. | |
174 | try: | |
175 | _pakfire.unshare(_pakfire.SCHED_CLONE_NEWNS|_pakfire.SCHED_CLONE_NEWIPC|_pakfire.SCHED_CLONE_NEWUTS) | |
176 | except RuntimeError, e: | |
177 | _pakfire.unshare(_pakfire.SCHED_CLONE_NEWNS) | |
178 | ||
8930b228 | 179 | # Mount the directories. |
e9c8d79a MT |
180 | try: |
181 | self._mountall() | |
182 | except OSError, e: | |
183 | if e.errno == 30: # Read-only FS | |
184 | raise BuildError, "Buildroot is read-only: %s" % self.pakfire.path | |
185 | ||
186 | # Raise all other errors. | |
187 | raise | |
8930b228 | 188 | |
36b328f2 MT |
189 | # Lock the build environment. |
190 | self.lock() | |
191 | ||
192 | # Initialize pakfire instance. | |
193 | self.pakfire.initialize() | |
194 | ||
392371f7 MT |
195 | # Optionally enable private networking. |
196 | if self.settings.get("private_network", None): | |
197 | _pakfire.unshare(_pakfire.SCHED_CLONE_NEWNET) | |
198 | ||
9a416dbc MT |
199 | # Populate /dev. |
200 | self.populate_dev() | |
201 | ||
83e5f0da MT |
202 | # Setup domain name resolution in chroot. |
203 | self.setup_dns() | |
8930b228 MT |
204 | |
205 | # Extract all needed packages. | |
206 | self.extract() | |
207 | ||
208 | def stop(self): | |
2b6cc06d | 209 | if self.cgroup: |
3503b149 MT |
210 | # Move the builder process out of the cgroup. |
211 | self.cgroup.migrate_task(self.cgroup.parent, os.getpid()) | |
212 | ||
2b6cc06d MT |
213 | # Kill all still running processes in the cgroup. |
214 | self.cgroup.kill_and_wait() | |
215 | ||
216 | # Remove cgroup and all parent cgroups if they are empty. | |
2b6cc06d MT |
217 | self.cgroup.destroy() |
218 | ||
219 | parent = self.cgroup.parent | |
220 | while parent: | |
221 | if not parent.is_empty(recursive=True): | |
222 | break | |
223 | ||
224 | parent.destroy() | |
225 | parent = parent.parent | |
226 | ||
227 | else: | |
228 | util.orphans_kill(self.path) | |
8930b228 | 229 | |
36b328f2 MT |
230 | # Shut down pakfire instance. |
231 | self.pakfire.destroy() | |
232 | ||
233 | # Unlock build environment. | |
234 | self.unlock() | |
8930b228 MT |
235 | |
236 | # Umount the build environment. | |
237 | self._umountall() | |
238 | ||
239 | # Remove all files. | |
240 | self.destroy() | |
241 | ||
992b09d6 MT |
242 | @property |
243 | def config(self): | |
244 | """ | |
245 | Proxy method for easy access to the configuration. | |
246 | """ | |
247 | return self.pakfire.config | |
248 | ||
36b328f2 MT |
249 | @property |
250 | def distro(self): | |
251 | """ | |
252 | Proxy method for easy access to the distribution. | |
253 | """ | |
254 | return self.pakfire.distro | |
255 | ||
256 | @property | |
257 | def path(self): | |
258 | """ | |
259 | Proxy method for easy access to the path. | |
260 | """ | |
261 | return self.pakfire.path | |
262 | ||
7c8f2953 MT |
263 | @property |
264 | def arch(self): | |
265 | """ | |
266 | Inherit architecture from distribution configuration. | |
267 | """ | |
36b328f2 | 268 | return self.pakfire.distro.arch |
7c8f2953 | 269 | |
64ffcd37 MT |
270 | @property |
271 | def personality(self): | |
272 | """ | |
273 | Gets the personality from the distribution configuration. | |
274 | """ | |
36b328f2 | 275 | return self.pakfire.distro.personality |
64ffcd37 | 276 | |
fc4d4177 MT |
277 | @property |
278 | def info(self): | |
279 | return { | |
280 | "build_date" : time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(self.build_time)), | |
281 | "build_host" : socket.gethostname(), | |
282 | "build_id" : self.build_id, | |
283 | "build_time" : self.build_time, | |
284 | } | |
285 | ||
1389d9d5 MT |
286 | @property |
287 | def keyring(self): | |
288 | """ | |
289 | Shortcut to access the pakfire keyring. | |
1389d9d5 | 290 | """ |
1389d9d5 MT |
291 | return self.pakfire.keyring |
292 | ||
47a4cb89 MT |
293 | def lock(self): |
294 | filename = os.path.join(self.path, ".lock") | |
295 | ||
296 | try: | |
297 | self._lock = open(filename, "a+") | |
298 | except IOError, e: | |
299 | return 0 | |
300 | ||
301 | try: | |
302 | fcntl.lockf(self._lock.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) | |
303 | except IOError, e: | |
304 | raise BuildRootLocked, "Buildroot is locked" | |
305 | ||
306 | return 1 | |
307 | ||
308 | def unlock(self): | |
309 | if self._lock: | |
310 | self._lock.close() | |
311 | self._lock = None | |
312 | ||
36b328f2 MT |
313 | def init_cgroup(self): |
314 | """ | |
315 | Initialize cgroup (if the system supports it). | |
316 | """ | |
317 | if not cgroup.supported(): | |
318 | self.cgroup = None | |
319 | return | |
320 | ||
904c8f11 MT |
321 | # Search for the cgroup this process is currently running in. |
322 | parent_cgroup = cgroup.find_by_pid(os.getpid()) | |
323 | if not parent_cgroup: | |
50a5fda7 | 324 | self.cgroup = None |
904c8f11 MT |
325 | return |
326 | ||
327 | # Create our own cgroup inside the parent cgroup. | |
328 | self.cgroup = parent_cgroup.create_child_cgroup("pakfire/builder/%s" % self.build_id) | |
36b328f2 | 329 | |
904c8f11 MT |
330 | # Attach the pakfire-builder process to the group. |
331 | self.cgroup.attach() | |
36b328f2 MT |
332 | |
333 | def init_logging(self, logfile): | |
334 | if logfile: | |
335 | self.log = log.getChild(self.build_id) | |
336 | # Propage everything to the root logger that we will see something | |
337 | # on the terminal. | |
338 | self.log.propagate = 1 | |
339 | self.log.setLevel(logging.INFO) | |
340 | ||
341 | # Add the given logfile to the logger. | |
342 | h = logging.FileHandler(logfile) | |
343 | self.log.addHandler(h) | |
344 | ||
345 | # Format the log output for the file. | |
346 | f = logger.BuildFormatter() | |
347 | h.setFormatter(f) | |
348 | else: | |
349 | # If no logile was given, we use the root logger. | |
350 | self.log = logging.getLogger("pakfire") | |
351 | ||
47a4cb89 MT |
352 | def copyin(self, file_out, file_in): |
353 | if file_in.startswith("/"): | |
354 | file_in = file_in[1:] | |
355 | ||
356 | file_in = self.chrootPath(file_in) | |
357 | ||
358 | #if not os.path.exists(file_out): | |
359 | # return | |
360 | ||
361 | dir_in = os.path.dirname(file_in) | |
362 | if not os.path.exists(dir_in): | |
363 | os.makedirs(dir_in) | |
364 | ||
8b6bc023 | 365 | self.log.debug("%s --> %s" % (file_out, file_in)) |
47a4cb89 MT |
366 | |
367 | shutil.copy2(file_out, file_in) | |
368 | ||
369 | def copyout(self, file_in, file_out): | |
370 | if file_in.startswith("/"): | |
371 | file_in = file_in[1:] | |
372 | ||
373 | file_in = self.chrootPath(file_in) | |
374 | ||
375 | #if not os.path.exists(file_in): | |
376 | # return | |
377 | ||
378 | dir_out = os.path.dirname(file_out) | |
379 | if not os.path.exists(dir_out): | |
380 | os.makedirs(dir_out) | |
381 | ||
8b6bc023 | 382 | self.log.debug("%s --> %s" % (file_in, file_out)) |
47a4cb89 MT |
383 | |
384 | shutil.copy2(file_in, file_out) | |
385 | ||
386 | def copy_result(self, resultdir): | |
7187b3fe MT |
387 | # XXX should use find_result_packages |
388 | ||
47a4cb89 MT |
389 | dir_in = self.chrootPath("result") |
390 | ||
391 | for dir, subdirs, files in os.walk(dir_in): | |
392 | basename = os.path.basename(dir) | |
393 | dir = dir[len(self.chrootPath()):] | |
394 | for file in files: | |
395 | file_in = os.path.join(dir, file) | |
396 | ||
397 | file_out = os.path.join( | |
398 | resultdir, | |
399 | basename, | |
400 | file, | |
401 | ) | |
402 | ||
403 | self.copyout(file_in, file_out) | |
404 | ||
7187b3fe MT |
405 | def find_result_packages(self): |
406 | ret = [] | |
407 | ||
408 | for dir, subdirs, files in os.walk(self.resultdir): | |
409 | for file in files: | |
410 | if not file.endswith(".%s" % PACKAGE_EXTENSION): | |
411 | continue | |
412 | ||
413 | file = os.path.join(dir, file) | |
414 | ret.append(file) | |
415 | ||
416 | return ret | |
417 | ||
36b328f2 | 418 | def extract(self, requires=None): |
47a4cb89 MT |
419 | """ |
420 | Gets a dependency set and extracts all packages | |
421 | to the environment. | |
422 | """ | |
9c2ad426 MT |
423 | if not requires: |
424 | requires = [] | |
5be98997 | 425 | |
8c7abfb6 MT |
426 | # Add neccessary build dependencies. |
427 | requires += BUILD_PACKAGES | |
3d960a21 | 428 | |
33f4679b MT |
429 | # If we have ccache enabled, we need to extract it |
430 | # to the build chroot. | |
431 | if self.settings.get("enable_ccache"): | |
9c2ad426 | 432 | requires.append("ccache") |
33f4679b | 433 | |
5be98997 MT |
434 | # If we have icecream enabled, we need to extract it |
435 | # to the build chroot. | |
436 | if self.settings.get("enable_icecream"): | |
9c2ad426 | 437 | requires.append("icecream") |
47a4cb89 MT |
438 | |
439 | # Get build dependencies from source package. | |
3817ae8e MT |
440 | if self.pkg: |
441 | for req in self.pkg.requires: | |
442 | requires.append(req) | |
47a4cb89 | 443 | |
9c2ad426 | 444 | # Install all packages. |
3817ae8e | 445 | self.log.info(_("Install packages needed for build...")) |
9c2ad426 | 446 | self.install(requires) |
47a4cb89 MT |
447 | |
448 | # Copy the makefile and load source tarballs. | |
3817ae8e MT |
449 | if self.pkg: |
450 | self.pkg.extract(_("Extracting"), prefix=self.build_dir) | |
47a4cb89 | 451 | |
bf3bbed5 MT |
452 | # Add an empty line at the end. |
453 | self.log.info("") | |
454 | ||
4fffe3c4 | 455 | def install(self, requires, **kwargs): |
9c2ad426 MT |
456 | """ |
457 | Install everything that is required in requires. | |
458 | """ | |
c9ec78ca MT |
459 | # If we got nothing to do, we quit immediately. |
460 | if not requires: | |
461 | return | |
462 | ||
4fffe3c4 MT |
463 | kwargs.update({ |
464 | "interactive" : False, | |
465 | "logger" : self.log, | |
466 | }) | |
c9ec78ca | 467 | |
4fffe3c4 MT |
468 | if not kwargs.has_key("allow_downgrade"): |
469 | kwargs["allow_downgrade"] = True | |
1389d9d5 | 470 | |
4fffe3c4 MT |
471 | # Install everything. |
472 | self.pakfire.install(requires, **kwargs) | |
c9ec78ca | 473 | |
47a4cb89 MT |
474 | def chrootPath(self, *args): |
475 | # Remove all leading slashes | |
476 | _args = [] | |
477 | for arg in args: | |
478 | if arg.startswith("/"): | |
479 | arg = arg[1:] | |
480 | _args.append(arg) | |
481 | args = _args | |
482 | ||
483 | ret = os.path.join(self.path, *args) | |
484 | ret = ret.replace("//", "/") | |
485 | ||
486 | assert ret.startswith(self.path) | |
487 | ||
488 | return ret | |
489 | ||
9a416dbc | 490 | def populate_dev(self): |
47a4cb89 | 491 | nodes = [ |
9a416dbc MT |
492 | "/dev/null", |
493 | "/dev/zero", | |
494 | "/dev/full", | |
495 | "/dev/random", | |
496 | "/dev/urandom", | |
497 | "/dev/tty", | |
498 | "/dev/ptmx", | |
499 | "/dev/kmsg", | |
500 | "/dev/rtc0", | |
501 | "/dev/console", | |
47a4cb89 MT |
502 | ] |
503 | ||
504 | # If we need loop devices (which are optional) we create them here. | |
505 | if self.settings["enable_loop_devices"]: | |
506 | for i in range(0, 7): | |
9a416dbc | 507 | nodes.append("/dev/loop%d" % i) |
47a4cb89 | 508 | |
47a4cb89 | 509 | for node in nodes: |
9a416dbc MT |
510 | # Stat the original node of the host system and copy it to |
511 | # the build chroot. | |
efffd953 MT |
512 | try: |
513 | node_stat = os.stat(node) | |
514 | ||
515 | # If it cannot be found, just go on. | |
516 | except OSError: | |
517 | continue | |
9a416dbc MT |
518 | |
519 | self._create_node(node, node_stat.st_mode, node_stat.st_rdev) | |
47a4cb89 MT |
520 | |
521 | os.symlink("/proc/self/fd/0", self.chrootPath("dev", "stdin")) | |
522 | os.symlink("/proc/self/fd/1", self.chrootPath("dev", "stdout")) | |
523 | os.symlink("/proc/self/fd/2", self.chrootPath("dev", "stderr")) | |
524 | os.symlink("/proc/self/fd", self.chrootPath("dev", "fd")) | |
525 | ||
83e5f0da | 526 | def setup_dns(self): |
18973967 MT |
527 | """ |
528 | Add DNS resolution facility to chroot environment by copying | |
529 | /etc/resolv.conf and /etc/hosts. | |
530 | """ | |
531 | for i in ("/etc/resolv.conf", "/etc/hosts"): | |
532 | self.copyin(i, i) | |
47a4cb89 MT |
533 | |
534 | def _create_node(self, filename, mode, device): | |
8b6bc023 | 535 | self.log.debug("Create node: %s (%s)" % (filename, mode)) |
47a4cb89 MT |
536 | |
537 | filename = self.chrootPath(filename) | |
538 | ||
539 | # Create parent directory if it is missing. | |
540 | dirname = os.path.dirname(filename) | |
541 | if not os.path.exists(dirname): | |
542 | os.makedirs(dirname) | |
543 | ||
544 | os.mknod(filename, mode, device) | |
545 | ||
526c3e7f | 546 | def destroy(self): |
8b6bc023 | 547 | self.log.debug("Destroying environment %s" % self.path) |
47a4cb89 MT |
548 | |
549 | if os.path.exists(self.path): | |
550 | util.rm(self.path) | |
551 | ||
e412b8dc | 552 | def cleanup(self): |
8b6bc023 | 553 | self.log.debug("Cleaning environemnt.") |
e412b8dc | 554 | |
e412b8dc | 555 | # Remove the build directory and buildroot. |
c44f9d6a | 556 | dirs = (self.build_dir, self.chrootPath("result"),) |
e412b8dc MT |
557 | |
558 | for d in dirs: | |
e412b8dc MT |
559 | if not os.path.exists(d): |
560 | continue | |
561 | ||
562 | util.rm(d) | |
563 | os.makedirs(d) | |
564 | ||
47a4cb89 MT |
565 | def _mountall(self): |
566 | self.log.debug("Mounting environment") | |
8930b228 MT |
567 | for src, dest, fs, options in self.mountpoints: |
568 | mountpoint = self.chrootPath(dest) | |
569 | if options: | |
570 | options = "-o %s" % options | |
571 | ||
572 | # Eventually create mountpoint directory | |
573 | if not os.path.exists(mountpoint): | |
574 | os.makedirs(mountpoint) | |
575 | ||
64ffcd37 | 576 | self.execute_root("mount -n -t %s %s %s %s" % (fs, options, src, mountpoint), shell=True) |
47a4cb89 MT |
577 | |
578 | def _umountall(self): | |
579 | self.log.debug("Umounting environment") | |
8930b228 MT |
580 | |
581 | mountpoints = [] | |
582 | for src, dest, fs, options in reversed(self.mountpoints): | |
36b328f2 MT |
583 | dest = self.chrootPath(dest) |
584 | ||
8930b228 MT |
585 | if not dest in mountpoints: |
586 | mountpoints.append(dest) | |
587 | ||
36b328f2 MT |
588 | while mountpoints: |
589 | for mp in mountpoints: | |
590 | try: | |
591 | self.execute_root("umount -n %s" % mp, shell=True) | |
592 | except ShellEnvironmentError: | |
593 | pass | |
8930b228 | 594 | |
36b328f2 MT |
595 | if not os.path.ismount(mp): |
596 | mountpoints.remove(mp) | |
47a4cb89 MT |
597 | |
598 | @property | |
599 | def mountpoints(self): | |
8930b228 MT |
600 | mountpoints = [] |
601 | ||
64ffcd37 MT |
602 | # Make root as a tmpfs if enabled. |
603 | if self.settings.get("buildroot_tmpfs"): | |
604 | mountpoints += [ | |
605 | ("pakfire_root", "/", "tmpfs", "defaults"), | |
606 | ] | |
8930b228 MT |
607 | |
608 | mountpoints += [ | |
609 | # src, dest, fs, options | |
610 | ("pakfire_proc", "/proc", "proc", "nosuid,noexec,nodev"), | |
611 | ("/proc/sys", "/proc/sys", "bind", "bind"), | |
612 | ("/proc/sys", "/proc/sys", "bind", "bind,ro,remount"), | |
613 | ("/sys", "/sys", "bind", "bind"), | |
614 | ("/sys", "/sys", "bind", "bind,ro,remount"), | |
615 | ("pakfire_tmpfs", "/dev", "tmpfs", "mode=755,nosuid"), | |
616 | ("/dev/pts", "/dev/pts", "bind", "bind"), | |
617 | ("pakfire_tmpfs", "/run", "tmpfs", "mode=755,nosuid,nodev"), | |
4252a549 | 618 | ("pakfire_tmpfs", "/tmp", "tmpfs", "mode=755,nosuid,nodev"), |
47a4cb89 MT |
619 | ] |
620 | ||
8930b228 MT |
621 | # If selinux is enabled. |
622 | if os.path.exists("/sys/fs/selinux"): | |
623 | mountpoints += [ | |
624 | ("/sys/fs/selinux", "/sys/fs/selinux", "bind", "bind"), | |
625 | ("/sys/fs/selinux", "/sys/fs/selinux", "bind", "bind,ro,remount"), | |
626 | ] | |
47a4cb89 | 627 | |
8930b228 | 628 | # If ccache support is requested, we bind mount the cache. |
33f4679b | 629 | if self.settings.get("enable_ccache"): |
046278b2 MT |
630 | # Create ccache cache directory if it does not exist. |
631 | if not os.path.exists(CCACHE_CACHE_DIR): | |
632 | os.makedirs(CCACHE_CACHE_DIR) | |
633 | ||
8930b228 MT |
634 | mountpoints += [ |
635 | (CCACHE_CACHE_DIR, "/var/cache/ccache", "bind", "bind"), | |
636 | ] | |
33f4679b | 637 | |
8930b228 | 638 | return mountpoints |
47a4cb89 MT |
639 | |
640 | @property | |
641 | def environ(self): | |
1dd38b7b MT |
642 | env = MINIMAL_ENVIRONMENT.copy() |
643 | env.update({ | |
0cf10c2d MT |
644 | # Add HOME manually, because it is occasionally not set |
645 | # and some builds get in trouble then. | |
a6659a32 | 646 | "TERM" : os.environ.get("TERM", "vt100"), |
0cf10c2d | 647 | |
d64b975b MT |
648 | # Sanitize language. |
649 | "LANG" : os.environ.setdefault("LANG", "en_US.UTF-8"), | |
650 | ||
936f6b37 MT |
651 | # Set the container that we can detect, if we are inside a |
652 | # chroot. | |
653 | "container" : "pakfire-builder", | |
1dd38b7b | 654 | }) |
47a4cb89 MT |
655 | |
656 | # Inherit environment from distro | |
657 | env.update(self.pakfire.distro.environ) | |
658 | ||
27f55929 MT |
659 | # ccache environment settings |
660 | if self.settings.get("enable_ccache", False): | |
661 | compress = self.settings.get("ccache_compress", False) | |
662 | if compress: | |
663 | env["CCACHE_COMPRESS"] = "1" | |
664 | ||
665 | # Let ccache create its temporary files in /tmp. | |
666 | env["CCACHE_TEMPDIR"] = "/tmp" | |
667 | ||
5be98997 | 668 | # Icecream environment settings |
c07a3ca7 | 669 | if self.settings.get("enable_icecream", False): |
5be98997 MT |
670 | # Set the toolchain path |
671 | if self.settings.get("icecream_toolchain", None): | |
672 | env["ICECC_VERSION"] = self.settings.get("icecream_toolchain") | |
673 | ||
674 | # Set preferred host if configured. | |
675 | if self.settings.get("icecream_preferred_host", None): | |
676 | env["ICECC_PREFERRED_HOST"] = \ | |
677 | self.settings.get("icecream_preferred_host") | |
678 | ||
77a330d5 MT |
679 | # Fake UTS_MACHINE, when we cannot use the personality syscall and |
680 | # if the host architecture is not equal to the target architecture. | |
681 | if not self.pakfire.distro.personality and \ | |
a6bd96bc | 682 | not system.native_arch == self.pakfire.distro.arch: |
77a330d5 MT |
683 | env.update({ |
684 | "LD_PRELOAD" : "/usr/lib/libpakfire_preload.so", | |
685 | "UTS_MACHINE" : self.pakfire.distro.arch, | |
686 | }) | |
47a4cb89 MT |
687 | |
688 | return env | |
689 | ||
c62d93f1 MT |
690 | @property |
691 | def installed_packages(self): | |
692 | """ | |
693 | Returns an iterator over all installed packages in this build environment. | |
694 | """ | |
695 | # Get the repository of all installed packages. | |
696 | repo = self.pakfire.repos.get_repo("@system") | |
697 | ||
698 | # Return an iterator over the packages. | |
699 | return iter(repo) | |
700 | ||
854d8ccf MT |
701 | def write_config(self): |
702 | # Cleanup everything in /etc/pakfire. | |
703 | util.rm(self.chrootPath(CONFIG_DIR)) | |
704 | ||
705 | for i in (CONFIG_DIR, CONFIG_REPOS_DIR): | |
706 | i = self.chrootPath(i) | |
707 | if not os.path.exists(i): | |
708 | os.makedirs(i) | |
709 | ||
710 | # Write general.conf. | |
711 | f = open(self.chrootPath(CONFIG_DIR, "general.conf"), "w") | |
712 | f.close() | |
713 | ||
714 | # Write builder.conf. | |
715 | f = open(self.chrootPath(CONFIG_DIR, "builder.conf"), "w") | |
716 | f.write(self.distro.get_config()) | |
717 | f.close() | |
718 | ||
719 | # Create pakfire configuration files. | |
720 | for repo in self.pakfire.repos: | |
721 | conf = repo.get_config() | |
722 | ||
723 | if not conf: | |
724 | continue | |
725 | ||
726 | filename = self.chrootPath(CONFIG_REPOS_DIR, "%s.repo" % repo.name) | |
727 | f = open(filename, "w") | |
728 | f.write("\n".join(conf)) | |
729 | f.close() | |
730 | ||
64ffcd37 MT |
731 | @property |
732 | def pkg_makefile(self): | |
733 | return os.path.join(self.build_dir, "%s.%s" % (self.pkg.name, MAKEFILE_EXTENSION)) | |
47a4cb89 | 734 | |
64ffcd37 MT |
735 | def execute(self, command, logger=None, **kwargs): |
736 | """ | |
737 | Executes the given command in the build chroot. | |
738 | """ | |
8930b228 MT |
739 | # Environment variables |
740 | env = self.environ | |
47a4cb89 | 741 | |
8930b228 MT |
742 | if kwargs.has_key("env"): |
743 | env.update(kwargs.pop("env")) | |
15398910 | 744 | |
8b6bc023 | 745 | self.log.debug("Environment:") |
8930b228 | 746 | for k, v in sorted(env.items()): |
8b6bc023 | 747 | self.log.debug(" %s=%s" % (k, v)) |
e360ea59 | 748 | |
8930b228 MT |
749 | # Make every shell to a login shell because we set a lot of |
750 | # environment things there. | |
64ffcd37 MT |
751 | command = ["bash", "--login", "-c", command] |
752 | ||
753 | args = { | |
754 | "chroot_path" : self.chrootPath(), | |
755 | "cgroup" : self.cgroup, | |
756 | "env" : env, | |
757 | "logger" : logger, | |
758 | "personality" : self.personality, | |
759 | "shell" : False, | |
760 | } | |
761 | args.update(kwargs) | |
47a4cb89 | 762 | |
64ffcd37 MT |
763 | # Run the shit. |
764 | shellenv = shell.ShellExecuteEnvironment(command, **args) | |
765 | shellenv.execute() | |
766 | ||
767 | return shellenv | |
768 | ||
769 | def execute_root(self, command, **kwargs): | |
770 | """ | |
771 | Executes the given command outside the build chroot. | |
772 | """ | |
773 | shellenv = shell.ShellExecuteEnvironment(command, **kwargs) | |
774 | shellenv.execute() | |
775 | ||
776 | return shellenv | |
47a4cb89 | 777 | |
47230b23 | 778 | def build(self, install_test=True, prepare=False): |
3817ae8e MT |
779 | if not self.pkg: |
780 | raise BuildError, _("You cannot run a build when no package was given.") | |
c157d1e2 | 781 | |
c44f9d6a | 782 | # Search for the package file in build_dir and raise BuildError if it is not present. |
64ffcd37 MT |
783 | if not os.path.exists(self.pkg_makefile): |
784 | raise BuildError, _("Could not find makefile in build root: %s") % self.pkg_makefile | |
c44f9d6a | 785 | |
854d8ccf MT |
786 | # Write pakfire configuration into the chroot. |
787 | self.write_config() | |
c07a3ca7 MT |
788 | |
789 | # Create the build command, that is executed in the chroot. | |
a6bd96bc MT |
790 | build_command = [ |
791 | "/usr/lib/pakfire/builder", | |
792 | "--offline", | |
793 | "build", | |
64ffcd37 | 794 | "/%s" % os.path.relpath(self.pkg_makefile, self.chrootPath()), |
a6bd96bc MT |
795 | "--arch", self.arch, |
796 | "--nodeps", | |
a6bd96bc MT |
797 | "--resultdir=/result", |
798 | ] | |
c07a3ca7 | 799 | |
64ffcd37 | 800 | # Check if only the preparation stage should be run. |
47230b23 MT |
801 | if prepare: |
802 | build_command.append("--prepare") | |
803 | ||
36b328f2 MT |
804 | build_command = " ".join(build_command) |
805 | ||
c07a3ca7 | 806 | try: |
64ffcd37 | 807 | self.execute(build_command, logger=self.log) |
c07a3ca7 | 808 | |
4fffe3c4 | 809 | # Perform the install test after the actual build. |
47230b23 | 810 | if install_test and not prepare: |
4fffe3c4 MT |
811 | self.install_test() |
812 | ||
64ffcd37 | 813 | except ShellEnvironmentError: |
64ffcd37 MT |
814 | self.log.error(_("Build failed")) |
815 | ||
64252a9d | 816 | except KeyboardInterrupt: |
64252a9d MT |
817 | self.log.error(_("Build interrupted")) |
818 | ||
819 | raise | |
820 | ||
64ffcd37 MT |
821 | # Catch all other errors. |
822 | except: | |
516fc709 MT |
823 | self.log.error(_("Build failed."), exc_info=True) |
824 | ||
64ffcd37 MT |
825 | else: |
826 | # Don't sign packages in prepare mode. | |
827 | if prepare: | |
828 | return | |
c07a3ca7 | 829 | |
64ffcd37 MT |
830 | # Sign all built packages with the host key (if available). |
831 | self.sign_packages() | |
47230b23 | 832 | |
64ffcd37 MT |
833 | # Dump package information. |
834 | self.dump() | |
1389d9d5 | 835 | |
64ffcd37 | 836 | return |
1389d9d5 | 837 | |
64ffcd37 MT |
838 | # End here in case of an error. |
839 | raise BuildError, _("The build command failed. See logfile for details.") | |
1389d9d5 | 840 | |
4fffe3c4 MT |
841 | def install_test(self): |
842 | self.log.info(_("Running installation test...")) | |
843 | ||
844 | # Install all packages that were built. | |
532142c6 | 845 | self.install(self.find_result_packages(), allow_vendorchange=True, |
9b68f47c | 846 | allow_uninstall=True, signatures_mode="disabled") |
4fffe3c4 MT |
847 | |
848 | self.log.info(_("Installation test succeeded.")) | |
849 | self.log.info("") | |
850 | ||
47a4cb89 | 851 | def shell(self, args=[]): |
e9c20259 | 852 | if not util.cli_is_interactive(): |
8b6bc023 | 853 | self.log.warning("Cannot run shell on non-interactive console.") |
e9c20259 MT |
854 | return |
855 | ||
9c2ad426 MT |
856 | # Install all packages that are needed to run a shell. |
857 | self.install(SHELL_PACKAGES) | |
858 | ||
47a4cb89 | 859 | # XXX need to set CFLAGS here |
83e5f0da MT |
860 | command = "/usr/sbin/chroot %s %s %s" % \ |
861 | (self.chrootPath(), SHELL_SCRIPT, " ".join(args)) | |
47a4cb89 | 862 | |
e360ea59 MT |
863 | # Add personality if we require one |
864 | if self.pakfire.distro.personality: | |
a7596ccf MT |
865 | command = "%s %s" % (self.pakfire.distro.personality, command) |
866 | ||
867 | for key, val in self.environ.items(): | |
868 | command = "%s=\"%s\" " % (key, val) + command | |
e360ea59 | 869 | |
47a4cb89 | 870 | # Empty the environment |
a7596ccf | 871 | command = "env -i - %s" % command |
47a4cb89 | 872 | |
8b6bc023 | 873 | self.log.debug("Shell command: %s" % command) |
47a4cb89 | 874 | |
8930b228 MT |
875 | shell = os.system(command) |
876 | return os.WEXITSTATUS(shell) | |
c07a3ca7 | 877 | |
64ffcd37 MT |
878 | def sign_packages(self, keyfp=None): |
879 | # Do nothing if signing is not requested. | |
880 | if not self.settings.get("sign_packages"): | |
881 | return | |
882 | ||
883 | # Get key, that should be used for signing. | |
884 | if not keyfp: | |
885 | keyfp = self.keyring.get_host_key_id() | |
1389d9d5 MT |
886 | |
887 | # Find all files to process. | |
888 | files = self.find_result_packages() | |
889 | ||
890 | # Create a progressbar. | |
4fffe3c4 MT |
891 | print _("Signing packages...") |
892 | p = util.make_progress(keyfp, len(files)) | |
1389d9d5 MT |
893 | i = 0 |
894 | ||
895 | for file in files: | |
896 | # Update progressbar. | |
897 | if p: | |
898 | i += 1 | |
899 | p.update(i) | |
900 | ||
901 | # Open package file. | |
902 | pkg = packages.open(self.pakfire, None, file) | |
903 | ||
904 | # Sign it. | |
905 | pkg.sign(keyfp) | |
906 | ||
907 | # Close progressbar. | |
908 | if p: | |
909 | p.finish() | |
4fffe3c4 | 910 | print "" # Print an empty line. |
1389d9d5 MT |
911 | |
912 | def dump(self): | |
913 | pkgs = [] | |
914 | ||
915 | for file in self.find_result_packages(): | |
916 | pkg = packages.open(self.pakfire, None, file) | |
917 | pkgs.append(pkg) | |
918 | ||
919 | # If there are no packages, there is nothing to do. | |
920 | if not pkgs: | |
921 | return | |
922 | ||
923 | pkgs.sort() | |
924 | ||
925 | self.log.info(_("Dumping package information:")) | |
926 | for pkg in pkgs: | |
927 | dump = pkg.dump(long=True) | |
928 | ||
929 | for line in dump.splitlines(): | |
930 | self.log.info(" %s" % line) | |
931 | self.log.info("") # Empty line. | |
932 | ||
56f5e5ff | 933 | |
ff9299d0 | 934 | class Builder(object): |
c07a3ca7 MT |
935 | def __init__(self, pakfire, filename, resultdir, **kwargs): |
936 | self.pakfire = pakfire | |
937 | ||
938 | self.filename = filename | |
939 | ||
940 | self.resultdir = resultdir | |
941 | ||
942 | # Open package file. | |
943 | self.pkg = packages.Makefile(self.pakfire, self.filename) | |
944 | ||
c07a3ca7 | 945 | self._environ = { |
0d96815e | 946 | "LANG" : "C", |
c07a3ca7 MT |
947 | } |
948 | ||
0d96815e MT |
949 | @property |
950 | def buildroot(self): | |
951 | return self.pkg.buildroot | |
952 | ||
c07a3ca7 MT |
953 | @property |
954 | def distro(self): | |
955 | return self.pakfire.distro | |
956 | ||
957 | @property | |
958 | def environ(self): | |
959 | environ = os.environ | |
3c45a6af MT |
960 | |
961 | # Get all definitions from the package. | |
962 | environ.update(self.pkg.exports) | |
963 | ||
964 | # Overwrite some definitions by default values. | |
c07a3ca7 MT |
965 | environ.update(self._environ) |
966 | ||
967 | return environ | |
968 | ||
64ffcd37 MT |
969 | def execute(self, command, logger=None, **kwargs): |
970 | if logger is None: | |
08e95360 | 971 | logger = logging.getLogger("pakfire") |
c07a3ca7 MT |
972 | |
973 | # Make every shell to a login shell because we set a lot of | |
974 | # environment things there. | |
64ffcd37 MT |
975 | command = ["bash", "--login", "-c", command] |
976 | ||
977 | args = { | |
978 | "cwd" : "/%s" % LOCAL_TMP_PATH, | |
979 | "env" : self.environ, | |
980 | "logger" : logger, | |
981 | "personality" : self.distro.personality, | |
982 | "shell" : False, | |
983 | } | |
984 | args.update(kwargs) | |
2b6cc06d MT |
985 | |
986 | try: | |
64ffcd37 MT |
987 | shellenv = shell.ShellExecuteEnvironment(command, **args) |
988 | shellenv.execute() | |
2b6cc06d | 989 | |
64ffcd37 | 990 | except ShellEnvironmentError: |
2b6cc06d MT |
991 | logger.error("Command exited with an error: %s" % command) |
992 | raise | |
c07a3ca7 | 993 | |
64ffcd37 MT |
994 | return shellenv |
995 | ||
08e95360 MT |
996 | def run_script(self, script, *args): |
997 | if not script.startswith("/"): | |
998 | script = os.path.join(SCRIPT_DIR, script) | |
999 | ||
1000 | assert os.path.exists(script), "Script we should run does not exist: %s" % script | |
1001 | ||
1002 | cmd = [script,] | |
1003 | for arg in args: | |
1004 | cmd.append(arg) | |
1005 | cmd = " ".join(cmd) | |
1006 | ||
1007 | # Returns the output of the command, but the output won't get | |
1008 | # logged. | |
64ffcd37 MT |
1009 | exe = self.execute(cmd, record_output=True, log_output=False) |
1010 | ||
1011 | # Return the output of the command. | |
1012 | if exe.exitcode == 0: | |
1013 | return exe.output | |
08e95360 | 1014 | |
c07a3ca7 MT |
1015 | def create_icecream_toolchain(self): |
1016 | try: | |
64ffcd37 MT |
1017 | exe = self.execute( |
1018 | "icecc --build-native 2>/dev/null", | |
1019 | record_output=True, record_stderr=False, | |
1020 | log_output=False, log_errors=False, | |
1021 | cwd="/tmp", | |
1022 | ) | |
1023 | except ShellEnvironmentError: | |
c07a3ca7 MT |
1024 | return |
1025 | ||
64ffcd37 | 1026 | for line in exe.output.splitlines(): |
c07a3ca7 MT |
1027 | m = re.match(r"^creating ([a-z0-9]+\.tar\.gz)", line) |
1028 | if m: | |
dc99cccd | 1029 | self._environ["ICECC_VERSION"] = "/tmp/%s" % m.group(1) |
c07a3ca7 MT |
1030 | |
1031 | def create_buildscript(self, stage): | |
c07a3ca7 MT |
1032 | # Get buildscript from the package. |
1033 | script = self.pkg.get_buildscript(stage) | |
1034 | ||
1035 | # Write script to an empty file. | |
0184de6e | 1036 | f = tempfile.NamedTemporaryFile(mode="w", delete=False) |
c07a3ca7 MT |
1037 | f.write("#!/bin/sh\n\n") |
1038 | f.write("set -e\n") | |
1039 | f.write("set -x\n") | |
1040 | f.write("\n%s\n" % script) | |
1041 | f.write("exit 0\n") | |
1042 | f.close() | |
c07a3ca7 | 1043 | |
0184de6e MT |
1044 | # Make the script executable. |
1045 | os.chmod(f.name, 700) | |
1046 | ||
1047 | return f.name | |
c07a3ca7 | 1048 | |
47230b23 | 1049 | def build(self, stages=None): |
7abe644a MT |
1050 | # Create buildroot and remove all content if it was existant. |
1051 | util.rm(self.buildroot) | |
1052 | os.makedirs(self.buildroot) | |
c07a3ca7 MT |
1053 | |
1054 | # Build icecream toolchain if icecream is installed. | |
1055 | self.create_icecream_toolchain() | |
1056 | ||
013eb9f2 MT |
1057 | # Process stages in order. |
1058 | for stage in ("prepare", "build", "test", "install"): | |
1059 | # Skip unwanted stages. | |
1060 | if stages and not stage in stages: | |
1061 | continue | |
47230b23 | 1062 | |
013eb9f2 | 1063 | # Run stage. |
c07a3ca7 MT |
1064 | self.build_stage(stage) |
1065 | ||
013eb9f2 MT |
1066 | # Stop if install stage has not been processed. |
1067 | if stages and not "install" in stages: | |
47230b23 MT |
1068 | return |
1069 | ||
87745c01 | 1070 | # Run post-build stuff. |
1b51609b | 1071 | self.post_compress_man_pages() |
87745c01 | 1072 | self.post_remove_static_libs() |
3ce6a8ad | 1073 | self.post_extract_debuginfo() |
87745c01 | 1074 | |
c07a3ca7 MT |
1075 | # Package the result. |
1076 | # Make all these little package from the build environment. | |
8b6bc023 | 1077 | log.info(_("Creating packages:")) |
56f5e5ff | 1078 | pkgs = [] |
c07a3ca7 | 1079 | for pkg in reversed(self.pkg.packages): |
5dda54e4 MT |
1080 | packager = packages.packager.BinaryPackager(self.pakfire, pkg, |
1081 | self, self.buildroot) | |
56f5e5ff MT |
1082 | pkg = packager.run(self.resultdir) |
1083 | pkgs.append(pkg) | |
8b6bc023 | 1084 | log.info("") |
56f5e5ff | 1085 | |
c07a3ca7 MT |
1086 | def build_stage(self, stage): |
1087 | # Get the buildscript for this stage. | |
1088 | buildscript = self.create_buildscript(stage) | |
1089 | ||
1090 | # Execute the buildscript of this stage. | |
8b6bc023 | 1091 | log.info(_("Running stage %s:") % stage) |
c07a3ca7 | 1092 | |
75bb74a7 | 1093 | try: |
64ffcd37 | 1094 | self.execute(buildscript) |
75bb74a7 MT |
1095 | |
1096 | finally: | |
1097 | # Remove the buildscript. | |
1098 | if os.path.exists(buildscript): | |
1099 | os.unlink(buildscript) | |
c07a3ca7 | 1100 | |
87745c01 MT |
1101 | def post_remove_static_libs(self): |
1102 | keep_libs = self.pkg.lexer.build.get_var("keep_libraries") | |
1103 | keep_libs = keep_libs.split() | |
1104 | ||
1105 | try: | |
64ffcd37 | 1106 | self.execute("%s/remove-static-libs %s %s" % \ |
87745c01 | 1107 | (SCRIPT_DIR, self.buildroot, " ".join(keep_libs))) |
64ffcd37 | 1108 | except ShellEnvironmentError, e: |
8b6bc023 | 1109 | log.warning(_("Could not remove static libraries: %s") % e) |
87745c01 | 1110 | |
1b51609b MT |
1111 | def post_compress_man_pages(self): |
1112 | try: | |
64ffcd37 MT |
1113 | self.execute("%s/compress-man-pages %s" % (SCRIPT_DIR, self.buildroot)) |
1114 | except ShellEnvironmentError, e: | |
8b6bc023 | 1115 | log.warning(_("Compressing man pages did not complete successfully.")) |
1b51609b | 1116 | |
3ce6a8ad MT |
1117 | def post_extract_debuginfo(self): |
1118 | args = [] | |
1119 | ||
1120 | # Check if we need to run with strict build-id. | |
1121 | strict_id = self.pkg.lexer.build.get_var("debuginfo_strict_build_id", "true") | |
1122 | if strict_id in ("true", "yes", "1"): | |
1123 | args.append("--strict-build-id") | |
1124 | ||
1125 | args.append("--buildroot=%s" % self.pkg.buildroot) | |
1126 | args.append("--sourcedir=%s" % self.pkg.sourcedir) | |
1127 | ||
1128 | # Get additional options to pass to script. | |
1129 | options = self.pkg.lexer.build.get_var("debuginfo_options", "") | |
1130 | args += options.split() | |
1131 | ||
1132 | try: | |
64ffcd37 MT |
1133 | self.execute("%s/extract-debuginfo %s %s" % (SCRIPT_DIR, " ".join(args), self.pkg.buildroot)) |
1134 | except ShellEnvironmentError, e: | |
3ce6a8ad MT |
1135 | log.error(_("Extracting debuginfo did not complete with success. Aborting build.")) |
1136 | raise | |
1137 | ||
08e95360 MT |
1138 | def find_prerequires(self, scriptlet_file): |
1139 | assert os.path.exists(scriptlet_file), "Scriptlet file does not exist: %s" % scriptlet_file | |
1140 | ||
1141 | res = self.run_script("find-prerequires", scriptlet_file) | |
1142 | prerequires = set(res.splitlines()) | |
1143 | ||
1144 | return prerequires | |
1145 | ||
c07a3ca7 MT |
1146 | def cleanup(self): |
1147 | if os.path.exists(self.buildroot): | |
1148 | util.rm(self.buildroot) |