From 73f32d03758a53ad1baac31795cfd99e325032f3 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 28 Oct 2013 19:48:30 +0100 Subject: Show precise error messages in option merge failures For instance, if time.timeZone is defined multiple times, you now get the error message: error: user-thrown exception: The unique option `time.timeZone' is defined multiple times, in `/etc/nixos/configurations/misc/eelco/x11vnc.nix' and `/etc/nixos/configuration.nix'. while previously you got: error: user-thrown exception: Multiple definitions of string. Only one is allowed for this option. and only an inspection of the stack trace gave a clue as to what option caused the problem. --- lib/options.nix | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'lib/options.nix') diff --git a/lib/options.nix b/lib/options.nix index d649d1160a0..66957bc7f15 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -35,7 +35,7 @@ rec { addDefaultOptionValues = defs: opts: opts // builtins.listToAttrs (map (defName: { name = defName; - value = + value = let defValue = builtins.getAttr defName defs; optValue = builtins.getAttr defName opts; @@ -49,27 +49,26 @@ rec { else # `defValue' is an attribute set containing options. # So recurse. - if hasAttr defName opts && isAttrs optValue + if hasAttr defName opts && isAttrs optValue then addDefaultOptionValues defValue optValue else addDefaultOptionValues defValue {}; } ) (attrNames defs)); - mergeDefaultOption = list: + mergeDefaultOption = args: list: if length list == 1 then head list - else if all builtins.isFunction list then x: mergeDefaultOption (map (f: f x) list) + else if all builtins.isFunction list then x: mergeDefaultOption args (map (f: f x) list) else if all isList list then concatLists list else if all isAttrs list then fold lib.mergeAttrs {} list else if all builtins.isBool list then fold lib.or false list else if all builtins.isString list then lib.concatStrings list - else if all builtins.isInt list && all (x: x == head list) list - then head list - else throw "Cannot merge values."; + else if all builtins.isInt list && all (x: x == head list) list then head list + else throw "Cannot merge definitions of `${showOption args.prefix}' given in ${showFiles args.files}."; /* Obsolete, will remove soon. Specify an option type or apply function instead. */ - mergeTypedOption = typeName: predicate: merge: list: + mergeTypedOption = typeName: predicate: merge: args: list: if all predicate list then merge list else throw "Expect a ${typeName}."; @@ -82,9 +81,10 @@ rec { (x: if builtins ? isString then builtins.isString x else x + "") lib.concatStrings; - mergeOneOption = list: + mergeOneOption = args: list: if list == [] then abort "This case should never happen." - else if length list != 1 then throw "Multiple definitions. Only one is allowed for this option." + else if length list != 1 then + throw "The unique option `${showOption args.prefix}' is defined multiple times, in ${showFiles args.files}." else head list; @@ -135,6 +135,7 @@ rec { /* Helper functions. */ showOption = concatStringsSep "."; + showFiles = files: concatStringsSep " and " (map (f: "`${f}'") files); unknownModule = ""; } -- cgit 1.4.1