Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions lib/modules.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ let
any
attrByPath
attrNames
attrValues
catAttrs
concatLists
concatMap
Expand Down Expand Up @@ -760,11 +761,37 @@ let
# 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
# track before in order to prevent infinite recursion. So this only
# warns once per type name.
# Returns the new set of track type names

in warnDeprecation opt //
maybeDeprecationWarning =
let
recurse = level: track: type:
if type ? recursiveId && track.recursive ? ${type.recursiveId} then
track
else if level > 10 then
track // { potentialInfiniteRecursion = true; }
else
foldl'
(recurse (level + 1))
(track // warnIf
(! track.visited ? ${type.name} && type.deprecationMessage != null)
"The type `types.${type.name}' of option `${showOption loc}' defined in ${showFiles opt.declarations} is deprecated. ${type.deprecationMessage}" {
visited =
track.visited // { ${type.name} = null; };
recursive = track.recursive // lib.optionalAttrs (type ? recursiveId) { ${type.recursiveId} = null; };
})
(attrValues type.nestedTypes);
result = recurse 0 { visited = { }; recursive = { }; potentialInfiniteRecursion = false; } opt.type;
in
warnIf (result.potentialInfiniteRecursion)
"The type of option `${showOption loc}' defined in ${showFiles opt.declarations} might have infinitely nested different types: ${toString (attrNames result.visited)}"
result;

in builtins.seq maybeDeprecationWarning opt //
{ value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
inherit (res.defsFinal') highestPrio;
definitions = map (def: def.value) res.defsFinal;
Expand Down
15 changes: 9 additions & 6 deletions lib/types.nix
Original file line number Diff line number Diff line change
Expand Up @@ -436,12 +436,10 @@ rec {

# Deprecated; should not be used because it quietly concatenates
# strings, which is usually not what you want.
# We use a lib.warn because `deprecationMessage` doesn't trigger in nested types such as `attrsOf string`
string = lib.warn
"The type `types.string` is deprecated. See https://github.com/NixOS/nixpkgs/pull/66346 for better alternative types."
(separatedString "" // {
name = "string";
});
string = separatedString "" // {
name = "string";
deprecationMessage = "See https://github.com/NixOS/nixpkgs/pull/66346 for better alternative types.";
};

passwdEntry = entryType: addCheck entryType (str: !(hasInfix ":" str || hasInfix "\n" str)) // {
name = "passwdEntry ${entryType.name}";
Expand Down Expand Up @@ -850,6 +848,11 @@ rec {
functor = (defaultFunctor name) // { payload = values; binOp = a: b: unique (a ++ b); };
};

fix = f:
let
result = lib.mapAttrs (name: value: value // { recursiveId = name; }) (f result);
in result;

# Either value of type `t1` or `t2`.
either = t1: t2: mkOptionType rec {
name = "either";
Expand Down
6 changes: 3 additions & 3 deletions nixos/modules/services/games/freeciv.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ let
inherit (config.users) groups;
rootDir = "/run/freeciv";
argsFormat = {
type = with lib.types; let
type = with lib.types; (fix (final: {
valueType = nullOr (oneOf [
bool int float str
(listOf valueType)
(listOf final.valueType)
]) // {
description = "freeciv-server params";
};
in valueType;
})).valueType;
generate = name: value:
let mkParam = k: v:
if v == null then []
Expand Down
5 changes: 3 additions & 2 deletions nixos/modules/services/mail/davmail.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ let

cfg = config.services.davmail;

configType = with types;
oneOf [ (attrsOf configType) str int bool ] // {
configType = with types; (fix (final: {
valueType = oneOf [ (attrsOf final.valueType) str int bool ] // {
description = "davmail config type (str, int, bool or attribute set thereof)";
};
})).valueType;

toStr = val: if isBool val then boolToString val else toString val;

Expand Down
2 changes: 1 addition & 1 deletion nixos/modules/services/networking/privoxy.nix
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let
else "${name} ${toString val}\n";

configType = with types;
let atom = oneOf [ int bool string path ];
let atom = oneOf [ int bool str path ];
in attrsOf (either atom (listOf atom))
// { description = ''
privoxy configuration type. The format consists of an attribute
Expand Down
9 changes: 5 additions & 4 deletions nixos/modules/services/networking/unbound.nix
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,19 @@ in {
default = {};
type = with types; submodule {

freeformType = let
freeformType = (types.fix (final: {
validSettingsPrimitiveTypes = oneOf [ int str bool float ];
validSettingsTypes = oneOf [ validSettingsPrimitiveTypes (listOf validSettingsPrimitiveTypes) ];
settingsType = oneOf [ str (attrsOf validSettingsTypes) ];
in attrsOf (oneOf [ settingsType (listOf settingsType) ])
validSettingsTypes = oneOf [ final.validSettingsPrimitiveTypes (listOf final.validSettingsPrimitiveTypes) ];
settingsType = oneOf [ str (attrsOf final.validSettingsTypes) ];
result = attrsOf (oneOf [ final.settingsType (listOf final.settingsType) ])
// { description = ''
unbound.conf configuration type. The format consist of an attribute
set of settings. Each settings can be either one value, a list of
values or an attribute set. The allowed values are integers,
strings, booleans or floats.
'';
};
})).result;

options = {
remote-control.control-enable = mkOption {
Expand Down
6 changes: 3 additions & 3 deletions nixos/modules/services/web-apps/akkoma.nix
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ let
inherit (str) merge;
};

elixirValue = let
elixirValue = (types.fix (final: {
elixirValue' = with types;
nullOr (oneOf [ bool int float str (attrsOf elixirValue') (listOf elixirValue') ]) // {
nullOr (oneOf [ bool int float str (attrsOf final.elixirValue') (listOf final.elixirValue') ]) // {
description = "Elixir value";
};
in elixirValue';
})).elixirValue';

frontend = {
options = {
Expand Down
41 changes: 20 additions & 21 deletions pkgs/pkgs-lib/formats.nix
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,19 @@ rec {

json = {}: {

type = with lib.types; let
type = with lib.types; (fix (final: {
valueType = nullOr (oneOf [
bool
int
float
str
path
(attrsOf valueType)
(listOf valueType)
(attrsOf final.valueType)
(listOf final.valueType)
]) // {
description = "JSON value";
};
in valueType;
})).valueType;

generate = name: value: pkgs.callPackage ({ runCommand, jq }: runCommand name {
nativeBuildInputs = [ jq ];
Expand All @@ -70,19 +70,19 @@ rec {
json2yaml "$valuePath" "$out"
'') {};

type = with lib.types; let
type = with lib.types; (fix (final: {
valueType = nullOr (oneOf [
bool
int
float
str
path
(attrsOf valueType)
(listOf valueType)
(attrsOf final.valueType)
(listOf final.valueType)
]) // {
description = "YAML value";
};
in valueType;
})).valueType;

};

Expand Down Expand Up @@ -196,19 +196,19 @@ rec {
};

toml = {}: json {} // {
type = with lib.types; let
type = with lib.types; (fix (final: {
valueType = oneOf [
bool
int
float
str
path
(attrsOf valueType)
(listOf valueType)
(attrsOf final.valueType)
(listOf final.valueType)
] // {
description = "TOML value";
};
in valueType;
})).valueType;

generate = name: value: pkgs.callPackage ({ runCommand, remarshal }: runCommand name {
nativeBuildInputs = [ remarshal ];
Expand Down Expand Up @@ -310,20 +310,19 @@ rec {
'';
in
{
type = with lib.types; let
type = with lib.types; attrsOf (attrsOf (fix (final: {
valueType = nullOr
(oneOf [
bool
int
float
str
(attrsOf valueType)
(listOf valueType)
(attrsOf final.valueType)
(listOf final.valueType)
]) // {
description = "Elixir value";
};
in
attrsOf (attrsOf (valueType));
})).valueType);

lib =
let
Expand Down Expand Up @@ -420,19 +419,19 @@ rec {
# Outputs a succession of Python variable assignments
# Useful for many Django-based services
pythonVars = {}: {
type = with lib.types; let
type = with lib.types; attrsOf (types.fix (final: {
valueType = nullOr(oneOf [
bool
float
int
path
str
(attrsOf valueType)
(listOf valueType)
(attrsOf final.valueType)
(listOf final.valueType)
]) // {
description = "Python value";
};
in attrsOf valueType;
})).valueType;
generate = name: value: pkgs.callPackage ({ runCommand, python3, black }: runCommand name {
nativeBuildInputs = [ python3 black ];
value = builtins.toJSON value;
Expand Down