diff --git a/SwarselSystems.org b/SwarselSystems.org index 2c6a58a..24bb9f8 100644 --- a/SwarselSystems.org +++ b/SwarselSystems.org @@ -293,8 +293,6 @@ Handling the flake.nix file used to be a bit of a chore, since it felt like writ These blocks are later inserted here: [[#h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b][flake.nix template]]. Adding new flake inputs is very easy, you just add them to [[#h:8a411ee2-a58e-4b5b-99bd-4ba772f8f0a2][Inputs & Inputs@Outputs]] first by name in the first source-block, and then the path in the second source-block. Any variables to be set for the host configuration are done in [[#h:df0072bc-853f-438f-bd85-bfc869501015][let]], and the specific setup is done in either [[#h:9c9b9e3b-8771-44fa-ba9e-5056ae809655][nixosConfigurations]] (for NixOS systems), [[#h:f881aa05-a670-48dd-a57b-2916abdcb692][homeConfigurations]] (for home-manager systems), or [[#h:5f6ef553-59f9-4239-b6f3-63d33b57f335][nixOnDroidConfigurations]] (for Nix on Android) and [[#h:f881aa05-a670-48dd-a57b-2916abdcb692][darwinConfigurations]] (for Darwin systems, also known as Macs). There also used to be a [[#h:6a08495a-8566-4bb5-9fac-b03df01f6c81][nixos-generators]] section that used to define a Proxmox LXC image when I was still using Proxmox as my main server. An example of the repository at that time would be =acc0ad6: Add several NixOS hosts on Proxmox and Oracle Cloud=. - - ** flake.nix skeleton :PROPERTIES: :CUSTOM_ID: h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b @@ -308,151 +306,20 @@ In the start, I enable some public cache repositories. This saves some time duri In =outputs = inputs@ [...]=, the =inputs@= makes it so that all inputs are automatically passed to the outputs and can be called as =inputs.=, whereas explicit arguments may just be called by using ==. For most flakes this is fully sufficient, as they do not need to be called often and it saves me maintainance effort with this file. -#+begin_src nix :noweb yes :tangle flake.nix - { - description = "SwarseFlake - Nix Flake for all SwarselSystems"; +In this section I am creating some attributes that define general concepts of my configuration: - nixConfig = { - extra-substituters = [ - "https://nix-community.cachix.org" - "https://cache.ngi0.nixos.org/" - ]; - extra-trusted-public-keys = [ - "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" - "cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=" - ]; - }; - inputs = { - <> - }; - outputs = - inputs@{ self - , nixpkgs - , home-manager - , systems - , ... - }: - let - <> - in - inputs.flake-parts.lib.mkFlake { inherit inputs; } { - imports = [ - ./nix/globals.nix - ]; - flake = { config, ... }: - let - <> - - linuxUser = "swarsel"; - macUser = "leon.schwarzaeugl"; - - mkFullHost = host: type: { - ${host} = - let - systemFunc = if (type == "nixos") then lib.nixosSystem else inputs.nix-darwin.lib.darwinSystem; - in - systemFunc { - specialArgs = { inherit inputs outputs lib self; inherit (config) globals; }; - modules = [ - { - node.name = host; - node.secretsDir = ./hosts/${type}/${host}/secrets; - } - # put inports here that are for all hosts - inputs.disko.nixosModules.disko - inputs.sops-nix.nixosModules.sops - inputs.impermanence.nixosModules.impermanence - inputs.lanzaboote.nixosModules.lanzaboote - inputs.fw-fanctrl.nixosModules.default - inputs.nix-topology.nixosModules.default - inputs.home-manager.nixosModules.home-manager - "${self}/hosts/${type}/${host}" - { - _module.args.primaryUser = linuxUser; - } - ] ++ - (if (host == "iso") then [ - ] else - ([ - # put nixos imports here that are for all servers and normal hosts - "${self}/modules/nixos" - inputs.stylix.nixosModules.stylix - inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm - ] ++ (if (type == "nixos") then [ - "${self}/profiles/nixos" - { - home-manager.users."${linuxUser}".imports = [ - # put home-manager imports here that are for all normal hosts - "${self}/profiles/home" - "${self}/modules/home" - ]; - } - ] else [ - # put nixos imports here that are for darwin hosts - "${self}/modules/nixos/darwin" - "${self}/profiles/nixos" - inputs.home-manager.darwinModules.home-manager - { - home-manager.users."${macUser}".imports = [ - # put home-manager imports here that are for darwin hosts - "${self}/modules/home/darwin" - "${self}/profiles/home" - ]; - } - ]) - )); - }; - }; - - mkHalfHost = host: type: pkgs: { - ${host} = - let - systemFunc = if (type == "home") then inputs.home-manager.lib.homeManagerConfiguration else inputs.nix-on-droid.lib.nixOnDroidConfiguration; - in - systemFunc - { - inherit pkgs; - extraSpecialArgs = { inherit inputs outputs lib self; }; - modules = [ "${self}/hosts/${type}/${host}" ]; - }; - }; - - mkFullHostConfigs = hosts: type: lib.foldl (acc: set: acc // set) { } (lib.map (host: mkFullHost host type) hosts); - - mkHalfHostConfigs = hosts: type: pkgs: lib.foldl (acc: set: acc // set) { } (lib.map (host: mkHalfHost host type pkgs) hosts); - - in - { - <> - - nixosConfigurations = mkFullHostConfigs (lib.swarselsystems.readHosts "nixos") "nixos"; - homeConfigurations = mkHalfHostConfigs (lib.swarselsystems.readHosts "home") "home" lib.swarselsystems.pkgsFor.x86_64-linux; - darwinConfigurations = mkFullHostConfigs (lib.swarselsystems.readHosts "darwin") "darwin"; - nixOnDroidConfigurations = mkHalfHostConfigs (lib.swarselsystems.readHosts "android") "android" lib.swarselsystems.pkgsFor.aarch64-linux; - - topology = lib.swarselsystems.forEachSystem (pkgs: import inputs.nix-topology { - inherit pkgs; - modules = [ - "${self}/topology" - { inherit (self) nixosConfigurations; } - ]; - }); - - nodes = config.nixosConfigurations; - }; - systems = [ - "x86_64-linux" - "aarch64-linux" - "x86_64-darwin" - "aarch64-darwin" - ]; - }; - } -#+end_src -** Inputs -:PROPERTIES: -:CUSTOM_ID: h:8a411ee2-a58e-4b5b-99bd-4ba772f8f0a2 -:END: +- =nixosModules= imports self-defined options that I only want to use on NixOS systems. All modules are held as separately as possible, to allow for easier sharing with other people mostly. +- =homeModules= imports modules that are to be used on NixOS and non-NixOS systems. These are mostly used to define outputs (monitors), keyboards and special commands for machines. +- =packages= holds packages that I am building myself. These are mostly shell scripts, but also a few others such as AppImages and firefox addons. +- =devShells= provides a development shell that can be used as a bootstrap for new installs using =nix develop= while inside the flake directory. It received an overhaul in =0a6cf0e feat: add checks to devShell=, since when it is handled using =forAllSystems= and now including pre-commit-hook checks. +- =formatter= provides the formatter that is to be used on =.nix= files. It can be called by using =nix fmt=. +- =check= provides the pre-commit-hook checks that I have explained in [[#h:cbd5002c-e0fa-434a-951b-e05b179e4e3f][Pre-commit-hooks (Checks)]]. +- =overlays= imports a few community overlays (such as the emacs-overlay) and also three overlays of my own: + 1) =additions= holds derivations that I am adding myself to nixpkgs - i.e. this is where the packages defined in =/pkgs= get added to nixpkgs. + 2) =modifications= holds derivations that I have performed overrides on. The list of interesting attribute overrides can be found by looking at the source code of a derivation and looking at the start of the file for lines of the form = ? =. But this can also be used to, for example, fetch a different version of a package instead. + 3) =nixpkgs-stable= holds the newest version of stable nixpkgs. I only use this on packages that seem broken on unstable, which are not many. + 4) =zjstatus= holds some options for =zellij=, but I have stopped using it since I prefer =tmux=. + They are defined in [[#h:5e3e21e0-57af-4dad-b32f-6400af9b7aab][Overlays (additions, overrides, nixpkgs-stable)]]. The way this is handled was simplified in =647a2ae feat: simplify overlay structure=; however, the old structure might be easier to understand as a reference. Here we define inputs and outputs of the flake. First, the following list is for the outputs of the flake. @@ -508,233 +375,834 @@ When setting this option normally, the password would normally be written world- - [[https://github.com/oddlama/nix-topology][nix-topology]] This automatically creates a topology diagram of my configuration. -#+begin_src nix-ts :tangle no :noweb-ref flakeinputs - - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - nixpkgs-kernel.url = "github:NixOS/nixpkgs/063f43f2dbdef86376cc29ad646c45c46e93234c?narHash=sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o%3D"; #specifically pinned for kernel version - nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.05"; - nixpkgs-stable24_05.url = "github:NixOS/nixpkgs/nixos-24.05"; - nixpkgs-stable24_11.url = "github:NixOS/nixpkgs/nixos-24.11"; - systems.url = "github:nix-systems/default"; - home-manager = { - url = "github:nix-community/home-manager"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - emacs-overlay = { - url = "github:nix-community/emacs-overlay"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nur.url = "github:nix-community/NUR"; - nixgl.url = "github:guibou/nixGL"; - stylix.url = "github:danth/stylix"; - sops-nix.url = "github:Mic92/sops-nix"; - lanzaboote.url = "github:nix-community/lanzaboote"; - nix-on-droid = { - url = "github:nix-community/nix-on-droid/release-24.05"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nixos-generators = { - url = "github:nix-community/nixos-generators"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nixos-hardware = { - url = "github:NixOS/nixos-hardware/master"; - }; - nix-alien = { - url = "github:thiagokokada/nix-alien"; - }; - nswitch-rcm-nix = { - url = "github:Swarsel/nswitch-rcm-nix"; - }; - nix-index-database = { - url = "github:nix-community/nix-index-database"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - disko = { - url = "github:nix-community/disko"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - impermanence.url = "github:nix-community/impermanence"; - zjstatus = { - url = "github:dj95/zjstatus"; - }; - fw-fanctrl = { - url = "github:TamtamHero/fw-fanctrl/packaging/nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nix-darwin = { - url = "github:lnl7/nix-darwin"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - pre-commit-hooks = { - url = "github:cachix/git-hooks.nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nix-secrets = { - url = "git+ssh://git@github.com/Swarsel/nix-secrets.git?ref=main&shallow=1"; - flake = false; - inputs = { }; - }; - vbc-nix = { - url = "git+ssh://git@github.com/vbc-it/vbc-nix.git?ref=main"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nix-topology.url = "github:oddlama/nix-topology"; - flake-parts.url = "github:hercules-ci/flake-parts"; -#+end_src -** let -:PROPERTIES: -:CUSTOM_ID: h:df0072bc-853f-438f-bd85-bfc869501015 -:END: - -Here I define a few variables that I need for my system specifications. There used to be more here, but I managed to optimize my configuration, and only two things remain: -- =outputs=, which is needed for =lib= -- =lib=: This exposes a common =lib= for NixOS and home-manager that is extended by my own personal =lib= functions. - -#+begin_src nix-ts :tangle no :noweb-ref flakelet - - inherit (self) outputs; - lib = (nixpkgs.lib // home-manager.lib).extend (_: _: { swarselsystems = import ./lib { inherit self lib inputs outputs systems; }; }); - -#+end_src -** General (outputs) -:PROPERTIES: -:CUSTOM_ID: h:54cd8f65-a3ba-43c3-ae37-5f04383fe720 -:END: - -In this section I am creating some attributes that define general concepts of my configuration: - -- =nixosModules= imports self-defined options that I only want to use on NixOS systems. All modules are held as separately as possible, to allow for easier sharing with other people mostly. -- =homeModules= imports modules that are to be used on NixOS and non-NixOS systems. These are mostly used to define outputs (monitors), keyboards and special commands for machines. -- =packages= holds packages that I am building myself. These are mostly shell scripts, but also a few others such as AppImages and firefox addons. -- =devShells= provides a development shell that can be used as a bootstrap for new installs using =nix develop= while inside the flake directory. It received an overhaul in =0a6cf0e feat: add checks to devShell=, since when it is handled using =forAllSystems= and now including pre-commit-hook checks. -- =formatter= provides the formatter that is to be used on =.nix= files. It can be called by using =nix fmt=. -- =check= provides the pre-commit-hook checks that I have explained in [[#h:cbd5002c-e0fa-434a-951b-e05b179e4e3f][Pre-commit-hooks (Checks)]]. -- =overlays= imports a few community overlays (such as the emacs-overlay) and also three overlays of my own: - 1) =additions= holds derivations that I am adding myself to nixpkgs - i.e. this is where the packages defined in =/pkgs= get added to nixpkgs. - 2) =modifications= holds derivations that I have performed overrides on. The list of interesting attribute overrides can be found by looking at the source code of a derivation and looking at the start of the file for lines of the form = ? =. But this can also be used to, for example, fetch a different version of a package instead. - 3) =nixpkgs-stable= holds the newest version of stable nixpkgs. I only use this on packages that seem broken on unstable, which are not many. - 4) =zjstatus= holds some options for =zellij=, but I have stopped using it since I prefer =tmux=. - They are defined in [[#h:5e3e21e0-57af-4dad-b32f-6400af9b7aab][Overlays (additions, overrides, nixpkgs-stable)]]. The way this is handled was simplified in =647a2ae feat: simplify overlay structure=; however, the old structure might be easier to understand as a reference. - -#+begin_src nix-ts :tangle no :noweb-ref flakeoutputgeneral - inherit lib; - - # nixosModules = import ./modules/nixos { inherit lib; }; - # homeModules = import ./modules/home { inherit lib; }; - packages = lib.swarselsystems.forEachLinuxSystem (pkgs: import ./pkgs { inherit lib pkgs; }); - formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); - overlays = import ./overlays { inherit self lib inputs; }; - - apps = lib.swarselsystems.forAllSystems (system: - let - appNames = [ - "swarsel-bootstrap" - "swarsel-install" - "swarsel-rebuild" - "swarsel-postinstall" - ]; - appSet = lib.swarselsystems.mkApps system appNames self; - in - - appSet // { - default = appSet.swarsel-bootstrap; - } - ); - - devShells = lib.swarselsystems.forAllSystems (system: - let - pkgs = lib.swarselsystems.pkgsFor.${system}; - checks = self.checks.${system}; - in +#+begin_src nix :noweb yes :tangle flake.nix { - default = pkgs.mkShell { - # plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: { - # buildInputs = [pkgs.nixVersions.latest pkgs.boost]; - # patches = (o.patches or []) ++ [ "${self}/nix/nix-plugins.patch" ]; - # })}/lib/nix/plugins - NIX_CONFIG = '' - plugin-files = ${pkgs.nix-plugins}/lib/nix/plugins - extra-builtins-file = ${self + /nix/extra-builtins.nix} - ''; - inherit (checks.pre-commit-check) shellHook; + description = "SwarseFlake - Nix Flake for all SwarselSystems"; - buildInputs = checks.pre-commit-check.enabledPackages; - nativeBuildInputs = [ - (builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions. - # pkgs.nix - pkgs.home-manager - pkgs.git - pkgs.just - pkgs.age - pkgs.ssh-to-age - pkgs.sops - pkgs.statix - pkgs.deadnix - pkgs.nixpkgs-fmt + nixConfig = { + extra-substituters = [ + "https://nix-community.cachix.org" + "https://cache.ngi0.nixos.org/" + ]; + extra-trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=" ]; }; + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + nixpkgs-kernel.url = "github:NixOS/nixpkgs/063f43f2dbdef86376cc29ad646c45c46e93234c?narHash=sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o%3D"; #specifically pinned for kernel version + nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.05"; + nixpkgs-stable24_05.url = "github:NixOS/nixpkgs/nixos-24.05"; + nixpkgs-stable24_11.url = "github:NixOS/nixpkgs/nixos-24.11"; + systems.url = "github:nix-systems/default"; + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + emacs-overlay = { + url = "github:nix-community/emacs-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nur.url = "github:nix-community/NUR"; + nixgl.url = "github:guibou/nixGL"; + stylix.url = "github:danth/stylix"; + sops-nix.url = "github:Mic92/sops-nix"; + lanzaboote.url = "github:nix-community/lanzaboote"; + nix-on-droid = { + url = "github:nix-community/nix-on-droid/release-24.05"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nixos-generators = { + url = "github:nix-community/nixos-generators"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nixos-hardware = { + url = "github:NixOS/nixos-hardware/master"; + }; + nix-alien = { + url = "github:thiagokokada/nix-alien"; + }; + nswitch-rcm-nix = { + url = "github:Swarsel/nswitch-rcm-nix"; + }; + nix-index-database = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + disko = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + impermanence.url = "github:nix-community/impermanence"; + zjstatus = { + url = "github:dj95/zjstatus"; + }; + fw-fanctrl = { + url = "github:TamtamHero/fw-fanctrl/packaging/nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nix-darwin = { + url = "github:lnl7/nix-darwin"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + pre-commit-hooks = { + url = "github:cachix/git-hooks.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nix-secrets = { + url = "git+ssh://git@github.com/Swarsel/nix-secrets.git?ref=main&shallow=1"; + flake = false; + inputs = { }; + }; + vbc-nix = { + url = "git+ssh://git@github.com/vbc-it/vbc-nix.git?ref=main"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nix-topology.url = "github:oddlama/nix-topology"; + flake-parts.url = "github:hercules-ci/flake-parts"; + devshell = { + url = "github:numtide/devshell"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + outputs = + inputs: + inputs.flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ + ./nix/globals.nix + ./nix/hosts.nix + ./nix/topology.nix + ./nix/devshell.nix + ./nix/apps.nix + ./nix/packages.nix + ./nix/overlays.nix + ./nix/lib.nix + ./nix/templates.nix + ./nix/formatter.nix + ./nix/modules.nix + ]; + systems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + }; } - ); +#+end_src +** Auxiliary files +:PROPERTIES: +:CUSTOM_ID: h:23602ad9-91f6-4eba-943a-2308070fbaec +:END: +*** extra-builtins +:PROPERTIES: +:CUSTOM_ID: h:87c7893e-e946-4fc0-8973-1ca27d15cf0e +:END: - templates = import ./templates { inherit lib; }; +#+begin_src nix-ts :tangle nix/extra-builtins.nix + # adapted from https://github.com/oddlama/nix-config/blob/main/nix/extra-builtins.nix + { exec, ... }: + let + assertMsg = pred: msg: pred || builtins.throw msg; + hasSuffix = + suffix: content: + let + lenContent = builtins.stringLength content; + lenSuffix = builtins.stringLength suffix; + in + lenContent >= lenSuffix && builtins.substring (lenContent - lenSuffix) lenContent content == suffix; + in + { + # Instead of calling sops directly here, we call a wrapper script that will cache the output + # in a predictable path in /tmp, which allows us to only require the password for each encrypted + # file once. + sopsImportEncrypted = + nixFile: + assert assertMsg (builtins.isPath nixFile) + "The file to decrypt must be given as a path (not a string) to prevent impurity."; + assert assertMsg (hasSuffix ".nix.enc" nixFile) + "The content of the decrypted file must be a nix expression and should therefore end in .nix.enc"; + exec [ + ./sops-decrypt-and-cache.sh + nixFile + ]; + } - checks = lib.swarselsystems.forAllSystems (system: +#+end_src +*** sops-decrypt-and-cache +:PROPERTIES: +:CUSTOM_ID: h:315e6ef6-27d5-4cd8-85ff-053eabe60ddb +:END: + +#+begin_src shell :tangle nix/sops-decrypt-and-cache.sh :shebang #!/usr/bin/env bash + # adapted from https://github.com/oddlama/nix-config/blob/main/nix/rage-decrypt-and-cache.sh + set -euo pipefail + + print_out_path=false + if [[ $1 == "--print-out-path" ]]; then + print_out_path=true + shift + fi + + file="$1" + shift + + basename="${file%".enc"}" + # store path prefix or ./ if applicable + [[ $file == "/nix/store/"* ]] && basename="${basename#*"-"}" + [[ $file == "./"* ]] && basename="${basename#"./"}" + + # Calculate a unique content-based identifier (relocations of + # the source file in the nix store should not affect caching) + new_name="$(sha512sum "$file")" + new_name="${new_name:0:32}-${basename//"/"/"%"}" + + # Derive the path where the decrypted file will be stored + out="/var/tmp/nix-import-encrypted/$UID/$new_name" + umask 077 + mkdir -p "$(dirname "$out")" + + # Decrypt only if necessary + if [[ ! -e $out ]]; then + agekey=$(sudo ssh-to-age -private-key -i /etc/ssh/sops || sudo ssh-to-age -private-key -i /etc/ssh/ssh_host_ed25519_key) + SOPS_AGE_KEY="$agekey" sops decrypt --output "$out" "$file" + fi + + # Print out path or decrypted content + if [[ $print_out_path == true ]]; then + echo "$out" + else + cat "$out" + fi +#+end_src +** Library functions +:PROPERTIES: +:CUSTOM_ID: h:f9b7ffba-b7e2-4554-9a35-ece0bf173e1c +:END: + +This section defines all functions of my own that I add to =lib=. These are used in all places over the config, with many of them being used in =flake.nix=. + +A breakdown of each function: + +The interesting part is in the start: +- first, I define =pkgsFor=. This function reads all available systems from nixpkgs and generates pkgs for them. +- next, =forEachSystem= is a function that can be called to declare an output for each such defined system. +- =forAllSystems= is a crude function that I use for expressions that depend on =system=, as the prior two attributes already consumed it at that stage. This is only really used to generate the checks in their own file. +- =mkFullHostConfigs= is the function that dynamically creates all definded hosts. The hosts are defined by placing a directory in =hosts/= under either the =nixos/= or =darwin/= directory. These directories are being read by =readHosts= and delivered to this funtion in the later call in [[#h:9c9b9e3b-8771-44fa-ba9e-5056ae809655][nixosConfigurations]] or [[#h:f881aa05-a670-48dd-a57b-2916abdcb692][darwinConfigurations]]. +- =mkFullHost=: + This is a function that takes a hostname as well as a boolean whether it is NixOS or not, and returns a matching =nixosSystem= or =darwinSystem=. This function is only used for systems that can use both NixOS and home-manager options (darwin still counts here as it can use some NixOS options). This is used in mkFullHostConfigs. In more detail, it dynamically creates a nixosConfiguration host, setting its =speciaArgs= and =modules= attributes. The modules are populated based on whether this is a NixOS or darwin host. For the latter, I will only ever use machines that I get for testing from work, and for these my username is different, so I implemented an if-condition for it. This could be done more cleanly using variables, but some care needs to be taken with the home-manager imports and this approach works, so for now this is fine. Thanks to this function, the import sections of the host configs are pretty clean for most hosts. + =lib.optionals= evaluates to an empty list (=[]=) in case that the conditional is not met. + +#+begin_src nix-ts :tangle nix/lib.nix + { self, inputs, ... }: + let + swarselsystems = + let + inherit (inputs) systems; + inherit (inputs.nixpkgs) lib; + in + rec { + mkIfElseList = p: yes: no: lib.mkMerge [ + (lib.mkIf p yes) + (lib.mkIf (!p) no) + ]; + + mkIfElse = p: yes: no: if p then yes else no; + + pkgsFor = lib.genAttrs (import systems) (system: + import inputs.nixpkgs { + inherit system; + overlays = [ self.overlays.default ]; + config.allowUnfree = true; + } + ); + + toCapitalized = str: + if builtins.stringLength str == 0 then + "" + else + let + first = builtins.substring 0 1 str; + rest = builtins.substring 1 (builtins.stringLength str - 1) str; + upper = lib.toUpper first; + lower = lib.toLower rest; + in + upper + lower; + + + mkTrueOption = lib.mkOption { + type = lib.types.bool; + default = true; + }; + + mkStrong = lib.mkOverride 60; + + forEachSystem = f: lib.genAttrs (import systems) (system: f pkgsFor.${system}); + forEachLinuxSystem = f: lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system: f pkgsFor.${system}); + + readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}"); + readNix = type: lib.filter (name: name != "default.nix") (lib.attrNames (builtins.readDir "${self}/${type}")); + + + + + mkModules = names: type: builtins.listToAttrs (map + (name: { + inherit name; + value = import "${self}/modules/${type}/${name}"; + }) + names); + + mkProfiles = names: type: builtins.listToAttrs (map + (name: { + inherit name; + value = import "${self}/profiles/${type}/${name}"; + }) + names); + + + mkImports = names: baseDir: lib.map (name: "${self}/${baseDir}/${name}") names; + + eachMonitor = _: monitor: { + inherit (monitor) name; + value = builtins.removeAttrs monitor [ "workspace" "name" "output" ]; + }; + + eachOutput = _: monitor: { + inherit (monitor) name; + value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ]; + }; + }; + in + { + flake = _: + { + lib = (inputs.nixpkgs.lib // inputs.home-manager.lib).extend (_: _: { + inherit swarselsystems; + }); + }; + } +#+end_src +** Packages (pkgs) +:PROPERTIES: +:CUSTOM_ID: h:6ed1a641-dba8-4e85-a62e-be93264df57a +:END: + +This does not use =perSystem= since some of my custom packages are not able to be built on darwin systems, and I was not yet interested in writing logic for handling that. + +#+begin_src nix-ts :tangle nix/packages.nix +{ self, ... }: +{ + flake = _: let - pkgs = lib.swarselsystems.pkgsFor.${system}; + inherit (self.outputs) lib; in - import ./checks { inherit self inputs system pkgs; } - ); + { + packages = lib.swarselsystems.forEachLinuxSystem (pkgs: import "${self}/pkgs" { inherit self lib pkgs; }); + }; +} +#+end_src +** Globals +:PROPERTIES: +:CUSTOM_ID: h:af83893d-c0f9-4b45-b816-4849110d41b3 +:END: + +The structure of =globals.nix.enc= requires a toplevel =globals=. + +#+begin_src nix-ts :tangle nix/globals.nix + # adapted from https://github.com/oddlama/nix-config/blob/main/nix/globals.nix + { inputs, ... }: + { + flake = { config, lib, ... }: + { + globals = + let + globalsSystem = lib.evalModules { + prefix = [ "globals" ]; + specialArgs = { + inherit lib; + inherit inputs; + inherit (config) nodes; + }; + modules = [ + ../modules/nixos/common/globals.nix + ( + { lib, ... }: + let + # Try to access the extra builtin we loaded via nix-plugins. + # Throw an error if that doesn't exist. + sopsImportEncrypted = + assert lib.assertMsg (builtins ? extraBuiltins.sopsImportEncrypted) + "The extra builtin 'sopsImportEncrypted' is not available, so repo.secrets cannot be decrypted. Did you forget to add nix-plugins and point it to `./nix/extra-builtins.nix` ?"; + builtins.extraBuiltins.sopsImportEncrypted; + in + + { + imports = [ + (sopsImportEncrypted ../secrets/repo/globals.nix.enc) + ]; + + } + ) + ( + { lib, ... }: + { + globals = lib.mkMerge ( + lib.concatLists ( + lib.flip lib.mapAttrsToList config.nodes ( + name: cfg: + builtins.addErrorContext "while aggregating globals from nixosConfigurations.${name} into flake-level globals:" cfg.config._globalsDefs + ) + ) + ); + } + ) + ]; + }; + in + { + # Make sure the keys of this attrset are trivially evaluatable to avoid infinite recursion, + # therefore we inherit relevant attributes from the config. + inherit (globalsSystem.config.globals) + domains + services + user + ; + }; + }; + } - diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix; #+end_src -** Pre-commit-hooks (Checks) +** Hosts :PROPERTIES: -:CUSTOM_ID: h:cbd5002c-e0fa-434a-951b-e05b179e4e3f +:CUSTOM_ID: h:5c5bf78a-9a66-436f-bd85-85871d9d402b +:END: + +#+begin_src nix-ts :tangle nix/hosts.nix + { self, inputs, ... }: + { + flake = { config, ... }: + let + inherit (self) outputs; + inherit (outputs) lib; + # lib = (inputs.nixpkgs.lib // inputs.home-manager.lib).extend (_: _: { swarselsystems = import "${self}/lib" { inherit self lib inputs outputs; inherit (inputs) systems; }; }); + + mkNixosHost = { minimal }: name: + lib.nixosSystem { + specialArgs = { inherit inputs outputs lib self minimal; inherit (config) globals nodes; }; + modules = [ + inputs.disko.nixosModules.disko + inputs.sops-nix.nixosModules.sops + inputs.impermanence.nixosModules.impermanence + inputs.lanzaboote.nixosModules.lanzaboote + inputs.nix-topology.nixosModules.default + inputs.home-manager.nixosModules.home-manager + "${self}/hosts/nixos/${name}" + "${self}/profiles/nixos" + "${self}/modules/nixos" + { + node.name = name; + node.secretsDir = ../hosts/nixos/${name}/secrets; + } + ]; + }; + + mkDarwinHost = { minimal }: name: + inputs.nix-darwin.lib.darwinSystem { + specialArgs = { inherit inputs outputs lib self minimal; inherit (config) globals nodes; }; + modules = [ + # inputs.disko.nixosModules.disko + # inputs.sops-nix.nixosModules.sops + # inputs.impermanence.nixosModules.impermanence + # inputs.lanzaboote.nixosModules.lanzaboote + # inputs.fw-fanctrl.nixosModules.default + # inputs.nix-topology.nixosModules.default + inputs.home-manager.darwinModules.home-manager + "${self}/hosts/darwin/${name}" + "${self}/modules/nixos/darwin" + # needed for infrastructure + "${self}/modules/nixos/common/meta.nix" + "${self}/modules/nixos/common/globals.nix" + { + node.name = name; + node.secretsDir = ../hosts/darwin/${name}/secrets; + } + ]; + }; + + mkHalfHost = name: type: pkgs: { + ${name} = + let + systemFunc = if (type == "home") then inputs.home-manager.lib.homeManagerConfiguration else inputs.nix-on-droid.lib.nixOnDroidConfiguration; + in + systemFunc + { + inherit pkgs; + extraSpecialArgs = { inherit inputs outputs lib self; }; + modules = [ "${self}/hosts/${type}/${name}" ]; + }; + }; + + mkHalfHostConfigs = hosts: type: pkgs: lib.foldl (acc: set: acc // set) { } (lib.map (name: mkHalfHost name type pkgs) hosts); + nixosHosts = builtins.attrNames (lib.filterAttrs (_: type: type == "directory") (builtins.readDir "${self}/hosts/nixos")); + darwinHosts = builtins.attrNames (lib.filterAttrs (_: type: type == "directory") (builtins.readDir "${self}/hosts/darwin")); + in + { + nixosConfigurations = lib.genAttrs nixosHosts (mkNixosHost { + minimal = false; + }); + nixosConfigurationsMinimal = lib.genAttrs nixosHosts (mkNixosHost { + minimal = true; + }); + darwinConfigurations = lib.genAttrs darwinHosts (mkDarwinHost { + minimal = false; + }); + darwinConfigurationsMinimal = lib.genAttrs darwinHosts (mkDarwinHost { + minimal = true; + }); + + # TODO: Build these for all architectures + homeConfigurations = mkHalfHostConfigs (lib.swarselsystems.readHosts "home") "home" lib.swarselsystems.pkgsFor.x86_64-linux; + nixOnDroidConfigurations = mkHalfHostConfigs (lib.swarselsystems.readHosts "android") "android" lib.swarselsystems.pkgsFor.aarch64-linux; + + diskoConfigurations.default = import "${self}/templates/hosts/nixos/disk-config.nix"; + + nodes = config.nixosConfigurations // config.darwinConfigurations; + + }; + } +#+end_src + +** Topology +:PROPERTIES: +:CUSTOM_ID: h:391e7712-fef3-4f13-a3ed-d36e228166fd +:END: + +#+begin_src nix-ts :tangle nix/topology.nix + { self, inputs, ... }: + { + imports = [ + inputs.nix-topology.flakeModule + ]; + + perSystem.topology.modules = [ + ({ config, ... }: + let + inherit (config.lib.topology) + mkInternet + mkDevice + mkSwitch + mkRouter + mkConnection + ; + in + { + renderer = "elk"; + + networks = { + home-lan = { + name = "Home LAN"; + cidrv4 = "192.168.1.0/24"; + }; + wg = { + name = "Wireguard Tunnel"; + cidrv4 = "192.168.3.0/24"; + }; + }; + + nodes = { + internet = mkInternet { + connections = [ + (mkConnection "moonside" "wan") + (mkConnection "pfsense" "wan") + (mkConnection "sync" "wan") + (mkConnection "toto" "bootstrapper") + (mkConnection "chaostheatre" "demo host") + ]; + }; + + chaostheatre.interfaces."demo host" = { }; + toto.interfaces."bootstrapper" = { }; + sync.interfaces.wan = { }; + moonside.interfaces.wan = { }; + + pfsense = mkRouter "pfSense" { + info = "HUNSN RM02"; + image = "${self}/topology-images/hunsn.png"; + interfaceGroups = [ + [ + "eth2" + "eth3" + "eth4" + "eth5" + "eth6" + ] + [ "wan" ] + ]; + interfaces.wg = { + addresses = [ "192.168.3.1" ]; + network = "wg"; + virtual = true; + type = "wireguard"; + }; + + connections = { + eth2 = mkConnection "switch-livingroom" "eth1"; + eth4 = mkConnection "winters" "eth1"; + eth3 = mkConnection "switch-bedroom" "eth1"; + eth6 = mkConnection "wifi-ap" "eth1"; + wg = mkConnection "moonside" "wg"; + }; + interfaces = { + eth2 = { + addresses = [ "192.168.1.1" ]; + network = "home-lan"; + }; + eth3 = { + addresses = [ "192.168.1.1" ]; + network = "home-lan"; + }; + eth4 = { + addresses = [ "192.168.1.1" ]; + network = "home-lan"; + }; + eth6 = { + addresses = [ "192.168.1.1" ]; + network = "home-lan"; + }; + }; + }; + + winters.interfaces."eth1" = { }; + + wifi-ap = mkSwitch "Wi-Fi AP" { + info = "Huawei"; + image = "${self}/topology-images/huawei.png"; + interfaceGroups = [ + [ + "eth1" + "wifi" + ] + ]; + }; + + switch-livingroom = mkSwitch "Switch Livingroom" { + info = "TL-SG108"; + image = "${self}/topology-images/TL-SG108.png"; + interfaceGroups = [ + [ + "eth1" + "eth2" + "eth3" + "eth4" + "eth5" + "eth6" + "eth7" + "eth8" + ] + ]; + connections = { + eth2 = mkConnection "nswitch" "eth1"; + eth7 = mkConnection "pc" "eth1"; + eth8 = mkConnection "nbl-imba-2" "eth1"; + }; + }; + + nswitch = mkDevice "Nintendo Switch" { + info = "Nintendo Switch"; + image = "${self}/topology-images/nintendo-switch.png"; + interfaces.eth1 = { }; + }; + + pc = mkDevice "Windows Gaming Server" { + info = "i7-4790k, GTX970, 32GB RAM"; + image = "${self}/topology-images/pc.png"; + interfaces.eth1 = { }; + }; + + nbl-imba-2.interfaces.eth1 = { }; + + switch-bedroom = mkSwitch "Switch Bedroom" { + info = "TL-SG1005D"; + image = "${self}/topology-images/TL-SG1005D.png"; + interfaceGroups = [ + [ + "eth1" + "eth2" + "eth3" + "eth4" + "eth5" + ] + ]; + connections.eth2 = mkConnection "printer" "eth1"; + }; + + printer = mkDevice "Printer" { + info = "DELL C2665dnf"; + image = "${self}/topology-images/DELL-C2665dnf.png"; + interfaces.eth1 = { }; + }; + + }; + + }) + + + ]; + } + +#+end_src + +** Devshell (checks) +:PROPERTIES: +:CUSTOM_ID: h:4d0548db-99b2-4e07-b762-6d86fbb26d4c :END: This file defines a number of checks that can either be run by calling =nix flake check= or while in a =nix-shell= or =nix develop=. This helps me make sure that my flake confirms to my self-imposed standards. The GitHub actions perform less checks than are being done here (they are only checking the formatting, as well as =statix= and =deadnix=) -#+begin_src nix-ts :tangle checks/default.nix - { self, inputs, pkgs, system, ... }: +#+begin_src nix-ts :tangle nix/devshell.nix + { self, inputs, ... }: { - pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run { - src = "${self}"; - hooks = { - check-added-large-files.enable = true; - check-case-conflicts.enable = true; - check-executables-have-shebangs.enable = true; - check-shebang-scripts-are-executable.enable = false; - check-merge-conflicts.enable = true; - deadnix.enable = true; - detect-private-keys.enable = true; - end-of-file-fixer.enable = true; - fix-byte-order-marker.enable = true; - flake-checker.enable = true; - forbid-new-submodules.enable = true; - mixed-line-endings.enable = true; - nixpkgs-fmt.enable = true; - statix.enable = true; - trim-trailing-whitespace.enable = true; + imports = [ + inputs.devshell.flakeModule + inputs.pre-commit-hooks.flakeModule + ]; - destroyed-symlinks = { - enable = true; - entry = "${inputs.pre-commit-hooks.checks.${system}.pre-commit-hooks}/bin/destroyed-symlinks"; + perSystem = { pkgs, system, ... }: + { + pre-commit = { + check.enable = true; + settings = { + addGcRoot = true; + hooks = { + check-added-large-files.enable = true; + check-case-conflicts.enable = true; + check-executables-have-shebangs.enable = true; + check-shebang-scripts-are-executable.enable = false; + check-merge-conflicts.enable = true; + deadnix.enable = true; + detect-private-keys.enable = true; + end-of-file-fixer.enable = true; + fix-byte-order-marker.enable = true; + flake-checker.enable = true; + forbid-new-submodules.enable = true; + mixed-line-endings.enable = true; + nixpkgs-fmt.enable = true; + statix.enable = true; + trim-trailing-whitespace.enable = true; + + destroyed-symlinks = { + enable = true; + entry = "${inputs.pre-commit-hooks.checks.${system}.pre-commit-hooks}/bin/destroyed-symlinks"; + }; + + shellcheck = { + enable = true; + entry = "${pkgs.shellcheck}/bin/shellcheck --shell=bash"; + }; + + shfmt = { + enable = true; + entry = "${pkgs.shfmt}/bin/shfmt -i 4 -sr -d -s -l"; + }; + }; + }; }; - shellcheck = { - enable = true; - entry = "${pkgs.shellcheck}/bin/shellcheck --shell=bash"; - }; + devshells.default = { + packages = [ + (builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions. + pkgs.git + pkgs.just + pkgs.age + pkgs.ssh-to-age + pkgs.sops + pkgs.home-manager + pkgs.nixpkgs-fmt + self.packages.${system}.swarsel-build + self.packages.${system}.swarsel-deploy + ]; - shfmt = { - enable = true; - entry = "${pkgs.shfmt}/bin/shfmt -i 4 -sr -d -s -l"; - }; + commands = [ + { + package = pkgs.statix; + help = "Lint flake"; + } + { + package = pkgs.deadnix; + help = "Check flake for dead code"; + } + { + package = pkgs.nix-tree; + help = "Interactively browse dependency graphs of Nix derivations"; + } + { + package = pkgs.nvd; + help = "Diff two nix toplevels and show which packages were upgraded"; + } + { + package = pkgs.nix-diff; + help = "Explain why two Nix derivations differ"; + } + { + package = pkgs.nix-output-monitor; + help = "Nix Output Monitor (a drop-in alternative for `nix` which shows a build graph)"; + name = "nom"; + } + { + name = "hm"; + help = "Manage home-manager config"; + command = "home-manager"; + } + { + name = "fmt"; + help = "Format flake"; + command = "nixpkgs-fmt --check \"$FLAKE\""; + } + { + name = "sd"; + help = "Build and deploy this nix config to nodes"; + command = "swarsel-deploy \"$@\""; + } + { + name = "sl"; + help = "Build and deploy a config to nodes"; + command = "swarsel-deploy \${1} switch"; + } + { + name = "sw"; + help = "Build and switch to the host's config locally"; + command = "swarsel-deploy $(hostname) switch"; + } + { + name = "bld"; + help = "Build a number of configurations"; + command = "swarel-build \"$@\""; + } + { + name = "c"; + help = "Work with the flake git repository"; + command = "git --git-dir=$FLAKE/.git --work-tree=$FLAKE/ \"$@\""; + } + ]; + devshell.startup.pre-commit-install.text = "pre-commit install"; + + env = [ + { + # Additionally configure nix-plugins with our extra builtins file. + # We need this for our repo secrets. + name = "NIX_CONFIG"; + value = '' + plugin-files = ${pkgs.nix-plugins}/lib/nix/plugins + extra-builtins-file = ${self + /nix/extra-builtins.nix} + ''; + } + ]; + }; }; - }; } #+end_src @@ -746,39 +1214,221 @@ This file defines a number of checks that can either be run by calling =nix flak This file defines the templates that are being exposed by the flake. These can be used by running =nix flake init -t github:Swarsel/.dotfiles#=. -#+begin_src nix-ts :tangle templates/default.nix - { lib, ... }: - let - templateNames = [ - "python" - "rust" - "go" - "cpp" - "latex" - "default" - ]; - in - lib.swarselsystems.mkTemplates templateNames +#+begin_src nix-ts :tangle nix/templates.nix + { self, ... }: + { + flake = _: { + templates = + let + mkTemplates = names: builtins.listToAttrs (map + (name: { + inherit name; + value = { + path = "${self}/templates/${name}"; + description = "${name} project "; + }; + }) + names); + templateNames = [ + "python" + "rust" + "go" + "cpp" + "latex" + "default" + ]; + in + mkTemplates templateNames; + }; + } #+end_src - - -** Hosts - -#+begin_src nix-ts :tangle no -#+end_src - -** topologyConfigurations +** Formatter :PROPERTIES: -:CUSTOM_ID: h:1337e267-bca3-4c65-863f-9f44b753dee4 +:CUSTOM_ID: h:5fce36ae-715d-42d3-9ad4-46137d85083f :END: -#+begin_src nix-ts :tangle no :noweb-ref topologyconf - +#+begin_src nix-ts :tangle nix/formatter.nix + _: + { + perSystem = { pkgs, ... }: { + formatter = pkgs.nixpkgs-fmt; + }; + } #+end_src +** Modules +:PROPERTIES: +:CUSTOM_ID: h:e8eb0617-3441-421d-9b44-716ed40159ab +:END: + +#+begin_src nix-ts :tangle nix/modules.nix + { self, ... }: + { + flake = _: + let + inherit (self.outputs) lib; + in + { + nixosModules.default = import "${self}/modules/nixos" { inherit lib; }; + homeModules = import "${self}/modules/home" { inherit lib; }; + }; + } + +#+end_src +** Apps +:PROPERTIES: +:CUSTOM_ID: h:52e1fae8-0e8c-4be6-a6ce-758ada652dd3 +:END: + +This file defines a number of checks that can either be run by calling =nix flake check= or while in a =nix-shell= or =nix develop=. This helps me make sure that my flake confirms to my self-imposed standards. The GitHub actions perform less checks than are being done here (they are only checking the formatting, as well as =statix= and =deadnix=) + +#+begin_src nix-ts :tangle nix/apps.nix + { self, ... }: + { + perSystem = { system, ... }: + let + mkApps = system: names: self: builtins.listToAttrs (map + (name: { + inherit name; + value = { + type = "app"; + program = "${self.packages.${system}.${name}}/bin/${name}"; + meta = { + description = "Custom app ${name}."; + }; + }; + }) + names); + + appNames = [ + "swarsel-bootstrap" + "swarsel-install" + "swarsel-rebuild" + "swarsel-postinstall" + ]; + + appSet = mkApps system appNames self; + in + { + apps = appSet // { + default = appSet.swarsel-bootstrap; + }; + }; + } +#+end_src +** Overlays +:PROPERTIES: +:CUSTOM_ID: h:7a059bd9-13f8-4005-b270-b41eeb6a4af2 +:END: + +In this section I define packages that I manually want to nixpkgs. This can be useful for packages that are currently awaiting a PR or public packages that I do not want to maintain. + +As such, I also define three additional overlays: + +1) =additions= + These are for the aforementioned added packages +2) =modification= + These are for packages that are on nixpkgs, but do not fit my usecase, meaning I need to perform modifications on them. +3) =nixpkgs-stable= + This is simply a mirror of the most recent stable branch of nixpkgs. Useful for packages that are broken on nixpkgs, but do not need to be on bleeding edge anyways. + +Also, this is where I define all of my own modules. These are mostly used for setting some host-specifics directly than opposed to through multiple options. + +Lastly, I add some of my own library functions to be used alongside the functions provided by =nixpkgs= and =home-manager=. + +#+begin_src nix-ts :tangle nix/overlays.nix + { self, inputs, ... }: + let + inherit (self) outputs; + inherit (outputs) lib; + in + { + flake = { config, ... }: + { + overlays = { + default = final: prev: + let + additions = final: _: import "${self}/pkgs" { pkgs = final; inherit self lib; }; + + modifications = final: prev: { + vesktop = prev.vesktop.override { + withSystemVencord = true; + }; + + firefox = prev.firefox.override { + nativeMessagingHosts = [ + prev.tridactyl-native + prev.browserpass + prev.plasma5Packages.plasma-browser-integration + ]; + }; + + mgba = final.swarsel-mgba; + + retroarch = prev.retroarch.withCores (cores: with cores; [ + snes9x # snes + nestopia # nes + dosbox # dos + scummvm # scumm + vba-m # gb/a + mgba # gb/a + melonds # ds + dolphin # gc/wii + ]); + }; + + nixpkgs-stable = final: _: { + stable = import inputs.nixpkgs-stable { + inherit (final) system; + config.allowUnfree = true; + }; + }; + + nixpkgs-kernel = final: _: { + kernel = import inputs.nixpkgs-kernel { + inherit (final) system; + config.allowUnfree = true; + }; + }; + + nixpkgs-stable24_05 = final: _: { + stable24_05 = import inputs.nixpkgs-stable24_05 { + inherit (final) system; + config.allowUnfree = true; + }; + }; + + nixpkgs-stable24_11 = final: _: { + stable24_11 = import inputs.nixpkgs-stable24_11 { + inherit (final) system; + config.allowUnfree = true; + }; + }; + + zjstatus = _: prev: { + zjstatus = inputs.zjstatus.packages.${prev.system}.default; + }; + + in + (additions final prev) + // (modifications final prev) + // (nixpkgs-stable final prev) + // (nixpkgs-kernel final prev) + // (nixpkgs-stable24_05 final prev) + // (nixpkgs-stable24_11 final prev) + // (zjstatus final prev) + // (inputs.vbc-nix.overlays.default final prev) + // (inputs.nur.overlays.default final prev) + // (inputs.emacs-overlay.overlay final prev) + // (inputs.nix-topology.overlays.default final prev) + // (inputs.nixgl.overlay final prev); + }; + }; + } +#+end_src * System :PROPERTIES: :CUSTOM_ID: h:02cd20be-1ffa-4904-9d5a-da5a89ba1421 @@ -807,12 +1457,13 @@ This is the template that I use for new deployments of personal machines. Server :END: #+begin_src nix-ts :tangle templates/hosts/nixos/default.nix - { self, inputs, pkgs, lib, primaryUser, ... }: + { self, inputs, pkgs, lib, globals, ... }: let modulesPath = "${self}/modules"; sharedOptions = { isBtrfs = true; }; + primaryUser = globals.user.name; in { @@ -1018,8 +1669,9 @@ My work machine. Built for more security, this is the gold standard of my config :CUSTOM_ID: h:567c0055-f5f7-4e53-8f13-d767d7166e9d :END: #+begin_src nix-ts :tangle hosts/nixos/nbl-imba-2/default.nix - { self, config, inputs, lib, primaryUser, ... }: + { self, config, inputs, lib, globals, ... }: let + primaryUser = globals.user.name; sharedOptions = { isBtrfs = true; isLinux = true; @@ -1273,8 +1925,9 @@ This is my main server that I run at home. It handles most tasks that require bi :CUSTOM_ID: h:8ad68406-4a75-45ba-97ad-4c310b921124 :END: #+begin_src nix-ts :tangle hosts/nixos/winters/default.nix - { lib, config, primaryUser, ... }: + { lib, config, globals, ... }: let + primaryUser = globals.user.name; sharedOptions = { isBtrfs = false; isLinux = true; @@ -1382,7 +2035,7 @@ This is my main server that I run at home. It handles most tasks that require bi A Mac notebook that I have received from work. I use this machine for getting accustomed to the Apple ecosystem as well as as a sandbox for nix-darwin configurations. #+begin_src nix-ts :tangle hosts/darwin/nbm-imba-166/default.nix - { lib, ... }: + { lib, config, ... }: let inherit (config.repo.secrets.local) workUser; in @@ -1493,8 +2146,9 @@ This machine mainly acts as an external sync helper. It manages the following th :END: #+begin_src nix-ts :tangle hosts/nixos/sync/default.nix - { lib, config, primaryUser, ... }: + { lib, config, globals, ... }: let + primaryUser = globals.user.name; sharedOptions = { isBtrfs = false; isLinux = true; @@ -1725,8 +2379,9 @@ This machine mainly acts as an external sync helper. It manages the following th :END: #+begin_src nix-ts :tangle hosts/nixos/moonside/default.nix - { lib, config, primaryUser, ... }: + { lib, config, globals, ... }: let + primaryUser = globals.user.name; inherit (config.repo.secrets.common) workHostName; inherit (config.repo.secrets.local.syncthing) dev1 dev2 dev3 loc1; serviceDomain = config.repo.secrets.common.services.domains.syncthing3; @@ -2129,7 +2784,7 @@ This is a slim setup for developing base configuration. I do not track the hardw :CUSTOM_ID: h:4e53b40b-98b2-4615-b1b0-3696a75edd6e :END: #+begin_src nix-ts :tangle hosts/nixos/toto/default.nix - { self, inputs, pkgs, lib, primaryUser, ... }: + { self, inputs, pkgs, lib, ... }: let modulesPath = "${self}/modules"; sharedOptions = { @@ -2152,7 +2807,7 @@ This is a slim setup for developing base configuration. I do not track the hardw inputs.home-manager.nixosModules.home-manager { - home-manager.users."${primaryUser}".imports = [ + home-manager.users."setup".imports = [ inputs.sops-nix.homeManagerModules.sops "${modulesPath}/home/common/sharedsetup.nix" "${self}/profiles/home" @@ -2201,7 +2856,7 @@ This is a slim setup for developing base configuration. I do not track the hardw } sharedOptions; - home-manager.users."${primaryUser}" = { + home-manager.users."setup" = { home.stateVersion = lib.mkForce "23.05"; swarselsystems = lib.recursiveUpdate { @@ -2377,8 +3032,8 @@ Also, an initial bash history is provided to allow for a very quick local deploy #+end_src -#+begin_src nix-ts :tangle hosts/nixos/iso/default.nix - { self, pkgs, inputs, config, lib, modulesPath, primaryUser ? "swarsel", ... }: +#+begin_src nix-ts :tangle nix/iso.nix + { self, pkgs, inputs, config, lib, modulesPath, ... }: let pubKeys = lib.filesystem.listFilesRecursive "${self}/secrets/keys/ssh"; in @@ -2398,30 +3053,18 @@ Also, an initial bash history is provided to allow for a very quick local deploy inputs.home-manager.nixosModules.home-manager { - home-manager.users."${primaryUser}".imports = [ + home-manager.users."setup".imports = [ "${self}/modules/home/common/settings.nix" "${self}/modules/home/common/sharedsetup.nix" ]; } ]; - options.node = { - name = lib.mkOption { - description = "Node Name."; - type = lib.types.str; - }; - secretsDir = lib.mkOption { - description = "Path to the secrets directory for this node."; - type = lib.types.path; - default = ./.; - }; - }; config = { - node.name = lib.mkForce "drugstore"; swarselsystems = { info = "~SwarselSystems~ installer ISO"; }; - home-manager.users."${primaryUser}" = { + home-manager.users."setup" = { home = { stateVersion = "23.05"; file = { @@ -2458,15 +3101,15 @@ Also, an initial bash history is provided to allow for a very quick local deploy config.allowUnfree = true; }; - services.getty.autologinUser = lib.mkForce primaryUser; + services.getty.autologinUser = lib.mkForce "setup"; users = { allowNoPasswordLogin = true; groups.swarsel = { }; users = { - swarsel = { - name = primaryUser; - group = primaryUser; + setup = { + name = "setup"; + group = "setup"; isNormalUser = true; password = "setup"; # this is overwritten after install openssh.authorizedKeys.keys = lib.lists.forEach pubKeys (key: builtins.readFile key); @@ -2474,7 +3117,7 @@ Also, an initial bash history is provided to allow for a very quick local deploy }; root = { # password = lib.mkForce config.users.users.swarsel.password; # this is overwritten after install - openssh.authorizedKeys.keys = config.users.users."${primaryUser}".openssh.authorizedKeys.keys; + openssh.authorizedKeys.keys = config.users.users."setup".openssh.authorizedKeys.keys; }; }; }; @@ -2490,10 +3133,10 @@ Also, an initial bash history is provided to allow for a very quick local deploy system.activationScripts.cache = { text = '' - mkdir -p -m=0777 /home/${primaryUser}/.local/state/nix/profiles - mkdir -p -m=0777 /home/${primaryUser}/.local/state/home-manager/gcroots - mkdir -p -m=0777 /home/${primaryUser}/.local/share/nix/ - printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /home/${primaryUser}/.local/share/nix/trusted-settings.json > /dev/null + mkdir -p -m=0777 /home/setup/.local/state/nix/profiles + mkdir -p -m=0777 /home/setup/.local/state/home-manager/gcroots + mkdir -p -m=0777 /home/setup/.local/share/nix/ + printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /home/setup/.local/share/nix/trusted-settings.json > /dev/null mkdir -p /root/.local/share/nix/ printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /root/.local/share/nix/trusted-settings.json > /dev/null ''; @@ -2528,15 +3171,14 @@ Also, an initial bash history is provided to allow for a very quick local deploy This is the "reference implementation" of a setup that runs without NixOS, only relying on home-manager. I try to test this every now and then and keep it supported. However, manual steps are needed to get the system to work fully, depending on what distribution you are running on. #+begin_src nix-ts :tangle hosts/home/default/default.nix - { self, outputs, config, ... }: + { self, inputs, outputs, ... }: { imports = [ inputs.stylix.homeManagerModules.stylix inputs.sops-nix.homeManagerModules.sops inputs.nix-index-database.hmModules.nix-index - ./modules/home/common - "${self}/modules/home/common/sharedsetup.nix" + "${self}/modules/home" ]; nixpkgs = { @@ -2584,9 +3226,11 @@ I also set the =WLR_RENDERER_ALLOW_SOFTWARE=1= to allow this configuration to ru :END: #+begin_src nix-ts :tangle hosts/nixos/chaostheatre/default.nix - { self, inputs, config, pkgs, lib, primaryUser, ... }: + { self, inputs, config, pkgs, lib, ... }: let + mainUser = "demo"; sharedOptions = { + inherit mainUser; isBtrfs = false; isLinux = true; isPublic = true; @@ -2606,7 +3250,7 @@ I also set the =WLR_RENDERER_ALLOW_SOFTWARE=1= to allow this configuration to ru "${self}/hosts/nixos/chaostheatre/options.nix" inputs.home-manager.nixosModules.home-manager { - home-manager.users."${primaryUser}".imports = [ + home-manager.users."${mainUser}".imports = [ "${self}/modules/home/common/settings.nix" "${self}/hosts/nixos/chaostheatre/options-home.nix" "${self}/modules/home/common/sharedsetup.nix" @@ -2645,7 +3289,7 @@ I also set the =WLR_RENDERER_ALLOW_SOFTWARE=1= to allow this configuration to ru } sharedOptions; - home-manager.users."${primaryUser}" = { + home-manager.users.${mainUser} = { home.stateVersion = lib.mkForce "23.05"; swarselsystems = lib.recursiveUpdate { @@ -2816,3108 +3460,6 @@ in #+end_src -** Additions and modifications -:PROPERTIES: -:CUSTOM_ID: h:ab272ab4-3c93-48b1-8f1e-f710aa9aae5d -:END: - -In this section I define packages that I manually want to nixpkgs. This can be useful for packages that are currently awaiting a PR or public packages that I do not want to maintain. - -As such, I also define three additional overlays: - -1) =additions= - These are for the aforementioned added packages -2) =modification= - These are for packages that are on nixpkgs, but do not fit my usecase, meaning I need to perform modifications on them. -3) =nixpkgs-stable= - This is simply a mirror of the most recent stable branch of nixpkgs. Useful for packages that are broken on nixpkgs, but do not need to be on bleeding edge anyways. - -Also, this is where I define all of my own modules. These are mostly used for setting some host-specifics directly than opposed to through multiple options. - -Lastly, I add some of my own library functions to be used alongside the functions provided by =nixpkgs= and =home-manager=. - -*** Packages -:PROPERTIES: -:CUSTOM_ID: h:64a5cc16-6b16-4802-b421-c67ccef853e1 -:END: - -This is the central station for self-defined packages. These are all referenced in =default.nix=. Wherever possible, I am keeping the shell version of these scripts in this file as well and then read it using =builtin.readFile= in the NixOS configurations. This lets me keep full control in this one file but also keep the separate files uncluttered. - -Note: The structure of generating the packages was changed in commit =2cf03a3 refactor: package and module generation=. That commit can be checked out in order to see a simpler version of achieving the same thing. - -#+begin_src nix-ts :tangle pkgs/default.nix - { lib, pkgs, ... }: - let - packageNames = lib.swarselsystems.readNix "pkgs"; - in - lib.swarselsystems.mkPackages packageNames pkgs - - -#+end_src - -**** pass-fuzzel -:PROPERTIES: -:CUSTOM_ID: h:4fce458d-7c9c-4bcd-bd90-76b745fe5ce3 -:END: - -This app allows me, in conjunction with my Yubikey, to quickly enter passwords when the need arises. Normal and TOTP passwords are supported, and they can either be printed directly or copied to the clipboard. - -#+begin_src shell :tangle scripts/pass-fuzzel.sh :mkdirp yes - # Adapted from https://code.kulupu.party/thesuess/home-manager/src/branch/main/modules/river.nix - shopt -s nullglob globstar - - otp=0 - typeit=0 - while :; do - case ${1:-} in - -t | --type) - typeit=1 - ;; - -o | --otp) - otp=1 - ;; - ,*) break ;; - esac - shift - done - - export PASSWORD_STORE_DIR=~/.local/share/password-store - prefix=${PASSWORD_STORE_DIR-~/.local/share/password-store} - if [[ $otp -eq 0 ]]; then - password_files=("$prefix"/**/*.gpg) - else - password_files=("$prefix"/otp/**/*.gpg) - fi - password_files=("${password_files[@]#"$prefix"/}") - password_files=("${password_files[@]%.gpg}") - - password=$(printf '%s\n' "${password_files[@]}" | fuzzel --dmenu "$@") - - [[ -n $password ]] || exit - if [[ $otp -eq 0 ]]; then - if [[ $typeit -eq 0 ]]; then - pass show -c "$password" &> /tmp/pass-fuzzel - else - pass show "$password" | { - IFS= read -r pass - printf %s "$pass" - } | wtype - - fi - else - if [[ $typeit -eq 0 ]]; then - pass otp -c "$password" &> /tmp/pass-fuzzel - else - pass otp "$password" | { - IFS= read -r pass - printf %s "$pass" - } | wtype - - fi - fi - notify-send -u critical -a pass -t 1000 "Copied/Typed Password" -#+end_src - -#+begin_src nix-ts :tangle pkgs/pass-fuzzel/default.nix - { self, name, writeShellApplication, libnotify, pass, fuzzel, wtype }: - writeShellApplication { - inherit name; - runtimeInputs = [ libnotify (pass.withExtensions (exts: [ exts.pass-otp ])) fuzzel wtype ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } - -#+end_src - -**** cura5 -:PROPERTIES: -:CUSTOM_ID: h:799579f3-ddd3-4f76-928a-a8c665980476 -:END: - -The version of =cura= used to be quite outdated in nixpkgs. I am fetching a newer AppImage here and use that instead. - - -#+begin_src nix-ts :tangle pkgs/cura5/default.nix - # taken from https://github.com/NixOS/nixpkgs/issues/186570#issuecomment-1627797219 - { appimageTools, fetchurl, writeScriptBin, pkgs, ... }: - - - let - cura5 = appimageTools.wrapType2 rec { - pname = "cura5"; - version = "5.9.0"; - src = fetchurl { - url = "https://github.com/Ultimaker/Cura/releases/download/${version}/UltiMaker-Cura-${version}-linux-X64.AppImage"; - hash = "sha256-STtVeM4Zs+PVSRO3cI0LxnjRDhOxSlttZF+2RIXnAp4="; - }; - extraPkgs = pkgs: with pkgs; [ ]; - }; - in - writeScriptBin "cura" '' - #! ${pkgs.bash}/bin/bash - # AppImage version of Cura loses current working directory and treats all paths relative to $HOME. - # So we convert each of the files passed as argument to an absolute path. - # This fixes use cases like `cd /path/to/my/files; cura mymodel.stl anothermodel.stl`. - args=() - for a in "$@"; do - if [ -e "$a" ]; then - a="$(realpath "$a")" - fi - args+=("$a") - done - exec "${cura5}/bin/cura5" "''${args[@]}" - '' - -#+end_src - -**** hm-specialisation -:PROPERTIES: -:CUSTOM_ID: h:e6612cff-0804-47ef-9f2b-d2cc6d81a896 -:END: - -This script allows for quick git home-manager specialisation switching. - - -#+begin_src nix-ts :tangle pkgs/hm-specialisation/default.nix - { name, writeShellApplication, fzf, findutils, home-manager, ... }: - - writeShellApplication { - inherit name; - runtimeInputs = [ fzf findutils home-manager ]; - text = '' - genpath=$(home-manager generations | head -1 | awk '{print $7}') - dirs=$(find "$genpath/specialisation" -type l 2>/dev/null; [ -d "$genpath" ] && echo "$genpath") - "$(echo "$dirs" | fzf --prompt="Choose home-manager specialisation to activate")"/activate - ''; - } - - -#+end_src - -**** cdw -:PROPERTIES: -:CUSTOM_ID: h:73b14c7a-5444-4fed-b7ac-d65542cdeda3 -:END: - -This script allows for quick git worktree switching. - - -#+begin_src nix-ts :tangle pkgs/cdw/default.nix - { name, writeShellApplication, fzf, ... }: - - writeShellApplication { - inherit name; - runtimeInputs = [ fzf ]; - text = '' - cd "$(git worktree list | fzf | awk '{print $1}')" - ''; - } - - -#+end_src - -**** cdb -:PROPERTIES: -:CUSTOM_ID: h:5ad99997-e54c-4f0b-9ab7-15f76b1e16e1 -:END: - -This script allows for quick git branch switching. - -#+begin_src nix-ts :tangle pkgs/cdb/default.nix - { name, writeShellApplication, fzf, ... }: - - writeShellApplication { - inherit name; - runtimeInputs = [ fzf ]; - text = '' - git checkout "$(git branch --list | grep -v "^\*" | fzf | awk '{print $1}')" - ''; - } - -#+end_src - -**** bak -:PROPERTIES: -:CUSTOM_ID: h:03b1b77b-3ca8-4a8f-8e28-9f29004d96d3 -:END: - -This script lets me quickly backup files by appending =.bak= to the filename. - - -#+begin_src nix-ts :tangle pkgs/bak/default.nix - { name, writeShellApplication, ... }: - - writeShellApplication { - inherit name; - text = '' - cp -r "$1"{,.bak} - ''; - } - - -#+end_src - -**** timer -:PROPERTIES: -:CUSTOM_ID: h:3c72d263-411c-44f0-90ff-55f14d4d9d49 -:END: - -This app starts a configuratble timer and uses TTS to say something once the timer runs out. - - -#+begin_src nix-ts :tangle pkgs/timer/default.nix - { name, writeShellApplication, speechd, ... }: - - writeShellApplication { - inherit name; - runtimeInputs = [ speechd ]; - text = '' - sleep "$1"; while true; do spd-say "$2"; sleep 0.5; done; - ''; - } - -#+end_src - -**** e -:PROPERTIES: -:CUSTOM_ID: h:1834df06-9238-4efa-9af6-851dafe66c68 -:END: - -This is a shorthand for calling emacsclient mostly. Also, it hides the kittyterm scratchpad window that I sometimes use for calling a command quickly, in case it is on the screen. After emacs closes, the kittyterm window is then shown again if it was visible earlier. - -#+begin_src shell :tangle scripts/e.sh - wait=0 - while :; do - case ${1:-} in - -w | --wait) - wait=1 - ;; - ,*) break ;; - esac - shift - done - - STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep kittyterm || true) - if [ "$STR" == "" ]; then - swaymsg '[title="kittyterm"]' scratchpad show - emacsclient -c -a "" "$@" - swaymsg '[title="kittyterm"]' scratchpad show - else - if [[ $wait -eq 0 ]]; then - emacsclient -n -c -a "" "$@" - else - emacsclient -c -a "" "$@" - fi - fi -#+end_src - -#+begin_src nix-ts :tangle pkgs/e/default.nix - { self, name, writeShellApplication, emacs30-pgtk, sway, jq }: - writeShellApplication { - inherit name; - runtimeInputs = [ emacs30-pgtk sway jq ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } - -#+end_src - -**** command-not-found -:PROPERTIES: -:CUSTOM_ID: h:10268005-a9cd-4a00-967c-cbe975c552fa -:END: - -The normal =command-not-found.sh= uses the outdated =nix-shell= commands as suggestions. This version supplies me with the more modern =nixpkgs#= version. - - -#+begin_src shell :tangle scripts/command-not-found.sh - # Adapted from https://github.com/bennofs/nix-index/blob/master/command-not-found.sh - command_not_found_handle() { - if [ -n "${MC_SID-}" ] || ! [ -t 1 ]; then - >&2 echo "$1: command not found" - return 127 - fi - - echo -n "searching nix-index..." - ATTRS=$(@nix-locate@ --minimal --no-group --type x --type s --top-level --whole-name --at-root "/bin/$1") - - case $(echo -n "$ATTRS" | grep -c "^") in - 0) - >&2 echo -ne "$(@tput@ el1)\r" - >&2 echo "$1: command not found" - ;; - ,*) - >&2 echo -ne "$(@tput@ el1)\r" - >&2 echo "The program ‘$(@tput@ setaf 4)$1$(@tput@ sgr0)’ is currently not installed." - >&2 echo "It is provided by the following derivation(s):" - while read -r ATTR; do - ATTR=${ATTR%.out} - >&2 echo " $(@tput@ setaf 12)nixpkgs#$(@tput@ setaf 4)$ATTR$(@tput@ sgr0)" - done <<< "$ATTRS" - ;; - esac - - return 127 - } - - command_not_found_handler() { - command_not_found_handle "$@" - return $? - } -#+end_src - -**** swarselcheck -:PROPERTIES: -:CUSTOM_ID: h:82f4f414-749b-4d5a-aaaa-6e3ec15fbc3d -:END: - -This app checks for different apps that I keep around in the scratchpad for quick viewing and hiding (messengers and music players mostly) and then behaves like the kittyterm hider that I described in [[#h:1834df06-9238-4efa-9af6-851dafe66c68][e]]. - -#+begin_src shell :tangle scripts/swarselcheck.sh - kitty=0 - element=0 - vesktop=0 - spotifyplayer=0 - while :; do - case ${1:-} in - -k | --kitty) - kitty=1 - ;; - -e | --element) - element=1 - ;; - -d | --vesktop) - vesktop=1 - ;; - -s | --spotifyplayer) - spotifyplayer=1 - ;; - ,*) break ;; - esac - shift - done - - if [[ $kitty -eq 1 ]]; then - STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep kittyterm || true) - CHECK=$(swaymsg -t get_tree | grep kittyterm || true) - if [ "$CHECK" == "" ]; then - exec kitty -T kittyterm -o confirm_os_window_close=0 zellij attach --create kittyterm & - sleep 1 - fi - if [ "$STR" == "" ]; then - exec swaymsg '[title="kittyterm"]' scratchpad show - else - exec swaymsg '[title="kittyterm"]' scratchpad show - fi - elif [[ $element -eq 1 ]]; then - STR=$(swaymsg -t get_tree | grep Element || true) - if [ "$STR" == "" ]; then - exec element-desktop - else - exec swaymsg '[app_id=Element]' kill - fi - elif [[ $vesktop -eq 1 ]]; then - STR=$(swaymsg -t get_tree | grep vesktop || true) - if [ "$STR" == "" ]; then - exec vesktop - else - exec swaymsg '[app_id=vesktop]' kill - fi - elif [[ $spotifyplayer -eq 1 ]]; then - STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep spotifytui || true) - CHECK=$(swaymsg -t get_tree | grep spotifytui || true) - if [ "$CHECK" == "" ]; then - exec kitty -T spotifytui -o confirm_os_window_close=0 spotify_player & - sleep 1 - fi - if [ "$STR" == "" ]; then - exec swaymsg '[title="spotifytui"]' scratchpad show - else - exec swaymsg '[title="spotifytui"]' scratchpad show - fi - fi -#+end_src - -#+begin_src nix-ts :tangle pkgs/swarselcheck/default.nix - { self, name, writeShellApplication, kitty, element-desktop, vesktop, spotify-player, jq }: - writeShellApplication { - inherit name; - runtimeInputs = [ kitty element-desktop vesktop spotify-player jq ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } - -#+end_src - -**** swarselzellij -:PROPERTIES: -:CUSTOM_ID: h:564c102c-e335-4f17-a613-c5a436bb4864 -:END: - -#+begin_src shell :tangle scripts/swarselzellij.sh - KITTIES=$(($(pgrep -P 1 kitty | wc -l) - 1)) - - if ((KITTIES < 1)); then - exec kitty -o confirm_os_window_close=0 zellij attach --create main - else - exec kitty -o confirm_os_window_close=0 zellij attach --create "temp $KITTIES" - fi -#+end_src - -#+begin_src nix-ts :tangle pkgs/swarselzellij/default.nix - { self, name, writeShellApplication, kitty }: - writeShellApplication { - inherit name; - runtimeInputs = [ kitty ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } - -#+end_src - -**** waybarupdate -:PROPERTIES: -:CUSTOM_ID: h:f93f66f9-6b8b-478e-b139-b2f382c1f25e -:END: - -This scripts checks if there are uncommited changes in either my dotfile repo, my university repo, or my passfile repo. In that case a warning will be shown in waybar. - -#+begin_src shell :tangle scripts/waybarupdate.sh - CFG=$(git --git-dir="$HOME"/.dotfiles/.git --work-tree="$HOME"/.dotfiles/ status -s | wc -l) - CSE=$(git --git-dir="$DOCUMENT_DIR_PRIV"/CSE_TUWIEN/.git --work-tree="$DOCUMENT_DIR_PRIV"/CSE_TUWIEN/ status -s | wc -l) - PASS=$(($(git --git-dir="$HOME"/.local/share/password-store/.git --work-tree="$HOME"/.local/share/password-store/ status -s | wc -l) + $(git --git-dir="$HOME"/.local/share/password-store/.git --work-tree="$HOME"/.local/share/password-store/ diff origin/main..HEAD | wc -l))) - - if [[ $CFG != 0 ]]; then - CFG_STR='CONFIG' - else - CFG_STR='' - fi - - if [[ $CSE != 0 ]]; then - CSE_STR=' CSE' - else - CSE_STR='' - fi - - if [[ $PASS != 0 ]]; then - PASS_STR=' PASS' - else - PASS_STR='' - fi - - OUT="$CFG_STR""$CSE_STR""$PASS_STR" - echo "$OUT" -#+end_src - -#+begin_src nix-ts :tangle pkgs/waybarupdate/default.nix - { self, name, writeShellApplication, git }: - writeShellApplication { - inherit name; - runtimeInputs = [ git ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } - -#+end_src - -**** opacitytoggle -:PROPERTIES: -:CUSTOM_ID: h:a1d94db2-837a-40c4-bbd8-81ce847440ee -:END: - -This app quickly toggles between 5% and 0% transparency. - -#+begin_src shell :tangle scripts/opacitytoggle.sh - if swaymsg opacity plus 0.01 -q; then - swaymsg opacity 1 - else - swaymsg opacity 0.95 - fi -#+end_src - -#+begin_src nix-ts :tangle pkgs/opacitytoggle/default.nix - { self, name, writeShellApplication, sway }: - writeShellApplication { - inherit name; - runtimeInputs = [ sway ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } -#+end_src - -**** fs-diff -:PROPERTIES: -:CUSTOM_ID: h:7c4e41b3-8c1e-4f71-87a6-30d40baed6a0 -:END: - -This utility is used to compare the current state of the root directory with the blanket state that is stored in /root-blank (the snapshot that is restored on each reboot of an impermanence machine). Using this, I can find files that I will lose once I reboot - if there are important files in that list, I can then easily add them to the persist options. - -#+begin_src shell :tangle scripts/fs-diff.sh - set -euo pipefail - - OLD_TRANSID=$(sudo btrfs subvolume find-new /mnt/root-blank 9999999) - OLD_TRANSID=${OLD_TRANSID#transid marker was } - - sudo btrfs subvolume find-new "/mnt/root" "$OLD_TRANSID" | - sed '$d' | - cut -f17- -d' ' | - sort | - uniq | - while read -r path; do - path="/$path" - if [ -L "$path" ]; then - : # The path is a symbolic link, so is probably handled by NixOS already - elif [ -d "$path" ]; then - : # The path is a directory, ignore - else - echo "$path" - fi - done -#+end_src - -#+begin_src nix-ts :tangle pkgs/fs-diff/default.nix - { self, name, writeShellApplication }: - writeShellApplication { - inherit name; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } -#+end_src - -**** github-notifications -:PROPERTIES: -:CUSTOM_ID: h:a9398c4e-4d3b-4942-b03c-192f9c0517e5 -:END: - -This utility checks if there are updated packages in nixpkgs-unstable. It does so by fully building the most recent configuration, which I do not love, but it has its merits once I am willing to switch to the newer version. - - -#+begin_src nix-ts :tangle pkgs/github-notifications/default.nix - { name, writeShellApplication, jq, ... }: - - writeShellApplication { - inherit name; - runtimeInputs = [ jq ]; - text = '' - count=$(curl -u Swarsel:"$(cat "$XDG_RUNTIME_DIR/secrets/github_notif")" https://api.github.com/notifications | jq '. | length') - - if [[ "$count" != "0" ]]; then - echo "{\"text\":\"$count\"}" - fi - ''; - } -#+end_src - -**** fullscreen -:PROPERTIES: -:CUSTOM_ID: h:9d49531a-1d9b-4600-b200-18befb5e0f3a -:END: - -This application moves the wl-mirror app to the T workspace and makes it fullscreen there. - -#+begin_src nix-ts :tangle pkgs/fullscreen/default.nix - { name, writeShellApplication, sway, ... }: - - writeShellApplication { - inherit name; - runtimeInputs = [ sway ]; - text = '' - swaymsg '[app_id=at.yrlf.wl_mirror] move to workspace 14:T' - swaymsg '[app_id=at.yrlf.wl_mirror] fullscreen' - ''; - } -#+end_src -**** screenshare -:PROPERTIES: -:CUSTOM_ID: h:960e539c-2a5a-4e21-b3d4-bcdfc8be8fda -:END: - - -#+begin_src shell :tangle scripts/screenshare.sh - - headless="false" - while [[ $# -gt 0 ]]; do - case "$1" in - -h) - headless="true" - ;; - ,*) - echo "Invalid option detected." - ;; - esac - shift - done - - SHARESCREEN="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$(hostname)".config.home-manager.users."$(whoami)".swarselsystems.sharescreen)" - - if [[ $headless == "true" ]]; then - wl-mirror "$SHARESCREEN" - else - wl-mirror "$SHARESCREEN" & - sleep 0.1 - swaymsg '[app_id=at.yrlf.wl_mirror] move to workspace 14:T' - swaymsg '[app_id=at.yrlf.wl_mirror] fullscreen' - fi -#+end_src - - -#+begin_src nix-ts :tangle pkgs/screenshare/default.nix - { self, name, writeShellApplication, sway }: - writeShellApplication { - inherit name; - runtimeInputs = [ sway ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } -#+end_src - -**** swarsel-bootstrap -:PROPERTIES: -:CUSTOM_ID: h:74db57ae-0bb9-4257-84be-eddbc85130dd -:END: - -This program sets up a new NixOS host remotely. It also takes care of secret management on the new host. - -#+begin_src shell :tangle scripts/swarsel-bootstrap.sh - # highly inspired by https://github.com/EmergentMind/nix-config/blob/dev/scripts/bootstrap-nixos.sh - set -eo pipefail - - target_hostname="" - target_destination="" - target_user="swarsel" - ssh_port="22" - persist_dir="" - disk_encryption=0 - temp=$(mktemp -d) - - function help_and_exit() { - echo - echo "Remotely installs SwarselSystem on a target machine including secret deployment." - echo - echo "USAGE: $0 -n -d [OPTIONS]" - echo - echo "ARGS:" - echo " -n specify target_hostname of the target host to deploy the nixos config on." - echo " -d specify ip or url to the target host." - echo " target during install process." - echo - echo "OPTIONS:" - echo " -u specify target_user with sudo access. nix-config will be cloned to their home." - echo " Default='${target_user}'." - echo " --port specify the ssh port to use for remote access. Default=${ssh_port}." - echo " --debug Enable debug mode." - echo " -h | --help Print this help." - exit 0 - } - - function cleanup() { - rm -rf "$temp" - } - trap cleanup exit - - function red() { - echo -e "\x1B[31m[!] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[31m[!] $($2) \x1B[0m" - fi - } - function green() { - echo -e "\x1B[32m[+] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[32m[+] $($2) \x1B[0m" - fi - } - function yellow() { - echo -e "\x1B[33m[*] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[33m[*] $($2) \x1B[0m" - fi - } - - function yes_or_no() { - echo -en "\x1B[32m[+] $* [y/n] (default: y): \x1B[0m" - while true; do - read -rp "" yn - yn=${yn:-y} - case $yn in - [Yy]*) return 0 ;; - [Nn]*) return 1 ;; - esac - done - } - - function update_sops_file() { - key_name=$1 - key_type=$2 - key=$3 - - if [ ! "$key_type" == "hosts" ] && [ ! "$key_type" == "users" ]; then - red "Invalid key type passed to update_sops_file. Must be either 'hosts' or 'users'." - exit 1 - fi - cd "${git_root}" - - SOPS_FILE=".sops.yaml" - sed -i "{ - # Remove any * and & entries for this host - /[*&]$key_name/ d; - # Inject a new age: entry - # n matches the first line following age: and p prints it, then we transform it while reusing the spacing - /age:/{n; p; s/\(.*- \*\).*/\1$key_name/}; - # Inject a new hosts or user: entry - /&$key_type/{n; p; s/\(.*- &\).*/\1$key_name $key/} - }" $SOPS_FILE - green "Updating .sops.yaml" - cd - - } - - while [[ $# -gt 0 ]]; do - case "$1" in - -n) - shift - target_hostname=$1 - ;; - -d) - shift - target_destination=$1 - ;; - -u) - shift - target_user=$1 - ;; - --port) - shift - ssh_port=$1 - ;; - --debug) - set -x - ;; - -h | --help) help_and_exit ;; - ,*) - echo "Invalid option detected." - help_and_exit - ;; - esac - shift - done - - green "~SwarselSystems~ remote installer" - green "Reading system information for $target_hostname ..." - - DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)" - green "Root Disk: $DISK" - - CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)" - if [[ $CRYPTED == "true" ]]; then - green "Encryption: ✓" - disk_encryption=1 - else - red "Encryption: X" - disk_encryption=0 - fi - - IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)" - if [[ $IMPERMANENCE == "true" ]]; then - green "Impermanence: ✓" - persist_dir="/persist" - else - red "Impermanence: X" - persist_dir="" - fi - - SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" - if [[ $SWAP == "true" ]]; then - green "Swap: ✓" - else - red "Swap: X" - fi - - SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSecureBoot)" - if [[ $SECUREBOOT == "true" ]]; then - green "Secure Boot: ✓" - else - red "Secure Boot: X" - fi - - ssh_cmd="ssh -oport=${ssh_port} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t $target_user@$target_destination" - # ssh_root_cmd=$(echo "$ssh_cmd" | sed "s|${target_user}@|root@|") # uses @ in the sed switch to avoid it triggering on the $ssh_key value - ssh_root_cmd=${ssh_cmd/${target_user}@/root@} - scp_cmd="scp -oport=${ssh_port} -o StrictHostKeyChecking=no" - - if [[ -z ${FLAKE} ]]; then - FLAKE=/home/"$target_user"/.dotfiles - fi - if [ ! -d "$FLAKE" ]; then - cd /home/"$target_user" - yellow "Flake directory not found - cloning repository from GitHub" - git clone git@github.com:Swarsel/.dotfiles.git || (yellow "Could not clone repository via SSH - defaulting to HTTPS" && git clone https://github.com/Swarsel/.dotfiles.git) - FLAKE=/home/"$target_user"/.dotfiles - fi - - cd "$FLAKE" - git_root=$(git rev-parse --show-toplevel) - # ------------------------ - green "Wiping known_hosts of $target_destination" - sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts - # ------------------------ - green "Preparing a new ssh_host_ed25519_key pair for $target_hostname." - # Create the directory where sshd expects to find the host keys - install -d -m755 "$temp/$persist_dir/etc/ssh" - # Generate host ssh key pair without a passphrase - ssh-keygen -t ed25519 -f "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" -C root@"$target_hostname" -N "" - # Set the correct permissions so sshd will accept the key - chmod 600 "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" - echo "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" - # This will fail if we already know the host, but that's fine - ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true - # ------------------------ - # when using luks, disko expects a passphrase on /tmp/disko-password, so we set it for now and will update the passphrase later - # via the config - if [ "$disk_encryption" -eq 1 ]; then - while true; do - green "Set disk encryption passphrase:" - read -rs luks_passphrase - green "Please confirm passphrase:" - read -rs luks_passphrase_confirm - if [[ $luks_passphrase == "$luks_passphrase_confirm" ]]; then - $ssh_root_cmd "/bin/sh -c 'echo $luks_passphrase > /tmp/disko-password'" - break - else - red "Passwords do not match" - fi - done - fi - # ------------------------ - green "Generating hardware-config.nix for $target_hostname and adding it to the nix-config." - $ssh_root_cmd "nixos-generate-config --force --no-filesystems --root /mnt" - - green "Injecting initialSetup" - $ssh_root_cmd "sed -i '/ boot.extraModulePackages /a \ swarselsystems.initialSetup = true;' /mnt/etc/nixos/hardware-configuration.nix" - - mkdir -p "$FLAKE"/hosts/nixos/"$target_hostname" - $scp_cmd root@"$target_destination":/mnt/etc/nixos/hardware-configuration.nix "${git_root}"/hosts/nixos/"$target_hostname"/hardware-configuration.nix - # ------------------------ - - green "Deploying minimal NixOS installation on $target_destination" - SHELL=/bin/sh nix run github:nix-community/nixos-anywhere -- --ssh-port "$ssh_port" --extra-files "$temp" --flake .#"$target_hostname" root@"$target_destination" - - echo "Updating ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" - ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true - # ------------------------ - - while true; do - read -rp "Press Enter to continue once the remote host has finished booting." - if nc -z "$target_destination" "${ssh_port}" 2> /dev/null; then - green "$target_destination is booted. Continuing..." - break - else - yellow "$target_destination is not yet ready." - fi - done - - # ------------------------ - - if [[ $SECUREBOOT == "true" ]]; then - green "Setting up secure boot keys" - $ssh_root_cmd "mkdir -p /var/lib/sbctl" - read -ra scp_call <<< "${scp_cmd}" - sudo "${scp_call[@]}" -r /var/lib/sbctl root@"$target_destination":/var/lib/ - $ssh_root_cmd "sbctl enroll-keys --ignore-immutable --microsoft || true" - fi - # ------------------------ - green "Disabling initialSetup" - sed -i '/swarselsystems\.initialSetup = true;/d' "$git_root"/hosts/nixos/"$target_hostname"/hardware-configuration.nix - - if [ -n "$persist_dir" ]; then - $ssh_root_cmd "cp /etc/machine-id $persist_dir/etc/machine-id || true" - $ssh_root_cmd "cp -R /etc/ssh/ $persist_dir/etc/ssh/ || true" - fi - # ------------------------ - green "Generating an age key based on the new ssh_host_ed25519_key." - target_key=$( - ssh-keyscan -p "$ssh_port" -t ssh-ed25519 "$target_destination" 2>&1 | - grep ssh-ed25519 | - cut -f2- -d" " || - ( - red "Failed to get ssh key. Host down?" - exit 1 - ) - ) - host_age_key=$(nix shell nixpkgs#ssh-to-age.out -c sh -c "echo $target_key | ssh-to-age") - - if grep -qv '^age1' <<< "$host_age_key"; then - red "The result from generated age key does not match the expected format." - yellow "Result: $host_age_key" - yellow "Expected format: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - exit 1 - else - echo "$host_age_key" - fi - - green "Updating nix-secrets/.sops.yaml" - update_sops_file "$target_hostname" "hosts" "$host_age_key" - yellow ".sops.yaml has been updated. There may be superfluous entries, you might need to edit manually." - if yes_or_no "Do you want to manually edit .sops.yaml now?"; then - vim "${git_root}"/.sops.yaml - fi - green "Updating all secrets files to reflect updates .sops.yaml" - sops updatekeys --yes --enable-local-keyservice "${git_root}"/secrets/*/secrets.yaml - # -------------------------- - green "Making ssh_host_ed25519_key available to home-manager for user $target_user" - sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts - $scp_cmd root@"$target_destination":/etc/ssh/ssh_host_ed25519_key root@"$target_destination":/home/"$target_user"/.ssh/ssh_host_ed25519_key - $ssh_root_cmd "mkdir -p /home/$target_user/.ssh; chown $target_user:users /home/$target_user/.ssh/ssh_host_ed25519_key" - # __________________________ - - if yes_or_no "Add ssh host fingerprints for git upstream repositories? (This is needed for building the full config)"; then - green "Adding ssh host fingerprints for git{lab,hub}" - $ssh_cmd "mkdir -p /home/$target_user/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com swagit.swarsel.win >> /home/$target_user/.ssh/known_hosts" - $ssh_root_cmd "mkdir -p /root/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com swagit.swarsel.win >> /root/.ssh/known_hosts" - fi - # -------------------------- - - if yes_or_no "Do you want to copy your full nix-config and nix-secrets to $target_hostname?"; then - green "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" - ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true - green "Copying full nix-config to $target_hostname" - cd "${git_root}" - just sync "$target_user" "$target_destination" - - if [ -n "$persist_dir" ]; then - $ssh_root_cmd "cp -r /home/$target_user/.dotfiles $persist_dir/.dotfiles || true" - $ssh_root_cmd "cp -r /home/$target_user/.ssh $persist_dir/.ssh || true" - fi - - if yes_or_no "Do you want to rebuild immediately?"; then - green "Rebuilding nix-config on $target_hostname" - yellow "Reminder: The password is 'setup'" - $ssh_root_cmd "mkdir -p /root/.local/share/nix/; printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' > /root/.local/share/nix/trusted-settings.json" - $ssh_cmd -oForwardAgent=yes "cd .dotfiles && sudo nixos-rebuild --show-trace --flake .#$target_hostname switch" - fi - else - echo - green "NixOS was successfully installed!" - echo "Post-install config build instructions:" - echo "To copy nix-config from this machine to the $target_hostname, run the following command from ~/nix-config" - echo "just sync $target_user $target_destination" - echo "To rebuild, sign into $target_hostname and run the following command from ~/nix-config" - echo "cd nix-config" - # see above FIXME:(bootstrap) - echo "sudo nixos-rebuild --show-trace --flake .#$target_hostname switch" - # echo "just rebuild" - echo - fi - - if yes_or_no "You can now commit and push the nix-config, which includes the hardware-configuration.nix for $target_hostname?"; then - cd "${git_root}" - deadnix hosts/nixos/"$target_hostname"/hardware-configuration.nix -qe - nixpkgs-fmt hosts/nixos/"$target_hostname"/hardware-configuration.nix - (pre-commit run --all-files 2> /dev/null || true) && - git add "$git_root/hosts/nixos/$target_hostname/hardware-configuration.nix" && - git add "$git_root/.sops.yaml" && - git add "$git_root/secrets" && - (git commit -m "feat: deployed $target_hostname" || true) && git push - fi -#+end_src - - -#+begin_src nix-ts :tangle pkgs/swarsel-bootstrap/default.nix - { self, name, writeShellApplication, openssh }: - writeShellApplication { - inherit name; - runtimeInputs = [ openssh ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } -#+end_src - -**** swarsel-rebuild -:PROPERTIES: -:CUSTOM_ID: h:1eabdc59-8832-44ca-a22b-11f848ab150a -:END: - -#+begin_src shell :tangle scripts/swarsel-rebuild.sh - set -eo pipefail - - target_config="chaostheatre" - target_user="swarsel" - - function help_and_exit() { - echo - echo "Builds SwarselSystem configuration." - echo - echo "USAGE: $0 [OPTIONS]" - echo - echo "ARGS:" - echo " -n specify nixos config to build." - echo " Default: chaostheatre" - echo " -u specify user to deploy for." - echo " Default: swarsel" - echo " -h | --help Print this help." - exit 0 - } - - function red() { - echo -e "\x1B[31m[!] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[31m[!] $($2) \x1B[0m" - fi - } - function green() { - echo -e "\x1B[32m[+] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[32m[+] $($2) \x1B[0m" - fi - } - function yellow() { - echo -e "\x1B[33m[*] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[33m[*] $($2) \x1B[0m" - fi - } - - while [[ $# -gt 0 ]]; do - case "$1" in - -n) - shift - target_config=$1 - ;; - -u) - shift - target_user=$1 - ;; - -h | --help) help_and_exit ;; - ,*) - echo "Invalid option detected." - help_and_exit - ;; - esac - shift - done - - cd /home/"$target_user" - - if [ ! -d /home/"$target_user"/.dotfiles ]; then - green "Cloning repository from GitHub" - git clone https://github.com/Swarsel/.dotfiles.git - else - red "A .dotfiles repository is in the way. Please (re-)move the repository and try again." - exit 1 - fi - - local_keys=$(ssh-add -L || true) - pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/keys/ssh/yubikey.pub) - read -ra pub_arr <<< "$pub_key" - - cd .dotfiles - if [[ $local_keys != *"${pub_arr[1]}"* ]]; then - yellow "The ssh key for this configuration is not available." - green "Adjusting flake.nix so that the configuration is buildable" - sed -i '/nix-secrets = {/,/^[[:space:]]*};/d' flake.nix - sed -i '/vbc-nix = {/,/^[[:space:]]*};/d' flake.nix - sed -i '/[[:space:]]*\/\/ (inputs.vbc-nix.overlays.default final prev)/d' overlays/default.nix - rm modules/home/common/env.nix - rm modules/home/common/gammastep.nix - rm modules/home/common/git.nix - rm modules/home/common/mail.nix - rm modules/home/common/yubikey.nix - rm modules/nixos/server/restic.nix - rm hosts/nixos/sync/default.nix - rm -rf modules/nixos/server - rm -rf modules/home/server - nix flake update vbc-nix - git add . - else - green "Valid SSH key found! Continuing with installation" - fi - sudo nixos-generate-config --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/ - git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/hardware-configuration.nix - - green "Installing flake $target_config" - sudo nixos-rebuild --show-trace --flake .#"$target_config" boot - yellow "Please keep in mind that this is only a demo of the configuration. Things might break unexpectedly." -#+end_src - - - -#+begin_src nix-ts :tangle pkgs/swarsel-rebuild/default.nix - { self, name, writeShellApplication, git }: - writeShellApplication { - inherit name; - runtimeInputs = [ git ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } -#+end_src - -**** swarsel-install -:PROPERTIES: -:CUSTOM_ID: h:fbd8aaf2-9dca-4ca3-aca1-19d0d188a435 -:END: - -Autoformatting always puts the =EOF= with indentation, which makes shfmt check fail. When editing this block, unindent them manually. - -#+begin_src shell :tangle scripts/swarsel-install.sh - set -eo pipefail - - target_config="chaostheatre" - target_hostname="chaostheatre" - target_user="swarsel" - persist_dir="" - target_disk="/dev/vda" - disk_encryption=0 - - function help_and_exit() { - echo - echo "Locally installs SwarselSystem on this machine." - echo - echo "USAGE: $0 -n -d [OPTIONS]" - echo - echo "ARGS:" - echo " -n specify the nixos config to deploy." - echo " Default: chaostheatre" - echo " -d specify disk to install on." - echo " Default: /dev/vda" - echo " -u specify user to deploy for." - echo " Default: swarsel" - echo " -h | --help Print this help." - exit 0 - } - - function red() { - echo -e "\x1B[31m[!] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[31m[!] $($2) \x1B[0m" - fi - } - function green() { - echo -e "\x1B[32m[+] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[32m[+] $($2) \x1B[0m" - fi - } - function yellow() { - echo -e "\x1B[33m[*] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[33m[*] $($2) \x1B[0m" - fi - } - - while [[ $# -gt 0 ]]; do - case "$1" in - -n) - shift - target_config=$1 - target_hostname=$1 - ;; - -u) - shift - target_user=$1 - ;; - -d) - shift - target_disk=$1 - ;; - -h | --help) help_and_exit ;; - ,*) - echo "Invalid option detected." - help_and_exit - ;; - esac - shift - done - - function cleanup() { - sudo rm -rf .cache/nix - sudo rm -rf /root/.cache/nix - } - trap cleanup exit - - green "~SwarselSystems~ local installer" - - cd /home/"$target_user" - - sudo rm -rf /root/.cache/nix - sudo rm -rf .cache/nix - sudo rm -rf .dotfiles - - green "Cloning repository from GitHub" - git clone https://github.com/Swarsel/.dotfiles.git - - local_keys=$(ssh-add -L || true) - pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/keys/ssh/yubikey.pub) - read -ra pub_arr <<< "$pub_key" - - cd .dotfiles - if [[ $local_keys != *"${pub_arr[1]}"* ]]; then - yellow "The ssh key for this configuration is not available." - green "Adjusting flake.nix so that the configuration is buildable ..." - sed -i '/nix-secrets = {/,/^[[:space:]]*};/d' flake.nix - sed -i '/vbc-nix = {/,/^[[:space:]]*};/d' flake.nix - sed -i '/[[:space:]]*\/\/ (inputs.vbc-nix.overlays.default final prev)/d' overlays/default.nix - rm modules/home/common/env.nix - rm modules/home/common/gammastep.nix - rm modules/home/common/git.nix - rm modules/home/common/mail.nix - rm modules/home/common/yubikey.nix - rm modules/nixos/server/restic.nix - rm hosts/nixos/sync/default.nix - rm -rf modules/nixos/server - rm -rf modules/home/server - cat > hosts/nixos/chaostheatre/options-home.nix << EOF - { self, lib, ... }: - { - options = { - swarselsystems = { - modules = { - yubikey = lib.mkEnableOption "dummy option for chaostheatre"; - env = lib.mkEnableOption "dummy option for chaostheatre"; - git = lib.mkEnableOption "dummy option for chaostheatre"; - mail = lib.mkEnableOption "dummy option for chaostheatre"; - gammastep = lib.mkEnableOption "dummy option for chaostheatre"; - }; - }; - }; - } - EOF - nix flake update vbc-nix - git add . - else - green "Valid SSH key found! Continuing with installation" - fi - - green "Reading system information for $target_config ..." - DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)" - green "Root Disk in config: $DISK - Root Disk passed in cli: $target_disk" - - CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)" - if [[ $CRYPTED == "true" ]]; then - green "Encryption: ✓" - disk_encryption=1 - else - red "Encryption: X" - disk_encryption=0 - fi - - IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)" - if [[ $IMPERMANENCE == "true" ]]; then - green "Impermanence: ✓" - persist_dir="/persist" - else - red "Impermanence: X" - persist_dir="" - fi - - SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" - if [[ $SWAP == "true" ]]; then - green "Swap: ✓" - else - red "Swap: X" - fi - - SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSecureBoot)" - if [[ $SECUREBOOT == "true" ]]; then - green "Secure Boot: ✓" - else - red "Secure Boot: X" - fi - - if [ "$disk_encryption" -eq 1 ]; then - while true; do - green "Set disk encryption passphrase:" - read -rs luks_passphrase - green "Please confirm passphrase:" - read -rs luks_passphrase_confirm - if [[ $luks_passphrase == "$luks_passphrase_confirm" ]]; then - echo "$luks_passphrase" > /tmp/disko-password - break - else - red "Passwords do not match" - fi - done - fi - - green "Setting up disk ..." - if [[ $target_config == "chaostheatre" ]]; then - sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/v1.10.0 -- --mode destroy,format,mount --flake .#"$target_config" --yes-wipe-all-disks --arg diskDevice "$target_disk" - else - sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount --flake .#"$target_config" --yes-wipe-all-disks - fi - sudo mkdir -p /mnt/"$persist_dir"/home/"$target_user"/ - sudo cp -r /home/"$target_user"/.dotfiles /mnt/"$persist_dir"/home/"$target_user"/ - sudo chown -R 1000:100 /mnt/"$persist_dir"/home/"$target_user" - - green "Generating hardware configuration ..." - sudo nixos-generate-config --root /mnt --no-filesystems --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/ - - green "Injecting initialSetup ..." - sudo sed -i '/ boot.extraModulePackages /a \ swarselsystems.initialSetup = true;' /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/hardware-configuration.nix - - git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/hardware-configuration.nix - sudo mkdir -p /root/.local/share/nix/ - printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | sudo tee /root/.local/share/nix/trusted-settings.json > /dev/null - green "Installing flake $target_config" - sudo nixos-install --flake .#"$target_config" - green "Installation finished! Reboot to see changes" -#+end_src - - - -#+begin_src nix-ts :tangle pkgs/swarsel-install/default.nix - { self, name, writeShellApplication, git }: - writeShellApplication { - inherit name; - runtimeInputs = [ git ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } -#+end_src - -**** swarsel-postinstall -:PROPERTIES: -:CUSTOM_ID: h:c98a7615-e5da-4f47-8ed1-2b2ea65519e9 -:END: - -#+begin_src shell :tangle scripts/swarsel-postinstall.sh - set -eo pipefail - - target_config="chaostheatre" - target_user="swarsel" - - function help_and_exit() { - echo - echo "Locally installs SwarselSystem on this machine." - echo - echo "USAGE: $0 -d [OPTIONS]" - echo - echo "ARGS:" - echo " -d specify disk to install on." - echo " -n specify the nixos config to deploy." - echo " Default: chaostheatre" - echo " Default: chaostheatre" - echo " -u specify user to deploy for." - echo " Default: swarsel" - echo " -h | --help Print this help." - exit 0 - } - - function green() { - echo -e "\x1B[32m[+] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[32m[+] $($2) \x1B[0m" - fi - } - - while [[ $# -gt 0 ]]; do - case "$1" in - -n) - shift - target_config=$1 - ;; - -u) - shift - target_user=$1 - ;; - -h | --help) help_and_exit ;; - ,*) - echo "Invalid option detected." - help_and_exit - ;; - esac - shift - done - - function cleanup() { - sudo rm -rf .cache/nix - sudo rm -rf /root/.cache/nix - } - trap cleanup exit - - sudo rm -rf .cache/nix - sudo rm -rf /root/.cache/nix - - green "~SwarselSystems~ remote post-installer" - - cd /home/"$target_user"/.dotfiles - - SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_config".config.swarselsystems.isSecureBoot)" - - if [[ $SECUREBOOT == "true" ]]; then - green "Setting up secure boot keys" - sudo mkdir -p /var/lib/sbctl - sbctl create-keys || true - sbctl enroll-keys --ignore-immutable --microsoft || true - fi - - green "Disabling initialSetup" - sed -i '/swarselsystems\.initialSetup = true;/d' /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/hardware-configuration.nix - sudo nixos-rebuild --flake .#"$target_config" switch - green "Post-install finished!" -#+end_src - - - -#+begin_src nix-ts :tangle pkgs/swarsel-postinstall/default.nix - { self, name, writeShellApplication, git }: - writeShellApplication { - inherit name; - runtimeInputs = [ git ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } -#+end_src - -**** t2ts -:PROPERTIES: -:CUSTOM_ID: h:5ad99997-e54c-4f0b-9ab7-15f76b1e16e1 -:END: - -#+begin_src nix-ts :tangle pkgs/t2ts/default.nix - { name, writeShellApplication, ... }: - - writeShellApplication { - inherit name; - runtimeInputs = [ ]; - text = '' - date -d"$1" +%s - ''; - } - -#+end_src - -**** ts2t -:PROPERTIES: -:CUSTOM_ID: h:5ad99997-e54c-4f0b-9ab7-15f76b1e16e1 -:END: - -#+begin_src nix-ts :tangle pkgs/ts2t/default.nix - { name, writeShellApplication, ... }: - - writeShellApplication { - inherit name; - runtimeInputs = [ ]; - text = '' - date -d @"$1" 2>/dev/null || date -r "$1" - ''; - } - -#+end_src - -**** vershell -:PROPERTIES: -:CUSTOM_ID: h:7806b129-a4a5-4d10-af27-6cbeafbcb294 -:END: - -#+begin_src nix-ts :tangle pkgs/vershell/default.nix - { name, writeShellApplication, ... }: - - writeShellApplication { - inherit name; - runtimeInputs = [ ]; - text = '' - nix shell github:nixos/nixpkgs/"$1"#"$2"; - ''; - } - -#+end_src - -**** eontimer -:PROPERTIES: -:CUSTOM_ID: h:9fda7829-09a4-4b8f-86f6-08b078ab2874 -:END: - -#+begin_src nix-ts :tangle pkgs/eontimer/default.nix - { lib - , python3 - , fetchFromGitHub - , makeDesktopItem - , writeShellScript - , ... - }: - let - wrapper = writeShellScript "eontimer-wrapper" '' - export QT_QPA_PLATFORM=xcb - exec @out@/bin/EonTimer - ''; - in - python3.pkgs.buildPythonApplication rec { - pname = "eontimer"; - version = "3.0.0-rc.6"; - pyproject = true; - - src = fetchFromGitHub { - owner = "DasAmpharos"; - repo = "EonTimer"; - rev = version; - hash = "sha256-+XN/VGGlEg2gVncRZrWDOZ2bfxt8xyIu22F2wHlG6YI="; - }; - - build-system = [ - python3.pkgs.setuptools - python3.pkgs.wheel - ]; - - dependencies = with python3.pkgs; [ - altgraph - certifi - charset-normalizer - idna - libsass - macholib - packaging - pillow - pipdeptree - platformdirs - pyinstaller - pyinstaller-hooks-contrib - pyside6 - requests - setuptools - shiboken6 - urllib3 - ]; - - nativeBuildInputs = [ - python3.pkgs.pyinstaller - ]; - - buildPhase = '' - runHook preBuild - - pyinstaller --clean --noconfirm EonTimer.spec - - runHook postBuild - ''; - - installPhase = '' - runHook preInstall - - mkdir -p $out/bin - mkdir -p $out/share/applications - cp dist/EonTimer $out/bin/ - install -Dm755 -T ${wrapper} $out/bin/eontimer - substituteInPlace $out/bin/eontimer --subst-var out - - runHook postInstall - ''; - - postInstall = '' - install -Dm755 -t $out/share/applications ${ - makeDesktopItem { - name = "eontimer"; - desktopName = "EonTimer"; - comment = "Start EonTimer"; - exec = "eontimer"; - } - }/share/applications/eontimer.desktop - ''; - - - - meta = { - description = "Pokémon RNG Timer"; - homepage = "https://github.com/DasAmpharos/EonTimer"; - license = lib.licenses.mit; - maintainers = with lib.maintainers; [ ]; - mainProgram = "eon-timer"; - }; - } - -#+end_src - -**** project -:PROPERTIES: -:CUSTOM_ID: h:154b6df4-dd50-4f60-9794-05a140d02994 -:END: - -#+begin_src shell :tangle scripts/project.sh - set -euo pipefail - - if [ ! -d "$(pwd)/.git" ]; then - git init - fi - nix flake init --template "$FLAKE"#"$1" - direnv allow -#+end_src - -#+begin_src nix-ts :tangle pkgs/project/default.nix - { self, name, writeShellApplication }: - writeShellApplication { - inherit name; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } -#+end_src - -**** fhs -:PROPERTIES: -:CUSTOM_ID: h:36d6c17c-6d91-4297-b76d-9d7feab6c1a0 -:END: - - -#+begin_src nix-ts :tangle pkgs/fhs/default.nix - { name, pkgs, ... }: - let - base = pkgs.appimageTools.defaultFhsEnvArgs; - in - pkgs.buildFHSEnv (base // { - name = "fhs"; - targetPkgs = pkgs: (base.targetPkgs pkgs) ++ [ pkgs.pkg-config ]; - profile = "export FHS=1"; - runScript = "zsh"; - extraOutputsToInstall = [ "dev" ]; - }) -#+end_src - -**** swarsel-displaypower -:PROPERTIES: -:CUSTOM_ID: h:814d5e7f-4b95-412d-b246-33f888514ec6 -:END: - -A crude script to power on all displays that might be attached. Needed because sometimes displays do not awake from sleep. - -#+begin_src shell :tangle scripts/swarsel-displaypower.sh - swaymsg "output * power on" > /dev/null 2>&1 || true - swaymsg "output * dpms on" > /dev/null 2>&1 || true -#+end_src - -#+begin_src nix-ts :tangle pkgs/swarsel-displaypower/default.nix - { self, name, writeShellApplication, sway }: - writeShellApplication { - inherit name; - runtimeInputs = [ sway ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } - -#+end_src - -**** swarsel-mgba -:PROPERTIES: -:CUSTOM_ID: h:799579f3-ddd3-4f76-928a-a8c665980476 -:END: - -AppImage version of mgba in which the lua scripting works. - - -#+begin_src nix-ts :tangle pkgs/swarsel-mgba/default.nix - { appimageTools, fetchurl, ... }: - let - pname = "mgba"; - version = "0.10.4"; - src = fetchurl { - url = "https://github.com/mgba-emu/mgba/releases/download/${version}/mGBA-${version}-appimage-x64.appimage"; - hash = "sha256-rDihDfuA8DqxvCe6UeavCzpjeU+fSqUbFnyTNC2dc1I="; - }; - appimageContents = appimageTools.extractType2 { inherit pname version src; }; - in - appimageTools.wrapType2 { - inherit pname version src; - extraInstallCommands = '' - install -Dm444 ${appimageContents}/io.mgba.mGBA.desktop -t $out/share/applications - substituteInPlace $out/share/applications/io.mgba.mGBA.desktop \ - --replace-fail 'Exec=mgba-qt %f' 'Exec=mgba' - cp -r ${appimageContents}/usr/share/icons $out/share - ''; - - } - -#+end_src - -**** swarsel-deploy -:PROPERTIES: -:CUSTOM_ID: h:c3362d4e-d3a8-43e8-9ef7-272b6de0572e -:END: - -#+begin_src nix-ts :tangle pkgs/swarsel-deploy/default.nix - # heavily inspired from https://github.com/oddlama/nix-config/blob/d42cbde676001a7ad8a3cace156e050933a4dcc3/pkgs/deploy.nix - { name, bc, nix-output-monitor, writeShellApplication, ... }: - writeShellApplication { - runtimeInputs = [ bc nix-output-monitor ]; - inherit name; - text = '' - set -euo pipefail - shopt -s lastpipe # allow cmd | readarray - - function die() { - echo "error: $*" >&2 - exit 1 - } - function show_help() { - echo 'Usage: deploy [OPTIONS] [ACTION]' - echo "Builds, pushes and activates nixosConfigurations on target systems." - echo "" - echo 'ACTION:' - echo ' switch [default] Switch immediately to the new configuration and make it the boot default' - echo ' boot Make the configuration the new boot default' - echo " test Activate the configuration but don't make it the boot default" - echo " dry-activate Don't activate, just show what would be done" - echo "" - echo 'OPTIONS: [passed to nix build]' - } - - function time_start() { - T_START=$(date +%s.%N) - } - - function time_next() { - T_END=$(date +%s.%N) - T_LAST=$(${bc}/bin/bc <<< "scale=1; ($T_END - $T_START)/1") - T_START="$T_END" - } - - USER_FLAKE_DIR=$(git rev-parse --show-toplevel 2> /dev/null || pwd) || - die "Could not determine current working directory. Something went very wrong." - [[ -e "$USER_FLAKE_DIR/flake.nix" ]] || - die "Could not determine location of your project's flake.nix. Please run this at or below your main directory containing the flake.nix." - cd "$USER_FLAKE_DIR" - - [[ $# -gt 0 ]] || { - show_help - exit 1 - } - - OPTIONS=() - POSITIONAL_ARGS=() - while [[ $# -gt 0 ]]; do - case "$1" in - "help" | "--help" | "-help" | "-h") - show_help - exit 1 - ;; - - -*) OPTIONS+=("$1") ;; - ,*) POSITIONAL_ARGS+=("$1") ;; - esac - shift - done - - [[ ''${#POSITIONAL_ARGS[@]} -ge 1 ]] || - die "Missing argument: " - [[ ''${#POSITIONAL_ARGS[@]} -le 2 ]] || - die "Too many arguments given." - - tr , '\n' <<< "''${POSITIONAL_ARGS[0]}" | sort -u | readarray -t HOSTS - ACTION="''${POSITIONAL_ARGS[1]-switch}" - - # Expand flake paths for hosts definitions - declare -A TOPLEVEL_FLAKE_PATHS - for host in "''${HOSTS[@]}"; do - TOPLEVEL_FLAKE_PATHS["$host"]=".#nixosConfigurations.$host.config.system.build.toplevel" - done - - time_start - - # Get outputs of all derivations (should be cached) - declare -A TOPLEVEL_STORE_PATHS - for host in "''${HOSTS[@]}"; do - toplevel="''${TOPLEVEL_FLAKE_PATHS["$host"]}" - # Make sudo call to get prompt out of the way - sudo echo " Building 📦 $host" - nix build --no-link "''${OPTIONS[@]}" --show-trace --log-format internal-json -v "$toplevel" |& ${nix-output-monitor}/bin/nom --json || - die "Failed to get derivation path for $host from ''${TOPLEVEL_FLAKE_PATHS["$host"]}" - TOPLEVEL_STORE_PATHS["$host"]=$(nix build --no-link --print-out-paths "''${OPTIONS[@]}" "$toplevel") - time_next - echo " Built ✅ $host ''${TOPLEVEL_STORE_PATHS["$host"]} in ''${T_LAST}s" - done - - current_host=$(hostname) - - for host in "''${HOSTS[@]}"; do - store_path="''${TOPLEVEL_STORE_PATHS["$host"]}" - - if [ "$host" = "$current_host" ]; then - echo -e "\033[1;36m Running locally for $host... \033[m" - ssh_prefix="sudo" - else - echo -e "\033[1;36m Copying \033[m➡️ \033[34m$host\033[m" - nix copy --to "ssh://$host" "$store_path" - time_next - echo -e "\033[1;32m Copied \033[m✅ \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m" - ssh_prefix="ssh $host --" - fi - - echo -e "\033[1;36m Applying \033[m⚙️ \033[34m$host\033[m" - prev_system=$($ssh_prefix readlink -e /nix/var/nix/profiles/system) - $ssh_prefix /run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set "$store_path" || - die "Failed to set system profile" - $ssh_prefix "$store_path"/bin/switch-to-configuration "$ACTION" || - echo "Error while activating new system" >&2 - - if [[ -n $prev_system ]]; then - $ssh_prefix nvd --color always diff "$prev_system" "$store_path" || true - fi - - time_next - echo -e "\033[1;32m Applied \033[m✅ \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m" - done - ''; - } - -#+end_src - -**** sshrm -:PROPERTIES: -:CUSTOM_ID: h:02842543-caca-4d4c-a4d2-7ac749b5c136 -:END: - -This programs simply runs ssh-keygen on the last host that I tried to ssh into. I need this frequently when working with cloud-init usually. - -#+begin_src shell :tangle scripts/sshrm.sh - HISTFILE="$HOME"/.histfile - - last_ssh_cmd=$(grep -E "ssh " "$HISTFILE" | sed -E 's/^: [0-9]+:[0-9]+;//' | grep "^ssh " | tail -1) - host=$(echo "$last_ssh_cmd" | sed -E 's/.*ssh ([^@ ]+@)?([^ ]+).*/\2/') - - if [[ -n $host ]]; then - echo "Removing SSH host key for: $host" - ssh-keygen -R "$host" - else - echo "No valid SSH command found in history." - fi -#+end_src - -#+begin_src nix-ts :tangle pkgs/sshrm/default.nix - { self, name, writeShellApplication, openssh }: - writeShellApplication { - inherit name; - runtimeInputs = [ openssh ]; - text = builtins.readFile "${self}/scripts/${name}.sh"; - } -#+end_src - -*** Overlays (additions, overrides, nixpkgs-stable) -:PROPERTIES: -:CUSTOM_ID: h:5e3e21e0-57af-4dad-b32f-6400af9b7aab -:END: - -This file now holds all of the "nixpkgs-changes" that I am using across the configurations. Most notable here are the =modifications=, where I am editing derivations according to my needs. - -When adding a new entry here, do not forget to add it in the default output of this file, otherwise it will not be exposed to the rest of the system. - -#+begin_src nix-ts :tangle overlays/default.nix - { self, inputs, lib, ... }: - - let - additions = final: _: import "${self}/pkgs" { pkgs = final; inherit lib; }; - - modifications = final: prev: { - vesktop = prev.vesktop.override { - withSystemVencord = true; - }; - - firefox = prev.firefox.override { - nativeMessagingHosts = [ - prev.tridactyl-native - prev.browserpass - prev.plasma5Packages.plasma-browser-integration - ]; - }; - - mgba = final.swarsel-mgba; - - retroarch = prev.retroarch.withCores (cores: with cores; [ - snes9x # snes - nestopia # nes - dosbox # dos - scummvm # scumm - vba-m # gb/a - mgba # gb/a - melonds # ds - dolphin # gc/wii - ]); - - - - }; - - nixpkgs-stable = final: _: { - stable = import inputs.nixpkgs-stable { - inherit (final) system; - config.allowUnfree = true; - }; - }; - - nixpkgs-kernel = final: _: { - kernel = import inputs.nixpkgs-kernel { - inherit (final) system; - config.allowUnfree = true; - }; - }; - - nixpkgs-stable24_05 = final: _: { - stable24_05 = import inputs.nixpkgs-stable24_05 { - inherit (final) system; - config.allowUnfree = true; - }; - }; - - nixpkgs-stable24_11 = final: _: { - stable24_11 = import inputs.nixpkgs-stable24_11 { - inherit (final) system; - config.allowUnfree = true; - }; - }; - - zjstatus = _: prev: { - zjstatus = inputs.zjstatus.packages.${prev.system}.default; - }; - - in - { - default = - final: prev: - - (additions final prev) - // (modifications final prev) - // (nixpkgs-stable final prev) - // (nixpkgs-kernel final prev) - // (nixpkgs-stable24_05 final prev) - // (nixpkgs-stable24_11 final prev) - // (zjstatus final prev) - // (inputs.vbc-nix.overlays.default final prev) - // (inputs.nur.overlays.default final prev) - // (inputs.emacs-overlay.overlay final prev) - // (inputs.nix-topology.overlays.default final prev) - // (inputs.nixgl.overlay final prev); - - } - -#+end_src - -*** Profiles -:PROPERTIES: -:CUSTOM_ID: h:f0f1c961-3e7a-47b8-99ab-1654bb45dffc -:END: - -In this section I define custom modules under the =swarsel= attribute. These are mostly used to define settings specific to a host. I keep these settings confined to either home-manager or nixos to maintain compatibility with non-NixOS machines. - -Note: The structure of generating the packages was changed in commit =2cf03a3 refactor: package and module generation=. That commit can be checked out in order to see a simpler version of achieving the same thing. - -**** NixOS -:PROPERTIES: -:CUSTOM_ID: h:14e68518-8ec7-48ec-b208-0e3d6d49954d -:END: - -Modules that need to be loaded on the NixOS level. Note that these will not be available on systems that are not running NixOS. - -#+begin_src nix-ts :tangle profiles/nixos/default.nix - { lib, ... }: - let - profileNames = lib.swarselsystems.readNix "profiles/nixos"; - in - { - imports = lib.swarselsystems.mkImports profileNames "profiles/nixos"; - } -#+end_src -***** Personal -:PROPERTIES: -:CUSTOM_ID: h:32d654de-8db2-403a-9a27-4c46d7b9172d -:END: - -#+begin_src nix-ts :tangle profiles/nixos/personal/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.personal = lib.mkEnableOption "is this a personal host"; - config = lib.mkIf config.swarselsystems.profiles.personal { - swarselsystems.modules = { - packages = lib.mkDefault true; - general = lib.mkDefault true; - home-manager = lib.mkDefault true; - xserver = lib.mkDefault true; - users = lib.mkDefault true; - env = lib.mkDefault true; - security = lib.mkDefault true; - systemdTimeout = lib.mkDefault true; - hardware = lib.mkDefault true; - pulseaudio = lib.mkDefault true; - pipewire = lib.mkDefault true; - network = lib.mkDefault true; - time = lib.mkDefault true; - sops = lib.mkDefault true; - pii = lib.mkDefault true; - stylix = lib.mkDefault true; - programs = lib.mkDefault true; - zsh = lib.mkDefault true; - syncthing = lib.mkDefault true; - blueman = lib.mkDefault true; - networkDevices = lib.mkDefault true; - gvfs = lib.mkDefault true; - interceptionTools = lib.mkDefault true; - swayosd = lib.mkDefault true; - ppd = lib.mkDefault true; - yubikey = lib.mkDefault true; - ledger = lib.mkDefault true; - keyboards = lib.mkDefault true; - login = lib.mkDefault true; - nix-ld = lib.mkDefault true; - impermanence = lib.mkDefault true; - nvd = lib.mkDefault true; - gnome-keyring = lib.mkDefault true; - sway = lib.mkDefault true; - xdg-portal = lib.mkDefault true; - distrobox = lib.mkDefault true; - appimage = lib.mkDefault true; - lid = lib.mkDefault true; - lowBattery = lib.mkDefault true; - lanzaboote = lib.mkDefault true; - autologin = lib.mkDefault true; - - optional = { - gaming = lib.mkDefault true; - virtualbox = lib.mkDefault true; - nswitch-rcm = lib.mkDefault true; - }; - - server = { - ssh = lib.mkDefault true; - }; - }; - - }; - - } - -#+end_src - -***** Chaostheatre -:PROPERTIES: -:CUSTOM_ID: h:b79fbb59-9cf2-48eb-b469-2589223dda95 -:END: - -#+begin_src nix-ts :tangle profiles/nixos/chaostheatre/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.chaostheatre = lib.mkEnableOption "is this a chaostheatre host"; - config = lib.mkIf config.swarselsystems.profiles.chaostheatre { - swarselsystems.modules = { - packages = lib.mkDefault true; - general = lib.mkDefault true; - home-manager = lib.mkDefault true; - xserver = lib.mkDefault true; - users = lib.mkDefault true; - env = lib.mkDefault true; - security = lib.mkDefault true; - systemdTimeout = lib.mkDefault true; - hardware = lib.mkDefault true; - pulseaudio = lib.mkDefault true; - pipewire = lib.mkDefault true; - network = lib.mkDefault true; - time = lib.mkDefault true; - sops = lib.mkDefault false; - stylix = lib.mkDefault true; - programs = lib.mkDefault true; - zsh = lib.mkDefault true; - syncthing = lib.mkDefault true; - blueman = lib.mkDefault true; - networkDevices = lib.mkDefault true; - gvfs = lib.mkDefault true; - interceptionTools = lib.mkDefault true; - swayosd = lib.mkDefault true; - ppd = lib.mkDefault true; - yubikey = lib.mkDefault true; - ledger = lib.mkDefault true; - keyboards = lib.mkDefault true; - login = lib.mkDefault true; - nix-ld = lib.mkDefault true; - impermanence = lib.mkDefault true; - nvd = lib.mkDefault true; - gnome-keyring = lib.mkDefault true; - sway = lib.mkDefault true; - xdg-portal = lib.mkDefault true; - distrobox = lib.mkDefault true; - appimage = lib.mkDefault true; - lid = lib.mkDefault true; - lowBattery = lib.mkDefault true; - lanzaboote = lib.mkDefault true; - autologin = lib.mkDefault true; - }; - - }; - - } - -#+end_src - -***** toto -:PROPERTIES: -:CUSTOM_ID: h:125443fb-deb6-44c9-83ee-bbd10daf78dd -:END: - -#+begin_src nix-ts :tangle profiles/nixos/toto/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.toto = lib.mkEnableOption "is this a toto (setup) host"; - config = lib.mkIf config.swarselsystems.profiles.toto { - swarselsystems.modules = { - general = lib.mkDefault true; - home-manager = lib.mkDefault true; - xserver = lib.mkDefault true; - users = lib.mkDefault true; - sops = lib.mkDefault true; - impermanence = lib.mkDefault true; - lanzaboote = lib.mkDefault true; - autologin = lib.mkDefault true; - server = { - ssh = lib.mkDefault true; - }; - }; - - }; - - } - -#+end_src - -***** Work -:PROPERTIES: -:CUSTOM_ID: h:cb3631a8-9c1b-42f2-ab01-502c7b4c273d -:END: - -#+begin_src nix-ts :tangle profiles/nixos/work/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.work = lib.mkEnableOption "is this a work host"; - config = lib.mkIf config.swarselsystems.profiles.work { - swarselsystems.modules = { - optional = { - work = lib.mkDefault true; - }; - }; - - }; - - } - -#+end_src - -***** Framework -:PROPERTIES: -:CUSTOM_ID: h:eb272c99-842a-4095-bc65-283562749300 -:END: - -#+begin_src nix-ts :tangle profiles/nixos/framework/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.framework = lib.mkEnableOption "is this a framework brand host"; - config = lib.mkIf config.swarselsystems.profiles.framework { - swarselsystems.modules = { - optional = { - framework = lib.mkDefault true; - }; - }; - - }; - - } - -#+end_src - -***** AMD CPU -:PROPERTIES: -:CUSTOM_ID: h:b7beb4a5-8808-438d-8799-7f08f38fd1ba -:END: - -#+begin_src nix-ts :tangle profiles/nixos/amdcpu/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.amdcpu = lib.mkEnableOption "is this a host with amd cpu"; - config = lib.mkIf config.swarselsystems.profiles.amdcpu { - swarselsystems.modules = { - optional = { - amdcpu = lib.mkDefault true; - }; - }; - - }; - - } - -#+end_src - -***** AMD GPU -:PROPERTIES: -:CUSTOM_ID: h:79c71b6d-a1ad-447d-8940-bb5bfd71dced -:END: - -#+begin_src nix-ts :tangle profiles/nixos/amdgpu/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.amdgpu = lib.mkEnableOption "is this a host with amd gpu"; - config = lib.mkIf config.swarselsystems.profiles.amdgpu { - swarselsystems.modules = { - optional = { - amdgpu = lib.mkDefault true; - }; - }; - - }; - - } - -#+end_src - -***** Hibernation -:PROPERTIES: -:CUSTOM_ID: h:641d0a2a-0592-448a-a6e3-d0a9c330293e -:END: - -#+begin_src nix-ts :tangle profiles/nixos/hibernation/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.hibernation = lib.mkEnableOption "is this a host using hibernation"; - config = lib.mkIf config.swarselsystems.profiles.hibernation { - swarselsystems.modules = { - optional = { - hibernation = lib.mkDefault true; - }; - }; - - }; - - } - -#+end_src - -***** BTRFS -:PROPERTIES: -:CUSTOM_ID: h:0bb401e3-b195-4ff2-bc74-23c5a54d83d2 -:END: - -#+begin_src nix-ts :tangle profiles/nixos/btrfs/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.btrfs = lib.mkEnableOption "is this a host using btrfs"; - config = lib.mkIf config.swarselsystems.profiles.btrfs { - swarselsystems.modules = { - optional = { - btrfs = lib.mkDefault true; - }; - }; - - }; - - } - -#+end_src - -***** Local Server -:PROPERTIES: -:CUSTOM_ID: h:dfc076fd-ee74-4663-b164-653370c52b75 -:END: - -#+begin_src nix-ts :tangle profiles/nixos/localserver/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.server.local = lib.mkEnableOption "is this a local server"; - config = lib.mkIf config.swarselsystems.profiles.server.local { - swarselsystems = { - modules = { - general = lib.mkDefault true; - pii = lib.mkDefault true; - home-manager = lib.mkDefault true; - xserver = lib.mkDefault true; - time = lib.mkDefault true; - users = lib.mkDefault true; - sops = lib.mkDefault true; - server = { - general = lib.mkDefault true; - packages = lib.mkDefault true; - nfs = lib.mkDefault true; - nginx = lib.mkDefault true; - ssh = lib.mkDefault true; - kavita = lib.mkDefault true; - restic = lib.mkDefault true; - jellyfin = lib.mkDefault true; - navidrome = lib.mkDefault true; - spotifyd = lib.mkDefault true; - mpd = lib.mkDefault true; - postgresql = lib.mkDefault true; - matrix = lib.mkDefault true; - nextcloud = lib.mkDefault true; - immich = lib.mkDefault true; - paperless = lib.mkDefault true; - transmission = lib.mkDefault true; - syncthing = lib.mkDefault true; - grafana = lib.mkDefault true; - emacs = lib.mkDefault true; - freshrss = lib.mkDefault true; - jenkins = lib.mkDefault false; - kanidm = lib.mkDefault true; - firefly-iii = lib.mkDefault true; - koillection = lib.mkDefault true; - radicale = lib.mkDefault true; - atuin = lib.mkDefault true; - }; - }; - }; - }; - - } - -#+end_src -***** OCI Sync Server -:PROPERTIES: -:CUSTOM_ID: h:9b7b50d1-57ad-41ca-94ab-74393aae01bf -:END: - -#+begin_src nix-ts :tangle profiles/nixos/syncserver/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.server.sync = lib.mkEnableOption "is this a oci sync server"; - config = lib.mkIf config.swarselsystems.profiles.server.sync { - swarselsystems = { - modules = { - general = lib.mkDefault true; - nix-ld = lib.mkDefault true; - pii = lib.mkDefault true; - home-manager = lib.mkDefault true; - xserver = lib.mkDefault true; - time = lib.mkDefault true; - users = lib.mkDefault true; - sops = lib.mkDefault true; - server = { - general = lib.mkDefault true; - packages = lib.mkDefault true; - nginx = lib.mkDefault true; - ssh = lib.mkDefault true; - forgejo = lib.mkDefault true; - ankisync = lib.mkDefault true; - }; - }; - }; - }; - - } - -#+end_src -***** Moonside -:PROPERTIES: -:CUSTOM_ID: h:cc780ef2-7e5e-4835-b659-c731b306a320 -:END: - -#+begin_src nix-ts :tangle profiles/nixos/moonside/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.server.moonside = lib.mkEnableOption "is this a moonside server"; - config = lib.mkIf config.swarselsystems.profiles.server.moonside { - swarselsystems = { - modules = { - general = lib.mkDefault true; - pii = lib.mkDefault true; - home-manager = lib.mkDefault true; - xserver = lib.mkDefault true; - time = lib.mkDefault true; - users = lib.mkDefault true; - impermanence = lib.mkDefault true; - sops = lib.mkDefault true; - server = { - general = lib.mkDefault true; - packages = lib.mkDefault true; - nginx = lib.mkDefault true; - ssh = lib.mkDefault true; - oauth2-proxy = lib.mkDefault true; - croc = lib.mkDefault true; - microbin = lib.mkDefault true; - shlink = lib.mkDefault true; - }; - }; - }; - }; - - } - -#+end_src -**** home-manager -:PROPERTIES: -:CUSTOM_ID: h:ced5841f-c088-4d88-b3a1-7d62aad8837b -:END: - -This holds modules that are to be used on most hosts. These are also the most important options to configure, as these allow me easy access to monitor, keyboard, and other setups. - -#+BEGIN_src nix-ts :tangle profiles/home/default.nix - { lib, ... }: - let - profileNames = lib.swarselsystems.readNix "profiles/home"; - in - { - imports = lib.swarselsystems.mkImports profileNames "profiles/home"; - } -#+end_src - -***** Personal -:PROPERTIES: -:CUSTOM_ID: h:26512487-8c29-4b92-835b-d67394c3f5ef -:END: - -#+begin_src nix-ts :tangle profiles/home/personal/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.personal = lib.mkEnableOption "is this a personal host"; - config = lib.mkIf config.swarselsystems.profiles.personal { - swarselsystems.modules = { - packages = lib.mkDefault true; - ownpackages = lib.mkDefault true; - general = lib.mkDefault true; - nixgl = lib.mkDefault true; - sops = lib.mkDefault true; - yubikey = lib.mkDefault true; - ssh = lib.mkDefault true; - stylix = lib.mkDefault true; - desktop = lib.mkDefault true; - symlink = lib.mkDefault true; - env = lib.mkDefault true; - programs = lib.mkDefault true; - nix-index = lib.mkDefault true; - passwordstore = lib.mkDefault true; - direnv = lib.mkDefault true; - eza = lib.mkDefault true; - atuin = lib.mkDefault true; - git = lib.mkDefault true; - fuzzel = lib.mkDefault true; - starship = lib.mkDefault true; - kitty = lib.mkDefault true; - zsh = lib.mkDefault true; - zellij = lib.mkDefault true; - tmux = lib.mkDefault true; - mail = lib.mkDefault true; - emacs = lib.mkDefault true; - waybar = lib.mkDefault true; - firefox = lib.mkDefault true; - gnome-keyring = lib.mkDefault true; - kdeconnect = lib.mkDefault true; - mako = lib.mkDefault true; - swayosd = lib.mkDefault true; - yubikeytouch = lib.mkDefault true; - sway = lib.mkDefault true; - kanshi = lib.mkDefault true; - gpgagent = lib.mkDefault true; - gammastep = lib.mkDefault true; - - optional = { - gaming = lib.mkDefault true; - }; - }; - }; - - } - -#+end_src - -***** Chaostheatre -:PROPERTIES: -:CUSTOM_ID: h:36a0209f-2c17-4808-a1d0-a9e1920c307a -:END: - -#+begin_src nix-ts :tangle profiles/home/chaostheatre/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.chaostheatre = lib.mkEnableOption "is this a chaostheatre host"; - config = lib.mkIf config.swarselsystems.profiles.chaostheatre { - swarselsystems.modules = { - packages = lib.mkDefault true; - ownpackages = lib.mkDefault true; - general = lib.mkDefault true; - nixgl = lib.mkDefault true; - sops = lib.mkDefault true; - yubikey = lib.mkDefault false; - ssh = lib.mkDefault true; - stylix = lib.mkDefault true; - desktop = lib.mkDefault true; - symlink = lib.mkDefault true; - env = lib.mkDefault false; - programs = lib.mkDefault true; - nix-index = lib.mkDefault true; - direnv = lib.mkDefault true; - eza = lib.mkDefault true; - git = lib.mkDefault false; - fuzzel = lib.mkDefault true; - starship = lib.mkDefault true; - kitty = lib.mkDefault true; - zsh = lib.mkDefault true; - zellij = lib.mkDefault true; - tmux = lib.mkDefault true; - mail = lib.mkDefault false; - emacs = lib.mkDefault true; - waybar = lib.mkDefault true; - firefox = lib.mkDefault true; - gnome-keyring = lib.mkDefault true; - kdeconnect = lib.mkDefault true; - mako = lib.mkDefault true; - swayosd = lib.mkDefault true; - yubikeytouch = lib.mkDefault true; - sway = lib.mkDefault true; - kanshi = lib.mkDefault true; - gpgagent = lib.mkDefault true; - gammastep = lib.mkDefault false; - }; - }; - - } - -#+end_src - -***** toto -:PROPERTIES: -:CUSTOM_ID: h:e1d4f141-af11-448a-9796-fc822a8f77ec -:END: - -#+begin_src nix-ts :tangle profiles/home/toto/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.toto = lib.mkEnableOption "is this a toto (setup) host"; - config = lib.mkIf config.swarselsystems.profiles.toto { - swarselsystems.modules = { - general = lib.mkDefault true; - sops = lib.mkDefault true; - ssh = lib.mkDefault true; - }; - }; - - } - -#+end_src - -***** Work -:PROPERTIES: -:CUSTOM_ID: h:7b091523-a5b0-48b6-8b03-4dc2405e2d81 -:END: - -#+begin_src nix-ts :tangle profiles/home/work/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.work = lib.mkEnableOption "is this a work host"; - config = lib.mkIf config.swarselsystems.profiles.work { - swarselsystems.modules = { - optional = { - work = lib.mkDefault true; - }; - }; - }; - - } - -#+end_src - -***** Framework -:PROPERTIES: -:CUSTOM_ID: h:712b9d7f-16c0-42b3-b02b-6d79ee15cfcc -:END: - -#+begin_src nix-ts :tangle profiles/home/framework/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.framework = lib.mkEnableOption "is this a framework brand host"; - config = lib.mkIf config.swarselsystems.profiles.framework { - swarselsystems.modules = { - optional = { - framework = lib.mkDefault true; - }; - }; - - }; - - } - -#+end_src - -***** Darwin -:PROPERTIES: -:CUSTOM_ID: h:24e6d661-f498-478c-9008-e8d8c17432ca -:END: - -#+begin_src nix-ts :tangle profiles/home/darwin/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.darwin = lib.mkEnableOption "is this a darwin host"; - config = lib.mkIf config.swarselsystems.profiles.darwin { - swarselsystems.modules = { - general = lib.mkDefault true; - }; - }; - - } - -#+end_src - -***** Local Server -:PROPERTIES: -:CUSTOM_ID: h:8027b858-369e-4f12-bbaf-f15eeee3d904 -:END: - -#+begin_src nix-ts :tangle profiles/home/localserver/default.nix :mkdirp yes - { lib, config, ... }: - { - options.swarselsystems.profiles.server.local = lib.mkEnableOption "is this a local server"; - config = lib.mkIf config.swarselsystems.profiles.server.local { - swarselsystems.modules = { - general = lib.mkDefault true; - server = { - dotfiles = lib.mkDefault true; - }; - }; - }; - - } - -#+end_src - -*** Library functions -:PROPERTIES: -:CUSTOM_ID: h:4d38c9f7-2680-4c02-a1f4-ed8db0d55ce4 -:END: - -This section defines all functions of my own that I add to =lib=. These are used in all places over the config, with many of them being used in =flake.nix=. - -A breakdown of each function: - -The interesting part is in the start: -- first, I define =pkgsFor=. This function reads all available systems from nixpkgs and generates pkgs for them. -- next, =forEachSystem= is a function that can be called to declare an output for each such defined system. -- =forAllSystems= is a crude function that I use for expressions that depend on =system=, as the prior two attributes already consumed it at that stage. This is only really used to generate the checks in their own file. -- =mkFullHostConfigs= is the function that dynamically creates all definded hosts. The hosts are defined by placing a directory in =hosts/= under either the =nixos/= or =darwin/= directory. These directories are being read by =readHosts= and delivered to this funtion in the later call in [[#h:9c9b9e3b-8771-44fa-ba9e-5056ae809655][nixosConfigurations]] or [[#h:f881aa05-a670-48dd-a57b-2916abdcb692][darwinConfigurations]]. -- =mkFullHost=: - This is a function that takes a hostname as well as a boolean whether it is NixOS or not, and returns a matching =nixosSystem= or =darwinSystem=. This function is only used for systems that can use both NixOS and home-manager options (darwin still counts here as it can use some NixOS options). This is used in mkFullHostConfigs. In more detail, it dynamically creates a nixosConfiguration host, setting its =speciaArgs= and =modules= attributes. The modules are populated based on whether this is a NixOS or darwin host. For the latter, I will only ever use machines that I get for testing from work, and for these my username is different, so I implemented an if-condition for it. This could be done more cleanly using variables, but some care needs to be taken with the home-manager imports and this approach works, so for now this is fine. Thanks to this function, the import sections of the host configs are pretty clean for most hosts. - =lib.optionals= evaluates to an empty list (=[]=) in case that the conditional is not met. -TODO - -#+begin_src nix-ts :tangle lib/default.nix - { self, lib, systems, inputs, ... }: - { - - mkIfElseList = p: yes: no: lib.mkMerge [ - (lib.mkIf p yes) - (lib.mkIf (!p) no) - ]; - - mkIfElse = p: yes: no: if p then yes else no; - - forAllSystems = lib.genAttrs [ - "x86_64-linux" - "aarch64-linux" - "x86_64-darwin" - "aarch64-darwin" - ]; - - pkgsFor = lib.genAttrs (import systems) (system: - import inputs.nixpkgs { - inherit system; - overlays = [ self.overlays.default ]; - config.allowUnfree = true; - } - ); - - toCapitalized = str: - if builtins.stringLength str == 0 then - "" - else - let - first = builtins.substring 0 1 str; - rest = builtins.substring 1 (builtins.stringLength str - 1) str; - upper = lib.toUpper first; - lower = lib.toLower rest; - in - upper + lower; - - - # mkUser = name: { - # config.users.users.${name} = { - # group = name; - # isSystemUser = true; - # }; - - # config.users.groups.${name} = {}; - # }; - - mkTrueOption = lib.mkOption { - type = lib.types.bool; - default = true; - }; - - mkStrong = lib.mkOverride 60; - - getSecret = filename: lib.strings.trim (builtins.readFile "${filename}"); - - forEachSystem = f: lib.genAttrs (import systems) (system: f lib.swarselsystems.pkgsFor.${system}); - forEachLinuxSystem = f: lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system: f lib.swarselsystems.pkgsFor.${system}); - - readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}"); - readNix = type: lib.filter (name: name != "default.nix") (lib.attrNames (builtins.readDir "${self}/${type}")); - - mkApps = system: names: self: builtins.listToAttrs (map - (name: { - inherit name; - value = { - type = "app"; - program = "${self.packages.${system}.${name}}/bin/${name}"; - meta = { - description = "Custom app ${name}."; - }; - }; - }) - names); - - mkPackages = names: pkgs: builtins.listToAttrs (map - (name: { - inherit name; - value = pkgs.callPackage "${self}/pkgs/${name}" { inherit self name; }; - }) - names); - - - mkModules = names: type: builtins.listToAttrs (map - (name: { - inherit name; - value = import "${self}/modules/${type}/${name}"; - }) - names); - - mkProfiles = names: type: builtins.listToAttrs (map - (name: { - inherit name; - value = import "${self}/profiles/${type}/${name}"; - }) - names); - - mkTemplates = names: builtins.listToAttrs (map - (name: { - inherit name; - value = { - path = "${self}/templates/${name}"; - description = "${name} project "; - }; - }) - names); - - mkImports = names: baseDir: lib.map (name: "${self}/${baseDir}/${name}") names; - - eachMonitor = _: monitor: { - inherit (monitor) name; - value = builtins.removeAttrs monitor [ "workspace" "name" "output" ]; - }; - - eachOutput = _: monitor: { - inherit (monitor) name; - value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ]; - }; - - } -#+end_src - -*** Auxiliary files -:PROPERTIES: -:CUSTOM_ID: h:23602ad9-91f6-4eba-943a-2308070fbaec -:END: -**** extra-builtins -:PROPERTIES: -:CUSTOM_ID: h:87c7893e-e946-4fc0-8973-1ca27d15cf0e -:END: - -#+begin_src nix-ts :tangle nix/extra-builtins.nix - # adapted from https://github.com/oddlama/nix-config/blob/main/nix/extra-builtins.nix - { exec, ... }: - let - assertMsg = pred: msg: pred || builtins.throw msg; - hasSuffix = - suffix: content: - let - lenContent = builtins.stringLength content; - lenSuffix = builtins.stringLength suffix; - in - lenContent >= lenSuffix && builtins.substring (lenContent - lenSuffix) lenContent content == suffix; - in - { - # Instead of calling sops directly here, we call a wrapper script that will cache the output - # in a predictable path in /tmp, which allows us to only require the password for each encrypted - # file once. - sopsImportEncrypted = - nixFile: - assert assertMsg (builtins.isPath nixFile) - "The file to decrypt must be given as a path (not a string) to prevent impurity."; - assert assertMsg (hasSuffix ".nix.enc" nixFile) - "The content of the decrypted file must be a nix expression and should therefore end in .nix.enc"; - exec [ - ./sops-decrypt-and-cache.sh - nixFile - ]; - } - -#+end_src -**** sops-decrypt-and-cache -:PROPERTIES: -:CUSTOM_ID: h:315e6ef6-27d5-4cd8-85ff-053eabe60ddb -:END: - -#+begin_src shell :tangle nix/sops-decrypt-and-cache.sh :shebang #!/usr/bin/env bash - # adapted from https://github.com/oddlama/nix-config/blob/main/nix/rage-decrypt-and-cache.sh - set -euo pipefail - - print_out_path=false - if [[ $1 == "--print-out-path" ]]; then - print_out_path=true - shift - fi - - file="$1" - shift - - basename="${file%".enc"}" - # store path prefix or ./ if applicable - [[ $file == "/nix/store/"* ]] && basename="${basename#*"-"}" - [[ $file == "./"* ]] && basename="${basename#"./"}" - - # Calculate a unique content-based identifier (relocations of - # the source file in the nix store should not affect caching) - new_name="$(sha512sum "$file")" - new_name="${new_name:0:32}-${basename//"/"/"%"}" - - # Derive the path where the decrypted file will be stored - out="/var/tmp/nix-import-encrypted/$UID/$new_name" - umask 077 - mkdir -p "$(dirname "$out")" - - # Decrypt only if necessary - if [[ ! -e $out ]]; then - agekey=$(sudo ssh-to-age -private-key -i /etc/ssh/sops || sudo ssh-to-age -private-key -i /etc/ssh/ssh_host_ed25519_key) - SOPS_AGE_KEY="$agekey" sops decrypt --output "$out" "$file" - fi - - # Print out path or decrypted content - if [[ $print_out_path == true ]]; then - echo "$out" - else - cat "$out" - fi -#+end_src -**** nix-topology -:PROPERTIES: -:CUSTOM_ID: h:46458265-074e-4368-ad9a-055877754914 -:END: - -#+begin_src nix-ts :tangle topology/default.nix - { config, ... }: - let - inherit (config.lib.topology) - mkInternet - mkDevice - mkSwitch - mkRouter - mkConnection - ; - in - { - renderer = "elk"; - - networks = { - home-lan = { - name = "Home LAN"; - cidrv4 = "192.168.1.0/24"; - }; - wg = { - name = "Wireguard Tunnel"; - cidrv4 = "192.168.3.0/24"; - }; - }; - - nodes = { - internet = mkInternet { - connections = [ - (mkConnection "moonside" "wan") - (mkConnection "pfsense" "wan") - (mkConnection "sync" "wan") - (mkConnection "toto" "bootstrapper") - (mkConnection "drugstore" "installer image") - (mkConnection "chaostheatre" "demo host") - ]; - }; - - chaostheatre.interfaces."demo host" = { }; - drugstore.interfaces."installer image" = { }; - toto.interfaces."bootstrapper" = { }; - sync.interfaces.wan = { }; - moonside.interfaces.wan = { }; - - pfsense = mkRouter "pfSense" { - info = "HUNSN RM02"; - image = ../topology/images/hunsn.png; - interfaceGroups = [ - [ - "eth2" - "eth3" - "eth4" - "eth5" - "eth6" - ] - [ "wan" ] - ]; - interfaces.wg = { - addresses = [ "192.168.3.1" ]; - network = "wg"; - virtual = true; - type = "wireguard"; - }; - - connections = { - eth2 = mkConnection "switch-livingroom" "eth1"; - eth4 = mkConnection "winters" "eth1"; - eth3 = mkConnection "switch-bedroom" "eth1"; - eth6 = mkConnection "wifi-ap" "eth1"; - wg = mkConnection "moonside" "wg"; - }; - interfaces = { - eth2 = { - addresses = [ "192.168.1.1" ]; - network = "home-lan"; - }; - eth3 = { - addresses = [ "192.168.1.1" ]; - network = "home-lan"; - }; - eth4 = { - addresses = [ "192.168.1.1" ]; - network = "home-lan"; - }; - eth6 = { - addresses = [ "192.168.1.1" ]; - network = "home-lan"; - }; - }; - }; - - winters.interfaces."eth1" = { }; - - wifi-ap = mkSwitch "Wi-Fi AP" { - info = "Huawei"; - image = ../topology/images/huawei.png; - interfaceGroups = [ - [ - "eth1" - "wifi" - ] - ]; - }; - - switch-livingroom = mkSwitch "Switch Livingroom" { - info = "TL-SG108"; - image = ../topology/images/TL-SG108.png; - interfaceGroups = [ - [ - "eth1" - "eth2" - "eth3" - "eth4" - "eth5" - "eth6" - "eth7" - "eth8" - ] - ]; - connections = { - eth2 = mkConnection "nswitch" "eth1"; - eth7 = mkConnection "pc" "eth1"; - eth8 = mkConnection "nbl-imba-2" "eth1"; - }; - }; - - nswitch = mkDevice "Nintendo Switch" { - info = "Nintendo Switch"; - image = ../topology/images/nintendo-switch.png; - interfaces.eth1 = { }; - }; - - pc = mkDevice "Windows Gaming Server" { - info = "i7-4790k, GTX970, 32GB RAM"; - image = ../topology/images/pc.png; - interfaces.eth1 = { }; - }; - - nbl-imba-2.interfaces.eth1 = { }; - - switch-bedroom = mkSwitch "Switch Bedroom" { - info = "TL-SG1005D"; - image = ../topology/images/TL-SG1005D.png; - interfaceGroups = [ - [ - "eth1" - "eth2" - "eth3" - "eth4" - "eth5" - ] - ]; - connections.eth2 = mkConnection "printer" "eth1"; - }; - - printer = mkDevice "Printer" { - info = "DELL C2665dnf"; - image = ../topology/images/DELL-C2665dnf.png; - interfaces.eth1 = { }; - }; - - }; - - } - -#+end_src -**** Globals -:PROPERTIES: -:CUSTOM_ID: h:af83893d-c0f9-4b45-b816-4849110d41b3 -:END: - -#+begin_src nix-ts :tangle nix/globals.nix - # taken from https://github.com/oddlama/nix-config/blob/main/nix/globals.nix - { inputs, ... }: - { - flake = { config, lib, ... }: - { - globals = - let - globalsSystem = lib.evalModules { - prefix = [ "globals" ]; - specialArgs = { - inherit lib; - inherit inputs; - inherit (config) nodes; - }; - modules = [ - ../modules/nixos/common/globals.nix - ./globals-general.nix - ( - { lib, ... }: - { - globals = lib.mkMerge ( - lib.concatLists ( - lib.flip lib.mapAttrsToList config.nodes ( - name: cfg: - builtins.addErrorContext "while aggregating globals from nixosConfigurations.${name} into flake-level globals:" cfg.config._globalsDefs - ) - ) - ); - } - ) - ]; - }; - in - { - # Make sure the keys of this attrset are trivially evaluatable to avoid infinite recursion, - # therefore we inherit relevant attributes from the config. - inherit (globalsSystem.config.globals) - domains - services - user - ; - }; - }; - } - -#+end_src -**** Set general global options - -This file is only loaded in the =lib.evalModules= call in [[#h:af83893d-c0f9-4b45-b816-4849110d41b3][Globals]] to load globals that do not belong to one host in particular; the structure of =globals.nix.enc= requires a toplevel =globals=. - -#+begin_src nix-ts :tangle nix/globals-general.nix - { lib, ... }: - let - # Try to access the extra builtin we loaded via nix-plugins. - # Throw an error if that doesn't exist. - sopsImportEncrypted = - assert lib.assertMsg (builtins ? extraBuiltins.sopsImportEncrypted) - "The extra builtin 'sopsImportEncrypted' is not available, so repo.secrets cannot be decrypted. Did you forget to add nix-plugins and point it to `./nix/extra-builtins.nix` ?"; - builtins.extraBuiltins.sopsImportEncrypted; - in - - { - imports = [ - (sopsImportEncrypted ../secrets/repo/globals.nix.enc) - ]; - - } - -#+end_src ** NixOS :PROPERTIES: :CUSTOM_ID: h:6da812f5-358c-49cb-aff2-0a94f20d70b3 @@ -6061,6 +3603,9 @@ This section is for setting things that should be used on hosts that are using t name = mkOption { type = types.str; }; + work = mkOption { + type = types.str; + }; }; @@ -6290,15 +3835,21 @@ A breakdown of the flags being set: We enable the use of =home-manager= as a NixoS module. A nice trick here is the =extraSpecialArgs = inputs= line, which enables the use of =seflf= in most parts of the configuration. This is useful to refer to the root of the flake (which is otherwise quite hard while maintaining flake purity). #+begin_src nix-ts :tangle modules/nixos/common/home-manager.nix - { inputs, config, lib, outputs, globals, nodes, ... }: + { self, inputs, config, lib, outputs, globals, nodes, ... }: + let + mainUser = globals.user.name; + in { - options.swarselsystems.modules.home-manager = lib.mkEnableOption "home-manager"; config = lib.mkIf config.swarselsystems.modules.home-manager { home-manager = lib.mkIf config.swarselsystems.withHomeManager { useGlobalPkgs = true; useUserPackages = true; verbose = true; + users."${mainUser}".imports = [ + "${self}/profiles/home" + "${self}/modules/home" + ]; sharedModules = [ inputs.nix-index-database.hmModules.nix-index inputs.sops-nix.homeManagerModules.sops @@ -6620,6 +4171,9 @@ Normally, doing that also resets the lecture that happens on the first use of =s #+end_src *** Client +:PROPERTIES: +:CUSTOM_ID: h:1bb03c4c-7749-47c1-9af6-1b3d748cebf4 +:END: **** Imports :PROPERTIES: :CUSTOM_ID: h:4acbe063-188b-42e7-b75c-b6d2e232e784 @@ -6628,12 +4182,15 @@ Normally, doing that also resets the lecture that happens on the first use of =s This section is for setting things that should be used on hosts that are using the default NixOS configuration. This means that servers should NOT import this, as much of these imported modules are user-configured. #+begin_src nix-ts :tangle modules/nixos/client/default.nix - { lib, ... }: + { lib, inputs, ... }: let importNames = lib.swarselsystems.readNix "modules/nixos/client"; in { - imports = lib.swarselsystems.mkImports importNames "modules/nixos/client"; + imports = lib.swarselsystems.mkImports importNames "modules/nixos/client" ++ [ + inputs.stylix.nixosModules.stylix + inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm + ]; } #+end_src @@ -11780,8 +9337,13 @@ To get other URLs (token, etc.), use https:///oauth2/openid/ /tmp/pass-fuzzel + else + pass show "$password" | { + IFS= read -r pass + printf %s "$pass" + } | wtype - + fi + else + if [[ $typeit -eq 0 ]]; then + pass otp -c "$password" &> /tmp/pass-fuzzel + else + pass otp "$password" | { + IFS= read -r pass + printf %s "$pass" + } | wtype - + fi + fi + notify-send -u critical -a pass -t 1000 "Copied/Typed Password" +#+end_src + +#+begin_src nix-ts :tangle pkgs/pass-fuzzel/default.nix + { self, name, writeShellApplication, libnotify, pass, fuzzel, wtype }: + writeShellApplication { + inherit name; + runtimeInputs = [ libnotify (pass.withExtensions (exts: [ exts.pass-otp ])) fuzzel wtype ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } + +#+end_src + +*** cura5 +:PROPERTIES: +:CUSTOM_ID: h:799579f3-ddd3-4f76-928a-a8c665980476 +:END: + +The version of =cura= used to be quite outdated in nixpkgs. I am fetching a newer AppImage here and use that instead. + + +#+begin_src nix-ts :tangle pkgs/cura5/default.nix + # taken from https://github.com/NixOS/nixpkgs/issues/186570#issuecomment-1627797219 + { appimageTools, fetchurl, writeScriptBin, pkgs, ... }: + + + let + cura5 = appimageTools.wrapType2 rec { + pname = "cura5"; + version = "5.9.0"; + src = fetchurl { + url = "https://github.com/Ultimaker/Cura/releases/download/${version}/UltiMaker-Cura-${version}-linux-X64.AppImage"; + hash = "sha256-STtVeM4Zs+PVSRO3cI0LxnjRDhOxSlttZF+2RIXnAp4="; + }; + extraPkgs = pkgs: with pkgs; [ ]; + }; + in + writeScriptBin "cura" '' + #! ${pkgs.bash}/bin/bash + # AppImage version of Cura loses current working directory and treats all paths relative to $HOME. + # So we convert each of the files passed as argument to an absolute path. + # This fixes use cases like `cd /path/to/my/files; cura mymodel.stl anothermodel.stl`. + args=() + for a in "$@"; do + if [ -e "$a" ]; then + a="$(realpath "$a")" + fi + args+=("$a") + done + exec "${cura5}/bin/cura5" "''${args[@]}" + '' + +#+end_src + +*** hm-specialisation +:PROPERTIES: +:CUSTOM_ID: h:e6612cff-0804-47ef-9f2b-d2cc6d81a896 +:END: + +This script allows for quick git home-manager specialisation switching. + + +#+begin_src nix-ts :tangle pkgs/hm-specialisation/default.nix + { name, writeShellApplication, fzf, findutils, home-manager, ... }: + + writeShellApplication { + inherit name; + runtimeInputs = [ fzf findutils home-manager ]; + text = '' + genpath=$(home-manager generations | head -1 | awk '{print $7}') + dirs=$(find "$genpath/specialisation" -type l 2>/dev/null; [ -d "$genpath" ] && echo "$genpath") + "$(echo "$dirs" | fzf --prompt="Choose home-manager specialisation to activate")"/activate + ''; + } + + +#+end_src + +*** cdw +:PROPERTIES: +:CUSTOM_ID: h:73b14c7a-5444-4fed-b7ac-d65542cdeda3 +:END: + +This script allows for quick git worktree switching. + + +#+begin_src nix-ts :tangle pkgs/cdw/default.nix + { name, writeShellApplication, fzf, ... }: + + writeShellApplication { + inherit name; + runtimeInputs = [ fzf ]; + text = '' + cd "$(git worktree list | fzf | awk '{print $1}')" + ''; + } + + +#+end_src + +*** cdb +:PROPERTIES: +:CUSTOM_ID: h:5ad99997-e54c-4f0b-9ab7-15f76b1e16e1 +:END: + +This script allows for quick git branch switching. + +#+begin_src nix-ts :tangle pkgs/cdb/default.nix + { name, writeShellApplication, fzf, ... }: + + writeShellApplication { + inherit name; + runtimeInputs = [ fzf ]; + text = '' + git checkout "$(git branch --list | grep -v "^\*" | fzf | awk '{print $1}')" + ''; + } + +#+end_src + +*** bak +:PROPERTIES: +:CUSTOM_ID: h:03b1b77b-3ca8-4a8f-8e28-9f29004d96d3 +:END: + +This script lets me quickly backup files by appending =.bak= to the filename. + + +#+begin_src nix-ts :tangle pkgs/bak/default.nix + { name, writeShellApplication, ... }: + + writeShellApplication { + inherit name; + text = '' + cp -r "$1"{,.bak} + ''; + } + + +#+end_src + +*** timer +:PROPERTIES: +:CUSTOM_ID: h:3c72d263-411c-44f0-90ff-55f14d4d9d49 +:END: + +This app starts a configuratble timer and uses TTS to say something once the timer runs out. + + +#+begin_src nix-ts :tangle pkgs/timer/default.nix + { name, writeShellApplication, speechd, ... }: + + writeShellApplication { + inherit name; + runtimeInputs = [ speechd ]; + text = '' + sleep "$1"; while true; do spd-say "$2"; sleep 0.5; done; + ''; + } + +#+end_src + +*** e +:PROPERTIES: +:CUSTOM_ID: h:1834df06-9238-4efa-9af6-851dafe66c68 +:END: + +This is a shorthand for calling emacsclient mostly. Also, it hides the kittyterm scratchpad window that I sometimes use for calling a command quickly, in case it is on the screen. After emacs closes, the kittyterm window is then shown again if it was visible earlier. + +#+begin_src shell :tangle scripts/e.sh + wait=0 + while :; do + case ${1:-} in + -w | --wait) + wait=1 + ;; + ,*) break ;; + esac + shift + done + + STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep kittyterm || true) + if [ "$STR" == "" ]; then + swaymsg '[title="kittyterm"]' scratchpad show + emacsclient -c -a "" "$@" + swaymsg '[title="kittyterm"]' scratchpad show + else + if [[ $wait -eq 0 ]]; then + emacsclient -n -c -a "" "$@" + else + emacsclient -c -a "" "$@" + fi + fi +#+end_src + +#+begin_src nix-ts :tangle pkgs/e/default.nix + { self, name, writeShellApplication, emacs30-pgtk, sway, jq }: + writeShellApplication { + inherit name; + runtimeInputs = [ emacs30-pgtk sway jq ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } + +#+end_src + +*** command-not-found +:PROPERTIES: +:CUSTOM_ID: h:10268005-a9cd-4a00-967c-cbe975c552fa +:END: + +The normal =command-not-found.sh= uses the outdated =nix-shell= commands as suggestions. This version supplies me with the more modern =nixpkgs#= version. + + +#+begin_src shell :tangle scripts/command-not-found.sh + # Adapted from https://github.com/bennofs/nix-index/blob/master/command-not-found.sh + command_not_found_handle() { + if [ -n "${MC_SID-}" ] || ! [ -t 1 ]; then + >&2 echo "$1: command not found" + return 127 + fi + + echo -n "searching nix-index..." + ATTRS=$(@nix-locate@ --minimal --no-group --type x --type s --top-level --whole-name --at-root "/bin/$1") + + case $(echo -n "$ATTRS" | grep -c "^") in + 0) + >&2 echo -ne "$(@tput@ el1)\r" + >&2 echo "$1: command not found" + ;; + ,*) + >&2 echo -ne "$(@tput@ el1)\r" + >&2 echo "The program ‘$(@tput@ setaf 4)$1$(@tput@ sgr0)’ is currently not installed." + >&2 echo "It is provided by the following derivation(s):" + while read -r ATTR; do + ATTR=${ATTR%.out} + >&2 echo " $(@tput@ setaf 12)nixpkgs#$(@tput@ setaf 4)$ATTR$(@tput@ sgr0)" + done <<< "$ATTRS" + ;; + esac + + return 127 + } + + command_not_found_handler() { + command_not_found_handle "$@" + return $? + } +#+end_src + +*** swarselcheck +:PROPERTIES: +:CUSTOM_ID: h:82f4f414-749b-4d5a-aaaa-6e3ec15fbc3d +:END: + +This app checks for different apps that I keep around in the scratchpad for quick viewing and hiding (messengers and music players mostly) and then behaves like the kittyterm hider that I described in [[#h:1834df06-9238-4efa-9af6-851dafe66c68][e]]. + +#+begin_src shell :tangle scripts/swarselcheck.sh + kitty=0 + element=0 + vesktop=0 + spotifyplayer=0 + while :; do + case ${1:-} in + -k | --kitty) + kitty=1 + ;; + -e | --element) + element=1 + ;; + -d | --vesktop) + vesktop=1 + ;; + -s | --spotifyplayer) + spotifyplayer=1 + ;; + ,*) break ;; + esac + shift + done + + if [[ $kitty -eq 1 ]]; then + STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep kittyterm || true) + CHECK=$(swaymsg -t get_tree | grep kittyterm || true) + if [ "$CHECK" == "" ]; then + exec kitty -T kittyterm -o confirm_os_window_close=0 zellij attach --create kittyterm & + sleep 1 + fi + if [ "$STR" == "" ]; then + exec swaymsg '[title="kittyterm"]' scratchpad show + else + exec swaymsg '[title="kittyterm"]' scratchpad show + fi + elif [[ $element -eq 1 ]]; then + STR=$(swaymsg -t get_tree | grep Element || true) + if [ "$STR" == "" ]; then + exec element-desktop + else + exec swaymsg '[app_id=Element]' kill + fi + elif [[ $vesktop -eq 1 ]]; then + STR=$(swaymsg -t get_tree | grep vesktop || true) + if [ "$STR" == "" ]; then + exec vesktop + else + exec swaymsg '[app_id=vesktop]' kill + fi + elif [[ $spotifyplayer -eq 1 ]]; then + STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep spotifytui || true) + CHECK=$(swaymsg -t get_tree | grep spotifytui || true) + if [ "$CHECK" == "" ]; then + exec kitty -T spotifytui -o confirm_os_window_close=0 spotify_player & + sleep 1 + fi + if [ "$STR" == "" ]; then + exec swaymsg '[title="spotifytui"]' scratchpad show + else + exec swaymsg '[title="spotifytui"]' scratchpad show + fi + fi +#+end_src + +#+begin_src nix-ts :tangle pkgs/swarselcheck/default.nix + { self, name, writeShellApplication, kitty, element-desktop, vesktop, spotify-player, jq }: + writeShellApplication { + inherit name; + runtimeInputs = [ kitty element-desktop vesktop spotify-player jq ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } + +#+end_src + +*** swarselzellij +:PROPERTIES: +:CUSTOM_ID: h:564c102c-e335-4f17-a613-c5a436bb4864 +:END: + +#+begin_src shell :tangle scripts/swarselzellij.sh + KITTIES=$(($(pgrep -P 1 kitty | wc -l) - 1)) + + if ((KITTIES < 1)); then + exec kitty -o confirm_os_window_close=0 zellij attach --create main + else + exec kitty -o confirm_os_window_close=0 zellij attach --create "temp $KITTIES" + fi +#+end_src + +#+begin_src nix-ts :tangle pkgs/swarselzellij/default.nix + { self, name, writeShellApplication, kitty }: + writeShellApplication { + inherit name; + runtimeInputs = [ kitty ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } + +#+end_src + +*** waybarupdate +:PROPERTIES: +:CUSTOM_ID: h:f93f66f9-6b8b-478e-b139-b2f382c1f25e +:END: + +This scripts checks if there are uncommited changes in either my dotfile repo, my university repo, or my passfile repo. In that case a warning will be shown in waybar. + +#+begin_src shell :tangle scripts/waybarupdate.sh + CFG=$(git --git-dir="$HOME"/.dotfiles/.git --work-tree="$HOME"/.dotfiles/ status -s | wc -l) + CSE=$(git --git-dir="$DOCUMENT_DIR_PRIV"/CSE_TUWIEN/.git --work-tree="$DOCUMENT_DIR_PRIV"/CSE_TUWIEN/ status -s | wc -l) + PASS=$(($(git --git-dir="$HOME"/.local/share/password-store/.git --work-tree="$HOME"/.local/share/password-store/ status -s | wc -l) + $(git --git-dir="$HOME"/.local/share/password-store/.git --work-tree="$HOME"/.local/share/password-store/ diff origin/main..HEAD | wc -l))) + + if [[ $CFG != 0 ]]; then + CFG_STR='CONFIG' + else + CFG_STR='' + fi + + if [[ $CSE != 0 ]]; then + CSE_STR=' CSE' + else + CSE_STR='' + fi + + if [[ $PASS != 0 ]]; then + PASS_STR=' PASS' + else + PASS_STR='' + fi + + OUT="$CFG_STR""$CSE_STR""$PASS_STR" + echo "$OUT" +#+end_src + +#+begin_src nix-ts :tangle pkgs/waybarupdate/default.nix + { self, name, writeShellApplication, git }: + writeShellApplication { + inherit name; + runtimeInputs = [ git ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } + +#+end_src + +*** opacitytoggle +:PROPERTIES: +:CUSTOM_ID: h:a1d94db2-837a-40c4-bbd8-81ce847440ee +:END: + +This app quickly toggles between 5% and 0% transparency. + +#+begin_src shell :tangle scripts/opacitytoggle.sh + if swaymsg opacity plus 0.01 -q; then + swaymsg opacity 1 + else + swaymsg opacity 0.95 + fi +#+end_src + +#+begin_src nix-ts :tangle pkgs/opacitytoggle/default.nix + { self, name, writeShellApplication, sway }: + writeShellApplication { + inherit name; + runtimeInputs = [ sway ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } +#+end_src + +*** fs-diff +:PROPERTIES: +:CUSTOM_ID: h:7c4e41b3-8c1e-4f71-87a6-30d40baed6a0 +:END: + +This utility is used to compare the current state of the root directory with the blanket state that is stored in /root-blank (the snapshot that is restored on each reboot of an impermanence machine). Using this, I can find files that I will lose once I reboot - if there are important files in that list, I can then easily add them to the persist options. + +#+begin_src shell :tangle scripts/fs-diff.sh + set -euo pipefail + + OLD_TRANSID=$(sudo btrfs subvolume find-new /mnt/root-blank 9999999) + OLD_TRANSID=${OLD_TRANSID#transid marker was } + + sudo btrfs subvolume find-new "/mnt/root" "$OLD_TRANSID" | + sed '$d' | + cut -f17- -d' ' | + sort | + uniq | + while read -r path; do + path="/$path" + if [ -L "$path" ]; then + : # The path is a symbolic link, so is probably handled by NixOS already + elif [ -d "$path" ]; then + : # The path is a directory, ignore + else + echo "$path" + fi + done +#+end_src + +#+begin_src nix-ts :tangle pkgs/fs-diff/default.nix + { self, name, writeShellApplication }: + writeShellApplication { + inherit name; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } +#+end_src + +*** github-notifications +:PROPERTIES: +:CUSTOM_ID: h:a9398c4e-4d3b-4942-b03c-192f9c0517e5 +:END: + +This utility checks if there are updated packages in nixpkgs-unstable. It does so by fully building the most recent configuration, which I do not love, but it has its merits once I am willing to switch to the newer version. + + +#+begin_src nix-ts :tangle pkgs/github-notifications/default.nix + { name, writeShellApplication, jq, ... }: + + writeShellApplication { + inherit name; + runtimeInputs = [ jq ]; + text = '' + count=$(curl -u Swarsel:"$(cat "$XDG_RUNTIME_DIR/secrets/github_notif")" https://api.github.com/notifications | jq '. | length') + + if [[ "$count" != "0" ]]; then + echo "{\"text\":\"$count\"}" + fi + ''; + } +#+end_src + +*** fullscreen +:PROPERTIES: +:CUSTOM_ID: h:9d49531a-1d9b-4600-b200-18befb5e0f3a +:END: + +This application moves the wl-mirror app to the T workspace and makes it fullscreen there. + +#+begin_src nix-ts :tangle pkgs/fullscreen/default.nix + { name, writeShellApplication, sway, ... }: + + writeShellApplication { + inherit name; + runtimeInputs = [ sway ]; + text = '' + swaymsg '[app_id=at.yrlf.wl_mirror] move to workspace 14:T' + swaymsg '[app_id=at.yrlf.wl_mirror] fullscreen' + ''; + } +#+end_src +*** screenshare +:PROPERTIES: +:CUSTOM_ID: h:960e539c-2a5a-4e21-b3d4-bcdfc8be8fda +:END: + + +#+begin_src shell :tangle scripts/screenshare.sh + + headless="false" + while [[ $# -gt 0 ]]; do + case "$1" in + -h) + headless="true" + ;; + ,*) + echo "Invalid option detected." + ;; + esac + shift + done + + SHARESCREEN="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$(hostname)".config.home-manager.users."$(whoami)".swarselsystems.sharescreen)" + + if [[ $headless == "true" ]]; then + wl-mirror "$SHARESCREEN" + else + wl-mirror "$SHARESCREEN" & + sleep 0.1 + swaymsg '[app_id=at.yrlf.wl_mirror] move to workspace 14:T' + swaymsg '[app_id=at.yrlf.wl_mirror] fullscreen' + fi +#+end_src + + +#+begin_src nix-ts :tangle pkgs/screenshare/default.nix + { self, name, writeShellApplication, sway }: + writeShellApplication { + inherit name; + runtimeInputs = [ sway ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } +#+end_src + +*** swarsel-bootstrap +:PROPERTIES: +:CUSTOM_ID: h:74db57ae-0bb9-4257-84be-eddbc85130dd +:END: + +This program sets up a new NixOS host remotely. It also takes care of secret management on the new host. + +#+begin_src shell :tangle scripts/swarsel-bootstrap.sh + # highly inspired by https://github.com/EmergentMind/nix-config/blob/dev/scripts/bootstrap-nixos.sh + set -eo pipefail + + target_hostname="" + target_destination="" + target_user="swarsel" + ssh_port="22" + persist_dir="" + disk_encryption=0 + temp=$(mktemp -d) + + function help_and_exit() { + echo + echo "Remotely installs SwarselSystem on a target machine including secret deployment." + echo + echo "USAGE: $0 -n -d [OPTIONS]" + echo + echo "ARGS:" + echo " -n specify target_hostname of the target host to deploy the nixos config on." + echo " -d specify ip or url to the target host." + echo " target during install process." + echo + echo "OPTIONS:" + echo " -u specify target_user with sudo access. nix-config will be cloned to their home." + echo " Default='${target_user}'." + echo " --port specify the ssh port to use for remote access. Default=${ssh_port}." + echo " --debug Enable debug mode." + echo " -h | --help Print this help." + exit 0 + } + + function cleanup() { + rm -rf "$temp" + } + trap cleanup exit + + function red() { + echo -e "\x1B[31m[!] $1 \x1B[0m" + if [ -n "${2-}" ]; then + echo -e "\x1B[31m[!] $($2) \x1B[0m" + fi + } + function green() { + echo -e "\x1B[32m[+] $1 \x1B[0m" + if [ -n "${2-}" ]; then + echo -e "\x1B[32m[+] $($2) \x1B[0m" + fi + } + function yellow() { + echo -e "\x1B[33m[*] $1 \x1B[0m" + if [ -n "${2-}" ]; then + echo -e "\x1B[33m[*] $($2) \x1B[0m" + fi + } + + function yes_or_no() { + echo -en "\x1B[32m[+] $* [y/n] (default: y): \x1B[0m" + while true; do + read -rp "" yn + yn=${yn:-y} + case $yn in + [Yy]*) return 0 ;; + [Nn]*) return 1 ;; + esac + done + } + + function update_sops_file() { + key_name=$1 + key_type=$2 + key=$3 + + if [ ! "$key_type" == "hosts" ] && [ ! "$key_type" == "users" ]; then + red "Invalid key type passed to update_sops_file. Must be either 'hosts' or 'users'." + exit 1 + fi + cd "${git_root}" + + SOPS_FILE=".sops.yaml" + sed -i "{ + # Remove any * and & entries for this host + /[*&]$key_name/ d; + # Inject a new age: entry + # n matches the first line following age: and p prints it, then we transform it while reusing the spacing + /age:/{n; p; s/\(.*- \*\).*/\1$key_name/}; + # Inject a new hosts or user: entry + /&$key_type/{n; p; s/\(.*- &\).*/\1$key_name $key/} + }" $SOPS_FILE + green "Updating .sops.yaml" + cd - + } + + while [[ $# -gt 0 ]]; do + case "$1" in + -n) + shift + target_hostname=$1 + ;; + -d) + shift + target_destination=$1 + ;; + -u) + shift + target_user=$1 + ;; + --port) + shift + ssh_port=$1 + ;; + --debug) + set -x + ;; + -h | --help) help_and_exit ;; + ,*) + echo "Invalid option detected." + help_and_exit + ;; + esac + shift + done + + green "~SwarselSystems~ remote installer" + green "Reading system information for $target_hostname ..." + + DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)" + green "Root Disk: $DISK" + + CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)" + if [[ $CRYPTED == "true" ]]; then + green "Encryption: ✓" + disk_encryption=1 + else + red "Encryption: X" + disk_encryption=0 + fi + + IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)" + if [[ $IMPERMANENCE == "true" ]]; then + green "Impermanence: ✓" + persist_dir="/persist" + else + red "Impermanence: X" + persist_dir="" + fi + + SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" + if [[ $SWAP == "true" ]]; then + green "Swap: ✓" + else + red "Swap: X" + fi + + SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSecureBoot)" + if [[ $SECUREBOOT == "true" ]]; then + green "Secure Boot: ✓" + else + red "Secure Boot: X" + fi + + ssh_cmd="ssh -oport=${ssh_port} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t $target_user@$target_destination" + # ssh_root_cmd=$(echo "$ssh_cmd" | sed "s|${target_user}@|root@|") # uses @ in the sed switch to avoid it triggering on the $ssh_key value + ssh_root_cmd=${ssh_cmd/${target_user}@/root@} + scp_cmd="scp -oport=${ssh_port} -o StrictHostKeyChecking=no" + + if [[ -z ${FLAKE} ]]; then + FLAKE=/home/"$target_user"/.dotfiles + fi + if [ ! -d "$FLAKE" ]; then + cd /home/"$target_user" + yellow "Flake directory not found - cloning repository from GitHub" + git clone git@github.com:Swarsel/.dotfiles.git || (yellow "Could not clone repository via SSH - defaulting to HTTPS" && git clone https://github.com/Swarsel/.dotfiles.git) + FLAKE=/home/"$target_user"/.dotfiles + fi + + cd "$FLAKE" + git_root=$(git rev-parse --show-toplevel) + # ------------------------ + green "Wiping known_hosts of $target_destination" + sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts + # ------------------------ + green "Preparing a new ssh_host_ed25519_key pair for $target_hostname." + # Create the directory where sshd expects to find the host keys + install -d -m755 "$temp/$persist_dir/etc/ssh" + # Generate host ssh key pair without a passphrase + ssh-keygen -t ed25519 -f "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" -C root@"$target_hostname" -N "" + # Set the correct permissions so sshd will accept the key + chmod 600 "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" + echo "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" + # This will fail if we already know the host, but that's fine + ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true + # ------------------------ + # when using luks, disko expects a passphrase on /tmp/disko-password, so we set it for now and will update the passphrase later + # via the config + if [ "$disk_encryption" -eq 1 ]; then + while true; do + green "Set disk encryption passphrase:" + read -rs luks_passphrase + green "Please confirm passphrase:" + read -rs luks_passphrase_confirm + if [[ $luks_passphrase == "$luks_passphrase_confirm" ]]; then + $ssh_root_cmd "/bin/sh -c 'echo $luks_passphrase > /tmp/disko-password'" + break + else + red "Passwords do not match" + fi + done + fi + # ------------------------ + green "Generating hardware-config.nix for $target_hostname and adding it to the nix-config." + $ssh_root_cmd "nixos-generate-config --force --no-filesystems --root /mnt" + + green "Injecting initialSetup" + $ssh_root_cmd "sed -i '/ boot.extraModulePackages /a \ swarselsystems.initialSetup = true;' /mnt/etc/nixos/hardware-configuration.nix" + + mkdir -p "$FLAKE"/hosts/nixos/"$target_hostname" + $scp_cmd root@"$target_destination":/mnt/etc/nixos/hardware-configuration.nix "${git_root}"/hosts/nixos/"$target_hostname"/hardware-configuration.nix + # ------------------------ + + green "Deploying minimal NixOS installation on $target_destination" + SHELL=/bin/sh nix run github:nix-community/nixos-anywhere -- --ssh-port "$ssh_port" --extra-files "$temp" --flake .#"$target_hostname" root@"$target_destination" + + echo "Updating ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" + ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true + # ------------------------ + + while true; do + read -rp "Press Enter to continue once the remote host has finished booting." + if nc -z "$target_destination" "${ssh_port}" 2> /dev/null; then + green "$target_destination is booted. Continuing..." + break + else + yellow "$target_destination is not yet ready." + fi + done + + # ------------------------ + + if [[ $SECUREBOOT == "true" ]]; then + green "Setting up secure boot keys" + $ssh_root_cmd "mkdir -p /var/lib/sbctl" + read -ra scp_call <<< "${scp_cmd}" + sudo "${scp_call[@]}" -r /var/lib/sbctl root@"$target_destination":/var/lib/ + $ssh_root_cmd "sbctl enroll-keys --ignore-immutable --microsoft || true" + fi + # ------------------------ + green "Disabling initialSetup" + sed -i '/swarselsystems\.initialSetup = true;/d' "$git_root"/hosts/nixos/"$target_hostname"/hardware-configuration.nix + + if [ -n "$persist_dir" ]; then + $ssh_root_cmd "cp /etc/machine-id $persist_dir/etc/machine-id || true" + $ssh_root_cmd "cp -R /etc/ssh/ $persist_dir/etc/ssh/ || true" + fi + # ------------------------ + green "Generating an age key based on the new ssh_host_ed25519_key." + target_key=$( + ssh-keyscan -p "$ssh_port" -t ssh-ed25519 "$target_destination" 2>&1 | + grep ssh-ed25519 | + cut -f2- -d" " || + ( + red "Failed to get ssh key. Host down?" + exit 1 + ) + ) + host_age_key=$(nix shell nixpkgs#ssh-to-age.out -c sh -c "echo $target_key | ssh-to-age") + + if grep -qv '^age1' <<< "$host_age_key"; then + red "The result from generated age key does not match the expected format." + yellow "Result: $host_age_key" + yellow "Expected format: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + exit 1 + else + echo "$host_age_key" + fi + + green "Updating nix-secrets/.sops.yaml" + update_sops_file "$target_hostname" "hosts" "$host_age_key" + yellow ".sops.yaml has been updated. There may be superfluous entries, you might need to edit manually." + if yes_or_no "Do you want to manually edit .sops.yaml now?"; then + vim "${git_root}"/.sops.yaml + fi + green "Updating all secrets files to reflect updates .sops.yaml" + sops updatekeys --yes --enable-local-keyservice "${git_root}"/secrets/*/secrets.yaml + # -------------------------- + green "Making ssh_host_ed25519_key available to home-manager for user $target_user" + sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts + $scp_cmd root@"$target_destination":/etc/ssh/ssh_host_ed25519_key root@"$target_destination":/home/"$target_user"/.ssh/ssh_host_ed25519_key + $ssh_root_cmd "mkdir -p /home/$target_user/.ssh; chown $target_user:users /home/$target_user/.ssh/ssh_host_ed25519_key" + # __________________________ + + if yes_or_no "Add ssh host fingerprints for git upstream repositories? (This is needed for building the full config)"; then + green "Adding ssh host fingerprints for git{lab,hub}" + $ssh_cmd "mkdir -p /home/$target_user/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com swagit.swarsel.win >> /home/$target_user/.ssh/known_hosts" + $ssh_root_cmd "mkdir -p /root/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com swagit.swarsel.win >> /root/.ssh/known_hosts" + fi + # -------------------------- + + if yes_or_no "Do you want to copy your full nix-config and nix-secrets to $target_hostname?"; then + green "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" + ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true + green "Copying full nix-config to $target_hostname" + cd "${git_root}" + just sync "$target_user" "$target_destination" + + if [ -n "$persist_dir" ]; then + $ssh_root_cmd "cp -r /home/$target_user/.dotfiles $persist_dir/.dotfiles || true" + $ssh_root_cmd "cp -r /home/$target_user/.ssh $persist_dir/.ssh || true" + fi + + if yes_or_no "Do you want to rebuild immediately?"; then + green "Rebuilding nix-config on $target_hostname" + yellow "Reminder: The password is 'setup'" + $ssh_root_cmd "mkdir -p /root/.local/share/nix/; printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' > /root/.local/share/nix/trusted-settings.json" + $ssh_cmd -oForwardAgent=yes "cd .dotfiles && sudo nixos-rebuild --show-trace --flake .#$target_hostname switch" + fi + else + echo + green "NixOS was successfully installed!" + echo "Post-install config build instructions:" + echo "To copy nix-config from this machine to the $target_hostname, run the following command from ~/nix-config" + echo "just sync $target_user $target_destination" + echo "To rebuild, sign into $target_hostname and run the following command from ~/nix-config" + echo "cd nix-config" + # see above FIXME:(bootstrap) + echo "sudo nixos-rebuild --show-trace --flake .#$target_hostname switch" + # echo "just rebuild" + echo + fi + + if yes_or_no "You can now commit and push the nix-config, which includes the hardware-configuration.nix for $target_hostname?"; then + cd "${git_root}" + deadnix hosts/nixos/"$target_hostname"/hardware-configuration.nix -qe + nixpkgs-fmt hosts/nixos/"$target_hostname"/hardware-configuration.nix + (pre-commit run --all-files 2> /dev/null || true) && + git add "$git_root/hosts/nixos/$target_hostname/hardware-configuration.nix" && + git add "$git_root/.sops.yaml" && + git add "$git_root/secrets" && + (git commit -m "feat: deployed $target_hostname" || true) && git push + fi +#+end_src + + +#+begin_src nix-ts :tangle pkgs/swarsel-bootstrap/default.nix + { self, name, writeShellApplication, openssh }: + writeShellApplication { + inherit name; + runtimeInputs = [ openssh ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } +#+end_src + +*** swarsel-rebuild +:PROPERTIES: +:CUSTOM_ID: h:1eabdc59-8832-44ca-a22b-11f848ab150a +:END: + +#+begin_src shell :tangle scripts/swarsel-rebuild.sh + set -eo pipefail + + target_config="chaostheatre" + target_user="swarsel" + + function help_and_exit() { + echo + echo "Builds SwarselSystem configuration." + echo + echo "USAGE: $0 [OPTIONS]" + echo + echo "ARGS:" + echo " -n specify nixos config to build." + echo " Default: chaostheatre" + echo " -u specify user to deploy for." + echo " Default: swarsel" + echo " -h | --help Print this help." + exit 0 + } + + function red() { + echo -e "\x1B[31m[!] $1 \x1B[0m" + if [ -n "${2-}" ]; then + echo -e "\x1B[31m[!] $($2) \x1B[0m" + fi + } + function green() { + echo -e "\x1B[32m[+] $1 \x1B[0m" + if [ -n "${2-}" ]; then + echo -e "\x1B[32m[+] $($2) \x1B[0m" + fi + } + function yellow() { + echo -e "\x1B[33m[*] $1 \x1B[0m" + if [ -n "${2-}" ]; then + echo -e "\x1B[33m[*] $($2) \x1B[0m" + fi + } + + while [[ $# -gt 0 ]]; do + case "$1" in + -n) + shift + target_config=$1 + ;; + -u) + shift + target_user=$1 + ;; + -h | --help) help_and_exit ;; + ,*) + echo "Invalid option detected." + help_and_exit + ;; + esac + shift + done + + cd /home/"$target_user" + + if [ ! -d /home/"$target_user"/.dotfiles ]; then + green "Cloning repository from GitHub" + git clone https://github.com/Swarsel/.dotfiles.git + else + red "A .dotfiles repository is in the way. Please (re-)move the repository and try again." + exit 1 + fi + + local_keys=$(ssh-add -L || true) + pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/keys/ssh/yubikey.pub) + read -ra pub_arr <<< "$pub_key" + + cd .dotfiles + if [[ $local_keys != *"${pub_arr[1]}"* ]]; then + yellow "The ssh key for this configuration is not available." + green "Adjusting flake.nix so that the configuration is buildable" + sed -i '/nix-secrets = {/,/^[[:space:]]*};/d' flake.nix + sed -i '/vbc-nix = {/,/^[[:space:]]*};/d' flake.nix + sed -i '/[[:space:]]*\/\/ (inputs.vbc-nix.overlays.default final prev)/d' overlays/default.nix + rm modules/home/common/env.nix + rm modules/home/common/gammastep.nix + rm modules/home/common/git.nix + rm modules/home/common/mail.nix + rm modules/home/common/yubikey.nix + rm modules/nixos/server/restic.nix + rm hosts/nixos/sync/default.nix + rm -rf modules/nixos/server + rm -rf modules/home/server + nix flake update vbc-nix + git add . + else + green "Valid SSH key found! Continuing with installation" + fi + sudo nixos-generate-config --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/ + git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/hardware-configuration.nix + + green "Installing flake $target_config" + sudo nixos-rebuild --show-trace --flake .#"$target_config" boot + yellow "Please keep in mind that this is only a demo of the configuration. Things might break unexpectedly." +#+end_src + + + +#+begin_src nix-ts :tangle pkgs/swarsel-rebuild/default.nix + { self, name, writeShellApplication, git }: + writeShellApplication { + inherit name; + runtimeInputs = [ git ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } +#+end_src + +*** swarsel-install +:PROPERTIES: +:CUSTOM_ID: h:fbd8aaf2-9dca-4ca3-aca1-19d0d188a435 +:END: + +Autoformatting always puts the =EOF= with indentation, which makes shfmt check fail. When editing this block, unindent them manually. + +#+begin_src shell :tangle scripts/swarsel-install.sh + set -eo pipefail + + target_config="chaostheatre" + target_hostname="chaostheatre" + target_user="swarsel" + persist_dir="" + target_disk="/dev/vda" + disk_encryption=0 + + function help_and_exit() { + echo + echo "Locally installs SwarselSystem on this machine." + echo + echo "USAGE: $0 -n -d [OPTIONS]" + echo + echo "ARGS:" + echo " -n specify the nixos config to deploy." + echo " Default: chaostheatre" + echo " -d specify disk to install on." + echo " Default: /dev/vda" + echo " -u specify user to deploy for." + echo " Default: swarsel" + echo " -h | --help Print this help." + exit 0 + } + + function red() { + echo -e "\x1B[31m[!] $1 \x1B[0m" + if [ -n "${2-}" ]; then + echo -e "\x1B[31m[!] $($2) \x1B[0m" + fi + } + function green() { + echo -e "\x1B[32m[+] $1 \x1B[0m" + if [ -n "${2-}" ]; then + echo -e "\x1B[32m[+] $($2) \x1B[0m" + fi + } + function yellow() { + echo -e "\x1B[33m[*] $1 \x1B[0m" + if [ -n "${2-}" ]; then + echo -e "\x1B[33m[*] $($2) \x1B[0m" + fi + } + + while [[ $# -gt 0 ]]; do + case "$1" in + -n) + shift + target_config=$1 + target_hostname=$1 + ;; + -u) + shift + target_user=$1 + ;; + -d) + shift + target_disk=$1 + ;; + -h | --help) help_and_exit ;; + ,*) + echo "Invalid option detected." + help_and_exit + ;; + esac + shift + done + + function cleanup() { + sudo rm -rf .cache/nix + sudo rm -rf /root/.cache/nix + } + trap cleanup exit + + green "~SwarselSystems~ local installer" + + cd /home/"$target_user" + + sudo rm -rf /root/.cache/nix + sudo rm -rf .cache/nix + sudo rm -rf .dotfiles + + green "Cloning repository from GitHub" + git clone https://github.com/Swarsel/.dotfiles.git + + local_keys=$(ssh-add -L || true) + pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/keys/ssh/yubikey.pub) + read -ra pub_arr <<< "$pub_key" + + cd .dotfiles + if [[ $local_keys != *"${pub_arr[1]}"* ]]; then + yellow "The ssh key for this configuration is not available." + green "Adjusting flake.nix so that the configuration is buildable ..." + sed -i '/nix-secrets = {/,/^[[:space:]]*};/d' flake.nix + sed -i '/vbc-nix = {/,/^[[:space:]]*};/d' flake.nix + sed -i '/[[:space:]]*\/\/ (inputs.vbc-nix.overlays.default final prev)/d' overlays/default.nix + rm modules/home/common/env.nix + rm modules/home/common/gammastep.nix + rm modules/home/common/git.nix + rm modules/home/common/mail.nix + rm modules/home/common/yubikey.nix + rm modules/nixos/server/restic.nix + rm hosts/nixos/sync/default.nix + rm -rf modules/nixos/server + rm -rf modules/home/server + cat > hosts/nixos/chaostheatre/options-home.nix << EOF + { self, lib, ... }: + { + options = { + swarselsystems = { + modules = { + yubikey = lib.mkEnableOption "dummy option for chaostheatre"; + env = lib.mkEnableOption "dummy option for chaostheatre"; + git = lib.mkEnableOption "dummy option for chaostheatre"; + mail = lib.mkEnableOption "dummy option for chaostheatre"; + gammastep = lib.mkEnableOption "dummy option for chaostheatre"; + }; + }; + }; + } + EOF + nix flake update vbc-nix + git add . + else + green "Valid SSH key found! Continuing with installation" + fi + + green "Reading system information for $target_config ..." + DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)" + green "Root Disk in config: $DISK - Root Disk passed in cli: $target_disk" + + CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)" + if [[ $CRYPTED == "true" ]]; then + green "Encryption: ✓" + disk_encryption=1 + else + red "Encryption: X" + disk_encryption=0 + fi + + IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)" + if [[ $IMPERMANENCE == "true" ]]; then + green "Impermanence: ✓" + persist_dir="/persist" + else + red "Impermanence: X" + persist_dir="" + fi + + SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" + if [[ $SWAP == "true" ]]; then + green "Swap: ✓" + else + red "Swap: X" + fi + + SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSecureBoot)" + if [[ $SECUREBOOT == "true" ]]; then + green "Secure Boot: ✓" + else + red "Secure Boot: X" + fi + + if [ "$disk_encryption" -eq 1 ]; then + while true; do + green "Set disk encryption passphrase:" + read -rs luks_passphrase + green "Please confirm passphrase:" + read -rs luks_passphrase_confirm + if [[ $luks_passphrase == "$luks_passphrase_confirm" ]]; then + echo "$luks_passphrase" > /tmp/disko-password + break + else + red "Passwords do not match" + fi + done + fi + + green "Setting up disk ..." + if [[ $target_config == "chaostheatre" ]]; then + sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/v1.10.0 -- --mode destroy,format,mount --flake .#"$target_config" --yes-wipe-all-disks --arg diskDevice "$target_disk" + else + sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount --flake .#"$target_config" --yes-wipe-all-disks + fi + sudo mkdir -p /mnt/"$persist_dir"/home/"$target_user"/ + sudo cp -r /home/"$target_user"/.dotfiles /mnt/"$persist_dir"/home/"$target_user"/ + sudo chown -R 1000:100 /mnt/"$persist_dir"/home/"$target_user" + + green "Generating hardware configuration ..." + sudo nixos-generate-config --root /mnt --no-filesystems --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/ + + green "Injecting initialSetup ..." + sudo sed -i '/ boot.extraModulePackages /a \ swarselsystems.initialSetup = true;' /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/hardware-configuration.nix + + git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/hardware-configuration.nix + sudo mkdir -p /root/.local/share/nix/ + printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | sudo tee /root/.local/share/nix/trusted-settings.json > /dev/null + green "Installing flake $target_config" + sudo nixos-install --flake .#"$target_config" + green "Installation finished! Reboot to see changes" +#+end_src + + + +#+begin_src nix-ts :tangle pkgs/swarsel-install/default.nix + { self, name, writeShellApplication, git }: + writeShellApplication { + inherit name; + runtimeInputs = [ git ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } +#+end_src + +*** swarsel-postinstall +:PROPERTIES: +:CUSTOM_ID: h:c98a7615-e5da-4f47-8ed1-2b2ea65519e9 +:END: + +#+begin_src shell :tangle scripts/swarsel-postinstall.sh + set -eo pipefail + + target_config="chaostheatre" + target_user="swarsel" + + function help_and_exit() { + echo + echo "Locally installs SwarselSystem on this machine." + echo + echo "USAGE: $0 -d [OPTIONS]" + echo + echo "ARGS:" + echo " -d specify disk to install on." + echo " -n specify the nixos config to deploy." + echo " Default: chaostheatre" + echo " Default: chaostheatre" + echo " -u specify user to deploy for." + echo " Default: swarsel" + echo " -h | --help Print this help." + exit 0 + } + + function green() { + echo -e "\x1B[32m[+] $1 \x1B[0m" + if [ -n "${2-}" ]; then + echo -e "\x1B[32m[+] $($2) \x1B[0m" + fi + } + + while [[ $# -gt 0 ]]; do + case "$1" in + -n) + shift + target_config=$1 + ;; + -u) + shift + target_user=$1 + ;; + -h | --help) help_and_exit ;; + ,*) + echo "Invalid option detected." + help_and_exit + ;; + esac + shift + done + + function cleanup() { + sudo rm -rf .cache/nix + sudo rm -rf /root/.cache/nix + } + trap cleanup exit + + sudo rm -rf .cache/nix + sudo rm -rf /root/.cache/nix + + green "~SwarselSystems~ remote post-installer" + + cd /home/"$target_user"/.dotfiles + + SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_config".config.swarselsystems.isSecureBoot)" + + if [[ $SECUREBOOT == "true" ]]; then + green "Setting up secure boot keys" + sudo mkdir -p /var/lib/sbctl + sbctl create-keys || true + sbctl enroll-keys --ignore-immutable --microsoft || true + fi + + green "Disabling initialSetup" + sed -i '/swarselsystems\.initialSetup = true;/d' /home/"$target_user"/.dotfiles/hosts/nixos/"$target_config"/hardware-configuration.nix + sudo nixos-rebuild --flake .#"$target_config" switch + green "Post-install finished!" +#+end_src + + + +#+begin_src nix-ts :tangle pkgs/swarsel-postinstall/default.nix + { self, name, writeShellApplication, git }: + writeShellApplication { + inherit name; + runtimeInputs = [ git ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } +#+end_src + +*** t2ts +:PROPERTIES: +:CUSTOM_ID: h:5ad99997-e54c-4f0b-9ab7-15f76b1e16e1 +:END: + +#+begin_src nix-ts :tangle pkgs/t2ts/default.nix + { name, writeShellApplication, ... }: + + writeShellApplication { + inherit name; + runtimeInputs = [ ]; + text = '' + date -d"$1" +%s + ''; + } + +#+end_src + +*** ts2t +:PROPERTIES: +:CUSTOM_ID: h:5ad99997-e54c-4f0b-9ab7-15f76b1e16e1 +:END: + +#+begin_src nix-ts :tangle pkgs/ts2t/default.nix + { name, writeShellApplication, ... }: + + writeShellApplication { + inherit name; + runtimeInputs = [ ]; + text = '' + date -d @"$1" 2>/dev/null || date -r "$1" + ''; + } + +#+end_src + +*** vershell +:PROPERTIES: +:CUSTOM_ID: h:7806b129-a4a5-4d10-af27-6cbeafbcb294 +:END: + +#+begin_src nix-ts :tangle pkgs/vershell/default.nix + { name, writeShellApplication, ... }: + + writeShellApplication { + inherit name; + runtimeInputs = [ ]; + text = '' + nix shell github:nixos/nixpkgs/"$1"#"$2"; + ''; + } + +#+end_src + +*** eontimer +:PROPERTIES: +:CUSTOM_ID: h:9fda7829-09a4-4b8f-86f6-08b078ab2874 +:END: + +#+begin_src nix-ts :tangle pkgs/eontimer/default.nix + { lib + , python3 + , fetchFromGitHub + , makeDesktopItem + , writeShellScript + , ... + }: + let + wrapper = writeShellScript "eontimer-wrapper" '' + export QT_QPA_PLATFORM=xcb + exec @out@/bin/EonTimer + ''; + in + python3.pkgs.buildPythonApplication rec { + pname = "eontimer"; + version = "3.0.0-rc.6"; + pyproject = true; + + src = fetchFromGitHub { + owner = "DasAmpharos"; + repo = "EonTimer"; + rev = version; + hash = "sha256-+XN/VGGlEg2gVncRZrWDOZ2bfxt8xyIu22F2wHlG6YI="; + }; + + build-system = [ + python3.pkgs.setuptools + python3.pkgs.wheel + ]; + + dependencies = with python3.pkgs; [ + altgraph + certifi + charset-normalizer + idna + libsass + macholib + packaging + pillow + pipdeptree + platformdirs + pyinstaller + pyinstaller-hooks-contrib + pyside6 + requests + setuptools + shiboken6 + urllib3 + ]; + + nativeBuildInputs = [ + python3.pkgs.pyinstaller + ]; + + buildPhase = '' + runHook preBuild + + pyinstaller --clean --noconfirm EonTimer.spec + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/bin + mkdir -p $out/share/applications + cp dist/EonTimer $out/bin/ + install -Dm755 -T ${wrapper} $out/bin/eontimer + substituteInPlace $out/bin/eontimer --subst-var out + + runHook postInstall + ''; + + postInstall = '' + install -Dm755 -t $out/share/applications ${ + makeDesktopItem { + name = "eontimer"; + desktopName = "EonTimer"; + comment = "Start EonTimer"; + exec = "eontimer"; + } + }/share/applications/eontimer.desktop + ''; + + + + meta = { + description = "Pokémon RNG Timer"; + homepage = "https://github.com/DasAmpharos/EonTimer"; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [ ]; + mainProgram = "eon-timer"; + }; + } + +#+end_src + +*** project +:PROPERTIES: +:CUSTOM_ID: h:154b6df4-dd50-4f60-9794-05a140d02994 +:END: + +#+begin_src shell :tangle scripts/project.sh + set -euo pipefail + + if [ ! -d "$(pwd)/.git" ]; then + git init + fi + nix flake init --template "$FLAKE"#"$1" + direnv allow +#+end_src + +#+begin_src nix-ts :tangle pkgs/project/default.nix + { self, name, writeShellApplication }: + writeShellApplication { + inherit name; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } +#+end_src + +*** fhs +:PROPERTIES: +:CUSTOM_ID: h:36d6c17c-6d91-4297-b76d-9d7feab6c1a0 +:END: + + +#+begin_src nix-ts :tangle pkgs/fhs/default.nix + { name, pkgs, ... }: + let + base = pkgs.appimageTools.defaultFhsEnvArgs; + in + pkgs.buildFHSEnv (base // { + name = "fhs"; + targetPkgs = pkgs: (base.targetPkgs pkgs) ++ [ pkgs.pkg-config ]; + profile = "export FHS=1"; + runScript = "zsh"; + extraOutputsToInstall = [ "dev" ]; + }) +#+end_src + +*** swarsel-displaypower +:PROPERTIES: +:CUSTOM_ID: h:814d5e7f-4b95-412d-b246-33f888514ec6 +:END: + +A crude script to power on all displays that might be attached. Needed because sometimes displays do not awake from sleep. + +#+begin_src shell :tangle scripts/swarsel-displaypower.sh + swaymsg "output * power on" > /dev/null 2>&1 || true + swaymsg "output * dpms on" > /dev/null 2>&1 || true +#+end_src + +#+begin_src nix-ts :tangle pkgs/swarsel-displaypower/default.nix + { self, name, writeShellApplication, sway }: + writeShellApplication { + inherit name; + runtimeInputs = [ sway ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } + +#+end_src + +*** swarsel-mgba +:PROPERTIES: +:CUSTOM_ID: h:799579f3-ddd3-4f76-928a-a8c665980476 +:END: + +AppImage version of mgba in which the lua scripting works. + + +#+begin_src nix-ts :tangle pkgs/swarsel-mgba/default.nix + { appimageTools, fetchurl, ... }: + let + pname = "mgba"; + version = "0.10.4"; + src = fetchurl { + url = "https://github.com/mgba-emu/mgba/releases/download/${version}/mGBA-${version}-appimage-x64.appimage"; + hash = "sha256-rDihDfuA8DqxvCe6UeavCzpjeU+fSqUbFnyTNC2dc1I="; + }; + appimageContents = appimageTools.extractType2 { inherit pname version src; }; + in + appimageTools.wrapType2 { + inherit pname version src; + extraInstallCommands = '' + install -Dm444 ${appimageContents}/io.mgba.mGBA.desktop -t $out/share/applications + substituteInPlace $out/share/applications/io.mgba.mGBA.desktop \ + --replace-fail 'Exec=mgba-qt %f' 'Exec=mgba' + cp -r ${appimageContents}/usr/share/icons $out/share + ''; + + } + +#+end_src + +*** swarsel-deploy +:PROPERTIES: +:CUSTOM_ID: h:c3362d4e-d3a8-43e8-9ef7-272b6de0572e +:END: + +#+begin_src nix-ts :tangle pkgs/swarsel-deploy/default.nix + # heavily inspired from https://github.com/oddlama/nix-config/blob/d42cbde676001a7ad8a3cace156e050933a4dcc3/pkgs/deploy.nix + { name, bc, nix-output-monitor, writeShellApplication, ... }: + writeShellApplication { + runtimeInputs = [ bc nix-output-monitor ]; + inherit name; + text = '' + set -euo pipefail + shopt -s lastpipe # allow cmd | readarray + + function die() { + echo "error: $*" >&2 + exit 1 + } + function show_help() { + echo 'Usage: deploy [OPTIONS] [ACTION]' + echo "Builds, pushes and activates nixosConfigurations on target systems." + echo "" + echo 'ACTION:' + echo ' switch [default] Switch immediately to the new configuration and make it the boot default' + echo ' boot Make the configuration the new boot default' + echo " test Activate the configuration but don't make it the boot default" + echo " dry-activate Don't activate, just show what would be done" + echo "" + echo 'OPTIONS: [passed to nix build]' + } + + function time_start() { + T_START=$(date +%s.%N) + } + + function time_next() { + T_END=$(date +%s.%N) + T_LAST=$(${bc}/bin/bc <<< "scale=1; ($T_END - $T_START)/1") + T_START="$T_END" + } + + USER_FLAKE_DIR=$(git rev-parse --show-toplevel 2> /dev/null || pwd) || + die "Could not determine current working directory. Something went very wrong." + [[ -e "$USER_FLAKE_DIR/flake.nix" ]] || + die "Could not determine location of your project's flake.nix. Please run this at or below your main directory containing the flake.nix." + cd "$USER_FLAKE_DIR" + + [[ $# -gt 0 ]] || { + show_help + exit 1 + } + + OPTIONS=() + POSITIONAL_ARGS=() + while [[ $# -gt 0 ]]; do + case "$1" in + "help" | "--help" | "-help" | "-h") + show_help + exit 1 + ;; + + -*) OPTIONS+=("$1") ;; + ,*) POSITIONAL_ARGS+=("$1") ;; + esac + shift + done + + [[ ''${#POSITIONAL_ARGS[@]} -ge 1 ]] || + die "Missing argument: " + [[ ''${#POSITIONAL_ARGS[@]} -le 2 ]] || + die "Too many arguments given." + + tr , '\n' <<< "''${POSITIONAL_ARGS[0]}" | sort -u | readarray -t HOSTS + ACTION="''${POSITIONAL_ARGS[1]-switch}" + + # Expand flake paths for hosts definitions + declare -A TOPLEVEL_FLAKE_PATHS + for host in "''${HOSTS[@]}"; do + TOPLEVEL_FLAKE_PATHS["$host"]=".#nixosConfigurations.$host.config.system.build.toplevel" + done + + time_start + + # Get outputs of all derivations (should be cached) + declare -A TOPLEVEL_STORE_PATHS + for host in "''${HOSTS[@]}"; do + toplevel="''${TOPLEVEL_FLAKE_PATHS["$host"]}" + # Make sudo call to get prompt out of the way + sudo echo " Building 📦 $host" + nix build --no-link "''${OPTIONS[@]}" --show-trace --log-format internal-json -v "$toplevel" |& ${nix-output-monitor}/bin/nom --json || + die "Failed to get derivation path for $host from ''${TOPLEVEL_FLAKE_PATHS["$host"]}" + TOPLEVEL_STORE_PATHS["$host"]=$(nix build --no-link --print-out-paths "''${OPTIONS[@]}" "$toplevel") + time_next + echo " Built ✅ $host ''${TOPLEVEL_STORE_PATHS["$host"]} in ''${T_LAST}s" + done + + current_host=$(hostname) + + for host in "''${HOSTS[@]}"; do + store_path="''${TOPLEVEL_STORE_PATHS["$host"]}" + + if [ "$host" = "$current_host" ]; then + echo -e "\033[1;36m Running locally for $host... \033[m" + ssh_prefix="sudo" + else + echo -e "\033[1;36m Copying \033[m➡️ \033[34m$host\033[m" + nix copy --to "ssh://$host" "$store_path" + time_next + echo -e "\033[1;32m Copied \033[m✅ \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m" + ssh_prefix="ssh $host --" + fi + + echo -e "\033[1;36m Applying \033[m⚙️ \033[34m$host\033[m" + prev_system=$($ssh_prefix readlink -e /nix/var/nix/profiles/system) + $ssh_prefix /run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set "$store_path" || + die "Failed to set system profile" + $ssh_prefix "$store_path"/bin/switch-to-configuration "$ACTION" || + echo "Error while activating new system" >&2 + + if [[ -n $prev_system ]]; then + $ssh_prefix nvd --color always diff "$prev_system" "$store_path" || true + fi + + time_next + echo -e "\033[1;32m Applied \033[m✅ \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m" + done + ''; + } + +#+end_src + +*** swarsel-build +:PROPERTIES: +:CUSTOM_ID: h:c3362d4e-d3a8-43e8-9ef7-272b6de0572e +:END: + +#+begin_src nix-ts :tangle pkgs/swarsel-build/default.nix + { name, nix-output-monitor, writeShellApplication, ... }: + writeShellApplication { + runtimeInputs = [ nix-output-monitor ]; + inherit name; + text = '' + set -euo pipefail + [[ "$#" -ge 1 ]] \ + || { echo "usage: build ..." >&2; exit 1; } + HOSTS=() + for h in "$@"; do + HOSTS+=(".#nixosConfigurations.$h.config.system.build.toplevel") + done + nom build --no-link --print-out-paths --show-trace "''${HOSTS[@]}" + ''; + } + +#+end_src + +*** sshrm +:PROPERTIES: +:CUSTOM_ID: h:02842543-caca-4d4c-a4d2-7ac749b5c136 +:END: + +This programs simply runs ssh-keygen on the last host that I tried to ssh into. I need this frequently when working with cloud-init usually. + +#+begin_src shell :tangle scripts/sshrm.sh + HISTFILE="$HOME"/.histfile + + last_ssh_cmd=$(grep -E "ssh " "$HISTFILE" | sed -E 's/^: [0-9]+:[0-9]+;//' | grep "^ssh " | tail -1) + host=$(echo "$last_ssh_cmd" | sed -E 's/.*ssh ([^@ ]+@)?([^ ]+).*/\2/') + + if [[ -n $host ]]; then + echo "Removing SSH host key for: $host" + ssh-keygen -R "$host" + else + echo "No valid SSH command found in history." + fi +#+end_src + +#+begin_src nix-ts :tangle pkgs/sshrm/default.nix + { self, name, writeShellApplication, openssh }: + writeShellApplication { + inherit name; + runtimeInputs = [ openssh ]; + text = builtins.readFile "${self}/scripts/${name}.sh"; + } +#+end_src +** Profiles +:PROPERTIES: +:CUSTOM_ID: h:f0f1c961-3e7a-47b8-99ab-1654bb45dffc +:END: + +In this section I define custom modules under the =swarsel= attribute. These are mostly used to define settings specific to a host. I keep these settings confined to either home-manager or nixos to maintain compatibility with non-NixOS machines. + +Note: The structure of generating the packages was changed in commit =2cf03a3 refactor: package and module generation=. That commit can be checked out in order to see a simpler version of achieving the same thing. + +*** NixOS +:PROPERTIES: +:CUSTOM_ID: h:14e68518-8ec7-48ec-b208-0e3d6d49954d +:END: + +Modules that need to be loaded on the NixOS level. Note that these will not be available on systems that are not running NixOS. + +#+begin_src nix-ts :tangle profiles/nixos/default.nix + { lib, ... }: + let + profileNames = lib.swarselsystems.readNix "profiles/nixos"; + in + { + imports = lib.swarselsystems.mkImports profileNames "profiles/nixos"; + } +#+end_src +**** Personal +:PROPERTIES: +:CUSTOM_ID: h:32d654de-8db2-403a-9a27-4c46d7b9172d +:END: + +#+begin_src nix-ts :tangle profiles/nixos/personal/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.personal = lib.mkEnableOption "is this a personal host"; + config = lib.mkIf config.swarselsystems.profiles.personal { + swarselsystems.modules = { + packages = lib.mkDefault true; + general = lib.mkDefault true; + home-manager = lib.mkDefault true; + xserver = lib.mkDefault true; + users = lib.mkDefault true; + env = lib.mkDefault true; + security = lib.mkDefault true; + systemdTimeout = lib.mkDefault true; + hardware = lib.mkDefault true; + pulseaudio = lib.mkDefault true; + pipewire = lib.mkDefault true; + network = lib.mkDefault true; + time = lib.mkDefault true; + sops = lib.mkDefault true; + pii = lib.mkDefault true; + stylix = lib.mkDefault true; + programs = lib.mkDefault true; + zsh = lib.mkDefault true; + syncthing = lib.mkDefault true; + blueman = lib.mkDefault true; + networkDevices = lib.mkDefault true; + gvfs = lib.mkDefault true; + interceptionTools = lib.mkDefault true; + swayosd = lib.mkDefault true; + ppd = lib.mkDefault true; + yubikey = lib.mkDefault true; + ledger = lib.mkDefault true; + keyboards = lib.mkDefault true; + login = lib.mkDefault true; + nix-ld = lib.mkDefault true; + impermanence = lib.mkDefault true; + nvd = lib.mkDefault true; + gnome-keyring = lib.mkDefault true; + sway = lib.mkDefault true; + xdg-portal = lib.mkDefault true; + distrobox = lib.mkDefault true; + appimage = lib.mkDefault true; + lid = lib.mkDefault true; + lowBattery = lib.mkDefault true; + lanzaboote = lib.mkDefault true; + autologin = lib.mkDefault true; + + optional = { + gaming = lib.mkDefault true; + virtualbox = lib.mkDefault true; + nswitch-rcm = lib.mkDefault true; + }; + + server = { + ssh = lib.mkDefault true; + }; + }; + + }; + + } + +#+end_src + +**** Chaostheatre +:PROPERTIES: +:CUSTOM_ID: h:b79fbb59-9cf2-48eb-b469-2589223dda95 +:END: + +#+begin_src nix-ts :tangle profiles/nixos/chaostheatre/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.chaostheatre = lib.mkEnableOption "is this a chaostheatre host"; + config = lib.mkIf config.swarselsystems.profiles.chaostheatre { + swarselsystems.modules = { + packages = lib.mkDefault true; + general = lib.mkDefault true; + home-manager = lib.mkDefault true; + xserver = lib.mkDefault true; + users = lib.mkDefault true; + env = lib.mkDefault true; + security = lib.mkDefault true; + systemdTimeout = lib.mkDefault true; + hardware = lib.mkDefault true; + pulseaudio = lib.mkDefault true; + pipewire = lib.mkDefault true; + network = lib.mkDefault true; + time = lib.mkDefault true; + sops = lib.mkDefault false; + stylix = lib.mkDefault true; + programs = lib.mkDefault true; + zsh = lib.mkDefault true; + syncthing = lib.mkDefault true; + blueman = lib.mkDefault true; + networkDevices = lib.mkDefault true; + gvfs = lib.mkDefault true; + interceptionTools = lib.mkDefault true; + swayosd = lib.mkDefault true; + ppd = lib.mkDefault true; + yubikey = lib.mkDefault true; + ledger = lib.mkDefault true; + keyboards = lib.mkDefault true; + login = lib.mkDefault true; + nix-ld = lib.mkDefault true; + impermanence = lib.mkDefault true; + nvd = lib.mkDefault true; + gnome-keyring = lib.mkDefault true; + sway = lib.mkDefault true; + xdg-portal = lib.mkDefault true; + distrobox = lib.mkDefault true; + appimage = lib.mkDefault true; + lid = lib.mkDefault true; + lowBattery = lib.mkDefault true; + lanzaboote = lib.mkDefault true; + autologin = lib.mkDefault true; + }; + + }; + + } + +#+end_src + +**** toto +:PROPERTIES: +:CUSTOM_ID: h:125443fb-deb6-44c9-83ee-bbd10daf78dd +:END: + +#+begin_src nix-ts :tangle profiles/nixos/toto/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.toto = lib.mkEnableOption "is this a toto (setup) host"; + config = lib.mkIf config.swarselsystems.profiles.toto { + swarselsystems.modules = { + general = lib.mkDefault true; + home-manager = lib.mkDefault true; + xserver = lib.mkDefault true; + users = lib.mkDefault true; + sops = lib.mkDefault true; + impermanence = lib.mkDefault true; + lanzaboote = lib.mkDefault true; + autologin = lib.mkDefault true; + server = { + ssh = lib.mkDefault true; + }; + }; + + }; + + } + +#+end_src + +**** Work +:PROPERTIES: +:CUSTOM_ID: h:cb3631a8-9c1b-42f2-ab01-502c7b4c273d +:END: + +#+begin_src nix-ts :tangle profiles/nixos/work/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.work = lib.mkEnableOption "is this a work host"; + config = lib.mkIf config.swarselsystems.profiles.work { + swarselsystems.modules = { + optional = { + work = lib.mkDefault true; + }; + }; + + }; + + } + +#+end_src + +**** Framework +:PROPERTIES: +:CUSTOM_ID: h:eb272c99-842a-4095-bc65-283562749300 +:END: + +#+begin_src nix-ts :tangle profiles/nixos/framework/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.framework = lib.mkEnableOption "is this a framework brand host"; + config = lib.mkIf config.swarselsystems.profiles.framework { + swarselsystems.modules = { + optional = { + framework = lib.mkDefault true; + }; + }; + + }; + + } + +#+end_src + +**** AMD CPU +:PROPERTIES: +:CUSTOM_ID: h:b7beb4a5-8808-438d-8799-7f08f38fd1ba +:END: + +#+begin_src nix-ts :tangle profiles/nixos/amdcpu/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.amdcpu = lib.mkEnableOption "is this a host with amd cpu"; + config = lib.mkIf config.swarselsystems.profiles.amdcpu { + swarselsystems.modules = { + optional = { + amdcpu = lib.mkDefault true; + }; + }; + + }; + + } + +#+end_src + +**** AMD GPU +:PROPERTIES: +:CUSTOM_ID: h:79c71b6d-a1ad-447d-8940-bb5bfd71dced +:END: + +#+begin_src nix-ts :tangle profiles/nixos/amdgpu/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.amdgpu = lib.mkEnableOption "is this a host with amd gpu"; + config = lib.mkIf config.swarselsystems.profiles.amdgpu { + swarselsystems.modules = { + optional = { + amdgpu = lib.mkDefault true; + }; + }; + + }; + + } + +#+end_src + +**** Hibernation +:PROPERTIES: +:CUSTOM_ID: h:641d0a2a-0592-448a-a6e3-d0a9c330293e +:END: + +#+begin_src nix-ts :tangle profiles/nixos/hibernation/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.hibernation = lib.mkEnableOption "is this a host using hibernation"; + config = lib.mkIf config.swarselsystems.profiles.hibernation { + swarselsystems.modules = { + optional = { + hibernation = lib.mkDefault true; + }; + }; + + }; + + } + +#+end_src + +**** BTRFS +:PROPERTIES: +:CUSTOM_ID: h:0bb401e3-b195-4ff2-bc74-23c5a54d83d2 +:END: + +#+begin_src nix-ts :tangle profiles/nixos/btrfs/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.btrfs = lib.mkEnableOption "is this a host using btrfs"; + config = lib.mkIf config.swarselsystems.profiles.btrfs { + swarselsystems.modules = { + optional = { + btrfs = lib.mkDefault true; + }; + }; + + }; + + } + +#+end_src + +**** Local Server +:PROPERTIES: +:CUSTOM_ID: h:dfc076fd-ee74-4663-b164-653370c52b75 +:END: + +#+begin_src nix-ts :tangle profiles/nixos/localserver/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.server.local = lib.mkEnableOption "is this a local server"; + config = lib.mkIf config.swarselsystems.profiles.server.local { + swarselsystems = { + modules = { + general = lib.mkDefault true; + pii = lib.mkDefault true; + home-manager = lib.mkDefault true; + xserver = lib.mkDefault true; + time = lib.mkDefault true; + users = lib.mkDefault true; + sops = lib.mkDefault true; + server = { + general = lib.mkDefault true; + packages = lib.mkDefault true; + nfs = lib.mkDefault true; + nginx = lib.mkDefault true; + ssh = lib.mkDefault true; + kavita = lib.mkDefault true; + restic = lib.mkDefault true; + jellyfin = lib.mkDefault true; + navidrome = lib.mkDefault true; + spotifyd = lib.mkDefault true; + mpd = lib.mkDefault true; + postgresql = lib.mkDefault true; + matrix = lib.mkDefault true; + nextcloud = lib.mkDefault true; + immich = lib.mkDefault true; + paperless = lib.mkDefault true; + transmission = lib.mkDefault true; + syncthing = lib.mkDefault true; + grafana = lib.mkDefault true; + emacs = lib.mkDefault true; + freshrss = lib.mkDefault true; + jenkins = lib.mkDefault false; + kanidm = lib.mkDefault true; + firefly-iii = lib.mkDefault true; + koillection = lib.mkDefault true; + radicale = lib.mkDefault true; + atuin = lib.mkDefault true; + }; + }; + }; + }; + + } + +#+end_src +**** OCI Sync Server +:PROPERTIES: +:CUSTOM_ID: h:9b7b50d1-57ad-41ca-94ab-74393aae01bf +:END: + +#+begin_src nix-ts :tangle profiles/nixos/syncserver/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.server.sync = lib.mkEnableOption "is this a oci sync server"; + config = lib.mkIf config.swarselsystems.profiles.server.sync { + swarselsystems = { + modules = { + general = lib.mkDefault true; + nix-ld = lib.mkDefault true; + pii = lib.mkDefault true; + home-manager = lib.mkDefault true; + xserver = lib.mkDefault true; + time = lib.mkDefault true; + users = lib.mkDefault true; + sops = lib.mkDefault true; + server = { + general = lib.mkDefault true; + packages = lib.mkDefault true; + nginx = lib.mkDefault true; + ssh = lib.mkDefault true; + forgejo = lib.mkDefault true; + ankisync = lib.mkDefault true; + }; + }; + }; + }; + + } + +#+end_src +**** Moonside +:PROPERTIES: +:CUSTOM_ID: h:cc780ef2-7e5e-4835-b659-c731b306a320 +:END: + +#+begin_src nix-ts :tangle profiles/nixos/moonside/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.server.moonside = lib.mkEnableOption "is this a moonside server"; + config = lib.mkIf config.swarselsystems.profiles.server.moonside { + swarselsystems = { + modules = { + general = lib.mkDefault true; + pii = lib.mkDefault true; + home-manager = lib.mkDefault true; + xserver = lib.mkDefault true; + time = lib.mkDefault true; + users = lib.mkDefault true; + impermanence = lib.mkDefault true; + sops = lib.mkDefault true; + server = { + general = lib.mkDefault true; + packages = lib.mkDefault true; + nginx = lib.mkDefault true; + ssh = lib.mkDefault true; + oauth2-proxy = lib.mkDefault true; + croc = lib.mkDefault true; + microbin = lib.mkDefault true; + shlink = lib.mkDefault true; + }; + }; + }; + }; + + } + +#+end_src +*** home-manager +:PROPERTIES: +:CUSTOM_ID: h:ced5841f-c088-4d88-b3a1-7d62aad8837b +:END: + +This holds modules that are to be used on most hosts. These are also the most important options to configure, as these allow me easy access to monitor, keyboard, and other setups. + +#+BEGIN_src nix-ts :tangle profiles/home/default.nix + { lib, ... }: + let + profileNames = lib.swarselsystems.readNix "profiles/home"; + in + { + imports = lib.swarselsystems.mkImports profileNames "profiles/home"; + } +#+end_src + +**** Personal +:PROPERTIES: +:CUSTOM_ID: h:26512487-8c29-4b92-835b-d67394c3f5ef +:END: + +#+begin_src nix-ts :tangle profiles/home/personal/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.personal = lib.mkEnableOption "is this a personal host"; + config = lib.mkIf config.swarselsystems.profiles.personal { + swarselsystems.modules = { + packages = lib.mkDefault true; + ownpackages = lib.mkDefault true; + general = lib.mkDefault true; + nixgl = lib.mkDefault true; + sops = lib.mkDefault true; + yubikey = lib.mkDefault true; + ssh = lib.mkDefault true; + stylix = lib.mkDefault true; + desktop = lib.mkDefault true; + symlink = lib.mkDefault true; + env = lib.mkDefault true; + programs = lib.mkDefault true; + nix-index = lib.mkDefault true; + passwordstore = lib.mkDefault true; + direnv = lib.mkDefault true; + eza = lib.mkDefault true; + atuin = lib.mkDefault true; + git = lib.mkDefault true; + fuzzel = lib.mkDefault true; + starship = lib.mkDefault true; + kitty = lib.mkDefault true; + zsh = lib.mkDefault true; + zellij = lib.mkDefault true; + tmux = lib.mkDefault true; + mail = lib.mkDefault true; + emacs = lib.mkDefault true; + waybar = lib.mkDefault true; + firefox = lib.mkDefault true; + gnome-keyring = lib.mkDefault true; + kdeconnect = lib.mkDefault true; + mako = lib.mkDefault true; + swayosd = lib.mkDefault true; + yubikeytouch = lib.mkDefault true; + sway = lib.mkDefault true; + kanshi = lib.mkDefault true; + gpgagent = lib.mkDefault true; + gammastep = lib.mkDefault true; + + optional = { + gaming = lib.mkDefault true; + }; + }; + }; + + } + +#+end_src + +**** Chaostheatre +:PROPERTIES: +:CUSTOM_ID: h:36a0209f-2c17-4808-a1d0-a9e1920c307a +:END: + +#+begin_src nix-ts :tangle profiles/home/chaostheatre/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.chaostheatre = lib.mkEnableOption "is this a chaostheatre host"; + config = lib.mkIf config.swarselsystems.profiles.chaostheatre { + swarselsystems.modules = { + packages = lib.mkDefault true; + ownpackages = lib.mkDefault true; + general = lib.mkDefault true; + nixgl = lib.mkDefault true; + sops = lib.mkDefault true; + yubikey = lib.mkDefault false; + ssh = lib.mkDefault true; + stylix = lib.mkDefault true; + desktop = lib.mkDefault true; + symlink = lib.mkDefault true; + env = lib.mkDefault false; + programs = lib.mkDefault true; + nix-index = lib.mkDefault true; + direnv = lib.mkDefault true; + eza = lib.mkDefault true; + git = lib.mkDefault false; + fuzzel = lib.mkDefault true; + starship = lib.mkDefault true; + kitty = lib.mkDefault true; + zsh = lib.mkDefault true; + zellij = lib.mkDefault true; + tmux = lib.mkDefault true; + mail = lib.mkDefault false; + emacs = lib.mkDefault true; + waybar = lib.mkDefault true; + firefox = lib.mkDefault true; + gnome-keyring = lib.mkDefault true; + kdeconnect = lib.mkDefault true; + mako = lib.mkDefault true; + swayosd = lib.mkDefault true; + yubikeytouch = lib.mkDefault true; + sway = lib.mkDefault true; + kanshi = lib.mkDefault true; + gpgagent = lib.mkDefault true; + gammastep = lib.mkDefault false; + }; + }; + + } + +#+end_src + +**** toto +:PROPERTIES: +:CUSTOM_ID: h:e1d4f141-af11-448a-9796-fc822a8f77ec +:END: + +#+begin_src nix-ts :tangle profiles/home/toto/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.toto = lib.mkEnableOption "is this a toto (setup) host"; + config = lib.mkIf config.swarselsystems.profiles.toto { + swarselsystems.modules = { + general = lib.mkDefault true; + sops = lib.mkDefault true; + ssh = lib.mkDefault true; + }; + }; + + } + +#+end_src + +**** Work +:PROPERTIES: +:CUSTOM_ID: h:7b091523-a5b0-48b6-8b03-4dc2405e2d81 +:END: + +#+begin_src nix-ts :tangle profiles/home/work/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.work = lib.mkEnableOption "is this a work host"; + config = lib.mkIf config.swarselsystems.profiles.work { + swarselsystems.modules = { + optional = { + work = lib.mkDefault true; + }; + }; + }; + + } + +#+end_src + +**** Framework +:PROPERTIES: +:CUSTOM_ID: h:712b9d7f-16c0-42b3-b02b-6d79ee15cfcc +:END: + +#+begin_src nix-ts :tangle profiles/home/framework/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.framework = lib.mkEnableOption "is this a framework brand host"; + config = lib.mkIf config.swarselsystems.profiles.framework { + swarselsystems.modules = { + optional = { + framework = lib.mkDefault true; + }; + }; + + }; + + } + +#+end_src + +**** Darwin +:PROPERTIES: +:CUSTOM_ID: h:24e6d661-f498-478c-9008-e8d8c17432ca +:END: + +#+begin_src nix-ts :tangle profiles/home/darwin/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.darwin = lib.mkEnableOption "is this a darwin host"; + config = lib.mkIf config.swarselsystems.profiles.darwin { + swarselsystems.modules = { + general = lib.mkDefault true; + }; + }; + + } + +#+end_src + +**** Local Server +:PROPERTIES: +:CUSTOM_ID: h:8027b858-369e-4f12-bbaf-f15eeee3d904 +:END: + +#+begin_src nix-ts :tangle profiles/home/localserver/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselsystems.profiles.server.local = lib.mkEnableOption "is this a local server"; + config = lib.mkIf config.swarselsystems.profiles.server.local { + swarselsystems.modules = { + general = lib.mkDefault true; + server = { + dotfiles = lib.mkDefault true; + }; + }; + }; + + } + +#+end_src * Emacs :PROPERTIES: diff --git a/checks/default.nix b/checks/default.nix deleted file mode 100644 index 4830423..0000000 --- a/checks/default.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ self, inputs, pkgs, system, ... }: -{ - pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run { - src = "${self}"; - hooks = { - check-added-large-files.enable = true; - check-case-conflicts.enable = true; - check-executables-have-shebangs.enable = true; - check-shebang-scripts-are-executable.enable = false; - check-merge-conflicts.enable = true; - deadnix.enable = true; - detect-private-keys.enable = true; - end-of-file-fixer.enable = true; - fix-byte-order-marker.enable = true; - flake-checker.enable = true; - forbid-new-submodules.enable = true; - mixed-line-endings.enable = true; - nixpkgs-fmt.enable = true; - statix.enable = true; - trim-trailing-whitespace.enable = true; - - destroyed-symlinks = { - enable = true; - entry = "${inputs.pre-commit-hooks.checks.${system}.pre-commit-hooks}/bin/destroyed-symlinks"; - }; - - shellcheck = { - enable = true; - entry = "${pkgs.shellcheck}/bin/shellcheck --shell=bash"; - }; - - shfmt = { - enable = true; - entry = "${pkgs.shfmt}/bin/shfmt -i 4 -sr -d -s -l"; - }; - - }; - }; -} diff --git a/flake.lock b/flake.lock index fc7e793..76d3b20 100644 --- a/flake.lock +++ b/flake.lock @@ -98,6 +98,26 @@ } }, "devshell": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1741473158, + "narHash": "sha256-kWNaq6wQUbUMlPgw8Y+9/9wP0F8SHkjy24/mN3UAppg=", + "owner": "numtide", + "repo": "devshell", + "rev": "7c9e793ebe66bcba8292989a68c0419b737a22a0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, + "devshell_2": { "inputs": { "nixpkgs": [ "nix-topology", @@ -836,7 +856,7 @@ }, "nix-topology": { "inputs": { - "devshell": "devshell", + "devshell": "devshell_2", "flake-utils": "flake-utils", "nixpkgs": "nixpkgs_3", "pre-commit-hooks": "pre-commit-hooks" @@ -1420,6 +1440,7 @@ }, "root": { "inputs": { + "devshell": "devshell", "disko": "disko", "emacs-overlay": "emacs-overlay", "flake-parts": "flake-parts", diff --git a/flake.nix b/flake.nix index 7f6c149..cee0490 100644 --- a/flake.nix +++ b/flake.nix @@ -12,7 +12,6 @@ ]; }; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; nixpkgs-kernel.url = "github:NixOS/nixpkgs/063f43f2dbdef86376cc29ad646c45c46e93234c?narHash=sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o%3D"; #specifically pinned for kernel version nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.05"; @@ -84,196 +83,27 @@ }; nix-topology.url = "github:oddlama/nix-topology"; flake-parts.url = "github:hercules-ci/flake-parts"; + devshell = { + url = "github:numtide/devshell"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = - inputs@{ self - , nixpkgs - , home-manager - , systems - , ... - }: - let - - inherit (self) outputs; - lib = (nixpkgs.lib // home-manager.lib).extend (_: _: { swarselsystems = import ./lib { inherit self lib inputs outputs systems; }; }); - - in + inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } { imports = [ ./nix/globals.nix + ./nix/hosts.nix + ./nix/topology.nix + ./nix/devshell.nix + ./nix/apps.nix + ./nix/packages.nix + ./nix/overlays.nix + ./nix/lib.nix + ./nix/templates.nix + ./nix/formatter.nix + ./nix/modules.nix ]; - flake = { config, ... }: - let - - inherit (self) outputs; - lib = (nixpkgs.lib // home-manager.lib).extend (_: _: { swarselsystems = import ./lib { inherit self lib inputs outputs systems; }; }); - - - linuxUser = "swarsel"; - macUser = "leon.schwarzaeugl"; - - mkFullHost = host: type: { - ${host} = - let - systemFunc = if (type == "nixos") then lib.nixosSystem else inputs.nix-darwin.lib.darwinSystem; - in - systemFunc { - specialArgs = { inherit inputs outputs lib self; inherit (config) globals; }; - modules = [ - { - node.name = host; - node.secretsDir = ./hosts/${type}/${host}/secrets; - } - # put inports here that are for all hosts - inputs.disko.nixosModules.disko - inputs.sops-nix.nixosModules.sops - inputs.impermanence.nixosModules.impermanence - inputs.lanzaboote.nixosModules.lanzaboote - inputs.fw-fanctrl.nixosModules.default - inputs.nix-topology.nixosModules.default - inputs.home-manager.nixosModules.home-manager - "${self}/hosts/${type}/${host}" - { - _module.args.primaryUser = linuxUser; - } - ] ++ - (if (host == "iso") then [ - ] else - ([ - # put nixos imports here that are for all servers and normal hosts - "${self}/modules/nixos" - inputs.stylix.nixosModules.stylix - inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm - ] ++ (if (type == "nixos") then [ - "${self}/profiles/nixos" - { - home-manager.users."${linuxUser}".imports = [ - # put home-manager imports here that are for all normal hosts - "${self}/profiles/home" - "${self}/modules/home" - ]; - } - ] else [ - # put nixos imports here that are for darwin hosts - "${self}/modules/nixos/darwin" - "${self}/profiles/nixos" - inputs.home-manager.darwinModules.home-manager - { - home-manager.users."${macUser}".imports = [ - # put home-manager imports here that are for darwin hosts - "${self}/modules/home/darwin" - "${self}/profiles/home" - ]; - } - ]) - )); - }; - }; - - mkHalfHost = host: type: pkgs: { - ${host} = - let - systemFunc = if (type == "home") then inputs.home-manager.lib.homeManagerConfiguration else inputs.nix-on-droid.lib.nixOnDroidConfiguration; - in - systemFunc - { - inherit pkgs; - extraSpecialArgs = { inherit inputs outputs lib self; }; - modules = [ "${self}/hosts/${type}/${host}" ]; - }; - }; - - mkFullHostConfigs = hosts: type: lib.foldl (acc: set: acc // set) { } (lib.map (host: mkFullHost host type) hosts); - - mkHalfHostConfigs = hosts: type: pkgs: lib.foldl (acc: set: acc // set) { } (lib.map (host: mkHalfHost host type pkgs) hosts); - - in - { - inherit lib; - - # nixosModules = import ./modules/nixos { inherit lib; }; - # homeModules = import ./modules/home { inherit lib; }; - packages = lib.swarselsystems.forEachLinuxSystem (pkgs: import ./pkgs { inherit lib pkgs; }); - formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); - overlays = import ./overlays { inherit self lib inputs; }; - - apps = lib.swarselsystems.forAllSystems (system: - let - appNames = [ - "swarsel-bootstrap" - "swarsel-install" - "swarsel-rebuild" - "swarsel-postinstall" - ]; - appSet = lib.swarselsystems.mkApps system appNames self; - in - - appSet // { - default = appSet.swarsel-bootstrap; - } - ); - - devShells = lib.swarselsystems.forAllSystems (system: - let - pkgs = lib.swarselsystems.pkgsFor.${system}; - checks = self.checks.${system}; - in - { - default = pkgs.mkShell { - # plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: { - # buildInputs = [pkgs.nixVersions.latest pkgs.boost]; - # patches = (o.patches or []) ++ [ "${self}/nix/nix-plugins.patch" ]; - # })}/lib/nix/plugins - NIX_CONFIG = '' - plugin-files = ${pkgs.nix-plugins}/lib/nix/plugins - extra-builtins-file = ${self + /nix/extra-builtins.nix} - ''; - inherit (checks.pre-commit-check) shellHook; - - buildInputs = checks.pre-commit-check.enabledPackages; - nativeBuildInputs = [ - (builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions. - # pkgs.nix - pkgs.home-manager - pkgs.git - pkgs.just - pkgs.age - pkgs.ssh-to-age - pkgs.sops - pkgs.statix - pkgs.deadnix - pkgs.nixpkgs-fmt - ]; - }; - } - ); - - templates = import ./templates { inherit lib; }; - - checks = lib.swarselsystems.forAllSystems (system: - let - pkgs = lib.swarselsystems.pkgsFor.${system}; - in - import ./checks { inherit self inputs system pkgs; } - ); - - diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix; - - nixosConfigurations = mkFullHostConfigs (lib.swarselsystems.readHosts "nixos") "nixos"; - homeConfigurations = mkHalfHostConfigs (lib.swarselsystems.readHosts "home") "home" lib.swarselsystems.pkgsFor.x86_64-linux; - darwinConfigurations = mkFullHostConfigs (lib.swarselsystems.readHosts "darwin") "darwin"; - nixOnDroidConfigurations = mkHalfHostConfigs (lib.swarselsystems.readHosts "android") "android" lib.swarselsystems.pkgsFor.aarch64-linux; - - topology = lib.swarselsystems.forEachSystem (pkgs: import inputs.nix-topology { - inherit pkgs; - modules = [ - "${self}/topology" - { inherit (self) nixosConfigurations; } - ]; - }); - - nodes = config.nixosConfigurations; - }; systems = [ "x86_64-linux" "aarch64-linux" diff --git a/hosts/darwin/nbm-imba-166/default.nix b/hosts/darwin/nbm-imba-166/default.nix index a6d3972..2e77295 100644 --- a/hosts/darwin/nbm-imba-166/default.nix +++ b/hosts/darwin/nbm-imba-166/default.nix @@ -1,4 +1,4 @@ -{ lib, ... }: +{ lib, config, ... }: let inherit (config.repo.secrets.local) workUser; in diff --git a/hosts/home/default/default.nix b/hosts/home/default/default.nix index 5380d3b..99bf5ba 100644 --- a/hosts/home/default/default.nix +++ b/hosts/home/default/default.nix @@ -1,12 +1,11 @@ -{ self, outputs, config, ... }: +{ self, inputs, outputs, ... }: { imports = [ inputs.stylix.homeManagerModules.stylix inputs.sops-nix.homeManagerModules.sops inputs.nix-index-database.hmModules.nix-index - ./modules/home/common - "${self}/modules/home/common/sharedsetup.nix" + "${self}/modules/home" ]; nixpkgs = { diff --git a/hosts/nixos/chaostheatre/default.nix b/hosts/nixos/chaostheatre/default.nix index a1782b8..9313d13 100644 --- a/hosts/nixos/chaostheatre/default.nix +++ b/hosts/nixos/chaostheatre/default.nix @@ -1,6 +1,8 @@ -{ self, inputs, config, pkgs, lib, primaryUser, ... }: +{ self, inputs, config, pkgs, lib, ... }: let + mainUser = "demo"; sharedOptions = { + inherit mainUser; isBtrfs = false; isLinux = true; isPublic = true; @@ -20,7 +22,7 @@ in "${self}/hosts/nixos/chaostheatre/options.nix" inputs.home-manager.nixosModules.home-manager { - home-manager.users."${primaryUser}".imports = [ + home-manager.users."${mainUser}".imports = [ "${self}/modules/home/common/settings.nix" "${self}/hosts/nixos/chaostheatre/options-home.nix" "${self}/modules/home/common/sharedsetup.nix" @@ -59,7 +61,7 @@ in } sharedOptions; - home-manager.users."${primaryUser}" = { + home-manager.users.${mainUser} = { home.stateVersion = lib.mkForce "23.05"; swarselsystems = lib.recursiveUpdate { diff --git a/hosts/nixos/moonside/default.nix b/hosts/nixos/moonside/default.nix index 3086862..db2b44d 100644 --- a/hosts/nixos/moonside/default.nix +++ b/hosts/nixos/moonside/default.nix @@ -1,5 +1,6 @@ -{ lib, config, primaryUser, ... }: +{ lib, config, globals, ... }: let + primaryUser = globals.user.name; inherit (config.repo.secrets.common) workHostName; inherit (config.repo.secrets.local.syncthing) dev1 dev2 dev3 loc1; serviceDomain = config.repo.secrets.common.services.domains.syncthing3; diff --git a/hosts/nixos/nbl-imba-2/default.nix b/hosts/nixos/nbl-imba-2/default.nix index 2f6f91d..c523221 100644 --- a/hosts/nixos/nbl-imba-2/default.nix +++ b/hosts/nixos/nbl-imba-2/default.nix @@ -1,5 +1,6 @@ -{ self, config, inputs, lib, primaryUser, ... }: +{ self, config, inputs, lib, globals, ... }: let + primaryUser = globals.user.name; sharedOptions = { isBtrfs = true; isLinux = true; diff --git a/hosts/nixos/sync/default.nix b/hosts/nixos/sync/default.nix index ed9c017..d63b90b 100644 --- a/hosts/nixos/sync/default.nix +++ b/hosts/nixos/sync/default.nix @@ -1,5 +1,6 @@ -{ lib, config, primaryUser, ... }: +{ lib, config, globals, ... }: let + primaryUser = globals.user.name; sharedOptions = { isBtrfs = false; isLinux = true; diff --git a/hosts/nixos/toto/default.nix b/hosts/nixos/toto/default.nix index ce8ca8e..3c99422 100644 --- a/hosts/nixos/toto/default.nix +++ b/hosts/nixos/toto/default.nix @@ -1,4 +1,4 @@ -{ self, inputs, pkgs, lib, primaryUser, ... }: +{ self, inputs, pkgs, lib, ... }: let modulesPath = "${self}/modules"; sharedOptions = { @@ -21,7 +21,7 @@ in inputs.home-manager.nixosModules.home-manager { - home-manager.users."${primaryUser}".imports = [ + home-manager.users."setup".imports = [ inputs.sops-nix.homeManagerModules.sops "${modulesPath}/home/common/sharedsetup.nix" "${self}/profiles/home" @@ -70,7 +70,7 @@ in } sharedOptions; - home-manager.users."${primaryUser}" = { + home-manager.users."setup" = { home.stateVersion = lib.mkForce "23.05"; swarselsystems = lib.recursiveUpdate { diff --git a/hosts/nixos/winters/default.nix b/hosts/nixos/winters/default.nix index b25e76b..cc501db 100644 --- a/hosts/nixos/winters/default.nix +++ b/hosts/nixos/winters/default.nix @@ -1,5 +1,6 @@ -{ lib, config, primaryUser, ... }: +{ lib, config, globals, ... }: let + primaryUser = globals.user.name; sharedOptions = { isBtrfs = false; isLinux = true; diff --git a/lib/default.nix b/lib/default.nix deleted file mode 100644 index 3a90b04..0000000 --- a/lib/default.nix +++ /dev/null @@ -1,120 +0,0 @@ -{ self, lib, systems, inputs, ... }: -{ - - mkIfElseList = p: yes: no: lib.mkMerge [ - (lib.mkIf p yes) - (lib.mkIf (!p) no) - ]; - - mkIfElse = p: yes: no: if p then yes else no; - - forAllSystems = lib.genAttrs [ - "x86_64-linux" - "aarch64-linux" - "x86_64-darwin" - "aarch64-darwin" - ]; - - pkgsFor = lib.genAttrs (import systems) (system: - import inputs.nixpkgs { - inherit system; - overlays = [ self.overlays.default ]; - config.allowUnfree = true; - } - ); - - toCapitalized = str: - if builtins.stringLength str == 0 then - "" - else - let - first = builtins.substring 0 1 str; - rest = builtins.substring 1 (builtins.stringLength str - 1) str; - upper = lib.toUpper first; - lower = lib.toLower rest; - in - upper + lower; - - - # mkUser = name: { - # config.users.users.${name} = { - # group = name; - # isSystemUser = true; - # }; - - # config.users.groups.${name} = {}; - # }; - - mkTrueOption = lib.mkOption { - type = lib.types.bool; - default = true; - }; - - mkStrong = lib.mkOverride 60; - - getSecret = filename: lib.strings.trim (builtins.readFile "${filename}"); - - forEachSystem = f: lib.genAttrs (import systems) (system: f lib.swarselsystems.pkgsFor.${system}); - forEachLinuxSystem = f: lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system: f lib.swarselsystems.pkgsFor.${system}); - - readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}"); - readNix = type: lib.filter (name: name != "default.nix") (lib.attrNames (builtins.readDir "${self}/${type}")); - - mkApps = system: names: self: builtins.listToAttrs (map - (name: { - inherit name; - value = { - type = "app"; - program = "${self.packages.${system}.${name}}/bin/${name}"; - meta = { - description = "Custom app ${name}."; - }; - }; - }) - names); - - mkPackages = names: pkgs: builtins.listToAttrs (map - (name: { - inherit name; - value = pkgs.callPackage "${self}/pkgs/${name}" { inherit self name; }; - }) - names); - - - mkModules = names: type: builtins.listToAttrs (map - (name: { - inherit name; - value = import "${self}/modules/${type}/${name}"; - }) - names); - - mkProfiles = names: type: builtins.listToAttrs (map - (name: { - inherit name; - value = import "${self}/profiles/${type}/${name}"; - }) - names); - - mkTemplates = names: builtins.listToAttrs (map - (name: { - inherit name; - value = { - path = "${self}/templates/${name}"; - description = "${name} project "; - }; - }) - names); - - mkImports = names: baseDir: lib.map (name: "${self}/${baseDir}/${name}") names; - - eachMonitor = _: monitor: { - inherit (monitor) name; - value = builtins.removeAttrs monitor [ "workspace" "name" "output" ]; - }; - - eachOutput = _: monitor: { - inherit (monitor) name; - value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ]; - }; - -} diff --git a/modules/home/darwin/default.nix b/modules/home/darwin/default.nix index 6ebc883..e90171c 100644 --- a/modules/home/darwin/default.nix +++ b/modules/home/darwin/default.nix @@ -1,10 +1,7 @@ { self, ... }: -let - modulesPath = "${self}/modules"; -in { imports = [ - "${modulesPath}/home/common/settings.nix" - "${modulesPath}/home/common/sharedsetup.nix" + "${self}/modules/home/common/settings.nix" + "${self}/modules/home/common/sharedsetup.nix" ]; } diff --git a/modules/nixos/client/default.nix b/modules/nixos/client/default.nix index 84ef47c..b6b0e59 100644 --- a/modules/nixos/client/default.nix +++ b/modules/nixos/client/default.nix @@ -1,7 +1,10 @@ -{ lib, ... }: +{ lib, inputs, ... }: let importNames = lib.swarselsystems.readNix "modules/nixos/client"; in { - imports = lib.swarselsystems.mkImports importNames "modules/nixos/client"; + imports = lib.swarselsystems.mkImports importNames "modules/nixos/client" ++ [ + inputs.stylix.nixosModules.stylix + inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm + ]; } diff --git a/modules/nixos/common/globals.nix b/modules/nixos/common/globals.nix index a275927..74fcf6a 100644 --- a/modules/nixos/common/globals.nix +++ b/modules/nixos/common/globals.nix @@ -15,6 +15,9 @@ in name = mkOption { type = types.str; }; + work = mkOption { + type = types.str; + }; }; diff --git a/modules/nixos/common/home-manager.nix b/modules/nixos/common/home-manager.nix index 812d7ff..30771d2 100644 --- a/modules/nixos/common/home-manager.nix +++ b/modules/nixos/common/home-manager.nix @@ -1,12 +1,18 @@ -{ inputs, config, lib, outputs, globals, nodes, ... }: +{ self, inputs, config, lib, outputs, globals, nodes, ... }: +let + mainUser = globals.user.name; +in { - options.swarselsystems.modules.home-manager = lib.mkEnableOption "home-manager"; config = lib.mkIf config.swarselsystems.modules.home-manager { home-manager = lib.mkIf config.swarselsystems.withHomeManager { useGlobalPkgs = true; useUserPackages = true; verbose = true; + users."${mainUser}".imports = [ + "${self}/profiles/home" + "${self}/modules/home" + ]; sharedModules = [ inputs.nix-index-database.hmModules.nix-index inputs.sops-nix.homeManagerModules.sops diff --git a/modules/nixos/darwin/default.nix b/modules/nixos/darwin/default.nix index c58fba4..e7b02e6 100644 --- a/modules/nixos/darwin/default.nix +++ b/modules/nixos/darwin/default.nix @@ -1,5 +1,10 @@ -{ lib, config, outputs, ... }: +{ self, lib, config, outputs, globals, ... }: +let + macUser = globals.user.work; +in { + imports = [ + ]; options.swarselsystems.modules.darwin.general = lib.mkEnableOption "darwin config"; config = lib.mkIf config.swarselsystems.modules.darwin.general { @@ -12,6 +17,10 @@ }; }; + home-manager.users."${macUser}".imports = [ + "${self}/modules/home/darwin" + ]; + system.stateVersion = 4; }; } diff --git a/modules/nixos/optional/framework.nix b/modules/nixos/optional/framework.nix index 8395d2e..3627255 100644 --- a/modules/nixos/optional/framework.nix +++ b/modules/nixos/optional/framework.nix @@ -1,5 +1,8 @@ -{ lib, config, ... }: +{ lib, config, inputs, ... }: { + imports = [ + inputs.fw-fanctrl.nixosModules.default + ]; options.swarselsystems.modules.optional.framework = lib.mkEnableOption "optional framework machine settings"; config = lib.mkIf config.swarselsystems.modules.optional.framework { services = { diff --git a/nix/apps.nix b/nix/apps.nix new file mode 100644 index 0000000..954269e --- /dev/null +++ b/nix/apps.nix @@ -0,0 +1,32 @@ +{ self, ... }: +{ + perSystem = { system, ... }: + let + mkApps = system: names: self: builtins.listToAttrs (map + (name: { + inherit name; + value = { + type = "app"; + program = "${self.packages.${system}.${name}}/bin/${name}"; + meta = { + description = "Custom app ${name}."; + }; + }; + }) + names); + + appNames = [ + "swarsel-bootstrap" + "swarsel-install" + "swarsel-rebuild" + "swarsel-postinstall" + ]; + + appSet = mkApps system appNames self; + in + { + apps = appSet // { + default = appSet.swarsel-bootstrap; + }; + }; +} diff --git a/nix/devshell.nix b/nix/devshell.nix new file mode 100644 index 0000000..3a1fd9c --- /dev/null +++ b/nix/devshell.nix @@ -0,0 +1,141 @@ +{ self, inputs, ... }: +{ + imports = [ + inputs.devshell.flakeModule + inputs.pre-commit-hooks.flakeModule + ]; + + perSystem = { pkgs, system, ... }: + { + pre-commit = { + check.enable = true; + settings = { + addGcRoot = true; + hooks = { + check-added-large-files.enable = true; + check-case-conflicts.enable = true; + check-executables-have-shebangs.enable = true; + check-shebang-scripts-are-executable.enable = false; + check-merge-conflicts.enable = true; + deadnix.enable = true; + detect-private-keys.enable = true; + end-of-file-fixer.enable = true; + fix-byte-order-marker.enable = true; + flake-checker.enable = true; + forbid-new-submodules.enable = true; + mixed-line-endings.enable = true; + nixpkgs-fmt.enable = true; + statix.enable = true; + trim-trailing-whitespace.enable = true; + + destroyed-symlinks = { + enable = true; + entry = "${inputs.pre-commit-hooks.checks.${system}.pre-commit-hooks}/bin/destroyed-symlinks"; + }; + + shellcheck = { + enable = true; + entry = "${pkgs.shellcheck}/bin/shellcheck --shell=bash"; + }; + + shfmt = { + enable = true; + entry = "${pkgs.shfmt}/bin/shfmt -i 4 -sr -d -s -l"; + }; + }; + }; + }; + + devshells.default = { + packages = [ + (builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions. + pkgs.git + pkgs.just + pkgs.age + pkgs.ssh-to-age + pkgs.sops + pkgs.home-manager + pkgs.nixpkgs-fmt + self.packages.${system}.swarsel-build + self.packages.${system}.swarsel-deploy + ]; + + commands = [ + { + package = pkgs.statix; + help = "Lint flake"; + } + { + package = pkgs.deadnix; + help = "Check flake for dead code"; + } + { + package = pkgs.nix-tree; + help = "Interactively browse dependency graphs of Nix derivations"; + } + { + package = pkgs.nvd; + help = "Diff two nix toplevels and show which packages were upgraded"; + } + { + package = pkgs.nix-diff; + help = "Explain why two Nix derivations differ"; + } + { + package = pkgs.nix-output-monitor; + help = "Nix Output Monitor (a drop-in alternative for `nix` which shows a build graph)"; + name = "nom"; + } + { + name = "hm"; + help = "Manage home-manager config"; + command = "home-manager"; + } + { + name = "fmt"; + help = "Format flake"; + command = "nixpkgs-fmt --check \"$FLAKE\""; + } + { + name = "sd"; + help = "Build and deploy this nix config to nodes"; + command = "swarsel-deploy \"$@\""; + } + { + name = "sl"; + help = "Build and deploy a config to nodes"; + command = "swarsel-deploy \${1} switch"; + } + { + name = "sw"; + help = "Build and switch to the host's config locally"; + command = "swarsel-deploy $(hostname) switch"; + } + { + name = "bld"; + help = "Build a number of configurations"; + command = "swarel-build \"$@\""; + } + { + name = "c"; + help = "Work with the flake git repository"; + command = "git --git-dir=$FLAKE/.git --work-tree=$FLAKE/ \"$@\""; + } + ]; + + devshell.startup.pre-commit-install.text = "pre-commit install"; + + env = [ + { + # Additionally configure nix-plugins with our extra builtins file. + # We need this for our repo secrets. + name = "NIX_CONFIG"; + value = '' + plugin-files = ${pkgs.nix-plugins}/lib/nix/plugins + extra-builtins-file = ${self + /nix/extra-builtins.nix} + ''; + } + ]; + }; + }; +} diff --git a/nix/formatter.nix b/nix/formatter.nix new file mode 100644 index 0000000..c00f3f2 --- /dev/null +++ b/nix/formatter.nix @@ -0,0 +1,6 @@ +_: +{ + perSystem = { pkgs, ... }: { + formatter = pkgs.nixpkgs-fmt; + }; +} diff --git a/nix/globals.nix b/nix/globals.nix index 1ea68fd..d1f0c77 100644 --- a/nix/globals.nix +++ b/nix/globals.nix @@ -1,4 +1,4 @@ -# taken from https://github.com/oddlama/nix-config/blob/main/nix/globals.nix +# adapted from https://github.com/oddlama/nix-config/blob/main/nix/globals.nix { inputs, ... }: { flake = { config, lib, ... }: @@ -14,7 +14,24 @@ }; modules = [ ../modules/nixos/common/globals.nix - ./globals-general.nix + ( + { lib, ... }: + let + # Try to access the extra builtin we loaded via nix-plugins. + # Throw an error if that doesn't exist. + sopsImportEncrypted = + assert lib.assertMsg (builtins ? extraBuiltins.sopsImportEncrypted) + "The extra builtin 'sopsImportEncrypted' is not available, so repo.secrets cannot be decrypted. Did you forget to add nix-plugins and point it to `./nix/extra-builtins.nix` ?"; + builtins.extraBuiltins.sopsImportEncrypted; + in + + { + imports = [ + (sopsImportEncrypted ../secrets/repo/globals.nix.enc) + ]; + + } + ) ( { lib, ... }: { diff --git a/nix/hosts.nix b/nix/hosts.nix new file mode 100644 index 0000000..336c46c --- /dev/null +++ b/nix/hosts.nix @@ -0,0 +1,92 @@ +{ self, inputs, ... }: +{ + flake = { config, ... }: + let + inherit (self) outputs; + inherit (outputs) lib; + # lib = (inputs.nixpkgs.lib // inputs.home-manager.lib).extend (_: _: { swarselsystems = import "${self}/lib" { inherit self lib inputs outputs; inherit (inputs) systems; }; }); + + mkNixosHost = { minimal }: name: + lib.nixosSystem { + specialArgs = { inherit inputs outputs lib self minimal; inherit (config) globals nodes; }; + modules = [ + inputs.disko.nixosModules.disko + inputs.sops-nix.nixosModules.sops + inputs.impermanence.nixosModules.impermanence + inputs.lanzaboote.nixosModules.lanzaboote + inputs.nix-topology.nixosModules.default + inputs.home-manager.nixosModules.home-manager + "${self}/hosts/nixos/${name}" + "${self}/profiles/nixos" + "${self}/modules/nixos" + { + node.name = name; + node.secretsDir = ../hosts/nixos/${name}/secrets; + } + ]; + }; + + mkDarwinHost = { minimal }: name: + inputs.nix-darwin.lib.darwinSystem { + specialArgs = { inherit inputs outputs lib self minimal; inherit (config) globals nodes; }; + modules = [ + # inputs.disko.nixosModules.disko + # inputs.sops-nix.nixosModules.sops + # inputs.impermanence.nixosModules.impermanence + # inputs.lanzaboote.nixosModules.lanzaboote + # inputs.fw-fanctrl.nixosModules.default + # inputs.nix-topology.nixosModules.default + inputs.home-manager.darwinModules.home-manager + "${self}/hosts/darwin/${name}" + "${self}/modules/nixos/darwin" + # needed for infrastructure + "${self}/modules/nixos/common/meta.nix" + "${self}/modules/nixos/common/globals.nix" + { + node.name = name; + node.secretsDir = ../hosts/darwin/${name}/secrets; + } + ]; + }; + + mkHalfHost = name: type: pkgs: { + ${name} = + let + systemFunc = if (type == "home") then inputs.home-manager.lib.homeManagerConfiguration else inputs.nix-on-droid.lib.nixOnDroidConfiguration; + in + systemFunc + { + inherit pkgs; + extraSpecialArgs = { inherit inputs outputs lib self; }; + modules = [ "${self}/hosts/${type}/${name}" ]; + }; + }; + + mkHalfHostConfigs = hosts: type: pkgs: lib.foldl (acc: set: acc // set) { } (lib.map (name: mkHalfHost name type pkgs) hosts); + nixosHosts = builtins.attrNames (lib.filterAttrs (_: type: type == "directory") (builtins.readDir "${self}/hosts/nixos")); + darwinHosts = builtins.attrNames (lib.filterAttrs (_: type: type == "directory") (builtins.readDir "${self}/hosts/darwin")); + in + { + nixosConfigurations = lib.genAttrs nixosHosts (mkNixosHost { + minimal = false; + }); + nixosConfigurationsMinimal = lib.genAttrs nixosHosts (mkNixosHost { + minimal = true; + }); + darwinConfigurations = lib.genAttrs darwinHosts (mkDarwinHost { + minimal = false; + }); + darwinConfigurationsMinimal = lib.genAttrs darwinHosts (mkDarwinHost { + minimal = true; + }); + + # TODO: Build these for all architectures + homeConfigurations = mkHalfHostConfigs (lib.swarselsystems.readHosts "home") "home" lib.swarselsystems.pkgsFor.x86_64-linux; + nixOnDroidConfigurations = mkHalfHostConfigs (lib.swarselsystems.readHosts "android") "android" lib.swarselsystems.pkgsFor.aarch64-linux; + + diskoConfigurations.default = import "${self}/templates/hosts/nixos/disk-config.nix"; + + nodes = config.nixosConfigurations // config.darwinConfigurations; + + }; +} diff --git a/hosts/nixos/iso/default.nix b/nix/iso.nix similarity index 79% rename from hosts/nixos/iso/default.nix rename to nix/iso.nix index 29c90d7..a0b4e95 100644 --- a/hosts/nixos/iso/default.nix +++ b/nix/iso.nix @@ -1,4 +1,4 @@ -{ self, pkgs, inputs, config, lib, modulesPath, primaryUser ? "swarsel", ... }: +{ self, pkgs, inputs, config, lib, modulesPath, ... }: let pubKeys = lib.filesystem.listFilesRecursive "${self}/secrets/keys/ssh"; in @@ -18,30 +18,18 @@ in inputs.home-manager.nixosModules.home-manager { - home-manager.users."${primaryUser}".imports = [ + home-manager.users."setup".imports = [ "${self}/modules/home/common/settings.nix" "${self}/modules/home/common/sharedsetup.nix" ]; } ]; - options.node = { - name = lib.mkOption { - description = "Node Name."; - type = lib.types.str; - }; - secretsDir = lib.mkOption { - description = "Path to the secrets directory for this node."; - type = lib.types.path; - default = ./.; - }; - }; config = { - node.name = lib.mkForce "drugstore"; swarselsystems = { info = "~SwarselSystems~ installer ISO"; }; - home-manager.users."${primaryUser}" = { + home-manager.users."setup" = { home = { stateVersion = "23.05"; file = { @@ -78,15 +66,15 @@ in config.allowUnfree = true; }; - services.getty.autologinUser = lib.mkForce primaryUser; + services.getty.autologinUser = lib.mkForce "setup"; users = { allowNoPasswordLogin = true; groups.swarsel = { }; users = { - swarsel = { - name = primaryUser; - group = primaryUser; + setup = { + name = "setup"; + group = "setup"; isNormalUser = true; password = "setup"; # this is overwritten after install openssh.authorizedKeys.keys = lib.lists.forEach pubKeys (key: builtins.readFile key); @@ -94,7 +82,7 @@ in }; root = { # password = lib.mkForce config.users.users.swarsel.password; # this is overwritten after install - openssh.authorizedKeys.keys = config.users.users."${primaryUser}".openssh.authorizedKeys.keys; + openssh.authorizedKeys.keys = config.users.users."setup".openssh.authorizedKeys.keys; }; }; }; @@ -110,10 +98,10 @@ in system.activationScripts.cache = { text = '' - mkdir -p -m=0777 /home/${primaryUser}/.local/state/nix/profiles - mkdir -p -m=0777 /home/${primaryUser}/.local/state/home-manager/gcroots - mkdir -p -m=0777 /home/${primaryUser}/.local/share/nix/ - printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /home/${primaryUser}/.local/share/nix/trusted-settings.json > /dev/null + mkdir -p -m=0777 /home/setup/.local/state/nix/profiles + mkdir -p -m=0777 /home/setup/.local/state/home-manager/gcroots + mkdir -p -m=0777 /home/setup/.local/share/nix/ + printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /home/setup/.local/share/nix/trusted-settings.json > /dev/null mkdir -p /root/.local/share/nix/ printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /root/.local/share/nix/trusted-settings.json > /dev/null ''; diff --git a/nix/lib.nix b/nix/lib.nix new file mode 100644 index 0000000..8660d56 --- /dev/null +++ b/nix/lib.nix @@ -0,0 +1,88 @@ +{ self, inputs, ... }: +let + swarselsystems = + let + inherit (inputs) systems; + inherit (inputs.nixpkgs) lib; + in + rec { + mkIfElseList = p: yes: no: lib.mkMerge [ + (lib.mkIf p yes) + (lib.mkIf (!p) no) + ]; + + mkIfElse = p: yes: no: if p then yes else no; + + pkgsFor = lib.genAttrs (import systems) (system: + import inputs.nixpkgs { + inherit system; + overlays = [ self.overlays.default ]; + config.allowUnfree = true; + } + ); + + toCapitalized = str: + if builtins.stringLength str == 0 then + "" + else + let + first = builtins.substring 0 1 str; + rest = builtins.substring 1 (builtins.stringLength str - 1) str; + upper = lib.toUpper first; + lower = lib.toLower rest; + in + upper + lower; + + + mkTrueOption = lib.mkOption { + type = lib.types.bool; + default = true; + }; + + mkStrong = lib.mkOverride 60; + + forEachSystem = f: lib.genAttrs (import systems) (system: f pkgsFor.${system}); + forEachLinuxSystem = f: lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system: f pkgsFor.${system}); + + readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}"); + readNix = type: lib.filter (name: name != "default.nix") (lib.attrNames (builtins.readDir "${self}/${type}")); + + + + + mkModules = names: type: builtins.listToAttrs (map + (name: { + inherit name; + value = import "${self}/modules/${type}/${name}"; + }) + names); + + mkProfiles = names: type: builtins.listToAttrs (map + (name: { + inherit name; + value = import "${self}/profiles/${type}/${name}"; + }) + names); + + + mkImports = names: baseDir: lib.map (name: "${self}/${baseDir}/${name}") names; + + eachMonitor = _: monitor: { + inherit (monitor) name; + value = builtins.removeAttrs monitor [ "workspace" "name" "output" ]; + }; + + eachOutput = _: monitor: { + inherit (monitor) name; + value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ]; + }; + }; +in +{ + flake = _: + { + lib = (inputs.nixpkgs.lib // inputs.home-manager.lib).extend (_: _: { + inherit swarselsystems; + }); + }; +} diff --git a/nix/modules.nix b/nix/modules.nix new file mode 100644 index 0000000..9f6cb6f --- /dev/null +++ b/nix/modules.nix @@ -0,0 +1,11 @@ +{ self, ... }: +{ + flake = _: + let + inherit (self.outputs) lib; + in + { + nixosModules.default = import "${self}/modules/nixos" { inherit lib; }; + homeModules = import "${self}/modules/home" { inherit lib; }; + }; +} diff --git a/nix/overlays.nix b/nix/overlays.nix new file mode 100644 index 0000000..6d32b78 --- /dev/null +++ b/nix/overlays.nix @@ -0,0 +1,88 @@ +{ self, inputs, ... }: +let + inherit (self) outputs; + inherit (outputs) lib; +in +{ + flake = { config, ... }: + { + overlays = { + default = final: prev: + let + additions = final: _: import "${self}/pkgs" { pkgs = final; inherit self lib; }; + + modifications = final: prev: { + vesktop = prev.vesktop.override { + withSystemVencord = true; + }; + + firefox = prev.firefox.override { + nativeMessagingHosts = [ + prev.tridactyl-native + prev.browserpass + prev.plasma5Packages.plasma-browser-integration + ]; + }; + + mgba = final.swarsel-mgba; + + retroarch = prev.retroarch.withCores (cores: with cores; [ + snes9x # snes + nestopia # nes + dosbox # dos + scummvm # scumm + vba-m # gb/a + mgba # gb/a + melonds # ds + dolphin # gc/wii + ]); + }; + + nixpkgs-stable = final: _: { + stable = import inputs.nixpkgs-stable { + inherit (final) system; + config.allowUnfree = true; + }; + }; + + nixpkgs-kernel = final: _: { + kernel = import inputs.nixpkgs-kernel { + inherit (final) system; + config.allowUnfree = true; + }; + }; + + nixpkgs-stable24_05 = final: _: { + stable24_05 = import inputs.nixpkgs-stable24_05 { + inherit (final) system; + config.allowUnfree = true; + }; + }; + + nixpkgs-stable24_11 = final: _: { + stable24_11 = import inputs.nixpkgs-stable24_11 { + inherit (final) system; + config.allowUnfree = true; + }; + }; + + zjstatus = _: prev: { + zjstatus = inputs.zjstatus.packages.${prev.system}.default; + }; + + in + (additions final prev) + // (modifications final prev) + // (nixpkgs-stable final prev) + // (nixpkgs-kernel final prev) + // (nixpkgs-stable24_05 final prev) + // (nixpkgs-stable24_11 final prev) + // (zjstatus final prev) + // (inputs.vbc-nix.overlays.default final prev) + // (inputs.nur.overlays.default final prev) + // (inputs.emacs-overlay.overlay final prev) + // (inputs.nix-topology.overlays.default final prev) + // (inputs.nixgl.overlay final prev); + }; + }; +} diff --git a/nix/packages.nix b/nix/packages.nix new file mode 100644 index 0000000..9b1bade --- /dev/null +++ b/nix/packages.nix @@ -0,0 +1,10 @@ +{ self, ... }: +{ + flake = _: + let + inherit (self.outputs) lib; + in + { + packages = lib.swarselsystems.forEachLinuxSystem (pkgs: import "${self}/pkgs" { inherit self lib pkgs; }); + }; +} diff --git a/nix/templates.nix b/nix/templates.nix new file mode 100644 index 0000000..ded942a --- /dev/null +++ b/nix/templates.nix @@ -0,0 +1,26 @@ +{ self, ... }: +{ + flake = _: { + templates = + let + mkTemplates = names: builtins.listToAttrs (map + (name: { + inherit name; + value = { + path = "${self}/templates/${name}"; + description = "${name} project "; + }; + }) + names); + templateNames = [ + "python" + "rust" + "go" + "cpp" + "latex" + "default" + ]; + in + mkTemplates templateNames; + }; +} diff --git a/topology/images/DELL-C2665dnf.png b/nix/topology-images/DELL-C2665dnf.png similarity index 100% rename from topology/images/DELL-C2665dnf.png rename to nix/topology-images/DELL-C2665dnf.png diff --git a/topology/images/TL-SG1005D.png b/nix/topology-images/TL-SG1005D.png similarity index 100% rename from topology/images/TL-SG1005D.png rename to nix/topology-images/TL-SG1005D.png diff --git a/topology/images/TL-SG108.png b/nix/topology-images/TL-SG108.png similarity index 100% rename from topology/images/TL-SG108.png rename to nix/topology-images/TL-SG108.png diff --git a/topology/images/ankisync.png b/nix/topology-images/ankisync.png similarity index 100% rename from topology/images/ankisync.png rename to nix/topology-images/ankisync.png diff --git a/topology/images/croc.png b/nix/topology-images/croc.png similarity index 100% rename from topology/images/croc.png rename to nix/topology-images/croc.png diff --git a/topology/images/firefly-iii.png b/nix/topology-images/firefly-iii.png similarity index 100% rename from topology/images/firefly-iii.png rename to nix/topology-images/firefly-iii.png diff --git a/topology/images/freshrss.png b/nix/topology-images/freshrss.png similarity index 100% rename from topology/images/freshrss.png rename to nix/topology-images/freshrss.png diff --git a/topology/images/huawei.png b/nix/topology-images/huawei.png similarity index 100% rename from topology/images/huawei.png rename to nix/topology-images/huawei.png diff --git a/topology/images/hunsn.png b/nix/topology-images/hunsn.png similarity index 100% rename from topology/images/hunsn.png rename to nix/topology-images/hunsn.png diff --git a/topology/images/kavita.png b/nix/topology-images/kavita.png similarity index 100% rename from topology/images/kavita.png rename to nix/topology-images/kavita.png diff --git a/topology/images/koillection.png b/nix/topology-images/koillection.png similarity index 100% rename from topology/images/koillection.png rename to nix/topology-images/koillection.png diff --git a/topology/images/microbin.png b/nix/topology-images/microbin.png similarity index 100% rename from topology/images/microbin.png rename to nix/topology-images/microbin.png diff --git a/topology/images/mpd.png b/nix/topology-images/mpd.png similarity index 100% rename from topology/images/mpd.png rename to nix/topology-images/mpd.png diff --git a/topology/images/nintendo-switch.png b/nix/topology-images/nintendo-switch.png similarity index 100% rename from topology/images/nintendo-switch.png rename to nix/topology-images/nintendo-switch.png diff --git a/topology/images/pc.png b/nix/topology-images/pc.png similarity index 100% rename from topology/images/pc.png rename to nix/topology-images/pc.png diff --git a/topology/images/readarr.png b/nix/topology-images/readarr.png similarity index 100% rename from topology/images/readarr.png rename to nix/topology-images/readarr.png diff --git a/topology/images/shlink.png b/nix/topology-images/shlink.png similarity index 100% rename from topology/images/shlink.png rename to nix/topology-images/shlink.png diff --git a/nix/topology.nix b/nix/topology.nix new file mode 100644 index 0000000..2fec00a --- /dev/null +++ b/nix/topology.nix @@ -0,0 +1,171 @@ +{ self, inputs, ... }: +{ + imports = [ + inputs.nix-topology.flakeModule + ]; + + perSystem.topology.modules = [ + ({ config, ... }: + let + inherit (config.lib.topology) + mkInternet + mkDevice + mkSwitch + mkRouter + mkConnection + ; + in + { + renderer = "elk"; + + networks = { + home-lan = { + name = "Home LAN"; + cidrv4 = "192.168.1.0/24"; + }; + wg = { + name = "Wireguard Tunnel"; + cidrv4 = "192.168.3.0/24"; + }; + }; + + nodes = { + internet = mkInternet { + connections = [ + (mkConnection "moonside" "wan") + (mkConnection "pfsense" "wan") + (mkConnection "sync" "wan") + (mkConnection "toto" "bootstrapper") + (mkConnection "chaostheatre" "demo host") + ]; + }; + + chaostheatre.interfaces."demo host" = { }; + toto.interfaces."bootstrapper" = { }; + sync.interfaces.wan = { }; + moonside.interfaces.wan = { }; + + pfsense = mkRouter "pfSense" { + info = "HUNSN RM02"; + image = "${self}/topology-images/hunsn.png"; + interfaceGroups = [ + [ + "eth2" + "eth3" + "eth4" + "eth5" + "eth6" + ] + [ "wan" ] + ]; + interfaces.wg = { + addresses = [ "192.168.3.1" ]; + network = "wg"; + virtual = true; + type = "wireguard"; + }; + + connections = { + eth2 = mkConnection "switch-livingroom" "eth1"; + eth4 = mkConnection "winters" "eth1"; + eth3 = mkConnection "switch-bedroom" "eth1"; + eth6 = mkConnection "wifi-ap" "eth1"; + wg = mkConnection "moonside" "wg"; + }; + interfaces = { + eth2 = { + addresses = [ "192.168.1.1" ]; + network = "home-lan"; + }; + eth3 = { + addresses = [ "192.168.1.1" ]; + network = "home-lan"; + }; + eth4 = { + addresses = [ "192.168.1.1" ]; + network = "home-lan"; + }; + eth6 = { + addresses = [ "192.168.1.1" ]; + network = "home-lan"; + }; + }; + }; + + winters.interfaces."eth1" = { }; + + wifi-ap = mkSwitch "Wi-Fi AP" { + info = "Huawei"; + image = "${self}/topology-images/huawei.png"; + interfaceGroups = [ + [ + "eth1" + "wifi" + ] + ]; + }; + + switch-livingroom = mkSwitch "Switch Livingroom" { + info = "TL-SG108"; + image = "${self}/topology-images/TL-SG108.png"; + interfaceGroups = [ + [ + "eth1" + "eth2" + "eth3" + "eth4" + "eth5" + "eth6" + "eth7" + "eth8" + ] + ]; + connections = { + eth2 = mkConnection "nswitch" "eth1"; + eth7 = mkConnection "pc" "eth1"; + eth8 = mkConnection "nbl-imba-2" "eth1"; + }; + }; + + nswitch = mkDevice "Nintendo Switch" { + info = "Nintendo Switch"; + image = "${self}/topology-images/nintendo-switch.png"; + interfaces.eth1 = { }; + }; + + pc = mkDevice "Windows Gaming Server" { + info = "i7-4790k, GTX970, 32GB RAM"; + image = "${self}/topology-images/pc.png"; + interfaces.eth1 = { }; + }; + + nbl-imba-2.interfaces.eth1 = { }; + + switch-bedroom = mkSwitch "Switch Bedroom" { + info = "TL-SG1005D"; + image = "${self}/topology-images/TL-SG1005D.png"; + interfaceGroups = [ + [ + "eth1" + "eth2" + "eth3" + "eth4" + "eth5" + ] + ]; + connections.eth2 = mkConnection "printer" "eth1"; + }; + + printer = mkDevice "Printer" { + info = "DELL C2665dnf"; + image = "${self}/topology-images/DELL-C2665dnf.png"; + interfaces.eth1 = { }; + }; + + }; + + }) + + + ]; +} diff --git a/overlays/default.nix b/overlays/default.nix deleted file mode 100644 index 8a64d88..0000000 --- a/overlays/default.nix +++ /dev/null @@ -1,86 +0,0 @@ -{ self, inputs, lib, ... }: - -let - additions = final: _: import "${self}/pkgs" { pkgs = final; inherit lib; }; - - modifications = final: prev: { - vesktop = prev.vesktop.override { - withSystemVencord = true; - }; - - firefox = prev.firefox.override { - nativeMessagingHosts = [ - prev.tridactyl-native - prev.browserpass - prev.plasma5Packages.plasma-browser-integration - ]; - }; - - mgba = final.swarsel-mgba; - - retroarch = prev.retroarch.withCores (cores: with cores; [ - snes9x # snes - nestopia # nes - dosbox # dos - scummvm # scumm - vba-m # gb/a - mgba # gb/a - melonds # ds - dolphin # gc/wii - ]); - - - - }; - - nixpkgs-stable = final: _: { - stable = import inputs.nixpkgs-stable { - inherit (final) system; - config.allowUnfree = true; - }; - }; - - nixpkgs-kernel = final: _: { - kernel = import inputs.nixpkgs-kernel { - inherit (final) system; - config.allowUnfree = true; - }; - }; - - nixpkgs-stable24_05 = final: _: { - stable24_05 = import inputs.nixpkgs-stable24_05 { - inherit (final) system; - config.allowUnfree = true; - }; - }; - - nixpkgs-stable24_11 = final: _: { - stable24_11 = import inputs.nixpkgs-stable24_11 { - inherit (final) system; - config.allowUnfree = true; - }; - }; - - zjstatus = _: prev: { - zjstatus = inputs.zjstatus.packages.${prev.system}.default; - }; - -in -{ - default = - final: prev: - - (additions final prev) - // (modifications final prev) - // (nixpkgs-stable final prev) - // (nixpkgs-kernel final prev) - // (nixpkgs-stable24_05 final prev) - // (nixpkgs-stable24_11 final prev) - // (zjstatus final prev) - // (inputs.vbc-nix.overlays.default final prev) - // (inputs.nur.overlays.default final prev) - // (inputs.emacs-overlay.overlay final prev) - // (inputs.nix-topology.overlays.default final prev) - // (inputs.nixgl.overlay final prev); - -} diff --git a/pkgs/default.nix b/pkgs/default.nix index 5cbc29b..4301f59 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -1,5 +1,11 @@ -{ lib, pkgs, ... }: +{ self, lib, pkgs, ... }: let + mkPackages = names: pkgs: builtins.listToAttrs (map + (name: { + inherit name; + value = pkgs.callPackage "${self}/pkgs/${name}" { inherit self name; }; + }) + names); packageNames = lib.swarselsystems.readNix "pkgs"; in -lib.swarselsystems.mkPackages packageNames pkgs +mkPackages packageNames pkgs diff --git a/pkgs/swarsel-build/default.nix b/pkgs/swarsel-build/default.nix new file mode 100644 index 0000000..a9597dc --- /dev/null +++ b/pkgs/swarsel-build/default.nix @@ -0,0 +1,15 @@ +{ name, nix-output-monitor, writeShellApplication, ... }: +writeShellApplication { + runtimeInputs = [ nix-output-monitor ]; + inherit name; + text = '' + set -euo pipefail + [[ "$#" -ge 1 ]] \ + || { echo "usage: build ..." >&2; exit 1; } + HOSTS=() + for h in "$@"; do + HOSTS+=(".#nixosConfigurations.$h.config.system.build.toplevel") + done + nom build --no-link --print-out-paths --show-trace "''${HOSTS[@]}" + ''; +} diff --git a/secrets/repo/globals.nix.enc b/secrets/repo/globals.nix.enc index 3830a00..00450be 100644 --- a/secrets/repo/globals.nix.enc +++ b/secrets/repo/globals.nix.enc @@ -1,5 +1,5 @@ { - "data": "ENC[AES256_GCM,data:1h+/I2SLfNqHrqWDAYmkkxFMwbN23zhUVTfWYcG9hmwiZ5KZoGErt1pvR6p2BIyBb3XrfqQoV8TWJrE7IrDKRkdX4MoaviT+W6wXJ46nTJAkJ2lbuNIfQR1paAqiIfeRIzx2GgOf,iv:GIHpghRgq1SBIs8KHzNLTvFJ7aruPd6e4zDe5GjuNo0=,tag:TvXf4qYWoSOqvlqnVsKxsw==,type:str]", + "data": "ENC[AES256_GCM,data:PW4DwwvVLuaUtuvJr/h+Zx+8V1i1D3hVlATFr5yI5nykn7T/ZLf7lJFYJGqms9DHExxiGmYNWCXkFrRqOnKpBajxUuuljaE0Yd4bxIga4hF5KC+nJS5BGT9tVOQfp/sopJvp7QjxLKBcZcZ9uya2+DhxJdhmtRUj5A04ze68PsQMl4zuU7Y=,iv:1rblF4XnYDHpwz0Sl6E/3Xd9ITP5KWC8Qm5Ghf+TaTI=,tag:JmxpswTJZO7y9D4hQEn1Gw==,type:str]", "sops": { "age": [ { @@ -27,8 +27,8 @@ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBibGlMSU4vUEF5UlNVZzlr\nMTMyOFY2Zi8rZFdZT1JrelZEUUZkZHFvOFdzCjVPbVovaU9nZklJQWNZeDJZNm0r\nMXBIK2hsZEY0NElxTVVMWmN6WU1Ld28KLS0tIENaallkK05SMllia3prV25hZDR2\nZDBNU0dYYnJESG1JZGpvSGp1WW9UMVEKJgfdLp7BRXvyAekecNJiaBXmxSj1qNxx\nZeHceqEkfWV/PzX+RP4LHjXTQCLEOJijbKxDmxSsYq49hC9xjZASuw==\n-----END AGE ENCRYPTED FILE-----\n" } ], - "lastmodified": "2025-07-02T12:24:56Z", - "mac": "ENC[AES256_GCM,data:MTBfNpPWlBI6HbTrcUhydq4NH/4m+kQWPuIjHo2eJmGbdoXk1qN1fHoKTB5U29YZWQuybBiSCRtLLWZdKhs5Vv9UsXOPDsKLflCW+sr0DEKd37ONzhlHhWsHGLF9kFOXZtruJe0p0Sh7oGy3T6ee4ABog3LwQ59ZcRmAxr7haFI=,iv:mDCvJrZXPOeuD01sqoLNGEHcexHZkZ3ankBk/lCMbUs=,tag:fqqJ8O8lI30SIqcCxAXVPA==,type:str]", + "lastmodified": "2025-07-03T16:55:42Z", + "mac": "ENC[AES256_GCM,data:+k6CeK5XiwsJJtvqr/NnRQvERqsV46tQoDnY6L5ptKQLyhMC8HPhrfn/LTJmRNqA8VXaDwSqm8zn+l8mJK55P/kZeeuLSmsvSYIgKlbp6naAbhyWM/q7IsT1fOAmFGKuG5nKaOy+ufxaXwIWWRPejmi9i+gmEw2FOTNimwyOqwc=,iv:q6P6QuipKMGc5i5oZ7XoU/qkbgo4X/SejfJUorAGb1M=,tag:sGfym1AaYAYHEzwDC5Dgsg==,type:str]", "pgp": [ { "created_at": "2025-07-02T12:10:18Z", diff --git a/templates/default.nix b/templates/default.nix deleted file mode 100644 index 9fbe2e6..0000000 --- a/templates/default.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ lib, ... }: -let - templateNames = [ - "python" - "rust" - "go" - "cpp" - "latex" - "default" - ]; -in -lib.swarselsystems.mkTemplates templateNames diff --git a/templates/hosts/nixos/default.nix b/templates/hosts/nixos/default.nix index bd3eee3..4d4ecf9 100644 --- a/templates/hosts/nixos/default.nix +++ b/templates/hosts/nixos/default.nix @@ -1,9 +1,10 @@ -{ self, inputs, pkgs, lib, primaryUser, ... }: +{ self, inputs, pkgs, lib, globals, ... }: let modulesPath = "${self}/modules"; sharedOptions = { isBtrfs = true; }; + primaryUser = globals.user.name; in { diff --git a/topology/default.nix b/topology/default.nix deleted file mode 100644 index 5751ff6..0000000 --- a/topology/default.nix +++ /dev/null @@ -1,162 +0,0 @@ -{ config, ... }: -let - inherit (config.lib.topology) - mkInternet - mkDevice - mkSwitch - mkRouter - mkConnection - ; -in -{ - renderer = "elk"; - - networks = { - home-lan = { - name = "Home LAN"; - cidrv4 = "192.168.1.0/24"; - }; - wg = { - name = "Wireguard Tunnel"; - cidrv4 = "192.168.3.0/24"; - }; - }; - - nodes = { - internet = mkInternet { - connections = [ - (mkConnection "moonside" "wan") - (mkConnection "pfsense" "wan") - (mkConnection "sync" "wan") - (mkConnection "toto" "bootstrapper") - (mkConnection "drugstore" "installer image") - (mkConnection "chaostheatre" "demo host") - ]; - }; - - chaostheatre.interfaces."demo host" = { }; - drugstore.interfaces."installer image" = { }; - toto.interfaces."bootstrapper" = { }; - sync.interfaces.wan = { }; - moonside.interfaces.wan = { }; - - pfsense = mkRouter "pfSense" { - info = "HUNSN RM02"; - image = ../topology/images/hunsn.png; - interfaceGroups = [ - [ - "eth2" - "eth3" - "eth4" - "eth5" - "eth6" - ] - [ "wan" ] - ]; - interfaces.wg = { - addresses = [ "192.168.3.1" ]; - network = "wg"; - virtual = true; - type = "wireguard"; - }; - - connections = { - eth2 = mkConnection "switch-livingroom" "eth1"; - eth4 = mkConnection "winters" "eth1"; - eth3 = mkConnection "switch-bedroom" "eth1"; - eth6 = mkConnection "wifi-ap" "eth1"; - wg = mkConnection "moonside" "wg"; - }; - interfaces = { - eth2 = { - addresses = [ "192.168.1.1" ]; - network = "home-lan"; - }; - eth3 = { - addresses = [ "192.168.1.1" ]; - network = "home-lan"; - }; - eth4 = { - addresses = [ "192.168.1.1" ]; - network = "home-lan"; - }; - eth6 = { - addresses = [ "192.168.1.1" ]; - network = "home-lan"; - }; - }; - }; - - winters.interfaces."eth1" = { }; - - wifi-ap = mkSwitch "Wi-Fi AP" { - info = "Huawei"; - image = ../topology/images/huawei.png; - interfaceGroups = [ - [ - "eth1" - "wifi" - ] - ]; - }; - - switch-livingroom = mkSwitch "Switch Livingroom" { - info = "TL-SG108"; - image = ../topology/images/TL-SG108.png; - interfaceGroups = [ - [ - "eth1" - "eth2" - "eth3" - "eth4" - "eth5" - "eth6" - "eth7" - "eth8" - ] - ]; - connections = { - eth2 = mkConnection "nswitch" "eth1"; - eth7 = mkConnection "pc" "eth1"; - eth8 = mkConnection "nbl-imba-2" "eth1"; - }; - }; - - nswitch = mkDevice "Nintendo Switch" { - info = "Nintendo Switch"; - image = ../topology/images/nintendo-switch.png; - interfaces.eth1 = { }; - }; - - pc = mkDevice "Windows Gaming Server" { - info = "i7-4790k, GTX970, 32GB RAM"; - image = ../topology/images/pc.png; - interfaces.eth1 = { }; - }; - - nbl-imba-2.interfaces.eth1 = { }; - - switch-bedroom = mkSwitch "Switch Bedroom" { - info = "TL-SG1005D"; - image = ../topology/images/TL-SG1005D.png; - interfaceGroups = [ - [ - "eth1" - "eth2" - "eth3" - "eth4" - "eth5" - ] - ]; - connections.eth2 = mkConnection "printer" "eth1"; - }; - - printer = mkDevice "Printer" { - info = "DELL C2665dnf"; - image = ../topology/images/DELL-C2665dnf.png; - interfaces.eth1 = { }; - }; - - }; - -}