1# snippets that can be shared by multiple fetchers (pkgs/build-support)
2{ lib }:
3let
4 commonH = hashTypes: rec {
5 hashNames = [ "hash" ] ++ hashTypes;
6 hashSet = lib.genAttrs hashNames (lib.const { });
7 };
8
9 fakeH = {
10 hash = lib.fakeHash;
11 sha256 = lib.fakeSha256;
12 sha512 = lib.fakeSha512;
13 };
14in
15rec {
16
17 proxyImpureEnvVars = [
18 # We borrow these environment variables from the caller to allow
19 # easy proxy configuration. This is impure, but a fixed-output
20 # derivation like fetchurl is allowed to do so since its result is
21 # by definition pure.
22 "http_proxy"
23 "https_proxy"
24 "ftp_proxy"
25 "all_proxy"
26 "no_proxy"
27 "HTTP_PROXY"
28 "HTTPS_PROXY"
29 "FTP_PROXY"
30 "ALL_PROXY"
31 "NO_PROXY"
32
33 # https proxies typically need to inject custom root CAs too
34 "NIX_SSL_CERT_FILE"
35 ];
36
37 /**
38 Converts an attrset containing one of `hash`, `sha256` or `sha512`,
39 into one containing `outputHash{,Algo}` as accepted by `mkDerivation`.
40
41 An appropriate “fake hash” is substituted when the hash value is `""`,
42 as is the [convention for fetchers](#sec-pkgs-fetchers-updating-source-hashes-fakehash-method).
43
44 All other attributes in the set remain as-is.
45
46 # Example
47
48 ```nix
49 normalizeHash { } { hash = ""; foo = "bar"; }
50 =>
51 {
52 outputHash = lib.fakeHash;
53 outputHashAlgo = null;
54 foo = "bar";
55 }
56 ```
57
58 ```nix
59 normalizeHash { } { sha256 = lib.fakeSha256; }
60 =>
61 {
62 outputHash = lib.fakeSha256;
63 outputHashAlgo = "sha256";
64 }
65 ```
66
67 ```nix
68 normalizeHash { } { sha512 = lib.fakeSha512; }
69 =>
70 {
71 outputHash = lib.fakeSha512;
72 outputHashAlgo = "sha512";
73 }
74 ```
75
76 # Type
77 ```
78 normalizeHash :: { hashTypes :: List String, required :: Bool } -> AttrSet -> AttrSet
79 ```
80
81 # Arguments
82
83 hashTypes
84 : the set of attribute names accepted as hash inputs, in addition to `hash`
85
86 required
87 : whether to throw if no hash was present in the input; otherwise returns the original input, unmodified
88 */
89 normalizeHash =
90 {
91 hashTypes ? [ "sha256" ],
92 required ? true,
93 }:
94 let
95 inherit (lib)
96 concatMapStringsSep
97 head
98 tail
99 throwIf
100 ;
101 inherit (lib.attrsets)
102 attrsToList
103 intersectAttrs
104 removeAttrs
105 optionalAttrs
106 ;
107
108 inherit (commonH hashTypes) hashNames hashSet;
109 in
110 args:
111 if args ? "outputHash" then
112 args
113 else
114 let
115 # The argument hash, as a {name, value} pair
116 h =
117 # All hashes passed in arguments (possibly 0 or >1) as a list of {name, value} pairs
118 let
119 hashesAsNVPairs = attrsToList (intersectAttrs hashSet args);
120 in
121 if hashesAsNVPairs == [ ] then
122 throwIf required "fetcher called without `hash`" null
123 else if tail hashesAsNVPairs != [ ] then
124 throw "fetcher called with mutually-incompatible arguments: ${
125 concatMapStringsSep ", " (a: a.name) hashesAsNVPairs
126 }"
127 else
128 head hashesAsNVPairs;
129 in
130 removeAttrs args hashNames
131 // (optionalAttrs (h != null) {
132 outputHashAlgo = if h.name == "hash" then null else h.name;
133 outputHash =
134 if h.value == "" then
135 fakeH.${h.name} or (throw "no “fake hash” defined for ${h.name}")
136 else
137 h.value;
138 });
139
140 /**
141 Wraps a function which accepts `outputHash{,Algo}` into one which accepts `hash` or `sha{256,512}`
142
143 # Example
144 ```nix
145 withNormalizedHash { hashTypes = [ "sha256" "sha512" ]; } (
146 { outputHash, outputHashAlgo, ... }:
147 ...
148 )
149 ```
150 is a function which accepts one of `hash`, `sha256`, or `sha512` (or the original's `outputHash` and `outputHashAlgo`).
151
152 Its `functionArgs` metadata only lists `hash` as a parameter, optional iff. `outputHash` was an optional parameter of
153 the original function. `sha256`, `sha512`, `outputHash`, or `outputHashAlgo` are not mentioned in the `functionArgs`
154 metadata.
155
156 # Type
157 ```
158 withNormalizedHash :: { hashTypes :: List String } -> (AttrSet -> T) -> (AttrSet -> T)
159 ```
160
161 # Arguments
162
163 hashTypes
164 : the set of attribute names accepted as hash inputs, in addition to `hash`
165 : they must correspond to a valid value for `outputHashAlgo`, currently one of: `md5`, `sha1`, `sha256`, or `sha512`.
166
167 f
168 : the function to be wrapped
169
170 ::: {.note}
171 In nixpkgs, `mkDerivation` rejects MD5 `outputHash`es, and SHA-1 is being deprecated.
172
173 As such, there is no reason to add `md5` to `hashTypes`, and
174 `sha1` should only ever be included for backwards compatibility.
175 :::
176
177 # Output
178
179 `withNormalizedHash { inherit hashTypes; } f` is functionally equivalent to
180 ```nix
181 args: f (normalizeHash {
182 inherit hashTypes;
183 required = !(lib.functionArgs f).outputHash;
184 } args)
185 ```
186
187 However, `withNormalizedHash` preserves `functionArgs` metadata insofar as possible,
188 and is implemented somewhat more efficiently.
189 */
190 withNormalizedHash =
191 {
192 hashTypes ? [ "sha256" ],
193 }:
194 fetcher:
195 let
196 inherit (lib.attrsets) intersectAttrs removeAttrs;
197 inherit (lib.trivial) functionArgs setFunctionArgs;
198
199 inherit (commonH hashTypes) hashSet;
200 fArgs = functionArgs fetcher;
201
202 normalize = normalizeHash {
203 inherit hashTypes;
204 required = !fArgs.outputHash;
205 };
206 in
207 # The o.g. fetcher must *only* accept outputHash and outputHashAlgo
208 assert fArgs ? outputHash && fArgs ? outputHashAlgo;
209 assert intersectAttrs fArgs hashSet == { };
210
211 setFunctionArgs (args: fetcher (normalize args)) (
212 removeAttrs fArgs [
213 "outputHash"
214 "outputHashAlgo"
215 ]
216 // {
217 hash = fArgs.outputHash;
218 }
219 );
220}