{ nixpkgs, home-manager, hostsFolder, hardwaresFolder, modulesFolder, flakeRoot, homeDirectory ? "/home", inputs, globalConfig ? { }, globalOverlays ? [ ], defaultUser ? "meow", }: let inherit (nixpkgs) lib; self = rec { inherit hostsFolder hardwaresFolder modulesFolder globalConfig globalOverlays flakeRoot ; moduleList = builtins.attrNames (builtins.readDir modulesFolder); mergedModules = mergeModules ( builtins.listToAttrs ( map (fn: { name = fn; value = (import "${modulesFolder}/${fn}" { }); }) moduleList ) ); generateHostname = { hostName, hardwareName, system, }: "${hardwareName}-${hostName}-${system}"; mkHost = { host, hardware, system, stateVersion, overlays ? [ ], nixpkgsConfig ? { }, nixpkgsHostPlatform ? null, user ? defaultUser, }: let hostSystemConfig = "${hostsFolder}/${host}/nixos.nix"; hardwareSystemConfig = "${hardwaresFolder}/${hardware}/nixos.nix"; hostHomeConfig = "${hostsFolder}/${host}/home.nix"; hardwareHomeConfig = "${hardwaresFolder}/${hardware}/home.nix"; hostSystemExists = builtins.pathExists hostSystemConfig; hardwareSystemExists = builtins.pathExists hardwareSystemConfig; hostHomeExists = builtins.pathExists hostHomeConfig; hardwareHomeExists = builtins.pathExists hardwareHomeConfig; hasNixos = hostSystemExists || hardwareSystemExists; hasHome = hostHomeExists || hardwareHomeExists; importIfExists = path: if builtins.pathExists path then [ (import path) ] else [ ]; nixosModules = (importIfExists hostSystemConfig) ++ (importIfExists hardwareSystemConfig) ++ mergedModules.nixos; homeModules = (importIfExists hostHomeConfig) ++ (importIfExists hardwareHomeConfig) ++ mergedModules.home; hostname = generateHostname { hostName = host; hardwareName = hardware; inherit system; }; extraArgs = { inherit inputs; hostname = "${hardware}-${host}"; nix-meow = self; }; mergedNixpkgsConfig = deepMerge [ globalConfig nixpkgsConfig ]; mergedOverlays = overlays ++ globalOverlays; nixosConfigurations = lib.optionalAttrs hasNixos { ${hostname} = nixpkgs.lib.nixosSystem { specialArgs = extraArgs // { inherit user system; installer = false; }; inherit system; modules = [ { nixpkgs.config = mergedNixpkgsConfig; nixpkgs.overlays = mergedOverlays; } { system.stateVersion = lib.mkForce stateVersion; } ] ++ nixosModules; }; }; homeConfigurations = lib.optionalAttrs hasHome { ${hostname} = home-manager.lib.homeManagerConfiguration { pkgs = import nixpkgs { inherit system; config = mergedNixpkgsConfig; overlays = mergedOverlays; }; extraSpecialArgs = extraArgs // { inherit system user; }; modules = [ { home = { stateVersion = lib.mkForce stateVersion; homeDirectory = "${homeDirectory}/${user}"; username = user; }; } ] ++ homeModules; }; }; in { debug.${hostname} = { inherit host hardware system stateVersion hostSystemConfig hardwareSystemConfig hostHomeConfig hardwareHomeConfig hostSystemExists hardwareSystemExists hostHomeExists hardwareHomeExists hasNixos hasHome hostname ; }; inherit nixosConfigurations homeConfigurations; }; mergeHosts = { hosts, hardwares }: let inherit (builtins) attrNames map filter concatMap removeAttrs elem ; hostNames = attrNames hosts; hardwareNames = attrNames hardwares; in concatMap ( hostName: let hostAttrs = hosts.${hostName}; hostNoSystems = removeAttrs hostAttrs [ "systems" ]; hostSystems = hostAttrs.systems; in concatMap ( system: let matchingHardwares = filter ( hardwareName: elem system hardwares.${hardwareName}.systems ) hardwareNames; in map (hardwareName: { hardware = removeAttrs hardwares.${hardwareName} [ "systems" ]; host = hostNoSystems; inherit system hardwareName hostName; }) matchingHardwares ) hostSystems ) hostNames; deepMergeInner = a: b: builtins.foldl' ( merged: key: merged // { ${key} = if (a ? ${key}) && (b ? ${key}) && (builtins.isAttrs a.${key}) && (builtins.isAttrs b.${key}) then deepMergeInner a.${key} b.${key} else if (a ? ${key}) && (b ? ${key}) && (builtins.isList a.${key}) && (builtins.isList b.${key}) then a.${key} ++ b.${key} else b.${key} or a.${key}; } ) { } (builtins.attrNames (a // b)); deepMerge = sets: builtins.foldl' deepMergeInner { } sets; mergeModules = modules: let mergedModules = builtins.attrValues ( builtins.mapAttrs (name: module: { nixos = if builtins.hasAttr "nixos" module then [ module.nixos ] else [ ]; home = if builtins.hasAttr "home" module then [ module.home ] else [ ]; }) modules ); in deepMerge mergedModules; }; in self