mirror of
https://github.com/flectar/mail.git
synced 2026-11-11 17:57:54 +00:00
95 lines
4.0 KiB
Python
95 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Reconstruct the pinned Parley backport and compare it with checked-in sources."""
|
|
|
|
import hashlib
|
|
import io
|
|
import json
|
|
from pathlib import Path
|
|
import subprocess
|
|
import tarfile
|
|
import tempfile
|
|
import urllib.request
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
PATCHES = ROOT / "patches/parley"
|
|
|
|
|
|
def download(url, checksum):
|
|
with urllib.request.urlopen(url, timeout=60) as response:
|
|
data = response.read()
|
|
actual = hashlib.sha256(data).hexdigest()
|
|
if actual != checksum:
|
|
raise RuntimeError(f"Checksum mismatch for {url}: {actual}")
|
|
return data
|
|
|
|
|
|
def files(root):
|
|
return {p.relative_to(root): p.read_bytes() for p in root.rglob("*") if p.is_file()}
|
|
|
|
|
|
def main():
|
|
metadata = json.loads((PATCHES / "upstream.json").read_text())
|
|
with tempfile.TemporaryDirectory(prefix="mail-parley-") as tmp:
|
|
tree = Path(tmp)
|
|
version = metadata["version"]
|
|
archive = download(
|
|
f"https://static.crates.io/crates/parley/parley-{version}.crate",
|
|
metadata["sha256"],
|
|
)
|
|
with tarfile.open(fileobj=io.BytesIO(archive)) as source:
|
|
prefix = f"parley-{version}/"
|
|
for member in source.getmembers():
|
|
if not member.isfile():
|
|
raise RuntimeError(f"Unexpected archive member: {member.name}")
|
|
if not member.name.startswith(prefix) or ".." in Path(member.name).parts:
|
|
raise RuntimeError(f"Unsafe archive member: {member.name}")
|
|
dest = tree / "crates/parley" / member.name[len(prefix):]
|
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
dest.write_bytes(source.extractfile(member).read())
|
|
provenance = json.loads((tree / "crates/parley/.cargo_vcs_info.json").read_text())
|
|
if provenance["git"]["sha1"] != metadata["revision"]:
|
|
raise RuntimeError("Parley release revision differs from metadata")
|
|
revision = metadata["emoji_revision"]
|
|
for name, checksum in metadata["emoji_files"].items():
|
|
data = download(
|
|
f"https://raw.githubusercontent.com/linebender/parley/{revision}/parley_emoji/{name}",
|
|
checksum,
|
|
)
|
|
dest = tree / "crates/parley_emoji" / name
|
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
dest.write_bytes(data)
|
|
subprocess.run(
|
|
["git", "apply", str(PATCHES / "0001-emoji-presentation.patch")],
|
|
check=True, cwd=tree,
|
|
)
|
|
for crate in ("parley", "parley_emoji"):
|
|
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", "../../")]:
|
|
text = (ROOT / manifest).read_text()
|
|
patch_section = text.split("[patch.crates-io]", 1)[1].split("\n[", 1)[0]
|
|
if f'parley = {{ path = "{prefix}crates/parley" }}' not in patch_section:
|
|
raise RuntimeError(f"Missing Parley patch in {manifest}")
|
|
lockfile = ROOT / Path(manifest).with_name("Cargo.lock")
|
|
entries = lockfile.read_text().split("[[package]]")
|
|
for crate in ("parley", "parley_emoji"):
|
|
matches = [
|
|
entry for entry in entries
|
|
if f'name = "{crate}"\nversion = "{version}"' in entry
|
|
]
|
|
if len(matches) != 1 or "source = " in matches[0]:
|
|
raise RuntimeError(f"{lockfile}: {crate} must resolve to the local backport")
|
|
if (ROOT / "LICENSES/Parley-Emoji-MIT.txt").read_bytes() != (
|
|
ROOT / "crates/parley_emoji/LICENSE-MIT"
|
|
).read_bytes():
|
|
raise RuntimeError("Packaged Parley emoji license differs from upstream")
|
|
print("Parley backport, source checksums, manifests, and license verified.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|