1
1
mirror of https://github.com/divnix/digga.git synced 2024-12-23 08:02:21 +03:00

rakeLeaves: create and use standard auto-importer

The function picks up `.nix` files and stops recursing when it hits
a folder with a `default.nix`
This allows it to be used to collect hosts, overlays, and profiles
This commit is contained in:
Pacman99 2021-05-25 11:10:29 -07:00 committed by Parthiv Seetharaman
parent 8065740c86
commit 237e0bce9b
8 changed files with 69 additions and 185 deletions

View File

@ -40,9 +40,9 @@
};
inherit (attrs) mapFilterAttrs genAttrs' safeReadDir concatAttrs;
inherit (lists) profileMap collectProfiles unifyOverlays;
inherit (lists) unifyOverlays;
inherit (strings) rgxToString;
inherit (importers) mkProfileAttrs pathsIn importHosts;
inherit (importers) profileMap rakeLeaves;
inherit (generators) mkSuites mkDeployNodes mkHomeConfigurations;
}
);

View File

@ -37,14 +37,14 @@
let
profileSet = lib.genAttrs' profiles (path: {
name = baseNameOf path;
value = lib.mkProfileAttrs (toString path);
value = lib.rakeLeaves (toString path);
});
definedSuites = suites profileSet;
definedSuites = lib.mapAttrs (_: v: lib.profileMap v) (suites profileSet);
allProfiles = lib.collectProfiles profileSet;
allProfiles = lib.foldl (lhs: rhs: lhs ++ rhs) [ ] (builtins.attrValues definedSuites);
in
lib.mapAttrs (_: v: lib.profileMap v) definedSuites // {
definedSuites // {
inherit allProfiles;
};
}

View File

@ -1,73 +1,84 @@
{ lib }:
let
recImport = { dir, _import ? base: import "${dir}/${base}.nix" }:
lib.mapFilterAttrs
(_: v: v != null)
(n: v:
if n != "default.nix" && lib.hasSuffix ".nix" n && v == "regular"
then
let name = lib.removeSuffix ".nix" n; in lib.nameValuePair (name) (_import name)
else
lib.nameValuePair ("") (null))
(lib.safeReadDir dir);
mkProfileAttrs =
rakeLeaves =
/**
Synopsis: mkProfileAttrs _path_
Synopsis: rakeLeaves _path_
Recursively collect the subdirs of _path_ containing a default.nix into attrs.
This sets a contract, eliminating ambiguity for _default.nix_ living under the
profile directory.
Recursively collect the nix files of _path_ into attrs.
Example:
let profiles = mkProfileAttrs ./profiles; in
assert profiles ? core.default; 0
Output Format:
An attribute set where all `.nix` files and directories with `default.nix` in them
are mapped to keys(file with .nix stripped or folder name. All other directories
are recursed further into nested attribute sets with the same format.
Example file structure:
```
./core/default.nix
./base.nix
./main/dev.nix
./main/os/default.nix
```
Example output:
```
{
core = ./core;
base = base.nix;
main = {
dev = ./main/dev.nix;
os = ./main/os;
};
}
```
**/
dir:
dirPath:
let
imports =
let
files = lib.safeReadDir dir;
# Relative paths cause issues, so convert to string immediately
dir = toString dirPath;
p = n: v:
v == "directory"
&& n != "profiles";
in
lib.filterAttrs p files;
collect = file: type: {
name = lib.removeSuffix ".nix" file;
value = let path = "${dir}/${file}"; in
if (type == "regular")
|| (type == "directory" && builtins.pathExists "${path}/default.nix")
then path
else rakeLeaves path;
};
f = n: _:
lib.optionalAttrs
(lib.pathExists "${dir}/${n}/default.nix")
{ default = "${dir}/${n}"; }
// mkProfileAttrs "${dir}/${n}";
files = lib.filterAttrs
(file: type:
# Only include `.nix` files or directories
(type == "regular" && lib.hasSuffix ".nix" file) || (type == "directory")
)
(lib.safeReadDir dir);
in
lib.mapAttrs f imports;
pathsIn = dir:
let
fullPath = name: "${toString dir}/${name}";
in
map fullPath (lib.attrNames (lib.safeReadDir dir));
lib.mapAttrs' collect files;
getProfilePath = fallback: item:
if lib.isString item then item else fallback;
in
{
inherit pathsIn recImport mkProfileAttrs;
inherit rakeLeaves;
profileMap = list: map
(p: getProfilePath (throw "passed profile ${builtins.toJSON p} isn't a path") p)
(lib.flatten list);
overlays = dir:
{
# Meant to output a module that sets the overlays option
overlays = pathsIn dir;
# Only get top-level .nix files or default.nix from directories
overlays = map (getProfilePath (_: _: { })) (builtins.attrValues (rakeLeaves dir));
};
hosts = dir:
{
# Meant to output a module that sets the hosts option
hosts = recImport {
inherit dir;
_import = base: {
modules = import "${toString dir}/${base}.nix";
};
};
hosts = lib.mapAttrs
(n: p: {
# Only get top-level .nix files or default.nix from directories
modules = getProfilePath { } p;
})
(rakeLeaves dir);
};
}

