2021-04-12 15:52:51 +02:00
|
|
|
|
# Copyright (c) 2019 Vincent Ambo
|
|
|
|
|
# Copyright (c) 2020-2021 The TVL Authors
|
|
|
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
|
#
|
|
|
|
|
# Provides a function to automatically read a a filesystem structure
|
|
|
|
|
# into a Nix attribute set.
|
2021-08-26 18:41:50 +02:00
|
|
|
|
#
|
2021-09-08 17:16:11 +02:00
|
|
|
|
# Called with an attribute set taking the following arguments:
|
|
|
|
|
#
|
|
|
|
|
# path: Path to a directory from which to start reading the tree.
|
|
|
|
|
#
|
|
|
|
|
# args: Argument set to pass to each imported file.
|
|
|
|
|
#
|
|
|
|
|
# filter: Function to filter `args` based on the tree location. This should
|
|
|
|
|
# be a function of the form `args -> location -> args`, where the
|
|
|
|
|
# location is a list of strings representing the path components of
|
|
|
|
|
# the current readTree target. Optional.
|
|
|
|
|
{ ... }:
|
2019-12-21 06:42:32 +01:00
|
|
|
|
|
2019-11-15 15:52:23 +01:00
|
|
|
|
let
|
|
|
|
|
inherit (builtins)
|
|
|
|
|
attrNames
|
2019-12-09 21:34:49 +01:00
|
|
|
|
baseNameOf
|
2020-08-27 02:50:33 +02:00
|
|
|
|
concatStringsSep
|
2019-11-15 15:52:23 +01:00
|
|
|
|
filter
|
2019-12-19 16:33:30 +01:00
|
|
|
|
hasAttr
|
2019-11-15 15:52:23 +01:00
|
|
|
|
head
|
2020-05-28 14:51:36 +02:00
|
|
|
|
isAttrs
|
2019-11-25 16:32:02 +01:00
|
|
|
|
length
|
2019-11-15 15:52:23 +01:00
|
|
|
|
listToAttrs
|
|
|
|
|
map
|
|
|
|
|
match
|
2020-05-28 14:51:36 +02:00
|
|
|
|
readDir
|
|
|
|
|
substring;
|
2019-11-15 15:52:23 +01:00
|
|
|
|
|
2021-01-30 06:58:54 +01:00
|
|
|
|
argsWithPath = args: parts:
|
2020-08-04 10:50:10 +02:00
|
|
|
|
let meta.locatedAt = parts;
|
|
|
|
|
in meta // (if isAttrs args then args else args meta);
|
2019-11-15 15:52:23 +01:00
|
|
|
|
|
2020-05-28 14:51:36 +02:00
|
|
|
|
readDirVisible = path:
|
|
|
|
|
let
|
|
|
|
|
children = readDir path;
|
|
|
|
|
isVisible = f: f == ".skip-subtree" || (substring 0 1 f) != ".";
|
|
|
|
|
names = filter isVisible (attrNames children);
|
|
|
|
|
in listToAttrs (map (name: {
|
|
|
|
|
inherit name;
|
|
|
|
|
value = children.${name};
|
|
|
|
|
}) names);
|
|
|
|
|
|
2020-08-27 02:50:33 +02:00
|
|
|
|
# Create a mark containing the location of this attribute.
|
|
|
|
|
marker = parts: {
|
|
|
|
|
__readTree = parts;
|
|
|
|
|
};
|
|
|
|
|
|
2019-12-10 15:46:05 +01:00
|
|
|
|
# The marker is added to every set that was imported directly by
|
2019-12-09 21:34:49 +01:00
|
|
|
|
# readTree.
|
2021-09-08 17:27:37 +02:00
|
|
|
|
importWithMark = args: scopedArgs: path: parts: filter:
|
|
|
|
|
let
|
|
|
|
|
importedFile = if scopedArgs != {}
|
|
|
|
|
then builtins.scopedImport scopedArgs path
|
|
|
|
|
else import path;
|
2021-01-30 09:25:05 +01:00
|
|
|
|
pathType = builtins.typeOf importedFile;
|
|
|
|
|
imported =
|
2021-09-08 23:50:11 +02:00
|
|
|
|
if pathType != "lambda"
|
|
|
|
|
then builtins.throw "readTree: trying to import ${toString path}, but it’s a ${pathType}, you need to make it a function like { depot, pkgs, ... }"
|
|
|
|
|
else importedFile (filter (argsWithPath args parts) parts);
|
2019-12-10 15:46:05 +01:00
|
|
|
|
in if (isAttrs imported)
|
2020-08-27 02:50:33 +02:00
|
|
|
|
then imported // (marker parts)
|
2019-12-10 15:46:05 +01:00
|
|
|
|
else imported;
|
2019-11-15 15:52:23 +01:00
|
|
|
|
|
2019-12-09 21:34:49 +01:00
|
|
|
|
nixFileName = file:
|
2021-02-17 23:48:54 +01:00
|
|
|
|
let res = match "(.*)\\.nix" file;
|
2019-11-15 15:52:23 +01:00
|
|
|
|
in if res == null then null else head res;
|
|
|
|
|
|
2021-09-08 17:27:37 +02:00
|
|
|
|
readTree = { args, initPath, rootDir, parts, argsFilter, scopedArgs }:
|
2019-12-09 04:16:02 +01:00
|
|
|
|
let
|
2021-01-30 06:58:54 +01:00
|
|
|
|
dir = readDirVisible initPath;
|
|
|
|
|
joinChild = c: initPath + ("/" + c);
|
2019-12-09 21:34:49 +01:00
|
|
|
|
|
2021-04-12 21:49:36 +02:00
|
|
|
|
self = if rootDir
|
|
|
|
|
then { __readTree = []; }
|
2021-09-08 17:27:37 +02:00
|
|
|
|
else importWithMark args scopedArgs initPath parts argsFilter;
|
2021-04-12 21:49:36 +02:00
|
|
|
|
|
2019-12-19 16:33:30 +01:00
|
|
|
|
# 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
|
2019-12-09 21:34:49 +01:00
|
|
|
|
filterDir = f: dir."${f}" == "directory";
|
2019-12-19 16:33:30 +01:00
|
|
|
|
children = if hasAttr ".skip-subtree" dir then [] else map (c: {
|
2019-12-09 21:34:49 +01:00
|
|
|
|
name = c;
|
2021-04-12 21:49:36 +02:00
|
|
|
|
value = readTree {
|
2021-09-08 17:27:37 +02:00
|
|
|
|
inherit argsFilter scopedArgs;
|
2021-04-12 21:49:36 +02:00
|
|
|
|
args = args;
|
|
|
|
|
initPath = (joinChild c);
|
|
|
|
|
rootDir = false;
|
|
|
|
|
parts = (parts ++ [ c ]);
|
|
|
|
|
};
|
2019-12-09 21:34:49 +01:00
|
|
|
|
}) (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;
|
2021-09-08 17:27:37 +02:00
|
|
|
|
value = importWithMark args scopedArgs p (parts ++ [ c ]) argsFilter;
|
2019-12-09 21:34:49 +01:00
|
|
|
|
}) nixFiles;
|
2019-12-02 16:05:54 +01:00
|
|
|
|
in if dir ? "default.nix"
|
2019-12-20 21:44:00 +01:00
|
|
|
|
then (if isAttrs self then self // (listToAttrs children) else self)
|
2020-08-27 02:50:33 +02:00
|
|
|
|
else (listToAttrs (nixChildren ++ children) // (marker parts));
|
2021-01-30 06:58:54 +01:00
|
|
|
|
|
|
|
|
|
in {
|
2021-09-08 17:16:11 +02:00
|
|
|
|
__functor = _:
|
|
|
|
|
{ path
|
|
|
|
|
, args
|
2021-09-08 17:27:37 +02:00
|
|
|
|
, filter ? (x: _parts: x)
|
|
|
|
|
, scopedArgs ? {} }:
|
2021-09-08 17:16:11 +02:00
|
|
|
|
readTree {
|
2021-09-08 17:27:37 +02:00
|
|
|
|
inherit args scopedArgs;
|
2021-09-08 17:16:11 +02:00
|
|
|
|
argsFilter = filter;
|
|
|
|
|
initPath = path;
|
|
|
|
|
rootDir = true;
|
|
|
|
|
parts = [];
|
|
|
|
|
};
|
2021-01-30 06:58:54 +01:00
|
|
|
|
}
|