mirror of
https://github.com/d9pouces/id_configurator.git
synced 2026-11-09 01:47:21 +01:00
6b6bc541dd
Signed-off-by: d9pouces <github@19pouces.net>
95 lines
3.0 KiB
Python
95 lines
3.0 KiB
Python
"""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://<host used by the client>/ 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()
|