-
Notifications
You must be signed in to change notification settings - Fork 77
/
lib.nix
213 lines (199 loc) · 6.04 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
{
# 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
#
eachSystem = systems: f:
let
# Merge together the outputs for all systems.
op = attrs: system:
let
ret = f system;
op = attrs: key: attrs //
{
${key} = (attrs.${key} or { })
// { ${system} = ret.${key}; };
}
;
in
builtins.foldl' op attrs (builtins.attrNames ret);
in
builtins.foldl' op { }
(systems
++ # add the current system if --impure is used
(if builtins?currentSystem then
if builtins.elem builtins.currentSystem systems
then []
else [ builtins.currentSystem ]
else
[]))
;
# 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 =
{ drv
, name ? drv.pname or drv.name
, exePath ? drv.passthru.exePath or "/bin/${name}"
}:
{
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