Merge pull request #99132 from Infinisil/recursive-type-deprecation
Recursive type deprecation
This commit is contained in:
commit
ce93c98ce2
7 changed files with 83 additions and 11 deletions
|
@ -515,11 +515,20 @@ rec {
|
|||
# yield a value computed from the definitions
|
||||
value = if opt ? apply then opt.apply res.mergedValue else res.mergedValue;
|
||||
|
||||
warnDeprecation =
|
||||
warnIf (opt.type.deprecationMessage != null)
|
||||
"The type `types.${opt.type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${opt.type.deprecationMessage}";
|
||||
# Issue deprecation warnings recursively over all nested types of the
|
||||
# given type. But don't recurse if a type with the same name was already
|
||||
# visited before in order to prevent infinite recursion. So this only
|
||||
# warns once per type name.
|
||||
# Returns the new set of visited type names
|
||||
recursiveWarn = visited: type:
|
||||
let
|
||||
maybeWarn = warnIf (type.deprecationMessage != null)
|
||||
"The type `types.${type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${type.deprecationMessage}";
|
||||
in
|
||||
if visited ? ${type.name} then visited
|
||||
else lib.foldl' recursiveWarn (maybeWarn visited // { ${type.name} = null; }) (lib.attrValues type.nestedTypes);
|
||||
|
||||
in warnDeprecation opt //
|
||||
in builtins.seq (recursiveWarn {} opt.type) opt //
|
||||
{ value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
|
||||
inherit (res.defsFinal') highestPrio;
|
||||
definitions = map (def: def.value) res.defsFinal;
|
||||
|
|
|
@ -175,6 +175,9 @@ checkConfigOutput "true" config.submodule.config ./declare-submoduleWith-noshort
|
|||
## submoduleWith should merge all modules in one swoop
|
||||
checkConfigOutput "true" config.submodule.inner ./declare-submoduleWith-modules.nix
|
||||
checkConfigOutput "true" config.submodule.outer ./declare-submoduleWith-modules.nix
|
||||
# Should also be able to evaluate the type name (which evaluates freeformType,
|
||||
# which evaluates all the modules defined by the type)
|
||||
checkConfigOutput "submodule" options.submodule.type.description ./declare-submoduleWith-modules.nix
|
||||
|
||||
## Paths should be allowed as values and work as expected
|
||||
checkConfigOutput "true" config.submodule.enable ./declare-submoduleWith-path.nix
|
||||
|
@ -269,6 +272,12 @@ checkConfigError 'A definition for option .fun.\[function body\]. is not of type
|
|||
checkConfigOutput "b a" config.result ./functionTo/list-order.nix
|
||||
checkConfigOutput "a c" config.result ./functionTo/merging-attrs.nix
|
||||
|
||||
## Type deprecation
|
||||
checkConfigError 'The type `types.simple'\'' of option `simple'\'' defined in .* is deprecated. simple shall not be used' config.simple ./type-deprecation.nix
|
||||
checkConfigError 'The type `types.infinite'\'' of option `infinite'\'' defined in .* is deprecated. infinite shall not be used' config.infinite ./type-deprecation.nix
|
||||
checkConfigError 'The type `types.left'\'' of option `nested'\'' defined in .* is deprecated. left shall not be used' config.nested ./type-deprecation.nix
|
||||
checkConfigError 'The type `types.right'\'' of option `nested'\'' defined in .* is deprecated. right shall not be used' config.nested ./type-deprecation.nix
|
||||
|
||||
cat <<EOF
|
||||
====== module tests ======
|
||||
$pass Pass
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
default = false;
|
||||
};
|
||||
}
|
||||
{
|
||||
outer = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
default = {};
|
||||
|
@ -25,6 +22,7 @@
|
|||
})
|
||||
{
|
||||
inner = true;
|
||||
outer = true;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
|
39
lib/tests/modules/type-deprecation.nix
Normal file
39
lib/tests/modules/type-deprecation.nix
Normal file
|
@ -0,0 +1,39 @@
|
|||
{ lib, ... }: {
|
||||
|
||||
options.simple = lib.mkOption {
|
||||
type = lib.mkOptionType {
|
||||
name = "simple";
|
||||
deprecationMessage = "simple shall not be used";
|
||||
};
|
||||
default = throw "";
|
||||
};
|
||||
|
||||
options.infinite = lib.mkOption {
|
||||
type =
|
||||
let
|
||||
t = lib.mkOptionType {
|
||||
name = "infinite";
|
||||
deprecationMessage = "infinite shall not be used";
|
||||
};
|
||||
r = lib.types.either t (lib.types.attrsOf r);
|
||||
in r;
|
||||
default = throw "";
|
||||
};
|
||||
|
||||
options.nested = lib.mkOption {
|
||||
type =
|
||||
let
|
||||
left = lib.mkOptionType {
|
||||
name = "left";
|
||||
deprecationMessage = "left shall not be used";
|
||||
};
|
||||
right = lib.mkOptionType {
|
||||
name = "right";
|
||||
deprecationMessage = "right shall not be used";
|
||||
};
|
||||
in lib.types.either left right;
|
||||
|
||||
default = throw "";
|
||||
};
|
||||
|
||||
}
|
|
@ -147,9 +147,13 @@ rec {
|
|||
, # The deprecation message to display when this type is used by an option
|
||||
# If null, the type isn't deprecated
|
||||
deprecationMessage ? null
|
||||
, # The types that occur in the definition of this type. This is used to
|
||||
# issue deprecation warnings recursively. Can also be used to reuse
|
||||
# nested types
|
||||
nestedTypes ? {}
|
||||
}:
|
||||
{ _type = "option-type";
|
||||
inherit name check merge emptyValue getSubOptions getSubModules substSubModules typeMerge functor deprecationMessage;
|
||||
inherit name check merge emptyValue getSubOptions getSubModules substSubModules typeMerge functor deprecationMessage nestedTypes;
|
||||
description = if description == null then name else description;
|
||||
};
|
||||
|
||||
|
@ -365,6 +369,7 @@ rec {
|
|||
getSubModules = elemType.getSubModules;
|
||||
substSubModules = m: listOf (elemType.substSubModules m);
|
||||
functor = (defaultFunctor name) // { wrapped = elemType; };
|
||||
nestedTypes.elemType = elemType;
|
||||
};
|
||||
|
||||
nonEmptyListOf = elemType:
|
||||
|
@ -389,6 +394,7 @@ rec {
|
|||
getSubModules = elemType.getSubModules;
|
||||
substSubModules = m: attrsOf (elemType.substSubModules m);
|
||||
functor = (defaultFunctor name) // { wrapped = elemType; };
|
||||
nestedTypes.elemType = elemType;
|
||||
};
|
||||
|
||||
# A version of attrsOf that's lazy in its values at the expense of
|
||||
|
@ -413,6 +419,7 @@ rec {
|
|||
getSubModules = elemType.getSubModules;
|
||||
substSubModules = m: lazyAttrsOf (elemType.substSubModules m);
|
||||
functor = (defaultFunctor name) // { wrapped = elemType; };
|
||||
nestedTypes.elemType = elemType;
|
||||
};
|
||||
|
||||
# TODO: drop this in the future:
|
||||
|
@ -421,6 +428,7 @@ rec {
|
|||
deprecationMessage = "Mixing lists with attribute values is no longer"
|
||||
+ " possible; please use `types.attrsOf` instead. See"
|
||||
+ " https://github.com/NixOS/nixpkgs/issues/1800 for the motivation.";
|
||||
nestedTypes.elemType = elemType;
|
||||
};
|
||||
|
||||
# Value of given type but with no merging (i.e. `uniq list`s are not concatenated).
|
||||
|
@ -433,6 +441,7 @@ rec {
|
|||
getSubModules = elemType.getSubModules;
|
||||
substSubModules = m: uniq (elemType.substSubModules m);
|
||||
functor = (defaultFunctor name) // { wrapped = elemType; };
|
||||
nestedTypes.elemType = elemType;
|
||||
};
|
||||
|
||||
# Null or value of ...
|
||||
|
@ -451,6 +460,7 @@ rec {
|
|||
getSubModules = elemType.getSubModules;
|
||||
substSubModules = m: nullOr (elemType.substSubModules m);
|
||||
functor = (defaultFunctor name) // { wrapped = elemType; };
|
||||
nestedTypes.elemType = elemType;
|
||||
};
|
||||
|
||||
functionTo = elemType: mkOptionType {
|
||||
|
@ -535,6 +545,9 @@ rec {
|
|||
substSubModules = m: submoduleWith (attrs // {
|
||||
modules = m;
|
||||
});
|
||||
nestedTypes = lib.optionalAttrs (freeformType != null) {
|
||||
freeformType = freeformType;
|
||||
};
|
||||
functor = defaultFunctor name // {
|
||||
type = types.submoduleWith;
|
||||
payload = {
|
||||
|
@ -596,6 +609,8 @@ rec {
|
|||
then functor.type mt1 mt2
|
||||
else null;
|
||||
functor = (defaultFunctor name) // { wrapped = [ t1 t2 ]; };
|
||||
nestedTypes.left = t1;
|
||||
nestedTypes.right = t2;
|
||||
};
|
||||
|
||||
# Any of the types in the given list
|
||||
|
@ -627,6 +642,8 @@ rec {
|
|||
substSubModules = m: coercedTo coercedType coerceFunc (finalType.substSubModules m);
|
||||
typeMerge = t1: t2: null;
|
||||
functor = (defaultFunctor name) // { wrapped = finalType; };
|
||||
nestedTypes.coercedType = coercedType;
|
||||
nestedTypes.finalType = finalType;
|
||||
};
|
||||
|
||||
# Obsolete alternative to configOf. It takes its option
|
||||
|
|
|
@ -37,7 +37,7 @@ in
|
|||
enableProfilePath = mkEnableOption "exposing the Disnix profiles in the system's PATH";
|
||||
|
||||
profiles = mkOption {
|
||||
type = types.listOf types.string;
|
||||
type = types.listOf types.str;
|
||||
default = [ "default" ];
|
||||
example = [ "default" ];
|
||||
description = "Names of the Disnix profiles to expose in the system's PATH";
|
||||
|
|
|
@ -112,7 +112,7 @@ let
|
|||
http://tools.ietf.org/html/rfc4366#section-3.1
|
||||
'';
|
||||
};
|
||||
name = mkOpt types.string ''
|
||||
name = mkOpt types.str ''
|
||||
Name of the remote read config, which if specified must be unique among remote read configs.
|
||||
The name will be used in metrics and logging in place of a generated value to help users distinguish between
|
||||
remote read configs.
|
||||
|
@ -174,7 +174,7 @@ let
|
|||
write_relabel_configs = mkOpt (types.listOf promTypes.relabel_config) ''
|
||||
List of remote write relabel configurations.
|
||||
'';
|
||||
name = mkOpt types.string ''
|
||||
name = mkOpt types.str ''
|
||||
Name of the remote write config, which if specified must be unique among remote write configs.
|
||||
The name will be used in metrics and logging in place of a generated value to help users distinguish between
|
||||
remote write configs.
|
||||
|
|
Loading…
Reference in a new issue