nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 lib,
3 config,
4 stdenv,
5 stdenvNoCC,
6 jq,
7 lndir,
8 runtimeShell,
9 shellcheck-minimal,
10}:
11
12let
13 inherit (lib)
14 optionalAttrs
15 optionalString
16 hasPrefix
17 warn
18 map
19 isList
20 ;
21in
22
23rec {
24
25 # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
26 # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-runCommand
27 runCommand =
28 name: env:
29 runCommandWith {
30 stdenv = stdenvNoCC;
31 runLocal = false;
32 inherit name;
33 derivationArgs = env;
34 };
35 # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
36 # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-runCommandLocal
37 runCommandLocal =
38 name: env:
39 runCommandWith {
40 stdenv = stdenvNoCC;
41 runLocal = true;
42 inherit name;
43 derivationArgs = env;
44 };
45 # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
46 # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-runCommandCC
47 runCommandCC =
48 name: env:
49 runCommandWith {
50 stdenv = stdenv;
51 runLocal = false;
52 inherit name;
53 derivationArgs = env;
54 };
55 # `runCommandCCLocal` left out on purpose.
56 # We shouldn’t force the user to have a cc in scope.
57
58 # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
59 # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-runCommandWith
60 runCommandWith =
61 let
62 # prevent infinite recursion for the default stdenv value
63 defaultStdenv = stdenv;
64 in
65 {
66 # which stdenv to use, defaults to a stdenv with a C compiler, pkgs.stdenv
67 stdenv ? defaultStdenv,
68 # whether to build this derivation locally instead of substituting
69 runLocal ? false,
70 # extra arguments to pass to stdenv.mkDerivation
71 derivationArgs ? { },
72 # name of the resulting derivation
73 name,
74 # TODO(@Artturin): enable strictDeps always
75 }:
76 buildCommand:
77 stdenv.mkDerivation (
78 {
79 enableParallelBuilding = true;
80 inherit buildCommand name;
81 passAsFile = [ "buildCommand" ] ++ (derivationArgs.passAsFile or [ ]);
82 }
83 // lib.optionalAttrs (!derivationArgs ? meta) {
84 pos =
85 let
86 args = builtins.attrNames derivationArgs;
87 in
88 if builtins.length args > 0 then
89 builtins.unsafeGetAttrPos (builtins.head args) derivationArgs
90 else
91 null;
92 }
93 // (lib.optionalAttrs runLocal {
94 preferLocalBuild = true;
95 allowSubstitutes = false;
96 })
97 // builtins.removeAttrs derivationArgs [ "passAsFile" ]
98 );
99
100 # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
101 # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeTextFile
102 writeTextFile =
103 {
104 name,
105 text,
106 executable ? false,
107 destination ? "",
108 checkPhase ? "",
109 meta ? { },
110 passthru ? { },
111 allowSubstitutes ? false,
112 preferLocalBuild ? true,
113 derivationArgs ? { },
114 }:
115 assert lib.assertMsg (destination != "" -> (lib.hasPrefix "/" destination && destination != "/")) ''
116 destination must be an absolute path, relative to the derivation's out path,
117 got '${destination}' instead.
118
119 Ensure that the path starts with a / and specifies at least the filename.
120 '';
121
122 let
123 matches = builtins.match "/bin/([^/]+)" destination;
124 in
125 runCommand name
126 (
127 {
128 inherit
129 text
130 executable
131 checkPhase
132 allowSubstitutes
133 preferLocalBuild
134 ;
135 passAsFile = [ "text" ] ++ derivationArgs.passAsFile or [ ];
136 meta =
137 lib.optionalAttrs (executable && matches != null) {
138 mainProgram = lib.head matches;
139 }
140 // meta
141 // derivationArgs.meta or { };
142 passthru = passthru // derivationArgs.passthru or { };
143 }
144 // removeAttrs derivationArgs [
145 "passAsFile"
146 "meta"
147 "passthru"
148 ]
149 )
150 ''
151 target=$out${lib.escapeShellArg destination}
152 mkdir -p "$(dirname "$target")"
153
154 if [ -e "$textPath" ]; then
155 mv "$textPath" "$target"
156 else
157 echo -n "$text" > "$target"
158 fi
159
160 if [ -n "$executable" ]; then
161 chmod +x "$target"
162 fi
163
164 eval "$checkPhase"
165 '';
166
167 # See doc/build-helpers/trivial-build-helpers.chapter.md
168 # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
169 writeText =
170 name: text:
171 # TODO: To fully deprecate, replace the assertion with `lib.isString` and remove the warning
172 assert lib.assertMsg (lib.strings.isConvertibleWithToString text)
173 ''pkgs.writeText ${lib.strings.escapeNixString name}: The second argument should be a string, but it's a ${builtins.typeOf text} instead.'';
174 lib.warnIf (!lib.isString text)
175 ''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.''
176 writeTextFile
177 { inherit name text; };
178
179 # See doc/build-helpers/trivial-build-helpers.chapter.md
180 # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
181 writeTextDir =
182 path: text:
183 writeTextFile {
184 inherit text;
185 name = builtins.baseNameOf path;
186 destination = "/${path}";
187 };
188
189 # See doc/build-helpers/trivial-build-helpers.chapter.md
190 # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
191 writeScript =
192 name: text:
193 writeTextFile {
194 inherit name text;
195 executable = true;
196 };
197
198 # See doc/build-helpers/trivial-build-helpers.chapter.md
199 # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
200 writeScriptBin =
201 name: text:
202 writeTextFile {
203 inherit name text;
204 executable = true;
205 destination = "/bin/${name}";
206 };
207
208 # See doc/build-helpers/trivial-build-helpers.chapter.md
209 # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
210 writeShellScript =
211 name: text:
212 writeTextFile {
213 inherit name;
214 executable = true;
215 text = ''
216 #!${runtimeShell}
217 ${text}
218 '';
219 checkPhase = ''
220 ${stdenv.shellDryRun} "$target"
221 '';
222 };
223
224 # See doc/build-helpers/trivial-build-helpers.chapter.md
225 # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
226 writeShellScriptBin =
227 name: text:
228 writeTextFile {
229 inherit name;
230 executable = true;
231 destination = "/bin/${name}";
232 text = ''
233 #!${runtimeShell}
234 ${text}
235 '';
236 checkPhase = ''
237 ${stdenv.shellDryRun} "$target"
238 '';
239 meta.mainProgram = name;
240 };
241
242 # TODO: move parameter documentation to the Nixpkgs manual
243 # See doc/build-helpers/trivial-build-helpers.chapter.md
244 # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeShellApplication
245 writeShellApplication =
246 {
247 /*
248 The name of the script to write.
249
250 Type: String
251 */
252 name,
253 /*
254 The shell script's text, not including a shebang.
255
256 Type: String
257 */
258 text,
259 /*
260 Inputs to add to the shell script's `$PATH` at runtime.
261
262 Type: [String|Derivation]
263 */
264 runtimeInputs ? [ ],
265 /*
266 Extra environment variables to set at runtime.
267
268 Type: AttrSet
269 */
270 runtimeEnv ? null,
271 /*
272 `stdenv.mkDerivation`'s `meta` argument.
273
274 Type: AttrSet
275 */
276 meta ? { },
277 /*
278 `stdenv.mkDerivation`'s `passthru` argument.
279
280 Type: AttrSet
281 */
282 passthru ? { },
283 /*
284 The `checkPhase` to run. Defaults to `shellcheck` on supported
285 platforms and `bash -n`.
286
287 The script path will be given as `$target` in the `checkPhase`.
288
289 Type: String
290 */
291 checkPhase ? null,
292 /*
293 Checks to exclude when running `shellcheck`, e.g. `[ "SC2016" ]`.
294
295 See <https://www.shellcheck.net/wiki/> for a list of checks.
296
297 Type: [String]
298 */
299 excludeShellChecks ? [ ],
300 /*
301 Extra command-line flags to pass to ShellCheck.
302
303 Type: [String]
304 */
305 extraShellCheckFlags ? [ ],
306 /*
307 Bash options to activate with `set -o` at the start of the script.
308
309 Defaults to `[ "errexit" "nounset" "pipefail" ]`.
310
311 Type: [String]
312 */
313 bashOptions ? [
314 "errexit"
315 "nounset"
316 "pipefail"
317 ],
318 /*
319 Extra arguments to pass to `stdenv.mkDerivation`.
320
321 :::{.caution}
322 Certain derivation attributes are used internally,
323 overriding those could cause problems.
324 :::
325
326 Type: AttrSet
327 */
328 derivationArgs ? { },
329 /*
330 Whether to inherit the current `$PATH` in the script.
331
332 Type: Bool
333 */
334 inheritPath ? true,
335 }:
336 writeTextFile {
337 inherit
338 name
339 meta
340 passthru
341 derivationArgs
342 ;
343 executable = true;
344 destination = "/bin/${name}";
345 allowSubstitutes = true;
346 preferLocalBuild = false;
347 text = ''
348 #!${runtimeShell}
349 ${lib.concatMapStringsSep "\n" (option: "set -o ${option}") bashOptions}
350 ''
351 + lib.optionalString (runtimeEnv != null) (
352 lib.concatStrings (
353 lib.mapAttrsToList (name: value: ''
354 ${lib.toShellVar name value}
355 export ${name}
356 '') runtimeEnv
357 )
358 )
359 + lib.optionalString (runtimeInputs != [ ]) ''
360
361 export PATH="${lib.makeBinPath runtimeInputs}${lib.optionalString inheritPath ":$PATH"}"
362 ''
363 + ''
364
365 ${text}
366 '';
367
368 checkPhase =
369 let
370 excludeFlags = lib.optionals (excludeShellChecks != [ ]) [
371 "--exclude"
372 (lib.concatStringsSep "," excludeShellChecks)
373 ];
374 # GHC (=> shellcheck) isn't supported on some platforms (such as risc-v)
375 # but we still want to use writeShellApplication on those platforms
376 shellcheckCommand = lib.optionalString shellcheck-minimal.compiler.bootstrapAvailable ''
377 # use shellcheck which does not include docs
378 # pandoc takes long to build and documentation isn't needed for just running the cli
379 ${lib.getExe shellcheck-minimal} ${
380 lib.escapeShellArgs (excludeFlags ++ extraShellCheckFlags)
381 } "$target"
382 '';
383 in
384 if checkPhase == null then
385 ''
386 runHook preCheck
387 ${stdenv.shellDryRun} "$target"
388 ${shellcheckCommand}
389 runHook postCheck
390 ''
391 else
392 checkPhase;
393 };
394
395 # Create a C binary
396 # TODO: add to writers? pkgs/build-support/writers
397 writeCBin =
398 pname: code:
399 runCommandCC pname
400 {
401 inherit pname code;
402 executable = true;
403 passAsFile = [ "code" ];
404 # Pointless to do this on a remote machine.
405 preferLocalBuild = true;
406 allowSubstitutes = false;
407 meta = {
408 mainProgram = pname;
409 };
410 }
411 ''
412 n=$out/bin/${pname}
413 mkdir -p "$(dirname "$n")"
414 mv "$codePath" code.c
415 $CC -x c code.c -o "$n"
416 '';
417
418 # TODO: deduplicate with documentation in doc/build-helpers/trivial-build-helpers.chapter.md
419 # see also https://github.com/NixOS/nixpkgs/pull/249721
420 # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-concatText
421 /*
422 concat a list of files to the nix store.
423 The contents of files are added to the file in the store.
424
425 Example:
426
427 # Writes my-file to /nix/store/<store path>
428 concatTextFile {
429 name = "my-file";
430 files = [ drv1 "${drv2}/path/to/file" ];
431 }
432
433 See also the `concatText` helper function below.
434
435 # Writes executable my-file to /nix/store/<store path>/bin/my-file
436 concatTextFile {
437 name = "my-file";
438 files = [ drv1 "${drv2}/path/to/file" ];
439 executable = true;
440 destination = "/bin/my-file";
441 }
442 */
443 concatTextFile =
444 {
445 name, # the name of the derivation
446 files,
447 executable ? false, # run chmod +x ?
448 destination ? "", # relative path appended to $out eg "/bin/foo"
449 checkPhase ? "", # syntax checks, e.g. for scripts
450 meta ? { },
451 passthru ? { },
452 }:
453 runCommandLocal name
454 {
455 inherit
456 files
457 executable
458 checkPhase
459 meta
460 passthru
461 destination
462 ;
463 }
464 ''
465 file=$out$destination
466 mkdir -p "$(dirname "$file")"
467 cat $files > "$file"
468
469 if [ -n "$executable" ]; then
470 chmod +x "$file"
471 fi
472
473 eval "$checkPhase"
474 '';
475
476 # TODO: deduplicate with documentation in doc/build-helpers/trivial-build-helpers.chapter.md
477 # see also https://github.com/NixOS/nixpkgs/pull/249721
478 # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-concatText
479 /*
480 Writes a text file to nix store with no optional parameters available.
481
482 Example:
483
484 # Writes contents of files to /nix/store/<store path>
485 concatText "my-file" [ file1 file2 ]
486 */
487 concatText = name: files: concatTextFile { inherit name files; };
488
489 # TODO: deduplicate with documentation in doc/build-helpers/trivial-build-helpers.chapter.md
490 # see also https://github.com/NixOS/nixpkgs/pull/249721
491 # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-concatText
492 /*
493 Writes a text file to nix store with and mark it as executable.
494
495 Example:
496 # Writes contents of files to /nix/store/<store path>
497 concatScript "my-file" [ file1 file2 ]
498 */
499 concatScript =
500 name: files:
501 concatTextFile {
502 inherit name files;
503 executable = true;
504 };
505
506 /*
507 TODO: Deduplicate this documentation.
508 More docs in doc/build-helpers/trivial-build-helpers.chapter.md
509 See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-symlinkJoin
510
511 Create a forest of symlinks to the files in `paths`.
512
513 This creates a single derivation that replicates the directory structure
514 of all the input paths.
515
516 BEWARE: it may not "work right" when the passed paths contain symlinks to directories.
517
518 Example:
519
520 # adds symlinks of hello to current build.
521 symlinkJoin { name = "myhello"; paths = [ pkgs.hello ]; }
522
523 # adds symlinks of hello and stack to current build and prints "links added"
524 symlinkJoin { name = "myexample"; paths = [ pkgs.hello pkgs.stack ]; postBuild = "echo links added"; }
525
526 This creates a derivation with a directory structure like the following:
527
528 /nix/store/sglsr5g079a5235hy29da3mq3hv8sjmm-myexample
529 |-- bin
530 | |-- hello -> /nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10/bin/hello
531 | `-- stack -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/bin/stack
532 `-- share
533 |-- bash-completion
534 | `-- completions
535 | `-- stack -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/share/bash-completion/completions/stack
536 |-- fish
537 | `-- vendor_completions.d
538 | `-- stack.fish -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/share/fish/vendor_completions.d/stack.fish
539 ...
540
541 To create a directory structure from a specific subdirectory of input `paths` instead of their full trees,
542 you can either append the subdirectory path to each input path, or use the `stripPrefix` argument to
543 remove the common prefix during linking.
544
545 Example:
546
547 # create symlinks of tmpfiles.d rules from multiple packages
548 symlinkJoin { name = "tmpfiles.d"; paths = [ pkgs.lvm2 pkgs.nix ]; stripPrefix = "/lib/tmpfiles.d"; }
549
550 This creates a derivation with a directory structure like the following:
551
552 /nix/store/m5s775yicb763hfa133jwml5hwmwzv14-tmpfiles.d
553 |-- lvm2.conf -> /nix/store/k6js0l5f0zpvrhay49579fj939j77p2w-lvm2-2.03.29/lib/tmpfiles.d/lvm2.conf
554 `-- nix-daemon.conf -> /nix/store/z4v2s3s3y79fmabhps5hakb3c5dwaj5a-nix-1.33.7/lib/tmpfiles.d/nix-daemon.conf
555
556 By default, packages that don't contain the specified subdirectory are silently skipped.
557 Set `failOnMissing = true` to make the build fail if any input package is missing the subdirectory
558 (this is the default behavior when not using stripPrefix).
559
560 symlinkJoin and linkFarm are similar functions, but they output
561 derivations with different structure.
562
563 symlinkJoin is used to create a derivation with a familiar directory
564 structure (top-level bin/, share/, etc), but with all actual files being symlinks to
565 the files in the input derivations.
566
567 symlinkJoin is used many places in nixpkgs to create a single derivation
568 that appears to contain binaries, libraries, documentation, etc from
569 multiple input derivations.
570
571 linkFarm is instead used to create a simple derivation with symlinks to
572 other derivations. A derivation created with linkFarm is often used in CI
573 as a easy way to build multiple derivations at once.
574 */
575 symlinkJoin =
576 args_@{
577 name ?
578 assert lib.assertMsg (
579 args_ ? pname && args_ ? version
580 ) "symlinkJoin requires either a `name` OR `pname` and `version`";
581 "${args_.pname}-${args_.version}",
582 paths,
583 stripPrefix ? "",
584 preferLocalBuild ? true,
585 allowSubstitutes ? false,
586 postBuild ? "",
587 failOnMissing ? stripPrefix == "",
588 ...
589 }:
590 assert lib.assertMsg (stripPrefix != "" -> (hasPrefix "/" stripPrefix && stripPrefix != "/")) ''
591 stripPrefix must be either an empty string (disable stripping behavior), or relative path prefixed with /.
592
593 Ensure that the path starts with / and specifies path to the subdirectory.
594 '';
595
596 let
597 mapPaths =
598 f: paths:
599 map (
600 path:
601 if path == null then
602 null
603 else if isList path then
604 mapPaths f path
605 else
606 f path
607 ) paths;
608 args =
609 removeAttrs args_ [
610 "name"
611 "postBuild"
612 "stripPrefix"
613 "paths"
614 "failOnMissing"
615 ]
616 // {
617 inherit preferLocalBuild allowSubstitutes;
618 paths = mapPaths (path: "${path}${stripPrefix}") paths;
619 passAsFile = [ "paths" ];
620 }; # pass the defaults
621 in
622 runCommand name args ''
623 mkdir -p $out
624 for i in $(cat $pathsPath); do
625 ${optionalString (!failOnMissing) "if test -d $i; then "}${lndir}/bin/lndir -silent $i $out${
626 optionalString (!failOnMissing) "; fi"
627 }
628 done
629 ${postBuild}
630 '';
631
632 # TODO: move linkFarm docs to the Nixpkgs manual
633 /*
634 Quickly create a set of symlinks to derivations.
635
636 This creates a simple derivation with symlinks to all inputs.
637
638 entries can be a list of attribute sets like
639
640 [ { name = "name" ; path = "/nix/store/..."; } ]
641
642 or an attribute set name -> path like:
643
644 { name = "/nix/store/..."; other = "/nix/store/..."; }
645
646 Example:
647
648 # Symlinks hello and stack paths in store to current $out/hello-test and
649 # $out/foobar.
650 linkFarm "myexample" [ { name = "hello-test"; path = pkgs.hello; } { name = "foobar"; path = pkgs.stack; } ]
651
652 This creates a derivation with a directory structure like the following:
653
654 /nix/store/qc5728m4sa344mbks99r3q05mymwm4rw-myexample
655 |-- foobar -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1
656 `-- hello-test -> /nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
657
658 See the note on symlinkJoin for the difference between linkFarm and symlinkJoin.
659 */
660 linkFarm =
661 name: entries:
662 let
663 entries' =
664 if (lib.isAttrs entries) then
665 entries
666 # We do this foldl to have last-wins semantics in case of repeated entries
667 else if (lib.isList entries) then
668 lib.foldl (a: b: a // { "${b.name}" = b.path; }) { } entries
669 else
670 throw "linkFarm entries must be either attrs or a list!";
671
672 linkCommands = lib.mapAttrsToList (name: path: ''
673 mkdir -p -- "$(dirname -- ${lib.escapeShellArg "${name}"})"
674 ln -s -- ${lib.escapeShellArg "${path}"} ${lib.escapeShellArg "${name}"}
675 '') entries';
676 in
677 runCommand name
678 {
679 preferLocalBuild = true;
680 allowSubstitutes = false;
681 passthru.entries = entries';
682 }
683 ''
684 mkdir -p $out
685 cd $out
686 ${lib.concatStrings linkCommands}
687 '';
688
689 # TODO: move linkFarmFromDrvs docs to the Nixpkgs manual
690 /*
691 Easily create a linkFarm from a set of derivations.
692
693 This calls linkFarm with a list of entries created from the list of input
694 derivations. It turns each input derivation into an attribute set
695 like { name = drv.name ; path = drv }, and passes this to linkFarm.
696
697 Example:
698
699 # Symlinks the hello, gcc, and ghc derivations in $out
700 linkFarmFromDrvs "myexample" [ pkgs.hello pkgs.gcc pkgs.ghc ]
701
702 This creates a derivation with a directory structure like the following:
703
704 /nix/store/m3s6wkjy9c3wy830201bqsb91nk2yj8c-myexample
705 |-- gcc-wrapper-9.2.0 -> /nix/store/fqhjxf9ii4w4gqcsx59fyw2vvj91486a-gcc-wrapper-9.2.0
706 |-- ghc-8.6.5 -> /nix/store/gnf3s07bglhbbk4y6m76sbh42siym0s6-ghc-8.6.5
707 `-- hello-2.10 -> /nix/store/k0ll91c4npk4lg8lqhx00glg2m735g74-hello-2.10
708 */
709 linkFarmFromDrvs =
710 name: drvs:
711 let
712 mkEntryFromDrv = drv: {
713 name = drv.name;
714 path = drv;
715 };
716 in
717 linkFarm name (map mkEntryFromDrv drvs);
718
719 # TODO: move onlyBin docs to the Nixpkgs manual
720 /*
721 Produce a derivation that links to the target derivation's `/bin`,
722 and *only* `/bin`.
723
724 This is useful when your favourite package doesn't have a separate
725 bin output and other contents of the package's output (e.g. setup
726 hooks) cause trouble when used in your environment.
727 */
728 onlyBin =
729 drv:
730 runCommand "${drv.name}-only-bin" { } ''
731 mkdir -p $out
732 ln -s ${lib.getBin drv}/bin $out/bin
733 '';
734
735 # Docs in doc/build-helpers/special/makesetuphook.section.md
736 # See https://nixos.org/manual/nixpkgs/unstable/#sec-pkgs.makeSetupHook
737 makeSetupHook =
738 {
739 name ? lib.warn "calling makeSetupHook without passing a name is deprecated." "hook",
740 # hooks go in nativeBuildInputs so these will be nativeBuildInputs
741 propagatedBuildInputs ? [ ],
742 propagatedNativeBuildInputs ? [ ],
743 # these will be buildInputs
744 depsTargetTargetPropagated ? [ ],
745 meta ? { },
746 passthru ? { },
747 substitutions ? { },
748 }:
749 script:
750 runCommand name
751 (
752 substitutions
753 // {
754 # TODO(@Artturin:) substitutions should be inside the env attrset
755 # but users are likely passing non-substitution arguments through substitutions
756 # turn off __structuredAttrs to unbreak substituteAll
757 __structuredAttrs = false;
758 inherit meta;
759 inherit depsTargetTargetPropagated;
760 inherit propagatedBuildInputs;
761 inherit propagatedNativeBuildInputs;
762 strictDeps = true;
763 # TODO 2023-01, no backport: simplify to inherit passthru;
764 passthru =
765 passthru
766 // optionalAttrs (substitutions ? passthru) (
767 warn "makeSetupHook (name = ${lib.strings.escapeNixString name}): `substitutions.passthru` is deprecated. Please set `passthru` directly." substitutions.passthru
768 );
769 }
770 )
771 (
772 ''
773 mkdir -p $out/nix-support
774 cp ${script} $out/nix-support/setup-hook
775 recordPropagatedDependencies
776 ''
777 + lib.optionalString (substitutions != { }) ''
778 substituteAll ${script} $out/nix-support/setup-hook
779 ''
780 );
781
782 # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
783 # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeClosure
784 writeClosure =
785 paths:
786 runCommand "runtime-deps"
787 {
788 # Get the cleaner exportReferencesGraph interface
789 __structuredAttrs = true;
790 exportReferencesGraph.graph = paths;
791 nativeBuildInputs = [ jq ];
792 }
793 ''
794 jq -r ".graph | map(.path) | sort | .[]" "$NIX_ATTRS_JSON_FILE" > "$out"
795 '';
796
797 # Docs in doc/build-helpers/trivial-build-helpers.chapter.md
798 # See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeDirectReferencesToFile
799 writeDirectReferencesToFile =
800 path:
801 runCommand "runtime-references"
802 {
803 exportReferencesGraph = [
804 "graph"
805 path
806 ];
807 inherit path;
808 }
809 ''
810 touch ./references
811 while read p; do
812 read dummy
813 read nrRefs
814 if [[ $p == $path ]]; then
815 for ((i = 0; i < nrRefs; i++)); do
816 read ref;
817 echo $ref >>./references
818 done
819 else
820 for ((i = 0; i < nrRefs; i++)); do
821 read ref;
822 done
823 fi
824 done < graph
825 sort ./references >$out
826 '';
827
828 # TODO: move writeStringReferencesToFile docs to the Nixpkgs manual
829 /*
830 Extract a string's references to derivations and paths (its
831 context) and write them to a text file, removing the input string
832 itself from the dependency graph. This is useful when you want to
833 make a derivation depend on the string's references, but not its
834 contents (to avoid unnecessary rebuilds, for example).
835
836 Note that this only works as intended on Nix >= 2.3.
837 */
838 writeStringReferencesToFile =
839 string:
840 /*
841 The basic operation this performs is to copy the string context
842 from `string` to a second string and wrap that string in a
843 derivation. However, that alone is not enough, since nothing in the
844 string refers to the output paths of the derivations/paths in its
845 context, meaning they'll be considered build-time dependencies and
846 removed from the wrapper derivation's closure. Putting the
847 necessary output paths in the new string is however not very
848 straightforward - the attrset returned by `getContext` contains
849 only references to derivations' .drv-paths, not their output
850 paths. In order to "convert" them, we try to extract the
851 corresponding paths from the original string using regex.
852 */
853 let
854 # Taken from https://github.com/NixOS/nix/blob/130284b8508dad3c70e8160b15f3d62042fc730a/src/libutil/hash.cc#L84
855 nixHashChars = "0123456789abcdfghijklmnpqrsvwxyz";
856 context = builtins.getContext string;
857 derivations = lib.filterAttrs (n: v: v ? outputs) context;
858 # Objects copied from outside of the store, such as paths and
859 # `builtins.fetch*`ed ones
860 sources = lib.attrNames (lib.filterAttrs (n: v: v ? path) context);
861 packages = lib.mapAttrs' (name: value: {
862 inherit value;
863 name = lib.head (builtins.match "${builtins.storeDir}/[${nixHashChars}]+-(.*)\\.drv" name);
864 }) derivations;
865 # The syntax of output paths differs between outputs named `out`
866 # and other, explicitly named ones. For explicitly named ones,
867 # the output name is suffixed as `-name`, but `out` outputs
868 # aren't suffixed at all, and thus aren't easily distinguished
869 # from named output paths. Therefore, we find all the named ones
870 # first so we can use them to remove false matches when looking
871 # for `out` outputs (see the definition of `outputPaths`).
872 namedOutputPaths = lib.flatten (
873 lib.mapAttrsToList (
874 name: value:
875 (map (
876 output:
877 lib.filter lib.isList (
878 builtins.split "(${builtins.storeDir}/[${nixHashChars}]+-${name}-${output})" string
879 )
880 ) (lib.remove "out" value.outputs))
881 ) packages
882 );
883 # Only `out` outputs
884 outputPaths = lib.flatten (
885 lib.mapAttrsToList (
886 name: value:
887 if lib.elem "out" value.outputs then
888 lib.filter (
889 x:
890 lib.isList x
891 &&
892 # If the matched path is in `namedOutputPaths`,
893 # it's a partial match of an output path where
894 # the output name isn't `out`
895 lib.all (o: !lib.hasPrefix (lib.head x) o) namedOutputPaths
896 ) (builtins.split "(${builtins.storeDir}/[${nixHashChars}]+-${name})" string)
897 else
898 [ ]
899 ) packages
900 );
901 allPaths = lib.concatStringsSep "\n" (lib.unique (sources ++ namedOutputPaths ++ outputPaths));
902 allPathsWithContext = builtins.appendContext allPaths context;
903 in
904 if builtins ? getContext then
905 writeText "string-references" allPathsWithContext
906 else
907 writeDirectReferencesToFile (writeText "string-file" string);
908
909 # Docs in doc/build-helpers/fetchers.chapter.md
910 # See https://nixos.org/manual/nixpkgs/unstable/#requirefile
911 requireFile =
912 {
913 name ? null,
914 sha256 ? null,
915 sha1 ? null,
916 hash ? null,
917 url ? null,
918 message ? null,
919 hashMode ? "flat",
920 }:
921 assert (message != null) || (url != null);
922 assert (sha256 != null) || (sha1 != null) || (hash != null);
923 assert (name != null) || (url != null);
924 let
925 msg =
926 if message != null then
927 message
928 else
929 ''
930 Unfortunately, we cannot download file ${name_} automatically.
931 Please go to ${url} to download it yourself, and add it to the Nix store
932 using either
933 nix-store --add-fixed ${hashAlgo} ${name_}
934 or
935 nix-prefetch-url --type ${hashAlgo} file:///path/to/${name_}
936 '';
937 hashAlgo =
938 if hash != null then
939 (builtins.head (lib.strings.splitString "-" hash))
940 else if sha256 != null then
941 "sha256"
942 else
943 "sha1";
944 hashAlgo_ = if hash != null then "" else hashAlgo;
945 hash_ =
946 if hash != null then
947 hash
948 else if sha256 != null then
949 sha256
950 else
951 sha1;
952 name_ = if name == null then baseNameOf (toString url) else name;
953 in
954 stdenvNoCC.mkDerivation {
955 name = name_;
956 outputHashMode = hashMode;
957 outputHashAlgo = hashAlgo_;
958 outputHash = hash_;
959 preferLocalBuild = true;
960 allowSubstitutes = false;
961 builder = writeScript "restrict-message" ''
962 source ${stdenvNoCC}/setup
963 cat <<_EOF_
964
965 ***
966 ${msg}
967 ***
968
969 _EOF_
970 exit 1
971 '';
972 };
973
974 # TODO: move copyPathToStore docs to the Nixpkgs manual
975 /*
976 Copy a path to the Nix store.
977 Nix automatically copies files to the store before stringifying paths.
978 If you need the store path of a file, ${copyPathToStore <path>} can be
979 shortened to ${<path>}.
980 */
981 copyPathToStore = builtins.filterSource (p: t: true);
982
983 # TODO: move copyPathsToStore docs to the Nixpkgs manual
984 # Copy a list of paths to the Nix store.
985 copyPathsToStore = builtins.map copyPathToStore;
986
987 # TODO: move applyPatches docs to the Nixpkgs manual
988 /*
989 Applies a list of patches to a source directory.
990
991 Example:
992
993 # Patching nixpkgs:
994
995 applyPatches {
996 src = pkgs.path;
997 patches = [
998 (pkgs.fetchpatch {
999 url = "https://github.com/NixOS/nixpkgs/commit/1f770d20550a413e508e081ddc08464e9d08ba3d.patch";
1000 sha256 = "1nlzx171y3r3jbk0qhvnl711kmdk57jlq4na8f8bs8wz2pbffymr";
1001 })
1002 ];
1003 }
1004 */
1005 applyPatches =
1006 {
1007 src,
1008 name ?
1009 (
1010 if builtins.typeOf src == "path" then
1011 builtins.baseNameOf src
1012 else if builtins.isAttrs src && builtins.hasAttr "name" src then
1013 src.name
1014 else
1015 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."
1016 )
1017 + "-patched",
1018 patches ? [ ],
1019 prePatch ? "",
1020 postPatch ? "",
1021 ...
1022 }@args:
1023 assert lib.assertMsg (
1024 !args ? meta
1025 ) "applyPatches will not merge 'meta', change it in 'src' instead";
1026 assert lib.assertMsg (
1027 !args ? passthru
1028 ) "applyPatches will not merge 'passthru', change it in 'src' instead";
1029 if patches == [ ] && prePatch == "" && postPatch == "" then
1030 src # nothing to do, so use original src to avoid additional drv
1031 else
1032 let
1033 keepAttrs = names: lib.filterAttrs (name: val: lib.elem name names);
1034 # enables tools like nix-update to determine what src attributes to replace
1035 extraPassthru = lib.optionalAttrs (lib.isAttrs src) (
1036 keepAttrs [
1037 "rev"
1038 "tag"
1039 "url"
1040 "outputHash"
1041 "outputHashAlgo"
1042 ] src
1043 );
1044 in
1045 stdenvNoCC.mkDerivation (
1046 {
1047 inherit
1048 name
1049 src
1050 patches
1051 prePatch
1052 postPatch
1053 ;
1054 preferLocalBuild = true;
1055 allowSubstitutes = false;
1056 phases = "unpackPhase patchPhase installPhase";
1057 installPhase = "cp -R ./ $out";
1058 }
1059 # Carry (and merge) information from the underlying `src` if present.
1060 // (optionalAttrs (src ? meta) {
1061 inherit (src) meta;
1062 })
1063 // (optionalAttrs (extraPassthru != { } || src ? passthru) {
1064 passthru = extraPassthru // src.passthru or { };
1065 })
1066 # Forward any additional arguments to the derivation
1067 // (removeAttrs args [
1068 "src"
1069 "name"
1070 "patches"
1071 "prePatch"
1072 "postPatch"
1073 ])
1074 );
1075
1076 # TODO: move docs to Nixpkgs manual
1077 # An immutable file in the store with a length of 0 bytes.
1078 emptyFile = runCommand "empty-file" {
1079 outputHash = "sha256-d6xi4mKdjkX2JFicDIv5niSzpyI0m/Hnm8GGAIU04kY=";
1080 outputHashMode = "recursive";
1081 preferLocalBuild = true;
1082 } "touch $out";
1083
1084 # TODO: move docs to Nixpkgs manual
1085 # An immutable empty directory in the store.
1086 emptyDirectory = runCommand "empty-directory" {
1087 outputHashAlgo = "sha256";
1088 outputHashMode = "recursive";
1089 outputHash = "0sjjj9z1dhilhpc8pq4154czrb79z9cm044jvn75kxcjv6v5l2m5";
1090 preferLocalBuild = true;
1091 } "mkdir $out";
1092}