DEVELOPMENT ENVIRONMENT

~liljamo/nix-arta

e48b2517640d2f279cc0d3aea4ea47f79ac224fd — Jonni Liljamo 7 days ago 4992e9f
feat: move arwen to ws and clenup orphan modules
50 files changed, 55 insertions(+), 1624 deletions(-)

D lib/util.nix
D modules/default.nix
D modules/unfree.nix
D roles/audio.nix
D roles/base.nix
D roles/bluetooth.nix
D roles/cadvisor.nix
D roles/default.nix
D roles/docker.nix
D roles/gaming/default.nix
D roles/gaming/lutris.nix
D roles/gaming/steam.nix
D roles/git.nix
D roles/graphics/amd.nix
D roles/graphics/default.nix
D roles/graphics/nvidia.nix
D roles/hyprland.nix
D roles/imv.nix
D roles/kitty.nix
D roles/nix.nix
D roles/obs.nix
D roles/plasma.nix
D roles/podman.nix
D roles/prometheus.nix
D roles/qutebrowser.nix
D roles/shell/default.nix
D roles/shell/direnv.elv
D roles/tailscale.nix
D roles/zellij.nix
D systems/default.nix
D systems/hosts/alice/default.nix
D systems/hosts/default.nix
D systems/profiles/common/fonts.nix
D systems/profiles/default.nix
D systems/profiles/desktop/default.nix
D systems/profiles/desktop/desktop.nix
D systems/profiles/laptop/default.nix
D systems/profiles/laptop/laptop.nix
D systems/profiles/lxc/default.nix
D systems/profiles/lxc/lxc.nix
D systems/profiles/lxc/roles.nix
D systems/profiles/lxcbase/default.nix
D systems/profiles/lxcbase/lxcbase.nix
D systems/profiles/vm/default.nix
D systems/profiles/vm/vm.nix
A ws/hosts/alice/core/default.nix
R systems/hosts/alice/hardware-configuration.nix => ws/hosts/alice/core/hardware-configuration.nix
A ws/hosts/alice/core/impermanence.nix
R hosts/alice/default.nix => ws/hosts/alice/default.nix
R hosts/alice/hyprland.nix => ws/hosts/alice/hyprland.nix
D lib/util.nix => lib/util.nix +0 -31
@@ 1,31 0,0 @@
{lib, ...}: let
  hostnameIPv4 = {
    vm = {};

    lxc = {
      "dns" = "10.1.2.3";
      "metrics" = "10.1.2.5";
      "oci" = "10.1.2.9";
      "proxy" = "10.1.2.10";
      "auth" = "10.1.2.12";
      "cloud" = "10.1.2.15";
      "social" = "10.1.2.17";
    };
  };

  # getIPv4 "profile" "hostname"
  getIPv4 = profile: hostname: hostnameIPv4.${profile}.${hostname};

  # getHostnames "profile"
  getHostnames = profile: builtins.attrNames hostnameIPv4.${profile};

  # getDNSEntries "profile"
  getDNSEntries = profile:
    lib.attrsets.mapAttrs'
    (name: value: lib.attrsets.nameValuePair (name + ".home.arpa") value)
    hostnameIPv4.${profile};
in {
  getIPv4 = getIPv4;
  getHostnames = getHostnames;
  getDNSEntries = getDNSEntries;
}

D modules/default.nix => modules/default.nix +0 -5
@@ 1,5 0,0 @@
{
  imports = [
    ./unfree.nix
  ];
}

D modules/unfree.nix => modules/unfree.nix +0 -19
@@ 1,19 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.arta.unfree;
in {
  options.arta.unfree = {
    allow = lib.mkOption {
      type = lib.types.listOf lib.types.str;
      default = [];
    };
  };

  config = {
    nixpkgs.config.allowUnfreePredicate = pkg:
      builtins.elem (lib.getName pkg) cfg.allow;
  };
}

D roles/audio.nix => roles/audio.nix +0 -28
@@ 1,28 0,0 @@
{
  config,
  lib,
  pkgs,
  ...
}: let
  cfg = config.roles.audio;
in {
  options.roles.audio = {
    enable = lib.mkEnableOption "enable audio";
  };

  config = lib.mkIf cfg.enable {
    environment.systemPackages = with pkgs; [
      pavucontrol
    ];

    services.pipewire = {
      enable = true;
      alsa = {
        enable = true;
        support32Bit = true;
      };
      jack.enable = true;
      pulse.enable = true;
    };
  };
}

D roles/base.nix => roles/base.nix +0 -65
@@ 1,65 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.base;
in {
  options.roles.base = {
    root = lib.mkOption {
      type = lib.types.submodule {
        options = {
          hashedPasswordFile = lib.mkOption {
            type = lib.types.path;
          };
        };
      };
    };
    primaryUser = lib.mkOption {
      type = lib.types.submodule {
        options = {
          username = lib.mkOption {
            type = lib.types.str;
          };
          isWheel = lib.mkEnableOption "admin permissions";
          extraGroups = lib.mkOption {
            type = lib.types.listOf lib.types.str;
            default = [];
          };
          hashedPasswordFile = lib.mkOption {
            type = lib.types.path;
          };
        };
      };
    };
  };

  imports = [
    (lib.mkAliasOptionModule ["hm"] [
      "home-manager"
      "users"
      cfg.primaryUser.username
    ])
  ];

  config = let
    homeDirectory = "/home/${cfg.primaryUser.username}";
  in {
    users.users.root.hashedPasswordFile = cfg.root.hashedPasswordFile;
    users.users.${cfg.primaryUser.username} = {
      isNormalUser = true;
      extraGroups = cfg.primaryUser.extraGroups ++ lib.optional cfg.primaryUser.isWheel "wheel";
      home = homeDirectory;
      hashedPasswordFile = cfg.primaryUser.hashedPasswordFile;
    };
    home-manager = {
      useUserPackages = true;
      useGlobalPkgs = true;
    };
    hm.home = {
      inherit (cfg.primaryUser) username;
      inherit homeDirectory;
      stateVersion = config.system.stateVersion;
    };
  };
}

D roles/bluetooth.nix => roles/bluetooth.nix +0 -28
@@ 1,28 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.bluetooth;
in {
  options.roles.bluetooth = {
    enable = lib.mkEnableOption "enable bluetooth";
    enableHDAudio = lib.mkEnableOption "enable HD audio for bluetooth";
  };

  config = lib.mkIf cfg.enable {
    hardware.bluetooth.enable = true;
    services.blueman.enable = true;

    services.pipewire.wireplumber.extraConfig = lib.mkIf cfg.enableHDAudio {
      bluetoothEnhancements = {
        "monitor.bluez.properties" = {
          "bluez5.enable-sbc-xq" = true;
          "bluez5.enable-msbc" = true;
          "bluez5.enable-hw-volume" = true;
          "bluez5.roles" = ["hsp_hs" "hsp_ag" "hfp_hf" "hfp_ag"];
        };
      };
    };
  };
}

D roles/cadvisor.nix => roles/cadvisor.nix +0 -32
@@ 1,32 0,0 @@
{
  lib,
  config,
  ...
}: let
  cfg = config.roles.cadvisor;
in {
  options.roles.cadvisor = {
    enable = lib.mkEnableOption "cadvisor";
    port = lib.mkOption {
      type = lib.types.port;
      default = 9080;
    };
    openFirewall = lib.mkOption {
      type = lib.types.bool;
      default = false;
      description = "Wheter to open firewall port for cadvisor";
    };
  };

  config = lib.mkIf cfg.enable {
    networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [
      cfg.port
    ];

    services.cadvisor = {
      enable = true;
      listenAddress = "0.0.0.0";
      port = cfg.port;
    };
  };
}

D roles/default.nix => roles/default.nix +0 -25
@@ 1,25 0,0 @@
{...}: {
  imports = [
    ./gaming
    ./graphics
    ./shell

    ./audio.nix
    ./base.nix
    ./bluetooth.nix
    ./cadvisor.nix
    ./docker.nix
    ./git.nix
    ./hyprland.nix
    ./imv.nix
    ./kitty.nix
    ./nix.nix
    ./obs.nix
    ./plasma.nix
    ./podman.nix
    ./prometheus.nix
    ./qutebrowser.nix
    ./tailscale.nix
    ./zellij.nix
  ];
}

D roles/docker.nix => roles/docker.nix +0 -22
@@ 1,22 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.docker;
in {
  options.roles.docker = {
    enable = lib.mkEnableOption "Docker";
    enableNvidia = lib.mkEnableOption "Docker NVIDIA GPU support";
  };

  config = lib.mkIf cfg.enable {
    virtualisation.docker = {
      enable = true;
      enableNvidia = cfg.enableNvidia;
    };

    # FIXME: Make configurable.
    roles.base.primaryUser.extraGroups = ["docker"];
  };
}

D roles/gaming/default.nix => roles/gaming/default.nix +0 -59
@@ 1,59 0,0 @@
{
  config,
  lib,
  pkgs,
  ...
}: let
  cfg = config.roles.gaming;
in {
  imports = [
    ./lutris.nix
    ./steam.nix
  ];

  options.roles.gaming = {
    enable = lib.mkEnableOption "gaming utilities";
    lutris.enable = lib.mkEnableOption "Lutris";
    steam.enable = lib.mkEnableOption "Steam";
  };

  config = lib.mkIf cfg.enable {
    programs.gamemode = {
      enable = true;
    };

    environment.systemPackages = with pkgs; [
      gamescope
      protontricks
      gnome.zenity
      r2modman
    ];

    hm = {
      programs.mangohud = {
        enable = true;
        enableSessionWide = false;
        settings = {
          fps_limit = "60,90,120,200";
          time = true;

          gpu_stats = true;
          gpu_temp = true;
          gpu_text = "GPU";

          cpu_stats = true;
          cpu_temp = true;
          cpu_text = "CPU";

          vram = true;
          ram = true;

          fps = true;
          frametime = true;
          frame_timing = true;
          show_fps_limit = true;
        };
      };
    };
  };
}

D roles/gaming/lutris.nix => roles/gaming/lutris.nix +0 -16
@@ 1,16 0,0 @@
{
  config,
  lib,
  pkgs,
  ...
}: let
  cfg = config.roles.gaming;
in {
  config = lib.mkIf cfg.lutris.enable {
    environment.systemPackages = with pkgs; [
      lutris

      wineWowPackages.stable
    ];
  };
}

D roles/gaming/steam.nix => roles/gaming/steam.nix +0 -45
@@ 1,45 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.gaming;
in {
  config = lib.mkIf cfg.steam.enable {
    arta.unfree.allow = [
      "steam-run"
      "steam-original"
      "steam"
    ];

    nixpkgs.config.packageOverrides = pkgs: {
      steam = pkgs.steam.override {
        extraPkgs = pkgs:
          with pkgs; [
            # For gamescope to work properly:
            # https://github.com/NixOS/nixpkgs/issues/162562#issuecomment-1523177264
            xorg.libXcursor
            xorg.libXi
            xorg.libXinerama
            xorg.libXScrnSaver
            libpng
            libpulseaudio
            libvorbis
            stdenv.cc.cc.lib
            libkrb5
            keyutils

            # Fallback fonts (e.g. for Don't Get Lost).
            liberation_ttf
          ];
      };
    };

    programs.steam = {
      enable = true;
      remotePlay.openFirewall = false;
      dedicatedServer.openFirewall = false;
    };
    hardware.steam-hardware.enable = true;
  };
}

D roles/git.nix => roles/git.nix +0 -42
@@ 1,42 0,0 @@
{
  config,
  lib,
  pkgs,
  ...
}: let
  cfg = config.roles.git;
