diff --git a/README.md b/README.md index a6e4cee..6caf191 100644 --- a/README.md +++ b/README.md @@ -6,22 +6,30 @@
## 🚧 State of development -Version 2.0 is still very much an experiment and not ready to be used in a production -environment. If you must, try running it within a VM using the provided deployment -instructions. +All the basic functionality of v2 should be working correctly, including: + +- The custom lib implementation at self.lib, recursively built from the contents of the `lib` directory. +- Loading of systems from the `systems` directory, using easy-hosts. + - A basic workstation archetype for desktop systems. +- Creating users in your systems through ${self.namespace}.users, +automatically maps home-manager configurations from the `homes` directory to their corresponding users. + +Nonetheless, one should still consider this implementation experimental, +once I start using this on my laptop, +I'll aim for production grade stability. ## 🚀 Deployment To deploy a system run the following command in your terminal of choice. ```sh -sudo nixos-rebuild switch --flake .#hostname +sudo nixos-rebuild switch --flake .#hostname --accept-flake-config ``` If you're interested in a quick way to experiment with this configuration, you may use the following command to build a VM. ```sh -sudo nixos-rebuild build-vm --flake .#hostname +sudo nixos-rebuild build-vm --flake .#hostname --accept-flake-config ``` ## 📝 Goals and improvements diff --git a/homes/x86_64-linux/cyn/default.nix b/homes/x86_64-linux/cyn/default.nix new file mode 100644 index 0000000..bdf7c40 --- /dev/null +++ b/homes/x86_64-linux/cyn/default.nix @@ -0,0 +1,6 @@ +{pkgs, ...}: { + home.packages = with pkgs; [ + cowsay + cmatrix + ]; +} diff --git a/homes/x86_64-linux/jo/default.nix b/homes/x86_64-linux/jo/default.nix index 21cf78b..bd62c1a 100644 --- a/homes/x86_64-linux/jo/default.nix +++ b/homes/x86_64-linux/jo/default.nix @@ -1,10 +1,7 @@ -{ - pkgs, - ... -}: { +{pkgs, ...}: { home.packages = with pkgs; [ - vscodium - cmatrix + zed-editor + firefox ]; home.stateVersion = "25.05"; diff --git a/lib/module/default.nix b/lib/module/default.nix index 3d52e9d..61c73ae 100644 --- a/lib/module/default.nix +++ b/lib/module/default.nix @@ -1,8 +1,13 @@ -{ lib, self, ... }: { +{ + lib, + self, + ... +}: { # Create a NixOS module option on a single line. mkOpt = type: default: description: lib.mkOption {inherit type default description;}; + # Create a simple bool options mkBool = default: description: lib.mkOption { inherit default description; @@ -10,20 +15,17 @@ }; # Create a module compliant with the NixOS module system. - mkModule = - { - name ? "puzzlevision", - class, - modules, - }: { - _class = class; - - # Template: "[path-to-flake]/flake.nix#[class-name]Modules.[module-name]" - # Example: "[path-to-flake]/flake.nix#nixosModules.system.audio" - _file = "${self.outPath}/flake.nix#${class}Modules.${name}"; - - imports = modules; - }; + mkModule = { + name ? "puzzlevision", + class, + modules, + }: { + _class = class; + # Template: "[path-to-flake]/flake.nix#[class-name]Modules.[module-name]" + # Example: "[path-to-flake]/flake.nix#nixosModules.system.audio" + _file = "${self.outPath}/flake.nix#${class}Modules.${name}"; + imports = modules; + }; # TODO: add mkIfElse function } diff --git a/modules/flake/default.nix b/modules/flake/default.nix index fb9d01d..33820cf 100644 --- a/modules/flake/default.nix +++ b/modules/flake/default.nix @@ -6,13 +6,7 @@ # Automagically imports libs from "/lib/lib-name" and exposes them to the `flake.lib` output. ./lib.nix - # Recursively imports overlays from "/overlays/overlay-name" and exposes them to the `flake.overlays` output. - #./overlays.nix - # Automagically imports systems from "/systems/arch-classname/system-name". ./systems.nix - - # Automagically imports homes from "/homes/user-name". - #./homes.nix ]; } diff --git a/modules/flake/modules.nix b/modules/flake/modules.nix index 9fa3d3e..1952945 100644 --- a/modules/flake/modules.nix +++ b/modules/flake/modules.nix @@ -1,10 +1,10 @@ -{ self, ... }: -{ +{self, ...}: { flake = { - #nixosModules.puzzlevision = self.lib.mkModule { - # class = "nixos"; - # modules = self.lib.dirToModuleList ../nixos; - #}; + # TODO: figure out why this isn't working correctly + nixosModules.puzzlevision = self.lib.mkModule { + class = "nixos"; + modules = self.lib.dirToModuleList ../nixos; + }; homeModules.puzzlevision = self.lib.mkModule { class = "home"; diff --git a/modules/flake/systems.nix b/modules/flake/systems.nix index b0198bb..ea6523e 100644 --- a/modules/flake/systems.nix +++ b/modules/flake/systems.nix @@ -1,10 +1,12 @@ { lib, - inputs, self, + inputs, ... }: { - imports = [ inputs.easy-hosts.flakeModule ]; + imports = [ + inputs.easy-hosts.flakeModule + ]; easyHosts = { autoConstruct = true; diff --git a/modules/home/default.nix b/modules/home/default.nix new file mode 100644 index 0000000..ea8f50d --- /dev/null +++ b/modules/home/default.nix @@ -0,0 +1,2 @@ +{...}: { +} diff --git a/modules/home/desktop/gnome/default.nix b/modules/home/desktop/gnome/default.nix deleted file mode 100644 index daa75f5..0000000 --- a/modules/home/desktop/gnome/default.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ - lib, - pkgs, - self, - config, - osConfig, - ... -}: let - inherit (lib) mkIf mkOption; - inherit (self) namespace; - - cfg = config.${namespace}.desktop.gnome; -in { - options.${namespace}.desktop.gnome = with lib.types; { - enabled-extensions = mkOption { - type = listOf package; - default = with pkgs.gnomeExtensions; [dash-to-dock user-themes blur-my-shell appindicator unite color-picker clipboard-history]; - example = [dash-to-dock blur-my-shell]; - description = "Specify gnome extensions to install."; - }; - }; - - config = mkIf osConfig.${namespace}.desktop.gnome.enable { - home.packages = cfg.enabled-extensions; - - dconf.settings = { - "org/gnome/shell" = { - enabled-extensions = lib.forEach cfg.enabled-extensions (x: x.extensionUuid); - disabled-extensions = []; # Make sure none of our extensions are disabled on system rebuild - }; - }; - }; -} diff --git a/modules/nixos/archetypes/workstation/default.nix b/modules/nixos/archetypes/workstation/default.nix new file mode 100644 index 0000000..32b3c1a --- /dev/null +++ b/modules/nixos/archetypes/workstation/default.nix @@ -0,0 +1,32 @@ +{ + lib, + self, + config, + ... +}: let + inherit (lib) mkEnableOption mkIf mkDefault; + inherit (self) namespace; + + cfg = config.${namespace}.archetypes.workstation; +in { + options.${namespace}.archetypes.workstation = { + enable = mkEnableOption "the workstation archetype."; + }; + + config = mkIf cfg.enable { + ${namespace} = { + # Basic system functionality + system.grub.enable = true; + system.networking.enable = true; + system.kernel.enable = true; + + # Services + services.docker.enable = true; + + # Desktop environment + desktop.gnome.enable = true; + }; + + time.timeZone = mkDefault "Europe/Berlin"; + }; +} diff --git a/modules/nixos/desktop/gnome/default.nix b/modules/nixos/desktop/gnome/default.nix index d2432b5..01e40ba 100644 --- a/modules/nixos/desktop/gnome/default.nix +++ b/modules/nixos/desktop/gnome/default.nix @@ -9,7 +9,9 @@ cfg = config.${namespace}.desktop.gnome; in { - options.${namespace}.desktop.gnome = {enable = mkEnableOption "Enable the gnome desktop environment ${namespace}";}; + options.${namespace}.desktop.gnome = { + enable = mkEnableOption "the gnome desktop environment"; + }; config = mkIf cfg.enable { services.xserver.enable = true; diff --git a/modules/nixos/services/docker/default.nix b/modules/nixos/services/docker/default.nix new file mode 100644 index 0000000..bb3f805 --- /dev/null +++ b/modules/nixos/services/docker/default.nix @@ -0,0 +1,20 @@ +{ + lib, + self, + config, + ... +}: let + inherit (lib) mkIf mkEnableOption; + inherit (self) namespace; + + cfg = config.${namespace}.services.docker; +in { + options.${namespace}.services.docker = { + enable = mkEnableOption "the docker service."; + }; + + config = mkIf cfg.enable { + # Enable docker + virtualisation.docker.enable = true; + }; +} diff --git a/modules/nixos/common/grub/default.nix b/modules/nixos/system/grub/default.nix similarity index 72% rename from modules/nixos/common/grub/default.nix rename to modules/nixos/system/grub/default.nix index 5ec7745..ef2ab0e 100644 --- a/modules/nixos/common/grub/default.nix +++ b/modules/nixos/system/grub/default.nix @@ -3,21 +3,22 @@ self, config, ... -}: -let +}: let inherit (lib) mkEnableOption mkIf; inherit (self) namespace; - cfg = config.${namespace}.common.grub; + cfg = config.${namespace}.system.grub; in { - options.${namespace}.common.grub = { enable = mkEnableOption "grub"; }; + options.${namespace}.system.grub = { + enable = mkEnableOption "the grub bootloader."; + }; config = mkIf cfg.enable { boot.loader.systemd-boot.enable = false; boot.loader.grub = { enable = true; - devices = [ "nodev" ]; + devices = ["nodev"]; efiInstallAsRemovable = true; efiSupport = true; diff --git a/modules/nixos/system/kernel/default.nix b/modules/nixos/system/kernel/default.nix new file mode 100644 index 0000000..521846d --- /dev/null +++ b/modules/nixos/system/kernel/default.nix @@ -0,0 +1,22 @@ +{ + lib, + pkgs, + self, + config, + ... +}: let + inherit (lib) mkEnableOption mkIf; + inherit (self) namespace; + inherit (self.lib) mkOpt; + + cfg = config.${namespace}.system.kernel; +in { + options.${namespace}.system.kernel = { + enable = mkEnableOption "Modify the standard kernel settings"; + version = mkOpt lib.types.str "linuxPackages_latest" "Set the kernel version to be used by your system"; + }; + + config = mkIf cfg.enable { + boot.kernelPackages = pkgs.${cfg.version}; + }; +} diff --git a/modules/nixos/system/networking/default.nix b/modules/nixos/system/networking/default.nix new file mode 100644 index 0000000..2130053 --- /dev/null +++ b/modules/nixos/system/networking/default.nix @@ -0,0 +1,19 @@ +{ + lib, + self, + config, + ... +}: let + inherit (lib) mkEnableOption mkIf; + inherit (self) namespace; + + cfg = config.${namespace}.system.networking; +in { + options.${namespace}.system.networking = { + enable = mkEnableOption "networking."; + }; + + config = mkIf cfg.enable { + networking.networkmanager.enable = true; + }; +} diff --git a/modules/nixos/users/default.nix b/modules/nixos/users/default.nix index ef2d6dc..4d91d25 100644 --- a/modules/nixos/users/default.nix +++ b/modules/nixos/users/default.nix @@ -1,81 +1,78 @@ { lib, - config, self, pkgs, + config, ... }: let - inherit (lib) mkEnableOption mkIf mkOption types; + inherit (lib) types mkEnableOption mkOption mkIf; inherit (self) namespace; - inherit (self.lib) mkOpt dirToModuleList; - - cfg = config.${namespace}.users; + inherit (self.lib) dirToModuleList; # The identifier of the current system type, e.g. "x86_64-linux" or "aarch64-darwin" system = pkgs.system; + cfg = config.${namespace}.users; - # Type for a user configuration - userType = types.submodule { + userSubmodule = types.submodule { options = { - enable = mkEnableOption "this user"; - initialPassword = mkOpt (types.nullOr types.str) null "Initial password for the user"; - password = mkOpt (types.nullOr types.str) null "Plaintext password for the user"; - hashedPassword = mkOpt (types.nullOr types.str) null "Hashed password for the user"; - isNormalUser = mkOpt types.bool true "Whether this user is a normal user"; - extraGroups = mkOpt (types.listOf types.str) [] "Extra groups for the user"; + enable = mkEnableOption "this user."; + isNormalUser = self.lib.mkBool true "Whether this user is considered a normal user."; + isSystemUser = self.lib.mkBool false "Whether this user is considered a system user."; + initialPassword = self.lib.mkOpt (types.nullOr types.str) null "Plaintext insecure initial user password, only recommended for testing."; + password = self.lib.mkOpt (types.nullOr types.str) null "Plaintext insecure user password, only recommended for testing."; + extraGroups = self.lib.mkOpt (types.listOf types.str) [] "List of additional groups this user belongs to."; }; }; - # Function to get home configuration path for a username getHomeConfigPath = username: "${self.outPath}/homes/${system}/${username}"; + homeConfigExists = username: let + path = getHomeConfigPath username; + in + builtins.pathExists "${path}/default.nix"; - # Function to check if a home configuration exists for a username - homeConfigExists = username: - let path = getHomeConfigPath username; - in builtins.pathExists "${path}/default.nix"; - - # Import all home-manager modules homeModules = dirToModuleList "${self.outPath}/modules/home"; in { options.${namespace}.users = mkOption { - type = types.attrsOf userType; + type = types.attrsOf userSubmodule; default = {}; - description = "User configurations with auto-imported home-manager setup"; + description = "List of users to create. Also handles home configurations, placed in self.outPath/homes/[x86_64-linux, aarch64-linux, etc...], through home-manager."; }; config = { - # Ensure users are fully managed by NixOS - users.mutableUsers = false; + # TODO: fix this + #nix.settings.trusted-users = ["root" (lib.forEach cfg (username: toString username))]; - # Create the actual system users + # Manage users declaratively and map userConfig to users.users by name; + users.mutableUsers = false; users.users = lib.mapAttrs (username: userConfig: mkIf userConfig.enable { name = username; - inherit (userConfig) extraGroups initialPassword hashedPassword isNormalUser password; - } - ) cfg; + inherit (userConfig) isNormalUser isSystemUser initialPassword password extraGroups; + }) + cfg; - # Configure home-manager with auto-imported user configuration home-manager = { useGlobalPkgs = true; useUserPackages = true; extraSpecialArgs = { - inherit self; + inherit self system; namespace = self.namespace; }; - users = lib.mapAttrs (username: userConfig: - mkIf (userConfig.enable && homeConfigExists username) ( - { ... }: { - imports = [ - (getHomeConfigPath username) # Import the user's specific home configuration - ]; #++ homeModules; # Include all generalized home modules + users = + lib.mapAttrs ( + username: userConfig: + mkIf (userConfig.enable && homeConfigExists username) ( + {osConfig, ...}: { + # Import user home configuration and general home modules + imports = [(getHomeConfigPath username)] ++ homeModules; - home.stateVersion = lib.mkDefault config.system.stateVersion; - } + home.stateVersion = lib.mkDefault osConfig.system.stateVersion; + } + ) ) - ) cfg; + cfg; }; }; } diff --git a/modules/nixos/utils/vm/default.nix b/modules/nixos/utils/vm/default.nix deleted file mode 100644 index 5a72bbb..0000000 --- a/modules/nixos/utils/vm/default.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ - lib, - config, - self, - ... -}: let - inherit (lib) mkIf; - inherit (self) namespace; - - cfg = config.${namespace}.utils.vm; -in { - options.${namespace}.utils.vm = { - enable = self.lib.mkBool true "Whether to enable custom vm presets"; - preset = self.lib.mkOpt lib.types.str "performance" "Specify the prefered vm settings preset: performance, balance or powersave"; - }; - - config = mkIf cfg.enable { - virtualisation.vmVariant = { - virtualisation = { - cores = 6; - memorySize = 4096; - graphics = true; - }; - }; - }; -} diff --git a/systems/x86_64-nixos/puzzlevision/default.nix b/systems/x86_64-nixos/puzzlevision/default.nix index af76b22..dcde7a3 100644 --- a/systems/x86_64-nixos/puzzlevision/default.nix +++ b/systems/x86_64-nixos/puzzlevision/default.nix @@ -1,30 +1,43 @@ -{ - pkgs, - ... -}: { +{pkgs, ...}: { imports = [ ./hardware.nix ]; puzzlevision = { - # TODO: improve home-manager configuration loading as development continues and make sure everything works correctly. - users = { - jo = { - enable = true; - initialPassword = "balls"; - extraGroups = [ "wheel" ]; - }; + users.cyn = { + enable = true; + password = "cynical"; # For testing only, replace with sops secret before production use + extraGroups = ["wheel"]; }; - desktop.gnome.enable = true; - utils.vm.enable = true; - common.grub.enable = true; + users.jo = { + enable = true; + password = "jo"; # For testing only, replace with sops secret before production use + extraGroups = ["wheel"]; + }; + + archetypes.workstation.enable = true; }; - environment.systemPackages = with pkgs; [ - ghostty - firefox + # Configure 8GB SWAP partition + swapDevices = [ + { + device = "/swapfile"; + size = 8 * 1024; + } ]; + boot = { + # Configure additional kernel modules. + extraModulePackages = [ + pkgs.linuxPackages_latest.rtl8821ce # Use custom network-card driver. + ]; + + blacklistedKernelModules = [ + "rtw88_8821ce" # Block the default network-card driver. + ]; + }; + + networking.hostName = "puzzlevision"; system.stateVersion = "25.05"; }