2021-12-20 23:48:26 +00:00
|
|
|
{ lib }: { config, folder, inputs, ... }@args: with lib; let
|
2021-12-20 23:51:02 +00:00
|
|
|
# Made by kat witch (kittywitch)
|
2021-12-20 23:48:26 +00:00
|
|
|
pureTreeGrab = { base, path }: let
|
|
|
|
realPath = toString path;
|
|
|
|
dirContents = builtins.readDir path;
|
|
|
|
isDirectory = entry: dirContents."${entry}" == "directory";
|
|
|
|
isHidden = entry: hasPrefix "." entry;
|
|
|
|
isDir = entry: _: (isDirectory entry) && !(isHidden entry);
|
|
|
|
directories = filterAttrs isDir dirContents;
|
|
|
|
isNixFile = entry: _: let
|
|
|
|
result = builtins.match "(.*)\\.nix" entry;
|
|
|
|
in result != null && builtins.length result > 0;
|
|
|
|
nixFiles = filterAttrs isNixFile dirContents;
|
|
|
|
getPath = entry: "${realPath}/${entry}";
|
|
|
|
getPaths = entries: mapAttrs' (n: v:
|
|
|
|
nameValuePair (removeSuffix ".nix" n) (getPath n)
|
|
|
|
) entries;
|
|
|
|
nixFilePaths = getPaths nixFiles;
|
|
|
|
dirPaths = getPaths directories;
|
|
|
|
recursedPaths = mapAttrs (_: fullPath: pureTreeGrab {
|
|
|
|
inherit base;
|
|
|
|
path = fullPath;
|
|
|
|
}) dirPaths;
|
|
|
|
contents = recursedPaths // nixFilePaths;
|
|
|
|
in contents;
|
|
|
|
configTreeStruct = { config, ... }: {
|
|
|
|
options.treeConfig = mkOption {
|
|
|
|
type = with types; attrsOf (submodule ({ name, options, config, ... }: {
|
|
|
|
options = {
|
|
|
|
evaluateDefault = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
description = "Replace the contents of this branch or leaf with those provided by the evaluation of default.nix.";
|
|
|
|
default = false;
|
|
|
|
};
|
|
|
|
aliasDefault = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
description = "Replace the contents of this branch or leaf with the default.nix.";
|
|
|
|
default = false;
|
|
|
|
};
|
|
|
|
excludes = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
description = "Exclude files or folders from the recurser.";
|
|
|
|
default = [];
|
|
|
|
};
|
|
|
|
functor = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
description = "Provide a functor for the path provided";
|
|
|
|
default = false;
|
|
|
|
};
|
|
|
|
external = mkOption {
|
|
|
|
type = types.listOf types.unspecified;
|
|
|
|
description = "Add external imports into the functor.";
|
|
|
|
default = [];
|
|
|
|
};
|
|
|
|
excludes = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
description = "Exclude files or folders from the functor.";
|
|
|
|
default = [];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}));
|
|
|
|
};
|
|
|
|
config.treeConfig = {
|
|
|
|
"*" = {};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
configTree.treeConfig = config;
|
|
|
|
configTreeModule = (evalModules {
|
|
|
|
modules = [
|
|
|
|
configTreeStruct
|
|
|
|
configTree
|
|
|
|
];
|
|
|
|
}).config.treeConfig;
|
|
|
|
mapAttrsRecursive = f: set: let
|
|
|
|
recurse = path: set: let
|
|
|
|
g = name: value: if isAttrs value
|
|
|
|
then f (path ++ [name]) (recurse (path ++ [name]) value)
|
|
|
|
else f (path ++ [name]) value;
|
|
|
|
in mapAttrs g set;
|
|
|
|
in recurse [] set;
|
|
|
|
getPathString = path: concatStringsSep "/" path;
|
|
|
|
getConfig = path: default: configTreeModule.${getPathString path} or default;
|
|
|
|
revtail = path: sublist 0 (length path - 1) path;
|
|
|
|
getConfigRecursive = path: let
|
|
|
|
parentPath = revtail path;
|
|
|
|
in getConfig (path ++ singleton "*") (getConfigRecursive parentPath);
|
|
|
|
processLeaves = tree: config: mapAttrsRecursive (path: value: let
|
|
|
|
pathString = getPathString path;
|
|
|
|
leafConfig = getConfig path (getConfigRecursive (revtail path));
|
|
|
|
processConfig = path: value: let
|
|
|
|
processFunctor = prev: prev // {
|
|
|
|
__functor = self: { ... }: {
|
|
|
|
imports = attrValues (removeAttrs prev leafConfig.functor.excludes) ++ leafConfig.functor.external;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
processAliasDefault = prev: prev.default;
|
|
|
|
processDefault = prev: import prev.default (args // {
|
|
|
|
inherit lib;
|
|
|
|
tree = {
|
|
|
|
prev = removeAttrs prev (singleton "default");
|
|
|
|
pure = pureTree;
|
|
|
|
impure = impureTree;
|
|
|
|
};
|
|
|
|
});
|
|
|
|
processExcludes = prev: removeAttrs prev leafConfig.excludes;
|
|
|
|
processes = optionals (isAttrs value) (
|
|
|
|
optional (leafConfig.excludes != []) processExcludes
|
|
|
|
++ optional leafConfig.evaluateDefault processDefault
|
|
|
|
++ optional leafConfig.aliasDefault processAliasDefault
|
|
|
|
++ optional leafConfig.functor.enable processFunctor
|
|
|
|
);
|
|
|
|
in pipe value processes;
|
|
|
|
in processConfig path value) tree;
|
|
|
|
pureTree = pureTreeGrab { base = folder; path = folder; };
|
|
|
|
impureTree = processLeaves pureTree configTreeModule;
|
|
|
|
in {
|
|
|
|
config = configTreeModule;
|
|
|
|
pure = pureTree;
|
|
|
|
impure = impureTree;
|
|
|
|
}
|