in {
  options.roles.git = {
    enable = lib.mkEnableOption "enable git";
    email = lib.mkOption {
      type = lib.types.str;
    };
    name = lib.mkOption {
      type = lib.types.str;
    };
    gitExtraConfig = lib.mkOption {
      type = lib.types.lines;
      default = {};
    };
    enableLazygit = lib.mkEnableOption "enable lazygit";
  };

  config = {
    programs.lazygit = lib.mkIf cfg.enableLazygit {
      enable = true;
      settings = {
        disableStartupPopups = true;
      };
    };

    hm = {
      programs.git = lib.mkIf cfg.enable {
        enable = true;
        package = pkgs.gitAndTools.gitFull;
        userEmail = cfg.email;
        userName = cfg.name;
        extraConfig = cfg.gitExtraConfig;
      };
    };
  };
}

D roles/graphics/amd.nix => roles/graphics/amd.nix +0 -13
@@ 1,13 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.graphics;
in {
  config = lib.mkIf cfg.amd.enable {
    boot.initrd.kernelModules = ["amdgpu"];

    services.xserver.videoDrivers = ["amdgpu"];
  };
}

D roles/graphics/default.nix => roles/graphics/default.nix +0 -26
@@ 1,26 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.graphics;
in {
  imports = [
    ./amd.nix
    ./nvidia.nix
  ];

  options.roles.graphics = {
    enable = lib.mkEnableOption "graphics drivers";
    amd.enable = lib.mkEnableOption "AMDGPU drivers";
    nvidia.enable = lib.mkEnableOption "NVIDIA drivers";
  };

  config = lib.mkIf cfg.enable {
    hardware.opengl = {
      enable = true;
      driSupport = true;
      driSupport32Bit = true;
    };
  };
}

D roles/graphics/nvidia.nix => roles/graphics/nvidia.nix +0 -21
@@ 1,21 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.graphics;
in {
  config = lib.mkIf cfg.nvidia.enable {
    arta.unfree.allow = ["nvidia-x11"];

    services.xserver.videoDrivers = ["nvidia"];

    hardware.nvidia = {
      modesetting.enable = true;
      powerManagement.enable = true;
      open = true;
      nvidiaSettings = false;
    };
    boot.kernelParams = ["nvidia-drm.fbdev=1"];
  };
}

D roles/hyprland.nix => roles/hyprland.nix +0 -163
@@ 1,163 0,0 @@
{
  config,
  inputs,
  lib,
  pkgs,
  ...
}: let
  cfg = config.roles.hyprland;
in {
  options.roles.hyprland = {
    enable = lib.mkEnableOption "enable hyprland";
  };

  config = lib.mkIf cfg.enable {
    environment.systemPackages = [
      pkgs.bemenu

      pkgs.playerctl
    ];

    programs.hyprland.enable = true;

    security.pam.services.hyprlock = {};

    hm = {
      wayland.windowManager.hyprland = {
        enable = true;
        plugins = [inputs.hy3.packages.${pkgs.stdenv.hostPlatform.system}.hy3];
        # NOTE: These are just the default settings.
        settings = {
          exec-once = [
            "wpaperd -d"
          ];

          input = {
            kb_layout = "us,fi,no";
            kb_options = "grp:win_space_toggle,ctrl:nocaps";
            touchpad = {
              disable_while_typing = false;
            };
          };

          misc = {
            disable_hyprland_logo = true;
            disable_splash_rendering = true;
          };

          "$mod" = "SUPER";
          bind = [
            "$mod, Return, exec, kitty"
            "$mod SHIFT, return, exec, bemenu-run"
            "$mod SHIFT, x, exec, hyprlock"

            "$mod, w, exec, wpaperctl next"

            "$mod SHIFT, c, killactive"
            "$mod SHIFT, q, exit"

            "$mod, f, fullscreen, 0"
            "$mod SHIFT, space, togglefloating"

            "$mod, Tab, cyclenext,"
            "$mod, Tab, bringactivetotop,"

            "$mod, v, hy3:makegroup, v, ephemeral"
            "$mod, b, hy3:makegroup, h, ephemeral"

            "$mod, h, hy3:movefocus, l"
            "$mod, j, hy3:movefocus, d"
            "$mod, k, hy3:movefocus, u"
            "$mod, l, hy3:movefocus, r"
            "$mod SHIFT, h, hy3:movewindow, l"
            "$mod SHIFT, j, hy3:movewindow, d"
            "$mod SHIFT, k, hy3:movewindow, u"
            "$mod SHIFT, l, hy3:movewindow, r"

            "$mod, 1, workspace, 1"
            "$mod, 2, workspace, 2"
            "$mod, 3, workspace, 3"
            "$mod, 4, workspace, 4"
            "$mod, 5, workspace, 5"
            "$mod, 6, workspace, 6"
            "$mod, 7, workspace, 7"
            "$mod, 8, workspace, 8"
            "$mod, 9, workspace, 9"
            "$mod SHIFT, 1, hy3:movetoworkspace, 1"
            "$mod SHIFT, 2, hy3:movetoworkspace, 2"
            "$mod SHIFT, 3, hy3:movetoworkspace, 3"
            "$mod SHIFT, 4, hy3:movetoworkspace, 4"
            "$mod SHIFT, 5, hy3:movetoworkspace, 5"
            "$mod SHIFT, 6, hy3:movetoworkspace, 6"
            "$mod SHIFT, 7, hy3:movetoworkspace, 7"
            "$mod SHIFT, 8, hy3:movetoworkspace, 8"
            "$mod SHIFT, 9, hy3:movetoworkspace, 9"
          ];
          binde = [
            "$mod CTRL, h, resizeactive, -10 0"
            "$mod CTRL, j, resizeactive, 0 -10"
            "$mod CTRL, k, resizeactive, 0 10"
            "$mod CTRL, l, resizeactive, 10 0"
          ];

          bindm = [
            "$mod, mouse:272, movewindow"
            "$mod, mouse:273, resizewindow"
          ];
        };
      };

      services.hypridle = {
        enable = true;
        settings = {
          listener = [
            {
              timeout = 500;
            }
          ];
          general.lock_cmd = "hyprlock";
        };
      };

      programs.hyprlock = {
        enable = true;
        settings = {
          general = {
            no_fade_in = true;
            no_fade_out = true;
          };
          background = [
            {
              #path = "/home/skye/dev/femboys.png";
              color = "rgba(0, 0, 0, 1.0)";
            }
          ];
          input-field = [
            {
              monitor = "";
              size = "200, 50";
              position = "0, 0";
            }
          ];
        };
      };

      programs.wpaperd.enable = true;

      services.mako = {
        enable = true;
        maxVisible = 5;
        defaultTimeout = 5000;
        backgroundColor = "#7298bf";
        textColor = "#e0c296";
        borderColor = "#ffffff";
        borderSize = 2;
      };

      programs.waybar = {
        enable = true;
        systemd.enable = false;
      };
    };
  };
}

