nixfiles/tree.nix

140 lines
5 KiB
Nix
Raw Normal View History

2021-12-26 14:07:09 +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-21 15:26:21 +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: _:
2021-12-26 14:07:09 +00:00
let result = builtins.match "(.*)\\.nix" entry;
in result != null && builtins.length result > 0;
2021-12-21 15:26:21 +00:00
nixFiles = filterAttrs isNixFile dirContents;
getPath = entry: "${realPath}/${entry}";
2021-12-26 14:07:09 +00:00
getPaths = entries:
mapAttrs' (n: v: nameValuePair (removeSuffix ".nix" n) (getPath n))
2021-12-21 15:26:21 +00:00
entries;
nixFilePaths = getPaths nixFiles;
dirPaths = getPaths directories;
2021-12-26 14:07:09 +00:00
recursedPaths = mapAttrs (_: fullPath:
pureTreeGrab {
2021-12-21 15:26:21 +00:00
inherit base;
path = fullPath;
2021-12-26 14:07:09 +00:00
}) dirPaths;
2021-12-21 15:26:21 +00:00
contents = recursedPaths // nixFilePaths;
2021-12-26 14:07:09 +00:00
in contents;
2021-12-20 23:48:26 +00:00
configTreeStruct = { config, ... }: {
options.treeConfig = mkOption {
2021-12-26 14:07:09 +00:00
type = with types;
attrsOf (submodule ({ name, options, config, ... }: {
options = {
evaluateDefault = mkOption {
2021-12-20 23:48:26 +00:00
type = types.bool;
2021-12-26 14:07:09 +00:00
description =
"Replace the contents of this branch or leaf with those provided by the evaluation of default.nix.";
2021-12-20 23:48:26 +00:00
default = false;
};
2021-12-26 14:07:09 +00:00
aliasDefault = mkOption {
type = types.bool;
description =
"Replace the contents of this branch or leaf with the default.nix.";
default = false;
2021-12-20 23:48:26 +00:00
};
excludes = mkOption {
type = types.listOf types.str;
2021-12-26 14:07:09 +00:00
description = "Exclude files or folders from the recurser.";
2021-12-21 15:26:21 +00:00
default = [ ];
2021-12-20 23:48:26 +00:00
};
2021-12-26 14:07:09 +00:00
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 = [ ];
};
};
2021-12-20 23:48:26 +00:00
};
2021-12-26 14:07:09 +00:00
}));
2021-12-20 23:48:26 +00:00
};
2021-12-26 14:07:09 +00:00
config.treeConfig = { "*" = { }; };
2021-12-20 23:48:26 +00:00
};
configTree.treeConfig = config;
configTreeModule = (evalModules {
2021-12-26 14:07:09 +00:00
modules = [ configTreeStruct configTree ];
2021-12-20 23:48:26 +00:00
}).config.treeConfig;
2021-12-21 15:26:21 +00:00
mapAttrsRecursive = f: set:
let
recurse = path: set:
let
g = name: value:
2021-12-26 14:07:09 +00:00
if isAttrs value then
f (path ++ [ name ]) (recurse (path ++ [ name ]) value)
else
f (path ++ [ name ]) value;
in mapAttrs g set;
in recurse [ ] set;
2021-12-20 23:48:26 +00:00
getPathString = path: concatStringsSep "/" path;
getConfig = path: default: configTreeModule.${getPathString path} or default;
revtail = path: sublist 0 (length path - 1) path;
2021-12-21 15:26:21 +00:00
getConfigRecursive = path:
2021-12-26 14:07:09 +00:00
let parentPath = revtail path;
in getConfig (path ++ singleton "*") (getConfigRecursive parentPath);
processLeaves = tree: config:
mapAttrsRecursive (path: value:
2021-12-21 15:26:21 +00:00
let
pathString = getPathString path;
leafConfig = getConfig path (getConfigRecursive (revtail path));
processConfig = path: value:
let
2021-12-26 14:07:09 +00:00
processFunctor = prev:
prev // {
__functor = self:
{ ... }: {
imports =
attrValues (removeAttrs prev leafConfig.functor.excludes)
++ leafConfig.functor.external;
};
2021-12-21 15:26:21 +00:00
};
processAliasDefault = prev: prev.default;
2021-12-26 14:07:09 +00:00
processDefault = prev:
import prev.default (args // {
inherit lib;
tree = {
prev = removeAttrs prev (singleton "default");
pure = pureTree;
impure = impureTree;
};
});
2021-12-21 15:26:21 +00:00
processExcludes = prev: removeAttrs prev leafConfig.excludes;
2021-12-26 14:07:09 +00:00
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;
};
2021-12-20 23:48:26 +00:00
impureTree = processLeaves pureTree configTreeModule;
2021-12-26 14:07:09 +00:00
in {
2021-12-20 23:48:26 +00:00
config = configTreeModule;
pure = pureTree;
impure = impureTree;
}