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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
|
{
lib,
stdenvNoCC,
curl, # Note that `curl' may be `null', in case of the native stdenvNoCC.
cacert ? null,
rewriteURL,
hashedMirrors,
}:
let
defaultNativeBuildInputs = [ curl ];
inherit (lib)
concatMap
elemAt
fakeHash
fakeSha256
fakeSha512
filter
hasPrefix
head
isList
isString
length
mapAttrs'
match
nameValuePair
toFile
toShellVars
warn
;
nixpkgsVersion = lib.trivial.release;
mirrors = import ./mirrors.nix // {
inherit hashedMirrors;
};
# Write the list of mirrors to a file that we can reuse between
# fetchurl instantiations, instead of passing the mirrors to
# fetchurl instantiations via environment variables. This makes the
# resulting store derivations (.drv files) much smaller, which in
# turn makes nix-env/nix-instantiate faster.
mirrorsListFile =
let
# Add a prefix to the names of the mirrors to avoid variable name clashes in the builder
mirrorsPrefixed = mapAttrs' (n: v: nameValuePair ("_mirror_" + n) v) mirrors;
in
toFile "mirrors-list" (toShellVars mirrorsPrefixed);
# Names of the master sites that are mirrored (i.e., "sourceforge",
# "gnu", etc.).
sites = builtins.attrNames mirrors;
# partially applied set of functions for each hash type
# this is indexed into with a prefix to avoid re-calling hasPrefix, since it
# takes advantage of partial application for performance reasons
hasAlgoPrefix = lib.genAttrs [ "sha256" "sha1" "sha512" ] hasPrefix;
/**
Resolve a URL against the available mirrors.
If the input is a `"mirror://"` URL, it is normalized.
Otherwise, the URL is returned unmodified in a singleton list.
Mirror URLs should be formatted as:
```
mirror://{mirror_name}/{path}
```
The specified `mirror_name` must correspond to an entry in `pkgs/build-support/fetchurl/mirrors.nix`, otherwise an error is thrown.
# Inputs
`url` (String)
: A (possibly `"mirror://"`) URL to resolve.
# Output
A list of resolved URLs.
*/
resolveUrl =
url:
let
mirrorSplit = match "mirror://([[:alpha:]]+)/(.+)" url;
mirrorName = head mirrorSplit;
mirrorList = mirrors."${mirrorName}" or (throw "unknown mirror:// site ${mirrorName}");
in
if mirrorSplit == null || mirrorName == null then
[ url ]
else
map (mirror: mirror + elemAt mirrorSplit 1) mirrorList;
rewriteAllUrls =
if rewriteURL == null then
urls: urls
else
urls:
let
u = concatMap (
url:
let
rewritten = rewriteURL url;
in
if isString rewritten then [ rewritten ] else [ ]
) urls;
in
if u == [ ] then throw "urls is empty after rewriteURL (was ${toString urls})" else u;
impureEnvVars =
lib.fetchers.proxyImpureEnvVars
++ [
# This variable allows the user to pass additional options to curl
"NIX_CURL_FLAGS"
# This variable allows the user to override hashedMirrors from the
# command-line.
"NIX_HASHED_MIRRORS"
# This variable allows overriding the timeout for connecting to
# the hashed mirrors.
"NIX_CONNECT_TIMEOUT"
]
++ (map (site: "NIX_MIRRORS_${site}") sites);
in
lib.extendMkDerivation {
constructDrv = stdenvNoCC.mkDerivation;
excludeDrvArgNames = [
# Passed via passthru
"url"
# Additional stdenv.mkDerivation arguments from derived fetchers.
"derivationArgs"
# Hash attributes will be map to the corresponding outputHash*
"sha1"
"sha256"
"sha512"
];
extendDrvArgs =
finalAttrs:
{
# URL to fetch.
url ? "",
# Alternatively, a list of URLs specifying alternative download
# locations. They are tried in order.
urls ? [ ],
# Additional curl options needed for the download to succeed.
# Warning: Each space (no matter the escaping) will start a new argument.
# If you wish to pass arguments with spaces, use `curlOptsList`
curlOpts ? "",
# Additional curl options needed for the download to succeed.
curlOptsList ? [ ],
# Name of the file when pname + version is unspecified.
# Default to the basename of `url' (or of the first element of `urls').
name ? null,
# for versioned downloads optionally take pname + version.
pname ? null,
version ? null,
# SRI hash.
hash ? "",
# Legacy ways of specifying the hash.
outputHash ? "",
outputHashAlgo ? "",
sha1 ? "",
sha256 ? "",
sha512 ? "",
recursiveHash ? false,
# Shell code to build a netrc file for BASIC auth
netrcPhase ? null,
# Impure env vars (https://nixos.org/nix/manual/#sec-advanced-attributes)
# needed for netrcPhase
netrcImpureEnvVars ? [ ],
# Shell code executed after the file has been fetched
# successfully. This can do things like check or transform the file.
postFetch ? "",
# Whether to download to a temporary path rather than $out. Useful
# in conjunction with postFetch. The location of the temporary file
# is communicated to postFetch via $downloadedFile.
downloadToTemp ? false,
# If true, set executable bit on downloaded file
executable ? false,
# If set, don't download the file, but write a list of all possible
# URLs (resulting from resolving mirror:// URLs) to $out.
showURLs ? false,
# Meta information, if any.
meta ? { },
# Passthru information, if any.
passthru ? { },
# Doing the download on a remote machine just duplicates network
# traffic, so don't do that by default
preferLocalBuild ? true,
# Additional packages needed as part of a fetch
nativeBuildInputs ? [ ],
# Additional stdenvNoCC.mkDerivation arguments.
# It is typically for derived fetchers to pass down additional arguments,
# and the specified arguments have lower precedence than other mkDerivation arguments.
derivationArgs ? { },
}@args:
let
preRewriteUrls =
if urls == [ ] && url != "" then
(
if isString url then [ url ] else throw "`url` is not a string: ${lib.generators.toPretty { } urls}"
)
else if urls != [ ] && url == "" then
(if isList urls then urls else throw "`urls` is not a list: ${lib.generators.toPretty { } urls}")
else
throw "fetchurl requires either `url` or `urls` to be set: ${lib.generators.toPretty { } args}";
urls_ = rewriteAllUrls preRewriteUrls;
hash_ =
if
length (
filter (s: s != "") [
hash
outputHash
sha1
sha256
sha512
]
) > 1
then
throw "multiple hashes passed to fetchurl: ${lib.generators.toPretty { } urls_}"
else
if hash != "" then
{
outputHashAlgo = null;
outputHash = hash;
}
else if outputHash != "" then
if outputHashAlgo != "" then
{ inherit outputHashAlgo outputHash; }
else
throw "fetchurl was passed outputHash without outputHashAlgo: ${lib.generators.toPretty { } urls_}"
else if sha512 != "" then
{
outputHashAlgo = "sha512";
outputHash = sha512;
}
else if sha256 != "" then
{
outputHashAlgo = "sha256";
outputHash = sha256;
}
else if sha1 != "" then
{
outputHashAlgo = "sha1";
outputHash = sha1;
}
else if cacert != null then
{
outputHashAlgo = null;
outputHash = fakeHash;
}
else
throw "fetchurl requires a hash for fixed-output derivation: ${lib.generators.toPretty { } urls_}";
finalHashHasColon = match ".*:.*" finalAttrs.hash != null;
finalHashColonMatch = match "([^:]+)[:](.*)" finalAttrs.hash;
in
derivationArgs
// {
__structuredAttrs = true;
name =
if finalAttrs.pname or null != null && finalAttrs.version or null != null then
"${finalAttrs.pname}-${finalAttrs.version}"
else if showURLs then
"urls"
else if name != null then
name
else
baseNameOf (toString (head urls_));
builder = ./builder.sh;
nativeBuildInputs = defaultNativeBuildInputs ++ nativeBuildInputs;
strictDeps = true;
urls = urls_;
# If set, prefer the content-addressable mirrors
# (http://tarballs.nixos.org) over the original URLs.
preferHashedMirrors = false;
# New-style output content requirements.
hash =
if
hash_.outputHashAlgo == null
|| hash_.outputHash == ""
|| hasAlgoPrefix.${hash_.outputHashAlgo} hash_.outputHash
then
hash_.outputHash
else
"${hash_.outputHashAlgo}:${hash_.outputHash}";
outputHashAlgo = if finalHashHasColon then head finalHashColonMatch else null;
outputHash =
if finalAttrs.hash == "" then
fakeHash
else if finalHashHasColon then
elemAt finalHashColonMatch 1
else
finalAttrs.hash;
# Disable TLS verification only when we know the hash and no credentials are
# needed to access the resource
env = {
SSL_CERT_FILE =
if
(
hash_.outputHash == ""
|| hash_.outputHash == fakeSha256
|| hash_.outputHash == fakeSha512
|| hash_.outputHash == fakeHash
|| netrcPhase != null
)
then
"${cacert}/etc/ssl/certs/ca-bundle.crt"
else
"/no-cert-file.crt";
}
// (derivationArgs.env or { });
outputHashMode = if (recursiveHash || executable) then "recursive" else "flat";
curlOpts =
if isList curlOpts then
warn (
let
url = toString (builtins.head urls_);
curlOptsRepresentation = lib.generators.toPretty { multiline = false; } curlOpts;
curlOptsAsStringRepresentation = lib.strings.escapeNixString (toString curlOpts);
curlOptsListElementsRepresentation =
lib.concatMapStringsSep " " lib.strings.escapeNixString
curlOpts;
in
''
fetchurl for ${url}: curlOpts is a list (${curlOptsRepresentation}), which is not supported anymore.
- If you wish to get the same effect as before, for elements with spaces (even if escaped) to expand to multiple curl arguments, use a string argument instead:
curlOpts = ${curlOptsAsStringRepresentation};
- If you wish for each list element to be passed as a separate curl argument, allowing arguments to contain spaces, use curlOptsList instead:
curlOptsList = [ ${curlOptsListElementsRepresentation} ];
''
) curlOpts
else
curlOpts;
inherit
curlOptsList
downloadToTemp
executable
mirrorsListFile
postFetch
showURLs
;
impureEnvVars = impureEnvVars ++ netrcImpureEnvVars;
inherit nixpkgsVersion;
inherit preferLocalBuild;
inherit meta;
passthru = {
inherit url;
resolvedUrl = head (resolveUrl url);
}
// passthru;
};
# No ellipsis
inheritFunctionArgs = false;
}
// {
inherit resolveUrl;
}
|