# Given a path list of bash script »sources« and an attrset »context«, this function parses the scripts for the literal sequence »@{« followed by a lookup path of period-joined words, resolves that attribute path against »context«, declares a variable with that value, and swaps out the »@{« plus path for a »${« use of the declared variable. The returned script sources the variable definitions and all translated »sources« in order.
# The lookup path may end in »!« plus the name of a function and optionally string arguments separated by ».«s, in which case the function is taken from »helpers//self.lib.wip//(pkgs.lib or lib)//pkgs//builtins« and called with the string args and the resolved value as last arg; the return value then replaces the resolved value. Examples: »!attrNames«, »!toJSON«, »!catAttrs«, »!hashString.sha256«.
# The names of the declared values are the lookup paths, with ».« and »!« replaced by »_« and »__«.
# The symbol immediately following the lookup path (/builtin name) can be »}« or any other symbol that bash variable substitutions allow after the variable name (like »:«, »/«), eliminating the need to assign to a local variable to do things like replacements, fallbacks or substrings.
# If the lookup path does not exist in »context«, then the value will be considered the same as »null«, and a value of »null« will result in a bash variable that is not defined (which can then be handled in the bash script).
# Other scalars (bool, float, int, path) will be passed to »builtins.toString«. Anything that has an ».outPath« that is a string will be passed as that ».outPath«.
# Lists will be declared as bash arrays, attribute sets will be declared as associative arrays using »asBashDict«.
# Bash does not support any nested data structures. Lists or attrsets in within lists or attrsets are therefore (recursively) encoded and escaped as strings, such that calling »eval« on them is safe if (but only if) they are known to be encoded from nested lists/attrsets. Example: »eval 'declare -A fs='"@{config.fileSystems['/']}" ; root=${fs[device]}«.
scripts,# List of paths to scripts to process and then source in the returned script. Each script may also be an attrset »{ name; text; }« instead of a path.
context,# The root attrset for the resolution of substitutions.
pkgs,# Instantiated »nixpkgs«, as fallback location for helpers, and to grab »writeScript« etc from.
helpers?{},# Attrset of (highest priority) helper functions.
trace?(m:v:v),# Function that gets called with the names and values as they are processed. Pass »builtins.trace« for debugging, esp. when evaluating one of the accessed values fails.
parsed=builtins.split''@\{([#!]?)([a-zA-Z][a-zA-Z0-9_.-]*[a-zA-Z0-9](![a-zA-Z][a-zA-Z0-9_.-]*[a-zA-Z0-9])?)([:*@\[#%/^,\}])''text;# (first part of a bash parameter expansion, with »@« instead of »$«)
## Given a bash »script« as string and a function »name«, this finds and extracts the definition of that function in and from the script.
# The function definition has to start at the beginning of a line and must ends the next »}« of »)}« at the beginning of a line that is followed by nothing but a comment on that line.
# Used as a »system.activationScripts« snippet, this performs substitutions on a »text« before writing it to »path«.
# For each name-value pair in »substitutes«, all verbatim occurrences of the attribute name in »text« are replaced by the content of the file with path of the attribute value.
# Since this happens one by one in no defined order, the attribute values should be chosen such that they don't appear in any of the files that are substituted in.
# If a file that is supposed to be substituted in is missing, then »placeholder« is inserted instead, and the activation snipped reports a failure.
# If »enable« is false, then the file at »path« is »rm«ed instead.
# Simplifies a path (or any other string) such that it can be used as a systemd unit name.
escapeUnitName=name:lib.concatMapStringsSep""(s:ifbuiltins.isListsthen"-"elses)(builtins.split"[^a-zA-Z0-9_.\\-]+"name);# from nixos/modules/services/backup/syncoid.nix