# Copyright 2024 sysmocom - s.f.m.c. GmbH # SPDX-License-Identifier: GPL-3.0-or-later import logging import multiprocessing import os import packaging.version import re import shlex import string import subprocess import sys import testenv.cmd import testenv.podman git_dir = None jobs = None def init(): global git_dir global jobs # Make the git dir we clone into specific to the repository we build # against. Replace ":" because the libtool scripts fail to escape it when # setting LD_LIBRARY_PATH, leading to "cannot open shared object file" # errors. git_dir = os.path.join(testenv.args.cache, "git", f"build_against_{testenv.args.binary_repo}".replace(":", "_")) jobs = multiprocessing.cpu_count() + 1 os.makedirs(git_dir, exist_ok=True) def get_dbg_pkgs(dep): ret = [f"{dep}-dbg", f"{dep}-dbgsym"] # Get from e.g. libosmocore22 to libosmocore-dbg dep_nodigits = dep.rstrip(string.digits) if dep_nodigits != dep: ret += [f"{dep_nodigits}-dbg", f"{dep_nodigits}-dbgsym"] return ret def apt_get_dbg_pkgs(pkgs): dbg_pkgs_all = os.path.join(testenv.args.cache, "podman", "dbg_pkgs_all") dbg_pkgs = {} testenv.cmd.run(f"apt-cache pkgnames | grep -- -dbg > {shlex.quote(dbg_pkgs_all)}") for pkg in pkgs: # Iterate over apt-rdepends, example output: # osmo-mgw # Depends: libc6 (>= 2.34) # Depends: libosmoabis13 rdeps = testenv.cmd.run(["apt-rdepends", pkg], stdout=subprocess.PIPE) for line in rdeps.stdout.decode("utf-8").split("\n"): if line.startswith(" "): continue dep = line.rstrip().split(" ", 1)[0] if dep not in dbg_pkgs: for dbg_pkg in get_dbg_pkgs(dep): # Use subprocess.run so we don't get lots of log messages. # Also we don't need to run grep through podman. grep = subprocess.run(["grep", "-q", f"^{dbg_pkg}$", dbg_pkgs_all]) if grep.returncode == 0: dbg_pkgs[dep] = dbg_pkg break if dep not in dbg_pkgs: dbg_pkgs[dep] = None if dbg_pkgs[dep]: logging.debug(f"{pkg} -> {dep}: installing {dbg_pkgs[dep]}") ret = [] for dep, dbg in dbg_pkgs.items(): if dbg: ret += [dbg] return ret def apt_install(pkgs): if not pkgs: return # Remove duplicates pkgs = list(set(pkgs)) pkgs += apt_get_dbg_pkgs(pkgs) logging.info(f"Installing packages: {', '.join(pkgs)}") testenv.cmd.run(["apt-get", "-q", "install", "-y", "--no-install-recommends"] + pkgs) def clone_project(project): if os.path.exists(os.path.join(git_dir, project)): logging.debug(f"{project}: already cloned") return branch = "master" url = f"https://gerrit.osmocom.org/{project}" if testenv.args.binary_repo.endswith(":latest"): ls_remote = testenv.cmd.run(["git", "ls-remote", "--tags", url], capture_output=True, text=True) tags = [] pattern = re.compile("^\d+\.\d+\.\d+$") for line in ls_remote.stdout.split("\n"): if "refs/tags/" in line: tag = line.split("refs/tags/")[1].split("^")[0] if pattern.match(tag): tags += [tag] tags.sort(key=packaging.version.Version, reverse=True) branch = tags[0] logging.info(f"{project}: cloning {branch}") testenv.cmd.run( [ "git", "-C", git_dir, "clone", "--depth", "1", "--branch", branch, url, ] ) def from_source_sccp_demo_user(): sccp_dir = os.path.join(git_dir, "libosmo-sigtran") sccp_demo_user_path = os.path.join(sccp_dir, "examples/sccp_demo_user") # Install libraries even if not building sccp_demo_user, because it gets # linked dynamically against them. apt_install( [ "libosmo-netif-dev", "libosmocore-dev", ] ) if not os.path.exists(sccp_demo_user_path): clone_project("libosmo-sigtran") logging.info("Building sccp_demo_user") testenv.cmd.run(["autoreconf", "-fi"], cwd=sccp_dir) configure_cmd = ["./configure"] if testenv.args.binary_repo.endswith(":asan"): configure_cmd += ["--enable-sanitize"] testenv.cmd.run(configure_cmd, cwd=sccp_dir) testenv.cmd.run( ["make", "-j", f"{jobs}", "libosmo-sigtran.la"], cwd=os.path.join(sccp_dir, "src"), ) testenv.cmd.run( ["make", "-j", f"{jobs}", "sccp_demo_user"], cwd=os.path.join(sccp_dir, "examples"), ) testenv.cmd.run(["ln", "-s", sccp_demo_user_path, "/usr/local/bin/sccp_demo_user"]) def from_source_osmo_ns_dummy(): libosmocore_dir = os.path.join(git_dir, "libosmocore") osmo_ns_dummy_path = os.path.join(libosmocore_dir, "utils/osmo-ns-dummy") if not os.path.exists(osmo_ns_dummy_path): clone_project("libosmocore") logging.info("Building osmo-ns-dummy") testenv.cmd.run(["autoreconf", "-fi"], cwd=libosmocore_dir) configure_cmd = ["./configure"] if testenv.args.binary_repo.endswith(":asan"): configure_cmd += ["--enable-sanitize"] testenv.cmd.run(configure_cmd, cwd=libosmocore_dir) testenv.cmd.run( [os.path.join(testenv.data_dir, "scripts/build_osmo_ns_dummy.sh"), str(jobs)], cwd=libosmocore_dir ) testenv.cmd.run(["ln", "-s", osmo_ns_dummy_path, "/usr/local/bin/osmo-ns-dummy"]) def from_source(cfg, cfg_name, section): program = cfg[section]["program"].split(" ", 1)[0] if program == "run_sccp_demo_user.sh": return from_source_sccp_demo_user() if program == "run_osmo_ns_dummy.sh": return from_source_osmo_ns_dummy() logging.error(f"Can't install {section}! Fix this by either:") logging.error(f"* Adding package= to [{section}] in {cfg_name}") logging.error(" (if it can be installed from binary packages)") logging.error("* Editing from_source() in testenv/podman_install.py") sys.exit(1) def packages(cfg, cfg_name): packages = [] for section in cfg: if section in ["DEFAULT", "testsuite"]: continue section_data = cfg[section] if "package" in section_data: if section_data["package"] == "no": continue packages += section_data["package"].split(" ") else: from_source(cfg, cfg_name, section) apt_install(packages)