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