Skip to content

Commit

Permalink
Support additional format search paths
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tomeon committed Apr 15, 2022
1 parent adeb359 commit 547da9e
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 11 deletions.
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ you can use the `--system` option to create images for other architectures.
`nixos-generators` can be included as a `Flake` input and provides
a `nixos-generate` function for building images as `Flake` outputs. This
approach pins all dependencies and allows for conveniently defining multiple
output types based on one config.
output types based on one config.

An example `flake.nix` demonstrating this approach is below. `vmware` or
`virtualbox` images can be built from the same `configuration.nix` by running
Expand Down Expand Up @@ -145,6 +145,45 @@ An example `flake.nix` demonstrating this approach is below. `vmware` or
}
```

## Using custom formats

You can choose a format by telling `nixos-generate` its full path:

```console
nixos-generate --format-path ./path/to/my-format.nix
```

Additionally, you can tell `nixos-generate` where to search for format files by

* Adding `:`-separated paths to the `NIXOS_GENERATORS_FORMAT_SEARCH_PATH`
environment variable, or
* Calling `nixos-generate` with one or more `--format-search-path <path>`
options.

Example:

```console
NIXOS_GENERATORS_FORMAT_SEARCH_PATH=/path/a:/path/b nixos-generate --format-search-path /path/c --format-search-path /path/d -f my-format
```

The above command searches for the file `my-format.nix` in the order:

1. `/path/d`
2. `/path/c`
3. `/path/a`
4. `/path/b`
5. The builtin `nixos-generate` format directory

Note that:

* `nixos-generate` does not recognize a mechanism for escaping `:` characters
in paths specified in `NIXOS_GENERATORS_FORMAT_SEARCH_PATH`; if you have
custom formats that live in a path that contains `:`, specify the path with
`--format-search-path ./path/that/contains/a:or/two:`.
* `nixos-generate` ignores empty strings in the list of format search paths
(`nixos-generate --format-search-path ''`).
* Format names cannot be empty and cannot contain `/` elements.

### License

This project is licensed under the [MIT License](LICENSE).
Expand Down
107 changes: 97 additions & 10 deletions nixos-generate
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,27 @@ set -euo pipefail
## Configuration

readonly libexec_dir="${0%/*}"
readonly format_dir=$libexec_dir/formats

configuration=${NIXOS_CONFIG:-$libexec_dir/configuration.nix}
flake_uri=
flake_attr=
format=
format_path=
target_system=
cores=
run=
list_formats=false
show_format_search_path=false
nix_args=(
"$libexec_dir/nixos-generate.nix"
)
has_outlink=false
nix_build_args=()

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

## Functions

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

listFormats() {
for format in "$format_dir"/*.nix; do
basename "$format" ".nix"
local -A formats
local format_dir format_file format

for format_dir in "${format_dirs[@]}"; do
if [[ -n $format_dir ]]; then
for format_file in "$format_dir"/*.nix; do
if [[ -f "$format_file" ]]; then
format=$(basename "$format_file" ".nix")
formats["$format"]=1
fi
done
fi
done

for format in "${!formats[@]}"; do
printf -- '%s\n' "$format"
done | sort
}

showFormatSearchPath() {
local -i pos=1
local format_dir

for format_dir in "${format_dirs[@]}"; do
if [[ -n $format_dir ]]; then
printf -- '%d. "%q"\n' "$(( pos++ ))" "$format_dir"
fi
done
}

validateFormat() {
case "${1:-}" in
*/* | '')
abort "not a valid format name: ${1:-<empty>}"
return 1
;;
esac
}

findFormat() {
local format="${1?}"
shift

validateFormat "$format" || return

local -n ref_var="${1:-format_file}"
shift

local format_dir maybe_format_file

for format_dir in "${format_dirs[@]}"; do
if [[ -n $format_dir ]]; then
maybe_format_file="${format_dir}/${format}.nix"

if [[ -f "$maybe_format_file" ]]; then
ref_var="$maybe_format_file"
return
fi
fi
done

abort "unable to locate file for format: $format"
}

abort() {
Expand Down Expand Up @@ -84,27 +153,33 @@ while [[ $# -gt 0 ]]; do
shift 2
;;
-f | --format)
format_path=$format_dir/$2.nix
format="$2"
shift
;;
--format-path)
format_path=$2
shift
;;
--format-search-path)
format_dirs=("$2" "${format_dirs[@]}")
shift
;;
--help)
showUsage
exit
;;
--list)
listFormats
exit
list_formats=true
show_format_search_path=false
;;
--show-format-search-path)
list_formats=false
show_format_search_path=true
;;
--run)
run=1
# default to the VM format
if [[ -z $format_path ]]; then
format_path=$format_dir/vm.nix
fi
format="${format:-vm}"
;;
--show-trace)
nix_args+=(--show-trace)
Expand All @@ -129,12 +204,24 @@ while [[ $# -gt 0 ]]; do
shift
done

if $list_formats; then
listFormats
exit
elif $show_format_search_path; then
showFormatSearchPath
exit
fi

if ! $has_outlink; then
nix_build_args+=(--no-out-link)
fi

if [[ -z $format_path ]]; then
abort "missing format. use --help for more details"
if [[ -n $format ]] ;then
findFormat "$format" format_path
else
abort "missing format. use --help for more details"
fi
fi

if [[ ! -f $format_path ]]; then
Expand Down

0 comments on commit 547da9e

Please sign in to comment.