I didn't have the opportunity to do all work at once, so I've added TODOs to bring attention to the situation.
17 KiB
Trivial build helpers
Nixpkgs provides a variety of wrapper functions that help build commonly useful derivations.
Like stdenv.mkDerivation
, each of these build helpers creates a derivation, but the arguments passed are different (usually simpler) from those required by stdenv.mkDerivation
.
runCommand
runCommand :: String -> AttrSet -> String -> Derivation
The result of runCommand name drvAttrs buildCommand
is a derivation that is built by running the specified shell commands.
By default runCommand
runs in a stdenv with no compiler environment, whereas runCommandCC
uses the default stdenv, pkgs.stdenv
.
name :: String
- The name that Nix will append to the store path in the same way that
stdenv.mkDerivation
uses itsname
attribute. drvAttr :: AttrSet
- Attributes to pass to the underlying call to
stdenv.mkDerivation
. buildCommand :: String
- Shell commands to run in the derivation builder.
::: {.note} You have to create a file or directory
$out
for Nix to be able to run the builder successfully. :::
::: {.example #ex-runcommand-simple}
Invocation of runCommand
(import <nixpkgs> {}).runCommand "my-example" {} ''
echo My example command is running
mkdir $out
echo I can write data to the Nix store > $out/message
echo I can also run basic commands like:
echo ls
ls
echo whoami
whoami
echo date
date
''
:::
runCommandCC
This works just like runCommand
. The only difference is that it also provides a C compiler in buildCommand
's environment. To minimize your dependencies, you should only use this if you are sure you will need a C compiler as part of running your command.
runCommandLocal
Variant of runCommand
that forces the derivation to be built locally, it is not substituted. This is intended for very cheap commands (<1s execution time). It saves on the network round-trip and can speed up a build.
::: {.note}
This sets allowSubstitutes
to false
, so only use runCommandLocal
if you are certain the user will always have a builder for the system
of the derivation. This should be true for most trivial use cases (e.g., just copying some files to a different location or adding symlinks) because there the system
is usually the same as builtins.currentSystem
.
:::
Writing text files
Nixpkgs provides the following functions for producing derivations which write text files or executable scripts into the Nix store.
They are useful for creating files from Nix expression, and are all implemented as convenience wrappers around writeTextFile
.
Each of these functions will cause a derivation to be produced.
When you coerce the result of each of these functions to a string with string interpolation or builtins.toString
, it will evaluate to the store path of this derivation.
:::: {.note} Some of these functions will put the resulting files within a directory inside the derivation output. If you need to refer to the resulting files somewhere else in a Nix expression, append their path to the derivation's store path.
For example, if the file destination is a directory:
my-file = writeTextFile {
name = "my-file";
text = ''
Contents of File
'';
destination = "/share/my-file";
}
Remember to append "/share/my-file" to the resulting store path when using it elsewhere:
writeShellScript "evaluate-my-file.sh" ''
cat ${my-file}/share/my-file
'';
::::
writeTextFile
Write a text file to the Nix store.
writeTextFile
takes an attribute set with the following possible attributes:
name
(String)-
Corresponds to the name used in the Nix store path identifier.
text
(String)-
The contents of the file.
executable
(Bool, optional)-
Make this file have the executable bit set.
Default:
false
destination
(String, optional)-
A subpath under the derivation's output path into which to put the file. Subdirectories are created automatically when the derivation is realised.
By default, the store path itself will be a file containing the text contents.
Default:
""
checkPhase
(String, optional)-
Commands to run after generating the file.
Default:
""
meta
(Attribute set, optional)-
Additional metadata for the derivation.
Default:
{}
allowSubstitutes
(Bool, optional)-
Whether to allow substituting from a binary cache. Passed through to
allowSubsitutes
of the underlying call tobuiltins.derivation
.It defaults to
false
, as running the derivation's simplebuilder
executable locally is assumed to be faster than network operations. Set it to true if thecheckPhase
step is expensive.Default:
false
preferLocalBuild
(Bool, optional)-
Whether to prefer building locally, even if faster remote build machines are available.
Passed through to
preferLocalBuild
of the underlying call tobuiltins.derivation
.It defaults to
true
for the same reasonallowSubstitutes
defaults tofalse
.Default:
true
derivationArgs
(Attribute set, optional)-
Extra arguments to pass to the underlying call to
stdenv.mkDerivation
.Default:
{}
The resulting store path will include some variation of the name, and it will be a file unless destination
is used, in which case it will be a directory.
::: {.example #ex-writeTextFile}
Usage 1 of writeTextFile
Write my-file
to /nix/store/<store path>/some/subpath/my-cool-script
, making it executable.
Also run a check on the resulting file in a checkPhase
, and supply values for the less-used options.
writeTextFile {
name = "my-cool-script";
text = ''
#!/bin/sh
echo "This is my cool script!"
'';
executable = true;
destination = "/some/subpath/my-cool-script";
checkPhase = ''
${pkgs.shellcheck}/bin/shellcheck $out/some/subpath/my-cool-script
'';
meta = {
license = pkgs.lib.licenses.cc0;
};
allowSubstitutes = true;
preferLocalBuild = false;
};
:::
::: {.example #ex2-writeTextFile}
Usage 2 of writeTextFile
Write the string Contents of File
to /nix/store/<store path>
.
See also the helper function.
writeTextFile {
name = "my-file";
text = ''
Contents of File
'';
}
:::
::: {.example #ex3-writeTextFile}
Usage 3 of writeTextFile
Write an executable script my-script
to /nix/store/<store path>/bin/my-script
.
See also the helper function.
writeTextFile {
name = "my-script";
text = ''
echo "hi"
'';
executable = true;
destination = "/bin/my-script";
}
:::
writeText
Write a text file to the Nix store
writeText
takes the following arguments:
a string.
name
(String)-
The name used in the Nix store path.
text
(String)-
The contents of the file.
The store path will include the name, and it will be a file.
::: {.example #ex-writeText}
Usage of writeText
Write the string Contents of File
to /nix/store/<store path>
:
writeText "my-file"
''
Contents of File
'';
:::
This is equivalent to:
writeTextFile {
name = "my-file";
text = ''
Contents of File
'';
}
writeTextDir
Write a text file within a subdirectory of the Nix store.
writeTextDir
takes the following arguments:
path
(String)-
The destination within the Nix store path under which to create the file.
text
(String)-
The contents of the file.
The store path will be a directory.
::: {.example #ex-writeTextDir}
Usage of writeTextDir
Write the string Contents of File
to /nix/store/<store path>/share/my-file
:
writeTextDir "share/my-file"
''
Contents of File
'';
:::
This is equivalent to:
writeTextFile {
name = "my-file";
text = ''
Contents of File
'';
destination = "share/my-file";
}
writeScript
Write an executable script file to the Nix store.
writeScript
takes the following arguments:
name
(String)-
The name used in the Nix store path.
text
(String)-
The contents of the file.
The created file is marked as executable. The store path will include the name, and it will be a file.
::: {.example #ex-writeScript}
Usage of writeScript
Write the string Contents of File
to /nix/store/<store path>
and make the file executable.
writeScript "my-file"
''
Contents of File
'';
:::
This is equivalent to:
writeTextFile {
name = "my-file";
text = ''
Contents of File
'';
executable = true;
}
writeScriptBin
Write a script within a bin
subirectory of a directory in the Nix store.
This is for consistency with the convention of software packages placing executables under bin
.
writeScriptBin
takes the following arguments:
name
(String)-
The name used in the Nix store path and within the file created under the store path.
text
(String)-
The contents of the file.
The created file is marked as executable.
The file's contents will be put into /nix/store/<store path>/bin/<name>
.
The store path will include the the name, and it will be a directory.
::: {.example #ex-writeScriptBin}
Usage of writeScriptBin
writeScriptBin "my-script"
''
echo "hi"
'';
:::
This is equivalent to:
writeTextFile {
name = "my-script";
text = ''
echo "hi"
'';
executable = true;
destination = "bin/my-script"
}
writeShellScript
Write a Bash script to the store.
writeShellScript
takes the following arguments:
name
(String)-
The name used in the Nix store path.
text
(String)-
The contents of the file.
The created file is marked as executable. The store path will include the name, and it will be a file.
This function is almost exactly like , except that it prepends to the file a shebang line that points to the version of Bash used in Nixpkgs.
::: {.example #ex-writeShellScript}
Usage of writeShellScript
writeShellScript "my-script"
''
echo "hi"
'';
:::
This is equivalent to:
writeTextFile {
name = "my-script";
text = ''
#! ${pkgs.runtimeShell}
echo "hi"
'';
executable = true;
}
writeShellScriptBin
Write a Bash script to a "bin" subdirectory of a directory in the Nix store.
writeShellScriptBin
takes the following arguments:
name
(String)-
The name used in the Nix store path and within the file generated under the store path.
text
(String)-
The contents of the file.
The file's contents will be put into /nix/store/<store path>/bin/<name>
.
The store path will include the the name, and it will be a directory.
This function is a combination of and .
::: {.example #ex-writeShellScriptBin}
Usage of writeShellScriptBin
writeShellScriptBin "my-script"
''
echo "hi"
'';
:::
This is equivalent to:
writeTextFile {
name = "my-script";
text = ''
#! ${pkgs.runtimeShell}
echo "hi"
'';
executable = true;
destination = "bin/my-script"
}
concatTextFile
, concatText
, concatScript
These functions concatenate files
to the Nix store in a single file. This is useful for configuration files structured in lines of text. concatTextFile
takes an attribute set and expects two arguments, name
and files
. name
corresponds to the name used in the Nix store path. files
will be the files to be concatenated. You can also set executable
to true to make this file have the executable bit set.
concatText
andconcatScript
are simple wrappers over concatTextFile
.
Here are a few examples:
# 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";
}
# Writes contents of files to /nix/store/<store path>
concatText "my-file" [ file1 file2 ]
# Writes contents of files to /nix/store/<store path>
concatScript "my-file" [ file1 file2 ]
writeShellApplication
writeShellApplication
is similar to writeShellScriptBin
and writeScriptBin
but supports runtime dependencies with runtimeInputs
.
Writes an executable shell script to /nix/store/<store path>/bin/<name>
and checks its syntax with shellcheck
and the bash
's -n
option.
Some basic Bash options are set by default (errexit
, nounset
, and pipefail
), but can be overridden with bashOptions
.
Extra arguments may be passed to stdenv.mkDerivation
by setting derivationArgs
; note that variables set in this manner will be set when the shell script is built, not when it's run.
Runtime environment variables can be set with the runtimeEnv
argument.
For example, the following shell application can refer to curl
directly, rather than needing to write ${curl}/bin/curl
:
writeShellApplication {
name = "show-nixos-org";
runtimeInputs = [ curl w3m ];
text = ''
curl -s 'https://nixos.org' | w3m -dump -T text/html
'';
}
symlinkJoin
This can be used to put many derivations into the same directory structure. It works by creating a new derivation and adding symlinks to each of the paths listed. It expects two arguments, name
, and paths
. name
is the name used in the Nix store path for the created derivation. paths
is a list of paths that will be symlinked. These paths can be to Nix store derivations or any other subdirectory contained within.
Here is an example:
# 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
...
writeReferencesToFile
Writes the closure of transitive dependencies to a file.
This produces the equivalent of nix-store -q --requisites
.
For example,
writeReferencesToFile (writeScriptBin "hi" ''${hello}/bin/hello'')
produces an output path /nix/store/<hash>-runtime-deps
containing
/nix/store/<hash>-hello-2.10
/nix/store/<hash>-hi
/nix/store/<hash>-libidn2-2.3.0
/nix/store/<hash>-libunistring-0.9.10
/nix/store/<hash>-glibc-2.32-40
You can see that this includes hi
, the original input path,
hello
, which is a direct reference, but also
the other paths that are indirectly required to run hello
.
writeDirectReferencesToFile
Writes the set of references to the output file, that is, their immediate dependencies.
This produces the equivalent of nix-store -q --references
.
For example,
writeDirectReferencesToFile (writeScriptBin "hi" ''${hello}/bin/hello'')
produces an output path /nix/store/<hash>-runtime-references
containing
/nix/store/<hash>-hello-2.10
but none of hello
's dependencies because those are not referenced directly
by hi
's output.