"""Build a minimal, offline, hand-rolled crate and its sparse registry index entry, for integration-testing the `rust` module of id-configurator. No network access and no build backend (cargo) is used: the crate is a plain gzipped tar assembled with the standard library only, so this script can run in a minimal Python image with nothing installed. See https://doc.rust-lang.org/cargo/reference/registries.html#index-format for the sparse registry index/config.json format this reproduces. """ from __future__ import annotations import hashlib import io import json import pathlib import tarfile CRATE = "idconfiguratortestpkg" VERSION = "0.0.1" CRATE_FILE = f"{CRATE}-{VERSION}.crate" OUT_DIR = pathlib.Path("/srv") CARGO_TOML = f"""[package] name = "{CRATE}" version = "{VERSION}" edition = "2021" """ LIB_RS = "// test-only crate served by the id-configurator integration tests\n" def _add_file(archive: tarfile.TarFile, name: str, content: bytes) -> None: info = tarfile.TarInfo(name=f"{CRATE}-{VERSION}/{name}") info.size = len(content) archive.addfile(info, io.BytesIO(content)) def build_crate() -> bytes: buffer = io.BytesIO() with tarfile.open(fileobj=buffer, mode="w:gz") as archive: _add_file(archive, "Cargo.toml", CARGO_TOML.encode("utf-8")) _add_file(archive, "src/lib.rs", LIB_RS.encode("utf-8")) return buffer.getvalue() def index_path(name: str) -> pathlib.Path: """Mirror cargo's sparse index path convention for a crate name.""" if len(name) <= 2: return pathlib.Path(str(len(name))) / name if len(name) == 3: return pathlib.Path("3") / name[0] / name return pathlib.Path(name[0:2]) / name[2:4] / name def write_index(out_dir: pathlib.Path, crate: bytes) -> None: entry = { "name": CRATE, "vers": VERSION, "deps": [], "cksum": hashlib.sha256(crate).hexdigest(), "features": {}, "yanked": False, } path = out_dir / index_path(CRATE) path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(entry) + "\n", encoding="utf-8") def write_config_json(out_dir: pathlib.Path) -> None: # Cargo requires a fully-qualified "dl" download template, so this bakes # in a placeholder that nginx's sub_filter rewrites to the real # https:/// at request time (see # cargo-repo.nginx.conf) - the host and port this fixture is actually # reached on aren't known at image-build time. config = { "dl": "__BASE_URL__/api/v1/crates/{crate}/{version}/download", "api": "__BASE_URL__", } (out_dir / "config.json").write_text(json.dumps(config), encoding="utf-8") def main() -> None: OUT_DIR.mkdir(parents=True, exist_ok=True) crate = build_crate() download_path = OUT_DIR / "api/v1/crates" / CRATE / VERSION / "download" download_path.parent.mkdir(parents=True, exist_ok=True) download_path.write_bytes(crate) write_index(OUT_DIR, crate) write_config_json(OUT_DIR) if __name__ == "__main__": main()