core/pkgs/build-support/trivial-builders/default.nix

1002 lines
31 KiB
Nix
Raw Normal View History

2024-06-30 08:12:46 +00:00
{
lib,
config,
stdenv,
stdenvNoCC,
jq,
lndir,
runtimeShell,
shellcheck-minimal,
}:
2024-05-02 00:46:19 +00:00
let
2024-06-30 08:12:46 +00:00
inherit (lib) optionalAttrs warn;
2024-05-02 00:46:19 +00:00
in
rec {
# Docs in doc/build-helpers/trivial-build-helpers.chapter.md
# See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-runCommand
2024-06-30 08:12:46 +00:00
runCommand =
name: env:
runCommandWith {
stdenv = stdenvNoCC;
runLocal = false;
inherit name;
derivationArgs = env;
};
2024-05-02 00:46:19 +00:00
# Docs in doc/build-helpers/trivial-build-helpers.chapter.md
# See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-runCommandLocal
2024-06-30 08:12:46 +00:00
runCommandLocal =
name: env:
runCommandWith {
stdenv = stdenvNoCC;
runLocal = true;
inherit name;
derivationArgs = env;
};
2024-05-02 00:46:19 +00:00
# Docs in doc/build-helpers/trivial-build-helpers.chapter.md
# See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-runCommandCC
2024-06-30 08:12:46 +00:00
runCommandCC =
name: env:
runCommandWith {
stdenv = stdenv;
runLocal = false;
inherit name;
derivationArgs = env;
};
2024-05-02 00:46:19 +00:00
# `runCommandCCLocal` left out on purpose.
# We shouldnt force the user to have a cc in scope.
# TODO: Move documentation for runCommandWith to the Nixpkgs manual
/*
Generalized version of the `runCommand`-variants
which does customized behavior via a single
attribute set passed as the first argument
instead of having a lot of variants like
`runCommand*`. Additionally it allows changing
the used `stdenv` freely and has a more explicit
approach to changing the arguments passed to
`stdenv.mkDerivation`.
2024-06-30 08:12:46 +00:00
*/
2024-05-02 00:46:19 +00:00
runCommandWith =
let
# prevent infinite recursion for the default stdenv value
defaultStdenv = stdenv;
in
{
# which stdenv to use, defaults to a stdenv with a C compiler, pkgs.stdenv
2024-06-30 08:12:46 +00:00
stdenv ? defaultStdenv,
2024-05-02 00:46:19 +00:00
# whether to build this derivation locally instead of substituting
2024-06-30 08:12:46 +00:00
runLocal ? false,
2024-05-02 00:46:19 +00:00
# extra arguments to pass to stdenv.mkDerivation
2024-06-30 08:12:46 +00:00
derivationArgs ? { },
2024-05-02 00:46:19 +00:00
# name of the resulting derivation
2024-06-30 08:12:46 +00:00
name,
# TODO(@Artturin): enable strictDeps always
}:
buildCommand:
stdenv.mkDerivation (
{
2024-05-02 00:46:19 +00:00
enableParallelBuilding = true;
inherit buildCommand name;
2024-06-30 08:12:46 +00:00
passAsFile = [ "buildCommand" ] ++ (derivationArgs.passAsFile or [ ]);
2024-05-02 00:46:19 +00:00
}
2024-06-30 08:12:46 +00:00
// lib.optionalAttrs (!derivationArgs ? meta) {
pos =
let
args = builtins.attrNames derivationArgs;
in
if builtins.length args > 0 then
builtins.unsafeGetAttrPos (builtins.head args) derivationArgs
else
null;
2024-05-02 00:46:19 +00:00
}
// (lib.optionalAttrs runLocal {
preferLocalBuild = true;
allowSubstitutes = false;
})
2024-06-30 08:12:46 +00:00
// builtins.removeAttrs derivationArgs [ "passAsFile" ]
);
2024-05-02 00:46:19 +00:00
# Docs in doc/build-helpers/trivial-build-helpers.chapter.md
# See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeTextFile
writeTextFile =
2024-06-30 08:12:46 +00:00
{
name,
text,
executable ? false,
destination ? "",
checkPhase ? "",
meta ? { },
allowSubstitutes ? false,
preferLocalBuild ? true,
derivationArgs ? { },
2024-05-02 00:46:19 +00:00
}:
let
matches = builtins.match "/bin/([^/]+)" destination;
in
runCommand name
2024-06-30 08:12:46 +00:00
(
{
inherit
text
executable
checkPhase
allowSubstitutes
preferLocalBuild
;
passAsFile = [ "text" ] ++ derivationArgs.passAsFile or [ ];
meta =
lib.optionalAttrs (executable && matches != null) { mainProgram = lib.head matches; }
// meta
// derivationArgs.meta or { };
}
// removeAttrs derivationArgs [
"passAsFile"
"meta"
]
)
2024-05-02 00:46:19 +00:00
''
target=$out${lib.escapeShellArg destination}
mkdir -p "$(dirname "$target")"
if [ -e "$textPath" ]; then
mv "$textPath" "$target"
else
echo -n "$text" > "$target"
fi
if [ -n "$executable" ]; then
chmod +x "$target"
fi
eval "$checkPhase"
'';
# See doc/build-helpers/trivial-build-helpers.chapter.md
# or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
writeText = name: text: writeTextFile { inherit name text; };
# See doc/build-helpers/trivial-build-helpers.chapter.md
# or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
2024-06-30 08:12:46 +00:00
writeTextDir =
path: text:
writeTextFile {
inherit text;
name = builtins.baseNameOf path;
destination = "/${path}";
};
2024-05-02 00:46:19 +00:00
# See doc/build-helpers/trivial-build-helpers.chapter.md
# or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
2024-06-30 08:12:46 +00:00
writeScript =
name: text:
writeTextFile {
inherit name text;
executable = true;
};
2024-05-02 00:46:19 +00:00
# See doc/build-helpers/trivial-build-helpers.chapter.md
# or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
2024-06-30 08:12:46 +00:00
writeScriptBin =
name: text:
writeTextFile {
inherit name text;
executable = true;
destination = "/bin/${name}";
};
2024-05-02 00:46:19 +00:00
# See doc/build-helpers/trivial-build-helpers.chapter.md
# or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
2024-06-30 08:12:46 +00:00
writeShellScript =
name: text:
2024-05-02 00:46:19 +00:00
writeTextFile {
inherit name;
executable = true;
text = ''
#!${runtimeShell}
${text}
'';
checkPhase = ''
${stdenv.shellDryRun} "$target"
'';
};
# See doc/build-helpers/trivial-build-helpers.chapter.md
# or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
2024-06-30 08:12:46 +00:00
writeShellScriptBin =
name: text:
2024-05-02 00:46:19 +00:00
writeTextFile {
inherit name;
executable = true;
destination = "/bin/${name}";
text = ''
#!${runtimeShell}
${text}
'';
checkPhase = ''
${stdenv.shellDryRun} "$target"
'';
meta.mainProgram = name;
};
# TODO: move parameter documentation to the Nixpkgs manual
# See doc/build-helpers/trivial-build-helpers.chapter.md
# or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeShellApplication
writeShellApplication =
{
/*
The name of the script to write.
Type: String
2024-06-30 08:12:46 +00:00
*/
2024-05-02 00:46:19 +00:00
name,
/*
The shell script's text, not including a shebang.
Type: String
2024-06-30 08:12:46 +00:00
*/
2024-05-02 00:46:19 +00:00
text,
/*
Inputs to add to the shell script's `$PATH` at runtime.
Type: [String|Derivation]
2024-06-30 08:12:46 +00:00
*/
2024-05-02 00:46:19 +00:00
runtimeInputs ? [ ],
/*
Extra environment variables to set at runtime.
Type: AttrSet
2024-06-30 08:12:46 +00:00
*/
2024-05-02 00:46:19 +00:00
runtimeEnv ? null,
/*
`stdenv.mkDerivation`'s `meta` argument.
Type: AttrSet
2024-06-30 08:12:46 +00:00
*/
2024-05-02 00:46:19 +00:00
meta ? { },
/*
The `checkPhase` to run. Defaults to `shellcheck` on supported
platforms and `bash -n`.
The script path will be given as `$target` in the `checkPhase`.
Type: String
2024-06-30 08:12:46 +00:00
*/
2024-05-02 00:46:19 +00:00
checkPhase ? null,
/*
Checks to exclude when running `shellcheck`, e.g. `[ "SC2016" ]`.
See <https://www.shellcheck.net/wiki/> for a list of checks.
Type: [String]
2024-06-30 08:12:46 +00:00
*/
2024-05-02 00:46:19 +00:00
excludeShellChecks ? [ ],
/*
Extra command-line flags to pass to ShellCheck.
Type: [String]
2024-06-30 08:12:46 +00:00
*/
2024-05-02 00:46:19 +00:00
extraShellCheckFlags ? [ ],
/*
Bash options to activate with `set -o` at the start of the script.
Defaults to `[ "errexit" "nounset" "pipefail" ]`.
Type: [String]
2024-06-30 08:12:46 +00:00
*/
bashOptions ? [
"errexit"
"nounset"
"pipefail"
],
/*
Extra arguments to pass to `stdenv.mkDerivation`.
2024-05-02 00:46:19 +00:00
2024-06-30 08:12:46 +00:00
:::{.caution}
Certain derivation attributes are used internally,
overriding those could cause problems.
:::
2024-05-02 00:46:19 +00:00
2024-06-30 08:12:46 +00:00
Type: AttrSet
*/
2024-05-02 00:46:19 +00:00
derivationArgs ? { },
}:
writeTextFile {
inherit name meta derivationArgs;
executable = true;
destination = "/bin/${name}";
allowSubstitutes = true;
preferLocalBuild = false;
2024-06-30 08:12:46 +00:00
text =
''
#!${runtimeShell}
${lib.concatMapStringsSep "\n" (option: "set -o ${option}") bashOptions}
''
+ lib.optionalString (runtimeEnv != null) (
lib.concatStrings (
lib.mapAttrsToList (name: value: ''
2024-05-02 00:46:19 +00:00
${lib.toShellVar name value}
export ${name}
2024-06-30 08:12:46 +00:00
'') runtimeEnv
)
)
+ lib.optionalString (runtimeInputs != [ ]) ''
2024-05-02 00:46:19 +00:00
2024-06-30 08:12:46 +00:00
export PATH="${lib.makeBinPath runtimeInputs}:$PATH"
''
+ ''
2024-05-02 00:46:19 +00:00
2024-06-30 08:12:46 +00:00
${text}
'';
2024-05-02 00:46:19 +00:00
checkPhase =
# GHC (=> shellcheck) isn't supported on some platforms (such as risc-v)
# but we still want to use writeShellApplication on those platforms
let
shellcheckSupported = lib.meta.availableOn stdenv.buildPlatform shellcheck-minimal.compiler;
2024-06-30 08:12:46 +00:00
excludeFlags = lib.optionals (excludeShellChecks != [ ]) [
"--exclude"
(lib.concatStringsSep "," excludeShellChecks)
];
2024-05-02 00:46:19 +00:00
shellcheckCommand = lib.optionalString shellcheckSupported ''
# use shellcheck which does not include docs
# pandoc takes long to build and documentation isn't needed for just running the cli
2024-06-30 08:12:46 +00:00
${lib.getExe shellcheck-minimal} ${
lib.escapeShellArgs (excludeFlags ++ extraShellCheckFlags)
} "$target"
2024-05-02 00:46:19 +00:00
'';
in
2024-06-30 08:12:46 +00:00
if checkPhase == null then
''
runHook preCheck
${stdenv.shellDryRun} "$target"
${shellcheckCommand}
runHook postCheck
''
else
checkPhase;
2024-05-02 00:46:19 +00:00
};
# Create a C binary
# TODO: add to writers? pkgs/build-support/writers
2024-06-30 08:12:46 +00:00
writeCBin =
pname: code:
2024-05-02 00:46:19 +00:00
runCommandCC pname
{
inherit pname code;
executable = true;
passAsFile = [ "code" ];
# Pointless to do this on a remote machine.
preferLocalBuild = true;
allowSubstitutes = false;
meta = {
mainProgram = pname;
};
}
''
n=$out/bin/${pname}
mkdir -p "$(dirname "$n")"
mv "$codePath" code.c
$CC -x c code.c -o "$n"
'';
# TODO: deduplicate with documentation in doc/build-helpers/trivial-build-helpers.chapter.md
# see also https://github.com/NixOS/nixpkgs/pull/249721
# See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-concatText
2024-06-30 08:12:46 +00:00
/*
concat a list of files to the nix store.
2024-05-02 00:46:19 +00:00
The contents of files are added to the file in the store.
Example:
# Writes my-file to /nix/store/<store path>
concatTextFile {
name = "my-file";
files = [ drv1 "${drv2}/path/to/file" ];
}
See also the `concatText` helper function below.
# Writes executable my-file to /nix/store/<store path>/bin/my-file
concatTextFile {
name = "my-file";
files = [ drv1 "${drv2}/path/to/file" ];
executable = true;
destination = "/bin/my-file";
}
2024-06-30 08:12:46 +00:00
*/
2024-05-02 00:46:19 +00:00
concatTextFile =
2024-06-30 08:12:46 +00:00
{
name, # the name of the derivation
files,
executable ? false, # run chmod +x ?
destination ? "", # relative path appended to $out eg "/bin/foo"
checkPhase ? "", # syntax checks, e.g. for scripts
meta ? { },
2024-05-02 00:46:19 +00:00
}:
runCommandLocal name
2024-06-30 08:12:46 +00:00
{
inherit
files
executable
checkPhase
meta
destination
;
}
2024-05-02 00:46:19 +00:00
''
file=$out$destination
mkdir -p "$(dirname "$file")"
cat $files > "$file"
if [ -n "$executable" ]; then
chmod +x "$file"
fi
eval "$checkPhase"
'';
# TODO: deduplicate with documentation in doc/build-helpers/trivial-build-helpers.chapter.md
# see also https://github.com/NixOS/nixpkgs/pull/249721
# See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-concatText
/*
Writes a text file to nix store with no optional parameters available.
Example:
# Writes contents of files to /nix/store/<store path>
concatText "my-file" [ file1 file2 ]
*/
concatText = name: files: concatTextFile { inherit name files; };
# TODO: deduplicate with documentation in doc/build-helpers/trivial-build-helpers.chapter.md
# see also https://github.com/NixOS/nixpkgs/pull/249721
# See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-concatText
/*
Writes a text file to nix store with and mark it as executable.
Example:
# Writes contents of files to /nix/store/<store path>
concatScript "my-file" [ file1 file2 ]
*/
2024-06-30 08:12:46 +00:00
concatScript =
name: files:
concatTextFile {
inherit name files;
executable = true;
};
2024-05-02 00:46:19 +00:00
/*
TODO: Deduplicate this documentation.
More docs in doc/build-helpers/trivial-build-helpers.chapter.md
See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-symlinkJoin
Create a forest of symlinks to the files in `paths`.
This creates a single derivation that replicates the directory structure
of all the input paths.
BEWARE: it may not "work right" when the passed paths contain symlinks to directories.
Example:
# adds symlinks of hello to current build.
symlinkJoin { name = "myhello"; paths = [ pkgs.hello ]; }
# adds symlinks of hello and stack to current build and prints "links added"
symlinkJoin { name = "myexample"; paths = [ pkgs.hello pkgs.stack ]; postBuild = "echo links added"; }
This creates a derivation with a directory structure like the following:
/nix/store/sglsr5g079a5235hy29da3mq3hv8sjmm-myexample
|-- bin
| |-- hello -> /nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10/bin/hello
| `-- stack -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/bin/stack
`-- share
|-- bash-completion
| `-- completions
| `-- stack -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/share/bash-completion/completions/stack
|-- fish
| `-- vendor_completions.d
| `-- stack.fish -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/share/fish/vendor_completions.d/stack.fish
...
symlinkJoin and linkFarm are similar functions, but they output
derivations with different structure.
symlinkJoin is used to create a derivation with a familiar directory
structure (top-level bin/, share/, etc), but with all actual files being symlinks to
the files in the input derivations.
symlinkJoin is used many places in nixpkgs to create a single derivation
that appears to contain binaries, libraries, documentation, etc from
multiple input derivations.
linkFarm is instead used to create a simple derivation with symlinks to
other derivations. A derivation created with linkFarm is often used in CI
as a easy way to build multiple derivations at once.
2024-06-30 08:12:46 +00:00
*/
2024-05-02 00:46:19 +00:00
symlinkJoin =
2024-06-30 08:12:46 +00:00
args_@{
name,
paths,
preferLocalBuild ? true,
allowSubstitutes ? false,
postBuild ? "",
...
2024-05-02 00:46:19 +00:00
}:
let
2024-06-30 08:12:46 +00:00
args =
removeAttrs args_ [
"name"
"postBuild"
]
2024-05-02 00:46:19 +00:00
// {
2024-06-30 08:12:46 +00:00
inherit preferLocalBuild allowSubstitutes;
passAsFile = [ "paths" ];
}; # pass the defaults
2024-05-02 00:46:19 +00:00
in
2024-06-30 08:12:46 +00:00
runCommand name args ''
mkdir -p $out
for i in $(cat $pathsPath); do
${lndir}/bin/lndir -silent $i $out
done
${postBuild}
'';
2024-05-02 00:46:19 +00:00
# TODO: move linkFarm docs to the Nixpkgs manual
/*
Quickly create a set of symlinks to derivations.
This creates a simple derivation with symlinks to all inputs.
entries can be a list of attribute sets like
[ { name = "name" ; path = "/nix/store/..."; } ]
or an attribute set name -> path like:
{ name = "/nix/store/..."; other = "/nix/store/..."; }
Example:
# Symlinks hello and stack paths in store to current $out/hello-test and
# $out/foobar.
linkFarm "myexample" [ { name = "hello-test"; path = pkgs.hello; } { name = "foobar"; path = pkgs.stack; } ]
This creates a derivation with a directory structure like the following:
/nix/store/qc5728m4sa344mbks99r3q05mymwm4rw-myexample
|-- foobar -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1
`-- hello-test -> /nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10
See the note on symlinkJoin for the difference between linkFarm and symlinkJoin.
2024-06-30 08:12:46 +00:00
*/
linkFarm =
name: entries:
2024-05-02 00:46:19 +00:00
let
entries' =
2024-06-30 08:12:46 +00:00
if (lib.isAttrs entries) then
entries
2024-05-02 00:46:19 +00:00
# We do this foldl to have last-wins semantics in case of repeated entries
2024-06-30 08:12:46 +00:00
else if (lib.isList entries) then
lib.foldl (a: b: a // { "${b.name}" = b.path; }) { } entries
else
throw "linkFarm entries must be either attrs or a list!";
linkCommands = lib.mapAttrsToList (name: path: ''
mkdir -p "$(dirname ${lib.escapeShellArg "${name}"})"
ln -s ${lib.escapeShellArg "${path}"} ${lib.escapeShellArg "${name}"}
'') entries';
2024-05-02 00:46:19 +00:00
in
runCommand name
{
preferLocalBuild = true;
allowSubstitutes = false;
passthru.entries = entries';
2024-06-30 08:12:46 +00:00
}
''
mkdir -p $out
cd $out
${lib.concatStrings linkCommands}
'';
2024-05-02 00:46:19 +00:00
# TODO: move linkFarmFromDrvs docs to the Nixpkgs manual
/*
Easily create a linkFarm from a set of derivations.
This calls linkFarm with a list of entries created from the list of input
derivations. It turns each input derivation into an attribute set
like { name = drv.name ; path = drv }, and passes this to linkFarm.
Example:
# Symlinks the hello, gcc, and ghc derivations in $out
linkFarmFromDrvs "myexample" [ pkgs.hello pkgs.gcc pkgs.ghc ]
This creates a derivation with a directory structure like the following:
/nix/store/m3s6wkjy9c3wy830201bqsb91nk2yj8c-myexample
|-- gcc-wrapper-9.2.0 -> /nix/store/fqhjxf9ii4w4gqcsx59fyw2vvj91486a-gcc-wrapper-9.2.0
|-- ghc-8.6.5 -> /nix/store/gnf3s07bglhbbk4y6m76sbh42siym0s6-ghc-8.6.5
`-- hello-2.10 -> /nix/store/k0ll91c4npk4lg8lqhx00glg2m735g74-hello-2.10
*/
2024-06-30 08:12:46 +00:00
linkFarmFromDrvs =
name: drvs:
let
mkEntryFromDrv = drv: {
name = drv.name;
path = drv;
};
in
linkFarm name (map mkEntryFromDrv drvs);
2024-05-02 00:46:19 +00:00
# TODO: move onlyBin docs to the Nixpkgs manual
/*
Produce a derivation that links to the target derivation's `/bin`,
and *only* `/bin`.
This is useful when your favourite package doesn't have a separate
bin output and other contents of the package's output (e.g. setup
hooks) cause trouble when used in your environment.
*/
2024-06-30 08:12:46 +00:00
onlyBin =
drv:
runCommand "${drv.name}-only-bin" { } ''
mkdir -p $out
ln -s ${lib.getBin drv}/bin $out/bin
'';
2024-05-02 00:46:19 +00:00
# Docs in doc/builders/special/makesetuphook.section.md
# See https://nixos.org/manual/nixpkgs/unstable/#sec-pkgs.makeSetupHook
makeSetupHook =
2024-06-30 08:12:46 +00:00
{
name ? lib.warn "calling makeSetupHook without passing a name is deprecated." "hook",
deps ? [ ],
2024-05-02 00:46:19 +00:00
# hooks go in nativeBuildInput so these will be nativeBuildInput
2024-06-30 08:12:46 +00:00
propagatedBuildInputs ? [ ],
2024-05-02 00:46:19 +00:00
# these will be buildInputs
2024-06-30 08:12:46 +00:00
depsTargetTargetPropagated ? [ ],
meta ? { },
passthru ? { },
substitutions ? { },
2024-05-02 00:46:19 +00:00
}:
script:
runCommand name
2024-06-30 08:12:46 +00:00
(
substitutions
// {
# TODO(@Artturin:) substitutions should be inside the env attrset
# but users are likely passing non-substitution arguments through substitutions
# turn off __structuredAttrs to unbreak substituteAll
__structuredAttrs = false;
inherit meta;
inherit depsTargetTargetPropagated;
propagatedBuildInputs =
# remove list conditionals before 23.11
lib.warnIf (!lib.isList deps)
"'deps' argument to makeSetupHook must be a list. content of deps: ${toString deps}"
(
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}"
propagatedBuildInputs
++ (if lib.isList deps then deps else [ deps ])
);
strictDeps = true;
# TODO 2023-01, no backport: simplify to inherit passthru;
passthru =
passthru
// optionalAttrs (substitutions ? passthru) (
warn "makeSetupHook (name = ${lib.strings.escapeNixString name}): `substitutions.passthru` is deprecated. Please set `passthru` directly." substitutions.passthru
);
}
)
(
''
mkdir -p $out/nix-support
cp ${script} $out/nix-support/setup-hook
recordPropagatedDependencies
''
+ lib.optionalString (substitutions != { }) ''
substituteAll ${script} $out/nix-support/setup-hook
''
);
2024-05-02 00:46:19 +00:00
# Docs in doc/build-helpers/trivial-build-helpers.chapter.md
# See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeReferencesToFile
# TODO: Convert to throw after Nixpkgs 24.05 branch-off.
2024-06-30 08:12:46 +00:00
writeReferencesToFile =
(if config.allowAliases then lib.warn else throw)
"writeReferencesToFile is deprecated in favour of writeClosure"
(path: writeClosure [ path ]);
2024-05-02 00:46:19 +00:00
# Docs in doc/build-helpers/trivial-build-helpers.chapter.md
# See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeClosure
2024-06-30 08:12:46 +00:00
writeClosure =
paths:
runCommand "runtime-deps"
{
# Get the cleaner exportReferencesGraph interface
__structuredAttrs = true;
exportReferencesGraph.graph = paths;
nativeBuildInputs = [ jq ];
}
''
jq -r ".graph | map(.path) | sort | .[]" "$NIX_ATTRS_JSON_FILE" > "$out"
'';
2024-05-02 00:46:19 +00:00
# Docs in doc/build-helpers/trivial-build-helpers.chapter.md
# See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeDirectReferencesToFile
2024-06-30 08:12:46 +00:00
writeDirectReferencesToFile =
path:
runCommand "runtime-references"
{
exportReferencesGraph = [
"graph"
path
];
inherit path;
}
''
touch ./references
while read p; do
read dummy
read nrRefs
if [[ $p == $path ]]; then
for ((i = 0; i < nrRefs; i++)); do
read ref;
echo $ref >>./references
done
else
for ((i = 0; i < nrRefs; i++)); do
read ref;
done
fi
done < graph
sort ./references >$out
'';
2024-05-02 00:46:19 +00:00
# TODO: move writeStringReferencesToFile docs to the Nixpkgs manual
/*
Extract a string's references to derivations and paths (its
context) and write them to a text file, removing the input string
itself from the dependency graph. This is useful when you want to
make a derivation depend on the string's references, but not its
contents (to avoid unnecessary rebuilds, for example).
Note that this only works as intended on Nix >= 2.3.
2024-06-30 08:12:46 +00:00
*/
writeStringReferencesToFile =
string:
2024-05-02 00:46:19 +00:00
/*
The basic operation this performs is to copy the string context
from `string` to a second string and wrap that string in a
derivation. However, that alone is not enough, since nothing in the
string refers to the output paths of the derivations/paths in its
context, meaning they'll be considered build-time dependencies and
removed from the wrapper derivation's closure. Putting the
necessary output paths in the new string is however not very
straightforward - the attrset returned by `getContext` contains
only references to derivations' .drv-paths, not their output
paths. In order to "convert" them, we try to extract the
corresponding paths from the original string using regex.
*/
let
# Taken from https://github.com/NixOS/nix/blob/130284b8508dad3c70e8160b15f3d62042fc730a/src/libutil/hash.cc#L84
nixHashChars = "0123456789abcdfghijklmnpqrsvwxyz";
context = builtins.getContext string;
derivations = lib.filterAttrs (n: v: v ? outputs) context;
# Objects copied from outside of the store, such as paths and
# `builtins.fetch*`ed ones
sources = lib.attrNames (lib.filterAttrs (n: v: v ? path) context);
2024-06-30 08:12:46 +00:00
packages = lib.mapAttrs' (name: value: {
inherit value;
name = lib.head (builtins.match "${builtins.storeDir}/[${nixHashChars}]+-(.*)\.drv" name);
}) derivations;
2024-05-02 00:46:19 +00:00
# The syntax of output paths differs between outputs named `out`
# and other, explicitly named ones. For explicitly named ones,
# the output name is suffixed as `-name`, but `out` outputs
# aren't suffixed at all, and thus aren't easily distinguished
# from named output paths. Therefore, we find all the named ones
# first so we can use them to remove false matches when looking
# for `out` outputs (see the definition of `outputPaths`).
2024-06-30 08:12:46 +00:00
namedOutputPaths = lib.flatten (
lib.mapAttrsToList (
name: value:
(map (
output:
lib.filter lib.isList (
builtins.split "(${builtins.storeDir}/[${nixHashChars}]+-${name}-${output})" string
)
) (lib.remove "out" value.outputs))
) packages
);
2024-05-02 00:46:19 +00:00
# Only `out` outputs
2024-06-30 08:12:46 +00:00
outputPaths = lib.flatten (
lib.mapAttrsToList (
name: value:
if lib.elem "out" value.outputs then
lib.filter (
x:
lib.isList x
&&
# If the matched path is in `namedOutputPaths`,
# it's a partial match of an output path where
# the output name isn't `out`
lib.all (o: !lib.hasPrefix (lib.head x) o) namedOutputPaths
) (builtins.split "(${builtins.storeDir}/[${nixHashChars}]+-${name})" string)
else
[ ]
) packages
);
2024-05-02 00:46:19 +00:00
allPaths = lib.concatStringsSep "\n" (lib.unique (sources ++ namedOutputPaths ++ outputPaths));
allPathsWithContext = builtins.appendContext allPaths context;
in
if builtins ? getContext then
writeText "string-references" allPathsWithContext
else
writeDirectReferencesToFile (writeText "string-file" string);
# Docs in doc/build-helpers/fetchers.chapter.md
# See https://nixos.org/manual/nixpkgs/unstable/#requirefile
requireFile =
2024-06-30 08:12:46 +00:00
{
name ? null,
sha256 ? null,
sha1 ? null,
hash ? null,
url ? null,
message ? null,
hashMode ? "flat",
2024-05-02 00:46:19 +00:00
}:
2024-06-30 08:12:46 +00:00
assert (message != null) || (url != null);
assert (sha256 != null) || (sha1 != null) || (hash != null);
assert (name != null) || (url != null);
let
msg =
if message != null then
message
else
''
2024-05-02 00:46:19 +00:00
Unfortunately, we cannot download file ${name_} automatically.
Please go to ${url} to download it yourself, and add it to the Nix store
using either
nix-store --add-fixed ${hashAlgo} ${name_}
or
nix-prefetch-url --type ${hashAlgo} file:///path/to/${name_}
'';
2024-06-30 08:12:46 +00:00
hashAlgo =
if hash != null then
(builtins.head (lib.strings.splitString "-" hash))
else if sha256 != null then
"sha256"
else
"sha1";
hashAlgo_ = if hash != null then "" else hashAlgo;
hash_ =
if hash != null then
hash
else if sha256 != null then
sha256
else
sha1;
name_ = if name == null then baseNameOf (toString url) else name;
in
stdenvNoCC.mkDerivation {
name = name_;
outputHashMode = hashMode;
outputHashAlgo = hashAlgo_;
outputHash = hash_;
preferLocalBuild = true;
allowSubstitutes = false;
builder = writeScript "restrict-message" ''
source ${stdenvNoCC}/setup
cat <<_EOF_
2024-05-02 00:46:19 +00:00
2024-06-30 08:12:46 +00:00
***
${msg}
***
2024-05-02 00:46:19 +00:00
2024-06-30 08:12:46 +00:00
_EOF_
exit 1
'';
};
2024-05-02 00:46:19 +00:00
# TODO: move copyPathToStore docs to the Nixpkgs manual
/*
Copy a path to the Nix store.
Nix automatically copies files to the store before stringifying paths.
If you need the store path of a file, ${copyPathToStore <path>} can be
shortened to ${<path>}.
*/
copyPathToStore = builtins.filterSource (p: t: true);
# TODO: move copyPathsToStore docs to the Nixpkgs manual
2024-06-30 08:12:46 +00:00
# Copy a list of paths to the Nix store.
2024-05-02 00:46:19 +00:00
copyPathsToStore = builtins.map copyPathToStore;
# TODO: move applyPatches docs to the Nixpkgs manual
2024-06-30 08:12:46 +00:00
/*
Applies a list of patches to a source directory.
2024-05-02 00:46:19 +00:00
Example:
# Patching nixpkgs:
applyPatches {
src = pkgs.path;
patches = [
(pkgs.fetchpatch {
url = "https://github.com/NixOS/nixpkgs/commit/1f770d20550a413e508e081ddc08464e9d08ba3d.patch";
sha256 = "1nlzx171y3r3jbk0qhvnl711kmdk57jlq4na8f8bs8wz2pbffymr";
})
];
}
2024-06-30 08:12:46 +00:00
*/
2024-05-02 00:46:19 +00:00
applyPatches =
2024-06-30 08:12:46 +00:00
{
src,
name ?
(
if builtins.typeOf src == "path" then
builtins.baseNameOf src
else if builtins.isAttrs src && builtins.hasAttr "name" src then
src.name
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."
)
+ "-patched",
patches ? [ ],
prePatch ? "",
postPatch ? "",
...
2024-05-02 00:46:19 +00:00
}@args:
2024-06-30 08:12:46 +00:00
if patches == [ ] && prePatch == "" && postPatch == "" then
src # nothing to do, so use original src to avoid additional drv
else
stdenvNoCC.mkDerivation (
{
inherit
name
src
patches
prePatch
postPatch
;
preferLocalBuild = true;
allowSubstitutes = false;
phases = "unpackPhase patchPhase installPhase";
installPhase = "cp -R ./ $out";
}
# Carry `meta` information from the underlying `src` if present.
// (optionalAttrs (src ? meta) { inherit (src) meta; })
// (removeAttrs args [
"src"
"name"
"patches"
"prePatch"
"postPatch"
])
);
2024-05-02 00:46:19 +00:00
# TODO: move docs to Nixpkgs manual
2024-06-30 08:12:46 +00:00
# An immutable file in the store with a length of 0 bytes.
emptyFile = runCommand "empty-file" {
outputHashAlgo = "sha256";
outputHashMode = "recursive";
outputHash = "0ip26j2h11n1kgkz36rl4akv694yz65hr72q4kv4b3lxcbi65b3p";
preferLocalBuild = true;
} "touch $out";
2024-05-02 00:46:19 +00:00
# TODO: move docs to Nixpkgs manual
2024-06-30 08:12:46 +00:00
# An immutable empty directory in the store.
emptyDirectory = runCommand "empty-directory" {
outputHashAlgo = "sha256";
outputHashMode = "recursive";
outputHash = "0sjjj9z1dhilhpc8pq4154czrb79z9cm044jvn75kxcjv6v5l2m5";
preferLocalBuild = true;
} "mkdir $out";
2024-05-02 00:46:19 +00:00
}