Merge pull request #208168 from hercules-ci/lib-types-string-coercions

`types.path`: Do not allow lists of strings

authored by

Robert Hensing and committed by
GitHub
70dab284 1ca08d4c

+38 -14
+5 -3
lib/default.nix
··· 63 63 64 64 inherit (builtins) add addErrorContext attrNames concatLists 65 65 deepSeq elem elemAt filter genericClosure genList getAttr 66 - hasAttr head isAttrs isBool isInt isList isString length 66 + hasAttr head isAttrs isBool isInt isList isPath isString length 67 67 lessThan listToAttrs pathExists readFile replaceStrings seq 68 68 stringLength sub substring tail trace; 69 69 inherit (self.trivial) id const pipe concat or and bitAnd bitOr bitXor ··· 96 96 concatImapStringsSep makeSearchPath makeSearchPathOutput 97 97 makeLibraryPath makeBinPath optionalString 98 98 hasInfix hasPrefix hasSuffix stringToCharacters stringAsChars escape 99 - escapeShellArg escapeShellArgs isValidPosixName toShellVar toShellVars 99 + escapeShellArg escapeShellArgs 100 + isStorePath isStringLike 101 + isValidPosixName toShellVar toShellVars 100 102 escapeRegex escapeXML replaceChars lowerChars 101 103 upperChars toLower toUpper addContextFrom splitString 102 104 removePrefix removeSuffix versionOlder versionAtLeast 103 105 getName getVersion 104 106 mesonOption mesonBool mesonEnable 105 107 nameFromURL enableFeature enableFeatureAs withFeature 106 - withFeatureAs fixedWidthString fixedWidthNumber isStorePath 108 + withFeatureAs fixedWidthString fixedWidthNumber 107 109 toInt toIntBase10 readPathsFromFile fileContents; 108 110 inherit (self.stringsWithDeps) textClosureList textClosureMap 109 111 noDepEntry fullDepEntry packEntry stringAfter;
+28 -6
lib/strings.nix
··· 18 18 isInt 19 19 isList 20 20 isAttrs 21 + isPath 21 22 isString 22 23 match 23 24 parseDrvName ··· 395 396 */ 396 397 toShellVar = name: value: 397 398 lib.throwIfNot (isValidPosixName name) "toShellVar: ${name} is not a valid shell variable name" ( 398 - if isAttrs value && ! isCoercibleToString value then 399 + if isAttrs value && ! isStringLike value then 399 400 "declare -A ${name}=(${ 400 401 concatStringsSep " " (lib.mapAttrsToList (n: v: 401 402 "[${escapeShellArg n}]=${escapeShellArg v}" ··· 798 799 in lib.warnIf (!precise) "Imprecise conversion from float to string ${result}" 799 800 result; 800 801 801 - /* Check whether a value can be coerced to a string */ 802 - isCoercibleToString = x: 803 - elem (typeOf x) [ "path" "string" "null" "int" "float" "bool" ] || 804 - (isList x && lib.all isCoercibleToString x) || 802 + /* Soft-deprecated function. While the original implementation is available as 803 + isConvertibleWithToString, consider using isStringLike instead, if suitable. */ 804 + isCoercibleToString = lib.warnIf (lib.isInOldestRelease 2305) 805 + "lib.strings.isCoercibleToString is deprecated in favor of either isStringLike or isConvertibleWithToString. Only use the latter if it needs to return true for null, numbers, booleans and list of similarly coercibles." 806 + isConvertibleWithToString; 807 + 808 + /* Check whether a list or other value can be passed to toString. 809 + 810 + Many types of value are coercible to string this way, including int, float, 811 + null, bool, list of similarly coercible values. 812 + */ 813 + isConvertibleWithToString = x: 814 + isStringLike x || 815 + elem (typeOf x) [ "null" "int" "float" "bool" ] || 816 + (isList x && lib.all isConvertibleWithToString x); 817 + 818 + /* Check whether a value can be coerced to a string. 819 + The value must be a string, path, or attribute set. 820 + 821 + String-like values can be used without explicit conversion in 822 + string interpolations and in most functions that expect a string. 823 + */ 824 + isStringLike = x: 825 + isString x || 826 + isPath x || 805 827 x ? outPath || 806 828 x ? __toString; 807 829 ··· 818 840 => false 819 841 */ 820 842 isStorePath = x: 821 - if !(isList x) && isCoercibleToString x then 843 + if isStringLike x then 822 844 let str = toString x; in 823 845 substring 0 1 str == "/" 824 846 && dirOf str == storeDir
+3 -3
lib/types.nix
··· 54 54 concatStringsSep 55 55 escapeNixString 56 56 hasInfix 57 - isCoercibleToString 57 + isStringLike 58 58 ; 59 59 inherit (lib.trivial) 60 60 boolToString ··· 227 227 merge = loc: defs: 228 228 let 229 229 getType = value: 230 - if isAttrs value && isCoercibleToString value 230 + if isAttrs value && isStringLike value 231 231 then "stringCoercibleSet" 232 232 else builtins.typeOf value; 233 233 ··· 479 479 path = mkOptionType { 480 480 name = "path"; 481 481 descriptionClass = "noun"; 482 - check = x: isCoercibleToString x && builtins.substring 0 1 (toString x) == "/"; 482 + check = x: isStringLike x && builtins.substring 0 1 (toString x) == "/"; 483 483 merge = mergeEqualOption; 484 484 }; 485 485
+1 -1
nixos/modules/services/misc/nix-daemon.nix
··· 42 42 else if isDerivation v then toString v 43 43 else if builtins.isPath v then toString v 44 44 else if isString v then v 45 - else if strings.isCoercibleToString v then toString v 45 + else if strings.isConvertibleWithToString v then toString v 46 46 else abort "The nix conf value: ${toPretty {} v} can not be encoded"; 47 47 48 48 mkKeyValue = k: v: "${escape [ "=" ] k} = ${mkValueString v}";
+1 -1
nixos/modules/services/system/self-deploy.nix
··· 18 18 in 19 19 lib.concatStrings (lib.mapAttrsToList toArg args); 20 20 21 - isPathType = x: lib.strings.isCoercibleToString x && builtins.substring 0 1 (toString x) == "/"; 21 + isPathType = x: lib.types.path.check x; 22 22 23 23 in 24 24 {