diff --git a/lib/attrsets.nix b/lib/attrsets.nix index de5968b953485..b3bbc62c42bbd 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -7,7 +7,7 @@ let inherit (builtins) head length; inherit (lib.trivial) mergeAttrs warn; inherit (lib.strings) concatStringsSep concatMapStringsSep escapeNixIdentifier sanitizeDerivationName; - inherit (lib.lists) foldr foldl' concatMap elemAt all partition groupBy take foldl; + inherit (lib.lists) foldr foldl' concatMap elemAt all partition groupBy take foldl intersectLists; in rec { @@ -548,7 +548,7 @@ rec { `names` - : A list of attribute names to get out of `set` + : A list of attribute names to get out of `attrs` `attrs` @@ -575,6 +575,44 @@ rec { names: attrs: genAttrs names (name: attrs.${name}); + /** + Given a list of possible attribute names, return the set of + attribuets whose name is in the list from the given set. + + It works like `getAttrs` when the first attribute is a list, + but skip attributes not in the input set + instead of throwing the "attribute is missing" error. + + # Inputs + + `names` + + : A list of possible attribute names to get out of `attrs`. + + `attrs` + + : The set to get the existing named attribute from. + + # Type + + ``` + getOptionalAttrs :: [String] -> AttrSet -> AttrSet + ``` + + # Example + :::{.example} + + ## `lib.attrsets.getOptionalAttrs` usage example + ```nix + getOptionalAttrs [ "a" "b" "d" ] { a = 1; b = 2; c = 3; } + => { a = 1; b = 2; } + ``` + ::: + */ + getOptionalAttrs = + names: + attrs: getAttrs (intersectLists (attrNames attrs) names) attrs; + /** Collect each attribute named `attr` from a list of attribute sets. Sets that don't contain the named attribute are ignored. diff --git a/lib/default.nix b/lib/default.nix index 668c29640f9f1..63a491ddc4f60 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -79,7 +79,7 @@ let inherit (self.fixedPoints) fix fix' converge extends composeExtensions composeManyExtensions makeExtensible makeExtensibleWithCustomName; inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath - getAttrFromPath attrVals attrValues getAttrs catAttrs filterAttrs + getAttrFromPath attrVals attrValues getAttrs getOptionalAttrs catAttrs filterAttrs filterAttrsRecursive foldlAttrs foldAttrs collect nameValuePair mapAttrs mapAttrs' mapAttrsToList attrsToList concatMapAttrs mapAttrsRecursive mapAttrsRecursiveCond genAttrs isDerivation toDerivation optionalAttrs diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 6f1d9039db802..827c2a3aea905 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -52,6 +52,8 @@ let functionArgs generators genList + getAttrs + getOptionalAttrs getExe getExe' groupBy @@ -1854,6 +1856,45 @@ runTests { }; }; + testGetAttrsExample = { + expr = [ + (getAttrs [ "a" "b" ] { a = 1; b = 2; c = 3; }) + ]; + expected = [ + { a = 1; b = 2; } + ]; + }; + + testGetAttrsEmptyList = { + expr = getAttrs [ ] { a = 1; b = 2; c = 3; }; + expected = { }; + }; + + testGetAttrsEmpty = { + expr = getAttrs [ ] { }; + expected = { }; + }; + + testGetOptionalAttrsExample = { + expr = getOptionalAttrs [ "a" "b" "d" ] { a = 1; b = 2; c = 3; }; + expected = { a = 1; b = 2; }; + }; + + testGetOptionalAttrsEmptyNames = { + expr = getOptionalAttrs [ ] { a = 1; b = 2; c = 3; }; + expected = { }; + }; + + testGetOptionalAttrsEmptyValues = { + expr = getOptionalAttrs [ "a" "b" "d" ] { }; + expected = { }; + }; + + testGetOptionalAttrsEmpty = { + expr = getOptionalAttrs [ ] { }; + expected = { }; + }; + ## Levenshtein distance functions and co. testCommonPrefixLengthEmpty = { expr = strings.commonPrefixLength "" "hello";