mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-11 20:25:32 +03:00
lib: Use Nix's static scope checking, fix error message, optimize
Nix can perform static scope checking, but whenever code is inside a `with` expression, the analysis breaks down, because it can't know statically what's in the attribute set whose attributes were brought into scope. In those cases, Nix has to assume that everything works out. Except it doesnt. Removing `with` from lib/ revealed an undefined variable in an error message. If that doesn't convince you that we're better off without `with`, I can tell you that this PR results in a 3% evaluation performance improvement because Nix can look up local variables by index. This adds up with applications like the module system. Furthermore, removing `with` makes the binding site of each variable obvious, which helps with comprehension.
This commit is contained in:
parent
5aa2a98dfa
commit
afa6c51f27
9 changed files with 238 additions and 82 deletions
|
@ -8,7 +8,29 @@ in
|
|||
|
||||
rec {
|
||||
|
||||
inherit (builtins) stringLength substring head tail isString replaceStrings;
|
||||
inherit (builtins)
|
||||
compareVersions
|
||||
elem
|
||||
elemAt
|
||||
filter
|
||||
fromJSON
|
||||
head
|
||||
isInt
|
||||
isList
|
||||
isString
|
||||
match
|
||||
parseDrvName
|
||||
readFile
|
||||
replaceStrings
|
||||
split
|
||||
storeDir
|
||||
stringLength
|
||||
substring
|
||||
tail
|
||||
toJSON
|
||||
typeOf
|
||||
unsafeDiscardStringContext
|
||||
;
|
||||
|
||||
/* Concatenate a list of strings.
|
||||
|
||||
|
@ -120,7 +142,7 @@ rec {
|
|||
subDir:
|
||||
# List of base paths
|
||||
paths:
|
||||
concatStringsSep ":" (map (path: path + "/" + subDir) (builtins.filter (x: x != null) paths));
|
||||
concatStringsSep ":" (map (path: path + "/" + subDir) (filter (x: x != null) paths));
|
||||
|
||||
/* Construct a Unix-style search path by appending the given
|
||||
`subDir` to the specified `output` of each of the packages. If no
|
||||
|
@ -313,7 +335,7 @@ rec {
|
|||
escapeNixString "hello\${}\n"
|
||||
=> "\"hello\\\${}\\n\""
|
||||
*/
|
||||
escapeNixString = s: escape ["$"] (builtins.toJSON s);
|
||||
escapeNixString = s: escape ["$"] (toJSON s);
|
||||
|
||||
/* Turn a string into an exact regular expression
|
||||
|
||||
|
@ -337,7 +359,7 @@ rec {
|
|||
*/
|
||||
escapeNixIdentifier = s:
|
||||
# Regex from https://github.com/NixOS/nix/blob/d048577909e383439c2549e849c5c2f2016c997e/src/libexpr/lexer.l#L91
|
||||
if builtins.match "[a-zA-Z_][a-zA-Z0-9_'-]*" s != null
|
||||
if match "[a-zA-Z_][a-zA-Z0-9_'-]*" s != null
|
||||
then s else escapeNixString s;
|
||||
|
||||
# Obsolete - use replaceStrings instead.
|
||||
|
@ -466,7 +488,7 @@ rec {
|
|||
versionOlder "1.1" "1.1"
|
||||
=> false
|
||||
*/
|
||||
versionOlder = v1: v2: builtins.compareVersions v2 v1 == 1;
|
||||
versionOlder = v1: v2: compareVersions v2 v1 == 1;
|
||||
|
||||
/* Return true if string v1 denotes a version equal to or newer than v2.
|
||||
|
||||
|
@ -492,7 +514,7 @@ rec {
|
|||
*/
|
||||
getName = x:
|
||||
let
|
||||
parse = drv: (builtins.parseDrvName drv).name;
|
||||
parse = drv: (parseDrvName drv).name;
|
||||
in if isString x
|
||||
then parse x
|
||||
else x.pname or (parse x.name);
|
||||
|
@ -509,7 +531,7 @@ rec {
|
|||
*/
|
||||
getVersion = x:
|
||||
let
|
||||
parse = drv: (builtins.parseDrvName drv).version;
|
||||
parse = drv: (parseDrvName drv).version;
|
||||
in if isString x
|
||||
then parse x
|
||||
else x.version or (parse x.name);
|
||||
|
@ -527,7 +549,7 @@ rec {
|
|||
let
|
||||
components = splitString "/" url;
|
||||
filename = lib.last components;
|
||||
name = builtins.head (splitString sep filename);
|
||||
name = head (splitString sep filename);
|
||||
in assert name != filename; name;
|
||||
|
||||
/* Create an --{enable,disable}-<feat> string that can be passed to
|
||||
|
@ -617,14 +639,14 @@ rec {
|
|||
*/
|
||||
floatToString = float: let
|
||||
result = toString float;
|
||||
precise = float == builtins.fromJSON result;
|
||||
precise = float == fromJSON result;
|
||||
in if precise then result
|
||||
else lib.warn "Imprecise conversion from float to string ${result}" result;
|
||||
|
||||
/* Check whether a value can be coerced to a string */
|
||||
isCoercibleToString = x:
|
||||
builtins.elem (builtins.typeOf x) [ "path" "string" "null" "int" "float" "bool" ] ||
|
||||
(builtins.isList x && lib.all isCoercibleToString x) ||
|
||||
elem (typeOf x) [ "path" "string" "null" "int" "float" "bool" ] ||
|
||||
(isList x && lib.all isCoercibleToString x) ||
|
||||
x ? outPath ||
|
||||
x ? __toString;
|
||||
|
||||
|
@ -643,8 +665,8 @@ rec {
|
|||
isStorePath = x:
|
||||
if isCoercibleToString x then
|
||||
let str = toString x; in
|
||||
builtins.substring 0 1 str == "/"
|
||||
&& dirOf str == builtins.storeDir
|
||||
substring 0 1 str == "/"
|
||||
&& dirOf str == storeDir
|
||||
else
|
||||
false;
|
||||
|
||||
|
@ -662,8 +684,8 @@ rec {
|
|||
*/
|
||||
# Obviously, it is a bit hacky to use fromJSON this way.
|
||||
toInt = str:
|
||||
let may_be_int = builtins.fromJSON str; in
|
||||
if builtins.isInt may_be_int
|
||||
let may_be_int = fromJSON str; in
|
||||
if isInt may_be_int
|
||||
then may_be_int
|
||||
else throw "Could not convert ${str} to int.";
|
||||
|
||||
|
@ -685,10 +707,10 @@ rec {
|
|||
readPathsFromFile = lib.warn "lib.readPathsFromFile is deprecated, use a list instead"
|
||||
(rootPath: file:
|
||||
let
|
||||
lines = lib.splitString "\n" (builtins.readFile file);
|
||||
lines = lib.splitString "\n" (readFile file);
|
||||
removeComments = lib.filter (line: line != "" && !(lib.hasPrefix "#" line));
|
||||
relativePaths = removeComments lines;
|
||||
absolutePaths = builtins.map (path: rootPath + "/${path}") relativePaths;
|
||||
absolutePaths = map (path: rootPath + "/${path}") relativePaths;
|
||||
in
|
||||
absolutePaths);
|
||||
|
||||
|
@ -702,7 +724,7 @@ rec {
|
|||
fileContents ./version
|
||||
=> "1.0"
|
||||
*/
|
||||
fileContents = file: removeSuffix "\n" (builtins.readFile file);
|
||||
fileContents = file: removeSuffix "\n" (readFile file);
|
||||
|
||||
|
||||
/* Creates a valid derivation name from a potentially invalid one.
|
||||
|
@ -720,13 +742,13 @@ rec {
|
|||
sanitizeDerivationName = string: lib.pipe string [
|
||||
# Get rid of string context. This is safe under the assumption that the
|
||||
# resulting string is only used as a derivation name
|
||||
builtins.unsafeDiscardStringContext
|
||||
unsafeDiscardStringContext
|
||||
# Strip all leading "."
|
||||
(x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0)
|
||||
(x: elemAt (match "\\.*(.*)" x) 0)
|
||||
# Split out all invalid characters
|
||||
# https://github.com/NixOS/nix/blob/2.3.2/src/libstore/store-api.cc#L85-L112
|
||||
# https://github.com/NixOS/nix/blob/2242be83c61788b9c0736a92bb0b5c7bbfc40803/nix-rust/src/store/path.rs#L100-L125
|
||||
(builtins.split "[^[:alnum:]+._?=-]+")
|
||||
(split "[^[:alnum:]+._?=-]+")
|
||||
# Replace invalid character ranges with a "-"
|
||||
(concatMapStrings (s: if lib.isList s then "-" else s))
|
||||
# Limit to 211 characters (minus 4 chars for ".drv")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue