push sheeet
Some checks failed
Periodic Merges (6h) / master → staging-nixos (push) Failing after 12m50s
Periodic Merges (6h) / master → staging-next (push) Failing after 12m54s
Periodic Merges (24h) / merge-base(master,staging) → haskell-updates (push) Failing after 11m54s
Periodic Merges (6h) / staging-next → staging (push) Failing after 12m13s
Periodic Merges (24h) / staging-next-25.05 → staging-25.05 (push) Failing after 13m24s
Periodic Merges (24h) / release-25.05 → staging-next-25.05 (push) Failing after 14m28s

This commit is contained in:
Dark Steveneq
2025-10-09 14:15:47 +02:00
commit 646b892680
49168 changed files with 5897842 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
(
{ lib, ... }:
let
inherit (lib) types mkOption;
inherit (types) addCheck int attrsOf;
# type with a v1 merge
v1Type = addCheck int (v: v == 0);
# type with a v2 merge
v2Type = addCheck (attrsOf int) (v: v ? foo);
in
{
options.v1CheckedPass = mkOption {
type = v1Type;
default = 0;
};
options.v1CheckedFail = mkOption {
type = v1Type;
default = 1;
};
options.v2checkedPass = mkOption {
type = v2Type;
default = {
foo = 1;
};
# plug the value to make test script regex simple
apply = v: v.foo == 1;
};
options.v2checkedFail = mkOption {
type = v2Type;
default = { };
apply = v: lib.deepSeq v v;
};
}
)

View File

@@ -0,0 +1,19 @@
{ lib, ... }:
{
options.dummy = lib.mkOption {
type = lib.types.anything;
default = { };
};
freeformType =
let
a = lib.types.attrsOf (lib.types.submodule { options.bar = lib.mkOption { }; });
in
# modifying types like this breaks type merging.
# This test makes sure that type merging is not performed when only a single declaration exists.
# Don't modify types in practice!
a
// {
merge = loc: defs: { freeformItems = a.merge loc defs; };
};
config.foo.bar = "ok";
}

View File

@@ -0,0 +1,64 @@
# This is a test to show that mkAliasOptionModule sets the priority correctly
# for aliased options.
#
# This test shows that an alias with a high priority is able to override
# a non-aliased option.
{ config, lib, ... }:
let
inherit (lib)
mkAliasOptionModule
mkForce
mkOption
types
;
in
{
options = {
# A simple boolean option that can be enabled or disabled.
enable = mkOption {
type = types.nullOr types.bool;
default = null;
example = true;
description = ''
Some descriptive text
'';
};
# mkAliasOptionModule sets warnings, so this has to be defined.
warnings = mkOption {
internal = true;
default = [ ];
type = types.listOf types.str;
example = [ "The `foo' service is deprecated and will go away soon!" ];
description = ''
This option allows modules to show warnings to users during
the evaluation of the system configuration.
'';
};
};
imports = [
# Create an alias for the "enable" option.
(mkAliasOptionModule [ "enableAlias" ] [ "enable" ])
# Disable the aliased option with a high priority so it
# should override the next import.
(
{ config, lib, ... }:
{
enableAlias = mkForce false;
}
)
# Enable the normal (non-aliased) option.
(
{ config, lib, ... }:
{
enable = true;
}
)
];
}

View File

@@ -0,0 +1,64 @@
# This is a test to show that mkAliasOptionModule sets the priority correctly
# for aliased options.
#
# This test shows that an alias with a low priority is able to be overridden
# with a non-aliased option.
{ config, lib, ... }:
let
inherit (lib)
mkAliasOptionModule
mkDefault
mkOption
types
;
in
{
options = {
# A simple boolean option that can be enabled or disabled.
enable = mkOption {
type = types.nullOr types.bool;
default = null;
example = true;
description = ''
Some descriptive text
'';
};
# mkAliasOptionModule sets warnings, so this has to be defined.
warnings = mkOption {
internal = true;
default = [ ];
type = types.listOf types.str;
example = [ "The `foo' service is deprecated and will go away soon!" ];
description = ''
This option allows modules to show warnings to users during
the evaluation of the system configuration.
'';
};
};
imports = [
# Create an alias for the "enable" option.
(mkAliasOptionModule [ "enableAlias" ] [ "enable" ])
# Disable the aliased option, but with a default (low) priority so it
# should be able to be overridden by the next import.
(
{ config, lib, ... }:
{
enableAlias = mkDefault false;
}
)
# Enable the normal (non-aliased) option.
(
{ config, lib, ... }:
{
enable = true;
}
)
];
}

