From ade9e5bfb00494c9f723b98257604406d02383c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kjellstrup?= Date: Mon, 18 May 2026 09:21:55 +0200 Subject: [PATCH 1/2] support for Ubuntu 26.04+ --- tools/setup/install_dependencies.py | 47 +++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/tools/setup/install_dependencies.py b/tools/setup/install_dependencies.py index 8b8bcfd7ba6a..be37f3ff822f 100644 --- a/tools/setup/install_dependencies.py +++ b/tools/setup/install_dependencies.py @@ -178,6 +178,12 @@ "aarch64": "aarch64-unknown-linux-musl", } +# Fallback alternatives tried (in order) when a primary package is unavailable. +# Ubuntu 26.04+ renamed libgstreamer-plugins-good1.0-dev → libgstreamer-plugins-extra1.0-dev. +DEBIAN_PACKAGE_ALTERNATIVES: dict[str, list[str]] = { + "libgstreamer-plugins-good1.0-dev": ["libgstreamer-plugins-extra1.0-dev"], +} + APT_BASE_OPTIONS: list[str] = [ "-o", "DPkg::Lock::Timeout=300", @@ -285,12 +291,18 @@ def get_brew_install_command(packages: list[str]) -> list[str]: def check_apt_package_available(package: str) -> bool: - """Check if an apt package is available.""" + """Check if an apt package has an installation candidate (not merely referenced).""" result = subprocess.run( - ["apt-cache", "show", package], + ["apt-cache", "policy", package], capture_output=True, + text=True, ) - return result.returncode == 0 + if result.returncode != 0: + return False + for line in result.stdout.splitlines(): + if "Candidate:" in line: + return "(none)" not in line + return False def get_available_debian_packages(category: str) -> list[str]: @@ -303,6 +315,32 @@ def get_available_debian_packages(category: str) -> list[str]: return [pkg for pkg, ok in zip(packages, available, strict=False) if ok] +def resolve_package_alternatives(packages: list[str]) -> list[str]: + """Replace packages with their first available alternative when the primary is missing.""" + needs_check = {pkg for pkg in packages if pkg in DEBIAN_PACKAGE_ALTERNATIVES} + if not needs_check: + return packages + + all_candidates = {name for pkg in needs_check for name in [pkg, *DEBIAN_PACKAGE_ALTERNATIVES[pkg]]} + with ThreadPoolExecutor() as pool: + availability = dict(zip(all_candidates, pool.map(check_apt_package_available, all_candidates), strict=False)) + + resolved = [] + for pkg in packages: + if pkg not in needs_check: + resolved.append(pkg) + continue + chosen = pkg + if not availability.get(pkg): + for alt in DEBIAN_PACKAGE_ALTERNATIVES[pkg]: + if availability.get(alt): + print(f" Package {pkg} not available; using {alt}") + chosen = alt + break + resolved.append(chosen) + return resolved + + def validate_extra_packages(packages: list[str]) -> list[str]: """Validate extra package names passed from CI inputs.""" validated: list[str] = [] @@ -515,6 +553,9 @@ def install_debian( packages = get_debian_packages() packages = [pkg for pkg in packages if pkg not in bootstrap_packages] + # Resolve alternatives for packages renamed/replaced in newer distro releases + packages = resolve_package_alternatives(packages) + # Install main packages print(f"\nInstalling {len(packages)} packages...") if not run_apt_install_with_retry(packages, dry_run, sudo=True): From cb3808ea9606472f6a0773ba0cac33e6bb4113a0 Mon Sep 17 00:00:00 2001 From: Holden Ramsey <68555040+HTRamsey@users.noreply.github.com> Date: Thu, 21 May 2026 02:18:16 -0400 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- tools/setup/install_dependencies.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/setup/install_dependencies.py b/tools/setup/install_dependencies.py index be37f3ff822f..5309d99ab8f0 100644 --- a/tools/setup/install_dependencies.py +++ b/tools/setup/install_dependencies.py @@ -321,9 +321,17 @@ def resolve_package_alternatives(packages: list[str]) -> list[str]: if not needs_check: return packages - all_candidates = {name for pkg in needs_check for name in [pkg, *DEBIAN_PACKAGE_ALTERNATIVES[pkg]]} + all_candidates = sorted( + {name for pkg in needs_check for name in [pkg, *DEBIAN_PACKAGE_ALTERNATIVES[pkg]]} + ) with ThreadPoolExecutor() as pool: - availability = dict(zip(all_candidates, pool.map(check_apt_package_available, all_candidates), strict=False)) + availability = dict( + zip( + all_candidates, + pool.map(check_apt_package_available, all_candidates), + strict=False, + ) + ) resolved = [] for pkg in packages: