95 lines
2.5 KiB
Python
95 lines
2.5 KiB
Python
# flake8: noqa
|
|
from __future__ import annotations
|
|
import json
|
|
import subprocess
|
|
from typing import Any
|
|
from dataclasses import dataclass
|
|
from collections.abc import Callable
|
|
|
|
|
|
@dataclass
|
|
class ProcessResult[T]:
|
|
stdout: T
|
|
returncode: int
|
|
|
|
def success(self) -> bool:
|
|
return self.returncode == 0
|
|
|
|
def map[U](self, f: Callable[[T], U]) -> ProcessResult[U]:
|
|
new_stdout: U = f(self.stdout)
|
|
return ProcessResult(stdout=new_stdout, returncode=self.returncode)
|
|
|
|
|
|
def run(*cmd: str) -> ProcessResult[str]:
|
|
print(f"running {cmd!r}")
|
|
proc = subprocess.Popen(
|
|
cmd, stdout=subprocess.PIPE, stderr=None, stdin=subprocess.DEVNULL, text=True
|
|
)
|
|
(stdout_data, _) = proc.communicate()
|
|
print(f"finished, exit code {proc.returncode}")
|
|
return ProcessResult(stdout=stdout_data, returncode=proc.returncode)
|
|
|
|
|
|
def must_succeed(*cmd: str) -> str:
|
|
res = run(*cmd)
|
|
assert res.success()
|
|
return res.stdout
|
|
|
|
|
|
def parse_maybe_json(maybe_json: str) -> Any:
|
|
if maybe_json.strip() == "":
|
|
return None
|
|
else:
|
|
return json.loads(maybe_json)
|
|
|
|
|
|
def run_json(*cmd: str) -> ProcessResult[Any]:
|
|
res = run(*cmd)
|
|
return res.map(parse_maybe_json)
|
|
|
|
|
|
def do_build(installable: str, impure: bool) -> bool:
|
|
eval_command = ["nix", "derivation", "show", installable]
|
|
if impure:
|
|
eval_command.append("--impure")
|
|
res = run_json(*eval_command)
|
|
if not res.success():
|
|
return False
|
|
drv_paths = list(res.stdout.keys())
|
|
for drv_path in drv_paths:
|
|
print(f"{installable=} {drv_path=}")
|
|
res = run_json(
|
|
"nix",
|
|
"build",
|
|
"-j1",
|
|
"--keep-going",
|
|
"--no-link",
|
|
"--json",
|
|
drv_path + "^*",
|
|
)
|
|
if not res.success():
|
|
return False
|
|
builds = res.stdout
|
|
for build in builds:
|
|
for out_path in build["outputs"].values():
|
|
print(f"{installable=} {out_path=}")
|
|
res = run("into-nix-cache", out_path)
|
|
if not res.success():
|
|
return False
|
|
return True
|
|
|
|
|
|
res = run_json("nix", "eval", ".#.", "--json", "--apply", "f: f.archival.archiveList")
|
|
assert res.success()
|
|
build_list = res.stdout
|
|
|
|
for info in build_list:
|
|
name = info["name"]
|
|
if info["broken"]:
|
|
print(f"Skipping {name}, marked broken")
|
|
continue
|
|
res = do_build(f".#archival.drvs.{name}", impure=info["impure"])
|
|
if not res:
|
|
continue
|
|
do_build(f".#archival.buildDepsDrvs.{name}", impure=info["impure"])
|