D roles/imv.nix => roles/imv.nix +0 -15
@@ 1,15 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.imv;
in {
  options.roles.imv = {
    enable = lib.mkEnableOption "imv, a command line image viewer";
  };

  config = lib.mkIf cfg.enable {
    hm.programs.imv.enable = true;
  };
}

D roles/kitty.nix => roles/kitty.nix +0 -80
@@ 1,80 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.kitty;
in {
  options.roles.kitty = {
    enable = lib.mkEnableOption "enable kitty";
  };

  config.hm = lib.mkIf cfg.enable {
    programs.kitty = {
      enable = true;
      settings = {
        shell = "elvish";

        font_family = "FiraCode Nerd Font Mono";
        bold_font = "auto";
        italic_font = "auto";
        bold_italic_font = "auto";

        font_size = "12.0";

        enable_audio_bell = false;

        window_padding_width = 10;

        background_opacity = "0.9";

        foreground = "#5c6a72";
        background = "#fffbef";

        selection_foreground = "#829181";
        selection_background = "#f0f2d4";

        cursor = "#5c6a72";
        cursor_text_color = "#f8f5e4";

        url_color = "#3a94c5";

        active_border_color = "#8da101";
        inactive_border_color = "#bec5b2";
        bell_border_color = "#f57d26";
        visual_bell_color = "none";

        active_tab_background = "#fffbef";
        active_tab_foreground = "#5c6a72";
        inactive_tab_background = "#f2efdf";
        inactive_tab_foreground = "#939f91";
        tab_bar_background = "#f8f5e4";
        tab_bar_margin_color = "none";

        mark1_foreground = "#fffbef";
        mark1_background = "#3a94c5";
        mark2_foreground = "#fffbef";
        mark2_background = "#d3c6aa";
        mark3_foreground = "#fffbef";
        mark3_background = "#df69ba";

        color0 = "#708089";
        color8 = "#829181";
        color1 = "#f85552";
        color9 = "#e66868";
        color2 = "#8da101";
        color10 = "#93b259";
        color3 = "#dfa000";
        color11 = "#dfa000";
        color4 = "#3a94c5";
        color12 = "#3a94c5";
        color5 = "#df69ba";
        color13 = "#df69ba";
        color6 = "#35a77c";
        color14 = "#35a77c";
        color7 = "#939f91";
        color15 = "#a6b0a0";
      };
    };
  };
}

D roles/nix.nix => roles/nix.nix +0 -14
@@ 1,14 0,0 @@
{
  nix = {
    gc = {
      automatic = true;
      dates = "weekly";
      options = "--delete-older-than 7d";
    };
    settings = {
      auto-optimise-store = true;
      experimental-features = ["nix-command" "flakes"];
      trusted-users = ["@wheel"];
    };
  };
}

D roles/obs.nix => roles/obs.nix +0 -25
@@ 1,25 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.obs;
in {
  options.roles.obs = {
    enable = lib.mkEnableOption "OBS Studio";
    enableVirtualCamera = lib.mkEnableOption "OBS virtual camera"; # TODO: implement lol
  };

  config = lib.mkIf cfg.enable {
    hm.programs.obs-studio = {
      enable = true;
    };

    boot.extraModulePackages = [
      config.boot.kernelPackages.v4l2loopback
    ];
    boot.extraModprobeConfig = ''
      options v4l2loopback devices=1 video_nr=1 card_label="OBS virtual camera" exclusive_caps=1
    '';
  };
}

D roles/plasma.nix => roles/plasma.nix +0 -27
@@ 1,27 0,0 @@
{
  config,
  lib,
  pkgs,
  ...
}: let
  cfg = config.roles.plasma;
in {
  options.roles.plasma = {
    enable = lib.mkEnableOption "KDE Plasma";
  };

  config = lib.mkIf cfg.enable {
    services.displayManager = {
      defaultSession = "plasma";
      sddm = {
        enable = true;
        wayland.enable = true;
      };
    };
    services.desktopManager.plasma6.enable = true;

    environment.plasma6.excludePackages = with pkgs.kdePackages; [
      konsole
    ];
  };
}

D roles/podman.nix => roles/podman.nix +0 -17
@@ 1,17 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.podman;
in {
  options.roles.podman = {
    enable = lib.mkEnableOption "Podman";
  };

  config = lib.mkIf cfg.enable {
    virtualisation.podman = {
      enable = true;
    };
  };
}

D roles/prometheus.nix => roles/prometheus.nix +0 -70
@@ 1,70 0,0 @@
{
  lib,
  config,
  ...
}: let
  cfg = config.roles.prometheus;
