From daca7be3092f253e5a3c9ce059d5a0225de6902d Mon Sep 17 00:00:00 2001 From: Felix Uhl Date: Fri, 18 Oct 2024 22:57:34 +0200 Subject: [PATCH] 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. --- README.md | 2 +- cli.nix | 20 ++++++++++----- default.nix | 17 ++++++++++++- disko | 22 ++++++++++++----- docs/quickstart.md | 2 +- docs/reference.md | 10 +++++--- lib/default.nix | 55 +++++++++++++++++++++++++++++++++++++++++ lib/make-disk-image.nix | 2 +- lib/tests.nix | 26 +++++++++---------- 9 files changed, 123 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 9e4f127..88a4f66 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/cli.nix b/cli.nix index 3203ced..e66b470 100644 --- a/cli.nix +++ b/cli.nix @@ -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}; diff --git a/default.nix b/default.nix index bf3570e..2b4f1a8 100644 --- a/default.nix +++ b/default.nix @@ -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; diff --git a/disko b/disko index 4ef771a..28a79e5 100755 --- a/disko +++ b/disko @@ -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 diff --git a/docs/quickstart.md b/docs/quickstart.md index 30d0c89..e511ee8 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -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 diff --git a/docs/reference.md b/docs/reference.md index 104ba1d..bb1a0ba 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -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 diff --git a/lib/default.nix b/lib/default.nix index 7cd6ef9..78dcb95 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -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..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 = '' diff --git a/lib/make-disk-image.nix b/lib/make-disk-image.nix index 7343232..55d7d25 100644 --- a/lib/make-disk-image.nix +++ b/lib/make-disk-image.nix @@ -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 '' diff --git a/lib/tests.nix b/lib/tests.nix index fd24a80..5160cff 100644 --- a/lib/tests.nix +++ b/lib/tests.nix @@ -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") ''}