diff --git a/flakeModules/clan.nix b/flakeModules/clan.nix index 227ef0f4e..76eb2177b 100644 --- a/flakeModules/clan.nix +++ b/flakeModules/clan.nix @@ -39,23 +39,32 @@ in }; modules = [ clan-core.modules.clan.default + { + checks.minNixpkgsVersion = { + assertion = lib.versionAtLeast nixpkgs.lib.version "25.11"; + message = '' + Nixpkgs version: ${nixpkgs.lib.version} is incompatible with clan-core. (>= 25.11 is recommended) + --- + Your version of 'nixpkgs' seems too old for clan-core. + Please read: https://docs.clan.lol/guides/nixpkgs-flake-input + + You can ignore this check by setting: + clan.checks.minNixpkgsVersion.ignore = true; + --- + ''; + }; + } ]; }; apply = config: - # TOOD: - # - allow to disable version check? - # - self-incrementing version? - if !lib.versionAtLeast nixpkgs.lib.version "25.11" then - throw '' - Nixpkgs version: ${nixpkgs.lib.version} is incompatible with clan-core. (>= 25.11 is required) - --- - Your version of 'nixpkgs' seems too old for clan-core. - Please read: https://docs.clan.lol/guides/nixpkgs-flake-input - --- - '' - else - config; + lib.deepSeq (lib.mapAttrs ( + id: check: + if check.ignore || check.assertion then + null + else + throw "clan.checks.${id} failed with message\n${check.message}" + ) config.checks) config; }; # Mapped flake toplevel outputs diff --git a/lib/modules/clan/interface.nix b/lib/modules/clan/interface.nix index c4b1830d0..c6b70baf1 100644 --- a/lib/modules/clan/interface.nix +++ b/lib/modules/clan/interface.nix @@ -9,6 +9,36 @@ }: let types = lib.types; + + checkType = types.attrsOf ( + types.submodule { + # Skip entire evaluation of this check + options.ignore = lib.mkOption { + type = types.bool; + default = false; + description = "Ignores this check entirely"; + }; + + # Can only be defined once + options.assertion = lib.mkOption { + type = types.bool; + readOnly = true; + description = '' + The assertion that must hold true. + + If false, the message is shown. + ''; + }; + # Message shown when the assertion is false + options.message = lib.mkOption { + type = types.str; + description = "Message shown when the assertion is false"; + }; + + # TODO: add severity levels? + # Fail, Warn, Log + } + ); in { options = { @@ -18,6 +48,17 @@ in visible = false; default = [ ]; }; + + # id :: { assertion, message } + checks = lib.mkOption { + type = checkType; + default = { }; + description = '' + Assertions that must hold true when evaluating the clan. + When the assertion fails, the message is shown and the evaluation is aborted. + ''; + }; + self = lib.mkOption { type = types.raw; default = self;