mirror of
https://github.com/nix-community/dream2nix.git
synced 2024-11-25 11:45:01 +03:00
127 lines
3.1 KiB
Nix
127 lines
3.1 KiB
Nix
{lib, ...}: let
|
|
l = builtins // lib;
|
|
|
|
/*
|
|
Transforms a source tree into a nix attrset for simplicity and performance.
|
|
It's simpler to traverse an attrset than having to readDir manually.
|
|
It's more performant because it allows to parse a json or toml by accessing
|
|
attributes like `.jsonContent` or `.tomlContent` which ensures that the file
|
|
is only parsed once, even if the parsed content is used in multiple places.
|
|
|
|
produces this structure:
|
|
{
|
|
files = {
|
|
"package.json" = {
|
|
relPath = "package.json"
|
|
fullPath = "${source}/package.json"
|
|
content = ;
|
|
jsonContent = ;
|
|
tomlContent = ;
|
|
}
|
|
};
|
|
directories = {
|
|
"packages" = {
|
|
relPath = "packages";
|
|
fullPath = "${source}/packages";
|
|
files = {
|
|
|
|
};
|
|
directories = {
|
|
|
|
};
|
|
};
|
|
};
|
|
}
|
|
*/
|
|
prepareSourceTree = {
|
|
source,
|
|
depth ? 10,
|
|
}:
|
|
prepareSourceTreeInternal source "" "" depth;
|
|
|
|
readTextFile = file: l.replaceStrings ["\r\n"] ["\n"] (l.readFile file);
|
|
|
|
prepareSourceTreeInternal = sourceRoot: relPath: name: depth: let
|
|
relPath' = relPath;
|
|
fullPath' = "${toString sourceRoot}/${relPath}";
|
|
current = l.readDir fullPath';
|
|
|
|
fileNames =
|
|
l.filterAttrs (n: v: v == "regular") current;
|
|
|
|
directoryNames =
|
|
l.filterAttrs (n: v: v == "directory") current;
|
|
|
|
makeNewPath = prefix: name:
|
|
if prefix == ""
|
|
then name
|
|
else "${prefix}/${name}";
|
|
|
|
directories =
|
|
l.mapAttrs
|
|
(dname: _:
|
|
prepareSourceTreeInternal
|
|
sourceRoot
|
|
(makeNewPath relPath dname)
|
|
dname
|
|
(depth - 1))
|
|
directoryNames;
|
|
|
|
files =
|
|
l.mapAttrs
|
|
(fname: _: rec {
|
|
name = fname;
|
|
fullPath = "${fullPath'}/${fname}";
|
|
relPath = makeNewPath relPath' fname;
|
|
content = readTextFile fullPath;
|
|
jsonContent = l.fromJSON content;
|
|
tomlContent = l.fromTOML content;
|
|
})
|
|
fileNames;
|
|
|
|
# returns the tree object of the given sub-path
|
|
getNodeFromPath = path: let
|
|
cleanPath = l.removePrefix "/" path;
|
|
pathSplit = l.splitString "/" cleanPath;
|
|
dirSplit = l.init pathSplit;
|
|
leaf = l.last pathSplit;
|
|
error = throw ''
|
|
Failed while trying to navigate to ${path} from ${fullPath'}
|
|
'';
|
|
|
|
dirAttrPath =
|
|
l.init
|
|
(l.concatMap
|
|
(x: [x] ++ ["directories"])
|
|
dirSplit);
|
|
|
|
dir =
|
|
if (l.length dirSplit == 0) || dirAttrPath == [""]
|
|
then self
|
|
else if ! l.hasAttrByPath dirAttrPath directories
|
|
then error
|
|
else l.getAttrFromPath dirAttrPath directories;
|
|
in
|
|
if path == ""
|
|
then self
|
|
else if dir ? directories."${leaf}"
|
|
then dir.directories."${leaf}"
|
|
else if dir ? files."${leaf}"
|
|
then dir.files."${leaf}"
|
|
else error;
|
|
|
|
self =
|
|
{
|
|
inherit files getNodeFromPath name relPath;
|
|
|
|
fullPath = fullPath';
|
|
}
|
|
# stop recursion if depth is reached
|
|
// (l.optionalAttrs (depth > 0) {
|
|
inherit directories;
|
|
});
|
|
in
|
|
self;
|
|
in
|
|
prepareSourceTree
|