1import os 2import shutil 3import subprocess 4 5import infra 6 7 8class Builder(object): 9 def __init__(self, config, builddir, logtofile): 10 self.config = '\n'.join([line.lstrip() for line in 11 config.splitlines()]) + '\n' 12 self.builddir = builddir 13 self.logfile = infra.open_log_file(builddir, "build", logtofile) 14 15 def is_defconfig_valid(self, configfile, defconfig): 16 """Check if the .config is contains all lines present in the defconfig.""" 17 with open(configfile) as configf: 18 configlines = configf.readlines() 19 20 defconfiglines = defconfig.split("\n") 21 22 # Check that all the defconfig lines are still present 23 for defconfigline in defconfiglines: 24 if defconfigline + "\n" not in configlines: 25 self.logfile.write("WARN: defconfig can't be used\n") 26 self.logfile.write(" Missing: %s\n" % defconfigline.strip()) 27 self.logfile.flush() 28 return False 29 30 return True 31 32 def configure(self, make_extra_opts=[], make_extra_env={}): 33 """Configure the build. 34 35 make_extra_opts: a list of arguments to be passed to the make 36 command. 37 e.g. make_extra_opts=["BR2_EXTERNAL=/path"] 38 39 make_extra_env: a dict of variables to be appended (or replaced) 40 in the environment that calls make. 41 e.g. make_extra_env={"BR2_DL_DIR": "/path"} 42 """ 43 if not os.path.isdir(self.builddir): 44 os.makedirs(self.builddir) 45 46 config_file = os.path.join(self.builddir, ".config") 47 with open(config_file, "w+") as cf: 48 cf.write(self.config) 49 # dump the defconfig to the logfile for easy debugging 50 self.logfile.write("> start defconfig\n" + self.config + 51 "> end defconfig\n") 52 self.logfile.flush() 53 54 env = {"PATH": os.environ["PATH"]} 55 env.update(make_extra_env) 56 57 cmd = ["make", 58 "O={}".format(self.builddir)] 59 cmd += make_extra_opts 60 cmd += ["olddefconfig"] 61 62 ret = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile, 63 cwd=infra.basepath(), env=env) 64 if ret != 0: 65 raise SystemError("Cannot olddefconfig") 66 67 if not self.is_defconfig_valid(config_file, self.config): 68 raise SystemError("The defconfig is not valid") 69 70 def build(self, make_extra_opts=[], make_extra_env={}): 71 """Perform the build. 72 73 make_extra_opts: a list of arguments to be passed to the make 74 command. It can include a make target. 75 e.g. make_extra_opts=["foo-source"] 76 77 make_extra_env: a dict of variables to be appended (or replaced) 78 in the environment that calls make. 79 e.g. make_extra_env={"BR2_DL_DIR": "/path"} 80 """ 81 env = {"PATH": os.environ["PATH"]} 82 if "http_proxy" in os.environ: 83 self.logfile.write("Using system proxy: " + 84 os.environ["http_proxy"] + "\n") 85 env['http_proxy'] = os.environ["http_proxy"] 86 env['https_proxy'] = os.environ["http_proxy"] 87 env.update(make_extra_env) 88 89 cmd = ["make", "-C", self.builddir] 90 cmd += make_extra_opts 91 92 ret = subprocess.call(cmd, stdout=self.logfile, stderr=self.logfile, 93 env=env) 94 if ret != 0: 95 raise SystemError("Build failed") 96 97 open(self.stamp_path(), 'a').close() 98 99 def stamp_path(self): 100 return os.path.join(self.builddir, "build-done") 101 102 def is_finished(self): 103 return os.path.exists(self.stamp_path()) 104 105 def delete(self): 106 if os.path.exists(self.builddir): 107 shutil.rmtree(self.builddir) 108