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
|
let {
body = lib;
lib = nixpkgs.lib // builtins // {
evalSource = let
eval = source: lib.evalModules {
modules = lib.singleton {
_file = toString ./.;
imports = map (source: { inherit source; }) (lib.toList source);
options.source = lib.mkOption {
default = {};
type = lib.types.attrsOf lib.types.source;
};
};
};
sanitize = x: lib.getAttr (lib.typeOf x) {
bool = x;
list = map sanitize x;
set = lib.mapAttrs
(lib.const sanitize)
(lib.filterAttrs
(name: value: name != "_module" && value != null) x);
string = x;
};
in
# This function's return value can be used as pkgs.populate input.
source: sanitize (eval source).config.source;
# Inputs a source draws from other sources, as list of attribute sets like
# { path = [ "stockholm" "nixpkgs" ]; source = "nixpkgs"; }.
flakeFollows = source: let
flatten = prefix: inputs: lib.concatLists (lib.mapAttrsToList
(name: input:
lib.optional (input.follows or null != null) {
path = prefix ++ [ name ];
source = input.follows;
} ++
flatten (prefix ++ [ name ]) (input.inputs or {}))
inputs);
in
flatten [] (source.${source.type}.inputs or {});
# Tells whether a source's inputs get drawn from other sources by a
# generated flake in .populate/flakes, instead of by rewriting the lock
# file of the flake in the source. Symlink sources point at other
# sources, whose lock files stay as they are.
hasGeneratedFlake = source:
lib.flakeFollows source != [] &&
(source.type == "symlink" || !(source.${source.type}.rewriteLock or true));
# Tells whether a flake or flake-input source gets delivered as a copy,
# which gets patched, gets its lock file rewritten, or is materialized.
derivesFlake = source: let
source' = source.${source.type};
in
lib.elem source.type [ "flake" "flake-input" ] &&
(source'.materialize or false || source'.patches or [] != [] ||
(source'.rewriteLock or true && lib.flakeFollows source != []));
maybeHostName = default: let
# We're parsing /etc/hostname here because reading
# /proc/sys/kernel/hostname yields ""
path = "/etc/hostname";
lines = lib.splitString "\n" (lib.readFile path);
hostNames = lib.filter lib.types.label.check lines;
in
if lib.pathExists path then
if lib.length hostNames == 1 then
lib.head hostNames
else
lib.trace "malformed ${path}" default
else
default;
firstWord = s:
lib.head (lib.match "^([^[:space:]]*).*" s);
isLocalTarget = let
origin = lib.mkTarget "";
in target:
target.user == origin.user &&
lib.elem target.host [origin.host "localhost"];
mkTarget = s: let
parse = lib.match "(([^@]*)@)?(([^:/]+))?(:([^/]+))?(/.*)?" s;
elemAt' = xs: i: if lib.length xs > i then lib.elemAt xs i else null;
filterNull = lib.filterAttrs (n: v: v != null);
in {
user = lib.maybeEnv "LOGNAME" null;
host = lib.maybeEnv "HOSTNAME" (lib.maybeHostName "localhost");
port = null;
path = "/var/src";
sudo = false;
extraOptions = [];
} // (if lib.isString s then filterNull {
user = elemAt' parse 1;
host = elemAt' parse 3;
port = elemAt' parse 5;
path = elemAt' parse 6;
} else s);
mkUserPortSSHOpts = target:
(lib.optionals (target.user != null) ["-l" target.user]) ++
(lib.optionals (target.port != null) ["-p" target.port]);
shell = let
isSafeChar = lib.testString "[-+./0-9:=A-Z_a-z]";
quoteChar = c:
if isSafeChar c then c
else if c == "\n" then "'\n'"
else "\\${c}";
in {
quote = x: if x == "" then "''" else lib.stringAsChars quoteChar x;
# Shell code defining the function url_path, which prints the path $1
# as it goes into a URL: with every byte percent-encoded that isn't a
# letter, a digit, or one of -._~/. Nix decodes that, and otherwise
# takes, e.g., ? and # for delimiters, and refuses blanks.
urlPath = /* sh */ ''
url_path() {
printf %s "$1" | od -An -v -tx1 | tr -s ' ' '\n' |
while read -r url_byte; do
case $url_byte in
"") ;;
2[d-f]|3[0-9]|4[1-9a-f]|5[0-9a]|5f|6[1-9a-f]|7[0-9a]|7e)
printf "\\$(printf %o "0x$url_byte")"
;;
*)
printf '%%%s' "$url_byte"
;;
esac
done
}
'';
# Shell code that enables flakes for the Nix commands following it, and
# fails unless Nix supports them, i.e. is version 2.4 or later. `what`
# names what needs flakes, for the error message.
requireFlakes = what: /* sh */ ''
NIX_CONFIG=$(printf '%s\n%s' "''${NIX_CONFIG-}" \
'extra-experimental-features = nix-command flakes')
export NIX_CONFIG
if ! nix flake --help >/dev/null 2>&1; then
>&2 printf 'error: %s needs Nix 2.4 or later on %s, found: %s\n' \
${lib.shell.quote what} "$(uname -n)" "$(nix --version 2>&1 || :)"
exit 1
fi
'';
};
test = re: x: lib.isString x && lib.testString re x;
testString = re: x: lib.match re x != null;
types = nixpkgs.lib.types // import ./types { lib = body; };
};
nixpkgs.lib = import <nixpkgs/lib>;
}
|