forked from numtide/flake-utils
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lib.nix
251 lines (235 loc) · 7.57 KB
/
lib.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
{
# The list of systems supported by nixpkgs and hydra
defaultSystems ? [
"aarch64-linux"
"aarch64-darwin"
"x86_64-darwin"
"x86_64-linux"
]
}:
let
inherit defaultSystems;
# List of all systems defined in nixpkgs
# Keep in sync with nixpkgs wit the following command:
# $ nix-instantiate --json --eval --expr "with import <nixpkgs> {}; lib.platforms.all" | jq 'sort' | sed 's!,!!' > allSystems.nix
allSystems = import ./allSystems.nix;
# A map from system to system. It's useful to detect typos.
#
# Instead of typing `"x86_64-linux"`, type `flake-utils.lib.system.x86_64-linux`
# and get an error back if you used a dash instead of an underscore.
system =
builtins.listToAttrs
(map (system: { name = system; value = system; }) allSystems);
# eachSystem using defaultSystems
eachDefaultSystem = eachSystem defaultSystems;
# Builds a map from <attr>=value to <attr>.<system>=value for each system,
# except for the `hydraJobs` attribute, where it maps the inner attributes,
# from hydraJobs.<attr>=value to hydraJobs.<attr>.<system>=value.
#
eachSystem = systems: f:
let
# Taken from <nixpkgs/lib/attrsets.nix>
isDerivation = x: builtins.isAttrs x && x ? type && x.type == "derivation";
# Used to match Hydra's convention of how to define jobs. Basically transforms
#
# hydraJobs = {
# hello = <derivation>;
# haskellPackages.aeson = <derivation>;
# }
#
# to
#
# hydraJobs = {
# hello.x86_64-linux = <derivation>;
# haskellPackages.aeson.x86_64-linux = <derivation>;
# }
#
# if the given flake does `eachSystem [ "x86_64-linux" ] { ... }`.
pushDownSystem = system: merged:
builtins.mapAttrs
(name: value:
if ! (builtins.isAttrs value) then value
else if isDerivation value then (merged.${name} or { }) // { ${system} = value; }
else pushDownSystem system (merged.${name} or { }) value);
# Merge together the outputs for all systems.
op = attrs: system:
let
ret = f system;
op = attrs: key:
let
appendSystem = key: system: ret:
if key == "hydraJobs"
then (pushDownSystem system (attrs.hydraJobs or { }) ret.hydraJobs)
else { ${system} = ret.${key}; };
in
attrs //
{
${key} = (attrs.${key} or { })
// (appendSystem key system ret);
}
;
in
builtins.foldl' op attrs (builtins.attrNames ret);
in
builtins.foldl' op { } systems
;
# eachSystemMap using defaultSystems
eachDefaultSystemMap = eachSystemMap defaultSystems;
# Builds a map from <attr>=value to <system>.<attr> = value.
eachSystemMap = systems: f: builtins.listToAttrs (builtins.map (system: { name = system; value = f system; }) systems);
# Nix flakes insists on having a flat attribute set of derivations in
# various places like the `packages` and `checks` attributes.
#
# This function traverses a tree of attributes (by respecting
# recurseIntoAttrs) and only returns their derivations, with a flattened
# key-space.
#
# Eg:
#
# flattenTree { hello = pkgs.hello; gitAndTools = pkgs.gitAndTools };
#
# Returns:
#
# {
# hello = «derivation»;
# "gitAndTools/git" = «derivation»;
# "gitAndTools/hub" = «derivation»;
# # ...
# }
flattenTree = tree: import ./flattenTree.nix tree;
# Nix check functionality validates packages for various conditions, like if
# they build for any given platform or if they are marked broken.
#
# This function filters a flattend package set for conditinos that
# would *trivially* break `nix flake check`. It does not flatten a tree and it
# does not implement advanced package validation checks.
#
# Eg:
#
# filterPackages "x86_64-linux" {
# hello = pkgs.hello;
# "gitAndTools/git" = pkgs.gitAndTools // {meta.broken = true;};
# };
#
# Returns:
#
# {
# hello = «derivation»;
# }
filterPackages = import ./filterPackages.nix { inherit allSystems; };
# Meld merges subflakes using common inputs. Useful when you want
# to split up a large flake with many different components into more
# manageable parts.
#
# For example:
#
# {
# inputs = {
# flutils.url = "github:numtide/flake-utils";
# nixpkgs.url = "github:nixos/nixpkgs";
# };
# outputs = inputs@{ flutils, ... }: flutils.lib.meld inputs [
# ./nix/packages
# ./nix/hardware
# ./nix/overlays
# # ...
# ];
# }
#
# Where ./nix/packages/default.nix looks like just the output
# portion of a flake.
#
# { flutils, nixpkgs, ... }: flutils.lib.eachDefaultSystem (system:
# let pkgs = import nixpkgs { inherit system; }; in
# {
# packages = {
# foo = ...;
# bar = ...;
# # ...
# };
# }
# )
#
# You can also use meld within the subflakes to further subdivide
# your flake into a tree like structure. For example,
# ./nix/hardware/default.nix might look like:
#
# inputs@{ flutils, ... }: flutils.lib.meld inputs [
# ./foobox.nix
# ./barbox.nix
# ]
meld = let
# Pulled from nixpkgs.lib
recursiveUpdateUntil =
# Predicate, taking the path to the current attribute as a list of strings for attribute names, and the two values at that path from the original arguments.
pred:
# Left attribute set of the merge.
lhs:
# Right attribute set of the merge.
rhs:
let
f = attrPath:
builtins.zipAttrsWith (n: values:
let here = attrPath ++ [ n ];
in if builtins.length values == 1
|| pred here (builtins.elemAt values 1) (builtins.head values) then
builtins.head values
else
f here values);
in f [ ] [ rhs lhs ];
# Pulled from nixpkgs.lib
recursiveUpdate =
# Left attribute set of the merge.
lhs:
# Right attribute set of the merge.
rhs:
recursiveUpdateUntil (path: lhs: rhs: !(builtins.isAttrs lhs && builtins.isAttrs rhs)) lhs
rhs;
in inputs:
builtins.foldl' (output: subflake:
recursiveUpdate output (import subflake inputs)) { };
# Returns the structure used by `nix app`
mkApp = let
# Pulled from nixpkgs.lib
warn =
if builtins.elem (builtins.getEnv "NIX_ABORT_ON_WARN") ["1" "true" "yes"]
then msg: builtins.trace "[1;31mwarning: ${msg}[0m" (abort "NIX_ABORT_ON_WARN=true; warnings are treated as unrecoverable errors.")
else msg: builtins.trace "[1;31mwarning: ${msg}[0m";
in
{ drv
, name ? drv.pname or drv.name
, exePath ? "/bin/${name}"
}:
(if (drv.passthru or {}) ? exePath then
warn
"flake-utils.lib.mkApp: ${name} has the deprecated `drv.passthru.exePath` attribute. Please pass the `exePath` directly."
else
lib.id
)
{
type = "app";
program = "${drv}${exePath}";
};
# This function tries to capture a common flake pattern.
simpleFlake = import ./simpleFlake.nix { inherit lib defaultSystems; };
# Helper functions for Nix evaluation
check-utils = import ./check-utils.nix;
lib = {
inherit
allSystems
check-utils
defaultSystems
eachDefaultSystem
eachSystem
eachDefaultSystemMap
eachSystemMap
filterPackages
flattenTree
meld
mkApp
simpleFlake
system
;
};
in
lib