diff --git a/flakeModules/clan.nix b/flakeModules/clan.nix index ae960793c..a78ac5aad 100644 --- a/flakeModules/clan.nix +++ b/flakeModules/clan.nix @@ -34,7 +34,7 @@ in type = types.submoduleWith { specialArgs = { inherit clan-core self; - inherit (inputs) nixpkgs; + inherit (inputs) nixpkgs nix-darwin; # TODO: inject the inventory interface # inventoryInterface = {}; }; diff --git a/lib/build-clan/default.nix b/lib/build-clan/default.nix index 466368484..baa43bbd9 100644 --- a/lib/build-clan/default.nix +++ b/lib/build-clan/default.nix @@ -4,6 +4,7 @@ { lib, nixpkgs, + nix-darwin ? null, ... }: { @@ -54,6 +55,7 @@ inherit lib nixpkgs + nix-darwin clan-core self ; diff --git a/lib/build-clan/function-adapter.nix b/lib/build-clan/function-adapter.nix index 4a11fd1e0..aa8b1a601 100644 --- a/lib/build-clan/function-adapter.nix +++ b/lib/build-clan/function-adapter.nix @@ -1,6 +1,7 @@ { lib, nixpkgs, + nix-darwin ? null, clan-core, self, specialArgs ? { }, @@ -9,7 +10,12 @@ module: (lib.evalModules { specialArgs = { - inherit self clan-core nixpkgs; + inherit + self + clan-core + nixpkgs + nix-darwin + ; }; modules = [ ./interface.nix diff --git a/lib/build-clan/interface.nix b/lib/build-clan/interface.nix index 2f92275c0..c6436fb1a 100644 --- a/lib/build-clan/interface.nix +++ b/lib/build-clan/interface.nix @@ -123,6 +123,15 @@ in }; # Outputs + darwinConfigurations = lib.mkOption { + # Hide from documentation. + # Exposed at the top-level of the flake, clan.darwinConfigurations should not used by the user. + # Instead, the user should use the `.#darwinConfigurations` attribute of the flake output. + visible = false; + type = types.lazyAttrsOf types.raw; + default = { }; + }; + nixosConfigurations = lib.mkOption { # Hide from documentation. # Exposed at the top-level of the flake, clan.nixosConfigurations should not used by the user. diff --git a/lib/build-clan/module.nix b/lib/build-clan/module.nix index 5072bf499..9f69bf99b 100644 --- a/lib/build-clan/module.nix +++ b/lib/build-clan/module.nix @@ -3,6 +3,7 @@ config, clan-core, nixpkgs, + nix-darwin, lib, ... }: @@ -48,51 +49,99 @@ let } ); - # TODO: remove default system once we have a hardware-config mechanism - nixosConfiguration = - { - system ? null, - name, - pkgs ? null, - extraConfig ? { }, - }: - nixpkgs.lib.nixosSystem { - modules = - let - hwConfig = "${directory}/machines/${name}/hardware-configuration.nix"; - diskoConfig = "${directory}/machines/${name}/disko.nix"; - in - [ + moduleSystemConstructor = { + # TODO: remove default system once we have a hardware-config mechanism + nixos = + { + system ? null, + name, + pkgs ? null, + extraConfig ? { }, + }: + nixpkgs.lib.nixosSystem { + modules = + let + hwConfig = "${directory}/machines/${name}/hardware-configuration.nix"; + diskoConfig = "${directory}/machines/${name}/disko.nix"; + in + [ + { + # Autoinclude configuration.nix and hardware-configuration.nix + imports = builtins.filter builtins.pathExists [ + "${directory}/machines/${name}/configuration.nix" + hwConfig + diskoConfig + ]; + } + clan-core.nixosModules.clanCore + extraConfig + (machines.${name} or { }) + # Inherit the inventory assertions ? + # { inherit (mergedInventory) assertions; } + { imports = inventoryClass.machines.${name}.machineImports or [ ]; } + + # Import the distribute services + { imports = config.clanInternals.distributedServices.allMachines.${name} or [ ]; } + ( + { + # Settings + clan.core.settings = { + inherit directory; + inherit (config.inventory.meta) name icon; + + machine = { + inherit name; + }; + }; + # Inherited from clan wide settings + # TODO: remove these + + networking.hostName = lib.mkDefault name; + + # For vars we need to override the system so we run vars + # generators on the machine that runs `clan vars generate`. If a + # users is using the `pkgsForSystem`, we don't set + # nixpkgs.hostPlatform it would conflict with the `nixpkgs.pkgs` + # option. + nixpkgs.hostPlatform = lib.mkIf (system != null && (pkgsForSystem system) != null) ( + lib.mkForce system + ); + } + // lib.optionalAttrs (pkgs != null) { nixpkgs.pkgs = lib.mkForce pkgs; } + ) + ]; + + specialArgs = { + inherit clan-core; + } // specialArgs; + }; + + darwin = + { + system ? null, + name, + pkgs ? null, + extraConfig ? { }, + }: + nix-darwin.lib.darwinSystem { + modules = [ { - # Autoinclude configuration.nix and hardware-configuration.nix imports = builtins.filter builtins.pathExists [ "${directory}/machines/${name}/configuration.nix" - hwConfig - diskoConfig ]; } - clan-core.nixosModules.clanCore + ( + if !lib.hasAttrByPath [ "darwinModules" "clanCore" ] clan-core then + { } + else + throw "this should import clan-core.darwinModules.clanCore" + ) extraConfig (machines.${name} or { }) - # Inherit the inventory assertions ? - # { inherit (mergedInventory) assertions; } - { imports = inventoryClass.machines.${name}.machineImports or [ ]; } - - # Import the distribute services - { imports = config.clanInternals.distributedServices.allMachines.${name} or [ ]; } + # TODO: import inventory when it has support for defining `nix-darwin` modules ( { - # Settings - clan.core.settings = { - inherit directory; - inherit (config.inventory.meta) name icon; - - machine = { - inherit name; - }; - }; - # Inherited from clan wide settings - # TODO: remove these + # TODO: set clan-core settings when clan-core has support for `nix-darwin` networking.hostName = lib.mkDefault name; @@ -109,16 +158,24 @@ let ) ]; - specialArgs = { - inherit clan-core; - } // specialArgs; - }; + specialArgs = { + inherit clan-core; + } // specialArgs; + }; + }; allMachines = inventory.machines or { } // machines; - nixosConfigurations = lib.mapAttrs (name: _: nixosConfiguration { inherit name; }) allMachines; + machineClass = lib.mapAttrs (name: _: inventory.machineClass.${name} or "nixos") allMachines; - # This instantiates nixos for each system that we support: + configurations = lib.mapAttrs ( + name: _: moduleSystemConstructor.${machineClass.${name}} { inherit name; } + ) allMachines; + + nixosConfigurations = lib.filterAttrs (name: _: machineClass.${name} == "nixos") configurations; + darwinConfigurations = lib.filterAttrs (name: _: machineClass.${name} == "darwin") configurations; + + # This instantiates NixOS for each system that we support: # configPerSystem = ..nixosConfiguration # We need this to build nixos secret generators for each system configsPerSystem = builtins.listToAttrs ( @@ -127,7 +184,7 @@ let lib.nameValuePair system ( lib.mapAttrs ( name: _: - nixosConfiguration { + moduleSystemConstructor.${machineClass.${name}} { inherit name system; pkgs = pkgsFor.${system}; } @@ -142,7 +199,7 @@ let lib.nameValuePair system ( lib.mapAttrs ( name: _: args: - nixosConfiguration ( + moduleSystemConstructor.${machineClass.${name}} ( args // { inherit name system; @@ -194,6 +251,7 @@ in ]; inherit nixosConfigurations; + inherit darwinConfigurations; clanInternals = { moduleSchemas = clan-core.lib.modules.getModulesSchema config.inventory.modules; @@ -223,11 +281,17 @@ in # machine specifics machines = configsPerSystem; machinesFunc = configsFuncPerSystem; - all-machines-json = lib.mapAttrs ( - system: configs: - nixpkgs.legacyPackages.${system}.writers.writeJSON "machines.json" ( - lib.mapAttrs (_: m: m.config.system.clan.deployment.data) configs - ) - ) configsPerSystem; + all-machines-json = + if !lib.hasAttrByPath [ "darwinModules" "clanCore" ] clan-core then + lib.mapAttrs ( + system: configs: + nixpkgs.legacyPackages.${system}.writers.writeJSON "machines.json" ( + lib.mapAttrs (_: m: m.config.system.clan.deployment.data) ( + lib.filterAttrs (_n: v: v.class == "nixos") configs + ) + ) + ) configsPerSystem + else + throw "remove NixOS filter and support nix-darwin as well"; }; } diff --git a/lib/build-clan/public.nix b/lib/build-clan/public.nix index fb34480a6..3f1783a9a 100644 --- a/lib/build-clan/public.nix +++ b/lib/build-clan/public.nix @@ -14,5 +14,6 @@ topLevel = [ "clanInternals" "nixosConfigurations" + "darwinConfigurations" ]; } diff --git a/lib/build-clan/tests.nix b/lib/build-clan/tests.nix index 68b85811c..f87918e7a 100644 --- a/lib/build-clan/tests.nix +++ b/lib/build-clan/tests.nix @@ -76,7 +76,7 @@ in }; directory = ./.; imports = [ - # What the user needs to specif + # What the user needs to specify { directory = ./.; inventory.meta.name = "test"; @@ -165,10 +165,9 @@ in }; directory = ./.; meta.name = "test"; - inventory.machines.machine1.meta.name = "machine1"; + inventory.machines.machine1 = { }; machines.machine2 = { }; - }; in { @@ -200,4 +199,55 @@ in expr = result.nixosConfigurations.machine2.config.networking.hostName; expected = "dream2nix"; }; + + test_buildClan_darwin_machines = + let + result = buildClan { + self = { + inputs = { }; + }; + directory = ./.; + meta.name = "test"; + + machines.machine1 = { }; + machines.machine2 = { }; + machines.machine3 = { }; + + inventory.machineClass.machine2 = "darwin"; + inventory.machineClass.machine3 = "nixos"; + }; + in + { + expr = { + nixos = builtins.attrNames result.nixosConfigurations; + darwin = builtins.attrNames result.darwinConfigurations; + }; + expected = { + nixos = [ + "machine1" + "machine3" + ]; + darwin = [ "machine2" ]; + }; + }; + + test_buildClan_all_machines_laziness = + let + result = buildClan { + self = { + inputs = { }; + }; + directory = ./.; + meta.name = "test"; + + machines.machine1.non_existent_option = throw "eval error"; + inventory.machines.machine1.other_non_existent_option = throw "different eval error"; + }; + in + { + expr = builtins.attrNames result.nixosConfigurations; + expected = [ + "machine1" + ]; + }; } diff --git a/lib/default.nix b/lib/default.nix index 2d31c3048..ada137e8b 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -2,6 +2,7 @@ lib, self, nixpkgs, + nix-darwin ? null, ... }: # Produces the @@ -20,7 +21,7 @@ lib.fix (clanLib: { clan-core = self; pkgs = nixpkgs.legacyPackages.x86_64-linux; }; - buildClanModule = clanLib.callLib ./build-clan { inherit nixpkgs; }; + buildClanModule = clanLib.callLib ./build-clan { inherit nixpkgs nix-darwin; }; buildClan = clanLib.buildClanModule.buildClanWith { clan-core = self; }; # ------------------------------------ diff --git a/lib/flake-module.nix b/lib/flake-module.nix index a7cd3d5b9..19c093391 100644 --- a/lib/flake-module.nix +++ b/lib/flake-module.nix @@ -15,7 +15,7 @@ rec { ]; flake.clanLib = import ./default.nix { inherit lib inputs self; - inherit (inputs) nixpkgs; + inherit (inputs) nixpkgs nix-darwin; }; # TODO: remove this legacy alias flake.lib = flake.clanLib; diff --git a/lib/inventory/build-inventory/interface.nix b/lib/inventory/build-inventory/interface.nix index b496bb962..e04f35ab1 100644 --- a/lib/inventory/build-inventory/interface.nix +++ b/lib/inventory/build-inventory/interface.nix @@ -277,6 +277,22 @@ in ) ); }; + + machineClass = lib.mkOption { + default = { }; + type = types.attrsOf ( + types.enum [ + "nixos" + "darwin" + ] + ); + description = '' + The module system that should be used to construct the machine + + Set this to `darwin` for macOS machines + ''; + }; + instances = lib.mkOption { # Keep as internal until all de-/serialization issues are resolved visible = false; diff --git a/pkgs/clan-cli/clan_cli/inventory/classes.py b/pkgs/clan-cli/clan_cli/inventory/classes.py index 3ed9d3342..d21fb139c 100644 --- a/pkgs/clan-cli/clan_cli/inventory/classes.py +++ b/pkgs/clan-cli/clan_cli/inventory/classes.py @@ -29,6 +29,7 @@ Service = dict[str, Any] class Inventory(TypedDict): + machineClass: NotRequired[dict[str, Any]] machines: NotRequired[dict[str, Machine]] meta: NotRequired[Meta] modules: NotRequired[dict[str, Any]]