]> git.ipfire.org Git - pakfire.git/blame - pakfire/builder.py
Change code that populates /dev in the chroot.
[pakfire.git] / pakfire / builder.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
MT
21
22import fcntl
23import grp
24import logging
d59bde4c 25import math
47a4cb89
MT
26import os
27import re
28import shutil
fc4d4177 29import socket
47a4cb89 30import time
f02283bb 31import uuid
47a4cb89 32
7c8f2953 33import base
93bd0aa4 34import chroot
9eac53ba 35import logger
47a4cb89 36import packages
e0636b31 37import packages.packager
fa6d335b 38import repository
47a4cb89
MT
39import util
40
41from constants import *
4496b160 42from i18n import _
e9c20259 43from errors import BuildError, BuildRootLocked, Error
47a4cb89
MT
44
45
9eac53ba
MT
46BUILD_LOG_HEADER = """
47 ____ _ __ _ _ _ _ _
48| _ \ __ _| | __/ _(_)_ __ ___ | |__ _ _(_) | __| | ___ _ __
49| |_) / _` | |/ / |_| | '__/ _ \ | '_ \| | | | | |/ _` |/ _ \ '__|
50| __/ (_| | <| _| | | | __/ | |_) | |_| | | | (_| | __/ |
51|_| \__,_|_|\_\_| |_|_| \___| |_.__/ \__,_|_|_|\__,_|\___|_|
52
53 Time : %(time)s
54 Host : %(host)s
55 Version : %(version)s
56
57"""
58
c07a3ca7 59class BuildEnviron(object):
47a4cb89
MT
60 # The version of the kernel this machine is running.
61 kernel_version = os.uname()[2]
62
9eac53ba 63 def __init__(self, pkg=None, distro_config=None, build_id=None, logfile=None,
f22069bb
MT
64 builder_mode="release", **pakfire_args):
65 # Set mode.
66 assert builder_mode in ("development", "release",)
67 self.mode = builder_mode
68
69 # Disable the build repository in release mode.
70 if self.mode == "release":
71 if pakfire_args.has_key("disable_repos") and pakfire_args["disable_repos"]:
72 pakfire_args["disable_repos"] += ["build",]
73 else:
74 pakfire_args["disable_repos"] = ["build",]
75
9eac53ba
MT
76 # Save the build id and generate one if no build id was provided.
77 if not build_id:
78 build_id = "%s" % uuid.uuid4()
79
80 self.build_id = build_id
81
82 # Setup the logging.
83 if logfile:
84 self.log = logging.getLogger(self.build_id)
85 # Propage everything to the root logger that we will see something
86 # on the terminal.
87 self.log.propagate = 1
88 self.log.setLevel(logging.INFO)
89
90 # Add the given logfile to the logger.
91 h = logging.FileHandler(logfile)
92 self.log.addHandler(h)
93
94 # Format the log output for the file.
95 f = logger.BuildFormatter()
96 h.setFormatter(f)
97 else:
98 # If no logile was given, we use the root logger.
99 self.log = logging.getLogger()
100
8330691a
MT
101 # Log information about pakfire and some more information, when we
102 # are running in release mode.
103 if self.mode == "release":
104 logdata = {
105 "host" : socket.gethostname(),
106 "time" : time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()),
107 "version" : "Pakfire %s" % PAKFIRE_VERSION,
108 }
109
110 for line in BUILD_LOG_HEADER.splitlines():
111 self.log.info(line % logdata)
9eac53ba 112
7c8f2953 113 # Create pakfire instance.
1ee5d54a
MT
114 if pakfire_args.has_key("mode"):
115 del pakfire_args["mode"]
eb34496a 116 self.pakfire = base.Pakfire(mode="builder", distro_config=distro_config, **pakfire_args)
7c8f2953
MT
117 self.distro = self.pakfire.distro
118 self.path = self.pakfire.path
119
c07a3ca7
MT
120 # Log the package information.
121 self.pkg = packages.Makefile(self.pakfire, pkg)
122 self.log.info(_("Package information:"))
123 for line in self.pkg.dump(long=True).splitlines():
124 self.log.info(" %s" % line)
125 self.log.info("")
7c8f2953
MT
126
127 # XXX need to make this configureable
47a4cb89
MT
128 self.settings = {
129 "enable_loop_devices" : True,
33f4679b 130 "enable_ccache" : True,
8c716255 131 "enable_icecream" : False,
47a4cb89 132 }
7c8f2953 133 #self.settings.update(settings)
47a4cb89
MT
134
135 self.buildroot = "/buildroot"
136
137 # Lock the buildroot
138 self._lock = None
139 self.lock()
140
fc4d4177
MT
141 # Save the build time.
142 self.build_time = int(time.time())
f02283bb 143
8930b228
MT
144 def start(self):
145 # Mount the directories.
146 self._mountall()
147
9a416dbc
MT
148 # Populate /dev.
149 self.populate_dev()
150
8930b228
MT
151 # Create all devnodes and other dirs we need.
152 self.prepare()
153
154 # Extract all needed packages.
155 self.extract()
156
157 def stop(self):
158 # Kill all still running processes.
159 util.orphans_kill(self.path)
160
161 # Close pakfire instance.
162 del self.pakfire
163
164 # Umount the build environment.
165 self._umountall()
166
167 # Remove all files.
168 self.destroy()
169
7c8f2953
MT
170 @property
171 def arch(self):
172 """
173 Inherit architecture from distribution configuration.
174 """
175 return self.distro.arch
176
fc4d4177
MT
177 @property
178 def info(self):
179 return {
180 "build_date" : time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(self.build_time)),
181 "build_host" : socket.gethostname(),
182 "build_id" : self.build_id,
183 "build_time" : self.build_time,
184 }
185
47a4cb89
MT
186 def lock(self):
187 filename = os.path.join(self.path, ".lock")
188
189 try:
190 self._lock = open(filename, "a+")
191 except IOError, e:
192 return 0
193
194 try:
195 fcntl.lockf(self._lock.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
196 except IOError, e:
197 raise BuildRootLocked, "Buildroot is locked"
198
199 return 1
200
201 def unlock(self):
202 if self._lock:
203 self._lock.close()
204 self._lock = None
205
206 def copyin(self, file_out, file_in):
207 if file_in.startswith("/"):
208 file_in = file_in[1:]
209
210 file_in = self.chrootPath(file_in)
211
212 #if not os.path.exists(file_out):
213 # return
214
215 dir_in = os.path.dirname(file_in)
216 if not os.path.exists(dir_in):
217 os.makedirs(dir_in)
218
219 logging.debug("%s --> %s" % (file_out, file_in))
220
221 shutil.copy2(file_out, file_in)
222
223 def copyout(self, file_in, file_out):
224 if file_in.startswith("/"):
225 file_in = file_in[1:]
226
227 file_in = self.chrootPath(file_in)
228
229 #if not os.path.exists(file_in):
230 # return
231
232 dir_out = os.path.dirname(file_out)
233 if not os.path.exists(dir_out):
234 os.makedirs(dir_out)
235
236 logging.debug("%s --> %s" % (file_in, file_out))
237
238 shutil.copy2(file_in, file_out)
239
240 def copy_result(self, resultdir):
241 dir_in = self.chrootPath("result")
242
243 for dir, subdirs, files in os.walk(dir_in):
244 basename = os.path.basename(dir)
245 dir = dir[len(self.chrootPath()):]
246 for file in files:
247 file_in = os.path.join(dir, file)
248
249 file_out = os.path.join(
250 resultdir,
251 basename,
252 file,
253 )
254
255 self.copyout(file_in, file_out)
256
9c2ad426 257 def extract(self, requires=None, build_deps=True):
47a4cb89
MT
258 """
259 Gets a dependency set and extracts all packages
260 to the environment.
261 """
9c2ad426
MT
262 if not requires:
263 requires = []
5be98997 264
9c2ad426
MT
265 # Add neccessary build dependencies.
266 requires += BUILD_PACKAGES
3d960a21 267
33f4679b
MT
268 # If we have ccache enabled, we need to extract it
269 # to the build chroot.
270 if self.settings.get("enable_ccache"):
9c2ad426 271 requires.append("ccache")
33f4679b 272
5be98997
MT
273 # If we have icecream enabled, we need to extract it
274 # to the build chroot.
275 if self.settings.get("enable_icecream"):
9c2ad426 276 requires.append("icecream")
47a4cb89
MT
277
278 # Get build dependencies from source package.
c07a3ca7
MT
279 for req in self.pkg.requires:
280 requires.append(req)
47a4cb89 281
9c2ad426
MT
282 # Install all packages.
283 self.install(requires)
47a4cb89
MT
284
285 # Copy the makefile and load source tarballs.
c07a3ca7
MT
286 self.pkg.extract(_("Extracting"),
287 prefix=os.path.join(self.path, "build"))
47a4cb89 288
9c2ad426
MT
289 def install(self, requires):
290 """
291 Install everything that is required in requires.
292 """
c9ec78ca
MT
293 # If we got nothing to do, we quit immediately.
294 if not requires:
295 return
296
c07a3ca7
MT
297 self.pakfire.install(requires, interactive=False,
298 allow_downgrade=True, logger=self.log)
47a4cb89 299
c9ec78ca
MT
300 def install_test(self):
301 pkgs = []
c9ec78ca
MT
302 for dir, subdirs, files in os.walk(self.chrootPath("result")):
303 for file in files:
b88090e9 304 pkgs.append(os.path.join(dir, file))
c9ec78ca 305
08d60af8 306 self.pakfire.localinstall(pkgs, yes=True)
c9ec78ca 307
47a4cb89
MT
308 def chrootPath(self, *args):
309 # Remove all leading slashes
310 _args = []
311 for arg in args:
312 if arg.startswith("/"):
313 arg = arg[1:]
314 _args.append(arg)
315 args = _args
316
317 ret = os.path.join(self.path, *args)
318 ret = ret.replace("//", "/")
319
320 assert ret.startswith(self.path)
321
322 return ret
323
324 def prepare(self):
677ff42a
MT
325 prepared_tag = ".prepared"
326
327 if os.path.exists(self.chrootPath(prepared_tag)):
328 return
329
47a4cb89
MT
330 # Create directory.
331 if not os.path.exists(self.path):
332 os.makedirs(self.path)
333
334 # Create important directories.
335 dirs = [
336 "build",
337 self.buildroot,
338 "dev",
339 "dev/pts",
340 "dev/shm",
341 "etc",
342 "proc",
343 "result",
344 "sys",
345 "tmp",
346 "usr/src",
347 ]
33f4679b
MT
348
349 # Create cache dir if ccache is enabled.
350 if self.settings.get("enable_ccache"):
351 dirs.append("var/cache/ccache")
352
353 if not os.path.exists(CCACHE_CACHE_DIR):
354 os.makedirs(CCACHE_CACHE_DIR)
355
47a4cb89
MT
356 for dir in dirs:
357 dir = self.chrootPath(dir)
358 if not os.path.exists(dir):
359 os.makedirs(dir)
360
6378690e
MT
361 # Create neccessary files like /etc/fstab and /etc/mtab.
362 files = (
363 "etc/fstab",
677ff42a
MT
364 "etc/mtab",
365 prepared_tag,
6378690e
MT
366 )
367
368 for file in files:
369 file = self.chrootPath(file)
370 dir = os.path.dirname(file)
371 if not os.path.exists(dir):
372 os.makedirs(dir)
373 f = open(file, "w")
374 f.close()
375
47a4cb89
MT
376 self._prepare_dns()
377
9a416dbc 378 def populate_dev(self):
47a4cb89 379 nodes = [
9a416dbc
MT
380 "/dev/null",
381 "/dev/zero",
382 "/dev/full",
383 "/dev/random",
384 "/dev/urandom",
385 "/dev/tty",
386 "/dev/ptmx",
387 "/dev/kmsg",
388 "/dev/rtc0",
389 "/dev/console",
47a4cb89
MT
390 ]
391
392 # If we need loop devices (which are optional) we create them here.
393 if self.settings["enable_loop_devices"]:
394 for i in range(0, 7):
9a416dbc 395 nodes.append("/dev/loop%d" % i)
47a4cb89 396
47a4cb89 397 for node in nodes:
9a416dbc
MT
398 # Stat the original node of the host system and copy it to
399 # the build chroot.
400 node_stat = os.stat(node)
401
402 self._create_node(node, node_stat.st_mode, node_stat.st_rdev)
47a4cb89
MT
403
404 os.symlink("/proc/self/fd/0", self.chrootPath("dev", "stdin"))
405 os.symlink("/proc/self/fd/1", self.chrootPath("dev", "stdout"))
406 os.symlink("/proc/self/fd/2", self.chrootPath("dev", "stderr"))
407 os.symlink("/proc/self/fd", self.chrootPath("dev", "fd"))
408
47a4cb89 409 def _prepare_dns(self):
18973967
MT
410 """
411 Add DNS resolution facility to chroot environment by copying
412 /etc/resolv.conf and /etc/hosts.
413 """
414 for i in ("/etc/resolv.conf", "/etc/hosts"):
415 self.copyin(i, i)
47a4cb89
MT
416
417 def _create_node(self, filename, mode, device):
418 logging.debug("Create node: %s (%s)" % (filename, mode))
419
420 filename = self.chrootPath(filename)
421
422 # Create parent directory if it is missing.
423 dirname = os.path.dirname(filename)
424 if not os.path.exists(dirname):
425 os.makedirs(dirname)
426
427 os.mknod(filename, mode, device)
428
526c3e7f 429 def destroy(self):
e412b8dc 430 logging.debug("Destroying environment %s" % self.path)
47a4cb89
MT
431
432 if os.path.exists(self.path):
433 util.rm(self.path)
434
e412b8dc
MT
435 def cleanup(self):
436 logging.debug("Cleaning environemnt.")
437
e412b8dc
MT
438 # Remove the build directory and buildroot.
439 dirs = ("build", self.buildroot, "result")
440
441 for d in dirs:
442 d = self.chrootPath(d)
443 if not os.path.exists(d):
444 continue
445
446 util.rm(d)
447 os.makedirs(d)
448
47a4cb89
MT
449 def _mountall(self):
450 self.log.debug("Mounting environment")
8930b228
MT
451 for src, dest, fs, options in self.mountpoints:
452 mountpoint = self.chrootPath(dest)
453 if options:
454 options = "-o %s" % options
455
456 # Eventually create mountpoint directory
457 if not os.path.exists(mountpoint):
458 os.makedirs(mountpoint)
459
460 cmd = "mount -n -t %s %s %s %s" % \
461 (fs, options, src, mountpoint)
93bd0aa4 462 chroot.do(cmd, shell=True)
47a4cb89
MT
463
464 def _umountall(self):
465 self.log.debug("Umounting environment")
8930b228
MT
466
467 mountpoints = []
468 for src, dest, fs, options in reversed(self.mountpoints):
469 if not dest in mountpoints:
470 mountpoints.append(dest)
471
472 for dest in mountpoints:
473 mountpoint = self.chrootPath(dest)
474
475 chroot.do("umount -n %s" % mountpoint, raiseExc=0, shell=True)
47a4cb89
MT
476
477 @property
478 def mountpoints(self):
8930b228
MT
479 mountpoints = []
480
481 # Make root as a tmpfs.
482 #mountpoints += [
483 # ("pakfire_root", "/", "tmpfs", "defaults"),
484 #]
485
486 mountpoints += [
487 # src, dest, fs, options
488 ("pakfire_proc", "/proc", "proc", "nosuid,noexec,nodev"),
489 ("/proc/sys", "/proc/sys", "bind", "bind"),
490 ("/proc/sys", "/proc/sys", "bind", "bind,ro,remount"),
491 ("/sys", "/sys", "bind", "bind"),
492 ("/sys", "/sys", "bind", "bind,ro,remount"),
493 ("pakfire_tmpfs", "/dev", "tmpfs", "mode=755,nosuid"),
494 ("/dev/pts", "/dev/pts", "bind", "bind"),
495 ("pakfire_tmpfs", "/run", "tmpfs", "mode=755,nosuid,nodev"),
47a4cb89
MT
496 ]
497
8930b228
MT
498 # If selinux is enabled.
499 if os.path.exists("/sys/fs/selinux"):
500 mountpoints += [
501 ("/sys/fs/selinux", "/sys/fs/selinux", "bind", "bind"),
502 ("/sys/fs/selinux", "/sys/fs/selinux", "bind", "bind,ro,remount"),
503 ]
47a4cb89 504
8930b228 505 # If ccache support is requested, we bind mount the cache.
33f4679b 506 if self.settings.get("enable_ccache"):
8930b228
MT
507 mountpoints += [
508 (CCACHE_CACHE_DIR, "/var/cache/ccache", "bind", "bind"),
509 ]
33f4679b 510
8930b228 511 return mountpoints
47a4cb89
MT
512
513 @property
514 def environ(self):
515 env = {
0cf10c2d
MT
516 # Add HOME manually, because it is occasionally not set
517 # and some builds get in trouble then.
518 "HOME" : "/root",
89ebac67
MT
519 "TERM" : os.environ.get("TERM", "dumb"),
520 "PS1" : "\u:\w\$ ",
0cf10c2d 521
47a4cb89 522 "BUILDROOT" : self.buildroot,
c07a3ca7 523 "PARALLELISMFLAGS" : "-j%s" % util.calc_parallelism(),
47a4cb89
MT
524 }
525
526 # Inherit environment from distro
527 env.update(self.pakfire.distro.environ)
528
5be98997 529 # Icecream environment settings
c07a3ca7 530 if self.settings.get("enable_icecream", False):
5be98997
MT
531 # Set the toolchain path
532 if self.settings.get("icecream_toolchain", None):
533 env["ICECC_VERSION"] = self.settings.get("icecream_toolchain")
534
535 # Set preferred host if configured.
536 if self.settings.get("icecream_preferred_host", None):
537 env["ICECC_PREFERRED_HOST"] = \
538 self.settings.get("icecream_preferred_host")
539
47a4cb89
MT
540 # XXX what do we need else?
541
542 return env
543
9eac53ba 544 def do(self, command, shell=True, personality=None, logger=None, *args, **kwargs):
47a4cb89 545 ret = None
47a4cb89 546
8930b228
MT
547 # Environment variables
548 env = self.environ
47a4cb89 549
8930b228
MT
550 if kwargs.has_key("env"):
551 env.update(kwargs.pop("env"))
15398910 552
8930b228
MT
553 logging.debug("Environment:")
554 for k, v in sorted(env.items()):
555 logging.debug(" %s=%s" % (k, v))
e360ea59 556
8930b228
MT
557 # Update personality it none was set
558 if not personality:
559 personality = self.distro.personality
5be98997 560
8930b228
MT
561 # Make every shell to a login shell because we set a lot of
562 # environment things there.
563 if shell:
564 command = ["bash", "--login", "-c", command]
47a4cb89 565
8930b228
MT
566 if not kwargs.has_key("chrootPath"):
567 kwargs["chrootPath"] = self.chrootPath()
47a4cb89 568
8930b228
MT
569 ret = chroot.do(
570 command,
571 personality=personality,
572 shell=False,
573 env=env,
574 logger=logger,
575 *args,
576 **kwargs
577 )
47a4cb89
MT
578
579 return ret
580
75bb74a7 581 def build(self, install_test=True):
c157d1e2
MT
582 assert self.pkg
583
c07a3ca7
MT
584 pkgfile = os.path.join("/build", os.path.basename(self.pkg.filename))
585 resultdir = self.chrootPath("/result")
586
587 # Create the build command, that is executed in the chroot.
9b875540 588 build_command = ["/usr/lib/pakfire/builder", "--offline", "build", pkgfile,
75bb74a7 589 "--nodeps", "--resultdir=/result",]
c07a3ca7
MT
590
591 try:
592 self.do(" ".join(build_command), logger=self.log)
593
594 except Error:
595 raise BuildError, _("The build command failed. See logfile for details.")
596
75bb74a7
MT
597 # Perform install test.
598 if install_test:
599 self.install_test()
600
c07a3ca7
MT
601 # Copy the final packages and stuff.
602 # XXX TODO resultdir
47a4cb89
MT
603
604 def shell(self, args=[]):
e9c20259
MT
605 if not util.cli_is_interactive():
606 logging.warning("Cannot run shell on non-interactive console.")
607 return
608
9c2ad426
MT
609 # Install all packages that are needed to run a shell.
610 self.install(SHELL_PACKAGES)
611
47a4cb89 612 # XXX need to set CFLAGS here
a7596ccf 613 command = "/usr/sbin/chroot %s /usr/bin/chroot-shell %s" % \
47a4cb89
MT
614 (self.chrootPath(), " ".join(args))
615
e360ea59
MT
616 # Add personality if we require one
617 if self.pakfire.distro.personality:
a7596ccf
MT
618 command = "%s %s" % (self.pakfire.distro.personality, command)
619
620 for key, val in self.environ.items():
621 command = "%s=\"%s\" " % (key, val) + command
e360ea59 622
47a4cb89 623 # Empty the environment
a7596ccf 624 command = "env -i - %s" % command
47a4cb89
MT
625
626 logging.debug("Shell command: %s" % command)
627
8930b228
MT
628 shell = os.system(command)
629 return os.WEXITSTATUS(shell)
c07a3ca7 630
56f5e5ff 631
ff9299d0 632class Builder(object):
c07a3ca7
MT
633 def __init__(self, pakfire, filename, resultdir, **kwargs):
634 self.pakfire = pakfire
635
636 self.filename = filename
637
638 self.resultdir = resultdir
639
640 # Open package file.
641 self.pkg = packages.Makefile(self.pakfire, self.filename)
642
643 #self.buildroot = "/tmp/pakfire_buildroot/%s" % util.random_string(20)
644 self.buildroot = "/buildroot"
645
646 self._environ = {
647 "BUILDROOT" : self.buildroot,
648 "LANG" : "C",
649 }
650
651 @property
652 def distro(self):
653 return self.pakfire.distro
654
655 @property
656 def environ(self):
657 environ = os.environ
3c45a6af
MT
658
659 # Get all definitions from the package.
660 environ.update(self.pkg.exports)
661
662 # Overwrite some definitions by default values.
c07a3ca7
MT
663 environ.update(self._environ)
664
665 return environ
666
667 def do(self, command, shell=True, personality=None, cwd=None, *args, **kwargs):
668 # Environment variables
669 logging.debug("Environment:")
670 for k, v in sorted(self.environ.items()):
671 logging.debug(" %s=%s" % (k, v))
672
673 # Update personality it none was set
674 if not personality:
675 personality = self.distro.personality
676
677 if not cwd:
678 cwd = "/%s" % LOCAL_TMP_PATH
679
680 # Make every shell to a login shell because we set a lot of
681 # environment things there.
682 if shell:
683 command = ["bash", "--login", "-c", command]
684
685 return chroot.do(
686 command,
687 personality=personality,
688 shell=False,
689 env=self.environ,
690 logger=logging.getLogger(),
691 cwd=cwd,
692 *args,
693 **kwargs
694 )
695
696 def create_icecream_toolchain(self):
697 try:
9c6179fb 698 out = self.do("icecc --build-native 2>/dev/null", returnOutput=True)
c07a3ca7
MT
699 except Error:
700 return
701
702 for line in out.splitlines():
703 m = re.match(r"^creating ([a-z0-9]+\.tar\.gz)", line)
704 if m:
705 self._environ["icecream_toolchain"] = "/%s" % m.group(1)
706
707 def create_buildscript(self, stage):
708 file = "/tmp/build_%s" % util.random_string()
709
710 # Get buildscript from the package.
711 script = self.pkg.get_buildscript(stage)
712
713 # Write script to an empty file.
714 f = open(file, "w")
715 f.write("#!/bin/sh\n\n")
716 f.write("set -e\n")
717 f.write("set -x\n")
718 f.write("\n%s\n" % script)
719 f.write("exit 0\n")
720 f.close()
721 os.chmod(file, 700)
722
723 return file
724
725 def build(self):
726 # Create buildroot.
727 if not os.path.exists(self.buildroot):
728 os.makedirs(self.buildroot)
729
730 # Build icecream toolchain if icecream is installed.
731 self.create_icecream_toolchain()
732
733 for stage in ("prepare", "build", "test", "install"):
734 self.build_stage(stage)
735
736 # Package the result.
737 # Make all these little package from the build environment.
738 logging.info(_("Creating packages:"))
56f5e5ff 739 pkgs = []
c07a3ca7 740 for pkg in reversed(self.pkg.packages):
5dda54e4
MT
741 packager = packages.packager.BinaryPackager(self.pakfire, pkg,
742 self, self.buildroot)
56f5e5ff
MT
743 pkg = packager.run(self.resultdir)
744 pkgs.append(pkg)
745 logging.info("")
746
747 for pkg in sorted(pkgs):
748 for line in pkg.dump(long=True).splitlines():
749 logging.info(line)
750 logging.info("")
c07a3ca7
MT
751 logging.info("")
752
753 def build_stage(self, stage):
754 # Get the buildscript for this stage.
755 buildscript = self.create_buildscript(stage)
756
757 # Execute the buildscript of this stage.
758 logging.info(_("Running stage %s:") % stage)
c07a3ca7 759
75bb74a7
MT
760 try:
761 self.do(buildscript, shell=False)
762
763 finally:
764 # Remove the buildscript.
765 if os.path.exists(buildscript):
766 os.unlink(buildscript)
c07a3ca7
MT
767
768 def cleanup(self):
769 if os.path.exists(self.buildroot):
770 util.rm(self.buildroot)