From 01d1a36650eeccbd42bdc7417e21d4f6a93a5bae Mon Sep 17 00:00:00 2001 From: UGA Innovation Factory Date: Wed, 10 Dec 2025 14:52:34 +0000 Subject: [PATCH] feat: Export formatter and lxc configuration from flake --- flake.lock | 57 +++++++++++- flake.nix | 40 ++++++--- hosts/boot.nix | 14 ++- hosts/default.nix | 134 ++++++++++++++++++---------- hosts/types/nix-desktop.nix | 60 ++++++++----- hosts/types/nix-laptop.nix | 63 ++++++++----- hosts/types/nix-lxc.nix | 40 +++++++++ hosts/types/nix-surface.nix | 88 +++++++++++-------- hosts/user-config.nix | 171 ++++++++++++++++++++++++------------ inventory.nix | 22 ++++- sw/default.nix | 89 ++++++++++++------- sw/desktop/default.nix | 26 +++++- sw/desktop/programs.nix | 11 ++- sw/desktop/services.nix | 7 +- sw/ghostty.nix | 9 +- sw/kiosk/default.nix | 35 +++++++- sw/kiosk/gsettings.nix | 88 ++++++++++--------- sw/kiosk/programs.nix | 11 ++- sw/kiosk/services.nix | 36 ++++---- sw/nvim.nix | 13 +-- sw/python.nix | 10 ++- sw/theme.nix | 10 ++- users.nix | 16 +++- 23 files changed, 742 insertions(+), 308 deletions(-) create mode 100644 hosts/types/nix-lxc.nix diff --git a/flake.lock b/flake.lock index d100725..9bdfa28 100644 --- a/flake.lock +++ b/flake.lock @@ -95,6 +95,24 @@ "type": "github" } }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1681202837, + "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "cfacdce06f30d2b68473a46042957675eebb3401", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "git-hooks": { "inputs": { "flake-compat": [ @@ -393,7 +411,8 @@ "lazyvim-nixvim": "lazyvim-nixvim", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs_2", - "nixpkgs-old-kernel": "nixpkgs-old-kernel" + "nixpkgs-old-kernel": "nixpkgs-old-kernel", + "vscode-server": "vscode-server" } }, "systems": { @@ -411,6 +430,21 @@ "type": "github" } }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "treefmt-nix": { "inputs": { "nixpkgs": [ @@ -432,6 +466,27 @@ "repo": "treefmt-nix", "type": "github" } + }, + "vscode-server": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1753541826, + "narHash": "sha256-foGgZu8+bCNIGeuDqQ84jNbmKZpd+JvnrL2WlyU4tuU=", + "owner": "nix-community", + "repo": "nixos-vscode-server", + "rev": "6d5f074e4811d143d44169ba4af09b20ddb6937d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixos-vscode-server", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 8244ab8..40e4e0d 100644 --- a/flake.nix +++ b/flake.nix @@ -9,33 +9,51 @@ inputs = { # Core NixOS package repository (Release 25.11) nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; - + # Older kernel packages for Surface compatibility if needed nixpkgs-old-kernel.url = "github:NixOS/nixpkgs/nixos-25.05"; - + # Home Manager for user environment management home-manager = { url = "github:nix-community/home-manager/release-25.11"; inputs.nixpkgs.follows = "nixpkgs"; }; - + # Disko for declarative disk partitioning disko = { url = "github:nix-community/disko"; inputs.nixpkgs.follows = "nixpkgs"; }; - + # Hardware quirks and configurations nixos-hardware.url = "github:NixOS/nixos-hardware/master"; - + # Neovim configuration lazyvim-nixvim.url = "github:azuwis/lazyvim-nixvim"; - }; - outputs = inputs@{ self, nixpkgs, nixpkgs-old-kernel, home-manager, disko, lazyvim-nixvim, nixos-hardware,... }: { - # Formatter for 'nix fmt' - formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixfmt-rfc-style; - # Generate NixOS configurations from hosts/default.nix - nixosConfigurations = import ./hosts { inherit inputs; }; + # VS Code server for remote development + vscode-server = { + url = "github:nix-community/nixos-vscode-server"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; + outputs = + inputs@{ + self, + nixpkgs, + nixpkgs-old-kernel, + home-manager, + disko, + lazyvim-nixvim, + nixos-hardware, + vscode-server, + ... + }: + { + # Formatter for 'nix fmt' + formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixfmt-rfc-style; + + # Generate NixOS configurations from hosts/default.nix + nixosConfigurations = import ./hosts { inherit inputs; }; + }; } diff --git a/hosts/boot.nix b/hosts/boot.nix index 0a1483d..77cb2cd 100644 --- a/hosts/boot.nix +++ b/hosts/boot.nix @@ -47,7 +47,10 @@ format = "vfat"; mountpoint = "/boot"; mountOptions = [ "umask=0077" ]; - extraArgs = [ "-n" "BOOT" ]; + extraArgs = [ + "-n" + "BOOT" + ]; }; }; @@ -56,7 +59,9 @@ name = "swap"; label = "swap"; size = config.host.filesystem.swapSize; - content = { type = "swap"; }; + content = { + type = "swap"; + }; }; # Root Partition (takes remaining space) @@ -68,7 +73,10 @@ type = "filesystem"; format = "ext4"; mountpoint = "/"; - extraArgs = [ "-L" "ROOT" ]; + extraArgs = [ + "-L" + "ROOT" + ]; }; }; }; diff --git a/hosts/default.nix b/hosts/default.nix index c264086..3ecf97e 100644 --- a/hosts/default.nix +++ b/hosts/default.nix @@ -1,4 +1,8 @@ -{ inputs, hosts ? import ../inventory.nix, ... }: +{ + inputs, + hosts ? import ../inventory.nix, + ... +}: # ============================================================================ # Host Generator @@ -10,10 +14,10 @@ # 3. External flake integration for system overrides. let - nixpkgs = inputs.nixpkgs; - lib = nixpkgs.lib; + nixpkgs = inputs.nixpkgs; + lib = nixpkgs.lib; home-manager = inputs.home-manager; - disko = inputs.disko; + disko = inputs.disko; # Modules shared by all hosts commonModules = [ @@ -25,35 +29,44 @@ let disko.nixosModules.disko { system.stateVersion = "25.11"; - nix.settings.experimental-features = [ "nix-command" "flakes" ]; - + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + # Automatic Garbage Collection nix.gc = { automatic = true; dates = "weekly"; options = "--delete-older-than 30d"; }; - + # Optimize storage nix.optimise.automatic = true; } ]; # Helper to create a single NixOS system configuration - mkHost = { hostName, system ? "x86_64-linux", extraModules ? [ ] }: + mkHost = + { + hostName, + system ? "x86_64-linux", + extraModules ? [ ], + }: let # Load users.nix to find external user flakes # We use legacyPackages to evaluate the simple data structure of users.nix pkgs = nixpkgs.legacyPackages.${system}; usersData = import ../users.nix { inherit pkgs; }; - accounts = usersData.modules.users.accounts or {}; - + accounts = usersData.modules.users.accounts or { }; + # Extract flakeUrls and convert to modules - userFlakeModules = lib.mapAttrsToList (name: user: + userFlakeModules = lib.mapAttrsToList ( + name: user: if (user ? flakeUrl && user.flakeUrl != "") then (builtins.getFlake user.flakeUrl).nixosModules.default else - {} + { } ) accounts; in lib.nixosSystem { @@ -71,56 +84,85 @@ let }; # Function to generate a set of hosts based on inventory count and overrides - mkHostGroup = { prefix, count, system ? "x86_64-linux", extraModules ? [], deviceOverrides ? {} }: - lib.listToAttrs (map (i: { - name = "${prefix}${toString i}"; - value = + mkHostGroup = + { + prefix, + count, + system ? "x86_64-linux", + extraModules ? [ ], + deviceOverrides ? { }, + }: + lib.listToAttrs ( + lib.concatMap ( + i: let - devConf = deviceOverrides.${toString i} or {}; + defaultName = "${prefix}${toString i}"; + devConf = deviceOverrides.${toString i} or { }; hasOverride = builtins.hasAttr (toString i) deviceOverrides; - + hostName = + if hasOverride && (builtins.hasAttr "hostname" devConf) then devConf.hostname else defaultName; + # Extract flakeUrl if it exists - externalFlake = if hasOverride && (builtins.hasAttr "flakeUrl" devConf) - then builtins.getFlake devConf.flakeUrl - else null; - + externalFlake = + if hasOverride && (builtins.hasAttr "flakeUrl" devConf) then + builtins.getFlake devConf.flakeUrl + else + null; + # Module from external flake - externalModule = if externalFlake != null - then externalFlake.nixosModules.default - else {}; + externalModule = if externalFlake != null then externalFlake.nixosModules.default else { }; # Config override module (filesystem, users) - overrideModule = { ... }: + overrideModule = + { ... }: let # Remove special keys that are not filesystem options - fsConf = builtins.removeAttrs devConf [ "extraUsers" "flakeUrl" ]; - in lib.mkIf hasOverride { + fsConf = builtins.removeAttrs devConf [ + "extraUsers" + "flakeUrl" + "hostname" + ]; + in + lib.mkIf hasOverride { host.filesystem = fsConf; - modules.users.enabledUsers = devConf.extraUsers or []; + modules.users.enabledUsers = devConf.extraUsers or [ ]; }; + + config = mkHost { + hostName = hostName; + inherit system; + extraModules = + extraModules ++ [ overrideModule ] ++ (lib.optional (externalFlake != null) externalModule); + }; + + aliasNames = lib.optional (hostName != defaultName) hostName; + names = lib.unique ([ defaultName ] ++ aliasNames); in - mkHost { - hostName = "${prefix}${toString i}"; - inherit system; - extraModules = extraModules ++ [ overrideModule ] ++ (lib.optional (externalFlake != null) externalModule); - }; - }) (lib.range 1 count)); + lib.map (name: { + inherit name; + value = config; + }) names + ) (lib.range 1 count) + ); # Generate host groups based on the input hosts configuration - hostGroups = lib.mapAttrsToList (type: config: + hostGroups = lib.mapAttrsToList ( + type: config: let typeFile = ./types + "/${type}.nix"; - modules = if builtins.pathExists typeFile - then import typeFile { inherit inputs; } - else throw "Host type '${type}' not found in hosts/types/"; + modules = + if builtins.pathExists typeFile then + import typeFile { inherit inputs; } + else + throw "Host type '${type}' not found in hosts/types/"; in - mkHostGroup { - prefix = type; - inherit (config) count; - extraModules = modules; - deviceOverrides = config.devices or {}; - } + mkHostGroup { + prefix = type; + inherit (config) count; + extraModules = modules; + deviceOverrides = config.devices or { }; + } ) hosts; in - lib.foldl' lib.recursiveUpdate {} hostGroups +lib.foldl' lib.recursiveUpdate { } hostGroups diff --git a/hosts/types/nix-desktop.nix b/hosts/types/nix-desktop.nix index 9720162..36c9c16 100644 --- a/hosts/types/nix-desktop.nix +++ b/hosts/types/nix-desktop.nix @@ -1,24 +1,42 @@ -{ inputs, ... }: [ - ({ config, lib, modulesPath, ... }: { - imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; +{ inputs, ... }: +[ + ( + { + config, + lib, + modulesPath, + ... + }: + { + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; - boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" "sdhci_pci" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" ]; - boot.extraModulePackages = [ ]; - boot.kernelParams = [ - "quiet" - "splash" - "boot.shell_on_fail" - "udev.log_priority=3" - "rd.systemd.show_status=auto" - ]; + boot.initrd.availableKernelModules = [ + "xhci_pci" + "nvme" + "usb_storage" + "sd_mod" + "sdhci_pci" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + boot.kernelParams = [ + "quiet" + "splash" + "boot.shell_on_fail" + "udev.log_priority=3" + "rd.systemd.show_status=auto" + ]; - host.filesystem.swapSize = lib.mkDefault "16G"; - host.filesystem.device = lib.mkDefault "/dev/nvme0n1"; - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; - }) - { modules.sw.enable = true; modules.sw.type = "desktop"; } + host.filesystem.swapSize = lib.mkDefault "16G"; + host.filesystem.device = lib.mkDefault "/dev/nvme0n1"; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + } + ) + { + modules.sw.enable = true; + modules.sw.type = "desktop"; + } ] diff --git a/hosts/types/nix-laptop.nix b/hosts/types/nix-laptop.nix index a1f361d..84f697d 100644 --- a/hosts/types/nix-laptop.nix +++ b/hosts/types/nix-laptop.nix @@ -1,12 +1,27 @@ -{ inputs, ... }: [ - ({ config, lib, modulesPath, ... }: { - imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; +{ inputs, ... }: +[ + ( + { + config, + lib, + modulesPath, + ... + }: + { + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; - boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" "sdhci_pci" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" ]; - boot.extraModulePackages = [ ]; - boot.kernelParams = [ + boot.initrd.availableKernelModules = [ + "xhci_pci" + "thunderbolt" + "nvme" + "usb_storage" + "sd_mod" + "sdhci_pci" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + boot.kernelParams = [ "quiet" "splash" "boot.shell_on_fail" @@ -17,21 +32,25 @@ "i915.enable_fbc=0" ]; - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; - host.filesystem.device = lib.mkDefault "/dev/nvme0n1"; - host.filesystem.swapSize = lib.mkDefault "34G"; + host.filesystem.device = lib.mkDefault "/dev/nvme0n1"; + host.filesystem.swapSize = lib.mkDefault "34G"; - # Suspend / logind behavior - services.upower.enable = true; - services.logind.settings = { - Login = { - HandleLidSwitch = "suspend"; - HandleLidSwitchExternalPower = "suspend"; - HandleLidSwitchDocked = "ignore"; + # Suspend / logind behavior + services.upower.enable = true; + services.logind.settings = { + Login = { + HandleLidSwitch = "suspend"; + HandleLidSwitchExternalPower = "suspend"; + HandleLidSwitchDocked = "ignore"; + }; }; - }; - }) - { modules.sw.enable = true; modules.sw.type = "desktop"; } + } + ) + { + modules.sw.enable = true; + modules.sw.type = "desktop"; + } ] diff --git a/hosts/types/nix-lxc.nix b/hosts/types/nix-lxc.nix new file mode 100644 index 0000000..462d181 --- /dev/null +++ b/hosts/types/nix-lxc.nix @@ -0,0 +1,40 @@ +{ inputs, ... }: +[ + inputs.vscode-server.nixosModules.default + ( + { + config, + lib, + modulesPath, + ... + }: + { + nix.settings.trusted-users = [ + "root" + "engr-ugaif" + ]; + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + imports = [ + "${modulesPath}/virtualisation/proxmox-lxc.nix" + ]; + boot.isContainer = true; + boot.loader.systemd-boot.enable = lib.mkForce false; + disko.enableConfig = lib.mkForce false; + console.enable = true; + systemd.services."getty@".unitConfig.ConditionPathExists = [ + "" + "/dev/%I" + ]; + systemd.suppressedSystemUnits = [ + "dev-mqueue.mount" + "sys-kernel-debug.mount" + "sys-fs-fuse-connections.mount" + ]; + services.vscode-server.enable = true; + system.stateVersion = "25.11"; + } + ) +] diff --git a/hosts/types/nix-surface.nix b/hosts/types/nix-surface.nix index 89d84af..375371a 100644 --- a/hosts/types/nix-surface.nix +++ b/hosts/types/nix-surface.nix @@ -1,40 +1,58 @@ -{ inputs, ... }: [ - ({ config, lib, pkgs, modulesPath, ... }: - let - refSystem = inputs.nixpkgs-old-kernel.lib.nixosSystem { - system = pkgs.stdenv.hostPlatform.system; - modules = [ inputs.nixos-hardware.nixosModules.microsoft-surface-go ]; - }; - refKernelPackages = refSystem.config.boot.kernelPackages; - in - { - imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; +{ inputs, ... }: +[ + ( + { + config, + lib, + pkgs, + modulesPath, + ... + }: + let + refSystem = inputs.nixpkgs-old-kernel.lib.nixosSystem { + system = pkgs.stdenv.hostPlatform.system; + modules = [ inputs.nixos-hardware.nixosModules.microsoft-surface-go ]; + }; + refKernelPackages = refSystem.config.boot.kernelPackages; + in + { + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; - boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" "sdhci_pci" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" ]; - boot.extraModulePackages = [ ]; - boot.kernelParams = [ - "quiet" - "splash" - "boot.shell_on_fail" - "udev.log_priority=3" - "rd.systemd.show_status=auto" - "intel_ipu3_imgu" - "intel_ipu3_isys" - "fbcon=map:1" - "i915.enable_psr=0" # Panel Self Refresh breaks resume on Surface - "i915.enable_dc=0" - ]; + boot.initrd.availableKernelModules = [ + "xhci_pci" + "nvme" + "usb_storage" + "sd_mod" + "sdhci_pci" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + boot.kernelParams = [ + "quiet" + "splash" + "boot.shell_on_fail" + "udev.log_priority=3" + "rd.systemd.show_status=auto" + "intel_ipu3_imgu" + "intel_ipu3_isys" + "fbcon=map:1" + "i915.enable_psr=0" # Panel Self Refresh breaks resume on Surface + "i915.enable_dc=0" + ]; - boot.kernelPackages = lib.mkForce refKernelPackages; + boot.kernelPackages = lib.mkForce refKernelPackages; - host.filesystem.swapSize = lib.mkDefault "8G"; - host.filesystem.device = lib.mkDefault "/dev/mmcblk0"; - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; - }) + host.filesystem.swapSize = lib.mkDefault "8G"; + host.filesystem.device = lib.mkDefault "/dev/mmcblk0"; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + } + ) inputs.nixos-hardware.nixosModules.microsoft-surface-go - { modules.sw.enable = true; modules.sw.type = "kiosk"; } + { + modules.sw.enable = true; + modules.sw.type = "kiosk"; + } ] diff --git a/hosts/user-config.nix b/hosts/user-config.nix index b95f7c4..4eafdf5 100644 --- a/hosts/user-config.nix +++ b/hosts/user-config.nix @@ -1,4 +1,9 @@ -{ pkgs, config, lib, ... }: +{ + pkgs, + config, + lib, + ... +}: # ============================================================================ # User Configuration Module @@ -11,19 +16,63 @@ let # Submodule defining the structure of a user account userSubmodule = lib.types.submodule { options = { - isNormalUser = lib.mkOption { type = lib.types.bool; default = true; }; - description = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; }; - extraGroups = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; }; - hashedPassword = lib.mkOption { type = lib.types.str; default = "!"; }; - extraPackages = lib.mkOption { type = lib.types.listOf lib.types.package; default = []; }; - excludePackages = lib.mkOption { type = lib.types.listOf lib.types.package; default = []; }; - homePackages = lib.mkOption { type = lib.types.listOf lib.types.package; default = []; }; - extraImports = lib.mkOption { type = lib.types.listOf lib.types.path; default = []; }; - flakeUrl = lib.mkOption { type = lib.types.str; default = ""; description = "URL of a flake to import Home Manager configuration from (e.g. github:user/dotfiles)."; }; - opensshKeys = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; description = "List of SSH public keys for the user."; }; - shell = lib.mkOption { type = lib.types.nullOr lib.types.package; default = null; description = "The shell for this user."; }; - useZshTheme = lib.mkOption { type = lib.types.bool; default = true; description = "Whether to apply the system Zsh theme."; }; - useNvimPlugins = lib.mkOption { type = lib.types.bool; default = true; description = "Whether to apply the system Neovim configuration."; }; + isNormalUser = lib.mkOption { + type = lib.types.bool; + default = true; + }; + description = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + }; + extraGroups = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + }; + hashedPassword = lib.mkOption { + type = lib.types.str; + default = "!"; + }; + extraPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = [ ]; + }; + excludePackages = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = [ ]; + }; + homePackages = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = [ ]; + }; + extraImports = lib.mkOption { + type = lib.types.listOf lib.types.path; + default = [ ]; + }; + flakeUrl = lib.mkOption { + type = lib.types.str; + default = ""; + description = "URL of a flake to import Home Manager configuration from (e.g. github:user/dotfiles)."; + }; + opensshKeys = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "List of SSH public keys for the user."; + }; + shell = lib.mkOption { + type = lib.types.nullOr lib.types.package; + default = null; + description = "The shell for this user."; + }; + useZshTheme = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to apply the system Zsh theme."; + }; + useNvimPlugins = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to apply the system Neovim configuration."; + }; }; }; in @@ -36,71 +85,85 @@ in }; accounts = lib.mkOption { type = lib.types.attrsOf userSubmodule; - default = {}; + default = { }; description = "User accounts configuration."; }; enabledUsers = lib.mkOption { type = lib.types.listOf lib.types.str; - default = []; + default = [ ]; description = "List of users to enable on this system."; }; }; config = { # Default enabled users (always present) - modules.users.enabledUsers = [ "root" "engr-ugaif" ]; + modules.users.enabledUsers = [ + "root" + "engr-ugaif" + ]; # Generate NixOS users - users.users = + users.users = let - enabledAccounts = lib.filterAttrs (name: _: lib.elem name config.modules.users.enabledUsers) config.modules.users.accounts; + enabledAccounts = lib.filterAttrs ( + name: _: lib.elem name config.modules.users.enabledUsers + ) config.modules.users.accounts; in - lib.mapAttrs (name: user: - let - isPlasma6 = config.services.desktopManager.plasma6.enable; - defaultPackages = lib.optionals (isPlasma6 && name != "root") [ pkgs.kdePackages.kate ]; - finalPackages = lib.subtractLists user.excludePackages (defaultPackages ++ user.extraPackages); - in - { - inherit (user) isNormalUser extraGroups hashedPassword; - description = if user.description != null then user.description else lib.mkDefault ""; - openssh.authorizedKeys.keys = user.opensshKeys; - packages = finalPackages; - shell = if user.shell != null then user.shell else config.modules.users.shell; - } - ) enabledAccounts; - + lib.mapAttrs ( + name: user: + let + isPlasma6 = config.services.desktopManager.plasma6.enable; + defaultPackages = lib.optionals (isPlasma6 && name != "root") [ pkgs.kdePackages.kate ]; + finalPackages = lib.subtractLists user.excludePackages (defaultPackages ++ user.extraPackages); + in + { + inherit (user) isNormalUser extraGroups hashedPassword; + description = if user.description != null then user.description else lib.mkDefault ""; + openssh.authorizedKeys.keys = user.opensshKeys; + packages = finalPackages; + shell = if user.shell != null then user.shell else config.modules.users.shell; + } + ) enabledAccounts; + # Home Manager configs per user home-manager = { useGlobalPkgs = true; useUserPackages = true; - extraSpecialArgs = { osConfig = config; }; + extraSpecialArgs = { + osConfig = config; + }; - users = + users = let - enabledAccounts = lib.filterAttrs (name: _: lib.elem name config.modules.users.enabledUsers) config.modules.users.accounts; + enabledAccounts = lib.filterAttrs ( + name: _: lib.elem name config.modules.users.enabledUsers + ) config.modules.users.accounts; in - lib.mapAttrs (name: user: { ... }: + lib.mapAttrs ( + name: user: + { ... }: let isExternal = user.flakeUrl != ""; - + # Common imports based on flags - commonImports = - lib.optional user.useZshTheme ../sw/theme.nix - ++ lib.optional user.useNvimPlugins ../sw/nvim.nix; + commonImports = + lib.optional user.useZshTheme ../sw/theme.nix ++ lib.optional user.useNvimPlugins ../sw/nvim.nix; in - if isExternal then { - # External users: Only apply requested system modules. - # The external flake is responsible for home.username, home.packages, etc. - imports = commonImports; - } else { - # Local users: Apply full configuration. - imports = user.extraImports ++ commonImports; - home.username = name; - home.homeDirectory = if name == "root" then "/root" else "/home/${name}"; - home.stateVersion = "25.11"; - home.packages = user.homePackages; - } + if isExternal then + { + # External users: Only apply requested system modules. + # The external flake is responsible for home.username, home.packages, etc. + imports = commonImports; + } + else + { + # Local users: Apply full configuration. + imports = user.extraImports ++ commonImports; + home.username = name; + home.homeDirectory = if name == "root" then "/root" else "/home/${name}"; + home.stateVersion = "25.11"; + home.packages = user.homePackages; + } ) enabledAccounts; }; }; diff --git a/inventory.nix b/inventory.nix index 122a4fb..0ff5108 100644 --- a/inventory.nix +++ b/inventory.nix @@ -24,11 +24,15 @@ devices = { # Override example: # "2" = { swapSize = "64G"; }; - + # Enable specific users for this device index - "1" = { extraUsers = [ "hdh20267" ]; }; - "2" = { extraUsers = [ "hdh20267" ]; }; - + "1" = { + extraUsers = [ "hdh20267" ]; + }; + "2" = { + extraUsers = [ "hdh20267" ]; + }; + # Example of using an external flake for system configuration: # "2" = { flakeUrl = "github:user/system-flake"; }; }; @@ -41,4 +45,14 @@ # Surface Tablet Configuration (Kiosk Mode) # Base specs: eMMC drive, 8G Swap nix-surface.count = 3; + + # LXC Container Configuration + nix-lxc = { + count = 1; + devices = { + "1" = { + hostname = "nix-builder"; + }; + }; + }; } diff --git a/sw/default.nix b/sw/default.nix index 999f51b..1558f49 100644 --- a/sw/default.nix +++ b/sw/default.nix @@ -1,4 +1,10 @@ -{ config, lib, pkgs, inputs, ... }: +{ + config, + lib, + pkgs, + inputs, + ... +}: # ============================================================================ # Software Module Entry Point @@ -22,20 +28,23 @@ in enable = mkEnableOption "Standard Workstation Configuration"; type = mkOption { - type = types.enum [ "desktop" "kiosk" ]; + type = types.enum [ + "desktop" + "kiosk" + ]; default = "desktop"; description = "Type of system configuration: 'desktop' for normal OS, 'kiosk' for tablet/kiosk mode."; }; extraPackages = mkOption { type = types.listOf types.package; - default = []; + default = [ ]; description = "Extra packages to install."; }; excludePackages = mkOption { type = types.listOf types.package; - default = []; + default = [ ]; description = "Packages to exclude from the default list."; }; @@ -49,37 +58,57 @@ in config = mkIf cfg.enable (mkMerge [ { nixpkgs.config.allowUnfree = true; - + programs.zsh.enable = true; programs.nix-ld.enable = true; - environment.systemPackages = with pkgs; subtractLists cfg.excludePackages [ - htop - binutils - zsh - git - oh-my-posh - inputs.lazyvim-nixvim.packages.${stdenv.hostPlatform.system}.nvim - # Custom update script - (writeShellScriptBin "update-system" '' - HOSTNAME=$(hostname) - FLAKE_URI="github:UGA-Innovation-Factory/nixos-systems" - - # Pass arguments like --impure to nixos-rebuild - EXTRA_ARGS="$@" + environment.systemPackages = + with pkgs; + subtractLists cfg.excludePackages [ + htop + binutils + zsh + git + oh-my-posh + inputs.lazyvim-nixvim.packages.${stdenv.hostPlatform.system}.nvim + # Custom update script + (writeShellScriptBin "update-system" '' + HOSTNAME=$(hostname) + FLAKE_URI="github:UGA-Innovation-Factory/nixos-systems" - if [[ "$HOSTNAME" == nix-surface* ]]; then - echo "Detected Surface tablet. Using remote build host." - sudo nixos-rebuild switch --flake "$FLAKE_URI" --build-host engr-ugaif@192.168.11.133 --refresh $EXTRA_ARGS - else - echo "Updating local system..." - sudo nixos-rebuild switch --flake "$FLAKE_URI" --refresh $EXTRA_ARGS - fi - '') - ]; + # Pass arguments like --impure to nixos-rebuild + EXTRA_ARGS="$@" + + if [[ "$HOSTNAME" == nix-surface* ]]; then + echo "Detected Surface tablet. Using remote build host." + sudo nixos-rebuild switch --flake "$FLAKE_URI" --build-host engr-ugaif@192.168.11.133 --refresh $EXTRA_ARGS + else + echo "Updating local system..." + sudo nixos-rebuild switch --flake "$FLAKE_URI" --refresh $EXTRA_ARGS + fi + '') + ]; } # Import Desktop or Kiosk modules based on type - (mkIf (cfg.type == "desktop") (import ./desktop { inherit config lib pkgs inputs; })) - (mkIf (cfg.type == "kiosk") (import ./kiosk { inherit config lib pkgs inputs; })) + (mkIf (cfg.type == "desktop") ( + import ./desktop { + inherit + config + lib + pkgs + inputs + ; + } + )) + (mkIf (cfg.type == "kiosk") ( + import ./kiosk { + inherit + config + lib + pkgs + inputs + ; + } + )) ]); } diff --git a/sw/desktop/default.nix b/sw/desktop/default.nix index 5a48d54..342a875 100644 --- a/sw/desktop/default.nix +++ b/sw/desktop/default.nix @@ -1,5 +1,25 @@ -{ config, lib, pkgs, inputs, ... }: +{ + config, + lib, + pkgs, + inputs, + ... +}: lib.mkMerge [ - (import ./programs.nix { inherit config lib pkgs inputs; }) - (import ./services.nix { inherit config lib pkgs inputs; }) + (import ./programs.nix { + inherit + config + lib + pkgs + inputs + ; + }) + (import ./services.nix { + inherit + config + lib + pkgs + inputs + ; + }) ] diff --git a/sw/desktop/programs.nix b/sw/desktop/programs.nix index 77433cd..7f8b075 100644 --- a/sw/desktop/programs.nix +++ b/sw/desktop/programs.nix @@ -1,4 +1,10 @@ -{ config, lib, pkgs, inputs, ... }: +{ + config, + lib, + pkgs, + inputs, + ... +}: with lib; @@ -15,7 +21,8 @@ let teams-for-linux wpsoffice ]; -in { +in +{ environment.systemPackages = subtractLists cfg.excludePackages (basePackages ++ cfg.extraPackages); programs.mtr.enable = true; diff --git a/sw/desktop/services.nix b/sw/desktop/services.nix index 1511f80..7e78c4d 100644 --- a/sw/desktop/services.nix +++ b/sw/desktop/services.nix @@ -1,4 +1,9 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: { modules.sw.python.enable = lib.mkDefault true; diff --git a/sw/ghostty.nix b/sw/ghostty.nix index 0a67a6a..282f263 100644 --- a/sw/ghostty.nix +++ b/sw/ghostty.nix @@ -1,4 +1,9 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: # ============================================================================ # Ghostty Terminfo Module @@ -8,7 +13,7 @@ # adds it to the system packages. let - ghostty-terminfo = pkgs.runCommand "ghostty-terminfo" {} '' + ghostty-terminfo = pkgs.runCommand "ghostty-terminfo" { } '' mkdir -p $out/share/terminfo cat > ghostty.info <<'EOF' xterm-ghostty|ghostty|Ghostty, diff --git a/sw/kiosk/default.nix b/sw/kiosk/default.nix index cb3cf84..50e14fa 100644 --- a/sw/kiosk/default.nix +++ b/sw/kiosk/default.nix @@ -1,6 +1,33 @@ -{ config, lib, pkgs, inputs, ... }: +{ + config, + lib, + pkgs, + inputs, + ... +}: lib.mkMerge [ - (import ./programs.nix { inherit config lib pkgs inputs; }) - (import ./services.nix { inherit config lib pkgs inputs; }) - (import ./gsettings.nix { inherit config lib pkgs inputs; }) + (import ./programs.nix { + inherit + config + lib + pkgs + inputs + ; + }) + (import ./services.nix { + inherit + config + lib + pkgs + inputs + ; + }) + (import ./gsettings.nix { + inherit + config + lib + pkgs + inputs + ; + }) ] diff --git a/sw/kiosk/gsettings.nix b/sw/kiosk/gsettings.nix index 2ead5d1..990d7e2 100644 --- a/sw/kiosk/gsettings.nix +++ b/sw/kiosk/gsettings.nix @@ -1,50 +1,58 @@ -{ config, lib, inputs, ... }: +{ + config, + lib, + inputs, + ... +}: let cfg = config.modules.sw; -in { +in +{ programs.dconf = { enable = true; profiles.user = { - databases = [{ - settings = { - "org/gnome/desktop/interface" = { - color-scheme = "prefer-dark"; - clock-format = "12h"; - clock-show-weekday = true; - show-battery-percentage = true; + databases = [ + { + settings = { + "org/gnome/desktop/interface" = { + color-scheme = "prefer-dark"; + clock-format = "12h"; + clock-show-weekday = true; + show-battery-percentage = true; + }; + "org/gnome/desktop/media-handling" = { + automount = false; + automount-open = false; + autorun-never = true; + }; + "org/gnome/settings-daemon/plugins/power" = { + sleep-inactive-ac-type = "nothing"; + }; + "org/gnome/desktop/lockdown" = { + disable-lock-screen = true; + }; + "org/gnome/desktop/screensaver" = { + lock-enabled = false; + }; + "org/gnome/desktop/session" = { + idle-delay = inputs.nixpkgs.lib.gvariant.mkUint32 0; + }; + "org/gnome/desktop/input-sources" = { + sources = "[('ibus', 'xkb:us::eng')]"; + }; + "org/gnome/desktop/mru-sources" = { + sources = "[('ibus', 'xkb:us::eng')]"; + }; + "sm/puri/phosh" = { + lock-enabled = false; + }; + "org/gnome/desktop/a11y/applications" = { + screen-keyboard-enabled = true; + }; }; - "org/gnome/desktop/media-handling" = { - automount = false; - automount-open = false; - autorun-never = true; - }; - "org/gnome/settings-daemon/plugins/power" = { - sleep-inactive-ac-type = "nothing"; - }; - "org/gnome/desktop/lockdown" = { - disable-lock-screen = true; - }; - "org/gnome/desktop/screensaver" = { - lock-enabled = false; - }; - "org/gnome/desktop/session" = { - idle-delay = inputs.nixpkgs.lib.gvariant.mkUint32 0; - }; - "org/gnome/desktop/input-sources" = { - sources = "[('ibus', 'xkb:us::eng')]"; - }; - "org/gnome/desktop/mru-sources" = { - sources = "[('ibus', 'xkb:us::eng')]"; - }; - "sm/puri/phosh" = { - lock-enabled = false; - }; - "org/gnome/desktop/a11y/applications" = { - screen-keyboard-enabled = true; - }; - }; - }]; + } + ]; }; }; } diff --git a/sw/kiosk/programs.nix b/sw/kiosk/programs.nix index 25bd5ed..a883c1f 100644 --- a/sw/kiosk/programs.nix +++ b/sw/kiosk/programs.nix @@ -1,4 +1,10 @@ -{ config, lib, pkgs, inputs, ... }: +{ + config, + lib, + pkgs, + inputs, + ... +}: with lib; @@ -13,7 +19,8 @@ let phoc gsettings-desktop-schemas ]; -in { +in +{ environment.systemPackages = subtractLists cfg.excludePackages (basePackages ++ cfg.extraPackages); programs.chromium = { diff --git a/sw/kiosk/services.nix b/sw/kiosk/services.nix index 56cef76..5bcfcb6 100644 --- a/sw/kiosk/services.nix +++ b/sw/kiosk/services.nix @@ -1,4 +1,9 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: { services.xserver = { @@ -28,7 +33,7 @@ enable = true; ibus.engines = [ pkgs.ibus-engines.m17n ]; }; - + services.gnome.gnome-keyring.enable = lib.mkForce false; environment.sessionVariables = { @@ -36,9 +41,10 @@ GDK_DPI_SCALE = "0.5"; # Make GLib / gsettings actually see schemas - XDG_DATA_DIRS = [ "/run/current-system/sw/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}" ]; - GSETTINGS_SCHEMA_DIR = - "/run/current-system/sw/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}/glib-2.0/schemas"; + XDG_DATA_DIRS = [ + "/run/current-system/sw/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}" + ]; + GSETTINGS_SCHEMA_DIR = "/run/current-system/sw/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}/glib-2.0/schemas"; }; environment.etc."machine-info".text = '' @@ -46,12 +52,12 @@ ''; services.logind.settings.Login = { - HandlePowerKey="ignore"; - HandleSuspendKey="ignore"; - HandleHibernateKey="ignore"; - HandleLidSwitch="ignore"; - HandleLidSwitchExternalPower="ignore"; - IdleAction="ignore"; + HandlePowerKey = "ignore"; + HandleSuspendKey = "ignore"; + HandleHibernateKey = "ignore"; + HandleLidSwitch = "ignore"; + HandleLidSwitchExternalPower = "ignore"; + IdleAction = "ignore"; }; # Enable networking @@ -90,7 +96,7 @@ systemd.user.services.squeekboard = { description = "Squeekboard on-screen keyboard"; wantedBy = [ "graphical-session.target" ]; - partOf = [ "graphical-session.target" ]; + partOf = [ "graphical-session.target" ]; serviceConfig = { ExecStart = "${pkgs.squeekboard}/bin/squeekboard"; @@ -101,7 +107,7 @@ systemd.user.services."force-osk" = { description = "Force the OSK to Enable"; wantedBy = [ "chromium-kiosk.service" ]; - partOf = [ "chromium-kiosk.service" ]; + partOf = [ "chromium-kiosk.service" ]; serviceConfig = { ExecStartPre = '' @@ -117,7 +123,7 @@ systemd.user.services."force-input-sources" = { description = "Force the Gsettings Input Sources"; wantedBy = [ "chromium-kiosk.service" ]; - partOf = [ "chromium-kiosk.service" ]; + partOf = [ "chromium-kiosk.service" ]; serviceConfig = { ExecStartPre = '' @@ -137,7 +143,7 @@ systemd.user.services."chromium-kiosk" = { description = "Chromium kiosk"; wantedBy = [ "graphical-session.target" ]; - partOf = [ "graphical-session.target" ]; + partOf = [ "graphical-session.target" ]; serviceConfig = { ExecStart = '' diff --git a/sw/nvim.nix b/sw/nvim.nix index 47feade..b798db2 100644 --- a/sw/nvim.nix +++ b/sw/nvim.nix @@ -5,16 +5,19 @@ # ============================================================================ # This module configures Neovim, specifically setting up TreeSitter parsers # to ensure syntax highlighting works correctly. - + # https://github.com/nvim-treesitter/nvim-treesitter#i-get-query-error-invalid-node-type-at-position xdg.configFile."nvim/parser".source = let parsers = pkgs.symlinkJoin { name = "treesitter-parsers"; - paths = (pkgs.vimPlugins.nvim-treesitter.withPlugins (plugins: with plugins; [ - c - lua - ])).dependencies; + paths = + (pkgs.vimPlugins.nvim-treesitter.withPlugins ( + plugins: with plugins; [ + c + lua + ] + )).dependencies; }; in "${parsers}/parser"; diff --git a/sw/python.nix b/sw/python.nix index 3f9d2f9..3902f4e 100644 --- a/sw/python.nix +++ b/sw/python.nix @@ -1,4 +1,9 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: # ============================================================================ # Python Environment @@ -11,7 +16,8 @@ with lib; let cfg = config.modules.sw.python; -in { +in +{ options.modules.sw.python = { enable = mkEnableOption "Python development tools (pixi, uv)"; }; diff --git a/sw/theme.nix b/sw/theme.nix index 24e40d5..8014e12 100644 --- a/sw/theme.nix +++ b/sw/theme.nix @@ -1,4 +1,10 @@ -{ pkgs, config, osConfig, lib, ... }: +{ + pkgs, + config, + osConfig, + lib, + ... +}: # ============================================================================ # Shell Theme Configuration @@ -14,7 +20,7 @@ let }; # Make a root variant with red username (wraps {{ .UserName }} with ANSI red) - jyumppRootTheme = pkgs.runCommand "jyumpp-root.omp.json" {} '' + jyumppRootTheme = pkgs.runCommand "jyumpp-root.omp.json" { } '' sed -E 's|\{\{[[:space:]]*\.UserName[[:space:]]*\}\}|<#FF3B30>{{ .UserName }}|g' \ ${jyumppTheme} > $out ''; diff --git a/users.nix b/users.nix index 097250d..14e627d 100644 --- a/users.nix +++ b/users.nix @@ -16,13 +16,23 @@ }; engr-ugaif = { description = "UGA Innovation Factory"; - extraGroups = [ "networkmanager" "wheel" "video" "input" ]; + extraGroups = [ + "networkmanager" + "wheel" + "video" + "input" + ]; hashedPassword = "$6$El6e2NhPrhVFjbFU$imlGZqUiizWw5fMP/ib0CeboOcFhYjIVb8oR1V1dP2NjDeri3jMoUm4ZABOB2uAF8UEDjAGHhFuZxhtbHg647/"; - opensshKeys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBC7xzHxY2BfFUybMvG4wHSF9oEAGzRiLTFEndLvWV/X hdh20267@engr733847d.engr.uga.edu" ]; + opensshKeys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBC7xzHxY2BfFUybMvG4wHSF9oEAGzRiLTFEndLvWV/X hdh20267@engr733847d.engr.uga.edu" + ]; }; hdh20267 = { description = "Hunter Halloran"; - extraGroups = [ "networkmanager" "wheel" ]; + extraGroups = [ + "networkmanager" + "wheel" + ]; homePackages = [ pkgs.ghostty ]; shell = pkgs.zsh; # Example of using an external flake for configuration: