Introduce buildtools configuration scheme:
- version: sets the buildtools version to be fetched
- base_url: optional url property. If not set, kas will use
downloads.yoctoproject.org
- filename: optional archive filename.
All of the properties above are further documented in a follow-up commit.
kas/libkas.py | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 136 insertions(+)
diff --git a/kas/libkas.py b/kas/libkas.py
index 89113fa..8207035 100644
--- a/kas/libkas.py
+++ b/kas/libkas.py
@@ -31,9 +31,15 @@ import logging
import tempfile
import asyncio
import errno
+import glob
+import hashlib
import pathlib
+import platform
+import shutil
import signal
+import stat
from subprocess import Popen, PIPE, run as subprocess_run
+from urllib.parse import quote
from .context import get_context
from .kasusererror import KasUserError, CommandExecError
@@ -258,6 +264,102 @@ def repos_apply_patches(repos):
raise TaskExecError('apply patches', e.ret_code)
+def get_buildtools_path():
+ # Set the dest. directory for buildtools's setup
+ env = os.environ.get("KAS_BUILDTOOLS_DIR")
+ if env:
+ buildtools_dir = os.path.realpath(env)
+ else:
+ buildtools_dir = get_context().build_dir + "/buildtools"
+
+ return buildtools_dir
+
+
+def check_sha256sum(installer_path, sha256sum_url):
+ hash_sha256 = hashlib.sha256()
+ with open(installer_path, "rb") as f:
+ for chunk in iter(lambda: f.read(8192), b""):
+ hash_sha256.update(chunk)
+
+ calc = hash_sha256.hexdigest()
+
+ # Download sha256sum file
+ sha256sum_path = installer_path + ".sha256sum"
+ fetch_cmd = ['wget', '-q', '-O', sha256sum_path, sha256sum_url]
+ (ret, _) = run_cmd(fetch_cmd, cwd=get_context().kas_work_dir)
+ if ret != 0:
+ raise InitBuildEnvError("Could not download buildtools sha256sum file")
+
+ with open(sha256sum_path, "r") as f:
+ lines = f.readlines()
+
+ reference = lines[0].split()[0]
+
+ return calc == reference
+
+
+def download_buildtools():
+ arch = platform.machine()
+ ctx = get_context()
+ conf_buildtools = ctx.config.get_buildtools()
+ version = conf_buildtools['version']
+ buildtools_dir = get_buildtools_path()
+
+ if 'base_url' in conf_buildtools:
+ base_url = conf_buildtools['base_url']
+ else:
+ yocto_releases = "
https://downloads.yoctoproject.org/releases/yocto"
+ base_url = f"{yocto_releases}/yocto-{version}/buildtools/"
+
+ if 'filename' in conf_buildtools:
+ filename = conf_buildtools['filename']
+ else:
+ filename = f"{arch}-buildtools-extended-nativesdk-standalone-{version}.sh"
+
+ # Enable extended buildtools tarball
+ buildtools_url = f"{base_url}/{quote(filename)}"
+ tmpbuildtools = os.path.join(buildtools_dir, filename)
+
+
logging.info(f"Downloading Buildtools {version}")
+ # Download installer
+ fetch_cmd = ['wget', '-q', '-O', tmpbuildtools, buildtools_url]
+ (ret, _) = run_cmd(fetch_cmd, cwd=ctx.kas_work_dir)
+ if ret != 0:
+ raise InitBuildEnvError("Could not download buildtools installer")
+
+ # Check if the installer's sha256sum matches
+ if not check_sha256sum(tmpbuildtools, buildtools_url + ".sha256sum"):
+ raise InitBuildEnvError("sha256sum mismatch: installer may be corrupted")
+
+ # Make installer executable
+ st = os.stat(tmpbuildtools)
+ os.chmod(tmpbuildtools, st.st_mode | stat.S_IEXEC)
+
+ # Run installer
+ installer_cmd = [tmpbuildtools, '-d', buildtools_dir, '-y']
+ env = {'PATH': '/usr/sbin:/usr/bin:/sbin:/bin'}
+ (ret, _) = run_cmd(installer_cmd, cwd=ctx.kas_work_dir, env=env)
+ if ret != 0:
+ raise InitBuildEnvError("Could not run buildtools installer")
+
+
+def get_buildtools_version():
+ try:
+ version_file = glob.glob(os.path.join(get_buildtools_path(), "version-*"))
+ if len(version_file) != 1:
+ raise ValueError("Invalid number of version files")
+
+ with open(os.path.realpath(version_file[0]), 'r') as f:
+ lines = f.readlines()
+
+ if len(lines) > 1 and "Distro Version" in lines[1]:
+ return lines[1].split(':', 1)[1].strip()
+ except Exception as e:
+ logging.warning(f"Unable to read buildtools version: {e}")
+
+ return -1
+
+
def get_build_environ(build_system):
"""
Creates the build environment variables.
@@ -288,9 +390,43 @@ def get_build_environ(build_system):
if not init_repo:
raise InitBuildEnvError('Did not find any init-build-env script')
+ conf_buildtools = get_context().config.get_buildtools()
+ buildtools_env = ""
+
+ if conf_buildtools:
+ # Create the dest. directory if it doesn't exist
+ buildtools_dir = get_buildtools_path()
+ pathlib.Path(buildtools_dir).mkdir(parents=True, exist_ok=True)
+
+ if not os.listdir(buildtools_dir):
+ # Directory is empty, try to fetch from upstream
+
logging.info(f"Buildtools ({buildtools_dir}): directory is empty")
+ download_buildtools()
+ else:
+ # Directory is not empty: fetch buildtools if the versions don't match
+ found_version = get_buildtools_version()
+ if found_version != conf_buildtools['version']:
+ logging.warning("Buildtools: version mismatch")
+
logging.info(f"Required version: {conf_buildtools['version']}")
+
logging.info(f"Found version: {found_version}")
+ shutil.rmtree(os.path.realpath(buildtools_dir))
+ os.makedirs(os.path.realpath(buildtools_dir))
+ download_buildtools()
+
+ envfiles = glob.glob(os.path.join(buildtools_dir, "environment-setup-*"))
+ if len(envfiles) == 1:
+ buildtools_env = "source {}\n".format(os.path.realpath(envfiles[0]))
+ else:
+ logging.error(
+ f"Expected 1 environment setup file, but found {len(envfiles)}. "
+ "Invalid or misconfigured buildtools package."
+ )
+ return -1
+
with tempfile.TemporaryDirectory() as temp_dir:
script = f"""#!/bin/bash
set -e
+ {buildtools_env}
source {init_script} $1 > /dev/null
env
"""
--
2.47.0