biome: 1.9.2 -> 1.9.3
[NixPkgs.git] / pkgs / build-support / trivial-builders / default.nix
blob2dc130e55d859d90a733d5b711bd088f18406319
1 { lib, config, stdenv, stdenvNoCC, jq, lndir, runtimeShell, shellcheck-minimal }:
3 let
4   inherit (lib)
5     optionalAttrs
6     warn
7     ;
8 in
10 rec {
12   # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
13   # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-runCommand
14   runCommand = name: env: runCommandWith {
15     stdenv = stdenvNoCC;
16     runLocal = false;
17     inherit name;
18     derivationArgs = env;
19   };
20   # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
21   # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-runCommandLocal
22   runCommandLocal = name: env: runCommandWith {
23     stdenv = stdenvNoCC;
24     runLocal = true;
25     inherit name;
26     derivationArgs = env;
27   };
28   # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
29   # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-runCommandCC
30   runCommandCC = name: env: runCommandWith {
31     stdenv = stdenv;
32     runLocal = false;
33     inherit name;
34     derivationArgs = env;
35   };
36   # `runCommandCCLocal` left out on purpose.
37   # We shouldn’t force the user to have a cc in scope.
39   # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
40   # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-runCommandWith
41   runCommandWith =
42     let
43       # prevent infinite recursion for the default stdenv value
44       defaultStdenv = stdenv;
45     in
46     {
47       # which stdenv to use, defaults to a stdenv with a C compiler, pkgs.stdenv
48       stdenv ? defaultStdenv
49       # whether to build this derivation locally instead of substituting
50     , runLocal ? false
51       # extra arguments to pass to stdenv.mkDerivation
52     , derivationArgs ? { }
53       # name of the resulting derivation
54     , name
55       # TODO(@Artturin): enable strictDeps always
56     }: buildCommand:
57       stdenv.mkDerivation ({
58         enableParallelBuilding = true;
59         inherit buildCommand name;
60         passAsFile = [ "buildCommand" ]
61           ++ (derivationArgs.passAsFile or [ ]);
62       }
63       // lib.optionalAttrs (! derivationArgs?meta) {
64         pos = let args = builtins.attrNames derivationArgs; in
65           if builtins.length args > 0
66           then builtins.unsafeGetAttrPos (builtins.head args) derivationArgs
67           else null;
68       }
69       // (lib.optionalAttrs runLocal {
70         preferLocalBuild = true;
71         allowSubstitutes = false;
72       })
73       // builtins.removeAttrs derivationArgs [ "passAsFile" ]);
76   # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
77   # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeTextFile
78   writeTextFile =
79     { name
80     , text
81     , executable ? false
82     , destination ? ""
83     , checkPhase ? ""
84     , meta ? { }
85     , allowSubstitutes ? false
86     , preferLocalBuild ? true
87     , derivationArgs ? { }
88     }:
89     assert lib.assertMsg (destination != "" -> (lib.hasPrefix "/" destination && destination != "/")) ''
90       destination must be an absolute path, relative to the derivation's out path,
91       got '${destination}' instead.
93       Ensure that the path starts with a / and specifies at least the filename.
94     '';
96     let
97       matches = builtins.match "/bin/([^/]+)" destination;
98     in
99     runCommand name
100       ({
101         inherit text executable checkPhase allowSubstitutes preferLocalBuild;
102         passAsFile = [ "text" ]
103           ++ derivationArgs.passAsFile or [ ];
104         meta = lib.optionalAttrs (executable && matches != null)
105           {
106             mainProgram = lib.head matches;
107           } // meta // derivationArgs.meta or {};
108       } // removeAttrs derivationArgs [ "passAsFile" "meta" ])
109       ''
110         target=$out${lib.escapeShellArg destination}
111         mkdir -p "$(dirname "$target")"
113         if [ -e "$textPath" ]; then
114           mv "$textPath" "$target"
115         else
116           echo -n "$text" > "$target"
117         fi
119         if [ -n "$executable" ]; then
120           chmod +x "$target"
121         fi
123         eval "$checkPhase"
124       '';
126   # See doc/build-helpers/trivial-build-helpers.chapter.md
127   # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
128   writeText = name: text:
129     # TODO: To fully deprecate, replace the assertion with `lib.isString` and remove the warning
130     assert lib.assertMsg (lib.strings.isConvertibleWithToString text) ''
131       pkgs.writeText ${lib.strings.escapeNixString name}: The second argument should be a string, but it's a ${builtins.typeOf text} instead.'';
132     lib.warnIf (! lib.isString text) ''
133       pkgs.writeText ${lib.strings.escapeNixString name}: The second argument should be a string, but it's a ${builtins.typeOf text} instead, which is deprecated. Use `toString` to convert the value to a string first.''
134     writeTextFile { inherit name text; };
136   # See doc/build-helpers/trivial-build-helpers.chapter.md
137   # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
138   writeTextDir = path: text: writeTextFile {
139     inherit text;
140     name = builtins.baseNameOf path;
141     destination = "/${path}";
142   };
144   # See doc/build-helpers/trivial-build-helpers.chapter.md
145   # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
146   writeScript = name: text: writeTextFile { inherit name text; executable = true; };
148   # See doc/build-helpers/trivial-build-helpers.chapter.md
149   # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
150   writeScriptBin = name: text: writeTextFile {
151     inherit name text;
152     executable = true;
153     destination = "/bin/${name}";
154   };
156   # See doc/build-helpers/trivial-build-helpers.chapter.md
157   # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
158   writeShellScript = name: text:
159     writeTextFile {
160       inherit name;
161       executable = true;
162       text = ''
163         #!${runtimeShell}
164         ${text}
165       '';
166       checkPhase = ''
167         ${stdenv.shellDryRun} "$target"
168       '';
169     };
171   # See doc/build-helpers/trivial-build-helpers.chapter.md
172   # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
173   writeShellScriptBin = name: text:
174     writeTextFile {
175       inherit name;
176       executable = true;
177       destination = "/bin/${name}";
178       text = ''
179         #!${runtimeShell}
180         ${text}
181       '';
182       checkPhase = ''
183         ${stdenv.shellDryRun} "$target"
184       '';
185       meta.mainProgram = name;
186     };
188   # TODO: move parameter documentation to the Nixpkgs manual
189   # See doc/build-helpers/trivial-build-helpers.chapter.md
190   # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeShellApplication
191   writeShellApplication =
192     {
193       /*
194          The name of the script to write.
196          Type: String
197        */
198       name,
199       /*
200          The shell script's text, not including a shebang.
202          Type: String
203        */
204       text,
205       /*
206          Inputs to add to the shell script's `$PATH` at runtime.
208          Type: [String|Derivation]
209        */
210       runtimeInputs ? [ ],
211       /*
212          Extra environment variables to set at runtime.
214          Type: AttrSet
215        */
216       runtimeEnv ? null,
217       /*
218          `stdenv.mkDerivation`'s `meta` argument.
220          Type: AttrSet
221        */
222       meta ? { },
223       /*
224          The `checkPhase` to run. Defaults to `shellcheck` on supported
225          platforms and `bash -n`.
227          The script path will be given as `$target` in the `checkPhase`.
229          Type: String
230        */
231       checkPhase ? null,
232       /*
233          Checks to exclude when running `shellcheck`, e.g. `[ "SC2016" ]`.
235          See <https://www.shellcheck.net/wiki/> for a list of checks.
237          Type: [String]
238        */
239       excludeShellChecks ? [ ],
240       /*
241          Extra command-line flags to pass to ShellCheck.
243          Type: [String]
244        */
245       extraShellCheckFlags ? [ ],
246       /*
247          Bash options to activate with `set -o` at the start of the script.
249          Defaults to `[ "errexit" "nounset" "pipefail" ]`.
251          Type: [String]
252        */
253       bashOptions ? [ "errexit" "nounset" "pipefail" ],
254       /* Extra arguments to pass to `stdenv.mkDerivation`.
256          :::{.caution}
257          Certain derivation attributes are used internally,
258          overriding those could cause problems.
259          :::
261          Type: AttrSet
262        */
263       derivationArgs ? { },
264     }:
265     writeTextFile {
266       inherit name meta derivationArgs;
267       executable = true;
268       destination = "/bin/${name}";
269       allowSubstitutes = true;
270       preferLocalBuild = false;
271       text = ''
272         #!${runtimeShell}
273         ${lib.concatMapStringsSep "\n" (option: "set -o ${option}") bashOptions}
274       '' + lib.optionalString (runtimeEnv != null)
275         (lib.concatStrings
276           (lib.mapAttrsToList
277             (name: value: ''
278               ${lib.toShellVar name value}
279               export ${name}
280             '')
281             runtimeEnv))
282       + lib.optionalString (runtimeInputs != [ ]) ''
284         export PATH="${lib.makeBinPath runtimeInputs}:$PATH"
285       '' + ''
287         ${text}
288       '';
290       checkPhase =
291         # GHC (=> shellcheck) isn't supported on some platforms (such as risc-v)
292         # but we still want to use writeShellApplication on those platforms
293         let
294           shellcheckSupported = lib.meta.availableOn stdenv.buildPlatform shellcheck-minimal.compiler;
295           excludeFlags = lib.optionals (excludeShellChecks != [ ]) [ "--exclude" (lib.concatStringsSep "," excludeShellChecks) ];
296           shellcheckCommand = lib.optionalString shellcheckSupported ''
297             # use shellcheck which does not include docs
298             # pandoc takes long to build and documentation isn't needed for just running the cli
299             ${lib.getExe shellcheck-minimal} ${lib.escapeShellArgs (excludeFlags ++ extraShellCheckFlags)} "$target"
300           '';
301         in
302         if checkPhase == null then ''
303           runHook preCheck
304           ${stdenv.shellDryRun} "$target"
305           ${shellcheckCommand}
306           runHook postCheck
307         ''
308         else checkPhase;
309     };
311   # Create a C binary
312   # TODO: add to writers? pkgs/build-support/writers
313   writeCBin = pname: code:
314     runCommandCC pname
315       {
316         inherit pname code;
317         executable = true;
318         passAsFile = [ "code" ];
319         # Pointless to do this on a remote machine.
320         preferLocalBuild = true;
321         allowSubstitutes = false;
322         meta = {
323           mainProgram = pname;
324         };
325       }
326       ''
327         n=$out/bin/${pname}
328         mkdir -p "$(dirname "$n")"
329         mv "$codePath" code.c
330         $CC -x c code.c -o "$n"
331       '';
333   # TODO: deduplicate with documentation in doc/build-helpers/trivial-build-helpers.chapter.md
334   #       see also https://github.com/NixOS/nixpkgs/pull/249721
335   # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-concatText
336   /* concat a list of files to the nix store.
337     The contents of files are added to the file in the store.
339     Example:
342     # Writes my-file to /nix/store/<store path>
343     concatTextFile {
344       name = "my-file";
345       files = [ drv1 "${drv2}/path/to/file" ];
346     }
349     See also the `concatText` helper function below.
352     # Writes executable my-file to /nix/store/<store path>/bin/my-file
353     concatTextFile {
354       name = "my-file";
355       files = [ drv1 "${drv2}/path/to/file" ];
356       executable = true;
357       destination = "/bin/my-file";
358     }
361    */
362   concatTextFile =
363     { name # the name of the derivation
364     , files
365     , executable ? false # run chmod +x ?
366     , destination ? ""   # relative path appended to $out eg "/bin/foo"
367     , checkPhase ? ""    # syntax checks, e.g. for scripts
368     , meta ? { }
369     }:
370     runCommandLocal name
371       { inherit files executable checkPhase meta destination; }
372       ''
373         file=$out$destination
374         mkdir -p "$(dirname "$file")"
375         cat $files > "$file"
377         if [ -n "$executable" ]; then
378           chmod +x "$file"
379         fi
381         eval "$checkPhase"
382       '';
384   # TODO: deduplicate with documentation in doc/build-helpers/trivial-build-helpers.chapter.md
385   #       see also https://github.com/NixOS/nixpkgs/pull/249721
386   # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-concatText
387   /*
388     Writes a text file to nix store with no optional parameters available.
390     Example:
393     # Writes contents of files to /nix/store/<store path>
394     concatText "my-file" [ file1 file2 ]
397   */
398   concatText = name: files: concatTextFile { inherit name files; };
400   # TODO: deduplicate with documentation in doc/build-helpers/trivial-build-helpers.chapter.md
401   #       see also https://github.com/NixOS/nixpkgs/pull/249721
402   # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-concatText
403   /*
404     Writes a text file to nix store with and mark it as executable.
406     Example:
407     # Writes contents of files to /nix/store/<store path>
408     concatScript "my-file" [ file1 file2 ]
410   */
411   concatScript = name: files: concatTextFile { inherit name files; executable = true; };
414   /*
415     TODO: Deduplicate this documentation.
416     More docs in doc/build-helpers/trivial-build-helpers.chapter.md
417     See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-symlinkJoin
419     Create a forest of symlinks to the files in `paths`.
421     This creates a single derivation that replicates the directory structure
422     of all the input paths.
424     BEWARE: it may not "work right" when the passed paths contain symlinks to directories.
426     Example:
429     # adds symlinks of hello to current build.
430     symlinkJoin { name = "myhello"; paths = [ pkgs.hello ]; }
435     # adds symlinks of hello and stack to current build and prints "links added"
436     symlinkJoin { name = "myexample"; paths = [ pkgs.hello pkgs.stack ]; postBuild = "echo links added"; }
439     This creates a derivation with a directory structure like the following:
442     /nix/store/sglsr5g079a5235hy29da3mq3hv8sjmm-myexample
443     |-- bin
444     |   |-- hello -> /nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10/bin/hello
445     |   `-- stack -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/bin/stack
446     `-- share
447         |-- bash-completion
448         |   `-- completions
449         |       `-- stack -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/share/bash-completion/completions/stack
450         |-- fish
451         |   `-- vendor_completions.d
452         |       `-- stack.fish -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/share/fish/vendor_completions.d/stack.fish
453     ...
456     symlinkJoin and linkFarm are similar functions, but they output
457     derivations with different structure.
459     symlinkJoin is used to create a derivation with a familiar directory
460     structure (top-level bin/, share/, etc), but with all actual files being symlinks to
461     the files in the input derivations.
463     symlinkJoin is used many places in nixpkgs to create a single derivation
464     that appears to contain binaries, libraries, documentation, etc from
465     multiple input derivations.
467     linkFarm is instead used to create a simple derivation with symlinks to
468     other derivations.  A derivation created with linkFarm is often used in CI
469     as a easy way to build multiple derivations at once.
470    */
471   symlinkJoin =
472     args_@{ name
473     , paths
474     , preferLocalBuild ? true
475     , allowSubstitutes ? false
476     , postBuild ? ""
477     , ...
478     }:
479     let
480       args = removeAttrs args_ [ "name" "postBuild" ]
481         // {
482         inherit preferLocalBuild allowSubstitutes;
483         passAsFile = [ "paths" ];
484       }; # pass the defaults
485     in
486     runCommand name args
487       ''
488         mkdir -p $out
489         for i in $(cat $pathsPath); do
490           ${lndir}/bin/lndir -silent $i $out
491         done
492         ${postBuild}
493       '';
495   # TODO: move linkFarm docs to the Nixpkgs manual
496   /*
497     Quickly create a set of symlinks to derivations.
499     This creates a simple derivation with symlinks to all inputs.
501     entries can be a list of attribute sets like
503     [ { name = "name" ; path = "/nix/store/..."; } ]
506     or an attribute set name -> path like:
508     { name = "/nix/store/..."; other = "/nix/store/..."; }
511     Example:
513     # Symlinks hello and stack paths in store to current $out/hello-test and
514     # $out/foobar.
515     linkFarm "myexample" [ { name = "hello-test"; path = pkgs.hello; } { name = "foobar"; path = pkgs.stack; } ]
517     This creates a derivation with a directory structure like the following:
519     /nix/store/qc5728m4sa344mbks99r3q05mymwm4rw-myexample
520     |-- foobar -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1
521     `-- hello-test -> /nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
524     See the note on symlinkJoin for the difference between linkFarm and symlinkJoin.
525    */
526   linkFarm = name: entries:
527     let
528       entries' =
529         if (lib.isAttrs entries) then entries
530         # We do this foldl to have last-wins semantics in case of repeated entries
531         else if (lib.isList entries) then lib.foldl (a: b: a // { "${b.name}" = b.path; }) { } entries
532         else throw "linkFarm entries must be either attrs or a list!";
534       linkCommands = lib.mapAttrsToList
535         (name: path: ''
536           mkdir -p "$(dirname ${lib.escapeShellArg "${name}"})"
537           ln -s ${lib.escapeShellArg "${path}"} ${lib.escapeShellArg "${name}"}
538         '')
539         entries';
540     in
541     runCommand name
542       {
543         preferLocalBuild = true;
544         allowSubstitutes = false;
545         passthru.entries = entries';
546       } ''
547       mkdir -p $out
548       cd $out
549       ${lib.concatStrings linkCommands}
550     '';
552   # TODO: move linkFarmFromDrvs docs to the Nixpkgs manual
553   /*
554     Easily create a linkFarm from a set of derivations.
556     This calls linkFarm with a list of entries created from the list of input
557     derivations.  It turns each input derivation into an attribute set
558     like { name = drv.name ; path = drv }, and passes this to linkFarm.
560     Example:
562     # Symlinks the hello, gcc, and ghc derivations in $out
563     linkFarmFromDrvs "myexample" [ pkgs.hello pkgs.gcc pkgs.ghc ]
565     This creates a derivation with a directory structure like the following:
568     /nix/store/m3s6wkjy9c3wy830201bqsb91nk2yj8c-myexample
569     |-- gcc-wrapper-9.2.0 -> /nix/store/fqhjxf9ii4w4gqcsx59fyw2vvj91486a-gcc-wrapper-9.2.0
570     |-- ghc-8.6.5 -> /nix/store/gnf3s07bglhbbk4y6m76sbh42siym0s6-ghc-8.6.5
571     `-- hello-2.10 -> /nix/store/k0ll91c4npk4lg8lqhx00glg2m735g74-hello-2.10
573   */
574   linkFarmFromDrvs = name: drvs:
575     let mkEntryFromDrv = drv: { name = drv.name; path = drv; };
576     in linkFarm name (map mkEntryFromDrv drvs);
578   # TODO: move onlyBin docs to the Nixpkgs manual
579   /*
580     Produce a derivation that links to the target derivation's `/bin`,
581     and *only* `/bin`.
583     This is useful when your favourite package doesn't have a separate
584     bin output and other contents of the package's output (e.g. setup
585     hooks) cause trouble when used in your environment.
586   */
587   onlyBin = drv: runCommand "${drv.name}-only-bin" { } ''
588     mkdir -p $out
589     ln -s ${lib.getBin drv}/bin $out/bin
590   '';
593   # Docs in doc/build-helpers/special/makesetuphook.section.md
594   # See https://nixos.org/manual/nixpkgs/unstable/#sec-pkgs.makeSetupHook
595   makeSetupHook =
596     { name ? lib.warn "calling makeSetupHook without passing a name is deprecated." "hook"
597     , deps ? [ ]
598       # hooks go in nativeBuildInputs so these will be nativeBuildInputs
599     , propagatedBuildInputs ? [ ]
600       # these will be buildInputs
601     , depsTargetTargetPropagated ? [ ]
602     , meta ? { }
603     , passthru ? { }
604     , substitutions ? { }
605     }:
606     script:
607     runCommand name
608       (substitutions // {
609         # TODO(@Artturin:) substitutions should be inside the env attrset
610         # but users are likely passing non-substitution arguments through substitutions
611         # turn off __structuredAttrs to unbreak substituteAll
612         __structuredAttrs = false;
613         inherit meta;
614         inherit depsTargetTargetPropagated;
615         propagatedBuildInputs =
616           # remove list conditionals before 23.11
617           lib.warnIf (!lib.isList deps) "'deps' argument to makeSetupHook must be a list. content of deps: ${toString deps}"
618             (lib.warnIf (deps != [ ]) "'deps' argument to makeSetupHook is deprecated and will be removed in release 23.11., Please use propagatedBuildInputs instead. content of deps: ${toString deps}"
619               propagatedBuildInputs ++ (if lib.isList deps then deps else [ deps ]));
620         strictDeps = true;
621         # TODO 2023-01, no backport: simplify to inherit passthru;
622         passthru = passthru
623           // optionalAttrs (substitutions?passthru)
624           (warn "makeSetupHook (name = ${lib.strings.escapeNixString name}): `substitutions.passthru` is deprecated. Please set `passthru` directly."
625             substitutions.passthru);
626       })
627       (''
628         mkdir -p $out/nix-support
629         cp ${script} $out/nix-support/setup-hook
630         recordPropagatedDependencies
631       '' + lib.optionalString (substitutions != { }) ''
632         substituteAll ${script} $out/nix-support/setup-hook
633       '');
636   # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
637   # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeReferencesToFile
638   # TODO: Convert to throw after Nixpkgs 24.05 branch-off.
639   writeReferencesToFile = (if config.allowAliases then lib.warn else throw)
640     "writeReferencesToFile is deprecated in favour of writeClosure"
641     (path: writeClosure [ path ]);
643   # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
644   # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeClosure
645   writeClosure = paths: runCommand "runtime-deps"
646     {
647       # Get the cleaner exportReferencesGraph interface
648       __structuredAttrs = true;
649       exportReferencesGraph.graph = paths;
650       nativeBuildInputs = [ jq ];
651     }
652     ''
653       jq -r ".graph | map(.path) | sort | .[]" "$NIX_ATTRS_JSON_FILE" > "$out"
654     '';
656   # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
657   # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeDirectReferencesToFile
658   writeDirectReferencesToFile = path: runCommand "runtime-references"
659     {
660       exportReferencesGraph = [ "graph" path ];
661       inherit path;
662     }
663     ''
664       touch ./references
665       while read p; do
666         read dummy
667         read nrRefs
668         if [[ $p == $path ]]; then
669           for ((i = 0; i < nrRefs; i++)); do
670             read ref;
671             echo $ref >>./references
672           done
673         else
674           for ((i = 0; i < nrRefs; i++)); do
675             read ref;
676           done
677         fi
678       done < graph
679       sort ./references >$out
680     '';
682   # TODO: move writeStringReferencesToFile docs to the Nixpkgs manual
683   /*
684     Extract a string's references to derivations and paths (its
685     context) and write them to a text file, removing the input string
686     itself from the dependency graph. This is useful when you want to
687     make a derivation depend on the string's references, but not its
688     contents (to avoid unnecessary rebuilds, for example).
690     Note that this only works as intended on Nix >= 2.3.
691    */
692   writeStringReferencesToFile = string:
693     /*
694        The basic operation this performs is to copy the string context
695        from `string` to a second string and wrap that string in a
696        derivation. However, that alone is not enough, since nothing in the
697        string refers to the output paths of the derivations/paths in its
698        context, meaning they'll be considered build-time dependencies and
699        removed from the wrapper derivation's closure. Putting the
700        necessary output paths in the new string is however not very
701        straightforward - the attrset returned by `getContext` contains
702        only references to derivations' .drv-paths, not their output
703        paths. In order to "convert" them, we try to extract the
704        corresponding paths from the original string using regex.
705     */
706     let
707       # Taken from https://github.com/NixOS/nix/blob/130284b8508dad3c70e8160b15f3d62042fc730a/src/libutil/hash.cc#L84
708       nixHashChars = "0123456789abcdfghijklmnpqrsvwxyz";
709       context = builtins.getContext string;
710       derivations = lib.filterAttrs (n: v: v ? outputs) context;
711       # Objects copied from outside of the store, such as paths and
712       # `builtins.fetch*`ed ones
713       sources = lib.attrNames (lib.filterAttrs (n: v: v ? path) context);
714       packages =
715         lib.mapAttrs'
716           (name: value:
717             {
718               inherit value;
719               name = lib.head (builtins.match "${builtins.storeDir}/[${nixHashChars}]+-(.*)\.drv" name);
720             })
721           derivations;
722       # The syntax of output paths differs between outputs named `out`
723       # and other, explicitly named ones. For explicitly named ones,
724       # the output name is suffixed as `-name`, but `out` outputs
725       # aren't suffixed at all, and thus aren't easily distinguished
726       # from named output paths. Therefore, we find all the named ones
727       # first so we can use them to remove false matches when looking
728       # for `out` outputs (see the definition of `outputPaths`).
729       namedOutputPaths =
730         lib.flatten
731           (lib.mapAttrsToList
732             (name: value:
733               (map
734                 (output:
735                   lib.filter
736                     lib.isList
737                     (builtins.split "(${builtins.storeDir}/[${nixHashChars}]+-${name}-${output})" string))
738                 (lib.remove "out" value.outputs)))
739             packages);
740       # Only `out` outputs
741       outputPaths =
742         lib.flatten
743           (lib.mapAttrsToList
744             (name: value:
745               if lib.elem "out" value.outputs then
746                 lib.filter
747                   (x: lib.isList x &&
748                     # If the matched path is in `namedOutputPaths`,
749                     # it's a partial match of an output path where
750                     # the output name isn't `out`
751                     lib.all (o: !lib.hasPrefix (lib.head x) o) namedOutputPaths)
752                   (builtins.split "(${builtins.storeDir}/[${nixHashChars}]+-${name})" string)
753               else
754                 [ ])
755             packages);
756       allPaths = lib.concatStringsSep "\n" (lib.unique (sources ++ namedOutputPaths ++ outputPaths));
757       allPathsWithContext = builtins.appendContext allPaths context;
758     in
759     if builtins ? getContext then
760       writeText "string-references" allPathsWithContext
761     else
762       writeDirectReferencesToFile (writeText "string-file" string);
765   # Docs in doc/build-helpers/fetchers.chapter.md
766   # See https://nixos.org/manual/nixpkgs/unstable/#requirefile
767   requireFile =
768     { name ? null
769     , sha256 ? null
770     , sha1 ? null
771     , hash ? null
772     , url ? null
773     , message ? null
774     , hashMode ? "flat"
775     }:
776       assert (message != null) || (url != null);
777       assert (sha256 != null) || (sha1 != null) || (hash != null);
778       assert (name != null) || (url != null);
779       let
780         msg =
781           if message != null then message
782           else ''
783             Unfortunately, we cannot download file ${name_} automatically.
784             Please go to ${url} to download it yourself, and add it to the Nix store
785             using either
786               nix-store --add-fixed ${hashAlgo} ${name_}
787             or
788               nix-prefetch-url --type ${hashAlgo} file:///path/to/${name_}
789           '';
790         hashAlgo =
791           if hash != null then (builtins.head (lib.strings.splitString "-" hash))
792           else if sha256 != null then "sha256"
793           else "sha1";
794         hashAlgo_ = if hash != null then "" else hashAlgo;
795         hash_ =
796           if hash != null then hash
797           else if sha256 != null then sha256
798           else sha1;
799         name_ = if name == null then baseNameOf (toString url) else name;
800       in
801       stdenvNoCC.mkDerivation {
802         name = name_;
803         outputHashMode = hashMode;
804         outputHashAlgo = hashAlgo_;
805         outputHash = hash_;
806         preferLocalBuild = true;
807         allowSubstitutes = false;
808         builder = writeScript "restrict-message" ''
809           source ${stdenvNoCC}/setup
810           cat <<_EOF_
812           ***
813           ${msg}
814           ***
816           _EOF_
817           exit 1
818         '';
819       };
822   # TODO: move copyPathToStore docs to the Nixpkgs manual
823   /*
824     Copy a path to the Nix store.
825     Nix automatically copies files to the store before stringifying paths.
826     If you need the store path of a file, ${copyPathToStore <path>} can be
827     shortened to ${<path>}.
828   */
829   copyPathToStore = builtins.filterSource (p: t: true);
832   # TODO: move copyPathsToStore docs to the Nixpkgs manual
833   /*
834     Copy a list of paths to the Nix store.
835   */
836   copyPathsToStore = builtins.map copyPathToStore;
838   # TODO: move applyPatches docs to the Nixpkgs manual
839   /* Applies a list of patches to a source directory.
841     Example:
843     # Patching nixpkgs:
845     applyPatches {
846       src = pkgs.path;
847       patches = [
848         (pkgs.fetchpatch {
849           url = "https://github.com/NixOS/nixpkgs/commit/1f770d20550a413e508e081ddc08464e9d08ba3d.patch";
850           sha256 = "1nlzx171y3r3jbk0qhvnl711kmdk57jlq4na8f8bs8wz2pbffymr";
851         })
852       ];
853     }
855    */
856   applyPatches =
857     { src
858     , name ? (if builtins.typeOf src == "path"
859       then builtins.baseNameOf src
860       else
861         if builtins.isAttrs src && builtins.hasAttr "name" src
862         then src.name
863         else throw "applyPatches: please supply a `name` argument because a default name can only be computed when the `src` is a path or is an attribute set with a `name` attribute."
864       ) + "-patched"
865     , patches ? [ ]
866     , prePatch ? ""
867     , postPatch ? ""
868     , ...
869     }@args:
870     if patches == [ ] && prePatch == "" && postPatch == ""
871     then src # nothing to do, so use original src to avoid additional drv
872     else stdenvNoCC.mkDerivation
873       ({
874         inherit name src patches prePatch postPatch;
875         preferLocalBuild = true;
876         allowSubstitutes = false;
877         phases = "unpackPhase patchPhase installPhase";
878         installPhase = "cp -R ./ $out";
879       }
880       # Carry `meta` information from the underlying `src` if present.
881       // (optionalAttrs (src?meta) { inherit (src) meta; })
882       // (removeAttrs args [ "src" "name" "patches" "prePatch" "postPatch" ]));
884   # TODO: move docs to Nixpkgs manual
885   /* An immutable file in the store with a length of 0 bytes. */
886   emptyFile = runCommand "empty-file"
887     {
888       outputHash = "sha256-d6xi4mKdjkX2JFicDIv5niSzpyI0m/Hnm8GGAIU04kY=";
889       outputHashMode = "recursive";
890       preferLocalBuild = true;
891     } "touch $out";
893   # TODO: move docs to Nixpkgs manual
894   /* An immutable empty directory in the store. */
895   emptyDirectory = runCommand "empty-directory"
896     {
897       outputHashAlgo = "sha256";
898       outputHashMode = "recursive";
899       outputHash = "0sjjj9z1dhilhpc8pq4154czrb79z9cm044jvn75kxcjv6v5l2m5";
900       preferLocalBuild = true;
901     } "mkdir $out";