From 9f97bd0995b9bcee01b35dab6ba64ca6c1eb8caf Mon Sep 17 00:00:00 2001 From: Felix Uhl Date: Wed, 13 Nov 2024 00:08:21 +0100 Subject: [PATCH] lib: Fix jsonTypes evaluation This will be very useful for generating documentation. Backported from a5c646bd93c956d41d532dce4c8ff95573c3d2a0 for #789 --- flake.nix | 12 ++++--- lib/default.nix | 78 ++++++++++++++++++++++++++++++++++----------- lib/types/gpt.nix | 18 +++++++++++ lib/types/luks.nix | 2 ++ lib/types/table.nix | 2 ++ 5 files changed, 90 insertions(+), 22 deletions(-) diff --git a/flake.nix b/flake.nix index 501218b6..da3bfcba 100644 --- a/flake.nix +++ b/flake.nix @@ -19,13 +19,15 @@ versionInfo = import ./version.nix; version = versionInfo.version + (lib.optionalString (!versionInfo.released) "-dirty"); + + diskoLib = import ./lib { + inherit (nixpkgs) lib; + }; in { nixosModules.default = self.nixosModules.disko; # convention nixosModules.disko.imports = [ ./module.nix ]; - lib = import ./lib { - inherit (nixpkgs) lib; - }; + lib = diskoLib; packages = forAllSystems (system: let pkgs = nixpkgs.legacyPackages.${system}; @@ -64,11 +66,13 @@ shellcheck disk-deactivate/disk-deactivate disko touch $out ''; + + jsonTypes = pkgs.writeTextFile { name = "jsonTypes"; text = (builtins.toJSON diskoLib.jsonTypes); }; in # FIXME: aarch64-linux seems to hang on boot lib.optionalAttrs pkgs.stdenv.hostPlatform.isx86_64 (nixosTests // { inherit disko-install; }) // pkgs.lib.optionalAttrs (!pkgs.stdenv.buildPlatform.isRiscV64 && !pkgs.stdenv.hostPlatform.isx86_32) { - inherit shellcheck; + inherit shellcheck jsonTypes; inherit (self.packages.${system}) disko-doc; }); diff --git a/lib/default.nix b/lib/default.nix index ed88ec3b..d7c578df 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -23,9 +23,10 @@ let }; # option for valid contents of partitions (basically like devices, but without tables) + _partitionTypes = { inherit (diskoLib.types) btrfs filesystem zfs mdraid luks lvm_pv swap; }; partitionType = extraArgs: lib.mkOption { type = lib.types.nullOr (diskoLib.subType { - types = { inherit (diskoLib.types) btrfs filesystem zfs mdraid luks lvm_pv swap; }; + types = diskoLib._partitionTypes; inherit extraArgs; }); default = null; @@ -33,9 +34,10 @@ let }; # option for valid contents of devices + _deviceTypes = { inherit (diskoLib.types) table gpt btrfs filesystem zfs mdraid luks lvm_pv swap; }; deviceType = extraArgs: lib.mkOption { type = lib.types.nullOr (diskoLib.subType { - types = { inherit (diskoLib.types) table gpt btrfs filesystem zfs mdraid luks lvm_pv swap; }; + types = diskoLib._deviceTypes; inherit extraArgs; }); default = null; @@ -699,11 +701,22 @@ let typesSerializerLib = { rootMountPoint = ""; options = null; - config._module.args.name = "self.name"; - lib = { + config = { + _module = { + args.name = ""; + args._parent.name = ""; + args._parent.type = ""; + }; + name = ""; + }; + parent = { }; + device = "/dev/"; + # Spoof part of nixpkgs/lib to analyze the types + lib = lib // { mkOption = option: { - inherit (option) type description; - default = option.default or null; + inherit (option) type; + description = option.description or null; + default = option.defaultText or option.default or null; }; types = { attrsOf = subType: { @@ -718,32 +731,61 @@ let type = "nullOr"; inherit subType; }; + oneOf = types: { + type = "oneOf"; + inherit types; + }; + either = t1: t2: { + type = "oneOf"; + types = [ t1 t2 ]; + }; enum = choices: { type = "enum"; inherit choices; }; + anything = "anything"; + nonEmptyStr = "str"; + strMatching = _: "str"; str = "str"; bool = "bool"; int = "int"; - submodule = x: x { inherit (diskoLib.typesSerializerLib) lib config options; }; + submodule = x: x { + inherit (diskoLib.typesSerializerLib) lib config options; + name = ""; + }; }; }; diskoLib = { optionTypes.absolute-pathname = "absolute-pathname"; - deviceType = "devicetype"; - partitionType = "partitiontype"; - subType = types: "onOf ${toString (lib.attrNames types)}"; + # Spoof these types to avoid infinite recursion + deviceType = _: ""; + partitionType = _: ""; + subType = { types, ... }: { + type = "oneOf"; + types = lib.attrNames types; + }; + mkCreateOption = option: "_create"; }; }; - jsonTypes = lib.listToAttrs ( - map - (file: lib.nameValuePair - (lib.removeSuffix ".nix" file) - (diskoLib.serializeType (import ./types/${file} diskoLib.typesSerializerLib)) - ) - (lib.attrNames (builtins.readDir ./types)) - ); + jsonTypes = lib.listToAttrs + ( + map + (file: lib.nameValuePair + (lib.removeSuffix ".nix" file) + (diskoLib.serializeType (import ./types/${file} diskoLib.typesSerializerLib)) + ) + (lib.filter (name: lib.hasSuffix ".nix" name) (lib.attrNames (builtins.readDir ./types))) + ) // { + partitionType = { + type = "oneOf"; + types = lib.attrNames diskoLib._partitionTypes; + }; + deviceType = { + type = "oneOf"; + types = lib.attrNames diskoLib._deviceTypes; + }; + }; } // outputs; in diff --git a/lib/types/gpt.nix b/lib/types/gpt.nix index c52ef8c8..b547b4dd 100644 --- a/lib/types/gpt.nix +++ b/lib/types/gpt.nix @@ -42,6 +42,13 @@ in "/dev/disk/by-id/md-name-any:${config._parent.name}-part${toString partition.config._index}" else "/dev/disk/by-partlabel/${diskoLib.hexEscapeUdevSymlink partition.config.label}"; + defaultText = '' + if the parent is an mdadm device: + /dev/disk/by-id/md-name-any:''${config._parent.name}-part''${toString partition.config._index} + + otherwise: + /dev/disk/by-partlabel/''${diskoLib.hexEscapeUdevSymlink partition.config.label} + ''; description = "Device to use for the partition"; }; priority = lib.mkOption { @@ -80,6 +87,11 @@ in builtins.substring 0 limit (builtins.hashString "sha256" label) else label; + defaultText = '' + ''${config._parent.type}-''${config._parent.name}-''${partition.config.name} + + or a truncated hash of the above if it is longer than 36 characters + ''; }; size = lib.mkOption { type = lib.types.either (lib.types.enum [ "100%" ]) (lib.types.strMatching "[0-9]+[KMGTP]?"); @@ -93,6 +105,7 @@ in alignment = lib.mkOption { type = lib.types.int; default = if (builtins.substring (builtins.stringLength partition.config.start - 1) 1 partition.config.start == "s" || (builtins.substring (builtins.stringLength partition.config.end - 1) 1 partition.config.end == "s")) then 1 else 0; + defaultText = "1 if the unit of start or end is sectors, 0 otherwise"; description = "Alignment of the partition, if sectors are used as start or end it can be aligned to 1"; }; start = lib.mkOption { @@ -103,6 +116,9 @@ in end = lib.mkOption { type = lib.types.str; default = if partition.config.size == "100%" then "-0" else "+${partition.config.size}"; + defaultText = '' + if partition.config.size == "100%" then "-0" else "+''${partition.config.size}"; + ''; description = '' End of the partition, in sgdisk format. Use + for relative sizes from the partitions start @@ -142,8 +158,10 @@ in description = "Entry to add to the Hybrid MBR table"; }; _index = lib.mkOption { + type = lib.types.int; internal = true; default = diskoLib.indexOf (x: x.name == partition.config.name) sortedPartitions 0; + defaultText = null; }; }; })); diff --git a/lib/types/luks.nix b/lib/types/luks.nix index 8056b35d..637dc3ef 100644 --- a/lib/types/luks.nix +++ b/lib/types/luks.nix @@ -59,9 +59,11 @@ in askPassword = lib.mkOption { type = lib.types.bool; default = config.keyFile == null && config.passwordFile == null && (! config.settings ? "keyFile"); + defaultText = "true if neither keyFile nor passwordFile are set"; description = "Whether to ask for a password for initial encryption"; }; settings = lib.mkOption { + type = lib.types.attrsOf lib.types.anything; default = { }; description = "LUKS settings (as defined in configuration.nix in boot.initrd.luks.devices.)"; example = ''{ diff --git a/lib/types/table.nix b/lib/types/table.nix index 8aec03d8..249a5265 100644 --- a/lib/types/table.nix +++ b/lib/types/table.nix @@ -63,8 +63,10 @@ }; content = diskoLib.partitionType { parent = config; device = diskoLib.deviceNumbering config.device partition.config._index; }; _index = lib.mkOption { + type = lib.types.int; internal = true; default = lib.toInt (lib.head (builtins.match ".*entry ([[:digit:]]+)]" name)); + defaultText = null; }; }; }));