From fbd038eca24703d8c5cc3ce28adda3e71c5fabf4 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Sun, 2 Jan 2022 14:11:21 +0100 Subject: [PATCH 1/6] nixos/lib: init (experimental) --- flake.nix | 3 +++ nixos/lib/default.nix | 47 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 nixos/lib/default.nix diff --git a/flake.nix b/flake.nix index 1e20fcd40ebe..3275370017db 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,9 @@ in { lib = lib.extend (final: prev: { + + nixos = import ./nixos/lib { lib = final; }; + nixosSystem = { modules, ... } @ args: import ./nixos/lib/eval-config.nix (args // { modules = diff --git a/nixos/lib/default.nix b/nixos/lib/default.nix new file mode 100644 index 000000000000..6479b7144907 --- /dev/null +++ b/nixos/lib/default.nix @@ -0,0 +1,47 @@ +let + # The warning is in a top-level let binding so it is only printed once. + experimentalWarning = warn "lib.nixos.evalModules is experimental and subject to change. See nixos/lib/default.nix" null; + inherit (nonExtendedLib) warn; + nonExtendedLib = import ../../lib; +in +{ lib ? nonExtendedLib, ... }: +let + + /* + Invoke NixOS. Unlike traditional NixOS, this does not include all modules. + Any such modules have to be explicitly added via the `modules` parameter, + or imported using `imports` in a module. + + A minimal module list improves NixOS evaluation performance and allows + modules to be independently usable, supporting new use cases. + + Parameters: + + modules: A list of modules that constitute the configuration. + + specialArgs: An attribute set of module arguments. Unlike + `config._module.args`, these are available for use in + `imports`. + `config._module.args` should be preferred when possible. + + Return: + + An attribute set containing `config.system.build.toplevel` among other + attributes. See `lib.evalModules` in the Nixpkgs library. + + */ + evalModules = { + prefix ? [], + modules ? [], + specialArgs ? {}, + }: lib.evalModules { + inherit prefix modules; + specialArgs = { + modulesPath = builtins.toString ../modules; + } // specialArgs; + }; + +in +{ + evalModules = builtins.seq experimentalWarning evalModules; +} From be3967e351b6e1b010e95ec16217ed2db33da0c5 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Fri, 3 Dec 2021 12:04:36 +0000 Subject: [PATCH 2/6] nixos/nixpkgs.nix: Make independent (cherry picked from commit 62e7f0eda1c5acf0beb13a00a23f577912a6b8eb) --- nixos/modules/misc/nixpkgs.nix | 5 +++++ nixos/modules/misc/nixpkgs/test.nix | 8 ++++++++ nixos/tests/all-tests.nix | 4 ++++ 3 files changed, 17 insertions(+) create mode 100644 nixos/modules/misc/nixpkgs/test.nix diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix index 2e0c8e4cf2c4..69967c8a7601 100644 --- a/nixos/modules/misc/nixpkgs.nix +++ b/nixos/modules/misc/nixpkgs.nix @@ -64,6 +64,11 @@ let in { + imports = [ + ./assertions.nix + ./meta.nix + ]; + options.nixpkgs = { pkgs = mkOption { diff --git a/nixos/modules/misc/nixpkgs/test.nix b/nixos/modules/misc/nixpkgs/test.nix new file mode 100644 index 000000000000..ec5fab9fb4a5 --- /dev/null +++ b/nixos/modules/misc/nixpkgs/test.nix @@ -0,0 +1,8 @@ +{ evalMinimalConfig, pkgs, lib, stdenv }: +lib.recurseIntoAttrs { + invokeNixpkgsSimple = + (evalMinimalConfig ({ config, modulesPath, ... }: { + imports = [ (modulesPath + "/misc/nixpkgs.nix") ]; + nixpkgs.system = stdenv.hostPlatform.system; + }))._module.args.pkgs.hello; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 4f62980e8e91..d7971f6c2eb7 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -19,6 +19,9 @@ let handleTestOn = systems: path: args: if elem system systems then handleTest path args else {}; + + nixosLib = import ../lib {}; + evalMinimalConfig = module: nixosLib.evalModules { modules = [ module ]; }; in { _3proxy = handleTest ./3proxy.nix {}; @@ -327,6 +330,7 @@ in nix-serve-ssh = handleTest ./nix-serve-ssh.nix {}; nixops = handleTest ./nixops/default.nix {}; nixos-generate-config = handleTest ./nixos-generate-config.nix {}; + nixpkgs = pkgs.callPackage ../modules/misc/nixpkgs/test.nix { inherit evalMinimalConfig; }; node-red = handleTest ./node-red.nix {}; nomad = handleTest ./nomad.nix {}; novacomd = handleTestOn ["x86_64-linux"] ./novacomd.nix {}; From e31e096b667f671aea424681f2b4a65e385efe50 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Tue, 4 Jan 2022 21:54:35 +0100 Subject: [PATCH 3/6] nixos/lib: Move evalModules into its own file --- nixos/lib/default.nix | 52 ++++++------------------------- nixos/lib/eval-config-minimal.nix | 47 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 43 deletions(-) create mode 100644 nixos/lib/eval-config-minimal.nix diff --git a/nixos/lib/default.nix b/nixos/lib/default.nix index 6479b7144907..41ae2d863e05 100644 --- a/nixos/lib/default.nix +++ b/nixos/lib/default.nix @@ -1,47 +1,13 @@ +{ lib ? import ../../lib, ... }: let - # The warning is in a top-level let binding so it is only printed once. - experimentalWarning = warn "lib.nixos.evalModules is experimental and subject to change. See nixos/lib/default.nix" null; - inherit (nonExtendedLib) warn; - nonExtendedLib = import ../../lib; -in -{ lib ? nonExtendedLib, ... }: -let - - /* - Invoke NixOS. Unlike traditional NixOS, this does not include all modules. - Any such modules have to be explicitly added via the `modules` parameter, - or imported using `imports` in a module. - - A minimal module list improves NixOS evaluation performance and allows - modules to be independently usable, supporting new use cases. - - Parameters: - - modules: A list of modules that constitute the configuration. - - specialArgs: An attribute set of module arguments. Unlike - `config._module.args`, these are available for use in - `imports`. - `config._module.args` should be preferred when possible. - - Return: - - An attribute set containing `config.system.build.toplevel` among other - attributes. See `lib.evalModules` in the Nixpkgs library. - - */ - evalModules = { - prefix ? [], - modules ? [], - specialArgs ? {}, - }: lib.evalModules { - inherit prefix modules; - specialArgs = { - modulesPath = builtins.toString ../modules; - } // specialArgs; - }; - + eval-config-minimal = import ./eval-config-minimal.nix { inherit lib; }; in +/* + This attribute set appears as lib.nixos in the flake, or can be imported + using a binding like `nixosLib = import (nixpkgs + "/nixos/lib") { }`. +*/ { - evalModules = builtins.seq experimentalWarning evalModules; + inherit (eval-config-minimal) + evalModules + ; } diff --git a/nixos/lib/eval-config-minimal.nix b/nixos/lib/eval-config-minimal.nix new file mode 100644 index 000000000000..6479b7144907 --- /dev/null +++ b/nixos/lib/eval-config-minimal.nix @@ -0,0 +1,47 @@ +let + # The warning is in a top-level let binding so it is only printed once. + experimentalWarning = warn "lib.nixos.evalModules is experimental and subject to change. See nixos/lib/default.nix" null; + inherit (nonExtendedLib) warn; + nonExtendedLib = import ../../lib; +in +{ lib ? nonExtendedLib, ... }: +let + + /* + Invoke NixOS. Unlike traditional NixOS, this does not include all modules. + Any such modules have to be explicitly added via the `modules` parameter, + or imported using `imports` in a module. + + A minimal module list improves NixOS evaluation performance and allows + modules to be independently usable, supporting new use cases. + + Parameters: + + modules: A list of modules that constitute the configuration. + + specialArgs: An attribute set of module arguments. Unlike + `config._module.args`, these are available for use in + `imports`. + `config._module.args` should be preferred when possible. + + Return: + + An attribute set containing `config.system.build.toplevel` among other + attributes. See `lib.evalModules` in the Nixpkgs library. + + */ + evalModules = { + prefix ? [], + modules ? [], + specialArgs ? {}, + }: lib.evalModules { + inherit prefix modules; + specialArgs = { + modulesPath = builtins.toString ../modules; + } // specialArgs; + }; + +in +{ + evalModules = builtins.seq experimentalWarning evalModules; +} From 25caf736d5c16fa0c026c26ff4e7b7779fcbb7ae Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Tue, 4 Jan 2022 22:00:00 +0100 Subject: [PATCH 4/6] nixos/eval-config: Layer on top of nixos/eval-config-minimal --- nixos/lib/eval-config-minimal.nix | 4 ++-- nixos/lib/eval-config.nix | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/nixos/lib/eval-config-minimal.nix b/nixos/lib/eval-config-minimal.nix index 6479b7144907..a0fcf2389779 100644 --- a/nixos/lib/eval-config-minimal.nix +++ b/nixos/lib/eval-config-minimal.nix @@ -4,7 +4,7 @@ let inherit (nonExtendedLib) warn; nonExtendedLib = import ../../lib; in -{ lib ? nonExtendedLib, ... }: +{ lib ? nonExtendedLib, bypassEvalModulesWarning ? false, ... }: let /* @@ -43,5 +43,5 @@ let in { - evalModules = builtins.seq experimentalWarning evalModules; + evalModules = builtins.seq (if bypassEvalModulesWarning then null else experimentalWarning) evalModules; } diff --git a/nixos/lib/eval-config.nix b/nixos/lib/eval-config.nix index 62d09b8173bd..8ea82b30f16d 100644 --- a/nixos/lib/eval-config.nix +++ b/nixos/lib/eval-config.nix @@ -33,6 +33,8 @@ let pkgs_ = pkgs; in let + evalModulesMinimal = (import ./eval-config-minimal.nix { inherit lib; bypassEvalModulesWarning = true; }).evalModules; + pkgsModule = rec { _file = ./eval-config.nix; key = _file; @@ -70,11 +72,9 @@ let }; allUserModules = modules ++ legacyModules; - noUserModules = lib.evalModules ({ - inherit prefix; + noUserModules = evalModulesMinimal ({ + inherit prefix specialArgs; modules = baseModules ++ extraModules ++ [ pkgsModule modulesModule ]; - specialArgs = - { modulesPath = builtins.toString ../modules; } // specialArgs; }); # Extra arguments that are useful for constructing a similar configuration. From d3f956aba324a18bfafde59138929b320a9b4a2b Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Fri, 7 Jan 2022 01:09:46 +0100 Subject: [PATCH 5/6] nixos/lib: Add featureFlags, use it for minimal modules --- nixos/lib/default.nix | 24 ++++++++++++++++++++++-- nixos/lib/eval-config-minimal.nix | 13 +++++-------- nixos/tests/all-tests.nix | 6 +++++- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/nixos/lib/default.nix b/nixos/lib/default.nix index 41ae2d863e05..2b3056e01457 100644 --- a/nixos/lib/default.nix +++ b/nixos/lib/default.nix @@ -1,5 +1,25 @@ -{ lib ? import ../../lib, ... }: let + # The warning is in a top-level let binding so it is only printed once. + minimalModulesWarning = warn "lib.nixos.evalModules is experimental and subject to change. See nixos/lib/default.nix" null; + inherit (nonExtendedLib) warn; + nonExtendedLib = import ../../lib; +in +{ # Optional. Allows an extended `lib` to be used instead of the regular Nixpkgs lib. + lib ? nonExtendedLib, + + # Feature flags allow you to opt in to unfinished code. These may change some + # behavior or disable warnings. + featureFlags ? {}, + + # This file itself is rather new, so we accept unknown parameters to be forward + # compatible. This is generally not recommended, because typos go undetected. + ... +}: +let + seqIf = cond: if cond then builtins.seq else a: b: b; + # If cond, force `a` before returning any attr + seqAttrsIf = cond: a: lib.mapAttrs (_: v: seqIf cond a v); + eval-config-minimal = import ./eval-config-minimal.nix { inherit lib; }; in /* @@ -7,7 +27,7 @@ in using a binding like `nixosLib = import (nixpkgs + "/nixos/lib") { }`. */ { - inherit (eval-config-minimal) + inherit (seqAttrsIf (!featureFlags?minimalModules) minimalModulesWarning eval-config-minimal) evalModules ; } diff --git a/nixos/lib/eval-config-minimal.nix b/nixos/lib/eval-config-minimal.nix index a0fcf2389779..ed26e623b2f1 100644 --- a/nixos/lib/eval-config-minimal.nix +++ b/nixos/lib/eval-config-minimal.nix @@ -1,10 +1,7 @@ -let - # The warning is in a top-level let binding so it is only printed once. - experimentalWarning = warn "lib.nixos.evalModules is experimental and subject to change. See nixos/lib/default.nix" null; - inherit (nonExtendedLib) warn; - nonExtendedLib = import ../../lib; -in -{ lib ? nonExtendedLib, bypassEvalModulesWarning ? false, ... }: + +# DO NOT IMPORT. Use nixpkgsFlake.lib.nixos, or import (nixpkgs + "/nixos/lib") +{ lib }: # read -^ + let /* @@ -43,5 +40,5 @@ let in { - evalModules = builtins.seq (if bypassEvalModulesWarning then null else experimentalWarning) evalModules; + inherit evalModules; } diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index d7971f6c2eb7..0dee1a0e8b05 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -20,7 +20,11 @@ let if elem system systems then handleTest path args else {}; - nixosLib = import ../lib {}; + nixosLib = import ../lib { + # Experimental features need testing too, but there's no point in warning + # about it, so we enable the feature flag. + featureFlags.minimalModules = {}; + }; evalMinimalConfig = module: nixosLib.evalModules { modules = [ module ]; }; in { From 3168017b90440220c69d4ba8f39f469024b4cafe Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Fri, 7 Jan 2022 01:34:30 +0100 Subject: [PATCH 6/6] nixos/lib: Clarify that nixos.evalModules impl is NOT experimental --- nixos/lib/eval-config-minimal.nix | 7 ++++++- nixos/lib/eval-config.nix | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/nixos/lib/eval-config-minimal.nix b/nixos/lib/eval-config-minimal.nix index ed26e623b2f1..d45b9ffd4261 100644 --- a/nixos/lib/eval-config-minimal.nix +++ b/nixos/lib/eval-config-minimal.nix @@ -31,7 +31,12 @@ let prefix ? [], modules ? [], specialArgs ? {}, - }: lib.evalModules { + }: + # NOTE: Regular NixOS currently does use this function! Don't break it! + # Ideally we don't diverge, unless we learn that we should. + # In other words, only the public interface of nixos.evalModules + # is experimental. + lib.evalModules { inherit prefix modules; specialArgs = { modulesPath = builtins.toString ../modules; diff --git a/nixos/lib/eval-config.nix b/nixos/lib/eval-config.nix index 8ea82b30f16d..850322b8251b 100644 --- a/nixos/lib/eval-config.nix +++ b/nixos/lib/eval-config.nix @@ -33,7 +33,11 @@ let pkgs_ = pkgs; in let - evalModulesMinimal = (import ./eval-config-minimal.nix { inherit lib; bypassEvalModulesWarning = true; }).evalModules; + evalModulesMinimal = (import ./default.nix { + inherit lib; + # Implicit use of feature is noted in implementation. + featureFlags.minimalModules = { }; + }).evalModules; pkgsModule = rec { _file = ./eval-config.nix;