in {
  options.roles.prometheus = {
    exporters = lib.mkOption {
      type = lib.types.submodule {
        options = {
          enable = lib.mkEnableOption "prometheus exporters";
          openFirewall = lib.mkOption {
            type = lib.types.bool;
            default = false;
            description = "Wheter to open firewall ports for enabled exporters";
          };
          node = lib.mkOption {
            type = lib.types.submodule {
              options = {
                enable = lib.mkEnableOption "node exporter";
                port = lib.mkOption {
                  type = lib.types.port;
                  default = 9100;
                };
                extraFlags = lib.mkOption {
                  type = lib.types.listOf lib.types.str;
                  default = [];
                };
              };
            };
          };
          systemd = lib.mkOption {
            type = lib.types.submodule {
              options = {
                enable = lib.mkEnableOption "systemd exporter";
                port = lib.mkOption {
                  type = lib.types.port;
                  default = 9558;
                };
              };
            };
          };
        };
      };
      default = {};
    };
  };

  # FIXME: this or top level prometheus server enable
  config = lib.mkIf cfg.exporters.enable {
    # FIXME: only open for exporters that are enabled
    networking.firewall.allowedTCPPorts = lib.mkIf cfg.exporters.openFirewall [
      cfg.exporters.node.port
      cfg.exporters.systemd.port
    ];

    services.prometheus.exporters = lib.mkIf cfg.exporters.enable {
      node = lib.mkIf cfg.exporters.node.enable {
        enable = true;
        port = cfg.exporters.node.port;
        extraFlags = cfg.exporters.node.extraFlags;
      };
      systemd = lib.mkIf cfg.exporters.systemd.enable {
        enable = true;
        port = cfg.exporters.systemd.port;
      };
    };
  };
}

D roles/qutebrowser.nix => roles/qutebrowser.nix +0 -50
@@ 1,50 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.qutebrowser;
in {
  options.roles.qutebrowser = {
    enable = lib.mkEnableOption "";
  };

  config = lib.mkIf cfg.enable {
    hm.programs.qutebrowser = {
      enable = true;
      quickmarks = {
        nixpkgs = "https://github.com/nixos/nixpkgs";
        home-manager-options = "https://nix-community.github.io/home-manager/options.xhtml";
      };
      searchEngines = {
        DEFAULT = "https://www.startpage.com/sp/search?query={}";
      };
      # https://qutebrowser.org/doc/help/settings.html
      settings = {
        auto_save.session = true;
        colors.webpage.preferred_color_scheme = "light";
        content = {
          blocking = {
            enabled = true;
            method = "auto";
          };
          cookies = {
            accept = "no-3rdparty";
            store = false;
          };
          dns_prefetch = false;
          geolocation = false;
          headers = {
            do_not_track = true;
            referer = "never";
          };
        };
        downloads.remove_finished = 60000;
        url = {
          default_page = "about:blank";
          start_pages = "about:blank";
        };
      };
    };
  };
}

D roles/shell/default.nix => roles/shell/default.nix +0 -88
@@ 1,88 0,0 @@
{
  config,
  lib,
  pkgs,
  ...
}: let
  cfg = config.roles.shell;
in {
  options.roles.shell = {
    enable = lib.mkEnableOption "an opnionated shell environment";
  };

  config = lib.mkIf cfg.enable {
    environment.systemPackages = with pkgs; [
      elvish

      ripgrep
      fd

      btop

      sl

      silicon
    ];
    programs.direnv = {
      enable = true;
      nix-direnv.enable = true;
      silent = true;
    };
    hm = {
      home.file = {
        ".config/elvish/lib/direnv.elv" = {
          executable = true;
          source = ./direnv.elv;
        };
        ".config/elvish/rc.elv" = {
          executable = true;
          text = ''
            #!/usr/bin/env elvish
            use direnv
            eval (starship init elvish)
          '';
        };
      };
      programs.bash = {
        enable = true;
        bashrcExtra = ''
          eval "$(direnv hook bash)"
          eval "$(starship init bash)"
        '';
      };
      programs.starship = {
        enable = true;
        settings = {
          add_newline = false;
          scan_timeout = 10;
          /*
          format = lib.concatStrings [
            "$line_break"
            "$shell"
            "$nix_shell"
            "$directory"
            "$character"
          ];
          #format_right = lib.concatStrings [
          #
          #];
          character = {
            success_symbol = " >";
            error_symbol = " >";
          };
          directory = {
            truncation_length = 3;
            truncate_to_repo = true;
            format = "[$path](bold cyan)";
          };
          */
          shell = {
            disabled = false;
            bash_indicator = "bsh";
            elvish_indicator = "elv";
          };
        };
      };
    };
  };
}

D roles/shell/direnv.elv => roles/shell/direnv.elv +0 -18
@@ 1,18 0,0 @@
## Hook for direnv as of direnv 2.34.0
set @edit:before-readline = $@edit:before-readline {
	try {
		var m = [("direnv" export elvish | from-json)]
		if (> (count $m) 0) {
			set m = (all $m)
			keys $m | each { |k|
				if $m[$k] {
					set-env $k $m[$k]
				} else {
					unset-env $k
				}
			}
		}
	} catch e {
		echo $e
	}
}

D roles/tailscale.nix => roles/tailscale.nix +0 -34
@@ 1,34 0,0 @@
{
  config,
  lib,
  ...
}: let
  cfg = config.roles.tailscale;
in {
  options.roles.tailscale = {
    enable = lib.mkEnableOption "Tailscale";
    authKeyFile = lib.mkOption {
      type = lib.types.nullOr lib.types.path;
      default = null;
    };
    interfaceName = lib.mkOption {
      type = lib.types.str;
      default = "tailscale0";
    };
    enableSSH = lib.mkOption {
      type = lib.types.bool;
      default = false;
    };
  };

  config = lib.mkIf cfg.enable {
    services.tailscale = {
      enable = true;
      authKeyFile = lib.mkIf (cfg.authKeyFile != null) cfg.authKeyFile;
      extraUpFlags = lib.mkIf (cfg.enableSSH) ["--ssh"]; # TODO: Make modular for multiple possible flags.
      interfaceName = cfg.interfaceName;
      openFirewall = false;
      useRoutingFeatures = "none";
    };
  };
}

