tvl-depot/read-tree.nix
Vincent Ambo 467a66bac2 feat(readTree): Add support for skipping directory subtrees
Placing a special `.skip-subtree` file in any directory will now
prevent readTree from further traversing that part of the tree.

This makes it possible to have packages with internal Nix files that
are incompatible with the larger depot structure, for example for
projects like buildGo.nix which need to be compatible with the
external nixpkgs model.
2019-12-19 15:33:30 +00:00

61 lines
1.7 KiB
Nix

args: initPath:
let
inherit (builtins)
attrNames
baseNameOf
filter
hasAttr
head
length
listToAttrs
map
match
isAttrs
readDir;
argsWithPath = parts: args // {
locatedAt = parts;
};
# The marker is added to every set that was imported directly by
# readTree.
importWithMark = path: parts:
let imported = import path (argsWithPath parts);
in if (isAttrs imported)
then imported // { __readTree = true; }
else imported;
nixFileName = file:
let res = match "(.*)\.nix" file;
in if res == null then null else head res;
readTree = path: parts:
let
dir = readDir path;
self = importWithMark path parts;
joinChild = c: path + ("/" + c);
# Import subdirectories of the current one, unless the special
# `.skip-subtree` file exists which makes readTree ignore the
# children.
#
# This file can optionally contain information on why the tree
# should be ignored, but its content is not inspected by
# readTree
filterDir = f: dir."${f}" == "directory";
children = if hasAttr ".skip-subtree" dir then [] else map (c: {
name = c;
value = readTree (joinChild c) (parts ++ [ c ]);
}) (filter filterDir (attrNames dir));
# Import Nix files
nixFiles = filter (f: f != null) (map nixFileName (attrNames dir));
nixChildren = map (c: let p = joinChild (c + ".nix"); in {
name = c;
value = importWithMark p (parts ++ [ c ]);
}) nixFiles;
in if dir ? "default.nix"
then self // (listToAttrs children)
else listToAttrs (nixChildren ++ children);
in readTree initPath [ (baseNameOf initPath) ]