mirror of
https://git.yoctoproject.org/poky
synced 2026-03-04 06:19:40 +01:00
This adds support for the new bitbake-setup:
* Maintain backwards compatibility for poky-classic releases
* Assume bitbake-setup for all releases 'master' and forward
* When no ".templateconf" assume Poky and not OE
* Generate and use "init-build-env" script instead of 'oe-init-build-env'
directly, but "cd" to the clone and not the local installation.
* Include "bblayers.conf" because "cookerdata.py" now explicitly
required it, and let it be over-ridden by the usual "toaster-bblayers.conf".
* Force the value "TOPDIR" in "toaster.conf" to the local project's directory.
Normally "cookerdata.py" sets TOPDIR from getcwd(), but somehow in bitbake-setup
mode the CWD at this point has become ".../layers/openembedded-core", so
"bitbake.conf and all other files cannot be found. This non-obvious problem was
hard to discover. Until this is understood, the forced value will make things work.
[YOCTO #16012]
(Bitbake rev: 22b3fd418efc10da7e4a8c1725de285714d2396b)
Signed-off-by: David Reyna <David.Reyna@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
568 lines
26 KiB
Python
568 lines
26 KiB
Python
#
|
|
# BitBake Toaster Implementation
|
|
#
|
|
# Copyright (C) 2014 Intel Corporation
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-only
|
|
#
|
|
|
|
# DEBUGGING NOTE: if you need to add debug statements into the files within a
|
|
# Toaster-imported layer, you must disable the "git fetch ..." command after
|
|
# the initial clone else any changes will be automatically replaced with the
|
|
# original code
|
|
|
|
import os
|
|
import re
|
|
import shutil
|
|
import time
|
|
from bldcontrol.models import BuildEnvironment, BuildRequest, Build
|
|
from orm.models import CustomImageRecipe, Layer, Layer_Version, Project, ToasterSetting
|
|
from orm.models import signal_runbuilds
|
|
import subprocess
|
|
|
|
from toastermain import settings
|
|
|
|
from bldcontrol.bbcontroller import BuildEnvironmentController, ShellCmdException, BuildSetupException
|
|
|
|
import logging
|
|
logger = logging.getLogger("toaster")
|
|
|
|
install_dir = os.environ.get('TOASTER_DIR')
|
|
|
|
from pprint import pformat
|
|
|
|
class LocalhostBEController(BuildEnvironmentController):
|
|
""" Implementation of the BuildEnvironmentController for the localhost;
|
|
this controller manages the default build directory,
|
|
the server setup and system start and stop for the localhost-type build environment
|
|
|
|
"""
|
|
|
|
def __init__(self, be):
|
|
super(LocalhostBEController, self).__init__(be)
|
|
self.pokydirname = None
|
|
self.islayerset = False
|
|
|
|
def _shellcmd(self, command, cwd=None, nowait=False,env=None):
|
|
if cwd is None:
|
|
cwd = self.be.sourcedir
|
|
if env is None:
|
|
env=os.environ.copy()
|
|
|
|
logger.debug("lbc_shellcmd: (%s) %s" % (cwd, command))
|
|
p = subprocess.Popen(command, cwd = cwd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
|
|
if nowait:
|
|
return
|
|
(out,err) = p.communicate()
|
|
p.wait()
|
|
if p.returncode:
|
|
if len(err) == 0:
|
|
err = "command: %s \n%s" % (command, out)
|
|
else:
|
|
err = "command: %s \n%s" % (command, err)
|
|
logger.warning("localhostbecontroller: shellcmd error %s" % err)
|
|
raise ShellCmdException(err)
|
|
else:
|
|
logger.debug("localhostbecontroller: shellcmd success")
|
|
return out.decode('utf-8')
|
|
|
|
def getGitCloneDirectory(self, url, branch):
|
|
"""Construct unique clone directory name out of url and branch."""
|
|
if branch != "HEAD":
|
|
return "_toaster_clones/_%s_%s" % (re.sub('[:/@+%]', '_', url), branch)
|
|
|
|
# word of attention; this is a localhost-specific issue; only on the localhost we expect to have "HEAD" releases
|
|
# which _ALWAYS_ means the current poky checkout
|
|
from os.path import dirname as DN
|
|
local_checkout_path = DN(DN(DN(DN(DN(os.path.abspath(__file__))))))
|
|
#logger.debug("localhostbecontroller: using HEAD checkout in %s" % local_checkout_path)
|
|
return local_checkout_path
|
|
|
|
def setCloneStatus(self,bitbake,status,total,current,repo_name):
|
|
bitbake.req.build.repos_cloned=current
|
|
bitbake.req.build.repos_to_clone=total
|
|
bitbake.req.build.progress_item=repo_name
|
|
bitbake.req.build.save()
|
|
|
|
def setLayers(self, bitbake, layers, targets):
|
|
""" a word of attention: by convention, the first layer for any build will be poky! """
|
|
|
|
assert self.be.sourcedir is not None
|
|
|
|
layerlist = []
|
|
nongitlayerlist = []
|
|
layer_index = 0
|
|
git_env = os.environ.copy()
|
|
# (note: add custom environment settings here)
|
|
|
|
# set layers in the layersource
|
|
|
|
# 1. get a list of repos with branches, and map dirpaths for each layer
|
|
gitrepos = {}
|
|
|
|
# if we're using a remotely fetched version of bitbake add its git
|
|
# details to the list of repos to clone
|
|
if bitbake.giturl and bitbake.commit:
|
|
gitrepos[(bitbake.giturl, bitbake.commit)] = []
|
|
gitrepos[(bitbake.giturl, bitbake.commit)].append(
|
|
("bitbake", bitbake.dirpath, 0))
|
|
|
|
for layer in layers:
|
|
# We don't need to git clone the layer for the CustomImageRecipe
|
|
# as it's generated by us layer on if needed
|
|
if CustomImageRecipe.LAYER_NAME in layer.name:
|
|
continue
|
|
|
|
# If we have local layers then we don't need clone them
|
|
# For local layers giturl will be empty
|
|
if not layer.giturl:
|
|
nongitlayerlist.append( "%03d:%s" % (layer_index,layer.local_source_dir) )
|
|
continue
|
|
|
|
if not (layer.giturl, layer.commit) in gitrepos:
|
|
gitrepos[(layer.giturl, layer.commit)] = []
|
|
gitrepos[(layer.giturl, layer.commit)].append( (layer.name,layer.dirpath,layer_index) )
|
|
layer_index += 1
|
|
|
|
|
|
logger.debug("localhostbecontroller, our git repos are %s" % pformat(gitrepos))
|
|
|
|
|
|
# 2. Note for future use if the current source directory is a
|
|
# checked-out git repos that could match a layer's vcs_url and therefore
|
|
# be used to speed up cloning (rather than fetching it again).
|
|
|
|
cached_layers = {}
|
|
|
|
try:
|
|
for remotes in self._shellcmd("git remote -v", self.be.sourcedir,env=git_env).split("\n"):
|
|
try:
|
|
remote = remotes.split("\t")[1].split(" ")[0]
|
|
if remote not in cached_layers:
|
|
cached_layers[remote] = self.be.sourcedir
|
|
except IndexError:
|
|
pass
|
|
except ShellCmdException:
|
|
# ignore any errors in collecting git remotes this is an optional
|
|
# step
|
|
pass
|
|
|
|
logger.info("Using pre-checked out source for layer %s", cached_layers)
|
|
|
|
# 3. checkout the repositories
|
|
clone_count=0
|
|
clone_total=len(gitrepos.keys())
|
|
self.setCloneStatus(bitbake,'Started',clone_total,clone_count,'')
|
|
for giturl, commit in gitrepos.keys():
|
|
self.setCloneStatus(bitbake,'progress',clone_total,clone_count,gitrepos[(giturl, commit)][0][0])
|
|
clone_count += 1
|
|
|
|
localdirname = os.path.join(self.be.sourcedir, self.getGitCloneDirectory(giturl, commit))
|
|
logger.debug("localhostbecontroller: giturl %s:%s checking out in current directory %s" % (giturl, commit, localdirname))
|
|
|
|
# see if our directory is a git repository
|
|
if os.path.exists(localdirname):
|
|
try:
|
|
localremotes = self._shellcmd("git remote -v",
|
|
localdirname,env=git_env)
|
|
# NOTE: this nice-to-have check breaks when using git remaping to get past firewall
|
|
# Re-enable later with .gitconfig remapping checks
|
|
#if not giturl in localremotes and commit != 'HEAD':
|
|
# 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))
|
|
pass
|
|
except ShellCmdException:
|
|
# our localdirname might not be a git repository
|
|
#- that's fine
|
|
pass
|
|
else:
|
|
if giturl in cached_layers:
|
|
logger.debug("localhostbecontroller git-copying %s to %s" % (cached_layers[giturl], localdirname))
|
|
self._shellcmd("git clone \"%s\" \"%s\"" % (cached_layers[giturl], localdirname),env=git_env)
|
|
self._shellcmd("git remote remove origin", localdirname,env=git_env)
|
|
self._shellcmd("git remote add origin \"%s\"" % giturl, localdirname,env=git_env)
|
|
else:
|
|
logger.debug("localhostbecontroller: cloning %s in %s" % (giturl, localdirname))
|
|
self._shellcmd('git clone "%s" "%s"' % (giturl, localdirname),env=git_env)
|
|
|
|
# branch magic name "HEAD" will inhibit checkout
|
|
if commit != "HEAD":
|
|
logger.debug("localhostbecontroller: checking out commit %s to %s " % (commit, localdirname))
|
|
ref = commit if re.match('^[a-fA-F0-9]+$', commit) else 'origin/%s' % commit
|
|
# DEBUGGING NOTE: this is the 'git fetch" to disable after the initial clone to
|
|
# prevent inserted debugging commands from being lost
|
|
self._shellcmd('git fetch && git reset --hard "%s"' % ref, localdirname,env=git_env)
|
|
|
|
# take the localdirname as poky dir if we can find the oe-init-build-env
|
|
if self.pokydirname is None and os.path.exists(os.path.join(localdirname, "oe-init-build-env")):
|
|
logger.debug("localhostbecontroller: selected poky dir name %s" % localdirname)
|
|
self.pokydirname = localdirname
|
|
|
|
# make sure we have a working bitbake
|
|
if not os.path.exists(os.path.join(self.pokydirname, 'bitbake')):
|
|
logger.debug("localhostbecontroller: checking bitbake into the poky dirname %s " % self.pokydirname)
|
|
self._shellcmd("git clone -b \"%s\" \"%s\" \"%s\" " % (bitbake.commit, bitbake.giturl, os.path.join(self.pokydirname, 'bitbake')),env=git_env)
|
|
|
|
# verify our repositories
|
|
for name, dirpath, index in gitrepos[(giturl, commit)]:
|
|
localdirpath = os.path.join(localdirname, dirpath)
|
|
logger.debug("localhostbecontroller: localdirpath expects '%s'" % localdirpath)
|
|
if not os.path.exists(localdirpath):
|
|
raise BuildSetupException("Cannot find layer git path '%s' in checked out repository '%s:%s'. Exiting." % (localdirpath, giturl, commit))
|
|
|
|
if name != "bitbake":
|
|
layerlist.append("%03d:%s" % (index,localdirpath.rstrip("/")))
|
|
|
|
self.setCloneStatus(bitbake,'complete',clone_total,clone_count,'')
|
|
logger.debug("localhostbecontroller: current layer list %s " % pformat(layerlist))
|
|
|
|
# Resolve self.pokydirname if not resolved yet, consider the scenario
|
|
# where all layers are local, that's the else clause
|
|
if self.pokydirname is None:
|
|
if os.path.exists(os.path.join(self.be.sourcedir, "oe-init-build-env")):
|
|
logger.debug("localhostbecontroller: selected poky dir name %s" % self.be.sourcedir)
|
|
self.pokydirname = self.be.sourcedir
|
|
else:
|
|
# Alternatively, scan local layers for relative "oe-init-build-env" location
|
|
for layer in layers:
|
|
if os.path.exists(os.path.join(layer.layer_version.layer.local_source_dir,"..","oe-init-build-env")):
|
|
logger.debug("localhostbecontroller, setting pokydirname to %s" % (layer.layer_version.layer.local_source_dir))
|
|
self.pokydirname = os.path.join(layer.layer_version.layer.local_source_dir,"..")
|
|
break
|
|
else:
|
|
logger.error("pokydirname is not set, you will run into trouble!")
|
|
|
|
# 5. create custom layer and add custom recipes to it
|
|
for target in targets:
|
|
try:
|
|
customrecipe = CustomImageRecipe.objects.get(
|
|
name=target.target,
|
|
project=bitbake.req.project)
|
|
|
|
custom_layer_path = self.setup_custom_image_recipe(
|
|
customrecipe, layers)
|
|
|
|
if os.path.isdir(custom_layer_path):
|
|
layerlist.append("%03d:%s" % (layer_index,custom_layer_path))
|
|
|
|
except CustomImageRecipe.DoesNotExist:
|
|
continue # not a custom recipe, skip
|
|
|
|
layerlist.extend(nongitlayerlist)
|
|
logger.debug("\n\nset layers gives this list %s" % pformat(layerlist))
|
|
self.islayerset = True
|
|
|
|
# restore the order of layer list for bblayers.conf
|
|
layerlist.sort()
|
|
sorted_layerlist = [l[4:] for l in layerlist]
|
|
return sorted_layerlist
|
|
|
|
def setup_custom_image_recipe(self, customrecipe, layers):
|
|
""" Set up toaster-custom-images layer and recipe files """
|
|
layerpath = os.path.join(self.be.builddir,
|
|
CustomImageRecipe.LAYER_NAME)
|
|
|
|
# create directory structure
|
|
for name in ("conf", "recipes"):
|
|
path = os.path.join(layerpath, name)
|
|
if not os.path.isdir(path):
|
|
os.makedirs(path)
|
|
|
|
# create layer.conf
|
|
config = os.path.join(layerpath, "conf", "layer.conf")
|
|
if not os.path.isfile(config):
|
|
with open(config, "w") as conf:
|
|
conf.write('BBPATH .= ":${LAYERDIR}"\nBBFILES += "${LAYERDIR}/recipes/*.bb"\n')
|
|
|
|
# Update the Layer_Version dirpath that has our base_recipe in
|
|
# to be able to read the base recipe to then generate the
|
|
# custom recipe.
|
|
br_layer_base_recipe = layers.get(
|
|
layer_version=customrecipe.base_recipe.layer_version)
|
|
|
|
# If the layer is one that we've cloned we know where it lives
|
|
if br_layer_base_recipe.giturl and br_layer_base_recipe.commit:
|
|
layer_path = self.getGitCloneDirectory(
|
|
br_layer_base_recipe.giturl,
|
|
br_layer_base_recipe.commit)
|
|
# Otherwise it's a local layer
|
|
elif br_layer_base_recipe.local_source_dir:
|
|
layer_path = br_layer_base_recipe.local_source_dir
|
|
else:
|
|
logger.error("Unable to workout the dir path for the custom"
|
|
" image recipe")
|
|
|
|
br_layer_base_dirpath = os.path.join(
|
|
self.be.sourcedir,
|
|
layer_path,
|
|
customrecipe.base_recipe.layer_version.dirpath)
|
|
|
|
customrecipe.base_recipe.layer_version.dirpath = br_layer_base_dirpath
|
|
|
|
customrecipe.base_recipe.layer_version.save()
|
|
|
|
# create recipe
|
|
recipe_path = os.path.join(layerpath, "recipes", "%s.bb" %
|
|
customrecipe.name)
|
|
with open(recipe_path, "w") as recipef:
|
|
recipef.write(customrecipe.generate_recipe_file_contents())
|
|
|
|
# Update the layer and recipe objects
|
|
customrecipe.layer_version.dirpath = layerpath
|
|
customrecipe.layer_version.layer.local_source_dir = layerpath
|
|
customrecipe.layer_version.layer.save()
|
|
customrecipe.layer_version.save()
|
|
|
|
customrecipe.file_path = recipe_path
|
|
customrecipe.save()
|
|
|
|
return layerpath
|
|
|
|
|
|
def readServerLogFile(self):
|
|
return open(os.path.join(self.be.builddir, "toaster_server.log"), "r").read()
|
|
|
|
|
|
def triggerBuild(self, bitbake, layers, variables, targets, brbe):
|
|
layers = self.setLayers(bitbake, layers, targets)
|
|
is_merged_attr = bitbake.req.project.merged_attr
|
|
|
|
# Is this build for a Bitbake Setup installation?
|
|
isBBSetup = False
|
|
release_description = bitbake.req.project.release.description
|
|
if 'master' in release_description:
|
|
# This release going forward is Bitbake Setup
|
|
isBBSetup = True
|
|
else:
|
|
try:
|
|
# Yocto Project 5.3 "Whinlatter"
|
|
params = release_description.split(' ')
|
|
# Work past YP "10.1"
|
|
release_params = params[2].split('.')
|
|
if int(release_params[0]) > 5:
|
|
isBBSetup = True
|
|
if (release_params[0] == '5') and (int(release_params[1]) >= 3):
|
|
isBBSetup = True
|
|
except:
|
|
# If release schema not recognized, then this release is in the future
|
|
isBBSetup = True
|
|
|
|
git_env = os.environ.copy()
|
|
toaster_run_dir = git_env['BUILDDIR']
|
|
# (note: add custom environment settings here)
|
|
try:
|
|
# insure that the project init/build uses the selected bitbake, and not Toaster's
|
|
del git_env['TEMPLATECONF']
|
|
del git_env['BBBASEDIR']
|
|
del git_env['BUILDDIR']
|
|
except KeyError:
|
|
pass
|
|
|
|
# init build environment from the clone
|
|
if bitbake.req.project.builddir:
|
|
builddir = bitbake.req.project.builddir
|
|
else:
|
|
builddir = '%s-toaster-%d' % (self.be.builddir, bitbake.req.project.id)
|
|
oe_init = os.path.join(self.pokydirname, 'oe-init-build-env')
|
|
setup_init = os.path.join(builddir, 'init-build-env')
|
|
# init build environment and build directory structure
|
|
try:
|
|
custom_script = ToasterSetting.objects.get(name="CUSTOM_BUILD_INIT_SCRIPT").value
|
|
custom_script = custom_script.replace("%BUILDDIR%" ,builddir)
|
|
self._shellcmd("bash -c 'source %s'" % (custom_script),env=git_env)
|
|
except ToasterSetting.DoesNotExist:
|
|
# Normal setup
|
|
if isBBSetup:
|
|
# Create an 'init-build-env' for the build directory that points to respective cloned bitbake
|
|
os.makedirs(builddir, exist_ok = True)
|
|
build_init_script = os.path.join(builddir,'init-build-env')
|
|
os.system(f"cp {os.path.join(toaster_run_dir,'init-build-env')} {build_init_script}")
|
|
os.system(f"sed -i -e 's|^cd .*$|cd {self.pokydirname}|g' {build_init_script}")
|
|
os.system(f"sed -i -e 's|^set .*$|set {builddir}|g' {build_init_script}")
|
|
# Execute the init
|
|
self._shellcmd(f"bash -c 'source {build_init_script}'", env=git_env)
|
|
else:
|
|
self._shellcmd("bash -c 'source %s %s'" % (oe_init, builddir),
|
|
self.be.sourcedir,env=git_env)
|
|
|
|
# update bblayers.conf
|
|
if not is_merged_attr:
|
|
bblconfpath = os.path.join(builddir, "conf/toaster-bblayers.conf")
|
|
with open(bblconfpath, 'w') as bblayers:
|
|
bblayers.write('# line added by toaster build control\n'
|
|
'BBLAYERS = "%s"\n' % ' '.join(layers))
|
|
|
|
# write configuration file
|
|
confpath = os.path.join(builddir, 'conf/toaster.conf')
|
|
with open(confpath, 'w') as conf:
|
|
if isBBSetup:
|
|
# Force TOPDIR
|
|
conf.write(f'# Force TOPDIR\n')
|
|
conf.write(f'TOPDIR = "{builddir}"\n\n')
|
|
for var in variables:
|
|
conf.write('%s = "%s"\n' % (var.name, var.value))
|
|
conf.write('INHERIT += "toaster buildhistory"\n')
|
|
else:
|
|
# Append the Toaster-specific values directly to the bblayers.conf
|
|
bblconfpath = os.path.join(builddir, "conf/bblayers.conf")
|
|
bblconfpath_save = os.path.join(builddir, "conf/bblayers.conf.save")
|
|
shutil.copyfile(bblconfpath, bblconfpath_save)
|
|
with open(bblconfpath) as bblayers:
|
|
content = bblayers.readlines()
|
|
do_write = True
|
|
was_toaster = False
|
|
with open(bblconfpath,'w') as bblayers:
|
|
for line in content:
|
|
#line = line.strip('\n')
|
|
if 'TOASTER_CONFIG_PROLOG' in line:
|
|
do_write = False
|
|
was_toaster = True
|
|
elif 'TOASTER_CONFIG_EPILOG' in line:
|
|
do_write = True
|
|
elif do_write:
|
|
bblayers.write(line)
|
|
if not was_toaster:
|
|
bblayers.write('\n')
|
|
bblayers.write('#=== TOASTER_CONFIG_PROLOG ===\n')
|
|
bblayers.write('BBLAYERS = "\\\n')
|
|
for layer in layers:
|
|
bblayers.write(' %s \\\n' % layer)
|
|
bblayers.write(' "\n')
|
|
bblayers.write('#=== TOASTER_CONFIG_EPILOG ===\n')
|
|
# Append the Toaster-specific values directly to the local.conf
|
|
bbconfpath = os.path.join(builddir, "conf/local.conf")
|
|
bbconfpath_save = os.path.join(builddir, "conf/local.conf.save")
|
|
shutil.copyfile(bbconfpath, bbconfpath_save)
|
|
with open(bbconfpath) as f:
|
|
content = f.readlines()
|
|
do_write = True
|
|
was_toaster = False
|
|
with open(bbconfpath,'w') as conf:
|
|
for line in content:
|
|
#line = line.strip('\n')
|
|
if 'TOASTER_CONFIG_PROLOG' in line:
|
|
do_write = False
|
|
was_toaster = True
|
|
elif 'TOASTER_CONFIG_EPILOG' in line:
|
|
do_write = True
|
|
elif do_write:
|
|
conf.write(line)
|
|
if not was_toaster:
|
|
conf.write('\n')
|
|
conf.write('#=== TOASTER_CONFIG_PROLOG ===\n')
|
|
for var in variables:
|
|
if (not var.name.startswith("INTERNAL_")) and (not var.name == "BBLAYERS"):
|
|
conf.write('%s="%s"\n' % (var.name, var.value))
|
|
conf.write('#=== TOASTER_CONFIG_EPILOG ===\n')
|
|
|
|
# If 'target' is just the project preparation target, then we are done
|
|
for target in targets:
|
|
if "_PROJECT_PREPARE_" == target.target:
|
|
logger.debug('localhostbecontroller: Project has been prepared. Done.')
|
|
# Update the Build Request and release the build environment
|
|
bitbake.req.state = BuildRequest.REQ_COMPLETED
|
|
bitbake.req.save()
|
|
self.be.lock = BuildEnvironment.LOCK_FREE
|
|
self.be.save()
|
|
# Close the project build and progress bar
|
|
bitbake.req.build.outcome = Build.SUCCEEDED
|
|
bitbake.req.build.save()
|
|
# Update the project status
|
|
bitbake.req.project.set_variable(Project.PROJECT_SPECIFIC_STATUS,Project.PROJECT_SPECIFIC_CLONING_SUCCESS)
|
|
signal_runbuilds()
|
|
return
|
|
|
|
# clean the Toaster to build environment
|
|
env_clean = 'unset BBPATH;' # clean BBPATH for <= YP-2.4.0
|
|
|
|
# run bitbake server from the clone if available
|
|
# otherwise pick it from the PATH
|
|
bitbake = os.path.join(self.pokydirname, 'bitbake', 'bin', 'bitbake')
|
|
if not os.path.exists(bitbake):
|
|
logger.info("Bitbake not available under %s, will try to use it from PATH" %
|
|
self.pokydirname)
|
|
for path in os.environ["PATH"].split(os.pathsep):
|
|
if os.path.exists(os.path.join(path, 'bitbake')):
|
|
bitbake = os.path.join(path, 'bitbake')
|
|
break
|
|
else:
|
|
logger.error("Looks like Bitbake is not available, please fix your environment")
|
|
|
|
# NOTE: BB SETUP requires a 'bblayers.conf' even though Toaster immediately overrides it with 'toaster-bblayers.conf'
|
|
bblayers = os.path.join(builddir,"conf/bblayers.conf")
|
|
toasterlayers = os.path.join(builddir,"conf/toaster-bblayers.conf")
|
|
if isBBSetup:
|
|
# Use 'init-build-env' model
|
|
if not is_merged_attr:
|
|
self._shellcmd(f'{env_clean} bash -c \"source {setup_init}; BITBAKE_UI="knotty" {bitbake} --read {confpath} --read {bblayers} --read {toasterlayers} '
|
|
'--server-only -B 0.0.0.0:0\"', self.be.sourcedir)
|
|
else:
|
|
self._shellcmd(f'{env_clean} bash -c \"source {setup_init}; BITBAKE_UI="knotty" {bitbake} '
|
|
'--server-only -B 0.0.0.0:0\"', self.be.sourcedir)
|
|
else:
|
|
# Use 'oe-init-build-env' model
|
|
if not is_merged_attr:
|
|
self._shellcmd(f'{env_clean} bash -c \"source {oe_init} {builddir}; BITBAKE_UI="knotty" {bitbake} --read {confpath} --read {bblayers} --read {toasterlayers} '
|
|
'--server-only -B 0.0.0.0:0\"', self.be.sourcedir)
|
|
else:
|
|
self._shellcmd(f'{env_clean} bash -c \"source {oe_init} {builddir}; BITBAKE_UI="knotty" {bitbake} '
|
|
'--server-only -B 0.0.0.0:0\"', self.be.sourcedir)
|
|
|
|
# read port number from bitbake.lock
|
|
self.be.bbport = -1
|
|
bblock = os.path.join(builddir, 'bitbake.lock')
|
|
# allow 10 seconds for bb lock file to appear but also be populated
|
|
for lock_check in range(10):
|
|
if not os.path.exists(bblock):
|
|
logger.debug("localhostbecontroller: waiting for bblock file to appear")
|
|
time.sleep(1)
|
|
continue
|
|
if 10 < os.stat(bblock).st_size:
|
|
break
|
|
logger.debug("localhostbecontroller: waiting for bblock content to appear")
|
|
time.sleep(1)
|
|
else:
|
|
raise BuildSetupException("Cannot find bitbake server lock file '%s'. Exiting." % bblock)
|
|
|
|
with open(bblock) as fplock:
|
|
for line in fplock:
|
|
if ":" in line:
|
|
self.be.bbport = line.split(":")[-1].strip()
|
|
logger.debug("localhostbecontroller: bitbake port %s", self.be.bbport)
|
|
break
|
|
|
|
if -1 == self.be.bbport:
|
|
raise BuildSetupException("localhostbecontroller: can't read bitbake port from %s" % bblock)
|
|
|
|
self.be.bbaddress = "localhost"
|
|
self.be.bbstate = BuildEnvironment.SERVER_STARTED
|
|
self.be.lock = BuildEnvironment.LOCK_RUNNING
|
|
self.be.save()
|
|
|
|
bbtargets = ''
|
|
for target in targets:
|
|
task = target.task
|
|
if task:
|
|
if not task.startswith('do_'):
|
|
task = 'do_' + task
|
|
task = ':%s' % task
|
|
bbtargets += '%s%s ' % (target.target, task)
|
|
|
|
# run build with local bitbake. stop the server after the build.
|
|
log = os.path.join(builddir, 'toaster_ui.log')
|
|
local_bitbake = os.path.join(os.path.dirname(os.getenv('BBBASEDIR')),
|
|
'bitbake')
|
|
|
|
if not is_merged_attr:
|
|
self._shellcmd([f'{env_clean} bash -c \"(TOASTER_BRBE="{brbe}" BBSERVER="0.0.0.0:{self.be.bbport}" '
|
|
f'{bitbake} {bbtargets} -u toasterui --read {confpath} --read {bblayers} --read {toasterlayers} --token="" >>{log} 2>&1;'
|
|
f'BITBAKE_UI="knotty" BBSERVER=0.0.0.0:{self.be.bbport} {bitbake} -m)&\"'],
|
|
builddir, nowait=True)
|
|
else:
|
|
self._shellcmd([f'{env_clean} bash -c \"(TOASTER_BRBE="{brbe}" BBSERVER="0.0.0.0:{self.be.bbport}" '
|
|
f'{local_bitbake} {bbtargets} -u toasterui --token="" >>{log} 2>&1;'
|
|
f'BITBAKE_UI="knotty" BBSERVER=0.0.0.0:{self.be.bbport} {bitbake} -m)&\"'],
|
|
builddir, nowait=True)
|
|
|
|
logger.debug('localhostbecontroller: Build launched, exiting. '
|
|
f'Follow build logs at {log}')
|