D roles/zellij.nix => roles/zellij.nix +0 -113
@@ 1,113 0,0 @@
{
  config,
  inputs,
  lib,
  pkgs,
  ...
}: let
  cfg = config.roles.zellij;

  # Hard light:
  # https://github.com/sainnhe/everforest/blob/master/palette.md#light
  # https://github.com/sainnhe/everforest/blob/e5b9e2fb676a9ded3e86ae51924f7962fa4fb0ac/autoload/everforest.vim#L51
  everforest = {
    bg0 = "#FFF9E8";
    bg1 = "#F8F5E4";
    bg2 = "#F2EFDF";
    bg3 = "#EDEADA";
    bg4 = "#E8E5D5";
    bg5 = "#BEC5B2";
    fg = {
      default = "#5C6A72";
      accent = {
        cyan = "#35A77C";
        green = "#8DA101";
      };
      grey0 = "#7A8478";
      grey1 = "#859289";
      grey2 = "#9DA9A0";
      statusline = {
        green = "#93B259";
        grey = "#708089";
        red = "#E66868";
      };
    };
  };

  zjstatus = ''
    plugin location="file:${inputs.zjstatus.packages.${pkgs.system}.default}/bin/zjstatus.wasm" {
      format_left "{mode}"
      format_center "{tabs}"

      mode_locked "#[fg=${everforest.bg0},bg=${everforest.fg.statusline.red},bold] {name} "
      mode_normal "#[fg=${everforest.bg0},bg=${everforest.fg.statusline.green},bold] {name} "
      mode_tab "#[fg=${everforest.bg0},bg=${everforest.fg.accent.cyan},bold] {name} "

      tab_active "#[fg=${everforest.bg0},bg=${everforest.fg.statusline.green}] {name} "
      tab_normal "#[fg=${everforest.fg.default},bg=${everforest.bg3}] {name} "
    }
  '';
in {
  options.roles.zellij = {
    enable = lib.mkEnableOption "enable zellij";
  };

  config = lib.mkIf cfg.enable {
    hm = {
      programs.zellij = {
        enable = true;
        settings = {
          default_shell = "elvish";
          simplified_ui = true;
          pane_frames = false;
          default_layout = "default";
          ui.pane_frames.hide_session_name = true;
        };
      };

      home.file.".config/zellij/layouts/default.kdl".text = ''
        layout {
          default_tab_template {
            children
            pane size=1 {
              ${zjstatus}
            }
          }

          tab {
            pane
          }
        }
      '';

      home.file.".config/zellij/layouts/dev.kdl".text = ''
        layout {
          default_tab_template {
            children
            pane size=1 {
              ${zjstatus}
            }
          }

          tab name="nvim" focus=true  {
            pane
          }

          tab name="shell" {
            pane
          }
        }

        keybinds {
          locked {
            bind "Insert" { GoToTab 2; SwitchToMode "Normal"; }
          }

          shared_except "locked" {
            bind "Insert" { GoToTab 1; SwitchToMode "Locked"; }
          }
        }
      '';
    };
  };
}

D systems/default.nix => systems/default.nix +0 -52
@@ 1,52 0,0 @@
{
  lib,
  inputs,
  ...
}: {
  flake = let
    mkHost = name: cfg:
      inputs.nixpkgs.lib.nixosSystem {
        system = cfg.system;
        specialArgs = cfg.profile.specialArgs;
        modules =
          cfg.profile.modules
          ++ cfg.modules
          ++ [
            ./hosts/${name}
            ../hosts/${name}
            {
              networking.hostName = name;
            }
          ];
      };

    mkLXCTemplatePackage = name: cfg:
      inputs.nixos-generators.nixosGenerate {
        system = cfg.system;
        specialArgs = cfg.profile.specialArgs;
        modules =
          cfg.profile.modules
          ++ cfg.modules
          ++ [
            {
              networking.hostName = name;
            }
          ];
        format = "proxmox-lxc";
      };

    profiles = import ./profiles lib inputs;
    hosts = import ./hosts profiles;

    templatePackages = {
      lxcbase = {
        system = "x86_64-linux";
        profile = profiles.lxcbase;
        modules = [];
      };
    };
  in {
    nixosConfigurations = inputs.nixpkgs.lib.mapAttrs mkHost hosts;
    packages.x86_64-linux = inputs.nixpkgs.lib.mapAttrs mkLXCTemplatePackage templatePackages;
  };
}

D systems/hosts/alice/default.nix => systems/hosts/alice/default.nix +0 -54
@@ 1,54 0,0 @@
{
  inputs,
  lib,
  pkgs,
  ...
}: {
  imports = [
    ./hardware-configuration.nix
  ];

  boot.initrd.postDeviceCommands = lib.mkAfter ''
    zfs rollback -r zpool/root@blank
  '';

  sops.defaultSopsFile = ../../../secrets/alice/secrets.yaml;
  sops.gnupg.sshKeyPaths = ["/persist/etc/ssh/ssh_host_rsa_key"];
  sops.age.sshKeyPaths = ["/persist/etc/ssh/ssh_host_ed25519_key"];

  networking.hostId = "bc56f04f";
  networking.networkmanager.enable = true;

  time.timeZone = "Europe/Helsinki";

  i18n.defaultLocale = "en_US.UTF-8";

  services.xserver.xkb.layout = "us";

  environment.systemPackages = with pkgs; [
    inputs.nvim-flake.packages.x86_64-linux.nvim
    wget

    keepassxc
    firefox
    jellyfin-mpv-shim
  ];

  environment.persistence."/persist" = {
    hideMounts = true;
    directories = [
      "/etc/nixos"
      "/etc/ssh"
      "/var/lib/nixos"
      "/var/lib/tailscale"
    ];
  };

  services.openssh.enable = true;

  services.pcscd.enable = true;
  programs.gnupg.agent.enable = true;
  programs.gnupg.agent.pinentryPackage = pkgs.pinentry-gnome3;

  system.stateVersion = "24.05";
}

D systems/hosts/default.nix => systems/hosts/default.nix +0 -13
@@ 1,13 0,0 @@
{
  desktop,
  laptop,
  lxc,
  vm,
  ...
}: {
  alice = {
    system = "x86_64-linux";
    profile = desktop;
    modules = [];
  };
}

