fix(termux): replace the retired libffi runtime archive
Termux removed libffi 3.5.2 from its rolling package pool. The pinned URL returns 404 and stops runtime-library staging. Pin the available 3.8.0 archive with its downloaded SHA-256, which matches the package index. Name the package, version and URL when a download fails. Flush staging progress so piped build logs preserve the failure order. Update the bionic Python tests to follow the current supplier and binary layout. Verified all 83 library/license archives and 265 staged shared libraries. The complete staging step and its verified cache hit both returned 0. The pinned Python ctypes extension finds its required libffi symbols. Focused tests: 19 passed, 2 skipped. Bionic execution remains a CI gate.
This commit is contained in:
@@ -142,9 +142,9 @@
|
||||
"version": "2.8.4"
|
||||
},
|
||||
"libffi": {
|
||||
"sha256": "8c8c1d6ffb049d8496a21c1202d9b4dc9145140886fdbb45716684565f4ed3f5",
|
||||
"url": "https://packages.termux.dev/apt/termux-main/pool/main/libf/libffi/libffi_3.5.2_aarch64.deb",
|
||||
"version": "3.5.2"
|
||||
"sha256": "4f255badf74cd31f6a2801c17fa1444199c84c834b517b7c843e2fe9ebe91d77",
|
||||
"url": "https://packages.termux.dev/apt/termux-main/pool/main/libf/libffi/libffi_3.8.0_aarch64.deb",
|
||||
"version": "3.8.0"
|
||||
},
|
||||
"libgraphite": {
|
||||
"sha256": "15ac85737a35150cecb9e46ecb32567ae2a4fc28071cdf58fb95e1b77d7889d9",
|
||||
|
||||
@@ -117,8 +117,11 @@ def _ensure_extracted(work: Path, name: str, row: dict) -> Path:
|
||||
except OSError:
|
||||
archive_ok = False
|
||||
if not archive_ok:
|
||||
Download([Source(row["url"], archive, row["sha256"])],
|
||||
partials_dir=scratch).run()
|
||||
try:
|
||||
Download([Source(row["url"], archive, row["sha256"])],
|
||||
partials_dir=scratch).run()
|
||||
except Exception as exc:
|
||||
raise StageError(f"{name} {row['version']}: download failed from {row['url']}: {exc}") from exc
|
||||
if extract.exists():
|
||||
shutil.rmtree(extract)
|
||||
extract.mkdir(parents=True, exist_ok=True)
|
||||
@@ -176,7 +179,7 @@ def stage(payload: Path, table: dict, licenses: dict | None = None) -> Path:
|
||||
target = payload / "runtime-libs/share/doc"
|
||||
shutil.copytree(notices, target, dirs_exist_ok=True, symlinks=True)
|
||||
merged += n
|
||||
print(f" {name} {row['version']}: {n} new .so* -> runtime-libs/lib")
|
||||
print(f" {name} {row['version']}: {n} new .so* -> runtime-libs/lib", flush=True)
|
||||
|
||||
if not any(out.glob("*.so*")):
|
||||
raise StageError("no shared objects staged")
|
||||
|
||||
@@ -64,9 +64,8 @@ def _assert_pinned_bionic_row(lock, pkg, url_suffix_re):
|
||||
|
||||
|
||||
def test_python_bionic_row_matches_supplier(lock):
|
||||
"""The python bionic row is an explicit pin of the TUR .deb; the row and
|
||||
Python.fetch_url(bionic arm) must agree on the same pinned artifact."""
|
||||
_assert_pinned_bionic_row(lock, "python", r"python3\.11_(?P<ver>[0-9.]+)_aarch64\.deb$")
|
||||
"""The Python package definition and lock must agree on the termux-main artifact."""
|
||||
_assert_pinned_bionic_row(lock, "python", r"/p/python/python_(?P<ver>[0-9.]+(?:-[0-9]+)?)_aarch64\.deb$")
|
||||
def test_node_bionic_row_matches_supplier(lock):
|
||||
"""The node bionic row is an explicit pin of the termux-main nodejs .deb;
|
||||
the row and Nodejs.fetch_url(bionic arm) must agree."""
|
||||
@@ -79,18 +78,13 @@ def test_termux_docker_row_pins_digest(lock):
|
||||
assert row["url"] == f"docker://termux/termux-docker@{version}"
|
||||
|
||||
|
||||
def test_bionic_fetch_urls_resolve():
|
||||
def test_python_bionic_pin_is_independent_of_desktop_build_version(lock):
|
||||
from pm.registry import get_package
|
||||
|
||||
py = get_package("python")
|
||||
version = "3.11.15+20260807"
|
||||
assert py.fetch_url(version, "linux-arm64-bionic").endswith(
|
||||
"python3.11_3.11.15_aarch64.deb"
|
||||
)
|
||||
nd = get_package("node")
|
||||
assert nd.fetch_url("26.4.0", "linux-arm64-bionic").endswith(
|
||||
"nodejs_26.4.0-1_aarch64.deb"
|
||||
)
|
||||
package = lock["packages"]["python"]
|
||||
assert py.fetch_url(package["version"], "linux-arm64-bionic") == package["artifacts"]["linux-arm64-bionic"]["url"]
|
||||
assert py.deb_package == "python"
|
||||
|
||||
|
||||
def test_uv_bionic_row_matches_supplier(lock):
|
||||
@@ -164,7 +158,7 @@ def test_python_bionic_verify_is_file_evidence(tmp_path: Path):
|
||||
from pm.registry import get_package
|
||||
|
||||
py = get_package("python")
|
||||
bin_rel = Path("data/data/com.termux/files/usr/bin/python3.11")
|
||||
bin_rel = Path(py.prefix_rel) / py.main_rel("linux-arm64-bionic")
|
||||
entry = tmp_path / "entry"
|
||||
(entry / bin_rel).parent.mkdir(parents=True)
|
||||
(entry / bin_rel).write_bytes(b"bionic-elf-bytes")
|
||||
|
||||
@@ -217,6 +217,19 @@ def test_rebuild_removes_superseded_license_files(tmp_path, lib_source):
|
||||
assert (out / "liba.so").is_file()
|
||||
|
||||
|
||||
def test_failed_download_identifies_the_pin_without_publishing(tmp_path, lib_source):
|
||||
_, table = lib_source
|
||||
(tmp_path / "debs/libb.deb").unlink()
|
||||
payload = tmp_path / "payload"
|
||||
with pytest.raises(srl.StageError) as caught:
|
||||
srl.stage(payload, table)
|
||||
message = str(caught.value)
|
||||
assert "libb" in message and table["libb"]["version"] in message
|
||||
assert table["libb"]["url"] in message
|
||||
assert "404" in message
|
||||
assert not (payload / "runtime-libs/manifest.json").exists()
|
||||
|
||||
|
||||
def test_stale_scratch_cannot_poison_a_rebuilt_cache(tmp_path, lib_source):
|
||||
_, table = lib_source
|
||||
out = _stage(tmp_path, table)
|
||||
|
||||
Reference in New Issue
Block a user