nixd
Loading...
Searching...
No Matches
Flake.cpp
Go to the documentation of this file.
1#include "nixt/Flake.h"
2
3using namespace nix;
4
5namespace {
6
7const char *FlakeCompat = R"(
8src:
9
10let
11
12 lockFilePath = src + "/flake.lock";
13
14 lockFile = builtins.fromJSON (builtins.readFile lockFilePath);
15
16 callFlake4 = flakeSrc: locks:
17 let
18 flake = import (flakeSrc + "/flake.nix");
19
20 inputs = builtins.mapAttrs (n: v:
21 if v.flake or true
22 then callFlake4 (fetchTree (v.locked // v.info)) v.inputs
23 else fetchTree (v.locked // v.info)) locks;
24
25 outputs = flakeSrc // (flake.outputs (inputs // {self = outputs;}));
26 in
27 assert flake.edition == 201909;
28 outputs;
29
30 callLocklessFlake = flakeSrc:
31 let
32 flake = import (flakeSrc + "/flake.nix");
33 outputs = flakeSrc // (flake.outputs ({ self = outputs; }));
34 in outputs;
35
36 rootSrc = let
37 addOutPath = src: { outPath = src; };
38 in
39 { lastModified = 0; lastModifiedDate = formatSecondsSinceEpoch 0; }
40 // (addOutPath src);
41
42 # Format number of seconds in the Unix epoch as %Y%m%d%H%M%S.
43 formatSecondsSinceEpoch = t:
44 let
45 rem = x: y: x - x / y * y;
46 days = t / 86400;
47 secondsInDay = rem t 86400;
48 hours = secondsInDay / 3600;
49 minutes = (rem secondsInDay 3600) / 60;
50 seconds = rem t 60;
51
52 # Courtesy of https://stackoverflow.com/a/32158604.
53 z = days + 719468;
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;
57 y = yoe + era * 400;
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);
63
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)}";
66
67 allNodes =
68 builtins.mapAttrs
69 (key: node:
70 let
71 sourceInfo =
72 if key == lockFile.root
73 then rootSrc
74 else fetchTree (node.info or {} // removeAttrs node.locked ["dir"]);
75
76 subdir = if key == lockFile.root then "" else node.locked.dir or "";
77
78 outPath = sourceInfo + ((if subdir == "" then "" else "/") + subdir);
79
80 flake = import (outPath + "/flake.nix");
81
82 inputs = builtins.mapAttrs
83 (inputName: inputSpec: allNodes.${resolveInput inputSpec})
84 (node.inputs or {});
85
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
88 # node.
89 resolveInput = inputSpec:
90 if builtins.isList inputSpec
91 then getInputByPath lockFile.root inputSpec
92 else inputSpec;
93
94 # Follow an input path (e.g. ["dwarffs" "nixpkgs"]) from the
95 # root node, returning the final node.
96 getInputByPath = nodeName: path:
97 if path == []
98 then nodeName
99 else
100 getInputByPath
101 # Since this could be a 'follows' input, call resolveInput.
102 (resolveInput lockFile.nodes.${nodeName}.inputs.${builtins.head path})
103 (builtins.tail path);
104
105 outputs = flake.outputs (inputs // { self = result; });
106
107 result =
108 outputs
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 //
114 // sourceInfo
115 // {
116 # This shadows the sourceInfo.outPath
117 inherit outPath;
118
119 inherit inputs; inherit outputs; inherit sourceInfo; _type = "flake";
120 };
121
122 in
123 if node.flake or true then
124 assert builtins.isFunction flake.outputs;
125 result
126 else
127 sourceInfo
128 )
129 lockFile.nodes;
130
131 result =
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}";
139
140in
141 result
142)";
143
144} // namespace
145
146void nixt::callDirtyFlake(EvalState &State, std::string_view Src,
147 nix::Value &VRes) {
148
149 nix::Value *VSrc = State.allocValue();
150 VSrc->mkPath(State.rootPath(nix::CanonPath(Src, nix::CanonPath::fromCwd())));
151
152 auto *VFlakeCompat = State.allocValue();
153
154 nix::Expr *EFlakeCompat = State.parseExprFromString(
155 FlakeCompat, State.rootPath(nix::CanonPath::fromCwd()));
156 State.eval(EFlakeCompat, *VFlakeCompat);
157
158 State.callFunction(*VFlakeCompat, *VSrc, VRes, noPos);
159}
Utilities about nix flake.
Definition Kinds.h:6
void callDirtyFlake(nix::EvalState &State, std::string_view SrcPath, nix::Value &VRes)
Call nix flake, but do not use any "fetchers".