Merge pull request #168778 from hercules-ci/issue-168767-extendModules-module-dedup-collision

`lib.types.submoduleWith`: Avoid `_key` collisions after `extendModules` (issue #168767)
This commit is contained in:
Robert Hensing 2022-04-26 13:01:28 +02:00 committed by GitHub
commit 27a62a9c60
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 4 deletions

View file

@ -113,6 +113,10 @@ rec {
args ? {} args ? {}
, # This would be remove in the future, Prefer _module.check option instead. , # This would be remove in the future, Prefer _module.check option instead.
check ? true check ? true
# Internal variable to avoid `_key` collisions regardless
# of `extendModules`. Used in `submoduleWith`.
# Test case: lib/tests/modules, "168767"
, extensionOffset ? 0
}: }:
let let
withWarnings = x: withWarnings = x:
@ -338,15 +342,17 @@ rec {
modules ? [], modules ? [],
specialArgs ? {}, specialArgs ? {},
prefix ? [], prefix ? [],
extensionOffset ? length modules,
}: }:
evalModules (evalModulesArgs // { evalModules (evalModulesArgs // {
modules = regularModules ++ modules; modules = regularModules ++ modules;
specialArgs = evalModulesArgs.specialArgs or {} // specialArgs; specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
prefix = extendArgs.prefix or evalModulesArgs.prefix; prefix = extendArgs.prefix or evalModulesArgs.prefix;
inherit extensionOffset;
}); });
type = lib.types.submoduleWith { type = lib.types.submoduleWith {
inherit modules specialArgs; inherit modules specialArgs extensionOffset;
}; };
result = withWarnings { result = withWarnings {

View file

@ -293,7 +293,7 @@ checkConfigOutput '^"a c"$' config.result ./functionTo/merging-attrs.nix
# moduleType # moduleType
checkConfigOutput '^"a b"$' config.resultFoo ./declare-variants.nix ./define-variant.nix checkConfigOutput '^"a b"$' config.resultFoo ./declare-variants.nix ./define-variant.nix
checkConfigOutput '^"a y z"$' config.resultFooBar ./declare-variants.nix ./define-variant.nix checkConfigOutput '^"a b y z"$' config.resultFooBar ./declare-variants.nix ./define-variant.nix
checkConfigOutput '^"a b c"$' config.resultFooFoo ./declare-variants.nix ./define-variant.nix checkConfigOutput '^"a b c"$' config.resultFooFoo ./declare-variants.nix ./define-variant.nix
## emptyValue's ## emptyValue's
@ -327,6 +327,10 @@ checkConfigError 'The option .theOption.nested. in .other.nix. is already declar
# Test that types.optionType leaves types untouched as long as they don't need to be merged # Test that types.optionType leaves types untouched as long as they don't need to be merged
checkConfigOutput 'ok' config.freeformItems.foo.bar ./adhoc-freeformType-survives-type-merge.nix checkConfigOutput 'ok' config.freeformItems.foo.bar ./adhoc-freeformType-survives-type-merge.nix
# Anonymous submodules don't get nixed by import resolution/deduplication
# because of an `extendModules` bug, issue 168767.
checkConfigOutput '^1$' config.sub.specialisation.value ./extendModules-168767-imports.nix
cat <<EOF cat <<EOF
====== module tests ====== ====== module tests ======
$pass Pass $pass Pass

View file

@ -0,0 +1,41 @@
{ lib
, extendModules
, ...
}:
with lib;
{
imports = [
{
options.sub = mkOption {
default = { };
type = types.submodule (
{ config
, extendModules
, ...
}:
{
options.value = mkOption {
type = types.int;
};
options.specialisation = mkOption {
default = { };
inherit
(extendModules {
modules = [{
specialisation = mkOverride 0 { };
}];
})
type;
};
}
);
};
}
{ config.sub.value = 1; }
];
}

View file

@ -568,6 +568,11 @@ rec {
{ modules { modules
, specialArgs ? {} , specialArgs ? {}
, shorthandOnlyDefinesConfig ? false , shorthandOnlyDefinesConfig ? false
# Internal variable to avoid `_key` collisions regardless
# of `extendModules`. Wired through by `evalModules`.
# Test case: lib/tests/modules, "168767"
, extensionOffset ? 0
}@attrs: }@attrs:
let let
inherit (lib.modules) evalModules; inherit (lib.modules) evalModules;
@ -579,11 +584,11 @@ rec {
allModules = defs: imap1 (n: { value, file }: allModules = defs: imap1 (n: { value, file }:
if isFunction value if isFunction value
then setFunctionArgs then setFunctionArgs
(args: lib.modules.unifyModuleSyntax file "${toString file}-${toString n}" (value args)) (args: lib.modules.unifyModuleSyntax file "${toString file}-${toString (n + extensionOffset)}" (value args))
(functionArgs value) (functionArgs value)
else if isAttrs value else if isAttrs value
then then
lib.modules.unifyModuleSyntax file "${toString file}-${toString n}" (shorthandToModule value) lib.modules.unifyModuleSyntax file "${toString file}-${toString (n + extensionOffset)}" (shorthandToModule value)
else value else value
) defs; ) defs;
@ -620,6 +625,7 @@ rec {
(base.extendModules { (base.extendModules {
modules = [ { _module.args.name = last loc; } ] ++ allModules defs; modules = [ { _module.args.name = last loc; } ] ++ allModules defs;
prefix = loc; prefix = loc;
extensionOffset = extensionOffset + length defs;
}).config; }).config;
emptyValue = { value = {}; }; emptyValue = { value = {}; };
getSubOptions = prefix: (base.extendModules getSubOptions = prefix: (base.extendModules