outputs: make compatible with nix run and package lists

This adds new outpus like `format` and `formatNoDeps` which
are compatible with `nix run` so you can do something like

    nix run .#nixosConfigurations.myhostname.config.system.build.formatNoDeps

as originally intended in #78, or add disko to your configuration like

    environment.systemPackages = [
        config.system.build.format
        config.system.build.mount
        config.system.build.destroyFormatMount
    ];

as mentioned in #454.

Fixes part of #454
Supersedes #78

It also deprecates mode `disko` in favor of the clearer
`destroy,format,mount` and adds `format,mount` to allow easier in-place
updates.
This commit is contained in:
Felix Uhl 2024-10-18 22:57:34 +02:00
parent 856a290215
commit daca7be309
9 changed files with 123 additions and 33 deletions

View file

@ -99,7 +99,7 @@ a disk named /dev/sda, you would run the following command to partition, format
and mount the disk.
```console
sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode disko /tmp/disk-config.nix
sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount /tmp/disk-config.nix
```
## Related Tools

20
cli.nix
View file

@ -17,21 +17,29 @@ let
diskoAttr =
if noDeps then
{
format = "formatScriptNoDeps";
mount = "mountScriptNoDeps";
disko = "diskoScriptNoDeps";
destroy = "_cliDestroyNoDeps";
format = "_cliFormatNoDeps";
mount = "_cliMountNoDeps";
"format,mount" = "_cliFormatMountNoDeps";
"destroy,format,mount" = "_cliDestroyFormatMountNoDeps";
# legacy aliases
disko = "diskoScriptNoDeps";
create = "createScriptNoDeps";
zap_create_mount = "diskoScriptNoDeps";
}.${mode}
else
{
format = "formatScript";
mount = "mountScript";
disko = "diskoScript";
destroy = "_cliDestroy";
format = "_cliFormat";
mount = "_cliMount";
"format,mount" = "_cliFormatMount";
"destroy,format,mount" = "_cliDestroyFormatMount";
# legacy aliases
disko = "diskoScript";
create = "createScript";
zap_create_mount = "diskoScript";
}.${mode};

View file

@ -19,7 +19,22 @@ in
{
lib = lib.warn "the .lib.lib output is deprecated" diskoLib;
# legacy alias
_cliDestroy = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroy;
_cliDestroyNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyNoDeps;
_cliFormat = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).format;
_cliFormatNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatNoDeps;
_cliMount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mount;
_cliMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountNoDeps;
_cliFormatMount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMount;
_cliFormatMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMountNoDeps;
_cliDestroyFormatMount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMount;
_cliDestroyFormatMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMountNoDeps;
# legacy aliases
create = cfg: builtins.trace "the create output is deprecated, use format instead" (eval cfg).config.disko.devices._create;
createScript = cfg: pkgs: builtins.trace "the create output is deprecated, use format instead" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript;
createScriptNoDeps = cfg: pkgs: builtins.trace "the create output is deprecated, use format instead" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps;

22
disko
View file

@ -25,10 +25,12 @@ or else from the disko module of a NixOS configuration of that name under .nixos
Options:
* -m, --mode mode
set the mode, either format, mount or disko
format: create partition tables, zpools, lvms, raids and filesystems
mount: mount the partition at the specified root-mountpoint
disko: first unmount and destroy all filesystems on the disks we want to format, then run the create and mount mode
set the mode, either distroy, format, mount, format,mount or destroy,format,mount
destroy: unmount filesystems and destroy partition tables of the selected disks
format: create partition tables, zpools, lvms, raids and filesystems if they don't exist yet
mount: mount the partitions at the specified root-mountpoint
format,mount: run format and mount in sequence
destroy,format,mount: run all three modes in sequence. Previously known as --mode disko
* -f, --flake uri
fetch the disko config relative to this flake's root
* --arg name value
@ -126,8 +128,16 @@ nixBuild() {
fi
}
if ! { [[ $mode = "format" ]] || [[ $mode = "mount" ]] || [[ $mode = "disko" ]] || [[ $mode = "create" ]] || [[ $mode = "zap_create_mount" ]] ; }; then
abort "mode must be either format, mount or disko"
if ! {
# Base modes
[[ $mode = "destroy" ]] || [[ $mode = "format" ]] || [[ $mode = "mount" ]] ||
# Combined modes
[[ $mode = "format,mount" ]] ||
[[ $mode = "destroy,format,mount" ]] || # Replaces --mode disko
# Legacy modes, will be removed in next major version
[[ $mode = "disko" ]] || [[ $mode = "create" ]] || [[ $mode = "zap_create_mount" ]] ;
}; then
abort 'mode must be one of "destroy", "format", "mount", "destroy,format,mount" or "format,mount"'
fi
if [[ -n "${flake+x}" ]]; then

View file

@ -129,7 +129,7 @@ The following step will partition and format your disk, and mount it to `/mnt`.
**Please note: This will erase any existing data on your disk.**
```console
sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode disko /tmp/disk-config.nix
sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount /tmp/disk-config.nix
```
After the command has run, your file system should have been formatted and

View file

@ -21,10 +21,12 @@ or else from the disko module of a NixOS configuration of that name under .nixos
Options:
* -m, --mode mode
set the mode, either format, mount or disko
format: create partition tables, zpools, lvms, raids and filesystems
mount: mount the partition at the specified root-mountpoint
disko: first unmount and destroy all filesystems on the disks we want to format, then run the create and mount mode
set the mode, either distroy, format, mount, format,mount or destroy,format,mount
destroy: unmount filesystems and destroy partition tables of the selected disks
format: create partition tables, zpools, lvms, raids and filesystems if they don't exist yet
mount: mount the partitions at the specified root-mountpoint
format,mount: run format and mount in sequence
destroy,format,mount: run all three modes in sequence. Previously known as --mode disko
* -f, --flake uri
fetch the disko config relative to this flake's root
* --arg name value

View file

@ -444,6 +444,50 @@ let
];
in
lib.mapAttrs throwIfNoDisksDetected {
destroy = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-destroy" ''
export PATH=${lib.makeBinPath destroyDependencies}:$PATH
${cfg.config._destroy}
'';
format = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-format" ''
export PATH=${lib.makeBinPath (cfg.config._packages pkgs)}:$PATH
${cfg.config._create}
'';
mount = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-mount" ''
export PATH=${lib.makeBinPath (cfg.config._packages pkgs)}:$PATH
${cfg.config._mount}
'';
formatMount = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-format-mount" ''
export PATH=${lib.makeBinPath ((cfg.config._packages pkgs) ++ [ pkgs.bash ])}:$PATH
${cfg.config._formatMount}
'';
destroyFormatMount = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-destroy-format-mount" ''
export PATH=${lib.makeBinPath ((cfg.config._packages pkgs) ++ [ pkgs.bash ] ++ destroyDependencies)}:$PATH
${cfg.config._disko}
'';
# These are useful to skip copying executables uploading a script to an in-memory installer
destroyNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-destroy" ''
${cfg.config._destroy}
'';
formatNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-format" ''
${cfg.config._create}
'';
mountNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-mount" ''
${cfg.config._mount}
'';
formatMountNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-format-mount" ''
${cfg.config._formatMount}
'';
destroyFormatMountNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-destroy-format-mount" ''
${cfg.config._disko}
'';
# Legacy scripts, to be removed in version 2.0.0
# They are generally less useful, because the scripts are directly written to their $out path instead of
# into the $out/bin directory, which makes them incompatible with `nix run`
# (see https://github.com/nix-community/disko/pull/78), `lib.buildEnv` and thus `environment.systemPackages`,
# `user.users.<name>.packages` and `home.packages`, see https://github.com/nix-community/disko/issues/454
destroyScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-destroy" ''
export PATH=${lib.makeBinPath destroyDependencies}:$PATH
${cfg.config._destroy}
@ -549,6 +593,17 @@ let
${cfg.config._mount}
'';
};
_formatMount = lib.mkOption {
internal = true;
type = lib.types.str;
description = ''
The script to create and mount all devices defined by disko.devices, without wiping the disks first
'';
default = ''
${cfg.config._create}
${cfg.config._mount}
'';
};
_config = lib.mkOption {
internal = true;
description = ''

View file

@ -84,7 +84,7 @@ let
${lib.optionalString diskoCfg.testMode ''
export IN_DISKO_TEST=1
''}
${systemToInstall.config.system.build.diskoScript}
${lib.getExe systemToInstall.config.system.build.destroyFormatMount}
'';
installer = lib.optionalString cfg.copyNixStore ''

View file

@ -80,9 +80,9 @@ let
testConfigBooted = testLib.prepareDiskoConfig diskoConfigWithArgs testLib.devices;
tsp-generator = pkgs.callPackage ../. { checked = true; };
tsp-format = (tsp-generator.formatScript testConfigInstall) pkgs;
tsp-mount = (tsp-generator.mountScript testConfigInstall) pkgs;
tsp-disko = (tsp-generator.diskoScript testConfigInstall) pkgs;
tsp-format = (tsp-generator._cliFormat testConfigInstall) pkgs;
tsp-mount = (tsp-generator._cliMount testConfigInstall) pkgs;
tsp-disko = (tsp-generator._cliDestroyFormatMount testConfigInstall) pkgs;
tsp-config = tsp-generator.config testConfigBooted;
num-disks = builtins.length (lib.attrNames testConfigBooted.disko.devices.disk);
@ -260,24 +260,24 @@ let
machine.succeed("echo -n 'secretsecret' > /tmp/secret.key")
${lib.optionalString (testMode == "direct") ''
# running direct mode
machine.succeed("${tsp-format}")
machine.succeed("${tsp-mount}")
machine.succeed("${tsp-mount}") # verify that mount is idempotent
machine.succeed("${tsp-disko}") # verify that we can destroy and recreate
machine.succeed("${lib.getExe tsp-format}")
machine.succeed("${lib.getExe tsp-mount}")
machine.succeed("${lib.getExe tsp-mount}") # verify that mount is idempotent
machine.succeed("${lib.getExe tsp-disko}") # verify that we can destroy and recreate
machine.succeed("mkdir -p /mnt/home")
machine.succeed("touch /mnt/home/testfile")
machine.succeed("${tsp-format}") # verify that format is idempotent
machine.succeed("${lib.getExe tsp-format}") # verify that format is idempotent
machine.succeed("test -e /mnt/home/testfile")
''}
${lib.optionalString (testMode == "module") ''
# running module mode
machine.succeed("${nodes.machine.system.build.formatScript}")
machine.succeed("${nodes.machine.system.build.mountScript}")
machine.succeed("${nodes.machine.system.build.mountScript}") # verify that mount is idempotent
machine.succeed("${nodes.machine.system.build.diskoScript}") # verify that we can destroy and recreate again
machine.succeed("${lib.getExe nodes.machine.system.build.format}")
machine.succeed("${lib.getExe nodes.machine.system.build.mount}")
machine.succeed("${lib.getExe nodes.machine.system.build.mount}") # verify that mount is idempotent
machine.succeed("${lib.getExe nodes.machine.system.build.destroyFormatMount}") # verify that we can destroy and recreate again
machine.succeed("mkdir -p /mnt/home")
machine.succeed("touch /mnt/home/testfile")
machine.succeed("${nodes.machine.system.build.formatScript}") # verify that format is idempotent
machine.succeed("${lib.getExe nodes.machine.system.build.format}") # verify that format is idempotent
machine.succeed("test -e /mnt/home/testfile")
''}