nix/lib/inputs.nix
2026-05-20 16:02:24 +10:00

96 lines
3.1 KiB
Nix

let
pins = builtins.fromTOML (builtins.readFile ../pins/pins.toml);
lock = builtins.fromJSON (builtins.readFile ../pins/pins.lock.json);
fetchPin = name: builtins.fetchTree lock.${name};
resolveSpec =
upLock: spec:
if builtins.isList spec then walkPath upLock upLock.root spec else spec;
walkPath =
upLock: nodeName: path:
if path == [ ] then
nodeName
else
walkPath upLock (resolveSpec upLock upLock.nodes.${nodeName}.inputs.${builtins.head path}) (
builtins.tail path
);
evalTransitive =
upLock: nodeName: sourceInfo:
let
raw = import (sourceInfo.outPath + "/flake.nix");
node = upLock.nodes.${nodeName};
callerInputs = builtins.mapAttrs (
n: _decl:
let
ref =
(node.inputs or { }).${n}
or (throw "lib/inputs.nix: transitive '${n}' missing in flake.lock node '${nodeName}'");
childName = resolveSpec upLock ref;
childNode = upLock.nodes.${childName};
childSrc = builtins.fetchTree childNode.locked;
in
if childNode.flake or true then evalTransitive upLock childName childSrc else childSrc
) (raw.inputs or { });
outputs = raw.outputs (callerInputs // { self = result; });
result = outputs // sourceInfo // {
outPath = sourceInfo.outPath;
inputs = callerInputs;
inherit outputs;
inherit sourceInfo;
_type = "flake";
};
in
result;
evalTopFlake =
sourceInfo: pin:
let
raw = import (sourceInfo.outPath + "/flake.nix");
upLockPath = sourceInfo.outPath + "/flake.lock";
upLock =
if builtins.pathExists upLockPath then builtins.fromJSON (builtins.readFile upLockPath) else null;
overrides = builtins.mapAttrs (_: target: self.${target}) (pin.follows or { });
callerInputs = builtins.mapAttrs (
n: _decl:
if overrides ? ${n} then
overrides.${n}
else if upLock != null then
let
ref =
(upLock.nodes.${upLock.root}.inputs or { }).${n}
or (throw "lib/inputs.nix: input '${n}' declared but not in flake.lock at ${toString sourceInfo.outPath}");
childName = resolveSpec upLock ref;
childNode = upLock.nodes.${childName};
childSrc = builtins.fetchTree childNode.locked;
in
if childNode.flake or true then evalTransitive upLock childName childSrc else childSrc
else
throw "lib/inputs.nix: no flake.lock at ${toString sourceInfo.outPath}; cannot resolve '${n}'"
) (raw.inputs or { });
outputs = raw.outputs (callerInputs // { self = result; });
result = outputs // sourceInfo // {
outPath = sourceInfo.outPath;
inputs = callerInputs;
inherit outputs;
inherit sourceInfo;
_type = "flake";
};
in
result;
loadPin =
name: pin:
let
sourceInfo = fetchPin name;
in
if pin.flake or true then evalTopFlake sourceInfo pin else sourceInfo.outPath;
self = builtins.mapAttrs loadPin pins.inputs;
in
self