From 237e0bce9b0c8a8c65603520fba76e71a10f9be1 Mon Sep 17 00:00:00 2001 From: Pacman99 Date: Tue, 25 May 2021 11:10:29 -0700 Subject: [PATCH] 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 --- flake.nix | 4 +- src/generators.nix | 8 +-- src/importers.nix | 107 +++++++++++++++------------- src/lists.nix | 15 ---- src/pkgs-lib/tests/lib.nix | 93 ------------------------ tests/fullFlake/profiles/suites.nix | 10 --- tests/lib.nix | 17 ++--- tests/profiles/f.nix | 0 8 files changed, 69 insertions(+), 185 deletions(-) delete mode 100644 src/pkgs-lib/tests/lib.nix delete mode 100644 tests/fullFlake/profiles/suites.nix create mode 100644 tests/profiles/f.nix diff --git a/flake.nix b/flake.nix index 467345e..a628bd5 100644 --- a/flake.nix +++ b/flake.nix @@ -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; } ); diff --git a/src/generators.nix b/src/generators.nix index 15eda32..14b7627 100644 --- a/src/generators.nix +++ b/src/generators.nix @@ -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; }; } diff --git a/src/importers.nix b/src/importers.nix index 4858c84..2e1f65d 100644 --- a/src/importers.nix +++ b/src/importers.nix @@ -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); }; } diff --git a/src/lists.nix b/src/lists.nix index 4bef865..8077d5e 100644 --- a/src/lists.nix +++ b/src/lists.nix @@ -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); } diff --git a/src/pkgs-lib/tests/lib.nix b/src/pkgs-lib/tests/lib.nix deleted file mode 100644 index 586eac3..0000000 --- a/src/pkgs-lib/tests/lib.nix +++ /dev/null @@ -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 = [ ]; - }; - }; - }; -} diff --git a/tests/fullFlake/profiles/suites.nix b/tests/fullFlake/profiles/suites.nix deleted file mode 100644 index eadb20c..0000000 --- a/tests/fullFlake/profiles/suites.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ users, profiles, userProfiles, ... }: - -{ - system = with profiles; rec { - base = [ core users.nixos users.root ]; - }; - user = with userProfiles; rec { - base = [ direnv git ]; - }; -} diff --git a/tests/lib.nix b/tests/lib.nix index 78536e7..dd2d002 100644 --- a/tests/lib.nix +++ b/tests/lib.nix @@ -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) ]; }; }; diff --git a/tests/profiles/f.nix b/tests/profiles/f.nix new file mode 100644 index 0000000..e69de29