Skip to content

Commit 6d289ee

Browse files
committed
support additional format search paths
via the NIXOS_GENERATORS_FORMAT_SEARCH_PATH environment variable and --format-search-path CLI option. Additionally, introduce the --show-format-search-path option, which causes nixos-generate to print the list of paths it will search for format files.
1 parent 9191c85 commit 6d289ee

File tree

2 files changed

+140
-14
lines changed

2 files changed

+140
-14
lines changed

README.md

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ images can be built from that flake by running:
207207
`nixos-generators` can be included as a `Flake` input and provides
208208
a `nixos-generate` function for building images as `Flake` outputs. This
209209
approach pins all dependencies and allows for conveniently defining multiple
210-
output types based on one config.
210+
output types based on one config.
211211

212212
An example `flake.nix` demonstrating this approach is below. `vmware` or
213213
`virtualbox` images can be built from the same `configuration.nix` by running
@@ -237,14 +237,14 @@ multiple custom formats. `nixosGenerate` will then match against these custom f
237237
# ./configuration.nix
238238
];
239239
format = "vmware";
240-
240+
241241
# optional arguments:
242242
# explicit nixpkgs and lib:
243243
# pkgs = nixpkgs.legacyPackages.x86_64-linux;
244244
# lib = nixpkgs.legacyPackages.x86_64-linux.lib;
245245
# additional arguements to pass to modules:
246246
# specialArgs = { myExtraArg = "foobar"; };
247-
247+
248248
# you can also define your own custom formats
249249
# customFormats = { "myFormat" = <myFormatModule>; ... };
250250
# format = "myFormat";
@@ -268,6 +268,46 @@ multiple custom formats. `nixosGenerate` will then match against these custom f
268268
* If boot fails for some reason, you will not get a recovery shell unless the root user is enabled, which you can do by setting a password for them (`users.users.root.password = "something";`, possibly `users.mutableUsers = true;` so you can interactively change the passwords after boot)
269269
* After booting, if you intend to use `nixos-switch`, consider using `nixos-generate-config`.
270270

271+
## Using custom formats
272+
273+
You can choose a format by telling `nixos-generate` its full path:
274+
275+
```console
276+
nixos-generate --format-path ./path/to/my-format.nix
277+
```
278+
279+
Additionally, you can tell `nixos-generate` where to search for format files by
280+
281+
* Adding `:`-separated paths to the `NIXOS_GENERATORS_FORMAT_SEARCH_PATH`
282+
environment variable, or
283+
* Calling `nixos-generate` with one or more `--format-search-path <path>`
284+
options.
285+
286+
Example:
287+
288+
```console
289+
NIXOS_GENERATORS_FORMAT_SEARCH_PATH=/path/a:/path/b nixos-generate --format-search-path /path/c --format-search-path /path/d -f my-format
290+
```
291+
292+
The above command searches for the file `my-format.nix` in the following paths,
293+
in order from highest precedence to lowest:
294+
295+
1. `/path/d/my-format.nix`
296+
2. `/path/c/my-format.nix`
297+
3. `/path/a/my-format.nix`
298+
4. `/path/b/my-format.nix`
299+
5. `my-format.nix` in the builtin `nixos-generate` format directory
300+
301+
Note that:
302+
303+
* `nixos-generate` does not recognize a mechanism for escaping `:` characters
304+
in paths specified in `NIXOS_GENERATORS_FORMAT_SEARCH_PATH`; if you have
305+
custom formats that live in a path that contains `:`, specify the path with
306+
`--format-search-path ./path/that/contains/a:or/two:`.
307+
* `nixos-generate` ignores empty strings in the list of format search paths
308+
(`nixos-generate --format-search-path ''`).
309+
* Format names cannot be empty and cannot contain `/` elements.
310+
271311
### License
272312

273313
This project is licensed under the [MIT License](LICENSE).

nixos-generate

Lines changed: 97 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,27 @@ set -euo pipefail
44
## Configuration
55

66
readonly libexec_dir="${0%/*}"
7-
readonly format_dir=$libexec_dir/formats
87

98
configuration=${NIXOS_CONFIG:-$libexec_dir/configuration.nix}
109
flake_uri=
1110
flake_attr=
11+
format=
1212
format_path=
1313
target_system=
1414
cores=
1515
run=
16+
list_formats=false
17+
show_format_search_path=false
1618
nix_args=(
1719
"$libexec_dir/nixos-generate.nix"
1820
)
1921
has_outlink=false
2022
nix_build_args=()
2123

24+
# `printf' rather than `<<<' to avoid introducing a spurious trailing newline
25+
mapfile -t -d : format_dirs < <(printf -- '%s' "${NIXOS_GENERATORS_FORMAT_SEARCH_PATH:-}")
26+
format_dirs+=("$libexec_dir/formats")
27+
2228
## Functions
2329

2430
showUsage() {
@@ -34,7 +40,11 @@ Options:
3440
selects the nixos configuration to build, using flake uri like "~/dotfiles#my-config"
3541
* -f, --format NAME: select one of the pre-determined formats
3642
* --format-path PATH: pass a custom format
37-
* --list: list the available built-in formats
43+
* --format-search-path DIR:
44+
prepend a directory to the list of directories ${0##*/} searches for format definitions
45+
* --list: list the available formats
46+
* --show-format-search-path:
47+
list the directories ${0##*/} searches for format files
3848
* --run: runs the configuration in a VM
3949
only works for the "vm" and "vm-nogui" formats
4050
* --show-trace: show more detailed nix evaluation location information
@@ -47,9 +57,67 @@ USAGE
4757
}
4858

4959
listFormats() {
50-
for format in "$format_dir"/*.nix; do
51-
basename "$format" ".nix"
60+
local -A formats
61+
local format_dir format_file format
62+
63+
for format_dir in "${format_dirs[@]}"; do
64+
if [[ -n $format_dir ]]; then
65+
for format_file in "$format_dir"/*.nix; do
66+
if [[ -f "$format_file" ]]; then
67+
format=$(basename "$format_file" ".nix")
68+
formats["$format"]=1
69+
fi
70+
done
71+
fi
72+
done
73+
74+
for format in "${!formats[@]}"; do
75+
printf -- '%s\n' "$format"
76+
done | sort
77+
}
78+
79+
showFormatSearchPath() {
80+
local format_dir
81+
82+
for format_dir in "${format_dirs[@]}"; do
83+
if [[ -n $format_dir ]]; then
84+
printf -- '%s\n' "$format_dir"
85+
fi
86+
done
87+
}
88+
89+
validateFormat() {
90+
case "${1:-}" in
91+
*/* | '')
92+
abort "not a valid format name: ${1:-<empty>}"
93+
return 1
94+
;;
95+
esac
96+
}
97+
98+
findFormat() {
99+
local format="${1?}"
100+
shift
101+
102+
validateFormat "$format" || return
103+
104+
local -n ref_var="${1:-format_file}"
105+
shift
106+
107+
local format_dir maybe_format_file
108+
109+
for format_dir in "${format_dirs[@]}"; do
110+
if [[ -n $format_dir ]]; then
111+
maybe_format_file="${format_dir}/${format}.nix"
112+
113+
if [[ -f "$maybe_format_file" ]]; then
114+
ref_var="$maybe_format_file"
115+
return
116+
fi
117+
fi
52118
done
119+
120+
abort "unable to locate file for format: $format"
53121
}
54122

55123
abort() {
@@ -84,27 +152,33 @@ while [[ $# -gt 0 ]]; do
84152
shift 2
85153
;;
86154
-f | --format)
87-
format_path=$format_dir/$2.nix
155+
format="$2"
88156
shift
89157
;;
90158
--format-path)
91159
format_path=$2
92160
shift
93161
;;
162+
--format-search-path)
163+
format_dirs=("$2" "${format_dirs[@]}")
164+
shift
165+
;;
94166
--help)
95167
showUsage
96168
exit
97169
;;
98170
--list)
99-
listFormats
100-
exit
171+
list_formats=true
172+
show_format_search_path=false
173+
;;
174+
--show-format-search-path)
175+
list_formats=false
176+
show_format_search_path=true
101177
;;
102178
--run)
103179
run=1
104180
# default to the VM format
105-
if [[ -z $format_path ]]; then
106-
format_path=$format_dir/vm.nix
107-
fi
181+
format="${format:-vm}"
108182
;;
109183
--show-trace)
110184
nix_args+=(--show-trace)
@@ -129,12 +203,24 @@ while [[ $# -gt 0 ]]; do
129203
shift
130204
done
131205

206+
if $list_formats; then
207+
listFormats
208+
exit
209+
elif $show_format_search_path; then
210+
showFormatSearchPath
211+
exit
212+
fi
213+
132214
if ! $has_outlink; then
133215
nix_build_args+=(--no-out-link)
134216
fi
135217

136218
if [[ -z $format_path ]]; then
137-
abort "missing format. use --help for more details"
219+
if [[ -n $format ]] ;then
220+
findFormat "$format" format_path
221+
else
222+
abort "missing format. use --help for more details"
223+
fi
138224
fi
139225

140226
if [[ ! -f $format_path ]]; then

0 commit comments

Comments
 (0)