View File

@@ -0,0 +1,3 @@
{ _class, ... }:
assert _class == "nixos";
{ }

View File

@@ -0,0 +1,8 @@
{ lib, config, ... }:
{
options.conditionalWorks = lib.mkOption {
default = !config.value ? foo;
};
config.value.foo = lib.mkIf false "should not be defined";
}

View File

@@ -0,0 +1,8 @@
{ lib, config, ... }:
{
options.isLazy = lib.mkOption {
default = !config.value ? foo;
};
config.value.bar = throw "is not lazy";
}

View File

@@ -0,0 +1,26 @@
{ lib, ... }:
{
options.value = lib.mkOption {
type = lib.types.lazyAttrsOf lib.types.boolByOr;
};
config.value = {
falseFalse = lib.mkMerge [
false
false
];
trueFalse = lib.mkMerge [
true
false
];
falseTrue = lib.mkMerge [
false
true
];
trueTrue = lib.mkMerge [
true
true
];
};
}

View File

@@ -0,0 +1,82 @@
{ lib, ... }:
{
options = {
sub = {
nixosOk = lib.mkOption {
type = lib.types.submoduleWith {
class = "nixos";
modules = [
./assert-module-class-is-nixos.nix
];
};
};
# Same but will have bad definition
nixosFail = lib.mkOption {
type = lib.types.submoduleWith {
class = "nixos";
modules = [ ];
};
};
mergeFail = lib.mkOption {
type = lib.types.submoduleWith {
class = "nixos";
modules = [ ];
};
default = { };
};
};
};
imports = [
{
options = {
sub = {
mergeFail = lib.mkOption {
type = lib.types.submoduleWith {
class = "darwin";
modules = [ ];
};
};
};
};
}
];
config = {
_module.freeformType = lib.types.anything;
ok = lib.evalModules {
class = "nixos";
modules = [
./module-class-is-nixos.nix
./assert-module-class-is-nixos.nix
];
};
fail = lib.evalModules {
class = "nixos";
modules = [
./module-class-is-nixos.nix
./module-class-is-darwin.nix
];
};
fail-anon = lib.evalModules {
class = "nixos";
modules = [
./module-class-is-nixos.nix
{
_file = "foo.nix#darwinModules.default";
_class = "darwin";
config = { };
imports = [ ];
}
];
};
sub.nixosOk = {
_class = "nixos";
};
sub.nixosFail = {
imports = [ ./module-class-is-darwin.nix ];
};
};
}

View File

@@ -0,0 +1,75 @@
{ lib, ... }:
let
inherit (lib) types mkOption;
attrsOfModule = mkOption {
type = types.attrsOf (
types.submodule {
options.bar = mkOption {
type = types.int;
};
}
);
};
listOfModule = mkOption {
type = types.listOf (
types.submodule {
options.bar = mkOption {
type = types.int;
};
}
);
};
in
{
imports = [
# Module A
{
options.attrsOfModule = attrsOfModule;
options.mergedAttrsOfModule = attrsOfModule;
options.listOfModule = listOfModule;
options.mergedListOfModule = listOfModule;
}
# Module B
{
options.mergedAttrsOfModule = attrsOfModule;
options.mergedListOfModule = listOfModule;
}
# Values
# It is important that the value is defined in a separate module
# Without valueMeta the actual value and sub-options wouldn't be accessible via:
# options.attrsOfModule.type.getSubOptions
{
attrsOfModule = {
foo.bar = 42;
};
mergedAttrsOfModule = {
foo.bar = 42;
};
}
(
{ options, ... }:
{
config.listOfModule = [
{
bar = 42;
}
];
config.mergedListOfModule = [
{
bar = 42;
}
];
# Result options to expose the list module to bash as plain attribute path
options.listResult = mkOption {
default = (builtins.head options.listOfModule.valueMeta.list).configuration.options.bar.value;
};
options.mergedListResult = mkOption {
default = (builtins.head options.mergedListOfModule.valueMeta.list).configuration.options.bar.value;
};
}
)
];
}

View File

@@ -0,0 +1,57 @@
{ lib, options, ... }:
let
discardPositions = lib.mapAttrs (k: v: v);
in
# unsafeGetAttrPos is unspecified best-effort behavior, so we only want to consider this test on an evaluator that satisfies some basic assumptions about this function.
assert builtins.unsafeGetAttrPos "a" { a = true; } != null;
assert
builtins.unsafeGetAttrPos "a" (discardPositions {
a = true;
}) == null;
{
imports = [
{
options.imported.line14 = lib.mkOption {
type = lib.types.int;
};
# Simulates various patterns of generating modules such as
# programs.firefox.nativeMessagingHosts.ff2mpv. We don't expect to get
# line numbers for these, but we can fall back on knowing the file.
options.generated = discardPositions {
line22 = lib.mkOption {
type = lib.types.int;
};
};
options.submoduleLine38.extraOptLine27 = lib.mkOption {
default = 1;
type = lib.types.int;
};
}
];
options.nested.nestedLine34 = lib.mkOption {
type = lib.types.int;
};
options.submoduleLine38 = lib.mkOption {
default = { };
type = lib.types.submoduleWith {
modules = [
(
{ options, ... }:
{
options.submodDeclLine45 = lib.mkOption { };
}
)
{ freeformType = with lib.types; lazyAttrsOf (uniq unspecified); }
];
};
};
config = {
submoduleLine38.submodDeclLine45 =
(options.submoduleLine38.type.getSubOptions [ ]).submodDeclLine45.declarationPositions;
};
}

View File

@@ -0,0 +1,13 @@
{ lib, ... }:
let
deathtrapArgs = lib.mapAttrs (
k: _: throw "The module system is too strict, accessing an unused option's ${k} mkOption-attribute."
) (lib.functionArgs lib.mkOption);
in
{
options.value = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
default = { };
};
options.testing-laziness-so-don't-read-me = lib.mkOption deathtrapArgs;
}

View File

@@ -0,0 +1,31 @@
{ lib, ... }:
let
submod =
{ ... }:
{
options = {
enable = lib.mkOption {
default = false;
example = true;
type = lib.types.bool;
description = ''
Some descriptive text
'';
};
};
};
in
{
options = {
attrsOfSub = lib.mkOption {
default = { };
example = { };
type = lib.types.attrsOf (lib.types.submodule [ submod ]);
description = ''
Some descriptive text
'';
};
};
}

View File

@@ -0,0 +1,10 @@
{ lib, ... }:
let
inherit (lib) mkOption types;
in
{
options.bare-submodule.deep = mkOption {
type = types.int;
default = 2;
};
}

View File

@@ -0,0 +1,10 @@
{ lib, ... }:
let
inherit (lib) mkOption types;
in
{
options.bare-submodule.deep = mkOption {
type = types.int;
default = 2;
};
}

View File

@@ -0,0 +1,19 @@
{ config, lib, ... }:
let
inherit (lib) mkOption types;
in
{
options.bare-submodule = mkOption {
type = types.submoduleWith {
shorthandOnlyDefinesConfig = config.shorthandOnlyDefinesConfig;
modules = [
{
options.nested = mkOption {
type = types.int;
default = 1;
};
}
];
};
};
}

View File

@@ -0,0 +1,18 @@
{ config, lib, ... }:
let
inherit (lib) mkOption types;
in
{
options.bare-submodule = mkOption {
type = types.submoduleWith {
modules = [ ];
shorthandOnlyDefinesConfig = config.shorthandOnlyDefinesConfig;
};
default = { };
};
# config-dependent options: won't recommend, but useful for making this test parameterized
options.shorthandOnlyDefinesConfig = mkOption {
default = false;
};
}

View File

@@ -0,0 +1,9 @@
{ lib, ... }:
{
options = {
value = lib.mkOption {
type = lib.types.coercedTo lib.types.int toString lib.types.str;
};
};
}

View File

@@ -0,0 +1,10 @@
{ lib, ... }:
{
options = {
value = lib.mkOption {
default = "12";
type = lib.types.coercedTo lib.types.str lib.toInt lib.types.ints.s8;
};
};
}

View File

@@ -0,0 +1,10 @@
{ lib, ... }:
{
options = {
value = lib.mkOption {
default = 42;
type = lib.types.coercedTo lib.types.int toString lib.types.str;
};
};
}

View File

@@ -0,0 +1,6 @@
{ lib, ... }:
{
options.value = lib.mkOption {
type = lib.types.either lib.types.int lib.types.str;
};
}

View File

@@ -0,0 +1,14 @@
{ lib, ... }:
{
options.set = {
enable = lib.mkOption {
default = false;
example = true;
type = lib.types.bool;
description = ''
Some descriptive text
'';
};
};
}

View File

@@ -0,0 +1,14 @@
{ lib, ... }:
{
options = {
enable = lib.mkOption {
default = false;
example = true;
type = lib.types.bool;
description = ''
Some descriptive text
'';
};
};
}

