"""Build a minimal, offline, hand-rolled Composer package and its `packages.json` index, for integration-testing the `php` module of id-configurator. No network access and no build backend (composer) is used: the package is a plain zip file assembled with the standard library only, so this script can run in a minimal Python image with nothing installed. """ from __future__ import annotations import hashlib import io import json import pathlib import zipfile VENDOR = "interdiode" PACKAGE = "idconfiguratortestpkg" NAME = f"{VENDOR}/{PACKAGE}" VERSION = "0.0.1" ZIP_NAME = f"{PACKAGE}-{VERSION}.zip" OUT_DIR = pathlib.Path("/srv") COMPOSER_JSON = json.dumps({"name": NAME, "version": VERSION, "type": "library"}) def build_zip() -> bytes: buffer = io.BytesIO() with zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED) as archive: archive.writestr("composer.json", COMPOSER_JSON) archive.writestr( "marker.txt", "test-only package served by the id-configurator integration tests\n", ) return buffer.getvalue() def write_packages_json(out_dir: pathlib.Path, zip_content: bytes) -> None: # Composer requires a fully-qualified dist URL: unlike PyPI's simple # index, it does not resolve relative/root-relative ones against the # repository's own URL for this (non-v2) repository format. The host # and port this fixture will actually be reached on aren't known at # image-build time (tox-docker only assigns them once the container # starts), so this bakes in a placeholder that nginx's sub_filter # rewrites to the real https:/// at request # time (see php-repo.nginx.conf). packages = { "packages": { NAME: { VERSION: { "name": NAME, "version": VERSION, "dist": { "type": "zip", "url": f"__BASE_URL__/{ZIP_NAME}", "shasum": hashlib.sha1(zip_content).hexdigest(), # nosec B324 }, } } } } (out_dir / "packages.json").write_text( json.dumps(packages, indent=2), encoding="utf-8" ) def main() -> None: OUT_DIR.mkdir(parents=True, exist_ok=True) zip_content = build_zip() (OUT_DIR / ZIP_NAME).write_bytes(zip_content) write_packages_json(OUT_DIR, zip_content) if __name__ == "__main__": main()