View File

@ -1,19 +1,4 @@
{ lib }:
{
collectProfiles = set:
let
collectNestedProfiles = set:
lib.mapAttrsToList
(n: v:
if builtins.isAttrs v then
[ v.default or null ] ++ collectNestedProfiles v
else null
)
set;
in
builtins.filter (x: x != null) (lib.flatten (collectNestedProfiles set));
profileMap = list: map (profile: profile.default) (lib.flatten list);
unifyOverlays = channels: map (o: if builtins.isFunction (o null null) then o channels else o);
}

View File

@ -1,93 +0,0 @@
{ pkgs, lib, ... }:
with lib;
lib.runTests {
testConcatAttrs = {
expr = concatAttrs [{ foo = 1; } { bar = 2; } { baz = 3; }];
expected = { foo = 1; bar = 2; baz = 3; };
};
testGenAttrs' = {
expr = genAttrs'
[ "/foo/bar" "/baz/buzz" ]
(path: {
name = baseNameOf path;
value = "${path}/fizz";
});
expected = { bar = "/foo/bar/fizz"; buzz = "/baz/buzz/fizz"; };
};
testMapFilterAttrs = {
expr = mapFilterAttrs
(n: v: n == "foobar" && v == 1)
(n: v: lib.nameValuePair ("${n}bar") (v + 1))
{ foo = 0; bar = 2; };
expected = { foobar = 1; };
};
testPathsIn = {
expr = pathsIn (toString ./testPathsIn);
expected = map toString [
./testPathsIn/bar
./testPathsIn/baz
./testPathsIn/foo
];
};
testPathsToImportedAttrs = {
expr =
pathsToImportedAttrs [
(toString ./testPathsToImportedAttrs/dir)
./testPathsToImportedAttrs/foo.nix
./testPathsToImportedAttrs/bar.nix
./testPathsToImportedAttrs/t.nix
./testPathsToImportedAttrs/f.nix
];
expected = {
dir = { a = 5; };
foo = { bar = 1; };
bar = { foo = 2; };
t = true;
f = false;
};
};
testRgxToString = lib.testAllTrue [
(rgxToString ".+x" "vxk" == "vx")
(rgxToString "^fo" "foo" == "fo")
(rgxToString "a?" "a" == "a")
(rgxToString "hat" "foohatbar" == "hat")
];
testSafeReadDir = {
expr = safeReadDir ./profiles // safeReadDir ./nonexistentdir;
expected = {
foo = "directory";
t = "directory";
};
};
testSuites =
let
profiles = os.mkProfileAttrs (toString ./profiles);
users = "";
userProfiles = "";
suites = { profiles, ... }: {
system.bar = [ profiles.foo ];
};
in
{
expr = os.mkSuites { inherit profiles users userProfiles suites; };
expected = {
system = {
bar = [ profiles.foo.default ];
allProfiles = [ profiles.foo.default profiles.t.default ];
allUsers = [ ];
};
};
};
}

View File

@ -1,10 +0,0 @@
{ users, profiles, userProfiles, ... }:
{
system = with profiles; rec {
base = [ core users.nixos users.root ];
};
user = with userProfiles; rec {
base = [ direnv git ];
};
}

View File

@ -27,16 +27,6 @@ lib.runTests {
expected = { foobar = 1; };
};
testPathsIn = {
expr = pathsIn (toString ./testPathsIn);
expected = map toString [
./testPathsIn/bar
./testPathsIn/baz
./testPathsIn/foo
];
};
testRgxToString = lib.testAllTrue [
(rgxToString ".+x" "vxk" == "vx")
(rgxToString "^fo" "foo" == "fo")
@ -49,21 +39,22 @@ lib.runTests {
expected = {
foo = "directory";
t = "directory";
"f.nix" = "regular";
};
};
testSuites = {
expr = mkSuites {
suites = { profiles, ... }: with profiles; {
bar = [ foo ];
bar = [ foo f ];
};
profiles = [ (./profiles) ];
};
expected = {
bar = [ (toString ./profiles/foo) ];
bar = [ (toString ./profiles/foo) (toString ./profiles/f.nix) ];
allProfiles = [
(toString ./profiles/foo)
(toString ./profiles/t)
(toString ./profiles/f.nix)
];
};
};

0
tests/profiles/f.nix Normal file
View File