mirror of
				https://github.com/Jokiller230/puzzlevision.git
				synced 2025-10-31 05:40:05 +00:00 
			
		
		
		
	Compare commits
	
		
			3 commits
		
	
	
		
			cd32ad1c61
			...
			8a69e60c6f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8a69e60c6f | |||
| 09c06d34e5 | |||
| 54edba0070 | 
					 18 changed files with 219 additions and 161 deletions
				
			
		
							
								
								
									
										18
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										18
									
								
								README.md
									
										
									
									
									
								
							|  | @ -6,22 +6,30 @@ | |||
| <br> | ||||
| 
 | ||||
| ## 🚧 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 | ||||
|  |  | |||
							
								
								
									
										6
									
								
								homes/x86_64-linux/cyn/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								homes/x86_64-linux/cyn/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| {pkgs, ...}: { | ||||
|   home.packages = with pkgs; [ | ||||
|     cowsay | ||||
|     cmatrix | ||||
|   ]; | ||||
| } | ||||
|  | @ -1,10 +1,7 @@ | |||
| { | ||||
|   pkgs, | ||||
|   ... | ||||
| }: { | ||||
| {pkgs, ...}: { | ||||
|   home.packages = with pkgs; [ | ||||
|     vscodium | ||||
|     cmatrix | ||||
|     zed-editor | ||||
|     firefox | ||||
|   ]; | ||||
| 
 | ||||
|   home.stateVersion = "25.05"; | ||||
|  |  | |||
|  | @ -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 | ||||
| } | ||||
|  |  | |||
|  | @ -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 | ||||
|   ]; | ||||
| } | ||||
|  |  | |||
|  | @ -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"; | ||||
|  |  | |||
|  | @ -1,10 +1,12 @@ | |||
| { | ||||
|   lib, | ||||
|   inputs, | ||||
|   self, | ||||
|   inputs, | ||||
|   ... | ||||
| }: { | ||||
|   imports = [ inputs.easy-hosts.flakeModule ]; | ||||
|   imports = [ | ||||
|     inputs.easy-hosts.flakeModule | ||||
|   ]; | ||||
| 
 | ||||
|   easyHosts = { | ||||
|     autoConstruct = true; | ||||
|  |  | |||
							
								
								
									
										2
									
								
								modules/home/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								modules/home/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | |||
| {...}: { | ||||
| } | ||||
|  | @ -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 | ||||
|       }; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
							
								
								
									
										32
									
								
								modules/nixos/archetypes/workstation/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								modules/nixos/archetypes/workstation/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -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"; | ||||
|   }; | ||||
| } | ||||
|  | @ -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; | ||||
|  |  | |||
							
								
								
									
										20
									
								
								modules/nixos/services/docker/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								modules/nixos/services/docker/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
|   }; | ||||
| } | ||||
|  | @ -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; | ||||
| 
 | ||||
							
								
								
									
										22
									
								
								modules/nixos/system/kernel/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								modules/nixos/system/kernel/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -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}; | ||||
|   }; | ||||
| } | ||||
							
								
								
									
										19
									
								
								modules/nixos/system/networking/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								modules/nixos/system/networking/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
|   }; | ||||
| } | ||||
|  | @ -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; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
|  |  | |||
|  | @ -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; | ||||
|       }; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
|  | @ -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"; | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue