diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md new file mode 100644 index 0000000..78a41fc --- /dev/null +++ b/BREAKING_CHANGES.md @@ -0,0 +1,3 @@ +2023-02-14 6d630b8 + +btrfs, btrfs_subvol filesystem and lvm_lv extraArgs are now lists diff --git a/default.nix b/default.nix index 33473bf..c352481 100644 --- a/default.nix +++ b/default.nix @@ -1,5 +1,6 @@ { lib ? import , rootMountPoint ? "/mnt" +, checked ? false }: let types = import ./types { inherit lib rootMountPoint; }; @@ -18,33 +19,27 @@ in { types = types; create = cfg: types.diskoLib.create (eval cfg).config.devices; - createScript = cfg: pkgs: pkgs.writeScript "disko-create" '' - #!/usr/bin/env bash + createScript = cfg: pkgs: (types.diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-create" '' export PATH=${lib.makeBinPath (types.diskoLib.packages (eval cfg).config.devices pkgs)}:$PATH ${types.diskoLib.create (eval cfg).config.devices} ''; - createScriptNoDeps = cfg: pkgs: pkgs.writeScript "disko-create" '' - #!/usr/bin/env bash + createScriptNoDeps = cfg: pkgs: (types.diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-create" '' ${types.diskoLib.create (eval cfg).config.devices} ''; mount = cfg: types.diskoLib.mount (eval cfg).config.devices; - mountScript = cfg: pkgs: pkgs.writeScript "disko-mount" '' - #!/usr/bin/env bash + mountScript = cfg: pkgs: (types.diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-mount" '' export PATH=${lib.makeBinPath (types.diskoLib.packages (eval cfg).config.devices pkgs)}:$PATH ${types.diskoLib.mount (eval cfg).config.devices} ''; - mountScriptNoDeps = cfg: pkgs: pkgs.writeScript "disko-mount" '' - #!/usr/bin/env bash + mountScriptNoDeps = cfg: pkgs: (types.diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-mount" '' ${types.diskoLib.mount (eval cfg).config.devices} ''; zapCreateMount = cfg: types.diskoLib.zapCreateMount (eval cfg).config.devices; - zapCreateMountScript = cfg: pkgs: pkgs.writeScript "disko-zap-create-mount" '' - #!/usr/bin/env bash + zapCreateMountScript = cfg: pkgs: (types.diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-zap-create-mount" '' export PATH=${lib.makeBinPath (types.diskoLib.packages (eval cfg).config.devices pkgs)}:$PATH ${types.diskoLib.zapCreateMount (eval cfg).config.devices} ''; - zapCreateMountScriptNoDeps = cfg: pkgs: pkgs.writeScript "disko-zap-create-mount" '' - #!/usr/bin/env bash + zapCreateMountScriptNoDeps = cfg: pkgs: (types.diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-zap-create-mount" '' ${types.diskoLib.zapCreateMount (eval cfg).config.devices} ''; config = cfg: { imports = types.diskoLib.config (eval cfg).config.devices; }; diff --git a/example/btrfs-subvolumes.nix b/example/btrfs-subvolumes.nix index a6d8088..a574570 100644 --- a/example/btrfs-subvolumes.nix +++ b/example/btrfs-subvolumes.nix @@ -27,7 +27,7 @@ end = "100%"; content = { type = "btrfs"; - extraArgs = "-f"; # Override existing partition + extraArgs = [ "-f" ]; # Override existing partition subvolumes = { # Subvolume name is different from mountpoint "/rootfs" = { diff --git a/module.nix b/module.nix index 820d985..afdd315 100644 --- a/module.nix +++ b/module.nix @@ -5,6 +5,7 @@ let rootMountPoint = config.disko.rootMountPoint; }; cfg = config.disko; + checked = cfg.checkScripts; in { options.disko = { @@ -27,26 +28,32 @@ in type = lib.types.bool; default = true; }; + checkScripts = lib.mkOption { + description = '' + Whether to run shellcheck on script outputs + ''; + type = lib.types.bool; + default = false; + }; }; config = lib.mkIf (cfg.devices.disk != { }) { - system.build.formatScript = pkgs.writers.writeBash "disko-create" '' + system.build.formatScript = (types.diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-create" '' export PATH=${lib.makeBinPath (types.diskoLib.packages cfg.devices pkgs)}:$PATH ${types.diskoLib.create cfg.devices} ''; - system.build.mountScript = pkgs.writers.writeBash "disko-mount" '' + system.build.mountScript = (types.diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-mount" '' export PATH=${lib.makeBinPath (types.diskoLib.packages cfg.devices pkgs)}:$PATH ${types.diskoLib.mount cfg.devices} ''; - system.build.disko = pkgs.writers.writeBash "disko" '' + system.build.disko = (types.diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko" '' export PATH=${lib.makeBinPath (types.diskoLib.packages cfg.devices pkgs)}:$PATH ${types.diskoLib.zapCreateMount cfg.devices} ''; # This is useful to skip copying executables uploading a script to an in-memory installer - system.build.diskoNoDeps = pkgs.writeScript "disko" '' - #!/usr/bin/env bash + system.build.diskoNoDeps = (types.diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko" '' ${types.diskoLib.zapCreateMount cfg.devices} ''; diff --git a/tests/default.nix b/tests/default.nix index 1efc16c..3a9e072 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -11,8 +11,8 @@ let disko-config = import configFile; in { - "${name}-tsp-create" = pkgs.writeScript "create" ((pkgs.callPackage ../. { }).create disko-config); - "${name}-tsp-mount" = pkgs.writeScript "mount" ((pkgs.callPackage ../. { }).mount disko-config); + "${name}-tsp-create" = (pkgs.callPackage ../. { checked = true; }).createScript disko-config pkgs; + "${name}-tsp-mount" = (pkgs.callPackage ../. { checked = true; }).mountScript disko-config pkgs; }; allTestFilenames = diff --git a/tests/lib.nix b/tests/lib.nix index 43b6607..c3d8957 100644 --- a/tests/lib.nix +++ b/tests/lib.nix @@ -24,10 +24,11 @@ inherit (pkgs) system; }; disks = [ "/dev/vda" "/dev/vdb" "/dev/vdc" "/dev/vdd" "/dev/vde" "/dev/vdf" ]; - tsp-create = pkgs.writeScript "create" ((pkgs.callPackage ../. { }).create (import disko-config { disks = builtins.tail disks; inherit lib; })); - tsp-mount = pkgs.writeScript "mount" ((pkgs.callPackage ../. { }).mount (import disko-config { disks = builtins.tail disks; inherit lib; })); - tsp-config = (pkgs.callPackage ../. { }).config (import disko-config { inherit disks; inherit lib; }); - tsp-disko = pkgs.writeScript "disko" ((pkgs.callPackage ../. { }).zapCreateMount (import disko-config { disks = builtins.tail disks; inherit lib; })); + tsp-generator = pkgs.callPackage ../. { checked = true; }; + tsp-create = (tsp-generator.createScript (import disko-config { disks = builtins.tail disks; inherit lib; })) pkgs; + tsp-mount = (tsp-generator.mountScript (import disko-config { disks = builtins.tail disks; inherit lib; })) pkgs; + tsp-disko = (tsp-generator.zapCreateMountScript (import disko-config { disks = builtins.tail disks; inherit lib; })) pkgs; + tsp-config = tsp-generator.config (import disko-config { inherit disks; inherit lib; }); num-disks = builtins.length (lib.attrNames (import disko-config { inherit lib; }).disk); installed-system = { modulesPath, ... }: { imports = [ @@ -78,14 +79,15 @@ imports = [ ../module.nix ]; disko = { enableConfig = false; + checkScripts = true; devices = import disko-config { disks = builtins.tail disks; inherit lib; }; }; }) (lib.optionalAttrs (testMode == "cli") { imports = [ (modulesPath + "/installer/cd-dvd/channel.nix") ]; system.extraDependencies = [ - ((pkgs.callPackage ../. { }).createScript (import disko-config { disks = builtins.tail disks; inherit lib; }) pkgs) - ((pkgs.callPackage ../. { }).mountScript (import disko-config { disks = builtins.tail disks; inherit lib; }) pkgs) + ((pkgs.callPackage ../. { checked = true; }).createScript (import disko-config { disks = builtins.tail disks; inherit lib; }) pkgs) + ((pkgs.callPackage ../. { checked = true; }).mountScript (import disko-config { disks = builtins.tail disks; inherit lib; }) pkgs) ]; }) (modulesPath + "/profiles/base.nix") diff --git a/types/btrfs.nix b/types/btrfs.nix index 9473db7..ce212cd 100644 --- a/types/btrfs.nix +++ b/types/btrfs.nix @@ -7,9 +7,9 @@ description = "Type"; }; extraArgs = lib.mkOption { - type = lib.types.str; - default = ""; - description = "Arguments to pass to BTRFS"; + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Extra arguments"; }; mountOptions = lib.mkOption { type = lib.types.listOf lib.types.str; @@ -37,7 +37,7 @@ _create = diskoLib.mkCreateOption { inherit config options; default = { dev }: '' - mkfs.btrfs ${dev} ${config.extraArgs} + mkfs.btrfs ${dev} ${toString config.extraArgs} ${lib.concatMapStrings (subvol: subvol._create { inherit dev; }) (lib.attrValues config.subvolumes)} ''; }; diff --git a/types/btrfs_subvol.nix b/types/btrfs_subvol.nix index 699d3e8..caba3fe 100644 --- a/types/btrfs_subvol.nix +++ b/types/btrfs_subvol.nix @@ -13,9 +13,9 @@ description = "Type"; }; extraArgs = lib.mkOption { - type = lib.types.str; - default = ""; - description = "Extra arguments to pass"; + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Extra arguments"; }; mountOptions = lib.mkOption { type = lib.types.listOf lib.types.str; @@ -41,7 +41,7 @@ ( mount ${dev} "$MNTPOINT" -o subvol=/ trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT - btrfs subvolume create "$MNTPOINT"/${config.name} ${config.extraArgs} + btrfs subvolume create "$MNTPOINT"/${config.name} ${toString config.extraArgs} ) ''; }; diff --git a/types/default.nix b/types/default.nix index 2c967f6..f0e1909 100644 --- a/types/default.nix +++ b/types/default.nix @@ -193,6 +193,15 @@ rec { description = "Mount script"; }; + /* Writer for optionally checking bash scripts before writing them to the store + + writeCheckedBash :: AttrSet -> str -> str -> derivation + */ + writeCheckedBash = { pkgs, checked ? false, noDeps ? false }: pkgs.writers.makeScriptWriter { + interpreter = if noDeps then "/usr/bin/env bash" else "${pkgs.bash}/bin/bash"; + check = lib.optionalString checked "${pkgs.shellcheck}/bin/shellcheck -e SC2034"; + }; + /* Takes a disko device specification, returns an attrset with metadata @@ -243,6 +252,7 @@ rec { 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 diff --git a/types/filesystem.nix b/types/filesystem.nix index c9a3319..93d0cac 100644 --- a/types/filesystem.nix +++ b/types/filesystem.nix @@ -7,9 +7,9 @@ description = "Type"; }; extraArgs = lib.mkOption { - type = lib.types.str; - default = ""; - description = "Arguments to pass"; + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Extra arguments"; }; mountOptions = lib.mkOption { type = lib.types.listOf lib.types.str; @@ -35,7 +35,7 @@ inherit config options; default = { dev }: '' mkfs.${config.format} \ - ${config.extraArgs} \ + ${toString config.extraArgs} \ ${dev} ''; }; diff --git a/types/lvm_lv.nix b/types/lvm_lv.nix index 7ffa268..d2df6fc 100644 --- a/types/lvm_lv.nix +++ b/types/lvm_lv.nix @@ -22,8 +22,8 @@ description = "LVM type"; }; extraArgs = lib.mkOption { - type = lib.types.str; - default = ""; + type = lib.types.listOf lib.types.str; + default = [ ]; description = "Extra arguments"; }; content = diskoLib.partitionType; @@ -43,7 +43,7 @@ ${if lib.hasInfix "%" config.size then "-l" else "-L"} ${config.size} \ -n ${config.name} \ ${lib.optionalString (config.lvm_type != null) "--type=${config.lvm_type}"} \ - ${config.extraArgs} \ + ${toString config.extraArgs} \ ${vg} ${lib.optionalString (config.content != null) (config.content._create {dev = "/dev/${vg}/${config.name}";})} ''; diff --git a/types/lvm_pv.nix b/types/lvm_pv.nix index 03a95c7..1bf1c10 100644 --- a/types/lvm_pv.nix +++ b/types/lvm_pv.nix @@ -23,7 +23,7 @@ inherit config options; default = { dev }: '' pvcreate ${dev} - echo "${dev}" >> $disko_devices_dir/lvm_${config.vg} + echo "${dev}" >> "$disko_devices_dir"/lvm_${config.vg} ''; }; _mount = diskoLib.mkMountOption { diff --git a/types/lvm_vg.nix b/types/lvm_vg.nix index ba313e1..ac7c2fa 100644 --- a/types/lvm_vg.nix +++ b/types/lvm_vg.nix @@ -27,7 +27,9 @@ _create = diskoLib.mkCreateOption { inherit config options; default = _: '' - vgcreate ${config.name} $(tr '\n' ' ' < $disko_devices_dir/lvm_${config.name}) + readarray -t lvm_devices < <(cat "$disko_devices_dir"/lvm_${config.name}) + vgcreate ${config.name} \ + "''${lvm_devices[@]}" ${lib.concatMapStrings (lv: lv._create {vg = config.name; }) (lib.attrValues config.lvs)} ''; }; diff --git a/types/mdadm.nix b/types/mdadm.nix index d2b3937..5d1f043 100644 --- a/types/mdadm.nix +++ b/types/mdadm.nix @@ -34,13 +34,14 @@ _create = diskoLib.mkCreateOption { inherit config options; default = _: '' + readarray -t disk_devices < <(cat "$disko_devices_dir"/raid_${config.name}) echo 'y' | mdadm --create /dev/md/${config.name} \ --level=${toString config.level} \ - --raid-devices=$(wc -l $disko_devices_dir/raid_${config.name} | cut -f 1 -d " ") \ + --raid-devices="$(wc -l "$disko_devices_dir"/raid_${config.name} | cut -f 1 -d " ")" \ --metadata=${config.metadata} \ --force \ --homehost=any \ - $(tr '\n' ' ' < $disko_devices_dir/raid_${config.name}) + "''${disk_devices[@]}" udevadm trigger --subsystem-match=block; udevadm settle ${lib.optionalString (config.content != null) (config.content._create {dev = "/dev/md/${config.name}";})} ''; diff --git a/types/mdraid.nix b/types/mdraid.nix index 6eb24bc..52b7b03 100644 --- a/types/mdraid.nix +++ b/types/mdraid.nix @@ -23,7 +23,7 @@ _create = diskoLib.mkCreateOption { inherit config options; default = { dev }: '' - echo "${dev}" >> $disko_devices_dir/raid_${config.name} + echo "${dev}" >> "$disko_devices_dir"/raid_${config.name} ''; }; _mount = diskoLib.mkMountOption { diff --git a/types/zfs.nix b/types/zfs.nix index b30ad44..26e53ab 100644 --- a/types/zfs.nix +++ b/types/zfs.nix @@ -22,7 +22,7 @@ _create = diskoLib.mkCreateOption { inherit config options; default = { dev }: '' - echo "${dev}" >> $disko_devices_dir/zfs_${config.pool} + echo "${dev}" >> "$disko_devices_dir"/zfs_${config.pool} ''; }; _mount = diskoLib.mkMountOption { diff --git a/types/zpool.nix b/types/zpool.nix index de2b70d..0a7e66a 100644 --- a/types/zpool.nix +++ b/types/zpool.nix @@ -52,11 +52,12 @@ _create = diskoLib.mkCreateOption { inherit config options; default = _: '' + readarray -t zfs_devices < <(cat "$disko_devices_dir"/zfs_${config.name}) zpool create ${config.name} \ ${config.mode} \ ${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "-o ${n}=${v}") config.options)} \ ${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "-O ${n}=${v}") config.rootFsOptions)} \ - $(tr '\n' ' ' < $disko_devices_dir/zfs_${config.name}) + "''${zfs_devices[@]}" ${lib.concatMapStrings (dataset: dataset._create {zpool = config.name;}) (lib.attrValues config.datasets)} ''; };