diff --git a/lib/types/btrfs.nix b/lib/types/btrfs.nix index 92b5e6d..b87c85f 100644 --- a/lib/types/btrfs.nix +++ b/lib/types/btrfs.nix @@ -17,7 +17,36 @@ description = "A list of options to pass to mount."; }; subvolumes = lib.mkOption { - type = lib.types.attrsOf diskoLib.types.btrfs_subvol; + type = lib.types.attrsOf (lib.types.submodule ({ config, ... }: { + options = { + name = lib.mkOption { + type = lib.types.str; + default = config._module.args.name; + description = "Name of the BTRFS subvolume."; + }; + type = lib.mkOption { + type = lib.types.enum [ "btrfs_subvol" ]; + default = "btrfs_subvol"; + internal = true; + description = "Type"; + }; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Extra arguments"; + }; + mountOptions = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ "defaults" ]; + description = "Options to pass to mount"; + }; + mountpoint = lib.mkOption { + type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname; + default = null; + description = "Location to mount the subvolume to."; + }; + }; + })); default = { }; description = "Subvolumes to define for BTRFS."; }; @@ -30,22 +59,46 @@ internal = true; readOnly = true; type = lib.types.functionTo diskoLib.jsonType; - default = dev: - diskoLib.deepMergeMap (subvol: subvol._meta dev) (lib.attrValues config.subvolumes); + default = dev: { }; description = "Metadata"; }; _create = diskoLib.mkCreateOption { inherit config options; default = { dev }: '' mkfs.btrfs ${dev} ${toString config.extraArgs} - ${lib.concatMapStrings (subvol: subvol._create { inherit dev; }) (lib.attrValues config.subvolumes)} + ${lib.concatMapStrings (subvol: '' + MNTPOINT=$(mktemp -d) + ( + mount ${dev} "$MNTPOINT" -o subvol=/ + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume create "$MNTPOINT"/${subvol.name} ${toString subvol.extraArgs} + ) + '') (lib.attrValues config.subvolumes)} ''; }; _mount = diskoLib.mkMountOption { inherit config options; default = { dev }: let - subvolMounts = diskoLib.deepMergeMap (subvol: subvol._mount { inherit dev; parent = config.mountpoint; }) (lib.attrValues config.subvolumes); + subvolMounts = lib.concatMapAttrs + (_: subvol: + let + mountpoint = + if (subvol.mountpoint != null) then subvol.mountpoint + else if (config.mountpoint == null) then subvol.name + else null; + in + lib.optionalAttrs (mountpoint != null) { + fs.${mountpoint} = '' + if ! findmnt ${dev} "${rootMountPoint}${mountpoint}" > /dev/null 2>&1; then + mount ${dev} "${rootMountPoint}${mountpoint}" \ + ${lib.concatMapStringsSep " " (opt: "-o ${opt}") (subvol.mountOptions ++ [ "subvol=${subvol.name}" ])} \ + -o X-mount.mkdir + fi + ''; + } + ) + config.subvolumes; in { fs = subvolMounts.fs // lib.optionalAttrs (config.mountpoint != null) { @@ -63,7 +116,23 @@ internal = true; readOnly = true; default = dev: [ - (map (subvol: subvol._config dev config.mountpoint) (lib.attrValues config.subvolumes)) + (map + (subvol: + let + mountpoint = + if (subvol.mountpoint != null) then subvol.mountpoint + else if (config.mountpoint == null) then subvol.name + else null; + in + lib.optional (mountpoint != null) { + fileSystems.${mountpoint} = { + device = dev; + fsType = "btrfs"; + options = subvol.mountOptions ++ [ "subvol=${subvol.name}" ]; + }; + } + ) + (lib.attrValues config.subvolumes)) (lib.optional (config.mountpoint != null) { fileSystems.${config.mountpoint} = { device = dev; @@ -79,7 +148,7 @@ readOnly = true; type = lib.types.functionTo (lib.types.listOf lib.types.package); default = pkgs: - [ pkgs.btrfs-progs ] ++ lib.flatten (map (subvolume: subvolume._pkgs pkgs) (lib.attrValues config.subvolumes)); + [ pkgs.btrfs-progs pkgs.coreutils ]; description = "Packages"; }; }; diff --git a/lib/types/btrfs_subvol.nix b/lib/types/btrfs_subvol.nix deleted file mode 100644 index 461f5a2..0000000 --- a/lib/types/btrfs_subvol.nix +++ /dev/null @@ -1,94 +0,0 @@ -{ config, options, diskoLib, lib, rootMountPoint, ... }: -{ - options = { - name = lib.mkOption { - type = lib.types.str; - default = config._module.args.name; - description = "Name of the BTRFS subvolume."; - }; - type = lib.mkOption { - type = lib.types.enum [ "btrfs_subvol" ]; - default = "btrfs_subvol"; - internal = true; - description = "Type"; - }; - extraArgs = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ ]; - description = "Extra arguments"; - }; - mountOptions = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ "defaults" ]; - description = "Options to pass to mount"; - }; - mountpoint = lib.mkOption { - type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname; - default = null; - description = "Location to mount the subvolume to."; - }; - _meta = lib.mkOption { - internal = true; - readOnly = true; - type = lib.types.functionTo diskoLib.jsonType; - default = dev: { }; - description = "Metadata"; - }; - _create = diskoLib.mkCreateOption { - inherit config options; - default = { dev }: '' - MNTPOINT=$(mktemp -d) - ( - mount ${dev} "$MNTPOINT" -o subvol=/ - trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT - btrfs subvolume create "$MNTPOINT"/${config.name} ${toString config.extraArgs} - ) - ''; - }; - _mount = diskoLib.mkMountOption { - inherit config options; - default = { dev, parent }: - let - mountpoint = - if (config.mountpoint != null) then config.mountpoint - else if (parent == null) then config.name - else null; - in - lib.optionalAttrs (mountpoint != null) { - fs.${mountpoint} = '' - if ! findmnt ${dev} "${rootMountPoint}${mountpoint}" > /dev/null 2>&1; then - mount ${dev} "${rootMountPoint}${mountpoint}" \ - ${lib.concatMapStringsSep " " (opt: "-o ${opt}") (config.mountOptions ++ [ "subvol=${config.name}" ])} \ - -o X-mount.mkdir - fi - ''; - }; - }; - _config = lib.mkOption { - internal = true; - readOnly = true; - default = dev: parent: - let - mountpoint = - if (config.mountpoint != null) then config.mountpoint - else if (parent == null) then config.name - else null; - in - lib.optional (mountpoint != null) { - fileSystems.${mountpoint} = { - device = dev; - fsType = "btrfs"; - options = config.mountOptions ++ [ "subvol=${config.name}" ]; - }; - }; - description = "NixOS configuration"; - }; - _pkgs = lib.mkOption { - internal = true; - readOnly = true; - type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = pkgs: [ pkgs.coreutils ]; - description = "Packages"; - }; - }; -}