#!/usr/bin/env python3 """Compose a flake.lock for the freshly installed machine — offline. The generated downstream flake has exactly one input, `nomarchy`. A normal `nix flake lock` would fetch it from its forge; on an offline install we already KNOW the answer: the live ISO was built from a specific nomarchy rev whose source (and all transitive inputs, via the ISO's pinned store paths) is on hand. So we write the lock nix would have written: root ─▶ nomarchy (locked to the baked rev+narHash) └─▶ every node from nomarchy's own flake.lock, verbatim Nix resolves locked inputs by narHash against the store before touching the network, so evaluation on the target works without connectivity. Usage: compose-lock.py where / are the flake-lock node fields for the nomarchy input (any input type — github, git, …), baked at package build. """ import json import sys def main() -> None: src_lock, out, locked_json, original_json = sys.argv[1:5] locked = json.loads(locked_json) if not locked.get("narHash"): sys.exit("compose-lock: no narHash in locked metadata") with open(src_lock) as f: upstream = json.load(f) nodes = dict(upstream["nodes"]) # nomarchy's root node describes ITS inputs; that mapping becomes the # input set of the new `nomarchy` node. nomarchy_inputs = nodes.pop("root")["inputs"] if "nomarchy" in nodes: sys.exit("compose-lock: upstream lock already has a 'nomarchy' node") # Follows paths (list-valued inputs) are absolute from the lock's # root; the copied nodes now live one level down, so ["nixpkgs"] # must become ["nomarchy", "nixpkgs"]. Plain string values reference # node keys directly and stay as they are. for node in nodes.values(): for name, ref in node.get("inputs", {}).items(): if isinstance(ref, list): node["inputs"][name] = ["nomarchy"] + ref nodes["nomarchy"] = { "inputs": nomarchy_inputs, "locked": locked, "original": json.loads(original_json), } nodes["root"] = {"inputs": {"nomarchy": "nomarchy"}} with open(out, "w") as f: json.dump({"nodes": nodes, "root": "root", "version": 7}, f, indent=2) f.write("\n") pin = locked.get("rev", locked["narHash"])[:12] print(f"compose-lock: wrote {out} (nomarchy @ {pin})") if __name__ == "__main__": main()