% distro) # Checks we should only make if MACHINE is set correctly def check_sanity_validmachine(sanity_data): messages = "" # Check TUNE_ARCH is set if sanity_data.getVar('TUNE_ARCH') == 'INVALID': messages = messages + 'TUNE_ARCH is unset. Please ensure your MACHINE configuration includes a valid tune configuration file which will set this correctly.\n' # Check TARGET_OS is set if sanity_data.getVar('TARGET_OS') == 'INVALID': messages = messages + 'Please set TARGET_OS directly, or choose a MACHINE or DISTRO that does so.\n' # Check that we don't have duplicate entries in PACKAGE_ARCHS & that TUNE_PKGARCH is in PACKAGE_ARCHS pkgarchs = sanity_data.getVar('PACKAGE_ARCHS') tunepkg = sanity_data.getVar('TUNE_PKGARCH') defaulttune = sanity_data.getVar('DEFAULTTUNE') tunefound = False seen = {} dups = [] for pa in pkgarchs.split(): if seen.get(pa, 0) == 1: dups.append(pa) else: seen[pa] = 1 if pa == tunepkg: tunefound = True if len(dups): messages = messages + "Error, the PACKAGE_ARCHS variable contains duplicates. The following archs are listed more than once: %s" % " ".join(dups) if tunefound == False: messages = messages + "Error, the PACKAGE_ARCHS variable (%s) for DEFAULTTUNE (%s) does not contain TUNE_PKGARCH (%s)." % (pkgarchs, defaulttune, tunepkg) return messages # Patch before 2.7 can't handle all the features in git-style diffs. Some # patches may incorrectly apply, and others won't apply at all. def check_patch_version(sanity_data): from distutils.version import LooseVersion import re, subprocess try: result = subprocess.check_output(["patch", "--version"], stderr=subprocess.STDOUT).decode('utf-8') version = re.search(r"[0-9.]+", result.splitlines()[0]).group() if LooseVersion(version) < LooseVersion("2.7"): return "Your version of patch is older than 2.7 and has bugs which will break builds. Please install a newer version of patch.\n" else: return None except subprocess.CalledProcessError as e: return "Unable to execute patch --version, exit code %d:\n%s\n" % (e.returncode, e.output) # Unpatched versions of make 3.82 are known to be broken. See GNU Savannah Bug 30612. # Use a modified reproducer from http://savannah.gnu.org/bugs/?30612 to validate. def check_make_version(sanity_data): from distutils.version import LooseVersion import subprocess try: result = subprocess.check_output(['make', '--version'], stderr=subprocess.STDOUT).decode('utf-8') except subprocess.CalledProcessError as e: return "Unable to execute make --version, exit code %d\n%s\n" % (e.returncode, e.output) version = result.split()[2] if LooseVersion(version) == LooseVersion("3.82"): # Construct a test file f = open("makefile_test", "w") f.write("makefile_test.a: makefile_test_a.c makefile_test_b.c makefile_test.a( makefile_test_a.c makefile_test_b.c)\n") f.write("\n") f.write("makefile_test_a.c:\n") f.write(" touch $@\n") f.write("\n") f.write("makefile_test_b.c:\n") f.write(" touch $@\n") f.close() # Check if make 3.82 has been patched try: subprocess.check_call(['make', '-f', 'makefile_test']) except subprocess.CalledProcessError as e: return "Your version of make 3.82 is broken. Please revert to 3.81 or install a patched version.\n" finally: os.remove("makefile_test") if os.path.exists("makefile_test_a.c"): os.remove("makefile_test_a.c") if os.path.exists("makefile_test_b.c"): os.remove("makefile_test_b.c") if os.path.exists("makefile_test.a"): os.remove("makefile_test.a") return None # Check if we're running on WSL (Windows Subsystem for Linux). # WSLv1 is known not to work but WSLv2 should work properly as # long as the VHDX file is optimized often, let the user know # upfront. # More information on installing WSLv2 at: # https://docs.microsoft.com/en-us/windows/wsl/wsl2-install def check_wsl(d): with open("/proc/version", "r") as f: verdata = f.readlines() for l in verdata: if "Microsoft" in l: return "OpenEmbedded doesn't work under WSLv1, please upgrade to WSLv2 if you want to run builds on Windows" elif "microsoft" in l: bb.warn("You are running bitbake under WSLv2, this works properly but you should optimize your VHDX file eventually to avoid running out of storage space") return None # Require at least gcc version 6.0. # # This can be fixed on CentOS-7 with devtoolset-6+ # https://www.softwarecollections.org/en/scls/rhscl/devtoolset-6/ # # A less invasive fix is with scripts/install-buildtools (or with user # built buildtools-extended-tarball) # def check_gcc_version(sanity_data): from distutils.version import LooseVersion import subprocess build_cc, version = oe.utils.get_host_compiler_version(sanity_data) if build_cc.strip() == "gcc": if LooseVersion(version) < LooseVersion("6.0"): return "Your version of gcc is older than 6.0 and will break builds. Please install a newer version of gcc (you could use the project's buildtools-extended-tarball or use scripts/install-buildtools).\n" return None # Tar version 1.24 and onwards handle overwriting symlinks correctly # but earlier versions do not; this needs to work properly for sstate # Version 1.28 is needed so opkg-build works correctly when reproducibile builds are enabled def check_tar_version(sanity_data): from distutils.version import LooseVersion import subprocess try: result = subprocess.check_output(["tar", "--version"], stderr=subprocess.STDOUT).decode('utf-8') except subprocess.CalledProcessError as e: return "Unable to execute tar --version, exit code %d\n%s\n" % (e.returncode, e.output) version = result.split()[3] if LooseVersion(version) < LooseVersion("1.28"): return "Your version of tar is older than 1.28 and does not have the support needed to enable reproducible builds. Please install a newer version of tar (you could use the project's buildtools-tarball from our last release or use scripts/install-buildtools).\n" return None # We use git parameters and functionality only found in 1.7.8 or later # The kernel tools assume git >= 1.8.3.1 (verified needed > 1.7.9.5) see #6162 # The git fetcher also had workarounds for git < 1.7.9.2 which we've dropped def check_git_version(sanity_data): from distutils.version import LooseVersion import subprocess try: result = subprocess.check_output(["git", "--version"], stderr=subprocess.DEVNULL).decode('utf-8') except subprocess.CalledProcessError as e: return "Unable to execute git --version, exit code %d\n%s\n" % (e.returncode, e.output) version = result.split()[2] if LooseVersion(version) < LooseVersion("1.8.3.1"): return "Your version of git is older than 1.8.3.1 and has bugs which will break builds. Please install a newer version of git.\n" return None # Check the required perl modules which may not be installed by default def check_perl_modules(sanity_data): import subprocess ret = "" modules = ( "Text::ParseWords", "Thread::Queue", "Data::Dumper" ) errresult = '' for m in modules: try: subprocess.check_output(["perl", "-e", "use %s" % m]) except subprocess.CalledProcessError as e: errresult += bytes.decode(e.output) ret += "%s " % m if ret: return "Required perl module(s) not found: %s\n\n%s\n" % (ret, errresult) return None def sanity_check_conffiles(d): funcs = d.getVar('BBLAYERS_CONF_UPDATE_FUNCS').split() for func in funcs: conffile, current_version, required_version, func = func.split(":") if check_conf_exists(conffile, d) and d.getVar(current_version) is not None and \ d.getVar(current_version) != d.getVar(required_version): try: bb.build.exec_func(func, d) except NotImplementedError as e: bb.fatal(str(e)) d.setVar("BB_INVALIDCONF", True) def sanity_handle_abichanges(status, d): # # Check the 'ABI' of TMPDIR # import subprocess current_abi = d.getVar('OELAYOUT_ABI') abifile = d.getVar('SANITY_ABIFILE') if os.path.exists(abifile): with open(abifile, "r") as f: abi = f.read().strip() if not abi.isdigit(): with open(abifile, "w") as f: f.write(current_abi) elif int(abi) <= 11 and current_abi == "12": status.addresult("The layout of TMPDIR changed for Recipe Specific Sysroots.\nConversion doesn't make sense and this change will rebuild everything so please delete TMPDIR (%s).\n" % d.getVar("TMPDIR")) elif int(abi) <= 13 and current_abi == "14": status.addresult("TMPDIR changed to include path filtering from the pseudo database.\nIt is recommended to use a clean TMPDIR with the new pseudo path filtering so TMPDIR (%s) would need to be removed to continue.\n" % d.getVar("TMPDIR")) elif (abi != current_abi): # Code to convert from one ABI to another could go here if possible. status.addresult("Error, TMPDIR has changed its layout version number (%s to %s) and you need to either rebuild, revert or adjust it at your own risk.\n" % (abi, current_abi)) else: with open(abifile, "w") as f: f.write(current_abi) def check_sanity_sstate_dir_change(sstate_dir, data): # Sanity checks to be done when the value of SSTATE_DIR changes # Check that SSTATE_DIR isn't on a filesystem with limited filename length (eg. eCryptFS) testmsg = "" if sstate_dir != "": testmsg = check_create_long_filename(sstate_dir, "SSTATE_DIR") # If we don't have permissions to SSTATE_DIR, suggest the user set it as an SSTATE_MIRRORS try: err = testmsg.split(': ')[1].strip() if err == "Permission denied.": testmsg = testmsg + "You could try using %s in SSTATE_MIRRORS rather than as an SSTATE_CACHE.\n" % (sstate_dir) except IndexError: pass return testmsg def check_sanity_version_change(status, d): # Sanity checks to be done when SANITY_VERSION or NATIVELSBSTRING changes # In other words, these tests run once in a given build directory and then # never again until the sanity version or host distrubution id/version changes. # Check the python install is complete. Examples that are often removed in # minimal installations: glib-2.0-natives requries # xml.parsers.expat and icu # requires distutils.sysconfig. try: import xml.parsers.expat import distutils.sysconfig except ImportError as e: status.addresult('Your Python 3 is not a full install. Please install the module %s (see the Getting Started guide for further information).\n' % e.name) status.addresult(check_gcc_version(d)) status.addresult(check_make_version(d)) status.addresult(check_patch_version(d)) status.addresult(check_tar_version(d)) status.addresult(check_git_version(d)) status.addresult(check_perl_modules(d)) status.addresult(check_wsl(d)) missing = "" if not check_app_exists("${MAKE}", d): missing = missing + "GNU make," if not check_app_exists('${BUILD_CC}', d): missing = missing + "C Compiler (%s)," % d.getVar("BUILD_CC") if not check_app_exists('${BUILD_CXX}', d): missing = missing + "C++ Compiler (%s)," % d.getVar("BUILD_CXX") required_utilities = d.getVar('SANITY_REQUIRED_UTILITIES') for util in required_utilities.split(): if not check_app_exists(util, d): missing = missing + "%s," % util if missing: missing = missing.rstrip(',') status.addresult("Please install the following missing utilities: %s\n" % missing) assume_provided = d.getVar('ASSUME_PROVIDED').split() # Check user doesn't have ASSUME_PROVIDED = instead of += in local.conf if "diffstat-native" not in assume_provided: status.addresult('Please use ASSUME_PROVIDED +=, not ASSUME_PROVIDED = in your local.conf\n') # Check that TMPDIR isn't on a filesystem with limited filename length (eg. eCryptFS) import stat tmpdir = d.getVar('TMPDIR') status.addresult(check_create_long_filename(tmpdir, "TMPDIR")) tmpdirmode = os.stat(tmpdir).st_mode if (tmpdirmode & stat.S_ISGID): status.addresult("TMPDIR is setgid, please don't build in a setgid directory") if (tmpdirmode & stat.S_ISUID): status.addresult("TMPDIR is setuid, please don't build in a setuid directory") # Check that a user isn't building in a path in PSEUDO_IGNORE_PATHS pseudoignorepaths = d.getVar('PSEUDO_IGNORE_PATHS', expand=True).split(",") workdir = d.getVar('WORKDIR', expand=True) for i in pseudoignorepaths: if i and workdir.startswith(i): status.addresult("You are building in a path included in PSEUDO_IGNORE_PATHS " + str(i) + " please locate the build outside this path.\n") # Check if PSEUDO_IGNORE_PATHS and and paths under pseudo control overlap pseudoignorepaths = d.getVar('PSEUDO_IGNORE_PATHS', expand=True).split(",") pseudo_control_dir = "${D},${PKGD},${PKGDEST},${IMAGEROOTFS},${SDK_OUTPUT}" pseudocontroldir = d.expand(pseudo_control_dir).split(",") for i in pseudoignorepaths: for j in pseudocontroldir: if i and j: if j.startswith(i): status.addresult("A path included in PSEUDO_IGNORE_PATHS " + str(i) + " and the path " + str(j) + " overlap and this will break pseudo permission and ownership tracking. Please set the path " + str(j) + " to a different directory which does not overlap with pseudo controlled directories. \n") # Some third-party software apparently relies on chmod etc. being suid root (!!) import stat suid_check_bins = "chown chmod mknod".split() for bin_cmd in suid_check_bins: bin_path = bb.utils.which(os.environ["PATH"], bin_cmd) if bin_path: bin_stat = os.stat(bin_path) if bin_stat.st_uid == 0 and bin_stat.st_mode & stat.S_ISUID: status.addresult('%s has the setuid bit set. This interferes with pseudo and may cause other issues that break the build process.\n' % bin_path) # Check that we can fetch from various network transports netcheck = check_connectivity(d) status.addresult(netcheck) if netcheck: status.network_error = True nolibs = d.getVar('NO32LIBS') if not nolibs: lib32path = '/lib' if os.path.exists('/lib64') and ( os.path.islink('/lib64') or os.path.islink('/lib') ): lib32path = '/lib32' if os.path.exists('%s/libc.so.6' % lib32path) and not os.path.exists('/usr/include/gnu/stubs-32.h'): status.addresult("You have a 32-bit libc, but no 32-bit headers. You must install the 32-bit libc headers.\n") bbpaths = d.getVar('BBPATH').split(":") if ("." in bbpaths or "./" in bbpaths or "" in bbpaths): status.addresult("BBPATH references the current directory, either through " \ "an empty entry, a './' or a '.'.\n\t This is unsafe and means your "\ "layer configuration is adding empty elements to BBPATH.\n\t "\ "Please check your layer.conf files and other BBPATH " \ "settings to remove the current working directory " \ "references.\n" \ "Parsed BBPATH is" + str(bbpaths)); oes_bb_conf = d.getVar( 'OES_BITBAKE_CONF') if not oes_bb_conf: status.addresult('You are not using the OpenEmbedded version of conf/bitbake.conf. This means your environment is misconfigured, in particular check BBPATH.\n') # The length of TMPDIR can't be longer than 410 status.addresult(check_path_length(tmpdir, "TMPDIR", 410)) # Check that TMPDIR isn't located on nfs status.addresult(check_not_nfs(tmpdir, "TMPDIR")) # Check for case-insensitive file systems (such as Linux in Docker on # macOS with default HFS+ file system) status.addresult(check_case_sensitive(tmpdir, "TMPDIR")) def sanity_check_locale(d): """ Currently bitbake switches locale to en_US.UTF-8 so check that this locale actually exists. """ import locale try: locale.setlocale(locale.LC_ALL, "en_US.UTF-8") except locale.Error: raise_sanity_error("Your system needs to support the en_US.UTF-8 locale.", d) def check_sanity_everybuild(status, d): import os, stat # Sanity tests which test the users environment so need to run at each build (or are so cheap # it makes sense to always run them. if 0 == os.getuid(): raise_sanity_error("Do not use Bitbake as root.", d) # Check the Python version, we now have a minimum of Python 3.6 import sys if sys.hexversion < 0x030600F0: status.addresult('The system requires at least Python 3.6 to run. Please update your Python interpreter.\n') # Check the bitbake version meets minimum requirements from distutils.version import LooseVersion minversion = d.getVar('BB_MIN_VERSION') if (LooseVersion(bb.__version__) < LooseVersion(minversion)): status.addresult('Bitbake version %s is required and version %s was found\n' % (minversion, bb.__version__)) sanity_check_locale(d) paths = d.getVar('PATH').split(":") if "." in paths or "./" in paths or "" in paths: status.addresult("PATH contains '.', './' or '' (empty element), which will break the build, please remove this.\nParsed PATH is " + str(paths) + "\n") #Check if bitbake is present in PATH environment variable bb_check = bb.utils.which(d.getVar('PATH'), 'bitbake') if not bb_check: bb.warn("bitbake binary is not found in PATH, did you source the script?") # Check whether 'inherit' directive is found (used for a class to inherit) # in conf file it's supposed to be uppercase INHERIT inherit = d.getVar('inherit') if inherit: status.addresult("Please don't use inherit directive in your local.conf. The directive is supposed to be used in classes and recipes only to inherit of bbclasses. Here INHERIT should be used.\n") # Check that the DISTRO is valid, if set # need to take into account DISTRO renaming DISTRO distro = d.getVar('DISTRO') if distro and distro != "nodistro": if not ( check_conf_exists("conf/distro/${DISTRO}.conf", d) or check_conf_exists("conf/distro/include/${DISTRO}.inc", d) ): status.addresult("DISTRO '%s' not found. Please set a valid DISTRO in your local.conf\n" % d.getVar("DISTRO")) # Check that these variables don't use tilde-expansion as we don't do that for v in ("TMPDIR", "DL_DIR", "SSTATE_DIR"): if d.getVar(v).startswith("~"): status.addresult("%s uses ~ but Bitbake will not expand this, use an absolute path or variables." % v) # Check that DL_DIR is set, exists and is writable. In theory, we should never even hit the check if DL_DIR isn't # set, since so much relies on it being set. dldir = d.getVar('DL_DIR') if not dldir: status.addresult("DL_DIR is not set. Your environment is misconfigured, check that DL_DIR is set, and if the directory exists, that it is writable. \n") if os.path.exists(dldir) and not os.access(dldir, os.W_OK): status.addresult("DL_DIR: %s exists but you do not appear to have write access to it. \n" % dldir) check_symlink(dldir, d) # Check that the MACHINE is valid, if it is set machinevalid = True if d.getVar('MACHINE'): if not check_conf_exists("conf/machine/${MACHINE}.conf", d): status.addresult('MACHINE=%s is invalid. Please set a valid MACHINE in your local.conf, environment or other configuration file.\n' % (d.getVar('MACHINE'))) machinevalid = False else: status.addresult(check_sanity_validmachine(d)) else: status.addresult('Please set a MACHINE in your local.conf or environment\n') machinevalid = False if machinevalid: status.addresult(check_toolchain(d)) # Check that the SDKMACHINE is valid, if it is set if d.getVar('SDKMACHINE'): if not check_conf_exists("conf/machine-sdk/${SDKMACHINE}.conf", d): status.addresult('Specified SDKMACHINE value is not valid\n') elif d.getVar('SDK_ARCH', False) == "${BUILD_ARCH}": status.addresult('SDKMACHINE is set, but SDK_ARCH has not been changed as a result - SDKMACHINE may have been set too late (e.g. in the distro configuration)\n') # If SDK_VENDOR looks like "-my-sdk" then the triples are badly formed so fail early sdkvendor = d.getVar("SDK_VENDOR") if not (sdkvendor.startswith("-") and sdkvendor.count("-") == 1): status.addresult("SDK_VENDOR should be of the form '-foosdk' with a single dash; found '%s'\n" % sdkvendor) check_supported_distro(d) omask = os.umask(0o022) if omask & 0o755: status.addresult("Please use a umask which allows a+rx and u+rwx\n") os.umask(omask) if d.getVar('TARGET_ARCH') == "arm": # This path is no longer user-readable in modern (very recent) Linux try: if os.path.exists("/proc/sys/vm/mmap_min_addr"): f = open("/proc/sys/vm/mmap_min_addr", "r") try: if (int(f.read().strip()) > 65536): status.addresult("/proc/sys/vm/mmap_min_addr is not <= 65536. This will cause problems with qemu so please fix the value (as root).\n\nTo fix this in later reboots, set vm.mmap_min_addr = 65536 in /etc/sysctl.conf.\n") finally: f.close() except: pass for checkdir in ['COREBASE', 'TMPDIR']: val = d.getVar(checkdir) if val.find('..') != -1: status.addresult("Error, you have '..' in your %s directory path. Please ensure the variable contains an absolute path as this can break some recipe builds in obtuse ways." % checkdir) if val.find('+') != -1: status.addresult("Error, you have an invalid character (+) in your %s directory path. Please move the installation to a directory which doesn't include any + characters." % checkdir) if val.find('@') != -1: status.addresult("Error, you have an invalid character (@) in your %s directory path. Please move the installation to a directory which doesn't include any @ characters." % checkdir) if val.find(' ') != -1: status.addresult("Error, you have a space in your %s directory path. Please move the installation to a directory which doesn't include a space since autotools doesn't support this." % checkdir) if val.find('%') != -1: status.addresult("Error, you have an invalid character (%) in your %s directory path which causes problems with python string formatting. Please move the installation to a directory which doesn't include any % characters." % checkdir) # Check the format of MIRRORS, PREMIRRORS and SSTATE_MIRRORS import re mirror_vars = ['MIRRORS', 'PREMIRRORS', 'SSTATE_MIRRORS'] protocols = ['http', 'ftp', 'file', 'https', \ 'git', 'gitsm', 'hg', 'osc', 'p4', 'svn', \ 'bzr', 'cvs', 'npm', 'sftp', 'ssh', 's3', 'az' ] for mirror_var in mirror_vars: mirrors = (d.getVar(mirror_var) or '').replace('\\n', ' ').split() # Split into pairs if len(mirrors) % 2 != 0: bb.warn('Invalid mirror variable value for %s: %s, should contain paired members.' % (mirror_var, str(mirrors))) continue mirrors = list(zip(*[iter(mirrors)]*2)) for mirror_entry in mirrors: pattern, mirror = mirror_entry decoded = bb.fetch2.decodeurl(pattern) try: pattern_scheme = re.compile(decoded[0]) except re.error as exc: bb.warn('Invalid scheme regex (%s) in %s; %s' % (pattern, mirror_var, mirror_entry)) continue if not any(pattern_scheme.match(protocol) for protocol in protocols): bb.warn('Invalid protocol (%s) in %s: %s' % (decoded[0], mirror_var, mirror_entry)) continue if not any(mirror.startswith(protocol + '://') for protocol in protocols): bb.warn('Invalid protocol in %s: %s' % (mirror_var, mirror_entry)) continue if mirror.startswith('file://'): import urllib check_symlink(urllib.parse.urlparse(mirror).path, d) # SSTATE_MIRROR ends with a /PATH string if mirror.endswith('/PATH'): # remove /PATH$ from SSTATE_MIRROR to get a working # base directory path mirror_base = urllib.parse.urlparse(mirror[:-1*len('/PATH')]).path check_symlink(mirror_base, d) # Check that TMPDIR hasn't changed location since the last time we were run tmpdir = d.getVar('TMPDIR') checkfile = os.path.join(tmpdir, "saved_tmpdir") if os.path.exists(checkfile): with open(checkfile, "r") as f: saved_tmpdir = f.read().strip() if (saved_tmpdir != tmpdir): status.addresult("Error, TMPDIR has changed location. You need to either move it back to %s or delete it and rebuild\n" % saved_tmpdir) else: bb.utils.mkdirhier(tmpdir) # Remove setuid, setgid and sticky bits from TMPDIR try: os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISUID) os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISGID) os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISVTX) except OSError as exc: bb.warn("Unable to chmod TMPDIR: %s" % exc) with open(checkfile, "w") as f: f.write(tmpdir) # If /bin/sh is a symlink, check that it points to dash or bash if os.path.islink('/bin/sh'): real_sh = os.path.realpath('/bin/sh') # Due to update-alternatives, the shell name may take various # forms, such as /bin/dash, bin/bash, /bin/bash.bash ... if '/dash' not in real_sh and '/bash' not in real_sh: status.addresult("Error, /bin/sh links to %s, must be dash or bash\n" % real_sh) def check_sanity(sanity_data): class SanityStatus(object): def __init__(self): self.messages = "" self.network_error = False def addresult(self, message): if message: self.messages = self.messages + message status = SanityStatus() tmpdir = sanity_data.getVar('TMPDIR') sstate_dir = sanity_data.getVar('SSTATE_DIR') check_symlink(sstate_dir, sanity_data) # Check saved sanity info last_sanity_version = 0 last_tmpdir = "" last_sstate_dir = "" last_nativelsbstr = "" sanityverfile = sanity_data.expand("${TOPDIR}/cache/sanity_info") if os.path.exists(sanityverfile): with open(sanityverfile, 'r') as f: for line in f: if line.startswith('SANITY_VERSION'): last_sanity_version = int(line.split()[1]) if line.startswith('TMPDIR'): last_tmpdir = line.split()[1] if line.startswith('SSTATE_DIR'): last_sstate_dir = line.split()[1] if line.startswith('NATIVELSBSTRING'): last_nativelsbstr = line.split()[1] check_sanity_everybuild(status, sanity_data) sanity_version = int(sanity_data.getVar('SANITY_VERSION') or 1) network_error = False # NATIVELSBSTRING var may have been overridden with "universal", so # get actual host distribution id and version nativelsbstr = lsb_distro_identifier(sanity_data) if last_sanity_version < sanity_version or last_nativelsbstr != nativelsbstr: check_sanity_version_change(status, sanity_data) status.addresult(check_sanity_sstate_dir_change(sstate_dir, sanity_data)) else: if last_sstate_dir != sstate_dir: status.addresult(check_sanity_sstate_dir_change(sstate_dir, sanity_data)) if os.path.exists(os.path.dirname(sanityverfile)) and not status.messages: with open(sanityverfile, 'w') as f: f.write("SANITY_VERSION %s\n" % sanity_version) f.write("TMPDIR %s\n" % tmpdir) f.write("SSTATE_DIR %s\n" % sstate_dir) f.write("NATIVELSBSTRING %s\n" % nativelsbstr) sanity_handle_abichanges(status, sanity_data) if status.messages != "": raise_sanity_error(sanity_data.expand(status.messages), sanity_data, status.network_error) # Create a copy of the datastore and finalise it to ensure appends and # overrides are set - the datastore has yet to be finalised at ConfigParsed def copy_data(e): sanity_data = bb.data.createCopy(e.data) sanity_data.finalize() return sanity_data addhandler config_reparse_eventhandler config_reparse_eventhandler[eventmask] = "bb.event.ConfigParsed" python config_reparse_eventhandler() { sanity_check_conffiles(e.data) } addhandler check_sanity_eventhandler check_sanity_eventhandler[eventmask] = "bb.event.SanityCheck bb.event.NetworkTest" python check_sanity_eventhandler() { if bb.event.getName(e) == "SanityCheck": sanity_data = copy_data(e) check_sanity(sanity_data) if e.generateevents: sanity_data.setVar("SANITY_USE_EVENTS", "1") bb.event.fire(bb.event.SanityCheckPassed(), e.data) elif bb.event.getName(e) == "NetworkTest": sanity_data = copy_data(e) if e.generateevents: sanity_data.setVar("SANITY_USE_EVENTS", "1") bb.event.fire(bb.event.NetworkTestFailed() if check_connectivity(sanity_data) else bb.event.NetworkTestPassed(), e.data) return }