blob: 39ea736b58842bb3676ced7355ec9bd517c6fb6f [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002# BitBake Toaster Implementation
3#
4# Copyright (C) 2014 Intel Corporation
5#
Brad Bishopc342db32019-05-15 21:57:59 -04006# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -05007#
Patrick Williamsc124f4f2015-09-15 14:41:29 -05008
9import os
10import sys
11import re
Patrick Williamsf1e5d692016-03-30 15:21:19 -050012import shutil
Brad Bishopd7bf8c12018-02-25 22:55:05 -050013import time
Patrick Williamsc124f4f2015-09-15 14:41:29 -050014from django.db import transaction
15from django.db.models import Q
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080016from bldcontrol.models import BuildEnvironment, BuildRequest, BRLayer, BRVariable, BRTarget, BRBitbake, Build
17from orm.models import CustomImageRecipe, Layer, Layer_Version, Project, ProjectLayer, ToasterSetting
18from orm.models import signal_runbuilds
Patrick Williamsc124f4f2015-09-15 14:41:29 -050019import subprocess
20
21from toastermain import settings
22
Patrick Williamsc0f7c042017-02-23 20:41:17 -060023from bldcontrol.bbcontroller import BuildEnvironmentController, ShellCmdException, BuildSetupException, BitbakeController
Patrick Williamsc124f4f2015-09-15 14:41:29 -050024
25import logging
26logger = logging.getLogger("toaster")
27
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080028install_dir = os.environ.get('TOASTER_DIR')
29
Patrick Williamsc124f4f2015-09-15 14:41:29 -050030from pprint import pprint, pformat
31
32class LocalhostBEController(BuildEnvironmentController):
33 """ Implementation of the BuildEnvironmentController for the localhost;
34 this controller manages the default build directory,
35 the server setup and system start and stop for the localhost-type build environment
36
37 """
38
39 def __init__(self, be):
40 super(LocalhostBEController, self).__init__(be)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050041 self.pokydirname = None
42 self.islayerset = False
43
Brad Bishopd7bf8c12018-02-25 22:55:05 -050044 def _shellcmd(self, command, cwd=None, nowait=False,env=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050045 if cwd is None:
46 cwd = self.be.sourcedir
Brad Bishopd7bf8c12018-02-25 22:55:05 -050047 if env is None:
48 env=os.environ.copy()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049
Brad Bishopd7bf8c12018-02-25 22:55:05 -050050 logger.debug("lbc_shellcmd: (%s) %s" % (cwd, command))
51 p = subprocess.Popen(command, cwd = cwd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050052 if nowait:
53 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -050054 (out,err) = p.communicate()
55 p.wait()
56 if p.returncode:
57 if len(err) == 0:
58 err = "command: %s \n%s" % (command, out)
59 else:
60 err = "command: %s \n%s" % (command, err)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060061 logger.warning("localhostbecontroller: shellcmd error %s" % err)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050062 raise ShellCmdException(err)
63 else:
64 logger.debug("localhostbecontroller: shellcmd success")
Patrick Williamsc0f7c042017-02-23 20:41:17 -060065 return out.decode('utf-8')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050066
Patrick Williamsc124f4f2015-09-15 14:41:29 -050067 def getGitCloneDirectory(self, url, branch):
Patrick Williamsf1e5d692016-03-30 15:21:19 -050068 """Construct unique clone directory name out of url and branch."""
Patrick Williamsc124f4f2015-09-15 14:41:29 -050069 if branch != "HEAD":
Patrick Williamsc0f7c042017-02-23 20:41:17 -060070 return "_toaster_clones/_%s_%s" % (re.sub('[:/@+%]', '_', url), branch)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050071
72 # word of attention; this is a localhost-specific issue; only on the localhost we expect to have "HEAD" releases
73 # which _ALWAYS_ means the current poky checkout
74 from os.path import dirname as DN
75 local_checkout_path = DN(DN(DN(DN(DN(os.path.abspath(__file__))))))
76 #logger.debug("localhostbecontroller: using HEAD checkout in %s" % local_checkout_path)
77 return local_checkout_path
78
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080079 def setCloneStatus(self,bitbake,status,total,current,repo_name):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050080 bitbake.req.build.repos_cloned=current
81 bitbake.req.build.repos_to_clone=total
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080082 bitbake.req.build.progress_item=repo_name
Brad Bishopd7bf8c12018-02-25 22:55:05 -050083 bitbake.req.build.save()
84
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050085 def setLayers(self, bitbake, layers, targets):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050086 """ a word of attention: by convention, the first layer for any build will be poky! """
87
88 assert self.be.sourcedir is not None
Patrick Williamsc0f7c042017-02-23 20:41:17 -060089
90 layerlist = []
91 nongitlayerlist = []
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080092 layer_index = 0
Brad Bishopd7bf8c12018-02-25 22:55:05 -050093 git_env = os.environ.copy()
94 # (note: add custom environment settings here)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060095
Patrick Williamsc124f4f2015-09-15 14:41:29 -050096 # set layers in the layersource
97
98 # 1. get a list of repos with branches, and map dirpaths for each layer
99 gitrepos = {}
100
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600101 # if we're using a remotely fetched version of bitbake add its git
102 # details to the list of repos to clone
103 if bitbake.giturl and bitbake.commit:
104 gitrepos[(bitbake.giturl, bitbake.commit)] = []
105 gitrepos[(bitbake.giturl, bitbake.commit)].append(
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800106 ("bitbake", bitbake.dirpath, 0))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500107
108 for layer in layers:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500109 # We don't need to git clone the layer for the CustomImageRecipe
110 # as it's generated by us layer on if needed
111 if CustomImageRecipe.LAYER_NAME in layer.name:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500112 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600113
114 # If we have local layers then we don't need clone them
115 # For local layers giturl will be empty
116 if not layer.giturl:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800117 nongitlayerlist.append( "%03d:%s" % (layer_index,layer.local_source_dir) )
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600118 continue
119
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500120 if not (layer.giturl, layer.commit) in gitrepos:
121 gitrepos[(layer.giturl, layer.commit)] = []
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800122 gitrepos[(layer.giturl, layer.commit)].append( (layer.name,layer.dirpath,layer_index) )
123 layer_index += 1
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500124
125
126 logger.debug("localhostbecontroller, our git repos are %s" % pformat(gitrepos))
127
128
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500129 # 2. Note for future use if the current source directory is a
130 # checked-out git repos that could match a layer's vcs_url and therefore
131 # be used to speed up cloning (rather than fetching it again).
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500132
133 cached_layers = {}
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500134
135 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500136 for remotes in self._shellcmd("git remote -v", self.be.sourcedir,env=git_env).split("\n"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500137 try:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500138 remote = remotes.split("\t")[1].split(" ")[0]
139 if remote not in cached_layers:
140 cached_layers[remote] = self.be.sourcedir
141 except IndexError:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500142 pass
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500143 except ShellCmdException:
144 # ignore any errors in collecting git remotes this is an optional
145 # step
146 pass
147
148 logger.info("Using pre-checked out source for layer %s", cached_layers)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500149
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500150 # 3. checkout the repositories
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500151 clone_count=0
152 clone_total=len(gitrepos.keys())
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800153 self.setCloneStatus(bitbake,'Started',clone_total,clone_count,'')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500154 for giturl, commit in gitrepos.keys():
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800155 self.setCloneStatus(bitbake,'progress',clone_total,clone_count,gitrepos[(giturl, commit)][0][0])
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500156 clone_count += 1
157
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500158 localdirname = os.path.join(self.be.sourcedir, self.getGitCloneDirectory(giturl, commit))
159 logger.debug("localhostbecontroller: giturl %s:%s checking out in current directory %s" % (giturl, commit, localdirname))
160
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600161 # see if our directory is a git repository
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500162 if os.path.exists(localdirname):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600163 try:
164 localremotes = self._shellcmd("git remote -v",
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500165 localdirname,env=git_env)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800166 # NOTE: this nice-to-have check breaks when using git remaping to get past firewall
167 # Re-enable later with .gitconfig remapping checks
168 #if not giturl in localremotes and commit != 'HEAD':
169 # raise BuildSetupException("Existing git repository at %s, but with different remotes ('%s', expected '%s'). Toaster will not continue out of fear of damaging something." % (localdirname, ", ".join(localremotes.split("\n")), giturl))
170 pass
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600171 except ShellCmdException:
172 # our localdirname might not be a git repository
173 #- that's fine
174 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500175 else:
176 if giturl in cached_layers:
177 logger.debug("localhostbecontroller git-copying %s to %s" % (cached_layers[giturl], localdirname))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500178 self._shellcmd("git clone \"%s\" \"%s\"" % (cached_layers[giturl], localdirname),env=git_env)
179 self._shellcmd("git remote remove origin", localdirname,env=git_env)
180 self._shellcmd("git remote add origin \"%s\"" % giturl, localdirname,env=git_env)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500181 else:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500182 logger.debug("localhostbecontroller: cloning %s in %s" % (giturl, localdirname))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500183 self._shellcmd('git clone "%s" "%s"' % (giturl, localdirname),env=git_env)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500184
185 # branch magic name "HEAD" will inhibit checkout
186 if commit != "HEAD":
187 logger.debug("localhostbecontroller: checking out commit %s to %s " % (commit, localdirname))
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500188 ref = commit if re.match('^[a-fA-F0-9]+$', commit) else 'origin/%s' % commit
Brad Bishop316dfdd2018-06-25 12:45:53 -0400189 self._shellcmd('git fetch && git reset --hard "%s"' % ref, localdirname,env=git_env)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500190
191 # take the localdirname as poky dir if we can find the oe-init-build-env
192 if self.pokydirname is None and os.path.exists(os.path.join(localdirname, "oe-init-build-env")):
193 logger.debug("localhostbecontroller: selected poky dir name %s" % localdirname)
194 self.pokydirname = localdirname
195
196 # make sure we have a working bitbake
197 if not os.path.exists(os.path.join(self.pokydirname, 'bitbake')):
198 logger.debug("localhostbecontroller: checking bitbake into the poky dirname %s " % self.pokydirname)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500199 self._shellcmd("git clone -b \"%s\" \"%s\" \"%s\" " % (bitbake.commit, bitbake.giturl, os.path.join(self.pokydirname, 'bitbake')),env=git_env)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500200
201 # verify our repositories
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800202 for name, dirpath, index in gitrepos[(giturl, commit)]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500203 localdirpath = os.path.join(localdirname, dirpath)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800204 logger.debug("localhostbecontroller: localdirpath expects '%s'" % localdirpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500205 if not os.path.exists(localdirpath):
206 raise BuildSetupException("Cannot find layer git path '%s' in checked out repository '%s:%s'. Aborting." % (localdirpath, giturl, commit))
207
208 if name != "bitbake":
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800209 layerlist.append("%03d:%s" % (index,localdirpath.rstrip("/")))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500210
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800211 self.setCloneStatus(bitbake,'complete',clone_total,clone_count,'')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500212 logger.debug("localhostbecontroller: current layer list %s " % pformat(layerlist))
213
Brad Bishop5dd7cbb2018-09-05 22:26:40 -0700214 # Resolve self.pokydirname if not resolved yet, consider the scenario
215 # where all layers are local, that's the else clause
216 if self.pokydirname is None:
217 if os.path.exists(os.path.join(self.be.sourcedir, "oe-init-build-env")):
218 logger.debug("localhostbecontroller: selected poky dir name %s" % self.be.sourcedir)
219 self.pokydirname = self.be.sourcedir
220 else:
221 # Alternatively, scan local layers for relative "oe-init-build-env" location
222 for layer in layers:
223 if os.path.exists(os.path.join(layer.layer_version.layer.local_source_dir,"..","oe-init-build-env")):
224 logger.debug("localhostbecontroller, setting pokydirname to %s" % (layer.layer_version.layer.local_source_dir))
225 self.pokydirname = os.path.join(layer.layer_version.layer.local_source_dir,"..")
226 break
227 else:
228 logger.error("pokydirname is not set, you will run into trouble!")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500229
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500230 # 5. create custom layer and add custom recipes to it
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500231 for target in targets:
232 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500233 customrecipe = CustomImageRecipe.objects.get(
234 name=target.target,
235 project=bitbake.req.project)
236
237 custom_layer_path = self.setup_custom_image_recipe(
238 customrecipe, layers)
239
240 if os.path.isdir(custom_layer_path):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800241 layerlist.append("%03d:%s" % (layer_index,custom_layer_path))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500242
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500243 except CustomImageRecipe.DoesNotExist:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500244 continue # not a custom recipe, skip
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500245
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600246 layerlist.extend(nongitlayerlist)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500247 logger.debug("\n\nset layers gives this list %s" % pformat(layerlist))
248 self.islayerset = True
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800249
250 # restore the order of layer list for bblayers.conf
251 layerlist.sort()
252 sorted_layerlist = [l[4:] for l in layerlist]
253 return sorted_layerlist
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500254
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500255 def setup_custom_image_recipe(self, customrecipe, layers):
256 """ Set up toaster-custom-images layer and recipe files """
257 layerpath = os.path.join(self.be.builddir,
258 CustomImageRecipe.LAYER_NAME)
259
260 # create directory structure
261 for name in ("conf", "recipes"):
262 path = os.path.join(layerpath, name)
263 if not os.path.isdir(path):
264 os.makedirs(path)
265
266 # create layer.conf
267 config = os.path.join(layerpath, "conf", "layer.conf")
268 if not os.path.isfile(config):
269 with open(config, "w") as conf:
270 conf.write('BBPATH .= ":${LAYERDIR}"\nBBFILES += "${LAYERDIR}/recipes/*.bb"\n')
271
272 # Update the Layer_Version dirpath that has our base_recipe in
273 # to be able to read the base recipe to then generate the
274 # custom recipe.
275 br_layer_base_recipe = layers.get(
276 layer_version=customrecipe.base_recipe.layer_version)
277
278 # If the layer is one that we've cloned we know where it lives
279 if br_layer_base_recipe.giturl and br_layer_base_recipe.commit:
280 layer_path = self.getGitCloneDirectory(
281 br_layer_base_recipe.giturl,
282 br_layer_base_recipe.commit)
283 # Otherwise it's a local layer
284 elif br_layer_base_recipe.local_source_dir:
285 layer_path = br_layer_base_recipe.local_source_dir
286 else:
287 logger.error("Unable to workout the dir path for the custom"
288 " image recipe")
289
290 br_layer_base_dirpath = os.path.join(
291 self.be.sourcedir,
292 layer_path,
293 customrecipe.base_recipe.layer_version.dirpath)
294
295 customrecipe.base_recipe.layer_version.dirpath = br_layer_base_dirpath
296
297 customrecipe.base_recipe.layer_version.save()
298
299 # create recipe
300 recipe_path = os.path.join(layerpath, "recipes", "%s.bb" %
301 customrecipe.name)
302 with open(recipe_path, "w") as recipef:
303 recipef.write(customrecipe.generate_recipe_file_contents())
304
305 # Update the layer and recipe objects
306 customrecipe.layer_version.dirpath = layerpath
307 customrecipe.layer_version.layer.local_source_dir = layerpath
308 customrecipe.layer_version.layer.save()
309 customrecipe.layer_version.save()
310
311 customrecipe.file_path = recipe_path
312 customrecipe.save()
313
314 return layerpath
315
316
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500317 def readServerLogFile(self):
318 return open(os.path.join(self.be.builddir, "toaster_server.log"), "r").read()
319
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500320
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500321 def triggerBuild(self, bitbake, layers, variables, targets, brbe):
322 layers = self.setLayers(bitbake, layers, targets)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800323 is_merged_attr = bitbake.req.project.merged_attr
324
325 git_env = os.environ.copy()
326 # (note: add custom environment settings here)
327 try:
328 # insure that the project init/build uses the selected bitbake, and not Toaster's
329 del git_env['TEMPLATECONF']
330 del git_env['BBBASEDIR']
331 del git_env['BUILDDIR']
332 except KeyError:
333 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500334
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500335 # init build environment from the clone
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800336 if bitbake.req.project.builddir:
337 builddir = bitbake.req.project.builddir
338 else:
339 builddir = '%s-toaster-%d' % (self.be.builddir, bitbake.req.project.id)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500340 oe_init = os.path.join(self.pokydirname, 'oe-init-build-env')
341 # init build environment
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500342 try:
343 custom_script = ToasterSetting.objects.get(name="CUSTOM_BUILD_INIT_SCRIPT").value
344 custom_script = custom_script.replace("%BUILDDIR%" ,builddir)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800345 self._shellcmd("bash -c 'source %s'" % (custom_script),env=git_env)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500346 except ToasterSetting.DoesNotExist:
347 self._shellcmd("bash -c 'source %s %s'" % (oe_init, builddir),
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800348 self.be.sourcedir,env=git_env)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500349
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500350 # update bblayers.conf
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800351 if not is_merged_attr:
352 bblconfpath = os.path.join(builddir, "conf/toaster-bblayers.conf")
353 with open(bblconfpath, 'w') as bblayers:
354 bblayers.write('# line added by toaster build control\n'
355 'BBLAYERS = "%s"' % ' '.join(layers))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500356
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800357 # write configuration file
358 confpath = os.path.join(builddir, 'conf/toaster.conf')
359 with open(confpath, 'w') as conf:
360 for var in variables:
361 conf.write('%s="%s"\n' % (var.name, var.value))
362 conf.write('INHERIT+="toaster buildhistory"')
363 else:
364 # Append the Toaster-specific values directly to the bblayers.conf
365 bblconfpath = os.path.join(builddir, "conf/bblayers.conf")
366 bblconfpath_save = os.path.join(builddir, "conf/bblayers.conf.save")
367 shutil.copyfile(bblconfpath, bblconfpath_save)
368 with open(bblconfpath) as bblayers:
369 content = bblayers.readlines()
370 do_write = True
371 was_toaster = False
372 with open(bblconfpath,'w') as bblayers:
373 for line in content:
374 #line = line.strip('\n')
375 if 'TOASTER_CONFIG_PROLOG' in line:
376 do_write = False
377 was_toaster = True
378 elif 'TOASTER_CONFIG_EPILOG' in line:
379 do_write = True
380 elif do_write:
381 bblayers.write(line)
382 if not was_toaster:
383 bblayers.write('\n')
384 bblayers.write('#=== TOASTER_CONFIG_PROLOG ===\n')
385 bblayers.write('BBLAYERS = "\\\n')
386 for layer in layers:
387 bblayers.write(' %s \\\n' % layer)
388 bblayers.write(' "\n')
389 bblayers.write('#=== TOASTER_CONFIG_EPILOG ===\n')
390 # Append the Toaster-specific values directly to the local.conf
391 bbconfpath = os.path.join(builddir, "conf/local.conf")
392 bbconfpath_save = os.path.join(builddir, "conf/local.conf.save")
393 shutil.copyfile(bbconfpath, bbconfpath_save)
394 with open(bbconfpath) as f:
395 content = f.readlines()
396 do_write = True
397 was_toaster = False
398 with open(bbconfpath,'w') as conf:
399 for line in content:
400 #line = line.strip('\n')
401 if 'TOASTER_CONFIG_PROLOG' in line:
402 do_write = False
403 was_toaster = True
404 elif 'TOASTER_CONFIG_EPILOG' in line:
405 do_write = True
406 elif do_write:
407 conf.write(line)
408 if not was_toaster:
409 conf.write('\n')
410 conf.write('#=== TOASTER_CONFIG_PROLOG ===\n')
411 for var in variables:
412 if (not var.name.startswith("INTERNAL_")) and (not var.name == "BBLAYERS"):
413 conf.write('%s="%s"\n' % (var.name, var.value))
414 conf.write('#=== TOASTER_CONFIG_EPILOG ===\n')
415
416 # If 'target' is just the project preparation target, then we are done
417 for target in targets:
418 if "_PROJECT_PREPARE_" == target.target:
419 logger.debug('localhostbecontroller: Project has been prepared. Done.')
420 # Update the Build Request and release the build environment
421 bitbake.req.state = BuildRequest.REQ_COMPLETED
422 bitbake.req.save()
423 self.be.lock = BuildEnvironment.LOCK_FREE
424 self.be.save()
425 # Close the project build and progress bar
426 bitbake.req.build.outcome = Build.SUCCEEDED
427 bitbake.req.build.save()
428 # Update the project status
429 bitbake.req.project.set_variable(Project.PROJECT_SPECIFIC_STATUS,Project.PROJECT_SPECIFIC_CLONING_SUCCESS)
430 signal_runbuilds()
431 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500432
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500433 # clean the Toaster to build environment
434 env_clean = 'unset BBPATH;' # clean BBPATH for <= YP-2.4.0
435
Brad Bishop5dd7cbb2018-09-05 22:26:40 -0700436 # run bitbake server from the clone if available
437 # otherwise pick it from the PATH
438 bitbake = os.path.join(self.pokydirname, 'bitbake', 'bin', 'bitbake')
439 if not os.path.exists(bitbake):
440 logger.info("Bitbake not available under %s, will try to use it from PATH" %
441 self.pokydirname)
442 for path in os.environ["PATH"].split(os.pathsep):
443 if os.path.exists(os.path.join(path, 'bitbake')):
444 bitbake = os.path.join(path, 'bitbake')
445 break
446 else:
447 logger.error("Looks like Bitbake is not available, please fix your environment")
448
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500449 toasterlayers = os.path.join(builddir,"conf/toaster-bblayers.conf")
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800450 if not is_merged_attr:
451 self._shellcmd('%s bash -c \"source %s %s; BITBAKE_UI="knotty" %s --read %s --read %s '
452 '--server-only -B 0.0.0.0:0\"' % (env_clean, oe_init,
453 builddir, bitbake, confpath, toasterlayers), self.be.sourcedir)
454 else:
455 self._shellcmd('%s bash -c \"source %s %s; BITBAKE_UI="knotty" %s '
456 '--server-only -B 0.0.0.0:0\"' % (env_clean, oe_init,
457 builddir, bitbake), self.be.sourcedir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500458
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500459 # read port number from bitbake.lock
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500460 self.be.bbport = -1
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500461 bblock = os.path.join(builddir, 'bitbake.lock')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500462 # allow 10 seconds for bb lock file to appear but also be populated
463 for lock_check in range(10):
464 if not os.path.exists(bblock):
465 logger.debug("localhostbecontroller: waiting for bblock file to appear")
466 time.sleep(1)
467 continue
468 if 10 < os.stat(bblock).st_size:
469 break
470 logger.debug("localhostbecontroller: waiting for bblock content to appear")
471 time.sleep(1)
472 else:
473 raise BuildSetupException("Cannot find bitbake server lock file '%s'. Aborting." % bblock)
474
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500475 with open(bblock) as fplock:
476 for line in fplock:
477 if ":" in line:
478 self.be.bbport = line.split(":")[-1].strip()
479 logger.debug("localhostbecontroller: bitbake port %s", self.be.bbport)
480 break
481
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500482 if -1 == self.be.bbport:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500483 raise BuildSetupException("localhostbecontroller: can't read bitbake port from %s" % bblock)
484
485 self.be.bbaddress = "localhost"
486 self.be.bbstate = BuildEnvironment.SERVER_STARTED
487 self.be.lock = BuildEnvironment.LOCK_RUNNING
488 self.be.save()
489
490 bbtargets = ''
491 for target in targets:
492 task = target.task
493 if task:
494 if not task.startswith('do_'):
495 task = 'do_' + task
496 task = ':%s' % task
497 bbtargets += '%s%s ' % (target.target, task)
498
499 # run build with local bitbake. stop the server after the build.
500 log = os.path.join(builddir, 'toaster_ui.log')
501 local_bitbake = os.path.join(os.path.dirname(os.getenv('BBBASEDIR')),
502 'bitbake')
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800503 if not is_merged_attr:
504 self._shellcmd(['%s bash -c \"(TOASTER_BRBE="%s" BBSERVER="0.0.0.0:%s" '
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500505 '%s %s -u toasterui --read %s --read %s --token="" >>%s 2>&1;'
506 'BITBAKE_UI="knotty" BBSERVER=0.0.0.0:%s %s -m)&\"' \
507 % (env_clean, brbe, self.be.bbport, local_bitbake, bbtargets, confpath, toasterlayers, log,
508 self.be.bbport, bitbake,)],
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500509 builddir, nowait=True)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800510 else:
511 self._shellcmd(['%s bash -c \"(TOASTER_BRBE="%s" BBSERVER="0.0.0.0:%s" '
512 '%s %s -u toasterui --token="" >>%s 2>&1;'
513 'BITBAKE_UI="knotty" BBSERVER=0.0.0.0:%s %s -m)&\"' \
514 % (env_clean, brbe, self.be.bbport, local_bitbake, bbtargets, log,
515 self.be.bbport, bitbake,)],
516 builddir, nowait=True)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500517
518 logger.debug('localhostbecontroller: Build launched, exiting. '
519 'Follow build logs at %s' % log)