various: partially apply prefix/suffix/infix checks (#543869)

This commit is contained in:
Eman Resu
2026-07-26 21:41:24 +00:00
committed by GitHub
18 changed files with 142 additions and 101 deletions
+4 -2
View File
@@ -375,6 +375,8 @@ in
recurseIntoAttrs
removeSuffix
;
isNixFile = hasSuffix ".nix";
removeNixSuffix = removeSuffix ".nix";
# Generate an attrset corresponding to a given directory.
# This function is outside `packagesFromDirectoryRecursive`'s lambda expression,
@@ -397,10 +399,10 @@ in
}
);
}
else if type == "regular" && hasSuffix ".nix" name then
else if type == "regular" && isNixFile name then
{
# call .nix files
"${removeSuffix ".nix" name}" = callPackage path { };
"${removeNixSuffix name}" = callPackage path { };
}
else if type == "regular" then
{
+4 -2
View File
@@ -34,6 +34,8 @@ let
pathIsRegularFile
;
removeSlashSuffix = removeSuffix "/";
/**
A basic filter for `cleanSourceWith` that removes
directories of version control system, backup files (`*~`)
@@ -362,7 +364,7 @@ let
gitDir = absolutePath (dirOf path) (head m);
commonDir'' =
if pathIsRegularFile "${gitDir}/commondir" then fileContents "${gitDir}/commondir" else gitDir;
commonDir' = removeSuffix "/" commonDir'';
commonDir' = removeSlashSuffix commonDir'';
commonDir = absolutePath gitDir commonDir';
refFile = removePrefix "${commonDir}/" "${gitDir}/${file}";
in
@@ -460,7 +462,7 @@ let
urlToName =
url:
let
base = baseNameOf (removeSuffix "/" (last (splitString ":" (toString url))));
base = baseNameOf (removeSlashSuffix (last (splitString ":" (toString url))));
# chop away one git or archive-related extension
removeExt =
name:
+9 -5
View File
@@ -808,7 +808,7 @@ rec {
hasPrefix =
pref:
let
lenPrefix = stringLength pref;
getGivenPrefix = substring 0 (stringLength pref);
in
if isPath pref then
# Before 23.05, paths would be copied to the store before converting them
@@ -817,7 +817,7 @@ rec {
lib.strings.hasPrefix: The first argument (${toString pref}) is a path value, but only strings are supported.
You might want to use `lib.path.hasPrefix` instead, which correctly supports paths.''
else
str: substring 0 lenPrefix str == pref;
str: getGivenPrefix str == pref;
/**
Determine whether a string has given suffix.
@@ -905,7 +905,7 @@ rec {
hasInfix =
infix:
let
escapedInfix = escapeRegex infix;
matchGivenInfix = builtins.match ".*${escapeRegex infix}.*";
in
if isPath infix then
# Before 23.05, paths would be copied to the store before converting them
@@ -915,7 +915,7 @@ rec {
There is almost certainly a bug in the calling code, since this function always returns `false` in such a case.
This function also copies the path to the Nix store, which may not be what you want.''
else
content: builtins.match ".*${escapedInfix}.*" "${content}" != null;
content: matchGivenInfix "${content}" != null;
/**
Convert a string `s` to a list of characters (i.e. singleton strings).
@@ -2871,7 +2871,11 @@ rec {
:::
*/
fileContents = file: removeSuffix "\n" (readFile file);
fileContents =
let
removeNewlineSuffix = removeSuffix "\n";
in
file: removeNewlineSuffix (readFile file);
/**
Creates a valid derivation name from a potentially invalid one.
+3 -1
View File
@@ -27,6 +27,8 @@ let
execFormats
;
hasArmv7Prefix = hasPrefix "armv7";
# Based on lib.attrsets.matchAttrs, but with:
# - the initial isAttrs assertion removed, since this function is only ever
# called with attrsets
@@ -137,7 +139,7 @@ rec {
{
cpu = { inherit arch; };
}
) (filter (cpu: hasPrefix "armv7" cpu.arch or "") (attrValues cpuTypes));
) (filter (cpu: cpu ? arch && hasArmv7Prefix cpu.arch) (attrValues cpuTypes));
isAarch64 = {
cpu = {
family = "arm";
+6 -2
View File
@@ -91,6 +91,9 @@ let
in
if pos == null then "" else " at ${pos.file}:${toString pos.line}:${toString pos.column}";
hasColonInfix = hasInfix ":";
hasNewlineInfix = hasInfix "\n";
# Internal functor to help for migrating functor.wrapped to functor.payload.elemType
# Note that individual attributes can be overridden if needed.
elemTypeFunctor =
@@ -533,13 +536,14 @@ rec {
singleLineStr =
let
inherit (strMatching "[^\n\r]*\n?") check merge;
removeNewlineSuffix = lib.removeSuffix "\n";
in
mkOptionType {
name = "singleLineStr";
description = "(optionally newline-terminated) single-line string";
descriptionClass = "noun";
inherit check;
merge = loc: defs: lib.removeSuffix "\n" (merge loc defs);
merge = loc: defs: removeNewlineSuffix (merge loc defs);
};
strMatching =
@@ -580,7 +584,7 @@ rec {
passwdEntry =
entryType:
addCheck entryType (str: !(hasInfix ":" str || hasInfix "\n" str))
addCheck entryType (str: !(hasColonInfix str || hasNewlineInfix str))
// {
name = "passwdEntry ${entryType.name}";
description = "${
+25 -24
View File
@@ -42,6 +42,29 @@ let
in
let
hasSlashSuffix = hasSuffix "/";
isAbsolute = hasPrefix "/";
# normalisePath adds a slash at the end of the path if it didn't already
# have one.
#
# The reason slashes are added at the end of each path is to prevent `b`
# from accidentally depending on `a` in cases like
# a = { mountPoint = "/aaa"; ... }
# b = { device = "/aaaa"; ... }
# Here a.mountPoint *is* a prefix of b.device even though a.mountPoint is
# *not* a parent of b.device. If we add a slash at the end of each string,
# though, this is not a problem: "/aaa/" is not a prefix of "/aaaa/".
normalisePath = path: "${path}${optionalString (!hasSlashSuffix path) "/"}";
normalise =
mount:
mount
// {
device = normalisePath (toString mount.device);
mountPoint = normalisePath mount.mountPoint;
depends = map normalisePath mount.depends;
};
utils = rec {
# Copy configuration files to avoid having the entire sources in the system closure
@@ -71,29 +94,8 @@ let
fsBefore =
a: b:
let
# normalisePath adds a slash at the end of the path if it didn't already
# have one.
#
# The reason slashes are added at the end of each path is to prevent `b`
# from accidentally depending on `a` in cases like
# a = { mountPoint = "/aaa"; ... }
# b = { device = "/aaaa"; ... }
# Here a.mountPoint *is* a prefix of b.device even though a.mountPoint is
# *not* a parent of b.device. If we add a slash at the end of each string,
# though, this is not a problem: "/aaa/" is not a prefix of "/aaaa/".
normalisePath = path: "${path}${optionalString (!(hasSuffix "/" path)) "/"}";
normalise =
mount:
mount
// {
device = normalisePath (toString mount.device);
mountPoint = normalisePath mount.mountPoint;
depends = map normalisePath mount.depends;
};
a' = normalise a;
b' = normalise b;
in
hasPrefix a'.mountPoint b'.device
|| hasPrefix a'.mountPoint b'.mountPoint
@@ -116,7 +118,6 @@ let
in
s:
let
isAbsolute = hasPrefix "/" s;
# path_simplify(): collapse duplicate slashes and drop "." components.
rawComponents = filter (c: c != "" && c != ".") (splitString "/" s);
# systemd accepts ".." only where it is redundant: a leading ".." in an
@@ -129,7 +130,7 @@ let
acc: c:
if c == ".." then
# A leading ".." in an absolute path is the only redundant case.
if isAbsolute && acc.components == [ ] then acc else acc // { normalized = false; }
if isAbsolute s && acc.components == [ ] then acc else acc // { normalized = false; }
else
acc // { components = acc.components ++ [ c ]; }
)
@@ -145,7 +146,7 @@ let
else if simplified.components != [ ] then
concatStringsSep "/" simplified.components
# The root directory, and - matching systemd-escape - the empty string.
else if isAbsolute || s == "" then
else if isAbsolute s || s == "" then
"/"
# A relative path that reduces to nothing (e.g. "."), which has no
# valid escaping.
+3 -1
View File
@@ -904,9 +904,11 @@ let
text =
let
hasSpaceInfix = lib.hasInfix " ";
escapeEndingBrackets = lib.replaceStrings [ "]" ] [ "\\]" ];
# Formats a string for use in `module-arguments`. See `man pam.conf`.
formatModuleArgument =
token: if lib.hasInfix " " token then "[${lib.replaceStrings [ "]" ] [ "\\]" ] token}]" else token;
token: if hasSpaceInfix token then "[${escapeEndingBrackets token}]" else token;
formatRules =
type:
@@ -42,6 +42,8 @@ let
enable32BitAlsaPlugins =
cfg.alsa.support32Bit && pkgs.stdenv.hostPlatform.isx86_64 && pkgs.pkgsi686Linux.pipewire != null;
inPipewireDirectory = hasPrefix "pipewire/";
# The package doesn't output to $out/lib/pipewire directly so that the
# overlays can use the outputs to replace the originals in FHS environments.
#
@@ -383,7 +385,7 @@ in
assertion =
length (
attrNames (
filterAttrs (name: value: hasPrefix "pipewire/" name || name == "pipewire") config.environment.etc
filterAttrs (name: value: inPipewireDirectory name || name == "pipewire") config.environment.etc
)
) == 1;
message = "Using `environment.etc.\"pipewire<...>\"` directly is no longer supported. Use `services.pipewire.extraConfig` or `services.pipewire.configPackages` instead.";
+4 -2
View File
@@ -55,10 +55,12 @@ let
;
};
removeDriverPrefix = removePrefix "xf86-video-";
# Map video driver names to driver packages. FIXME: move into card-specific modules.
videoDrivers =
mapAttrs' (name: value: {
name = removePrefix "xf86-video-" value.pname;
name = removeDriverPrefix value.pname;
value = {
modules = [ value ];
};
@@ -466,7 +468,7 @@ in
];
relatedPackages = mapAttrsToList (name: value: {
path = [ name ];
title = removePrefix "xf86-video-" value.pname;
title = removeDriverPrefix value.pname;
}) knownVideoDriverPackages;
description = ''
@@ -25,6 +25,8 @@ let
" "
"\\"
];
hasTmpfilesPrefix = lib.hasPrefix "tmpfiles.d/";
removeTmpFilesPrefix = lib.removePrefix "tmpfiles.d/";
settingsOption = {
description = ''
@@ -299,8 +301,8 @@ in
''
+ concatMapStrings (
name:
optionalString (hasPrefix "tmpfiles.d/" name) ''
rm -f $out/${removePrefix "tmpfiles.d/" name}
optionalString (hasTmpfilesPrefix name) ''
rm -f $out/${removeTmpFilesPrefix name}
''
) config.system.build.etc.passthru.targets;
})
+25 -22
View File
@@ -259,6 +259,30 @@ let
inherit lua;
};
toGrammarName = lib.flip lib.pipe [
lib.getName
# added in buildGrammar
(lib.removeSuffix "-grammar")
# grammars from tree-sitter.builtGrammars
(lib.removePrefix "tree-sitter-")
(lib.replaceStrings [ "-" ] [ "_" ])
];
nvimGrammars = lib.mapAttrsToList (
name: value:
value.origGrammar
or (throw "additions to `pkgs.vimPlugins.nvim-treesitter.grammarPlugins` set should be passed through `pkgs.neovimUtils.grammarToPlugin` first")
) vimPlugins.nvim-treesitter.grammarPlugins;
isNvimGrammar = x: builtins.elem x nvimGrammars;
toNvimTreesitterGrammar = makeSetupHook {
name = "to-nvim-treesitter-grammar";
meta.license = lib.licenses.mit;
} ./to-nvim-treesitter-grammar.sh;
grammarToPlugin =
grammar:
# If the grammar has already been processed by this function, return it as-is.
@@ -268,28 +292,7 @@ let
grammar
else
let
name = lib.pipe grammar [
lib.getName
# added in buildGrammar
(lib.removeSuffix "-grammar")
# grammars from tree-sitter.builtGrammars
(lib.removePrefix "tree-sitter-")
(lib.replaceStrings [ "-" ] [ "_" ])
];
nvimGrammars = lib.mapAttrsToList (
name: value:
value.origGrammar
or (throw "additions to `pkgs.vimPlugins.nvim-treesitter.grammarPlugins` set should be passed through `pkgs.neovimUtils.grammarToPlugin` first")
) vimPlugins.nvim-treesitter.grammarPlugins;
isNvimGrammar = x: builtins.elem x nvimGrammars;
toNvimTreesitterGrammar = makeSetupHook {
name = "to-nvim-treesitter-grammar";
meta.license = lib.licenses.mit;
} ./to-nvim-treesitter-grammar.sh;
name = toGrammarName grammar;
in
(toVimPlugin (
+3 -1
View File
@@ -34,6 +34,8 @@ let
else
# FIXME fetching HEAD if no rev or tag is provided is problematic at best
"HEAD";
hasColonInfix = lib.hasInfix ":";
in
lib.makeOverridable (
@@ -133,7 +135,7 @@ lib.makeOverridable (
*/
let
finalHashHasColon = lib.hasInfix ":" finalAttrs.hash;
finalHashHasColon = hasColonInfix finalAttrs.hash;
finalHashColonMatch = lib.match "([^:]+)[:](.*)" finalAttrs.hash;
in
+6 -1
View File
@@ -52,6 +52,11 @@ let
# "gnu", etc.).
sites = builtins.attrNames mirrors;
# partially applied set of functions for each hash type
# this is indexed into with a prefix to avoid re-calling hasPrefix, since it
# takes advantage of partial application for performance reasons
hasAlgoPrefix = lib.genAttrs [ "sha256" "sha1" "sha512" ] hasPrefix;
/**
Resolve a URL against the available mirrors.
@@ -310,7 +315,7 @@ lib.extendMkDerivation {
if
hash_.outputHashAlgo == null
|| hash_.outputHash == ""
|| hasPrefix hash_.outputHashAlgo hash_.outputHash
|| hasAlgoPrefix.${hash_.outputHashAlgo} hash_.outputHash
then
hash_.outputHash
else
+7 -6
View File
@@ -75,10 +75,15 @@ let
*/
builtGrammars = lib.mapAttrs (_: lib.makeOverridable buildGrammar) grammars;
hasTreeSitterPrefix = lib.hasPrefix "tree-sitter-";
grammarDerivationsFrom = lib.filterAttrs (
name: value: lib.hasPrefix "tree-sitter-" name && lib.isDerivation value
name: value: hasTreeSitterPrefix name && lib.isDerivation value
);
removeTreesitterPrefix = lib.strings.removePrefix "tree-sitter-";
removeGrammarSuffix = lib.strings.removeSuffix "-grammar";
replaceHyphens = lib.strings.replaceStrings [ "-" ] "_";
mkGrammarLinkFarm =
grammars:
linkFarm "grammars" (
@@ -88,11 +93,7 @@ let
name = lib.strings.getName drv;
in
{
name =
(lib.strings.replaceStrings [ "-" ] [ "_" ] (
lib.strings.removePrefix "tree-sitter-" (lib.strings.removeSuffix "-grammar" name)
))
+ ".so";
name = (replaceHyphens (removeTreesitterPrefix (removeGrammarSuffix name))) + ".so";
path = "${drv}/parser";
}
) grammars
@@ -60,6 +60,8 @@ let
in
fixedWidthString len " " name;
hasZipSuffix = hasSuffix "zip";
isPythonModule =
drv:
# all pythonModules have the pythonModule attribute
@@ -318,7 +320,7 @@ lib.extendMkDerivation {
++ optionals removeBinBytecode [
pythonRemoveBinBytecodeHook
]
++ optionals (hasSuffix "zip" (finalAttrs.src.name or "")) [
++ optionals (attrs ? src.name && hasZipSuffix attrs.src.name) [
unzip
]
++ optionals (format' == "setuptools") [
@@ -27,6 +27,9 @@
eggBuildHook,
eggInstallHook,
}:
let
hasZipSuffix = lib.hasSuffix "zip";
in
lib.extendMkDerivation {
constructDrv = stdenv.mkDerivation;
@@ -207,7 +210,7 @@ lib.extendMkDerivation {
++ lib.optionals removeBinBytecode [
pythonRemoveBinBytecodeHook
]
++ lib.optionals (lib.hasSuffix "zip" (attrs.src.name or "")) [
++ lib.optionals (attrs ? src.name && hasZipSuffix attrs.src.name) [
unzip
]
++ lib.optionals (format == "setuptools") [
+26 -25
View File
@@ -3,6 +3,31 @@
nodejs-slim,
symlinkJoin,
}:
let
hasDisallowedPrefix = lib.hasPrefix "__";
allowedNames = [
"override"
"overrideAttrs"
"overrideDerivation"
"outputs"
"outputName"
"system"
"type"
# Filter out arguments of `getOutput`
"bin"
"dev"
"include"
"lib"
"man"
"out"
"static"
# Filter out outputs that didn't exist on 25.11
"npm"
"corepack"
];
in
(symlinkJoin {
pname = "nodejs";
inherit (nodejs-slim) version passthru meta;
@@ -22,31 +47,7 @@
})
(
builtins.filter (
name:
!lib.strings.hasPrefix "__" name
&& !(builtins.elem name [
"override"
"overrideAttrs"
"overrideDerivation"
"outputs"
"outputName"
"system"
"type"
# Filter out arguments of `getOutput`
"bin"
"dev"
"include"
"lib"
"man"
"out"
"static"
# Filter out outputs that didn't exist on 25.11
"npm"
"corepack"
])
&& !(builtins.hasAttr name nodejs)
name: !hasDisallowedPrefix name && !(builtins.elem name allowedNames) && !(nodejs ? ${name})
) (builtins.attrNames nodejs-slim)
)
))
@@ -337,6 +337,7 @@ let
compiler =
let
objs = filter isString (split " " mes_SOURCES);
removeSrcPrefix = lib.removePrefix "src/";
in
kaem.runCommand "${pname}-${version}"
{
@@ -360,7 +361,7 @@ let
-I ${srcPrefix}/include/linux/${arch} \
-I ${srcPost}/mes-${version}/src \
-c \
-o ${lib.removePrefix "src/" obj}.o \
-o ${removeSrcPrefix obj}.o \
${srcPost}/mes-${version}/${obj}
'') objs}
@@ -373,7 +374,7 @@ let
-nostdlib \
-o ''${out}/bin/mes \
${libs}/lib/${arch}-mes/crt1.o \
${lib.concatMapStringsSep " " (obj: "${lib.removePrefix "src/" obj}.o") objs}
${lib.concatMapStringsSep " " (obj: "${removeSrcPrefix obj}.o") objs}
'';
in
{