From b9f56ff57d342d809e62d6d98ddf9c76d738e730 Mon Sep 17 00:00:00 2001 From: John Ogle Date: Sat, 10 Jan 2026 13:09:47 -0800 Subject: [PATCH] feat(home-manager): Add platform compatibility guards to cross-platform roles Add lib.optionals pkgs.stdenv.isLinux guards to roles that contain Linux-only packages or services to prevent build failures on Darwin: - communication: Guard Electron apps (element-desktop, fluffychat, nextcloud-talk-desktop) that don't build on Darwin due to electron build-from-source limitations - kdeconnect: Guard entire config block since services.kdeconnect requires D-Bus and systemd (Linux-only) - sync: Guard syncthingtray package (requires Linux system tray) - email: Guard systemd.user.services/timers (Darwin uses launchd) - desktop: Guard Linux-only packages, services, and KDE-specific configurations including gnome-keyring, systemd services, and XDG mime associations Implements bead: nixos-configs-tcu --- home/roles/communication/default.nix | 9 +- home/roles/desktop/default.nix | 159 ++++++++++++++------------- home/roles/email/default.nix | 55 ++++----- home/roles/kdeconnect/default.nix | 4 +- home/roles/sync/default.nix | 6 +- 5 files changed, 127 insertions(+), 106 deletions(-) diff --git a/home/roles/communication/default.nix b/home/roles/communication/default.nix index 59bcac6..ea09995 100644 --- a/home/roles/communication/default.nix +++ b/home/roles/communication/default.nix @@ -4,6 +4,7 @@ with lib; let cfg = config.home.roles.communication; + isLinux = pkgs.stdenv.isLinux; in { options.home.roles.communication = { @@ -12,14 +13,14 @@ in config = mkIf cfg.enable { home.packages = [ - # Communication apps + # For logging back into google chat (cross-platform) + globalInputs.google-cookie-retrieval.packages.${system}.default + ] ++ optionals isLinux [ + # Linux-only communication apps (Electron apps don't build on Darwin) pkgs.element-desktop # Re-enabled in 25.11 after security issues were resolved pkgs.fluffychat pkgs.nextcloud-talk-desktop - - # For logging back into google chat - globalInputs.google-cookie-retrieval.packages.${system}.default ]; }; } diff --git a/home/roles/desktop/default.nix b/home/roles/desktop/default.nix index 0de7491..dc600ef 100644 --- a/home/roles/desktop/default.nix +++ b/home/roles/desktop/default.nix @@ -4,6 +4,7 @@ with lib; let cfg = config.home.roles.desktop; + isLinux = pkgs.stdenv.isLinux; in { options.home.roles.desktop = { @@ -12,61 +13,63 @@ in config = mkIf cfg.enable { home.packages = with pkgs; [ - # Desktop applications + # Cross-platform desktop applications bitwarden-desktop - dunst keepassxc + xdg-utils # XDG utilities for opening files/URLs with default applications + ] ++ optionals isLinux [ + # Linux-only desktop applications + dunst unstable.ghostty - - # Desktop utilities + + # Linux-only desktop utilities feh # Image viewer and wallpaper setter for X11 rofi # Application launcher for X11 solaar # Logitech management software waybar wofi # Application launcher for Wayland - xdg-utils # XDG utilities for opening files/URLs with default applications - - # System utilities with GUI components + + # Linux-only system utilities with GUI components (snapcast.override { pulseaudioSupport = true; }) - - # KDE tiling window management + + # KDE tiling window management (Linux-only) kdePackages.krohnkite # Dynamic tiling extension for KWin 6 - - # KDE PIM applications for email, calendar, and contacts + + # KDE PIM applications for email, calendar, and contacts (Linux-only) kdePackages.kmail kdePackages.kmail-account-wizard kdePackages.kmailtransport kdePackages.korganizer kdePackages.kaddressbook kdePackages.kontact - - # KDE System components needed for proper integration + + # KDE System components needed for proper integration (Linux-only) kdePackages.kded kdePackages.systemsettings kdePackages.kmenuedit - - # Desktop menu support + + # Desktop menu support (Linux-only) kdePackages.plasma-desktop # Contains applications.menu - - # KDE Online Accounts support + + # KDE Online Accounts support (Linux-only) kdePackages.kaccounts-integration kdePackages.kaccounts-providers kdePackages.signond - - # KDE Mapping + + # KDE Mapping (Linux-only) kdePackages.marble # Virtual globe and world atlas - - # KDE Productivity + + # KDE Productivity (Linux-only) kdePackages.kate # Advanced text editor with syntax highlighting kdePackages.okular # Universal document viewer (PDF, ePub, etc.) kdePackages.spectacle # Screenshot capture utility kdePackages.filelight # Visual disk usage analyzer - - # KDE Multimedia + + # KDE Multimedia (Linux-only) kdePackages.gwenview # Image viewer and basic editor kdePackages.elisa # Music player - - # KDE System Utilities + + # KDE System Utilities (Linux-only) kdePackages.ark # Archive manager (zip, tar, 7z, etc.) kdePackages.yakuake # Drop-down terminal emulator ]; @@ -77,61 +80,66 @@ in programs.spotify-player.enable = true; - services.gnome-keyring = { + # Linux-only: GNOME keyring service + services.gnome-keyring = mkIf isLinux { enable = true; }; - # rbw vault unlock on login and resume from suspend - systemd.user.services.rbw-unlock-on-login = { - Unit = { - Description = "Unlock rbw vault at login"; - After = [ "graphical-session.target" ]; + # Linux-only: systemd user services for rbw vault unlock + systemd.user.services = mkIf isLinux { + # rbw vault unlock on login + rbw-unlock-on-login = { + Unit = { + Description = "Unlock rbw vault at login"; + After = [ "graphical-session.target" ]; + }; + Service = { + Type = "oneshot"; + ExecStart = "${pkgs.rbw}/bin/rbw unlock"; + Environment = "RBW_AGENT=${pkgs.rbw}/bin/rbw-agent"; + # KillMode = "process" prevents systemd from killing the rbw-agent daemon + # when this oneshot service completes. The agent is spawned by rbw unlock + # and needs to persist after the service exits. + KillMode = "process"; + }; + Install = { + WantedBy = [ "graphical-session.target" ]; + }; }; - Service = { - Type = "oneshot"; - ExecStart = "${pkgs.rbw}/bin/rbw unlock"; - Environment = "RBW_AGENT=${pkgs.rbw}/bin/rbw-agent"; - # KillMode = "process" prevents systemd from killing the rbw-agent daemon - # when this oneshot service completes. The agent is spawned by rbw unlock - # and needs to persist after the service exits. - KillMode = "process"; - }; - Install = { - WantedBy = [ "graphical-session.target" ]; + + # rbw vault unlock on resume from suspend + rbw-unlock-on-resume = { + Unit = { + Description = "Unlock rbw vault after resume from suspend"; + After = [ "suspend.target" ]; + }; + Service = { + Type = "oneshot"; + ExecStart = "${pkgs.rbw}/bin/rbw unlock"; + Environment = "RBW_AGENT=${pkgs.rbw}/bin/rbw-agent"; + # KillMode = "process" prevents systemd from killing the rbw-agent daemon + # when this oneshot service completes. The agent is spawned by rbw unlock + # and needs to persist after the service exits. + KillMode = "process"; + }; + Install = { + WantedBy = [ "suspend.target" ]; + }; }; }; - systemd.user.services.rbw-unlock-on-resume = { - Unit = { - Description = "Unlock rbw vault after resume from suspend"; - After = [ "suspend.target" ]; - }; - Service = { - Type = "oneshot"; - ExecStart = "${pkgs.rbw}/bin/rbw unlock"; - Environment = "RBW_AGENT=${pkgs.rbw}/bin/rbw-agent"; - # KillMode = "process" prevents systemd from killing the rbw-agent daemon - # when this oneshot service completes. The agent is spawned by rbw unlock - # and needs to persist after the service exits. - KillMode = "process"; - }; - Install = { - WantedBy = [ "suspend.target" ]; - }; - }; - - # KDE environment variables for proper integration - home.sessionVariables = { + # Linux-only: KDE environment variables for proper integration + home.sessionVariables = mkIf isLinux { QT_QPA_PLATFORMTHEME = "kde"; KDE_SESSION_VERSION = "6"; }; xdg = { enable = true; - + # Ensure desktop files are made available for discovery desktopEntries = {}; # This creates the desktop files directory structure - + mimeApps = { enable = true; associations.added = { @@ -141,13 +149,14 @@ in "x-scheme-handler/https" = "firefox.desktop"; }; defaultApplications = { - # Web browsers + # Web browsers (cross-platform) "text/html" = "firefox.desktop"; "x-scheme-handler/http" = "firefox.desktop"; "x-scheme-handler/https" = "firefox.desktop"; "x-scheme-handler/about" = "firefox.desktop"; "x-scheme-handler/unknown" = "firefox.desktop"; - + } // optionalAttrs isLinux { + # Linux-only: KDE application associations # Documents "application/pdf" = "okular.desktop"; "text/plain" = "kate.desktop"; @@ -155,7 +164,7 @@ in "text/x-c" = "kate.desktop"; "text/x-python" = "kate.desktop"; "application/x-shellscript" = "kate.desktop"; - + # Images "image/png" = "gwenview.desktop"; "image/jpeg" = "gwenview.desktop"; @@ -164,25 +173,25 @@ in "image/bmp" = "gwenview.desktop"; "image/tiff" = "gwenview.desktop"; "image/webp" = "gwenview.desktop"; - + # Archives "application/zip" = "ark.desktop"; "application/x-tar" = "ark.desktop"; "application/x-compressed-tar" = "ark.desktop"; "application/x-7z-compressed" = "ark.desktop"; "application/x-rar" = "ark.desktop"; - + # Audio "audio/mpeg" = "elisa.desktop"; "audio/mp4" = "elisa.desktop"; "audio/flac" = "elisa.desktop"; "audio/ogg" = "elisa.desktop"; "audio/wav" = "elisa.desktop"; - + # Email "message/rfc822" = "kmail.desktop"; "x-scheme-handler/mailto" = "kmail.desktop"; - + # Calendar "text/calendar" = "korganizer.desktop"; "application/x-vnd.akonadi.calendar.event" = "korganizer.desktop"; @@ -190,9 +199,11 @@ in }; }; - # Fix for KDE applications.menu file issue on Plasma 6 + # Linux-only: Fix for KDE applications.menu file issue on Plasma 6 # KDE still looks for applications.menu but Plasma 6 renamed it to plasma-applications.menu - xdg.configFile."menus/applications.menu".source = "${pkgs.kdePackages.plasma-workspace}/etc/xdg/menus/plasma-applications.menu"; + xdg.configFile."menus/applications.menu" = mkIf isLinux { + source = "${pkgs.kdePackages.plasma-workspace}/etc/xdg/menus/plasma-applications.menu"; + }; # Note: modules must be imported at top-level home config }; diff --git a/home/roles/email/default.nix b/home/roles/email/default.nix index a71c635..7cd87a5 100644 --- a/home/roles/email/default.nix +++ b/home/roles/email/default.nix @@ -4,6 +4,7 @@ with lib; let cfg = config.home.roles.email; + isLinux = pkgs.stdenv.isLinux; in { options.home.roles.email = { @@ -89,34 +90,38 @@ in account default : proton ''; - # Systemd service for mail sync - systemd.user.services.mbsync = { - Unit = { - Description = "Mailbox synchronization service"; - After = [ "network-online.target" ]; - Wants = [ "network-online.target" ]; - }; - Service = { - Type = "oneshot"; - ExecStart = "${pkgs.bash}/bin/bash -c 'mkdir -p ~/Mail && ${pkgs.isync}/bin/mbsync -a && (${pkgs.mu}/bin/mu info >/dev/null 2>&1 || ${pkgs.mu}/bin/mu init --maildir ~/Mail --personal-address=john@ogle.fyi) && ${pkgs.mu}/bin/mu index'"; - Environment = "PATH=${pkgs.rbw}/bin:${pkgs.coreutils}/bin"; - StandardOutput = "journal"; - StandardError = "journal"; + # Linux-only: Systemd service for mail sync (Darwin uses launchd instead) + systemd.user.services = mkIf isLinux { + mbsync = { + Unit = { + Description = "Mailbox synchronization service"; + After = [ "network-online.target" ]; + Wants = [ "network-online.target" ]; + }; + Service = { + Type = "oneshot"; + ExecStart = "${pkgs.bash}/bin/bash -c 'mkdir -p ~/Mail && ${pkgs.isync}/bin/mbsync -a && (${pkgs.mu}/bin/mu info >/dev/null 2>&1 || ${pkgs.mu}/bin/mu init --maildir ~/Mail --personal-address=john@ogle.fyi) && ${pkgs.mu}/bin/mu index'"; + Environment = "PATH=${pkgs.rbw}/bin:${pkgs.coreutils}/bin"; + StandardOutput = "journal"; + StandardError = "journal"; + }; }; }; - # Systemd timer for automatic sync - systemd.user.timers.mbsync = { - Unit = { - Description = "Mailbox synchronization timer"; - }; - Timer = { - OnBootSec = "2min"; - OnUnitActiveSec = "5min"; - Unit = "mbsync.service"; - }; - Install = { - WantedBy = [ "timers.target" ]; + # Linux-only: Systemd timer for automatic sync + systemd.user.timers = mkIf isLinux { + mbsync = { + Unit = { + Description = "Mailbox synchronization timer"; + }; + Timer = { + OnBootSec = "2min"; + OnUnitActiveSec = "5min"; + Unit = "mbsync.service"; + }; + Install = { + WantedBy = [ "timers.target" ]; + }; }; }; }; diff --git a/home/roles/kdeconnect/default.nix b/home/roles/kdeconnect/default.nix index ceceb27..26675ca 100644 --- a/home/roles/kdeconnect/default.nix +++ b/home/roles/kdeconnect/default.nix @@ -4,13 +4,15 @@ with lib; let cfg = config.home.roles.kdeconnect; + isLinux = pkgs.stdenv.isLinux; in { options.home.roles.kdeconnect = { enable = mkEnableOption "Enable KDE Connect for device integration"; }; - config = mkIf cfg.enable { + # KDE Connect services are Linux-only (requires D-Bus and systemd) + config = mkIf (cfg.enable && isLinux) { services.kdeconnect = { enable = true; indicator = true; diff --git a/home/roles/sync/default.nix b/home/roles/sync/default.nix index 1789b69..c496737 100644 --- a/home/roles/sync/default.nix +++ b/home/roles/sync/default.nix @@ -4,6 +4,7 @@ with lib; let cfg = config.home.roles.sync; + isLinux = pkgs.stdenv.isLinux; in { options.home.roles.sync = { @@ -11,9 +12,10 @@ in }; config = mkIf cfg.enable { - home.packages = with pkgs; [ + # Linux-only: syncthingtray requires system tray support + home.packages = optionals isLinux (with pkgs; [ syncthingtray - ]; + ]); services.syncthing = { enable = true; -- 2.49.1