From d6c9c758919360c5331c1f756097244a756fd1ad Mon Sep 17 00:00:00 2001 From: Antonio Gurgel Date: Sat, 10 Aug 2024 12:45:51 -0700 Subject: [PATCH] Parametrize, exhaustively document `flattenTree` --- lib/default.nix | 64 ++++++++++++++++++++++++++++++------------------- src/mk.nix | 2 +- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/lib/default.nix b/lib/default.nix index 4d55562..7cf8275 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -49,32 +49,48 @@ (parseYAMLsFile yamlPath) ); + # Borrowed from divnix/digga and made more generic: # https://github.com/divnix/digga/blob/baa54f8/src/importers.nix#L2-L59 - # Borrowed from divnix/digga, with minor modifications: - # - Slash separators instead of periods, because `output.sh` - # will use these values as paths to build the derivation. - # - Look for functions (half-built service modules), not paths. - flattenTree = tree: let - op = sum: path: val: let - pathStr = builtins.concatStringsSep "/" path; - in - if builtins.isFunction val - then - (sum - // { - "${pathStr}" = val; - }) - else if builtins.isAttrs val - then - (recurse sum path val) - else - sum; # ignore val - - recurse = sum: path: val: + # + # Normally I dislike writing code-rephrasing comments, but every time I come + # across this function I burn 10m mentally reparsing it. + # - Input: + # - tree (attrs): Arbitrarily-nested elements, e.g.: + # {"a" = {"b" = <...>;}; "c" = <...>;} + # - pathSep (str): Path separator to use in output. + # - isLeaf (any -> bool): Determines "value" halves + # of output's KV pairs. + # - Output: flat attrset of functions, e.g.: + # {"a/b" = ; "c" = ;} + flattenTree = { + tree, + pathSep ? "/", + isLeaf ? builtins.isFunction, + }: let + # Contains the `foldl'` that forms the core of this function. + # Inputs: + # - acc (attrs): The accumulator. + # - path ([str]): `cursor`'s path in `tree`, e.g.: ["a" "b"]. + # - cursor (any): A value in `tree` under inspection. + recurse = acc: path: cursor: builtins.foldl' - (sum: key: op sum (path ++ [key]) val.${key}) - sum - (builtins.attrNames val); + (acc: key: op acc (path ++ [key]) cursor.${key}) + acc + (builtins.attrNames cursor); + + # Modifies accumulator according to cursor's type. + # If `cursor` is on a leaf, append to `acc` the key-value pair of + # the char-separated path and the leaf. + # If `cursor` is on an attrset, recurse into it. + # Otherwise, return accumulator unmodified. + op = acc: path: cursor: let + pathStr = builtins.concatStringsSep pathSep path; + in + if isLeaf cursor + then acc // {"${pathStr}" = cursor;} + else if builtins.isAttrs cursor + then recurse acc path cursor + else acc; # ignore value in recurse {} [] tree; } diff --git a/src/mk.nix b/src/mk.nix index 5c3c1c4..bc968da 100644 --- a/src/mk.nix +++ b/src/mk.nix @@ -111,7 +111,7 @@ in { paths = []; namespaces = []; } - (lib.flattenTree modules); + (lib.flattenTree {tree = modules;}); namespaces = { namespaces, # list of names