View File

@@ -0,0 +1,9 @@
{ lib, ... }:
{
options = {
value = lib.mkOption {
type = lib.types.ints.between (-21) 43;
};
};
}

View File

@@ -0,0 +1,9 @@
{ lib, ... }:
{
options.set = {
value = lib.mkOption {
type = lib.types.ints.positive;
};
};
}

View File

@@ -0,0 +1,9 @@
{ lib, ... }:
{
options = {
value = lib.mkOption {
type = lib.types.ints.positive;
};
};
}

View File

@@ -0,0 +1,9 @@
{ lib, ... }:
{
options = {
value = lib.mkOption {
type = lib.types.ints.unsigned;
};
};
}

View File

@@ -0,0 +1,7 @@
{ lib, ... }:
{
options.value = lib.mkOption {
type = lib.types.lazyAttrsOf (lib.types.str // { emptyValue.value = "empty"; });
default = { };
};
}

View File

@@ -0,0 +1,75 @@
{ lib, ... }:
let
pkgs.hello = {
type = "derivation";
pname = "hello";
};
in
{
options = {
package = lib.mkPackageOption pkgs "hello" { };
namedPackage = lib.mkPackageOption pkgs "Hello" {
default = [ "hello" ];
};
namedPackageSingletonDefault = lib.mkPackageOption pkgs "Hello" {
default = "hello";
};
pathPackage = lib.mkPackageOption pkgs [ "hello" ] { };
packageWithExample = lib.mkPackageOption pkgs "hello" {
example = "pkgs.hello.override { stdenv = pkgs.clangStdenv; }";
};
packageWithPathExample = lib.mkPackageOption pkgs "hello" {
example = [ "hello" ];
};
packageWithExtraDescription = lib.mkPackageOption pkgs "hello" {
extraDescription = "Example extra description.";
};
undefinedPackage = lib.mkPackageOption pkgs "hello" {
default = null;
};
nullablePackage = lib.mkPackageOption pkgs "hello" {
nullable = true;
default = null;
};
nullablePackageWithDefault = lib.mkPackageOption pkgs "hello" {
nullable = true;
};
packageWithPkgsText = lib.mkPackageOption pkgs "hello" {
pkgsText = "myPkgs";
};
packageFromOtherSet =
let
myPkgs = {
hello = pkgs.hello // {
pname = "hello-other";
};
};
in
lib.mkPackageOption myPkgs "hello" { };
packageInvalidIdentifier =
let
myPkgs."123"."with\"quote" = { inherit (pkgs) hello; };
in
lib.mkPackageOption myPkgs [ "123" "with\"quote" "hello" ] { };
packageInvalidIdentifierExample = lib.mkPackageOption pkgs "hello" {
example = [
"123"
"with\"quote"
"hello"
];
};
};
}

View File

@@ -0,0 +1,10 @@
{ lib, ... }:
{
options.value = lib.mkOption {
type = lib.types.oneOf [
lib.types.int
(lib.types.listOf lib.types.int)
lib.types.str
];
};
}

View File

@@ -0,0 +1,14 @@
{ lib, ... }:
{
options.set = lib.mkOption {
default = { };
example = {
a = 1;
};
type = lib.types.attrsOf lib.types.int;
description = ''
Some descriptive text
'';
};
}

View File

@@ -0,0 +1,35 @@
{ lib, ... }:
{
options.submodule = lib.mkOption {
inherit
(lib.evalModules {
modules = [
{
options.inner = lib.mkOption {
type = lib.types.bool;
default = false;
};
}
];
})
type
;
default = { };
};
config.submodule = lib.mkMerge [
(
{ lib, ... }:
{
options.outer = lib.mkOption {
type = lib.types.bool;
default = false;
};
}
)
{
inner = true;
outer = true;
}
];
}

View File

@@ -0,0 +1,32 @@
{ lib, ... }:
{
options.submodule = lib.mkOption {
type = lib.types.submoduleWith {
modules = [
{
options.inner = lib.mkOption {
type = lib.types.bool;
default = false;
};
}
];
};
default = { };
};
config.submodule = lib.mkMerge [
(
{ lib, ... }:
{
options.outer = lib.mkOption {
type = lib.types.bool;
default = false;
};
}
)
{
inner = true;
outer = true;
}
];
}

View File

@@ -0,0 +1,15 @@
{ lib, ... }:
let
sub.options.config = lib.mkOption {
type = lib.types.bool;
default = false;
};
in
{
options.submodule = lib.mkOption {
type = lib.types.submoduleWith {
modules = [ sub ];
};
default = { };
};
}

