Skip to content

Instantly share code, notes, and snippets.

@getchoo
Created February 26, 2025 10:02
Show Gist options
  • Save getchoo/694474d78c1d03abd16a99fc2c35cf3e to your computer and use it in GitHub Desktop.
Save getchoo/694474d78c1d03abd16a99fc2c35cf3e to your computer and use it in GitHub Desktop.
Python script for downloading NAR (Nix ARchive) files
#!/usr/bin/env nix-shell
#! nix-shell --pure -i python3 -p nix python3 python3Packages.requests
import argparse
import requests
import subprocess
from pathlib import Path
# https://nix.dev/manual/nix/2.24/store/store-path
DIGEST_SIZE_BYTES = 32
STORE_PATH = "/nix/store"
def digest_from_store_path(store_path: str) -> str:
start_pos = len(STORE_PATH) + 1
return store_path[start_pos : start_pos + DIGEST_SIZE_BYTES]
def parse_narinfo(narinfo: str) -> dict:
res = dict()
for line in narinfo.splitlines():
key, value = line.split(": ")
res[key] = value
return res
parser = argparse.ArgumentParser()
parser.add_argument("-b", "--binary-cache", default="cache.nixos.org")
parser.add_argument("-f", "--file")
parser.add_argument("-o", "--output")
parser.add_argument("installable")
args = parser.parse_args()
eval_command = ["nix", "eval", "--raw"]
if args.file is not None:
eval_command += ["--file", args.file]
eval_command += [f"{args.installable}.outPath"]
store_path = subprocess.run(
eval_command,
capture_output=True,
check=True,
text=True,
).stdout
path_digest = digest_from_store_path(store_path)
s = requests.Session()
narinfo_resp = s.get(f"https://{args.binary_cache}/{path_digest}.narinfo")
narinfo_resp.raise_for_status()
nar_url = parse_narinfo(narinfo_resp.text)["URL"]
nar_resp = s.get(f"https://{args.binary_cache}/{nar_url}")
nar_resp.raise_for_status()
out_path = Path()
if args.output is not None:
out_path = Path(args.output)
else:
out_path = Path(nar_url).name
with open(out_path, "xb") as file:
for chunk in nar_resp.iter_content(chunk_size=1024):
file.write(chunk)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment