7const char *FlakeCompat = R
"(
12 lockFilePath = src + "/flake.lock";
14 lockFile = builtins.fromJSON (builtins.readFile lockFilePath);
16 callFlake4 = flakeSrc: locks:
18 flake = import (flakeSrc + "/flake.nix");
20 inputs = builtins.mapAttrs (n: v:
22 then callFlake4 (fetchTree (v.locked // v.info)) v.inputs
23 else fetchTree (v.locked // v.info)) locks;
25 outputs = flakeSrc // (flake.outputs (inputs // {self = outputs;}));
27 assert flake.edition == 201909;
30 callLocklessFlake = flakeSrc:
32 flake = import (flakeSrc + "/flake.nix");
33 outputs = flakeSrc // (flake.outputs ({ self = outputs; }));
37 addOutPath = src: { outPath = src; };
39 { lastModified = 0; lastModifiedDate = formatSecondsSinceEpoch 0; }
42 # Format number of seconds in the Unix epoch as %Y%m%d%H%M%S.
43 formatSecondsSinceEpoch = t:
45 rem = x: y: x - x / y * y;
47 secondsInDay = rem t 86400;
48 hours = secondsInDay / 3600;
49 minutes = (rem secondsInDay 3600) / 60;
52 # Courtesy of https://stackoverflow.com/a/32158604.
54 era = (if z >= 0 then z else z - 146096) / 146097;
55 doe = z - era * 146097;
56 yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
58 doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
59 mp = (5 * doy + 2) / 153;
60 d = doy - (153 * mp + 2) / 5 + 1;
61 m = mp + (if mp < 10 then 3 else -9);
62 y' = y + (if m <= 2 then 1 else 0);
64 pad = s: if builtins.stringLength s < 2 then "0" + s else s;
65 in "${toString y'}${pad (toString m)}${pad (toString d)}${pad (toString hours)}${pad (toString minutes)}${pad (toString seconds)}";
72 if key == lockFile.root
74 else fetchTree (node.info or {} // removeAttrs node.locked ["dir"]);
76 subdir = if key == lockFile.root then "" else node.locked.dir or "";
78 outPath = sourceInfo + ((if subdir == "" then "" else "/") + subdir);
80 flake = import (outPath + "/flake.nix");
82 inputs = builtins.mapAttrs
83 (inputName: inputSpec: allNodes.${resolveInput inputSpec})
86 # Resolve a input spec into a node name. An input spec is
87 # either a node name, or a 'follows' path from the root
89 resolveInput = inputSpec:
90 if builtins.isList inputSpec
91 then getInputByPath lockFile.root inputSpec
94 # Follow an input path (e.g. ["dwarffs" "nixpkgs"]) from the
95 # root node, returning the final node.
96 getInputByPath = nodeName: path:
101 # Since this could be a 'follows' input, call resolveInput.
102 (resolveInput lockFile.nodes.${nodeName}.inputs.${builtins.head path})
103 (builtins.tail path);
105 outputs = flake.outputs (inputs // { self = result; });
109 # We add the sourceInfo attribute for its metadata, as they are
110 # relevant metadata for the flake. However, the outPath of the
111 # sourceInfo does not necessarily match the outPath of the flake,
112 # as the flake may be in a subdirectory of a source.
113 # This is shadowed in the next //
116 # This shadows the sourceInfo.outPath
119 inherit inputs; inherit outputs; inherit sourceInfo; _type = "flake";
123 if node.flake or true then
124 assert builtins.isFunction flake.outputs;
132 if !(builtins.pathExists lockFilePath)
133 then callLocklessFlake rootSrc
134 else if lockFile.version == 4
135 then callFlake4 rootSrc (lockFile.inputs)
136 else if lockFile.version >= 5 && lockFile.version <= 7
137 then allNodes.${lockFile.root}
138 else throw "lock file '${lockFilePath}' has unsupported version ${toString lockFile.version}";
149 nix::Value *VSrc = State.allocValue();
150 VSrc->mkPath(State.rootPath(nix::CanonPath(Src)));
152 auto *VFlakeCompat = State.allocValue();
154 nix::Expr *EFlakeCompat =
155 State.parseExprFromString(FlakeCompat, State.rootPath(
"."));
156 State.eval(EFlakeCompat, *VFlakeCompat);
158 State.callFunction(*VFlakeCompat, *VSrc, VRes, noPos);
Utilities about nix flake.
void callDirtyFlake(nix::EvalState &State, std::string_view SrcPath, nix::Value &VRes)
Call nix flake, but do not use any "fetchers".