View File

@@ -0,0 +1,13 @@
{ lib, ... }:
{
options.submodule = lib.mkOption {
type = lib.types.submoduleWith {
modules = [
./declare-enable.nix
];
};
default = { };
};
config.submodule = ./define-enable.nix;
}

View File

@@ -0,0 +1,16 @@
{ lib, ... }:
let
sub.options.config = lib.mkOption {
type = lib.types.bool;
default = false;
};
in
{
options.submodule = lib.mkOption {
type = lib.types.submoduleWith {
modules = [ sub ];
shorthandOnlyDefinesConfig = true;
};
default = { };
};
}

View File

@@ -0,0 +1,21 @@
{ lib, ... }:
{
options.submodule = lib.mkOption {
type = lib.types.submoduleWith {
modules = [
(
{ lib, ... }:
{
options.foo = lib.mkOption {
default = lib.foo;
};
}
)
];
specialArgs.lib = lib // {
foo = "foo";
};
};
default = { };
};
}

View File

@@ -0,0 +1,10 @@
{ lib, moduleType, ... }:
let
inherit (lib) mkOption types;
in
{
options.variants = mkOption {
type = types.lazyAttrsOf moduleType;
default = { };
};
}

View File

@@ -0,0 +1,28 @@
{ lib, options, ... }:
let
foo = lib.mkOptionType {
name = "foo";
functor = lib.types.defaultFunctor "foo" // {
wrapped = lib.types.int;
payload = 10;
};
};
in
{
imports = [
{
options.foo = lib.mkOption {
type = foo;
};
}
{
options.foo = lib.mkOption {
type = foo;
};
}
];
options.result = lib.mkOption {
default = builtins.seq options.foo null;
};
}

View File

@@ -0,0 +1,15 @@
{
lib ? import ../..,
modules ? [ ],
}:
{
inherit
(lib.evalModules {
inherit modules;
specialArgs.modulesPath = ./.;
})
config
options
;
}

View File

@@ -0,0 +1,33 @@
{ config, lib, ... }:
let
inherit (lib)
types
mkOption
setDefaultModuleLocation
evalModules
;
inherit (types)
deferredModule
lazyAttrsOf
submodule
str
raw
enum
;
in
{
options = {
deferred = mkOption {
type = deferredModule;
};
result = mkOption {
default = (evalModules { modules = [ config.deferred ]; }).config.result;
};
};
config = {
deferred =
{ ... }:
# this should be an attrset, so this fails
true;
};
}

View File

@@ -0,0 +1,77 @@
{ lib, ... }:
let
inherit (lib) types mkOption setDefaultModuleLocation;
inherit (types)
deferredModule
lazyAttrsOf
submodule
str
raw
enum
;
in
{
imports = [
# generic module, declaring submodules:
# - nodes.<name>
# - default
# where all nodes include the default
(
{ config, ... }:
{
_file = "generic.nix";
options.nodes = mkOption {
type = lazyAttrsOf (submodule {
imports = [ config.default ];
});
default = { };
};
options.default = mkOption {
type = deferredModule;
default = { };
description = ''
Module that is included in all nodes.
'';
};
}
)
{
_file = "default-1.nix";
default =
{ config, ... }:
{
options.settingsDict = lib.mkOption {
type = lazyAttrsOf str;
default = { };
};
options.bottom = lib.mkOption { type = enum [ ]; };
};
}
{
_file = "default-a-is-b.nix";
default = ./define-settingsDict-a-is-b.nix;
}
{
_file = "nodes-foo.nix";
nodes.foo.settingsDict.b = "beta";
}
{
_file = "the-file-that-contains-the-bad-config.nix";
default.bottom = "bogus";
}
{
_file = "nodes-foo-c-is-a.nix";
nodes.foo =
{ config, ... }:
{
settingsDict.c = config.settingsDict.a;
};
}
];
}

View File

@@ -0,0 +1,7 @@
{ ... }:
{
config = {
_module.args.custom = true;
};
}

View File

@@ -0,0 +1,3 @@
{
attrsOfSub.bar.enable = true;
}

View File

@@ -0,0 +1,3 @@
{
attrsOfSub.bar = { };
}

View File

@@ -0,0 +1,5 @@
{ lib, ... }:
{
attrsOfSub.foo.enable = lib.mkForce false;
}

View File

@@ -0,0 +1,5 @@
{ config, lib, ... }:
{
attrsOfSub.foo.enable = lib.mkIf config.enable true;
}

View File

@@ -0,0 +1,3 @@
{
attrsOfSub.foo.enable = true;
}

View File

@@ -0,0 +1,7 @@
{ lib, ... }:
{
attrsOfSub.foo = lib.mkForce {
enable = false;
};
}

View File

@@ -0,0 +1,7 @@
{ config, lib, ... }:
{
attrsOfSub.foo = lib.mkIf config.enable {
enable = true;
};
}

View File

@@ -0,0 +1,3 @@
{
attrsOfSub.foo = { };
}

View File

@@ -0,0 +1,7 @@
{ lib, ... }:
{
attrsOfSub = lib.mkForce {
foo.enable = false;
};
}

View File

@@ -0,0 +1,7 @@
{ config, lib, ... }:
{
attrsOfSub = lib.mkIf config.enable {
foo.enable = true;
};
}

View File

@@ -0,0 +1,4 @@
{
bare-submodule.nested = 42;
bare-submodule.deep = 420;
}

View File

@@ -0,0 +1,3 @@
{
config.enable = abort "oops";
}

View File

@@ -0,0 +1,5 @@
{ lib, ... }:
{
enable = lib.mkForce false;
}

View File

@@ -0,0 +1,3 @@
{
config.enable = throw "oops";
}

View File

@@ -0,0 +1,7 @@
{ custom, ... }:
{
config = {
enable = custom;
};
}

View File

@@ -0,0 +1,5 @@
{ lib, ... }:
# I think this might occur more realistically in a submodule
{
imports = [ (lib.mkIf true { enable = true; }) ];
}

View File

@@ -0,0 +1,3 @@
{
enable = true;
}

View File

@@ -0,0 +1,5 @@
{ lib, ... }:
lib.mkForce {
attrsOfSub.foo.enable = false;
}

View File

@@ -0,0 +1,5 @@
{ lib, ... }:
lib.mkForce {
enable = false;
}

View File

@@ -0,0 +1,24 @@
{ config, ... }:
{
class = {
"just" = "data";
};
a = "one";
b = "two";
meta = "meta";
_module.args.result =
let
r = removeAttrs config [ "_module" ];
in
builtins.trace (builtins.deepSeq r r) (
r == {
a = "one";
b = "two";
class = {
"just" = "data";
};
meta = "meta";
}
);
}

View File

@@ -0,0 +1,5 @@
{ config, lib, ... }:
lib.mkIf config.enable {
attrsOfSub.foo.enable = true;
}

View File

@@ -0,0 +1,3 @@
{
_module.check = false;
}

View File

@@ -0,0 +1,16 @@
{ lib, options, ... }:
# Some modules may be distributed separately and need to adapt to other modules
# that are distributed and versioned separately.
{
# Always defined, but the value depends on the presence of an option.
config.set = {
value = if options ? set.enable then 360 else 7;
}
# Only define if possible.
// lib.optionalAttrs (options ? set.enable) {
enable = true;
};
}

View File

@@ -0,0 +1,16 @@
{ lib, options, ... }:
# Some modules may be distributed separately and need to adapt to other modules
# that are distributed and versioned separately.
{
# Always defined, but the value depends on the presence of an option.
config = {
value = if options ? enable then 360 else 7;
}
# Only define if possible.
// lib.optionalAttrs (options ? enable) {
enable = true;
};
}

View File

@@ -0,0 +1,4 @@
{ config, ... }:
{
settingsDict.a = config.settingsDict.b;
}

View File

@@ -0,0 +1 @@
{ shorthandOnlyDefinesConfig = true; }

View File

@@ -0,0 +1,3 @@
{
submodule.config.config = true;
}

View File

@@ -0,0 +1,3 @@
{
submodule.config = true;
}

View File

@@ -0,0 +1,3 @@
{
value = -23;
}

View File

@@ -0,0 +1,3 @@
{
value = 42;
}

View File

@@ -0,0 +1,3 @@
{
value = 0;
}

View File

@@ -0,0 +1,3 @@
{
value = [ ];
}

View File

@@ -0,0 +1,3 @@
{
value = "foobar";
}

View File

@@ -0,0 +1,3 @@
{
value = "1000";
}

View File

@@ -0,0 +1,15 @@
{ lib, ... }:
{
imports = [
{
value = lib.mkDefault "def";
}
];
value = lib.mkMerge [
(lib.mkIf false "nope")
"yes"
];
}

View File

@@ -0,0 +1,3 @@
{
value = "24";
}

View File

