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