diff --git a/lib/filesystem.nix b/lib/filesystem.nix index 9f05c05eb7cd..47ca72543ca6 100644 --- a/lib/filesystem.nix +++ b/lib/filesystem.nix @@ -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 { diff --git a/lib/sources.nix b/lib/sources.nix index 9846e9c586f7..bc9f1c8f87e5 100644 --- a/lib/sources.nix +++ b/lib/sources.nix @@ -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: diff --git a/lib/strings.nix b/lib/strings.nix index 59a458aecf80..411e1729d7a7 100644 --- a/lib/strings.nix +++ b/lib/strings.nix @@ -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. diff --git a/lib/systems/inspect.nix b/lib/systems/inspect.nix index 98b3fc050bc1..9ef67e0ec2cf 100644 --- a/lib/systems/inspect.nix +++ b/lib/systems/inspect.nix @@ -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"; diff --git a/lib/types.nix b/lib/types.nix index 8ed7bec21713..3002b3c2bf8e 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -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 = "${ diff --git a/nixos/lib/utils.nix b/nixos/lib/utils.nix index d26d8b36acb5..487b20f53d8c 100644 --- a/nixos/lib/utils.nix +++ b/nixos/lib/utils.nix @@ -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. diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index c6e0bee172e8..6caedcd2ddc9 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -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: diff --git a/nixos/modules/services/desktops/pipewire/pipewire.nix b/nixos/modules/services/desktops/pipewire/pipewire.nix index fb72bd695cec..8d4b0a608d0d 100644 --- a/nixos/modules/services/desktops/pipewire/pipewire.nix +++ b/nixos/modules/services/desktops/pipewire/pipewire.nix @@ -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."; diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index e939931f8139..81823a6b7588 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -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 = '' diff --git a/nixos/modules/system/boot/systemd/tmpfiles.nix b/nixos/modules/system/boot/systemd/tmpfiles.nix index 631a02645d9b..b43d91d58dd0 100644 --- a/nixos/modules/system/boot/systemd/tmpfiles.nix +++ b/nixos/modules/system/boot/systemd/tmpfiles.nix @@ -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; }) diff --git a/pkgs/applications/editors/neovim/utils.nix b/pkgs/applications/editors/neovim/utils.nix index f95494812bd5..beca1cf1d4e2 100644 --- a/pkgs/applications/editors/neovim/utils.nix +++ b/pkgs/applications/editors/neovim/utils.nix @@ -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 ( diff --git a/pkgs/build-support/fetchgit/default.nix b/pkgs/build-support/fetchgit/default.nix index 440df372769e..990e6c6f9889 100644 --- a/pkgs/build-support/fetchgit/default.nix +++ b/pkgs/build-support/fetchgit/default.nix @@ -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 diff --git a/pkgs/build-support/fetchurl/default.nix b/pkgs/build-support/fetchurl/default.nix index b91d7a6f1c5d..27a3e543905a 100644 --- a/pkgs/build-support/fetchurl/default.nix +++ b/pkgs/build-support/fetchurl/default.nix @@ -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 diff --git a/pkgs/by-name/tr/tree-sitter/package.nix b/pkgs/by-name/tr/tree-sitter/package.nix index 5c2f8655c625..4c122fb6b903 100644 --- a/pkgs/by-name/tr/tree-sitter/package.nix +++ b/pkgs/by-name/tr/tree-sitter/package.nix @@ -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 diff --git a/pkgs/development/interpreters/python/mk-python-derivation.nix b/pkgs/development/interpreters/python/mk-python-derivation.nix index 48748b5eec77..387f97ccd072 100644 --- a/pkgs/development/interpreters/python/mk-python-derivation.nix +++ b/pkgs/development/interpreters/python/mk-python-derivation.nix @@ -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") [ diff --git a/pkgs/development/misc/resholve/python2/mk-python-derivation.nix b/pkgs/development/misc/resholve/python2/mk-python-derivation.nix index e6e660d704e5..c517b5393a24 100644 --- a/pkgs/development/misc/resholve/python2/mk-python-derivation.nix +++ b/pkgs/development/misc/resholve/python2/mk-python-derivation.nix @@ -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") [ diff --git a/pkgs/development/web/nodejs/symlink.nix b/pkgs/development/web/nodejs/symlink.nix index 1dd0822d8db4..34d919b20f46 100644 --- a/pkgs/development/web/nodejs/symlink.nix +++ b/pkgs/development/web/nodejs/symlink.nix @@ -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) ) )) diff --git a/pkgs/os-specific/linux/minimal-bootstrap/mes/default.nix b/pkgs/os-specific/linux/minimal-bootstrap/mes/default.nix index 7c3335ed1f21..3ed34e3ad2f6 100644 --- a/pkgs/os-specific/linux/minimal-bootstrap/mes/default.nix +++ b/pkgs/os-specific/linux/minimal-bootstrap/mes/default.nix @@ -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 {