#!/usr/bin/env python3 import argparse import hashlib from pathlib import Path import requests import subprocess import sys def get_hydra_store_path(url): """ Accepts an url to a hydra build. Can be: https://hydra.clerie.de/job/nixfiles/nixfiles/iso/latest-finished Or: https://hydra.clerie.de/build/917 """ r = requests.get(url, headers={"Accept": "application/json"}) r.raise_for_status() return Path(r.json()["buildoutputs"]["out"]["path"]) def cli(): parser = argparse.ArgumentParser( prog="update-from-hydra", description="Fetch the latest build of a Hydra job and set it as a specified symlink", ) parser.add_argument("hydra_url") parser.add_argument("update_path") parser.add_argument("cache_store_uri") args = parser.parse_args() hydra_url = args.hydra_url update_path = Path(args.update_path).absolute() cache_store_uri = args.cache_store_uri print("Update url:", hydra_url) print("Path to update:", update_path) current_store_path = None if update_path.exists(): if not update_path.is_symlink(): print("Path to update is not a symlink") exit(1) current_store_path = update_path.readlink() print("Current store path:", current_store_path) else: print("No current store path, update path does not exist") print("Look up Hydra build metadata") hydra_store_path = get_hydra_store_path(hydra_url) print("Store path in hydra:", hydra_store_path) if current_store_path == hydra_store_path: print("Current store path is up to date") exit() print("Downloading new store paths") subprocess.run(["nix", "copy", "--from", cache_store_uri, hydra_store_path]) print("Finished downloading") print("Updating path to update") update_path.parent.mkdir(parents=True, exist_ok=True) tmp_update_path = update_path.parent / ( update_path.name + ".new") print("Creating temporary symlink:", tmp_update_path) tmp_update_path.symlink_to(hydra_store_path) print("Rename symlink to:", update_path) tmp_update_path.rename(update_path) print("Adding to gcroot") try: gcroots_dir = Path("/nix/var/nix/gcroots/update-from-hydra") update_dir_hash = hashlib.sha256(bytes(update_path)).hexdigest() gcroots_dir.mkdir(parents=True, exist_ok=True) gcroots_symlink = gcroots_dir / update_dir_hash tmp_gcroots_symlink = gcroots_dir / (update_dir_hash + ".new") print("Creating temporary symlink:", tmp_gcroots_symlink) tmp_gcroots_symlink.symlink_to(update_path) print("Rename symlink to:", gcroots_symlink) tmp_gcroots_symlink.rename(gcroots_symlink) except PermissionError: print("Unable to create garbage collector root") if __name__ == "__main__": cli()