From 25281821e9be741bf1ab0de98572171adddaee11 Mon Sep 17 00:00:00 2001 From: clo4 Date: Tue, 18 Feb 2025 08:57:25 +1100 Subject: [PATCH 1/2] feat: home configurations in top-level users dir Blueprint now supports defining user configurations in the top-level 'users' directory, and makes this a first-class way to share user configurations without exposing them in the public interface of the flake. Users are created in 'users//home-configuration.nix' (though this is easy to change in the future). Existing home configurations can access all the generic configurations through the new 'users' argument. For example, a user defined at 'users/baz/home-configuration.nix' could be imported and used as a base by 'hosts/foobar/users/baz.nix' (`imports = [ users.baz ];`) OR as a standalone configuration without a hostname. Editorial: new users should still be encouraged to start creating their configuration per-machine to reduce the complexity of their config, and only move to a shared config when they _need_ to share it between multiple devices. --- lib/default.nix | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/lib/default.nix b/lib/default.nix index 5b84b36..cb2f8e0 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -128,6 +128,10 @@ let self = throw "self was renamed to flake"; }; + hmSpecialArgs = specialArgs // { + users = homesGeneric; + }; + inherit (mkEachSystem { inherit @@ -165,7 +169,7 @@ let { imports = [ homeManagerModule ]; home-manager.sharedModules = [ perSystemModule ]; - home-manager.extraSpecialArgs = specialArgs; + home-manager.extraSpecialArgs = hmSpecialArgs; home-manager.users = homesNested.${hostname}; home-manager.useGlobalPkgs = lib.mkDefault true; home-manager.useUserPackages = lib.mkDefault true; @@ -173,6 +177,26 @@ let in lib.optional (builtins.hasAttr hostname homesNested) module; + homesGeneric = + let + getEntryPath = + _username: userEntry: + if builtins.pathExists (userEntry.path + "/home-configuration.nix") then + userEntry.path + "/home-configuration.nix" + else + # If we decide to add users/.nix, it's as simple as + # testing `if userEntry.type == "regular"` + null; + + mkUsers = + userEntries: + let + users = lib.mapAttrs getEntryPath userEntries; + in + lib.filterAttrs (_name: value: value != null) users; + in + importDir (src + "/users") mkUsers; + # Attribute set mapping hostname (defined in hosts/) to a set of home # configurations (modules) for that host. If a host has no home # configuration, it will be omitted from the set. Likewise, if the user @@ -220,7 +244,7 @@ let }: home-manager.lib.homeManagerConfiguration { inherit pkgs; - extraSpecialArgs = specialArgs; + extraSpecialArgs = hmSpecialArgs; modules = [ perSystemModule modulePath @@ -258,13 +282,17 @@ let eachSystem ( { pkgs, ... }: { - homeConfigurations = lib.mapAttrs ( - _name: homeData: - mkHomeConfiguration { - inherit (homeData) modulePath username; - inherit pkgs; - } - ) homesFlat; + homeConfigurations = + lib.mapAttrs ( + _name: homeData: + mkHomeConfiguration { + inherit (homeData) modulePath username; + inherit pkgs; + } + ) homesFlat + // lib.mapAttrs ( + username: modulePath: mkHomeConfiguration { inherit pkgs username modulePath; } + ) homesGeneric; } ); @@ -468,7 +496,7 @@ let # nix3 CLI output (`packages` output expects flat attrset) # FIXME: Find another way to make this work without introducing legacyPackages. # May involve changing upstream home-manager. - legacyPackages = lib.optionalAttrs (homesNested != { }) standaloneHomeConfigurations; + legacyPackages = standaloneHomeConfigurations; darwinConfigurations = lib.mapAttrs (_: x: x.value) (hostsByCategory.darwinConfigurations or { }); nixosConfigurations = lib.mapAttrs (_: x: x.value) (hostsByCategory.nixosConfigurations or { }); From b033f96062fd91c024f6a04ee2cbf7c168a28a6e Mon Sep 17 00:00:00 2001 From: clo4 Date: Sat, 1 Mar 2025 18:14:24 +1100 Subject: [PATCH 2/2] refactor: remove 'users' attrset from module args This commit removes the 'users' attrset, as it doesn't give users anything they can't get from referencing the file path directly. Referencing the file by path makes the dependency tree more obvious. This commit can (should?) be squashed into its parent before merge. --- lib/default.nix | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/default.nix b/lib/default.nix index cb2f8e0..78685d0 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -128,10 +128,6 @@ let self = throw "self was renamed to flake"; }; - hmSpecialArgs = specialArgs // { - users = homesGeneric; - }; - inherit (mkEachSystem { inherit @@ -169,7 +165,7 @@ let { imports = [ homeManagerModule ]; home-manager.sharedModules = [ perSystemModule ]; - home-manager.extraSpecialArgs = hmSpecialArgs; + home-manager.extraSpecialArgs = specialArgs; home-manager.users = homesNested.${hostname}; home-manager.useGlobalPkgs = lib.mkDefault true; home-manager.useUserPackages = lib.mkDefault true; @@ -244,7 +240,7 @@ let }: home-manager.lib.homeManagerConfiguration { inherit pkgs; - extraSpecialArgs = hmSpecialArgs; + extraSpecialArgs = specialArgs; modules = [ perSystemModule modulePath