Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: improve documentation for trivial text writing functions #277534

Merged
merged 15 commits into from
Jan 15, 2024
Merged
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
340 changes: 324 additions & 16 deletions doc/build-helpers/trivial-build-helpers.chapter.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Trivial build helpers {#chap-trivial-builders}

Nixpkgs provides a couple of functions that help with building derivations. The most important one, `stdenv.mkDerivation`, has already been documented above. The following functions wrap `stdenv.mkDerivation`, making it easier to use in certain cases.
Nixpkgs provides a variety of wrapper functions that help build commonly useful derivations. Like [`stdenv.mkDerivation`](#sec-using-stdenv), each of these builders creates a derivation, but the arguments passed are different (usually simpler) from those required by `stdenv.mkDerivation`.

## `runCommand` {#trivial-builder-runCommand}

Expand Down Expand Up @@ -58,24 +58,108 @@ Variant of `runCommand` that forces the derivation to be built locally, it is no
This sets [`allowSubstitutes` to `false`](https://nixos.org/nix/manual/#adv-attr-allowSubstitutes), 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`.
:::

## `writeTextFile`, `writeText`, `writeTextDir`, `writeScript`, `writeScriptBin` {#trivial-builder-writeText}
## `writeTextFile`, `writeText`, `writeTextDir`, `writeScript`, `writeScriptBin`, `writeShellScript`, `writeShellScriptBin` {#trivial-builder-textwriting}
mcdonc marked this conversation as resolved.
Show resolved Hide resolved

These functions write `text` to the Nix store. This is useful for creating scripts from Nix expressions. `writeTextFile` takes an attribute set and expects two arguments, `name` and `text`. `name` corresponds to the name used in the Nix store path. `text` will be the contents of the file. You can also set `executable` to true to make this file have the executable bit set.
Nixpkgs provides the following functions for producing derivations which write text into the Nix store: `writeTextFile`, `writeText`, `writeTextDir`, `writeScript`, `writeScriptBin`, `writeShellScript`, and `writeShellScriptBin`.

Many more commands wrap `writeTextFile` including `writeText`, `writeTextDir`, `writeScript`, and `writeScriptBin`. These are convenience functions over `writeTextFile`.
`writeText`, `writeTextDir`, `writeScript`, `writeScriptBin`, `writeShellScript`, and `writeShellScriptBin` are convenience functions over `writeTextFile`.

Here are a few examples:
These are useful for creating files from Nix expressions, which may be scripts or non-executable text files.

Each of these functions will cause a derivation to be realized. When you coerce the result of each of these functions to a string, it will evaluate to the *store path* of this derivation.
mcdonc marked this conversation as resolved.
Show resolved Hide resolved

:::: {.warning}
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 Nix code, remember to append the path to the file For example:
mcdonc marked this conversation as resolved.
Show resolved Hide resolved
mcdonc marked this conversation as resolved.
Show resolved Hide resolved

```nix
my-file = writeTextFile {
name = "my-file";
text = ''
Contents of File
'';
destination = "/share/my-file";
}

writeShellScript "evaluate-my-file.sh" ''
cat ${my-file}/share/my-file
'';
```
::::

### `writeTextFile` {#trivial-builder-writeTextFile}

Writes a text file to the store

`writeTextFile` takes an attribute set with the following possible attributes:

`name`

: Corresponds to the name used in the Nix store path identifier.

`text`

: The contents of the file.

`executable` _optional_

: Make this file have the executable bit set. Defaults to `false`

`destination` _optional_

: Supplies a subpath under the derivation's Nix store ouput path into which to create the file. It may contain directory path elements, these are created automatically when the derivation is realized. Defaults to `""`, which indicates that the store path itself will be a file containing the text contents.

`checkPhase` _optional_

: Commands to run after generating the file, e.g. lints. It defaults to `""` (no checking).

`meta` _optional_

: Additional metadata for the derivation. It defaults to `{}`.

`allowSubstitutes` _optional_

: Whether to allow substituting from a binary cache. It defaults to `false`, as the operation is assumed to be faster performed locally. You may want to set this to true if the `checkPhase` step is expensive.

`preferLocalBuild` _optional_

: Whether to prefer building locally, even if faster remote builders are available. It defaults to `true` for the same reason `allowSubstitutes` defaults to `false`.

The resulting store path will include some variation of the name, and it will be a file unless `destination` (see below) is used, in which case it will be a directory.

::: {.example #ex-writeTextFile}
# Usages of `writeTextFile`
```nix
# Writes my-file to /nix/store/<store path>/some/subpath/my-cool-script,
# making it executable and also supplies values for the less-used options
writeTextFile rec {
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/${destination}
'';
meta = {
license = pkgs.lib.licenses.cc0;
};
allowSubstitutes = true;
preferLocalBuild = false;
}

# Writes my-file to /nix/store/<store path>
# See also the `writeText` helper function below.
writeTextFile {
name = "my-file";
text = ''
Contents of File
'';
}
# See also the `writeText` helper function below.

# Writes executable my-file to /nix/store/<store path>/bin/my-file
# see also the `writeScriptBin` helper function below.
writeTextFile {
name = "my-file";
text = ''
Expand All @@ -84,37 +168,261 @@ writeTextFile {
executable = true;
destination = "/bin/my-file";
}
# Writes contents of file to /nix/store/<store path>
```
:::

mcdonc marked this conversation as resolved.
Show resolved Hide resolved
### `writeText` {#trivial-builder-writeText}

Writes a text file to the store

`writeText` takes two arguments: `name` and `text`, each of which should be
a string.

`name`

: the name used in the Nix store path.

`text`

: will be the contents of the file.

The store path will include the the name, and it will be a file. Any path separators and shell-reserved elements in the name are escaped to create the store path identifier.
mcdonc marked this conversation as resolved.
Show resolved Hide resolved

Here is an example.

::: {.example #ex-writeText}
# Usage of `writeText`
```nix
# Writes my-file to /nix/store/<store path>
writeText "my-file"
''
Contents of File
'';
```
:::

This example is equivalent to:

```nix
writeTextFile {
name = "my-file";
text = ''
Contents of File
'';
}
```

### `writeTextDir` {#trivial-builder-writeTextDir}

Writes a text file within a subdirectory of the store.

`writeTextDir` takes two arguments: `path` and `text`, each of which should be a string.

`path`

: the destination within the Nix store path under which to create the file.

`text`

: the contents of the file.

The store path will be a directory.

::: {.example #ex-writeTextDir}
# Usage of `writeTextDir`
```nix
# Writes contents of file to /nix/store/<store path>/share/my-file
writeTextDir "share/my-file"
''
Contents of File
'';
```
:::

This example is equivalent to:

```nix
writeTextFile {
name = "my-file";
text = ''
Contents of File
'';
destination = "share/my-file";
}
```

### `writeScript` {#trivial-builder-writeScript}

Writes a script within the store.

`writeScript` takes two arguments: `name` and `text`, each of which should be a string.

`name`

: the name used in the Nix store path.

`text`

: the contents of the file.

The created file is marked as executable.

The store path will include the the name, and it will be a file. Any path separators and shell-reserved elements in the name are escaped to create the store path identifier.

Here is an example.

::: {.example #ex-writeScript}
# Usage of `writeScript`
```nix
# Writes my-file to /nix/store/<store path> and makes executable
writeScript "my-file"
''
Contents of File
'';
# Writes my-file to /nix/store/<store path>/bin/my-file and makes executable.
writeScriptBin "my-file"
```
:::

This example is equivalent to:

```nix
writeTextFile {
name = "my-file";
text = ''
Contents of File
'';
executable = true;
}
```

### `writeScriptBin` {#trivial-builder-writeScriptBin}

Writes a script within a "bin" subirectory of a subdirectory of the store.

`writeScriptBin` takes two arguments: `name` and `text`, each of which should be a string.

`name`

: the name used in the Nix store path and within the file generated under the store path.

`text`

: 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. Any path separators and shell-reserved elements in the name are escaped to create the store path identifier.

::: {.example #ex-writeScriptBin}
# Usage of `writeScriptBin`
```nix
writeScriptBin "my-script"
''
Contents of File
echo "hi"
'';
# Writes my-file to /nix/store/<store path> and makes executable.
writeShellScript "my-file"
```
:::

This example is equivalent to:

```nix
writeTextFile {
name = "my-script";
text = ''
echo "hi"
'';
executable = true;
destination = "bin/my-script"
}
```

### `writeShellScript` {#trivial-builder-writeShellScript}

Writes a shell script to the store.

`writeShellScript` takes two arguments: `name` and `text`, each of which should be a string.

`name`

: the name used in the Nix store path.

`text`

: the contents of the file.

The created file is marked as executable.

This function is almost exactly like `writeScript`, but it prepends a shebang line that points to the runtime shell (usually bash) at the top of the file contents.

The store path will include the the name, and it will be a file. Any path separators and shell-reserved elements in the name are escaped to create the store path identifier.

Here is an example.

::: {.example #ex-writeShellScript}
# Usage of `writeShellScript`
```nix
writeShellScript "my-script"
''
Contents of File
echo "hi"
'';
# Writes my-file to /nix/store/<store path>/bin/my-file and makes executable.
writeShellScriptBin "my-file"
```
:::

This example is equivalent to:

```nix
writeTextFile {
name = "my-script";
text = ''
#! ${pkgs.runtimeShell}
echo "hi"
'';
executable = true;
}
```
### `writeShellScriptBin` {#trivial-builder-writeShellScriptBin}

Writes a shell script to a "bin" subdirectory of subdirectory of the store.

`writeShellScriptBin` takes two arguments: `name` and `text`, each of which should be a string.

`name`

: the name used in the Nix store path and within the file generated under the store path.

`text`

: the contents of the file.

This function is almost exactly like `writeScriptBin`, but it prepends a shebang line that points to the runtime shell (usually bash) at the top of the file contents.

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. Any path separators and shell-reserved elements in the name are escaped to create the store path identifier.

::: {.example #ex-writeShellScriptBin}
# Usage of `writeShellScriptBin`
```nix
writeShellScriptBin "my-script"
''
Contents of File
echo "hi"
'';
```
:::

This example is equivalent to:

```nix
writeTextFile {
name = "my-script";
text = ''
#! ${pkgs.runtimeShell}
echo "hi"
'';
executable = true;
destination = "bin/my-script"
}
```

## `concatTextFile`, `concatText`, `concatScript` {#trivial-builder-concatText}
Expand Down