2024-12-12 14:41:43 +01:00
# SPDX-FileCopyrightText: 2024 Tom Hubrecht <tom.hubrecht@dgnum.eu>
#
# SPDX-License-Identifier: EUPL-1.2
2024-10-09 17:04:30 +02:00
###
# Collection of nixpkgs library functions, those are necessary for defining our own lib
#
# They have been simplified and builtins are used in some places, instead of lib shims.
rec {
/* *
Does the same as the update operator ' // ' except that attributes are
merged until the given predicate is verified . The predicate should
accept 3 arguments which are the path to reach the attribute , a part of
the first attribute set and a part of the second attribute set . When
the predicate is satisfied , the value of the first attribute set is
replaced by the value of the second attribute set .
# Inputs
` pred `
: Predicate , taking the path to the current attribute as a list of strings for attribute names , and the two values at that path from the original arguments .
` lhs `
: Left attribute set of the merge .
` rhs `
: Right attribute set of the merge .
# Type
` ` `
recursiveUpdateUntil : : ( [ String ] -> AttrSet -> AttrSet -> Bool ) -> AttrSet -> AttrSet -> AttrSet
` ` `
# Examples
: : : { . example }
## `lib.attrsets.recursiveUpdateUntil` usage example
` ` ` nix
recursiveUpdateUntil ( path : l : r : path == [ " f o o " ] ) {
# first attribute set
foo . bar = 1 ;
foo . baz = 2 ;
bar = 3 ;
} {
#second attribute set
foo . bar = 1 ;
foo . quz = 2 ;
baz = 4 ;
}
= > {
foo . bar = 1 ; # 'foo.*' from the second set
foo . quz = 2 ; #
bar = 3 ; # 'bar' from the first set
baz = 4 ; # 'baz' from the second set
}
` ` `
: : :
* /
recursiveUpdateUntil =
pred : lhs : rhs :
let
f =
attrPath :
builtins . zipAttrsWith (
n : values :
let
here = attrPath ++ [ n ] ;
in
if builtins . length values == 1 || pred here ( builtins . elemAt values 1 ) ( builtins . head values ) then
builtins . head values
else
f here values
) ;
in
f [ ] [
rhs
lhs
] ;
/* *
A recursive variant of the update operator ‘ // ’ . The recursion
stops when one of the attribute values is not an attribute set ,
in which case the right hand side value takes precedence over the
left hand side value .
# Inputs
` lhs `
: Left attribute set of the merge .
` rhs `
: Right attribute set of the merge .
# Type
` ` `
recursiveUpdate : : AttrSet -> AttrSet -> AttrSet
` ` `
# Examples
: : : { . example }
## `lib.attrsets.recursiveUpdate` usage example
` ` ` nix
recursiveUpdate {
boot . loader . grub . enable = true ;
boot . loader . grub . device = " / d e v / h d a " ;
} {
boot . loader . grub . device = " " ;
}
returns : {
boot . loader . grub . enable = true ;
boot . loader . grub . device = " " ;
}
` ` `
: : :
* /
recursiveUpdate =
lhs : rhs :
recursiveUpdateUntil (
_ : lhs : rhs :
! ( builtins . isAttrs lhs && builtins . isAttrs rhs )
) lhs rhs ;
/* *
Determine whether a string has given prefix .
# Inputs
` pref `
: Prefix to check for
` str `
: Input string
# Type
` ` `
hasPrefix : : string -> string -> bool
` ` `
# Examples
: : : { . example }
## `lib.strings.hasPrefix` usage example
` ` ` nix
hasPrefix " f o o " " f o o b a r "
= > true
hasPrefix " f o o " " b a r f o o "
= > false
` ` `
: : :
* /
hasPrefix = pref : str : ( builtins . substring 0 ( builtins . stringLength pref ) str == pref ) ;
/* *
Escape occurrence of the elements of ` list ` in ` string ` by
prefixing it with a backslash .
# Inputs
` list `
: 1 \ . Function argument
` string `
: 2 \ . Function argument
# Type
` ` `
escape : : [ string ] -> string -> string
` ` `
# Examples
: : : { . example }
## `lib.strings.escape` usage example
` ` ` nix
escape [ " ( " " ) " ] " ( f o o ) "
= > " \\ ( f o o \\ ) "
` ` `
: : :
* /
escape = list : builtins . replaceStrings list ( builtins . map ( c : " \\ ${ c } " ) list ) ;
/* *
Convert a string ` s ` to a list of characters ( i . e . singleton strings ) .
This allows you to , e . g . , map a function over each character . However ,
note that this will likely be horribly inefficient ; Nix is not a
general purpose programming language . Complex string manipulations
should , if appropriate , be done in a derivation .
Also note that Nix treats strings as a list of bytes and thus doesn't
handle unicode .
# Inputs
` s `
: 1 \ . Function argument
# Type
` ` `
stringToCharacters : : string -> [ string ]
` ` `
# Examples
: : : { . example }
## `lib.strings.stringToCharacters` usage example
` ` ` nix
stringToCharacters " "
= > [ ]
stringToCharacters " a b c "
= > [ " a " " b " " c " ]
stringToCharacters " 🦄 "
= > [ " <EFBFBD> " " <EFBFBD> " " <EFBFBD> " " <EFBFBD> " ]
` ` `
: : :
* /
stringToCharacters = s : builtins . genList ( p : builtins . substring p 1 s ) ( builtins . stringLength s ) ;
/* *
Turn a string ` s ` into an exact regular expression
# Inputs
` s `
: 1 \ . Function argument
# Type
` ` `
escapeRegex : : string -> string
` ` `
# Examples
: : : { . example }
## `lib.strings.escapeRegex` usage example
` ` ` nix
escapeRegex " [ ^ a - z ] * "
= > " \\ [ \\ ^ a - z ] \\ * "
` ` `
: : :
* /
escapeRegex = escape ( stringToCharacters " \\ [ { ( ) ^ $ ? * + | . " ) ;
/* *
Appends string context from string like object ` src ` to ` target ` .
: : : { . warning }
This is an implementation
detail of Nix and should be used carefully .
: : :
Strings in Nix carry an invisible ` context ` which is a list of strings
representing store paths . If the string is later used in a derivation
attribute , the derivation will properly populate the inputDrvs and
inputSrcs .
# Inputs
` src `
: The string to take the context from . If the argument is not a string ,
it will be implicitly converted to a string .
` target `
: The string to append the context to . If the argument is not a string ,
it will be implicitly converted to a string .
# Type
` ` `
addContextFrom : : string -> string -> string
` ` `
# Examples
: : : { . example }
## `lib.strings.addContextFrom` usage example
` ` ` nix
pkgs = import <nixpkgs> { } ;
addContextFrom pkgs . coreutils " b a r "
= > " b a r "
` ` `
The context can be displayed using the ` toString ` function :
` ` ` nix
nix-repl > builtins . getContext ( lib . strings . addContextFrom pkgs . coreutils " b a r " )
{
" / n i x / s t o r e / m 1 s 1 d 2 d k 2 d q q l w 3 j 9 0 j l 3 c j y 2 c y k b d x z - c o r e u t i l s - 9 . 5 . d r v " = { . . . } ;
}
` ` `
: : :
* /
addContextFrom = src : target : builtins . substring 0 0 src + target ;
/* *
Cut a string with a separator and produces a list of strings which
were separated by this separator .
# Inputs
` sep `
: 1 \ . Function argument
` s `
: 2 \ . Function argument
# Type
` ` `
splitString : : string -> string -> [ string ]
` ` `
# Examples
: : : { . example }
## `lib.strings.splitString` usage example
` ` ` nix
splitString " . " " f o o . b a r . b a z "
= > [ " f o o " " b a r " " b a z " ]
splitString " / " " / u s r / l o c a l / b i n "
= > [ " " " u s r " " l o c a l " " b i n " ]
` ` `
: : :
* /
splitString =
sep : s :
let
splits = builtins . filter builtins . isString (
builtins . split ( escapeRegex ( builtins . toString sep ) ) ( builtins . toString s )
) ;
in
builtins . map ( addContextFrom s ) splits ;
/* *
Remove duplicate elements from the ` list ` . O ( n ^ 2 ) complexity .
# Inputs
` list `
: Input list
# Type
` ` `
unique : : [ a ] -> [ a ]
` ` `
# Examples
: : : { . example }
## `lib.lists.unique` usage example
` ` ` nix
unique [ 3 2 3 4 ]
= > [ 3 2 4 ]
` ` `
: : :
* /
unique = builtins . foldl' ( acc : e : if builtins . elem e acc then acc else acc ++ [ e ] ) [ ] ;
/* *
Flip the order of the arguments of a binary function .
# Inputs
` f `
: 1 \ . Function argument
` a `
: 2 \ . Function argument
` b `
: 3 \ . Function argument
# Type
` ` `
flip : : ( a -> b -> c ) -> ( b -> a -> c )
` ` `
# Examples
: : : { . example }
## `lib.trivial.flip` usage example
` ` ` nix
flip concat [ 1 ] [ 2 ]
= > [ 2 1 ]
` ` `
: : :
* /
flip =
f : a : b :
f b a ;
2024-12-07 13:12:16 +01:00
/* *
` warn ` * ` message ` * * ` value ` *
Print a warning before returning the second argument .
See [ ` builtins . warn ` ] ( https://nix.dev/manual/nix/latest/language/builtins.html #builtins-warn) (Nix >= 2.23).
On older versions , the Nix 2 .23 behavior is emulated with [ ` builtins . trace ` ] ( https://nix.dev/manual/nix/latest/language/builtins.html #builtins-warn), including the [`NIX_ABORT_ON_WARN`](https://nix.dev/manual/nix/latest/command-ref/conf-file#conf-abort-on-warn) behavior, but not the `nix.conf` setting or command line option.
# Inputs
* ` message ` * ( String )
: Warning message to print before evaluating * ` value ` * .
* ` value ` * ( any value )
: Value to return as-is .
# Type
` ` `
String -> a -> a
` ` `
* /
warn =
# Since Nix 2.23, https://github.com/NixOS/nix/pull/10592
builtins . warn or (
let
mustAbort = builtins . elem ( builtins . getEnv " N I X _ A B O R T _ O N _ W A R N " ) [
" 1 "
" t r u e "
" y e s "
] ;
in
# Do not eta reduce v, so that we have the same strictness as `builtins.warn`.
msg : v :
# `builtins.warn` requires a string message, so we enforce that in our implementation, so that callers aren't accidentally incompatible with newer Nix versions.
assert builtins . isString msg ;
if mustAbort then
2024-12-07 13:03:35 +01:00
builtins . trace " [ 1 ; 3 1 m e v a l u a t i o n w a r n i n g : [ 0 m ${ msg } " (
2024-12-07 13:12:16 +01:00
abort " N I X _ A B O R T _ O N _ W A R N = t r u e ; w a r n i n g s a r e t r e a t e d a s u n r e c o v e r a b l e e r r o r s . "
)
else
2024-12-07 13:03:35 +01:00
builtins . trace " [ 1 ; 3 5 m e v a l u a t i o n w a r n i n g : [ 0 m ${ msg } " v
2024-12-07 13:12:16 +01:00
) ;
2024-10-09 17:04:30 +02:00
}