diff --git a/default.nix b/default.nix index 0e958dd..54c854e 100644 --- a/default.nix +++ b/default.nix @@ -10,7 +10,7 @@ let imports = lib.singleton { disko.devices = cfg.disko.devices; }; options = { disko.devices = lib.mkOption { - type = diskoLib.devices; + type = diskoLib.toplevel; }; }; }; diff --git a/doc.nix b/doc.nix index 745686a..d07f8f3 100644 --- a/doc.nix +++ b/doc.nix @@ -10,7 +10,7 @@ let { options.disko = { devices = lib.mkOption { - type = diskoLib.devices; + type = diskoLib.toplevel; default = { }; description = "The devices to set up"; }; diff --git a/lib/default.nix b/lib/default.nix index 75e35ae..5a1f4a0 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -250,71 +250,39 @@ let meta :: lib.types.devices -> AttrSet */ - meta = devices: diskoLib.deepMergeMap (dev: dev._meta) (flatten (map attrValues (attrValues devices))); + meta = toplevel: toplevel._meta; /* Takes a disko device specification and returns a string which formats the disks create :: lib.types.devices -> str */ - create = devices: - let - sortedDeviceList = diskoLib.sortDevicesByDependencies ((diskoLib.meta devices).deviceDependencies or { }) devices; - in - '' - set -efux - - disko_devices_dir=$(mktemp -d) - trap 'rm -rf "$disko_devices_dir"' EXIT - mkdir -p "$disko_devices_dir" - - ${concatMapStrings (dev: (attrByPath (dev ++ [ "_create" ]) "" devices)) sortedDeviceList} - ''; + create = toplevel: toplevel._create; /* Takes a disko device specification and returns a string which mounts the disks mount :: lib.types.devices -> str */ - mount = devices: - let - fsMounts = diskoLib.deepMergeMap (dev: dev._mount.fs or { }) (flatten (map attrValues (attrValues devices))); - sortedDeviceList = diskoLib.sortDevicesByDependencies ((diskoLib.meta devices).deviceDependencies or { }) devices; - in - '' - set -efux - # first create the necessary devices - ${concatMapStrings (dev: ((attrByPath (dev ++ [ "_mount" ]) {} devices)).dev or "") sortedDeviceList} - - # and then mount the filesystems in alphabetical order - ${concatStrings (attrValues fsMounts)} - ''; + mount = toplevel: toplevel._mount; /* takes a disko device specification and returns a string which unmounts, destroys all disks and then runs create and mount zapCreateMount :: lib.types.devices -> str */ - zapCreateMount = devices: '' + zapCreateMount = toplevel: + '' set -efux - umount -Rv "${rootMountPoint}" || : - - # shellcheck disable=SC2043 - for dev in ${toString (lib.catAttrs "device" (lib.attrValues devices.disk))}; do - ${../disk-deactivate}/disk-deactivate "$dev" | bash -x - done - - echo 'creating partitions...' - ${diskoLib.create devices} - echo 'mounting partitions...' - ${diskoLib.mount devices} + ${toplevel._disko} ''; /* Takes a disko device specification and returns a nixos configuration config :: lib.types.devices -> nixosConfig */ - config = devices: flatten (map (dev: dev._config) (flatten (map attrValues (attrValues devices)))); + config = toplevel: toplevel._config; + /* Takes a disko device specification and returns a function to get the needed packages to format/mount the disks packages :: lib.types.devices -> pkgs -> [ derivation ] */ - packages = devices: pkgs: unique (flatten (map (dev: dev._pkgs pkgs) (flatten (map attrValues (attrValues devices))))); + packages = toplevel: toplevel._packages; optionTypes = rec { filename = lib.mkOptionType { @@ -348,7 +316,9 @@ let /* topLevel type of the disko config, takes attrsets of disks, mdadms, zpools, nodevs, and lvm vgs. */ - devices = lib.types.submodule { + toplevel = lib.types.submodule (cfg: let + devices = { inherit (cfg.config) disk mdadm zpool lvm_vg nodev; }; + in { options = { disk = lib.mkOption { type = lib.types.attrsOf diskoLib.types.disk; @@ -375,8 +345,149 @@ let default = { }; description = "A non-block device"; }; + _meta = lib.mkOption { + internal = true; + description = '' + meta informationen generated by disko + currently used for building a dependency list so we know in which order to create the devices + ''; + default = diskoLib.deepMergeMap (dev: dev._meta) (flatten (map attrValues (attrValues devices))); + }; + _packages = lib.mkOption { + internal = true; + description = '' + packages required by the disko configuration + ''; + default = pkgs: unique (flatten (map (dev: dev._pkgs pkgs) (flatten (map attrValues (attrValues devices))))); + }; + _scripts = lib.mkOption { + internal = true; + description = '' + The scripts generated by disko + ''; + default = { pkgs, checked ? false }: { + umountScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-umount" '' + export PATH=${lib.makeBinPath (with pkgs; [ + util-linux + e2fsprogs + mdadm + zfs + lvm2 + ])}:$PATH + ${cfg.config._umount} + ''; + + formatScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-format" '' + export PATH=${lib.makeBinPath (cfg.config._packages pkgs)}:$PATH + ${cfg.config._create} + ''; + + mountScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-mount" '' + export PATH=${lib.makeBinPath (cfg.config._packages pkgs)}:$PATH + ${cfg.config._mount} + ''; + + diskoScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko" '' + export PATH=${lib.makeBinPath ((cfg.config._packages pkgs) ++ [ pkgs.bash ])}:$PATH + ${cfg.config._disko} + ''; + + # These are useful to skip copying executables uploading a script to an in-memory installer + umountScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-umount" '' + ${cfg.config._umount} + ''; + + formatScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-format" '' + ${cfg.config._create} + ''; + + system.build.mountScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-mount" '' + ${cfg.config._mount} + ''; + + diskoScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko" '' + ${cfg.config._disko} + ''; + }; + }; + _umount = lib.mkOption { + internal = true; + type = lib.types.str; + description = '' + The script to unmount (& destroy) all devices defined by disko.devices + ''; + default = '' + umount -Rv "${rootMountPoint}" || : + + # shellcheck disable=SC2043 + for dev in ${toString (lib.catAttrs "device" (lib.attrValues devices.disk))}; do + ${../disk-deactivate}/disk-deactivate "$dev" | bash -x + done + ''; + }; + _create = lib.mkOption { + internal = true; + type = lib.types.str; + description = '' + The script to create all devices defined by disko.devices + ''; + default = let + sortedDeviceList = diskoLib.sortDevicesByDependencies (cfg.config._meta.deviceDependencies or { }) devices; + in + '' + set -efux + + disko_devices_dir=$(mktemp -d) + trap 'rm -rf "$disko_devices_dir"' EXIT + mkdir -p "$disko_devices_dir" + + ${concatMapStrings (dev: (attrByPath (dev ++ [ "_create" ]) {} devices)) sortedDeviceList} + ''; + }; + _mount = lib.mkOption { + internal = true; + type = lib.types.str; + description = '' + The script to mount all devices defined by disko.devices + ''; + default = let + fsMounts = diskoLib.deepMergeMap (dev: dev._mount.fs or { }) (flatten (map attrValues (attrValues devices))); + sortedDeviceList = diskoLib.sortDevicesByDependencies (cfg.config._meta.deviceDependencies or { }) devices; + in '' + set -efux + # first create the necessary devices + ${concatMapStrings (dev: ((attrByPath (dev ++ [ "_mount" ]) {} devices)).dev or "") sortedDeviceList} + + # and then mount the filesystems in alphabetical order + ${concatStrings (attrValues fsMounts)} + ''; + }; + _disko = lib.mkOption { + internal = true; + type = lib.types.str; + description = '' + The script to umount, create and mount all devices defined by disko.devices + ''; + default = '' + ${cfg.config._umount} + ${cfg.config._create} + ${cfg.config._mount} + ''; + }; + _config = lib.mkOption { + internal = true; + description = '' + The NixOS config generated by disko + ''; + default = + let + configKeys = flatten (map attrNames (flatten (map (dev: dev._config) (flatten (map attrValues (attrValues devices)))))); + collectedConfigs = flatten (map (dev: dev._config) (flatten (map attrValues (attrValues devices)))); + in + lib.genAttrs configKeys (key: lib.mkMerge (lib.catAttrs key collectedConfigs)); + }; }; - }; + }); # import all tge types from the types directory types = lib.listToAttrs ( diff --git a/module.nix b/module.nix index f9b9c23..ccece50 100644 --- a/module.nix +++ b/module.nix @@ -5,12 +5,11 @@ let rootMountPoint = config.disko.rootMountPoint; }; cfg = config.disko; - checked = cfg.checkScripts; in { options.disko = { devices = lib.mkOption { - type = diskoLib.devices; + type = diskoLib.toplevel; default = { }; description = "The devices to set up"; }; @@ -37,43 +36,18 @@ in }; }; config = lib.mkIf (cfg.devices.disk != { }) { - system.build.formatScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-create" '' - export PATH=${lib.makeBinPath (diskoLib.packages cfg.devices pkgs)}:$PATH - ${diskoLib.create cfg.devices} - ''; + system.build = (cfg.devices._scripts { inherit pkgs; checked = cfg.checkScripts; }) // { - system.build.mountScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-mount" '' - export PATH=${lib.makeBinPath (diskoLib.packages cfg.devices pkgs)}:$PATH - ${diskoLib.mount cfg.devices} - ''; + # we keep this old outputs for compatibility + disko = builtins.trace "the .disko output is deprecated, plase use .diskoScript instead" cfg.devices._scripts.diskoScript; + diskoNoDeps = builtins.trace "the .diskoNoDeps output is deprecated, plase use .diskoScriptNoDeps instead" cfg.devices._scripts.diskoScriptNoDeps; + }; - # we keep this old output for compatibility - system.build.disko = builtins.trace "the .disko output is deprecated, plase use .diskoScript instead" config.system.build.diskoScript; - - system.build.diskoScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko" '' - export PATH=${lib.makeBinPath ((diskoLib.packages cfg.devices pkgs) ++ [ pkgs.bash ])}:$PATH - ${diskoLib.zapCreateMount cfg.devices} - ''; - - # These are useful to skip copying executables uploading a script to an in-memory installer - system.build.formatScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-create" '' - ${diskoLib.create cfg.devices} - ''; - - system.build.mountScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-mount" '' - ${diskoLib.mount cfg.devices} - ''; - - # we keep this old output for compatibility - system.build.diskoNoDeps = builtins.trace "the .diskoNoDeps output is deprecated, plase use .diskoScriptNoDeps instead" config.system.build.diskoScriptNoDeps; - - system.build.diskoScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko" '' - ${diskoLib.zapCreateMount cfg.devices} - ''; + # we need to specify the keys here, so we don't get an infinite recursion error # Remember to add config keys here if they are added to types - fileSystems = lib.mkIf cfg.enableConfig (lib.mkMerge (lib.catAttrs "fileSystems" (diskoLib.config cfg.devices))); - boot = lib.mkIf cfg.enableConfig (lib.mkMerge (lib.catAttrs "boot" (diskoLib.config cfg.devices))); - swapDevices = lib.mkIf cfg.enableConfig (lib.mkMerge (lib.catAttrs "swapDevices" (diskoLib.config cfg.devices))); + fileSystems = lib.mkIf cfg.enableConfig cfg.devices._config.fileSystems or {}; + boot = lib.mkIf cfg.enableConfig cfg.devices._config.boot or {}; + swapDevices = lib.mkIf cfg.enableConfig cfg.devices._config.swapDevices or []; }; }