Files
mail/scripts/verify-slint-winit.py

82 lines
3.7 KiB
Python

#!/usr/bin/env python3
"""Reconstruct the pinned Slint winit clipboard backport."""
import hashlib
import io
import json
from pathlib import Path
import subprocess
import tarfile
import tempfile
import tomllib
import urllib.request
ROOT = Path(__file__).resolve().parent.parent
PATCHES = ROOT / "patches/slint-winit"
CRATE = "i-slint-backend-winit"
def files(root):
return {
p.relative_to(root): p.read_bytes()
for p in root.rglob("*")
if p.is_file() and p.relative_to(root) != Path("Cargo.lock")
}
def main():
metadata = json.loads((PATCHES / "upstream.json").read_text())
version = metadata["version"]
url = f"https://static.crates.io/crates/{CRATE}/{CRATE}-{version}.crate"
with urllib.request.urlopen(url, timeout=60) as response:
archive = response.read()
if hashlib.sha256(archive).hexdigest() != metadata["sha256"]:
raise RuntimeError("Slint winit archive checksum differs from metadata")
with tempfile.TemporaryDirectory(prefix="mail-slint-winit-") as tmp:
tree = Path(tmp)
with tarfile.open(fileobj=io.BytesIO(archive)) as source:
prefix = f"{CRATE}-{version}/"
for member in source.getmembers():
if (not member.isfile() or not member.name.startswith(prefix)
or ".." in Path(member.name).parts):
raise RuntimeError(f"Unsafe archive member: {member.name}")
dest = tree / "crates" / CRATE / member.name[len(prefix):]
dest.parent.mkdir(parents=True, exist_ok=True)
dest.write_bytes(source.extractfile(member).read())
provenance = json.loads((tree / "crates" / CRATE / ".cargo_vcs_info.json").read_text())
if provenance["git"]["sha1"] != metadata["revision"]:
raise RuntimeError("Slint release revision differs from metadata")
for patch in sorted(PATCHES.glob("*.patch")):
subprocess.run(["git", "apply", str(patch)], check=True, cwd=tree)
expected = files(tree / "crates" / CRATE)
actual = files(ROOT / "crates" / CRATE)
for name in sorted(expected.keys() | actual.keys()):
if expected.get(name) != actual.get(name):
raise RuntimeError(f"Vendored source differs: crates/{CRATE}/{name}")
for manifest, prefix in [("Cargo.toml", ""), ("platform/android/Cargo.toml", "../../")]:
patches = tomllib.loads((ROOT / manifest).read_text())["patch"]["crates-io"]
if patches.get(CRATE) != {"path": f"{prefix}crates/{CRATE}"}:
raise RuntimeError(f"Missing Slint winit patch in {manifest}")
lockfile = ROOT / Path(manifest).with_name("Cargo.lock")
packages = tomllib.loads(lockfile.read_text())["package"]
def resolved(name):
return [p for p in packages if p["name"] == name]
backend = resolved(CRATE)
if len(backend) != 1 or backend[0]["version"] != version or "source" in backend[0]:
raise RuntimeError(f"{lockfile}: {CRATE} must resolve to the local backport")
if [p["version"] for p in resolved("slint")] != [version]:
raise RuntimeError(f"{lockfile}: the backport targets Slint {version}")
# smithay-clipboard 0.7.3 moved to SCTK 0.20; 0.7.2 shares winit's SCTK 0.19.
if [p["version"] for p in resolved("smithay-clipboard")] != [metadata["smithay_clipboard"]]:
raise RuntimeError(f"{lockfile}: smithay-clipboard must stay on SCTK 0.19")
if len(resolved("smithay-client-toolkit")) != 1:
raise RuntimeError(f"{lockfile}: expected a single smithay-client-toolkit")
print("Slint winit source checksum, clipboard backport, manifests, and lockfiles verified.")
if __name__ == "__main__":
main()