D systems/profiles/common/fonts.nix => systems/profiles/common/fonts.nix +0 -14
@@ 1,14 0,0 @@
{pkgs, ...}: let
  fonts = with pkgs; [
    font-awesome

    liberation_ttf

    (nerdfonts.override {
      fonts = ["FiraCode" "VictorMono"];
    })
  ];
in {
  environment.systemPackages = fonts;
  fonts.packages = fonts;
}

D systems/profiles/default.nix => systems/profiles/default.nix +0 -7
@@ 1,7 0,0 @@
lib: inputs: {
  desktop = import ./desktop inputs;
  laptop = import ./laptop inputs;
  lxc = import ./lxc lib inputs;
  lxcbase = import ./lxcbase lib inputs;
  vm = import ./vm lib inputs;
}

D systems/profiles/desktop/default.nix => systems/profiles/desktop/default.nix +0 -22
@@ 1,22 0,0 @@
inputs @ {
  home-manager,
  impermanence,
  sops-nix,
  ...
}: {
  modules = [
    sops-nix.nixosModules.sops
    impermanence.nixosModules.impermanence
    home-manager.nixosModules.home-manager

    ../common/fonts.nix

    ../../../modules
    ../../../roles

    ./desktop.nix
  ];
  specialArgs = {
    inherit inputs;
  };
}

D systems/profiles/desktop/desktop.nix => systems/profiles/desktop/desktop.nix +0 -3
@@ 1,3 0,0 @@
{
  environment.variables.EDITOR = "nvim";
}

D systems/profiles/laptop/default.nix => systems/profiles/laptop/default.nix +0 -22
@@ 1,22 0,0 @@
inputs @ {
  home-manager,
  impermanence,
  sops-nix,
  ...
}: {
  modules = [
    sops-nix.nixosModules.sops
    impermanence.nixosModules.impermanence
    home-manager.nixosModules.home-manager

    ../common/fonts.nix

    ../../../modules
    ../../../roles

    ./laptop.nix
  ];
  specialArgs = {
    inherit inputs;
  };
}

D systems/profiles/laptop/laptop.nix => systems/profiles/laptop/laptop.nix +0 -4
@@ 1,4 0,0 @@
{
  environment.variables.EDITOR = "nvim";
  programs.light.enable = true;
}

D systems/profiles/lxc/default.nix => systems/profiles/lxc/default.nix +0 -26
@@ 1,26 0,0 @@
lib: inputs @ {
  home-manager,
  sops-nix,
  ...
}: {
  modules = [
    "${inputs.nixpkgs}/nixos/modules/virtualisation/proxmox-lxc.nix"
    {
      proxmoxLXC.manageNetwork = true;
      proxmoxLXC.manageHostName = true;
    }

    sops-nix.nixosModules.sops
    home-manager.nixosModules.home-manager

    ../../../modules
    ../../../roles

    ./lxc.nix
    ./roles.nix
  ];
  specialArgs = {
    inherit inputs;
    artautil = import ../../../lib/util.nix {inherit lib;};
  };
}

D systems/profiles/lxc/lxc.nix => systems/profiles/lxc/lxc.nix +0 -53
@@ 1,53 0,0 @@
{
  artautil,
  config,
  lib,
  ...
}: {
  sops.defaultSopsFile = ../../../secrets/${config.networking.hostName}/secrets.yaml;

  time.timeZone = "Europe/Helsinki";

  networking.defaultGateway = {
    address = "10.1.2.1";
    interface = "eth0";
  };
  networking.nameservers = ["10.1.2.3"];
  networking.interfaces."eth0".ipv4.addresses = [
    {
      address = artautil.getIPv4 "lxc" config.networking.hostName;
      prefixLength = 24;
    }
  ];

  nix.settings.trusted-users = ["root"];

  users.users.root = {
    openssh.authorizedKeys.keys = [
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGAlif3ABIk0YSx++A+sEeRYPNMMZWLcDuoTKhmcCL6K jonni@liljamo.com"
    ];
  };

  services.openssh = {
    enable = true;
    settings = {
      PasswordAuthentication = lib.mkForce false;
      KbdInteractiveAuthentication = lib.mkForce false;
      PermitRootLogin = lib.mkForce "prohibit-password";
    };
  };

  systemd.suppressedSystemUnits = [
    "systemd-udev-trigger.service"
    "systemd-udevd.service"
    "sys-fs-fuse-connections.mount"
    "sys-kernel-debug.mount"
    "dev-mqueue.mount"
  ];
  services = {
    journald.extraConfig = "SystemMaxUse=4G";
    cron.systemCronJobs = [
      "0 22 * * * root journalctl --vacuum-time=7d"
    ];
  };
}

D systems/profiles/lxc/roles.nix => systems/profiles/lxc/roles.nix +0 -21
@@ 1,21 0,0 @@
{
  roles.prometheus.exporters = {
    enable = true;
    openFirewall = true;
    node = {
      enable = true;
      extraFlags = [
        "--collector.disable-defaults"
        "--collector.filesystem"
        "--collector.stat"
        "--collector.time"
      ];
    };
    systemd.enable = true;
  };

  roles.cadvisor = {
    enable = true;
    openFirewall = true;
  };
}

D systems/profiles/lxcbase/default.nix => systems/profiles/lxcbase/default.nix +0 -14
@@ 1,14 0,0 @@
lib: inputs: {
  modules = [
    "${inputs.nixpkgs}/nixos/modules/virtualisation/proxmox-lxc.nix"
    {
      proxmoxLXC.manageNetwork = true;
      proxmoxLXC.manageHostName = true;
    }

    ./lxcbase.nix
  ];
  specialArgs = {
    inherit inputs;
  };
}

D systems/profiles/lxcbase/lxcbase.nix => systems/profiles/lxcbase/lxcbase.nix +0 -48
@@ 1,48 0,0 @@
{lib, ...}: {
  time.timeZone = "Europe/Helsinki";

  networking.defaultGateway = {
    address = "10.1.2.1";
    interface = "eth0";
  };
  networking.nameservers = ["10.1.2.3"];
  networking.interfaces."eth0".ipv4.addresses = [
    {
      address = "10.1.2.2";
      prefixLength = 24;
    }
  ];

  nix.settings.trusted-users = ["root"];

  users.users.root = {
    openssh.authorizedKeys.keys = [
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGAlif3ABIk0YSx++A+sEeRYPNMMZWLcDuoTKhmcCL6K jonni@liljamo.com"
    ];
  };

  services.openssh = {
    enable = true;
    settings = {
      PasswordAuthentication = lib.mkForce false;
      KbdInteractiveAuthentication = lib.mkForce false;
      PermitRootLogin = lib.mkForce "prohibit-password";
    };
  };

  systemd.suppressedSystemUnits = [
    "systemd-udev-trigger.service"
    "systemd-udevd.service"
    "sys-fs-fuse-connections.mount"
    "sys-kernel-debug.mount"
    "dev-mqueue.mount"
  ];
  services = {
    journald.extraConfig = "SystemMaxUse=4G";
    cron.systemCronJobs = [
      "0 22 * * * root journalctl --vacuum-time=7d"
    ];
  };

  system.stateVersion = "24.05";
}

D systems/profiles/vm/default.nix => systems/profiles/vm/default.nix +0 -19
@@ 1,19 0,0 @@
lib: inputs @ {
  home-manager,
  sops-nix,
  ...
}: {
  modules = [
    sops-nix.nixosModules.sops
    home-manager.nixosModules.home-manager

    ../../../modules
    ../../../roles

    ./vm.nix
  ];
  specialArgs = {
    inherit inputs;
    artautil = import ../../../lib/util.nix {inherit lib;};
  };
}

D systems/profiles/vm/vm.nix => systems/profiles/vm/vm.nix +0 -55
@@ 1,55 0,0 @@
{
  artautil,
  config,
  lib,
  ...
}: {
  sops.defaultSopsFile = ../../../secrets/${config.networking.hostName}/secrets.yaml;

  time.timeZone = "Europe/Helsinki";

  # NOTE: There should ever only be a single network interface in my VMs.
  #       If this changes, consider taking this out and figuring another way
  #       to do this, e.g. defining the main interface in the base role or something.
  networking.usePredictableInterfaceNames = false;

  /*
  networking.defaultGateway = {
    address = "10.1.1.1";
    interface = "eth0";
  };
  */
  networking.nameservers = ["10.1.2.3"];
  /*
  networking.interfaces."eth0".ipv4.addresses = [
    {
      address = artautil.getIPv4 "vm" config.networking.hostName;
      prefixLength = 24;
    }
  ];
  */

  nix.settings.trusted-users = ["root"];

  users.users.root = {
    openssh.authorizedKeys.keys = [
      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGAlif3ABIk0YSx++A+sEeRYPNMMZWLcDuoTKhmcCL6K jonni@liljamo.com"
    ];
  };

  services.openssh = {
    enable = true;
    settings = {
      PasswordAuthentication = lib.mkForce false;
      KbdInteractiveAuthentication = lib.mkForce false;
      PermitRootLogin = lib.mkForce "prohibit-password";
    };
  };

  services = {
    journald.extraConfig = "SystemMaxUse=4G";
    cron.systemCronJobs = [
      "0 22 * * * root journalctl --vacuum-time=7d"
    ];
  };
}

A ws/hosts/alice/core/default.nix => ws/hosts/alice/core/default.nix +21 -0
@@ 0,0 1,21 @@
{lib, ...}: {
  imports = [
    ./hardware-configuration.nix
    ./impermanence.nix
  ];

  boot.initrd.postDeviceCommands = lib.mkAfter ''
    zfs rollback -r zpool/root@blank
  '';

  sops.defaultSopsFile = ../../../../secrets/alice/secrets.yaml;
  sops.gnupg.sshKeyPaths = ["/persist/etc/ssh/ssh_host_rsa_key"];
  sops.age.sshKeyPaths = ["/persist/etc/ssh/ssh_host_ed25519_key"];

  networking.hostId = "bc56f04f";
  networking.networkmanager.enable = true;

  time.timeZone = "Europe/Helsinki";

  system.stateVersion = "24.05";
}

R systems/hosts/alice/hardware-configuration.nix => ws/hosts/alice/core/hardware-configuration.nix +0 -0
A ws/hosts/alice/core/impermanence.nix => ws/hosts/alice/core/impermanence.nix +12 -0
@@ 0,0 1,12 @@
{
  environment.persistence."/persist" = {
    hideMounts = true;
    directories = [
      "/etc/nixos"
      "/etc/ssh"
      "/var/lib/flatpak"
      "/var/lib/nixos"
      "/var/lib/tailscale"
    ];
  };
}

R hosts/alice/default.nix => ws/hosts/alice/default.nix +22 -6
@@ 1,12 1,34 @@
{
  config,
  inputs,
  pkgs,
  ...
}: {
  imports = [
    ./core

    ./hyprland.nix
  ];

  i18n.defaultLocale = "en_US.UTF-8";

  services.xserver.xkb.layout = "us";

  environment.systemPackages = with pkgs; [
    inputs.nvim-flake.packages.x86_64-linux.nvim
    wget

    keepassxc
    firefox
    jellyfin-mpv-shim
  ];

  services.openssh.enable = true;

  services.pcscd.enable = true;
  programs.gnupg.agent.enable = true;
  programs.gnupg.agent.pinentryPackage = pkgs.pinentry-gnome3;

  sops.secrets.rootPwd.neededForUsers = true;
  sops.secrets.skyePwd.neededForUsers = true;



@@ 19,13 41,7 @@
    startInBackground = true;
  };

  # TODO: role...
  services.flatpak.enable = true;
  environment.persistence."/persist" = {
    directories = [
      "/var/lib/flatpak"
    ];
  };

  roles.base = {
    root = {

R hosts/alice/hyprland.nix => ws/hosts/alice/hyprland.nix +0 -0