@@ -0,0 +1,27 @@
{ config, lib, ... }:
let
inherit (lib) types mkOption attrNames;
in
{
options = {
attrs = mkOption { type = types.attrsOf lib.types.int; };
result = mkOption { };
resultFoo = mkOption { };
resultFooBar = mkOption { };
resultFooFoo = mkOption { };
};
config = {
attrs.a = 1;
variants.foo.attrs.b = 1;
variants.bar.attrs.y = 1;
variants.foo.variants.bar.attrs.z = 1;
variants.foo.variants.foo.attrs.c = 3;
resultFoo = lib.concatMapStringsSep " " toString (attrNames config.variants.foo.attrs);
resultFooBar = lib.concatMapStringsSep " " toString (
attrNames config.variants.foo.variants.bar.attrs
);
resultFooFoo = lib.concatMapStringsSep " " toString (
attrNames config.variants.foo.variants.foo.attrs
);
};
}

View File

@@ -0,0 +1,93 @@
{ lib, ... }:
let
inherit (lib) types mkOption;
inherit (types)
# attrsOf uses attrsWith internally
attrsOf
listOf
unique
nullOr
functionTo
coercedTo
either
;
in
{
imports = [
# Module A
(
{ ... }:
{
options.attrsWith = mkOption {
type = attrsOf (listOf types.str);
};
options.mergedAttrsWith = mkOption {
type = attrsOf (listOf types.str);
};
options.listOf = mkOption {
type = listOf (listOf types.str);
};
options.mergedListOf = mkOption {
type = listOf (listOf types.str);
};
# unique
options.unique = mkOption {
type = unique { message = ""; } (listOf types.str);
};
options.mergedUnique = mkOption {
type = unique { message = ""; } (listOf types.str);
};
# nullOr
options.nullOr = mkOption {
type = nullOr (listOf types.str);
};
options.mergedNullOr = mkOption {
type = nullOr (listOf types.str);
};
# functionTo
options.functionTo = mkOption {
type = functionTo (listOf types.str);
};
options.mergedFunctionTo = mkOption {
type = functionTo (listOf types.str);
};
# coercedTo
# Note: coercedTo is a non-mergeable option-type
options.coercedTo = mkOption {
type = coercedTo (listOf types.str) lib.id (listOf types.str);
};
options.either = mkOption {
type = either (listOf types.str) (listOf types.str);
};
options.mergedEither = mkOption {
type = either (listOf types.str) (listOf types.str);
};
}
)
# Module B
(
{ ... }:
{
options.mergedAttrsWith = mkOption {
type = attrsOf (listOf types.str);
};
options.mergedListOf = mkOption {
type = listOf (listOf types.str);
};
options.mergedUnique = mkOption {
type = unique { message = ""; } (listOf types.str);
};
options.mergedNullOr = mkOption {
type = nullOr (listOf types.str);
};
options.mergedFunctionTo = mkOption {
type = functionTo (listOf types.str);
};
options.mergedEither = mkOption {
type = either (listOf types.str) (listOf types.str);
};
}
)
];
}

View File

@@ -0,0 +1,5 @@
{ ... }:
{
disabledModules = [ ./declare-enable.nix ];
}

View File

@@ -0,0 +1,5 @@
{ ... }:
{
disabledModules = [ (toString ./define-enable.nix) ];
}

View File

@@ -0,0 +1,5 @@
{ ... }:
{
disabledModules = [ ./define-enable.nix ];
}

View File

@@ -0,0 +1,8 @@
{ ... }:
{
disabledModules = [
"define-enable.nix"
"declare-enable.nix"
];
}

View File

@@ -0,0 +1,18 @@
{ lib, ... }:
let
inherit (lib) mkOption types;
moduleWithKey =
{ config, ... }:
{
config = {
enable = true;
};
};
in
{
imports = [
./declare-enable.nix
];
disabledModules = [ { } ];
}

View File

@@ -0,0 +1,34 @@
{ lib, ... }:
let
inherit (lib) mkOption types;
moduleWithKey = {
key = "disable-module-with-key.nix#moduleWithKey";
config = {
enable = true;
};
};
in
{
options = {
positive = mkOption {
type = types.submodule {
imports = [
./declare-enable.nix
moduleWithKey
];
};
default = { };
};
negative = mkOption {
type = types.submodule {
imports = [
./declare-enable.nix
moduleWithKey
];
disabledModules = [ moduleWithKey ];
};
default = { };
};
};
}

View File

@@ -0,0 +1,34 @@
{ lib, ... }:
let
inherit (lib) mkOption types;
moduleWithKey = {
key = 123;
config = {
enable = true;
};
};
in
{
options = {
positive = mkOption {
type = types.submodule {
imports = [
./declare-enable.nix
moduleWithKey
];
};
default = { };
};
negative = mkOption {
type = types.submodule {
imports = [
./declare-enable.nix
moduleWithKey
];
disabledModules = [ 123 ];
};
default = { };
};
};
}

View File

@@ -0,0 +1,5 @@
{
imports = [
../declare-enable.nix
];
}

View File

@@ -0,0 +1,7 @@
{
disabledModules = [
./bar.nix
];
}

View File

@@ -0,0 +1,7 @@
{
disabledModules = [
./foo.nix
];
}

View File

@@ -0,0 +1,5 @@
{
imports = [
../declare-enable.nix
];
}

View File

@@ -0,0 +1,8 @@
{
imports = [
./foo.nix
./bar.nix
];
enable = true;
}

View File

@@ -0,0 +1,25 @@
{ lib, ... }:
{
imports = [
(lib.doRename {
from = [
"a"
"b"
];
to = [
"c"
"d"
"e"
];
warn = true;
use = x: x;
visible = true;
})
];
options = {
c.d.e = lib.mkOption { };
};
config = {
a.b = 1234;
};
}

View File

@@ -0,0 +1,15 @@
{ config, ... }:
{
config = {
services.foo.enable = true;
services.foo.bar = "baz";
result =
assert
config.services.foos == {
"" = {
bar = "baz";
};
};
true;
};
}

View File

@@ -0,0 +1,15 @@
{ config, ... }:
{
config = {
services.foos."".bar = "baz";
result =
assert
config.services.foos == {
"" = {
bar = "baz";
};
};
assert config.services.foo.bar == "baz";
true;
};
}

View File

@@ -0,0 +1,9 @@
{ config, options, ... }:
{
config = {
result =
assert config.services.foos == { };
assert !options.services.foo.bar.isDefined;
true;
};
}

View File

@@ -0,0 +1,58 @@
/**
Simulate a migration from a single-instance `services.foo` to a multi instance
`services.foos.<name>` module, where `name = ""` serves as the legacy /
compatibility instance.
- No instances must exist, unless one is defined in the multi-instance module,
or if the legacy enable option is set to true.
- The legacy instance options must be renamed to the new instance, if it exists.
The relevant scenarios are tested in separate files:
- ./doRename-condition-enable.nix
- ./doRename-condition-no-enable.nix
*/
{ config, lib, ... }:
let
inherit (lib)
mkOption
mkEnableOption
types
doRename
;
in
{
options = {
services.foo.enable = mkEnableOption "foo";
services.foos = mkOption {
type = types.attrsOf (
types.submodule {
options = {
bar = mkOption { type = types.str; };
};
}
);
default = { };
};
result = mkOption { };
};
imports = [
(doRename {
from = [
"services"
"foo"
"bar"
];
to = [
"services"
"foos"
""
"bar"
];
visible = true;
warn = false;
use = x: x;
withPriority = true;
condition = config.services.foo.enable;
})
];
}

View File

@@ -0,0 +1,28 @@
{ lib, config, ... }:
{
imports = [
(lib.doRename {
from = [
"a"
"b"
];
to = [
"c"
"d"
"e"
];
warn = true;
use = x: x;
visible = true;
})
];
options = {
warnings = lib.mkOption { type = lib.types.listOf lib.types.str; };
c.d.e = lib.mkOption { };
result = lib.mkOption { };
};
config = {
a.b = 1234;
result = lib.concatStringsSep "%" config.warnings;
};
}

View File

@@ -0,0 +1,35 @@
/*
A basic documentation generating module.
Declares and defines a `docs` option, suitable for making assertions about
the extraction "phase" of documentation generation.
*/
{ lib, options, ... }:
let
inherit (lib)
head
length
mkOption
types
;
traceListSeq = l: v: lib.foldl' (a: b: lib.traceSeq b a) v l;
in
{
options.docs = mkOption {
type = types.lazyAttrsOf types.raw;
description = ''
All options to be rendered, without any visibility filtering applied.
'';
};
config.docs = lib.zipAttrsWith (
name: values:
if length values > 1 then
traceListSeq values abort "Multiple options with the same name: ${name}"
else
assert length values == 1;
head values
) (map (opt: { ${opt.name} = opt; }) (lib.optionAttrSetToDocList options));
}

Some files were not shown because too many files have changed in this diff Show More