diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2021-01-24 01:13:31 +0100 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2021-01-24 01:13:31 +0100 |
commit | ada96f10e64d34f06853d9915a8db580420e69b4 (patch) | |
tree | c551ff5a31db95fbf9f26cb02ada00d2cb0b3384 /lib | |
parent | 3d11eafc9c516321901908338befe4c04b58f3aa (diff) | |
download | Nix-ada96f10e64d34f06853d9915a8db580420e69b4.tar.gz Nix-ada96f10e64d34f06853d9915a8db580420e69b4.tar.zst Nix-ada96f10e64d34f06853d9915a8db580420e69b4.zip |
Use relative path for private flakes
Diffstat (limited to 'lib')
-rw-r--r-- | lib/flake-compat-patched.nix | 190 | ||||
-rw-r--r-- | lib/flake-compat.nix | 12 |
2 files changed, 197 insertions, 5 deletions
diff --git a/lib/flake-compat-patched.nix b/lib/flake-compat-patched.nix new file mode 100644 index 0000000..217a99f --- /dev/null +++ b/lib/flake-compat-patched.nix | |||
@@ -0,0 +1,190 @@ | |||
1 | # Compatibility function to allow flakes to be used by | ||
2 | # non-flake-enabled Nix versions. Given a source tree containing a | ||
3 | # 'flake.nix' and 'flake.lock' file, it fetches the flake inputs and | ||
4 | # calls the flake's 'outputs' function. It then returns an attrset | ||
5 | # containing 'defaultNix' (to be used in 'default.nix'), 'shellNix' | ||
6 | # (to be used in 'shell.nix'). | ||
7 | |||
8 | { src, system ? builtins.currentSystem or "unknown-system" }: | ||
9 | |||
10 | let | ||
11 | |||
12 | lockFilePath = src + "/flake.lock"; | ||
13 | |||
14 | lockFile = builtins.fromJSON (builtins.readFile lockFilePath); | ||
15 | |||
16 | fetchTree = | ||
17 | info: | ||
18 | if info.type == "github" then | ||
19 | { outPath = fetchTarball "https://api.${info.host or "github.com"}/repos/${info.owner}/${info.repo}/tarball/${info.rev}"; | ||
20 | rev = info.rev; | ||
21 | shortRev = builtins.substring 0 7 info.rev; | ||
22 | lastModified = info.lastModified; | ||
23 | lastModifiedDate = formatSecondsSinceEpoch info.lastModified; | ||
24 | narHash = info.narHash; | ||
25 | } | ||
26 | else if info.type == "git" then | ||
27 | { outPath = | ||
28 | builtins.fetchGit | ||
29 | ({ url = info.url; } | ||
30 | // (if info ? rev then { inherit (info) rev; } else {}) | ||
31 | // (if info ? ref then { inherit (info) ref; } else {}) | ||
32 | ); | ||
33 | lastModified = info.lastModified; | ||
34 | lastModifiedDate = formatSecondsSinceEpoch info.lastModified; | ||
35 | narHash = info.narHash; | ||
36 | } // (if info ? rev then { | ||
37 | rev = info.rev; | ||
38 | shortRev = builtins.substring 0 7 info.rev; | ||
39 | } else { | ||
40 | }) | ||
41 | else if info.type == "path" then | ||
42 | { outPath = builtins.path { path = | ||
43 | if builtins.substring 0 1 info.path == "." | ||
44 | then builtins.toString src + "/" + info.path | ||
45 | else info.path; | ||
46 | }; | ||
47 | narHash = info.narHash; | ||
48 | } | ||
49 | else if info.type == "tarball" then | ||
50 | { outPath = fetchTarball info.url; | ||
51 | narHash = info.narHash; | ||
52 | } | ||
53 | else if info.type == "gitlab" then | ||
54 | { inherit (info) rev narHash lastModified; | ||
55 | outPath = fetchTarball "https://${info.host or "gitlab.com"}/api/v4/projects/${info.owner}%2F${info.repo}/repository/archive.tar.gz?sha=${info.rev}"; | ||
56 | shortRev = builtins.substring 0 7 info.rev; | ||
57 | } | ||
58 | else | ||
59 | # FIXME: add Mercurial, tarball inputs. | ||
60 | throw "flake input has unsupported input type '${info.type}'"; | ||
61 | |||
62 | callFlake4 = flakeSrc: locks: | ||
63 | let | ||
64 | flake = import (flakeSrc + "/flake.nix"); | ||
65 | |||
66 | inputs = builtins.mapAttrs (n: v: | ||
67 | if v.flake or true | ||
68 | then callFlake4 (fetchTree (v.locked // v.info)) v.inputs | ||
69 | else fetchTree (v.locked // v.info)) locks; | ||
70 | |||
71 | outputs = flakeSrc // (flake.outputs (inputs // {self = outputs;})); | ||
72 | in | ||
73 | assert flake.edition == 201909; | ||
74 | outputs; | ||
75 | |||
76 | callLocklessFlake = flakeSrc: | ||
77 | let | ||
78 | flake = import (flakeSrc + "/flake.nix"); | ||
79 | outputs = flakeSrc // (flake.outputs ({ self = outputs; })); | ||
80 | in outputs; | ||
81 | |||
82 | rootSrc = let | ||
83 | # Try to clean the source tree by using fetchGit, if this source | ||
84 | # tree is a valid git repository. | ||
85 | tryFetchGit = src: | ||
86 | if isGit && !isShallow | ||
87 | then | ||
88 | let res = builtins.fetchGit src; | ||
89 | in if res.rev == "0000000000000000000000000000000000000000" then removeAttrs res ["rev" "shortRev"] else res | ||
90 | else { outPath = src; }; | ||
91 | # NB git worktrees have a file for .git, so we don't check the type of .git | ||
92 | isGit = builtins.pathExists (src + "/.git"); | ||
93 | isShallow = builtins.pathExists (src + "/.git/shallow"); | ||
94 | |||
95 | in | ||
96 | { lastModified = 0; lastModifiedDate = formatSecondsSinceEpoch 0; } | ||
97 | // (if src ? outPath then src else tryFetchGit src); | ||
98 | |||
99 | # Format number of seconds in the Unix epoch as %Y%m%d%H%M%S. | ||
100 | formatSecondsSinceEpoch = t: | ||
101 | let | ||
102 | rem = x: y: x - x / y * y; | ||
103 | days = t / 86400; | ||
104 | secondsInDay = rem t 86400; | ||
105 | hours = secondsInDay / 3600; | ||
106 | minutes = (rem secondsInDay 3600) / 60; | ||
107 | seconds = rem t 60; | ||
108 | |||
109 | # Courtesy of https://stackoverflow.com/a/32158604. | ||
110 | z = days + 719468; | ||
111 | era = (if z >= 0 then z else z - 146096) / 146097; | ||
112 | doe = z - era * 146097; | ||
113 | yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; | ||
114 | y = yoe + era * 400; | ||
115 | doy = doe - (365 * yoe + yoe / 4 - yoe / 100); | ||
116 | mp = (5 * doy + 2) / 153; | ||
117 | d = doy - (153 * mp + 2) / 5 + 1; | ||
118 | m = mp + (if mp < 10 then 3 else -9); | ||
119 | y' = y + (if m <= 2 then 1 else 0); | ||
120 | |||
121 | pad = s: if builtins.stringLength s < 2 then "0" + s else s; | ||
122 | in "${toString y'}${pad (toString m)}${pad (toString d)}${pad (toString hours)}${pad (toString minutes)}${pad (toString seconds)}"; | ||
123 | |||
124 | allNodes = | ||
125 | builtins.mapAttrs | ||
126 | (key: node: | ||
127 | let | ||
128 | sourceInfo = | ||
129 | if key == lockFile.root | ||
130 | then rootSrc | ||
131 | else fetchTree (node.info or {} // removeAttrs node.locked ["dir"]); | ||
132 | |||
133 | subdir = if key == lockFile.root then "" else node.locked.dir or ""; | ||
134 | |||
135 | flake = import (sourceInfo + (if subdir != "" then "/" else "") + subdir + "/flake.nix"); | ||
136 | |||
137 | inputs = builtins.mapAttrs | ||
138 | (inputName: inputSpec: allNodes.${resolveInput inputSpec}) | ||
139 | (node.inputs or {}); | ||
140 | |||
141 | # Resolve a input spec into a node name. An input spec is | ||
142 | # either a node name, or a 'follows' path from the root | ||
143 | # node. | ||
144 | resolveInput = inputSpec: | ||
145 | if builtins.isList inputSpec | ||
146 | then getInputByPath lockFile.root inputSpec | ||
147 | else inputSpec; | ||
148 | |||
149 | # Follow an input path (e.g. ["dwarffs" "nixpkgs"]) from the | ||
150 | # root node, returning the final node. | ||
151 | getInputByPath = nodeName: path: | ||
152 | if path == [] | ||
153 | then nodeName | ||
154 | else | ||
155 | getInputByPath | ||
156 | # Since this could be a 'follows' input, call resolveInput. | ||
157 | (resolveInput lockFile.nodes.${nodeName}.inputs.${builtins.head path}) | ||
158 | (builtins.tail path); | ||
159 | |||
160 | outputs = flake.outputs (inputs // { self = result; }); | ||
161 | |||
162 | result = outputs // sourceInfo // { inherit inputs; inherit outputs; inherit sourceInfo; }; | ||
163 | in | ||
164 | if node.flake or true then | ||
165 | assert builtins.isFunction flake.outputs; | ||
166 | result | ||
167 | else | ||
168 | sourceInfo | ||
169 | ) | ||
170 | lockFile.nodes; | ||
171 | |||
172 | result = | ||
173 | if !(builtins.pathExists lockFilePath) | ||
174 | then callLocklessFlake rootSrc | ||
175 | else if lockFile.version == 4 | ||
176 | then callFlake4 rootSrc (lockFile.inputs) | ||
177 | else if lockFile.version >= 5 && lockFile.version <= 7 | ||
178 | then allNodes.${lockFile.root} | ||
179 | else throw "lock file '${lockFilePath}' has unsupported version ${toString lockFile.version}"; | ||
180 | |||
181 | in | ||
182 | rec { | ||
183 | defaultNix = | ||
184 | result | ||
185 | // (if result ? defaultPackage.${system} then { default = result.defaultPackage.${system}; } else {}); | ||
186 | |||
187 | shellNix = | ||
188 | defaultNix | ||
189 | // (if result ? devShell.${system} then { default = result.devShell.${system}; } else {}); | ||
190 | } | ||
diff --git a/lib/flake-compat.nix b/lib/flake-compat.nix index 1f0d492..d3daa10 100644 --- a/lib/flake-compat.nix +++ b/lib/flake-compat.nix | |||
@@ -1,6 +1,8 @@ | |||
1 | src: | 1 | src: |
2 | (import ( | 2 | (import ./flake-compat-patched.nix { inherit src; }).defaultNix |
3 | fetchTarball { | 3 | # Until https://github.com/edolstra/flake-compat/pull/18 is accepted |
4 | url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; | 4 | # (import ( |
5 | sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; | 5 | # fetchTarball { |
6 | }) { inherit src; }).defaultNix | 6 | # url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; |
7 | # sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; | ||
8 | # }) { inherit src; }).defaultNix | ||