Merge pull request #83241 from Infinisil/valid-drv-name

lib/strings: Add `sanitizeDerivationName` function

Changed files
+76 -2
lib
+2 -2
lib/attrsets.nix
···
let
inherit (builtins) head tail length;
inherit (lib.trivial) and;
-
inherit (lib.strings) concatStringsSep;
inherit (lib.lists) fold concatMap concatLists;
in
···
path' = builtins.storePath path;
res =
{ type = "derivation";
-
name = builtins.unsafeDiscardStringContext (builtins.substring 33 (-1) (baseNameOf path'));
outPath = path';
outputs = [ "out" ];
out = res;
···
let
inherit (builtins) head tail length;
inherit (lib.trivial) and;
+
inherit (lib.strings) concatStringsSep sanitizeDerivationName;
inherit (lib.lists) fold concatMap concatLists;
in
···
path' = builtins.storePath path;
res =
{ type = "derivation";
+
name = sanitizeDerivationName (builtins.substring 33 (-1) (baseNameOf path'));
outPath = path';
outputs = [ "out" ];
out = res;
+32
lib/strings.nix
···
=> "1.0"
*/
fileContents = file: removeSuffix "\n" (builtins.readFile file);
}
···
=> "1.0"
*/
fileContents = file: removeSuffix "\n" (builtins.readFile file);
+
+
+
/* Creates a valid derivation name from a potentially invalid one.
+
+
Type: sanitizeDerivationName :: String -> String
+
+
Example:
+
sanitizeDerivationName "../hello.bar # foo"
+
=> "-hello.bar-foo"
+
sanitizeDerivationName ""
+
=> "unknown"
+
sanitizeDerivationName pkgs.hello
+
=> "-nix-store-2g75chlbpxlrqn15zlby2dfh8hr9qwbk-hello-2.10"
+
*/
+
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
+
# Strip all leading "."
+
(x: builtins.elemAt (builtins.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:]+._?=-]+")
+
# Replace invalid character ranges with a "-"
+
(concatMapStrings (s: if lib.isList s then "-" else s))
+
# Limit to 211 characters (minus 4 chars for ".drv")
+
(x: substring (lib.max (stringLength x - 207) 0) (-1) x)
+
# If the result is empty, replace it with "unknown"
+
(x: if stringLength x == 0 then "unknown" else x)
+
];
+
}
+42
lib/tests/misc.nix
···
# if the resulting list is empty, all tests passed
with import ../default.nix;
runTests {
···
};
expected = "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
};
}
···
# if the resulting list is empty, all tests passed
with import ../default.nix;
+
let
+
+
testSanitizeDerivationName = { name, expected }:
+
let
+
drv = derivation {
+
name = strings.sanitizeDerivationName name;
+
builder = "x";
+
system = "x";
+
};
+
in {
+
# Evaluate the derivation so an invalid name would be caught
+
expr = builtins.seq drv.drvPath drv.name;
+
inherit expected;
+
};
+
+
in
+
runTests {
···
};
expected = "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
+
};
+
+
testSanitizeDerivationNameLeadingDots = testSanitizeDerivationName {
+
name = "..foo";
+
expected = "foo";
+
};
+
+
testSanitizeDerivationNameAscii = testSanitizeDerivationName {
+
name = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
+
expected = "-+--.-0123456789-=-?-ABCDEFGHIJKLMNOPQRSTUVWXYZ-_-abcdefghijklmnopqrstuvwxyz-";
+
};
+
+
testSanitizeDerivationNameTooLong = testSanitizeDerivationName {
+
name = "This string is loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
+
expected = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
+
};
+
+
testSanitizeDerivationNameTooLongWithInvalid = testSanitizeDerivationName {
+
name = "Hello there aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&&&&&&&";
+
expected = "there-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-";
+
};
+
+
testSanitizeDerivationNameEmpty = testSanitizeDerivationName {
+
name = "";
+
expected = "unknown";
};
}