From 79703eef083d70046873dbb86f08e2ff08f58197 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Mon, 10 Apr 2023 17:55:34 +0200 Subject: nixos,nixpkgs: Add module classes This allows modules that declare their class to be checked. While that's not most user modules, frameworks can take advantage of this by setting declaring the module class for their users. That way, the mistake of importing a module into the wrong hierarchy can be reported more clearly in some cases. --- nixos/lib/eval-cacheable-options.nix | 1 + nixos/lib/eval-config-minimal.nix | 4 +++- nixos/lib/testing/default.nix | 5 ++++- nixos/modules/misc/documentation.nix | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) (limited to 'nixos') diff --git a/nixos/lib/eval-cacheable-options.nix b/nixos/lib/eval-cacheable-options.nix index c3ba2ce663758..d26967ebe09b8 100644 --- a/nixos/lib/eval-cacheable-options.nix +++ b/nixos/lib/eval-cacheable-options.nix @@ -33,6 +33,7 @@ let ]; specialArgs = { inherit config pkgs utils; + class = "nixos"; }; }; docs = import "${nixosPath}/doc/manual" { diff --git a/nixos/lib/eval-config-minimal.nix b/nixos/lib/eval-config-minimal.nix index d45b9ffd42618..7e28f43051271 100644 --- a/nixos/lib/eval-config-minimal.nix +++ b/nixos/lib/eval-config-minimal.nix @@ -40,7 +40,9 @@ let inherit prefix modules; specialArgs = { modulesPath = builtins.toString ../modules; - } // specialArgs; + } // specialArgs // { + class = "nixos"; + }; }; in diff --git a/nixos/lib/testing/default.nix b/nixos/lib/testing/default.nix index 9d4f9dbc43d76..1bd6278ce6844 100644 --- a/nixos/lib/testing/default.nix +++ b/nixos/lib/testing/default.nix @@ -1,7 +1,10 @@ { lib }: let - evalTest = module: lib.evalModules { modules = testModules ++ [ module ]; }; + evalTest = module: lib.evalModules { + modules = testModules ++ [ module ]; + specialArgs.class = "nixosTest"; + }; runTest = module: (evalTest ({ config, ... }: { imports = [ module ]; result = config.test; })).config.result; testModules = [ diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix index e0c6af4abe106..1821dd866cb13 100644 --- a/nixos/modules/misc/documentation.nix +++ b/nixos/modules/misc/documentation.nix @@ -39,6 +39,7 @@ let _module.check = false; } ] ++ docModules.eager; specialArgs = specialArgs // { + class = "nixos"; pkgs = scrubDerivations "pkgs" pkgs; # allow access to arbitrary options for eager modules, eg for getting # option types from lazy modules -- cgit 1.4.1 From 8054785157119ea12e526481924d6676427904bb Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Mon, 17 Apr 2023 19:48:53 +0200 Subject: lib/modules: Move class out of specialArgs --- doc/doc-support/default.nix | 2 +- doc/module-system/module-system.chapter.md | 6 +++--- lib/modules.nix | 26 +++++++++++++++++++------- lib/tests/modules/class-check.nix | 6 +++--- lib/types.nix | 10 ++++++++-- nixos/lib/eval-config-minimal.nix | 5 ++--- nixos/lib/testing/default.nix | 2 +- nixos/modules/misc/documentation.nix | 2 +- pkgs/top-level/default.nix | 2 +- 9 files changed, 39 insertions(+), 22 deletions(-) (limited to 'nixos') diff --git a/doc/doc-support/default.nix b/doc/doc-support/default.nix index 67195a4a58b04..cfa7cbdc82839 100644 --- a/doc/doc-support/default.nix +++ b/doc/doc-support/default.nix @@ -47,7 +47,7 @@ let optionsDoc = pkgs.nixosOptionsDoc { inherit (pkgs.lib.evalModules { modules = [ ../../pkgs/top-level/config.nix ]; - specialArgs.class = "nixpkgsConfig"; + class = "nixpkgsConfig"; }) options; documentType = "none"; transformOptions = opt: diff --git a/doc/module-system/module-system.chapter.md b/doc/module-system/module-system.chapter.md index 9a24ab70c6c17..51e600d756405 100644 --- a/doc/module-system/module-system.chapter.md +++ b/doc/module-system/module-system.chapter.md @@ -28,11 +28,11 @@ An attribute set of module arguments that can be used in `imports`. This is in contrast to `config._module.args`, which is only available after all `imports` have been resolved. -#### `specialArgs.class` {#module-system-lib-evalModules-param-specialArgs-class} +#### `class` {#module-system-lib-evalModules-param-class} -If the `class` attribute is set in `specialArgs`, the module system will reject modules with a different `class`. +If the `class` attribute is set and non-`null`, the module system will reject `imports` with a different `class`. -The `class` value should be in lower [camel case](https://en.wikipedia.org/wiki/Camel_case). +The `class` value should be a string in lower [camel case](https://en.wikipedia.org/wiki/Camel_case). If applicable, the `class` should match the "prefix" of the attributes used in (experimental) [flakes](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html#description). Some examples are: diff --git a/lib/modules.nix b/lib/modules.nix index e83d5b6d1caec..3550ebddaeac9 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -78,13 +78,13 @@ let # when resolving module structure (like in imports). For everything else, # there's _module.args. If specialArgs.modulesPath is defined it will be # used as the base path for disabledModules. - # - # `specialArgs.class`: + specialArgs ? {} + , # `class`: # A nominal type for modules. When set and non-null, this adds a check to # make sure that only compatible modules are imported. - specialArgs ? {} - , # This would be remove in the future, Prefer _module.args option instead. - args ? {} + # This would be remove in the future, Prefer _module.args option instead. + class ? null + , args ? {} , # This would be remove in the future, Prefer _module.check option instead. check ? true }: @@ -220,6 +220,16 @@ let within a configuration, but can be used in module imports. ''; }; + + _module.class = mkOption { + readOnly = true; + internal = true; + description = lib.mdDoc '' + If the `class` attribute is set and non-`null`, the module system will reject `imports` with a different `class`. + + This option contains the expected `class` attribute of the current module evaluation. + ''; + }; }; config = { @@ -227,13 +237,14 @@ let inherit extendModules; moduleType = type; }; + _module.class = class; _module.specialArgs = specialArgs; }; }; merged = let collected = collectModules - (specialArgs.class or null) + class (specialArgs.modulesPath or "") (regularModules ++ [ internalModule ]) ({ inherit lib options config specialArgs; } // specialArgs); @@ -310,13 +321,14 @@ let prefix ? [], }: evalModules (evalModulesArgs // { + inherit class; modules = regularModules ++ modules; specialArgs = evalModulesArgs.specialArgs or {} // specialArgs; prefix = extendArgs.prefix or evalModulesArgs.prefix or []; }); type = lib.types.submoduleWith { - inherit modules specialArgs; + inherit modules specialArgs class; }; result = withWarnings { diff --git a/lib/tests/modules/class-check.nix b/lib/tests/modules/class-check.nix index f492c844abfbb..02d1431cc88b6 100644 --- a/lib/tests/modules/class-check.nix +++ b/lib/tests/modules/class-check.nix @@ -3,7 +3,7 @@ _module.freeformType = lib.types.anything; ok = lib.evalModules { - specialArgs.class = "nixos"; + class = "nixos"; modules = [ ./module-class-is-nixos.nix ]; @@ -11,7 +11,7 @@ fail = lib.evalModules { - specialArgs.class = "nixos"; + class = "nixos"; modules = [ ./module-class-is-nixos.nix ./module-class-is-darwin.nix @@ -20,7 +20,7 @@ fail-anon = lib.evalModules { - specialArgs.class = "nixos"; + class = "nixos"; modules = [ ./module-class-is-nixos.nix { _file = "foo.nix#darwinModules.default"; diff --git a/lib/types.nix b/lib/types.nix index 666e6502d161b..e0da18a2febb9 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -696,6 +696,7 @@ rec { , specialArgs ? {} , shorthandOnlyDefinesConfig ? false , description ? null + , class ? null }@attrs: let inherit (lib.modules) evalModules; @@ -707,7 +708,7 @@ rec { ) defs; base = evalModules { - inherit specialArgs; + inherit class specialArgs; modules = [{ # This is a work-around for the fact that some sub-modules, # such as the one included in an attribute set, expects an "args" @@ -762,9 +763,14 @@ rec { functor = defaultFunctor name // { type = types.submoduleWith; payload = { - inherit modules specialArgs shorthandOnlyDefinesConfig description; + inherit modules class specialArgs shorthandOnlyDefinesConfig description; }; binOp = lhs: rhs: { + class = + if lhs.class == null then rhs.class + else if rhs.class == null then lhs.class + else if lhs.class == rhs.class then lhs.class + else throw "A submoduleWith option is declared multiple times with conflicting class values \"${toString lhs.class}\" and \"${toString rhs.class}\"."; modules = lhs.modules ++ rhs.modules; specialArgs = let intersecting = builtins.intersectAttrs lhs.specialArgs rhs.specialArgs; diff --git a/nixos/lib/eval-config-minimal.nix b/nixos/lib/eval-config-minimal.nix index 7e28f43051271..036389121973d 100644 --- a/nixos/lib/eval-config-minimal.nix +++ b/nixos/lib/eval-config-minimal.nix @@ -38,11 +38,10 @@ let # is experimental. lib.evalModules { inherit prefix modules; + class = "nixos"; specialArgs = { modulesPath = builtins.toString ../modules; - } // specialArgs // { - class = "nixos"; - }; + } // specialArgs; }; in diff --git a/nixos/lib/testing/default.nix b/nixos/lib/testing/default.nix index 1bd6278ce6844..a89f734b1e645 100644 --- a/nixos/lib/testing/default.nix +++ b/nixos/lib/testing/default.nix @@ -3,7 +3,7 @@ let evalTest = module: lib.evalModules { modules = testModules ++ [ module ]; - specialArgs.class = "nixosTest"; + class = "nixosTest"; }; runTest = module: (evalTest ({ config, ... }: { imports = [ module ]; result = config.test; })).config.result; diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix index 1821dd866cb13..31486a2216ad0 100644 --- a/nixos/modules/misc/documentation.nix +++ b/nixos/modules/misc/documentation.nix @@ -38,8 +38,8 @@ let modules = [ { _module.check = false; } ] ++ docModules.eager; + class = "nixos"; specialArgs = specialArgs // { - class = "nixos"; pkgs = scrubDerivations "pkgs" pkgs; # allow access to arbitrary options for eager modules, eg for getting # option types from lazy modules diff --git a/pkgs/top-level/default.nix b/pkgs/top-level/default.nix index f54ce84aedad9..ba00e78ce2e62 100644 --- a/pkgs/top-level/default.nix +++ b/pkgs/top-level/default.nix @@ -82,7 +82,7 @@ in let config = config1; }) ]; - specialArgs.class = "nixpkgsConfig"; + class = "nixpkgsConfig"; }; # take all the rest as-is -- cgit 1.4.1