diff --git a/TODO b/TODO index 7d833fe..a7e71b0 100644 --- a/TODO +++ b/TODO @@ -1,35 +1,23 @@ implement agenix -separate stable-diffusion and ollama backends from their UIs - figure out a way to get firefox policies and plugins set up in webapps -is theme gen relevant with cosmic? -it appears that cosmic-theme is a thing but is it functional yet? - -concept: -a function that flake-ifies and overrides the sources for regular nixpkgs -derivations to allow you to keep them utd by yourself -^ not possible to make flake inputs based on a function, - just pull source as flake and override the source attribute.. - concept: a nixos-like OS with standardised option sets that nonetheless uses composable flake -pieces to construct the whole OS, thus breaking the monorepo syndrome +pieces to construct the whole OS, breaking the monorepo syndrome concept: direnv+flake with services possibilities: -* make own systemd user slice and run services out of it +* flake-containers, but with rootless nspawn? + +* make per project systemd user slice and run services out of it - can we adapt nixos service modules directly? - most lightweight option - can share services between projects by sharing slice -* run a command directly inside systemd-nspawn - - fully virtualised without needing an image or anything - - should be very fast - * roll an oci image and run inside systemd-nspawn - this allows reuse of the entire nixos module system, including service config - docker-like port forwarding + - doesn't fucking work, hates nix oci images, fake and bad diff --git a/flake.lock b/flake.lock index 3ae0772..6f64fb8 100644 --- a/flake.lock +++ b/flake.lock @@ -24,11 +24,11 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", "owner": "edolstra", "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", "type": "github" }, "original": { @@ -54,22 +54,6 @@ } }, "flake-compat_3": { - "flake": false, - "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-compat_4": { "flake": false, "locked": { "lastModified": 1717312683, @@ -140,24 +124,6 @@ "inputs": { "systems": "systems_2" }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_3": { - "inputs": { - "systems": "systems_3" - }, "locked": { "lastModified": 1681202837, "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", @@ -172,31 +138,13 @@ "type": "github" } }, - "flake-utils_4": { - "inputs": { - "systems": "systems_4" - }, - "locked": { - "lastModified": 1705309234, - "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "flatpaks": { "locked": { - "lastModified": 1711997375, - "narHash": "sha256-KvU4gOtuFMS9Il67glRGtdNfguAINT9pCaXtvCL8uI8=", + "lastModified": 1721549352, + "narHash": "sha256-nlXJa8RSOX0kykrIYW33ukoHYq+FOSNztHLLgqKwOp8=", "owner": "gmodena", "repo": "nix-flatpak", - "rev": "45bf66f7068db79b552da864c0e87452be624d6c", + "rev": "dbce39ea8664820ba9037caaf1e2fad365ed6b4b", "type": "github" }, "original": { @@ -235,11 +183,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1718241864, - "narHash": "sha256-/XOumFymqlUSS2OZZSOIUL7z1vQyxOEpuOqynH85aYI=", + "lastModified": 1723549983, + "narHash": "sha256-8lya0y9tR3dtVk++nUjVaPbSb5+Ah+vKgcX+3R556BQ=", "owner": "helix-editor", "repo": "helix", - "rev": "9c479e6d2de3bca9dec304f9182cee2b1c0ad766", + "rev": "f65ec32a1c2e09b3b32b521617f4a3ef19bc71c5", "type": "github" }, "original": { @@ -255,15 +203,16 @@ ] }, "locked": { - "lastModified": 1718243258, - "narHash": "sha256-abBpj2VU8p6qlRzTU8o22q68MmOaZ4v8zZ4UlYl5YRU=", - "owner": "nix-community", + "lastModified": 1723535926, + "narHash": "sha256-XCQ/IGVRwhM0m2jDYkTKySEKpdI5mRcrFCkEhkn2+K4=", + "owner": "n-hass", "repo": "home-manager", - "rev": "8d5e27b4807d25308dfe369d5a923d87e7dbfda3", + "rev": "db192f855b550c5e5cb25cef7d41be2081b32a3f", "type": "github" }, "original": { - "owner": "nix-community", + "owner": "n-hass", + "ref": "podman-module", "repo": "home-manager", "type": "github" } @@ -284,52 +233,43 @@ "type": "github" } }, - "nix-index-database": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, + "madness": { "locked": { - "lastModified": 1718011381, - "narHash": "sha256-sFXI+ZANp/OC+MwfJoZgPSf4xMdtzQMe1pS3FGti4C8=", - "owner": "Mic92", - "repo": "nix-index-database", - "rev": "88ad3d7501e22b2401dd72734b032b7baa794434", + "lastModified": 1720637547, + "narHash": "sha256-5MGG0iRBvP35VlcHvxVrapuLygZwHwMB3g0M0fWxz58=", + "owner": "antithesishq", + "repo": "madness", + "rev": "c22c9c03579b7175d94f63e44ee0e518bb5ccdba", "type": "github" }, "original": { - "owner": "Mic92", - "repo": "nix-index-database", + "owner": "antithesishq", + "repo": "madness", "type": "github" } }, - "nix-ld-rs": { + "nix-index-database": { "inputs": { - "flake-compat": "flake-compat", - "flake-utils": "flake-utils_2", - "nixpkgs": [ - "nixpkgs" - ] + "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1718260327, - "narHash": "sha256-P2PsdY2kLin3S0AW7dYWWI+1/a/+onp3KaAz8O32EnY=", - "owner": "nix-community", - "repo": "nix-ld-rs", - "rev": "753a1539846e6f75c88583777a3f6e40f4064302", + "lastModified": 1723352546, + "narHash": "sha256-WTIrvp0yV8ODd6lxAq4F7EbrPQv0gscBnyfn559c3k8=", + "owner": "Mic92", + "repo": "nix-index-database", + "rev": "ec78079a904d7d55e81a0468d764d0fffb50ac06", "type": "github" }, "original": { - "owner": "nix-community", - "repo": "nix-ld-rs", + "owner": "Mic92", + "repo": "nix-index-database", "type": "github" } }, "nix-rice": { "inputs": { - "flake-compat": "flake-compat_2", - "flake-utils": "flake-utils_3", + "flake-compat": "flake-compat", + "flake-utils": "flake-utils_2", "kitty-themes-src": "kitty-themes-src", "nixpkgs-lib": "nixpkgs-lib", "pre-commit-hooks": "pre-commit-hooks" @@ -352,14 +292,15 @@ "inputs": { "flake-parts": "flake-parts", "flake-root": "flake-root", - "nixpkgs": "nixpkgs_3" + "nixpkgs": "nixpkgs_4", + "treefmt-nix": "treefmt-nix" }, "locked": { - "lastModified": 1718200260, - "narHash": "sha256-YcifM/i8wMzZHjyY9FNoruDb5Arm6Xw4RKfdvZBLdQU=", + "lastModified": 1723381807, + "narHash": "sha256-tBvNlNvI3xRjmfUuzwgwWFrk+SO50wlrmAGRuG3Yzi4=", "owner": "nix-community", "repo": "nixd", - "rev": "6811dcf03ac055752a3f28cbabf90bd0b0cee417", + "rev": "c9d8970a646dbaa82981d050d905637a29bbdd21", "type": "github" }, "original": { @@ -370,16 +311,17 @@ }, "nixos-cosmic": { "inputs": { - "flake-compat": "flake-compat_4", - "nixpkgs": "nixpkgs_4", - "nixpkgs-stable": "nixpkgs-stable_2" + "flake-compat": "flake-compat_3", + "nixpkgs": "nixpkgs_5", + "nixpkgs-stable": "nixpkgs-stable_2", + "rust-overlay": "rust-overlay_2" }, "locked": { - "lastModified": 1718332244, - "narHash": "sha256-91RPJQ00iEtqvY21lPtPQNRWtips9X/iuIXOCS8qeZI=", + "lastModified": 1723512951, + "narHash": "sha256-XZMqVka80UyX9JB6qnsb8TVERWgHSaKo0IAw9rFTTIU=", "owner": "lilyinstarlight", "repo": "nixos-cosmic", - "rev": "aed79d6d7e67d4229378c9812fe464ceeb90473f", + "rev": "c2e0c9b3ef4ed20ea59031c6187b408d560cf874", "type": "github" }, "original": { @@ -455,11 +397,11 @@ }, "nixpkgs-stable_2": { "locked": { - "lastModified": 1718208800, - "narHash": "sha256-US1tAChvPxT52RV8GksWZS415tTS7PV42KTc2PNDBmc=", + "lastModified": 1723282977, + "narHash": "sha256-oTK91aOlA/4IsjNAZGMEBz7Sq1zBS0Ltu4/nIQdYDOg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "cc54fb41d13736e92229c21627ea4f22199fee6b", + "rev": "a781ff33ae258bbcfd4ed6e673860c3e923bf2cc", "type": "github" }, "original": { @@ -470,6 +412,22 @@ } }, "nixpkgs_2": { + "locked": { + "lastModified": 1723175592, + "narHash": "sha256-M0xJ3FbDUc4fRZ84dPGx5VvgFsOzds77KiBMW/mMTnI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5e0ca22929f3342b19569b21b2f3462f053e497b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { "locked": { "lastModified": 1681303793, "narHash": "sha256-JEdQHsYuCfRL2PICHlOiH/2ue3DwoxUX7DJ6zZxZXFk=", @@ -485,7 +443,7 @@ "type": "github" } }, - "nixpkgs_3": { + "nixpkgs_4": { "locked": { "lastModified": 1714562304, "narHash": "sha256-Mr3U37Rh6tH0FbaDFu0aZDwk9mPAe7ASaqDOGgLqqLU=", @@ -501,13 +459,13 @@ "type": "github" } }, - "nixpkgs_4": { + "nixpkgs_5": { "locked": { - "lastModified": 1718160348, - "narHash": "sha256-9YrUjdztqi4Gz8n3mBuqvCkMo4ojrA6nASwyIKWMpus=", + "lastModified": 1723175592, + "narHash": "sha256-M0xJ3FbDUc4fRZ84dPGx5VvgFsOzds77KiBMW/mMTnI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "57d6973abba7ea108bac64ae7629e7431e0199b6", + "rev": "5e0ca22929f3342b19569b21b2f3462f053e497b", "type": "github" }, "original": { @@ -519,11 +477,11 @@ }, "nur": { "locked": { - "lastModified": 1718337354, - "narHash": "sha256-gbkVNpb2cnt5uVrxWykzIO4xCC/FtUhtKNPJ/792Uh8=", + "lastModified": 1723554177, + "narHash": "sha256-c874Bx8Hi6NGEt+PZQ88tgay2eyZ9Zly6rDHFhKFRJk=", "owner": "nix-community", "repo": "NUR", - "rev": "6a09d5a34d9f535b2b03c62ea6e4b23d12d5ea83", + "rev": "494fb37109715b5e3498c6a85532d5be16bdf10e", "type": "github" }, "original": { @@ -534,13 +492,13 @@ }, "pre-commit-hooks": { "inputs": { - "flake-compat": "flake-compat_3", + "flake-compat": "flake-compat_2", "flake-utils": [ "nix-rice", "flake-utils" ], "gitignore": "gitignore", - "nixpkgs": "nixpkgs_2", + "nixpkgs": "nixpkgs_3", "nixpkgs-stable": "nixpkgs-stable" }, "locked": { @@ -562,8 +520,8 @@ "flatpaks": "flatpaks", "helix": "helix", "home-manager": "home-manager", + "madness": "madness", "nix-index-database": "nix-index-database", - "nix-ld-rs": "nix-ld-rs", "nix-rice": "nix-rice", "nixd": "nixd", "nixos-cosmic": "nixos-cosmic", @@ -572,7 +530,7 @@ "nixpkgs" ], "nur": "nur", - "rust-overlay": "rust-overlay_2" + "rust-overlay": "rust-overlay_3" } }, "rust-overlay": { @@ -602,17 +560,37 @@ }, "rust-overlay_2": { "inputs": { - "flake-utils": "flake-utils_4", + "nixpkgs": [ + "nixos-cosmic", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1723429325, + "narHash": "sha256-4x/32xTCd+xCwFoI/kKSiCr5LQA2ZlyTRYXKEni5HR8=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "65e3dc0fe079fe8df087cd38f1fe6836a0373aad", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "rust-overlay_3": { + "inputs": { "nixpkgs": [ "nixpkgs" ] }, "locked": { - "lastModified": 1718331519, - "narHash": "sha256-6Ru37wS8uec626nHVIh6hSpCYB7eNc3RPFa2U//bhw4=", + "lastModified": 1723515680, + "narHash": "sha256-nHdKymsHCVIh0Wdm4MvSgxcTTg34FJIYHRQkQYaSuvk=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "419e7fae2731f41dd9b3e34dfe8802be68558b92", + "rev": "4ee3d9e9569f70d7bb40f28804d6fe950c81eab3", "type": "github" }, "original": { @@ -651,33 +629,24 @@ "type": "github" } }, - "systems_3": { + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "nixd", + "nixpkgs" + ] + }, "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "lastModified": 1722330636, + "narHash": "sha256-uru7JzOa33YlSRwf9sfXpJG+UAV+bnBEYMjrzKrQZFw=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "768acdb06968e53aa1ee8de207fd955335c754b7", "type": "github" }, "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_4": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", + "owner": "numtide", + "repo": "treefmt-nix", "type": "github" } } diff --git a/flake.nix b/flake.nix index c965009..b78c2fa 100644 --- a/flake.nix +++ b/flake.nix @@ -12,36 +12,27 @@ inputs.nixpkgs.follows = "nixpkgs"; }; - helix = { - url = "github:helix-editor/helix"; - # inputs.nixpkgs.follows = "nixpkgs"; - }; + helix.url = "github:helix-editor/helix"; home-manager = { - url = "github:nix-community/home-manager"; + # url = "github:nix-community/home-manager"; + url = "github:n-hass/home-manager/podman-module"; inputs.nixpkgs.follows = "nixpkgs"; }; - nix-index-database = { - url = "github:Mic92/nix-index-database"; - inputs.nixpkgs.follows = "nixpkgs"; - }; + nix-index-database.url = "github:Mic92/nix-index-database"; nix-rice.url = "github:bertof/nix-rice"; nixd.url = "github:nix-community/nixd"; - nix-ld-rs = { - url = "github:nix-community/nix-ld-rs"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - flatpaks.url = "github:gmodena/nix-flatpak"; nixos-cosmic = { url = "github:lilyinstarlight/nixos-cosmic"; - # inputs.nixpkgs.follows = "nixpkgs"; }; + + madness.url = "github:antithesishq/madness"; }; outputs = { @@ -50,58 +41,65 @@ nixos-cosmic, home-manager, nur, - helix, flatpaks, - nixd, - nix-ld-rs, nix-index-database, - nix-rice, + madness, ... } @ inputs: let inherit (self) outputs; + sharedModules = [ + madness.nixosModules.madness + nur.nixosModules.nur + nix-index-database.nixosModules.nix-index + ./system/cachix.nix + ]; + system = "x86_64-linux"; in { overlays = import ./util/overlay.nix {inherit inputs;}; nixosConfigurations = { "quiver" = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; + inherit system; specialArgs = {inherit inputs outputs;}; - modules = [ - nixos-cosmic.nixosModules.default - nur.nixosModules.nur - nix-index-database.nixosModules.nix-index - ./system/quiver.nix - ./system/cachix.nix - home-manager.nixosModules.home-manager - { - home-manager.useGlobalPkgs = true; - home-manager.extraSpecialArgs = {inherit inputs outputs;}; - home-manager.users.bolt.imports = [ - flatpaks.homeManagerModules.nix-flatpak - ./home/bolt.nix - ]; - } - ]; + modules = + [ + ./system/quiver.nix + nixos-cosmic.nixosModules.default + home-manager.nixosModules.home-manager + { + home-manager = { + useGlobalPkgs = true; + extraSpecialArgs = {inherit inputs outputs;}; + users.bolt.imports = [ + flatpaks.homeManagerModules.nix-flatpak + ./home/bolt.nix + ]; + }; + } + ] + ++ sharedModules; }; "adrift" = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; + inherit system; specialArgs = {inherit inputs outputs;}; - modules = [ - nur.nixosModules.nur - nix-index-database.nixosModules.nix-index - ./system/adrift.nix - ./system/cachix.nix - home-manager.nixosModules.home-manager - { - home-manager.useGlobalPkgs = true; - home-manager.extraSpecialArgs = {inherit inputs outputs;}; - home-manager.users.plank.imports = [ - flatpaks.homeManagerModules.nix-flatpak - ./home/plank.nix - ]; - } - ]; + modules = + [ + ./system/adrift.nix + nixos-cosmic.nixosModules.default + home-manager.nixosModules.home-manager + { + home-manager = { + useGlobalPkgs = true; + extraSpecialArgs = {inherit inputs outputs;}; + users.plank.imports = [ + flatpaks.homeManagerModules.nix-flatpak + ./home/plank.nix + ]; + }; + } + ] + ++ sharedModules; }; }; }; diff --git a/home/bolt.nix b/home/bolt.nix index 544bcdf..6c77923 100644 --- a/home/bolt.nix +++ b/home/bolt.nix @@ -2,17 +2,18 @@ imports = [ ./home.nix ./util/local-webapp.nix - ./programs/stable-diffusion.nix - ./programs/ollama.nix + ./util/containers.nix + # ./programs/stable-diffusion.nix + ./programs/openwebui.nix ]; - home = { + home = rec { username = "bolt"; homeDirectory = "/home/bolt"; + sessionVariables.FLAKE = "${homeDirectory}/.nix"; }; home.packages = with pkgs; [ nicotine-plus - private-gpt ]; } diff --git a/home/home.nix b/home/home.nix index a15560c..6d97200 100644 --- a/home/home.nix +++ b/home/home.nix @@ -15,6 +15,7 @@ in { ./modules/theming.nix ./util/ez.nix ./util/flatpak.nix + ./util/cosmic.nix inputs.nix-index-database.hmModules.nix-index ]; @@ -24,7 +25,32 @@ in { options = "--delete-older-than 3d"; }; - xdg.enable = true; + xdg = { + enable = true; + # mimeApps = { + # enable = true; + # # TODO? + # # also figure out how cosmic detects default terminal + # }; + portal = let + xdg-cosmic = pkgs.xdg-desktop-portal-cosmic; + in { + enable = true; + config = { + common = { + default = [ + "cosmic" + ]; + }; + }; + configPackages = [ + xdg-cosmic + ]; + extraPortals = [ + xdg-cosmic + ]; + }; + }; home.packages = with pkgs; rice.fonts.pkgs @@ -42,6 +68,18 @@ in { }; services.udiskie.enable = true; + # fix reliance on nonexistent graphical-session-pre.target + systemd.user.services.udiskie = lib.mkForce { + Unit = { + Description = "udiskie mount daemon"; + After = []; + PartOf = ["graphical-session.target"]; + }; + + Service.ExecStart = ["${pkgs.udiskie}/bin/udiskie --appindicator"]; + + Install.WantedBy = ["graphical-session.target"]; + }; # programs.nix-index-database.comma.enable = true; # programs.nix-index = { diff --git a/home/icons/ollama.png b/home/icons/ollama.png new file mode 100644 index 0000000..45f7dd9 Binary files /dev/null and b/home/icons/ollama.png differ diff --git a/home/modules/chat.nix b/home/modules/chat.nix index dcb67f9..0b6152c 100644 --- a/home/modules/chat.nix +++ b/home/modules/chat.nix @@ -6,14 +6,14 @@ programs.firefox.webapps = { "Microsoft-Teams" = { url = "https://teams.microsoft.com"; - id = 1; + # id = 1; extraSettings = config.programs.firefox.profiles.default.settings; name = "Microsoft Teams"; icon = ../icons/ms_teams.png; }; "Facebook-Messenger" = { url = "https://www.messenger.com"; - id = 2; + # id = 2; extraSettings = config.programs.firefox.profiles.default.settings; name = "Facebook Messenger"; icon = ../icons/fb_msg.png; diff --git a/home/modules/cosmic.nix b/home/modules/cosmic.nix new file mode 100644 index 0000000..04055c2 --- /dev/null +++ b/home/modules/cosmic.nix @@ -0,0 +1,163 @@ +{ + pkgs, + lib, + ... +}: let + inherit (lib) range mapAttrsToList; + inherit (builtins) toString; + workspaceRange = range 1 6; + makeWorkspaceBinding = modifiers: action: + map (i: { + inherit modifiers; + key = toString i; + action = { + type = action; + data = i; + }; + }) + workspaceRange; + focusWsBindings = makeWorkspaceBinding ["Super"] "Workspace"; + moveWsBindings = makeWorkspaceBinding ["Super" "Shift"] "SendToWorkspace"; + + hjkl = { + "h" = "Left"; + "j" = "Down"; + "k" = "Up"; + "l" = "Right"; + # "i" = "In"; + # "u" = "Out"; + }; + makeDirBinding = modifiers: action: + mapAttrsToList ( + key: dir: { + inherit key modifiers; + action = { + type = action; + data = dir; + }; + } + ) + hjkl; + focusBindings = makeDirBinding ["Super"] "Focus"; + moveBindings = makeDirBinding ["Super" "Shift"] "Move"; + winManagementBindings = + focusWsBindings + ++ moveWsBindings + ++ focusBindings + ++ moveBindings; + binding = key: modifiers: action: { + inherit key modifiers action; + }; + spawnBinding = key: modifiers: app: { + inherit key modifiers; + action = { + type = "Spawn"; + data = app; + }; + }; + systemBinding = key: modifiers: action: { + inherit key modifiers; + action = { + type = "System"; + data = action; + }; + }; +in { + imports = [ + ../util/cosmic.nix + ]; + config.cosmic = { + enable = true; + defaultKeybindings = false; + # otherSettings = { + # "com.system76.CosmicPanel.Dock" = { + # option.opacity = 0.8; + # }; + # }; + keybindings = + winManagementBindings + ++ [ + # System bindings appear broken? + (binding "q" ["Super" "Shift"] "Close") + (binding "w" ["Super"] "ToggleStacking") + (binding "s" ["Super"] "ToggleOrientation") + (binding "space" ["Super"] "ToggleWindowFloating") + (binding "space" ["Super" "Shift"] "Maximize") + (binding "minus" ["Super"] "Minimize") + (binding "r" ["Super"] { + type = "Resizing"; + data = "Outwards"; + }) + (binding "r" ["Super" "Shift"] { + type = "Resizing"; + data = "Inwards"; + }) + (binding "tab" ["Super"] "NextOutput") + (binding "tab" ["Super" "Shift"] "MoveToNextOutput") + (binding "grave" ["Super"] "PreviousOutput") + (binding "grave" ["Super" "Shift"] "MoveToPreviousOutput") + (spawnBinding "equal" ["Super"] "keepassxc") + (systemBinding "f" ["Super"] "WebBrowser") + (systemBinding "e" ["Super"] "HomeFolder") + # broken at the moment + # (systemBinding "return" ["Super"] "Terminal") + (spawnBinding "return" ["Super"] "kitty") + (systemBinding "s" ["Super" "Shift"] "Screenshot") + (systemBinding null ["Super"] "Launcher") + (systemBinding "d" ["Super"] "AppLibrary") + (systemBinding "XF86AudioRaiseVolume" [] "VolumeRaise") + (systemBinding "XF86AudioLowerVolume" [] "VolumeLower") + (systemBinding "XF86AudioMute" [] "Mute") + (spawnBinding "XF86AudioNext" [] "playerctl next") + (spawnBinding "XF86AudioPrev" [] "playerctl previous") + (spawnBinding "XF86AudioPlay" [] "playerctl play-pause") + (spawnBinding "XF86AudioStop" [] "playerctl stop") + (systemBinding "XF86MonBrightnessUp" [] "BrightnessUp") + (systemBinding "XF86MonBrightnessDown" [] "BrightnessDown") + (spawnBinding "e" ["Super" "Shift"] "wlogout") + + # old, pre-System bindings + # (binding "q" ["Super" "Shift"] "Close") + # (binding "w" ["Super"] "ToggleStacking") + # (binding "s" ["Super"] "ToggleOrientation") + # (binding "space" ["Super"] "ToggleWindowFloating") + # (binding "space" ["Super" "Shift"] "Maximize") + # (binding "minus" ["Super"] "Minimize") + # (binding "r" ["Super"] { + # type = "Resizing"; + # data = "Outwards"; + # }) + # (binding "r" ["Super" "Shift"] { + # type = "Resizing"; + # data = "Inwards"; + # }) + # (binding "tab" ["Super"] "NextOutput") + # (binding "tab" ["Super" "Shift"] "MoveToNextOutput") + # (binding "grave" ["Super"] "PreviousOutput") + # (binding "grave" ["Super" "Shift"] "MoveToPreviousOutput") + # (spawnBinding "f" ["Super"] "firefox") + # (spawnBinding "e" ["Super"] "nautilus") + # (spawnBinding "equal" ["Super"] "keepassxc") + # (spawnBinding "return" ["Super"] "kitty") + # (spawnBinding "s" ["Super" "Shift"] "cosmic-screenshot") + # (spawnBinding null ["Super"] "cosmic-launcher") + # (spawnBinding "d" ["Super"] "cosmic-app-library") + # (spawnBinding "XF86AudioRaiseVolume" [] "amixer sset Master 5%+") + # (spawnBinding "XF86AudioLowerVolume" [] "amixer sset Master 5%-") + # (spawnBinding "XF86AudioMute" [] "amixer sset Master toggle") + # (spawnBinding "XF86AudioNext" [] "playerctl next") + # (spawnBinding "XF86AudioPrev" [] "playerctl previous") + # (spawnBinding "XF86AudioPlay" [] "playerctl play-pause") + # (spawnBinding "XF86AudioStop" [] "playerctl stop") + # ( + # spawnBinding "XF86MonBrightnessUp" [] + # "busctl --user call com.system76.CosmicSettingsDaemon /com/system76/CosmicSettingsDaemon com.system76.CosmicSettingsDaemon IncreaseDisplayBrightness" + # ) + # ( + # spawnBinding "XF86MonBrightnessDown" [] + # "busctl --user call com.system76.CosmicSettingsDaemon /com/system76/CosmicSettingsDaemon com.system76.CosmicSettingsDaemon DecreaseDisplayBrightness" + # ) + # (spawnBinding "e" ["Super" "Shift"] "wlogout") + ]; + }; +} diff --git a/home/modules/desktop.nix b/home/modules/desktop.nix index dabb14a..f1cb2ac 100644 --- a/home/modules/desktop.nix +++ b/home/modules/desktop.nix @@ -1,5 +1,6 @@ {pkgs, ...}: { imports = [ + ./cosmic.nix ./media-players.nix ./webapps.nix ./documents.nix @@ -9,8 +10,8 @@ ../programs/wlogout.nix ]; home.packages = with pkgs; [ - gnome.file-roller - gnome.nautilus + file-roller + nautilus thunderbird keepassxc ]; diff --git a/home/modules/documents.nix b/home/modules/documents.nix index c53140b..b78f883 100644 --- a/home/modules/documents.nix +++ b/home/modules/documents.nix @@ -3,15 +3,8 @@ ../util/flatpak.nix ]; flatpaks = [ - { - name = "md.obsidian.Obsidian"; - overrides = { - Environment = { - OBSIDIAN_DISABLE_GPU = "1"; - }; - }; - } - "org.onlyoffice.desktopeditors" + "md.obsidian.Obsidian" + "com.logseq.Logseq" "org.libreoffice.LibreOffice" "com.jgraph.drawio.desktop" ]; diff --git a/home/modules/niri.nix b/home/modules/niri.nix new file mode 100644 index 0000000..18b904e --- /dev/null +++ b/home/modules/niri.nix @@ -0,0 +1,7 @@ +{...}: { + programs.niri = { + enable = true; + settings = { + }; + }; +} diff --git a/home/modules/webapps.nix b/home/modules/webapps.nix index 05b9227..93b2853 100644 --- a/home/modules/webapps.nix +++ b/home/modules/webapps.nix @@ -5,14 +5,14 @@ programs.firefox.webapps = { "Syncthing" = { url = "http://127.0.0.1:8384"; - id = 3; + # id = 3; extraSettings = config.programs.firefox.profiles.default.settings; name = "Syncthing"; icon = ../icons/syncthing.png; }; "StudyTAFE" = { url = "https://www.studytafensw.edu.au"; - id = 4; + # id = 4; extraSettings = config.programs.firefox.profiles.default.settings; name = "TAFE Study"; icon = ../icons/tafe.jpg; diff --git a/home/programs/ollama.nix b/home/programs/ollama.nix index ca3dd17..0cab497 100644 --- a/home/programs/ollama.nix +++ b/home/programs/ollama.nix @@ -2,34 +2,30 @@ lib, pkgs, ... -}: let - inherit (lib) getExe; - inherit (builtins) toString; - inherit (pkgs) writeShellScript; -in { - localWebApps = { - openwebui = rec { - name = "Ollama (OpenWebUI)"; - genericName = "Ollama"; - icon = ../icons/openwebui.png; - id = 6; - port = 3021; - service = let - docker = getExe pkgs.docker; - in { - Type = "exec"; - ExecStartPre = "${writeShellScript "openwebui-check" '' - set -euo pipefail - echo Checking for container existence.. - if [[ $(${docker} inspect openwebui &> /dev/null; printf $?) -ne 0 ]]; then - echo Not found. Creating OpenWebUI/Ollama container.. - ${docker} create -e PORT=${toString port} --restart no --network host --gpus all -v ollama:/root/.ollama -v open-webui:/app/backend/data --name openwebui --restart always ghcr.io/open-webui/open-webui:ollama - fi - echo Check complete. - ''}"; - ExecStart = "${docker} start -a openwebui"; - ExecStop = "${docker} stop openwebui"; - }; +}: { + services.podman = { + containers.ollama = { + # serviceName = "ollama"; + image = "ollama/ollama:latest"; + # ports = ["11434:11434"]; + devices = ["nvidia.com/gpu=all"]; + autostart = false; + networks = ["ollama"]; + extraOptions = [ + "--health-cmd" + (lib.escapeShellArg "bash -c 'cat < /dev/null > /dev/tcp/localhost/11434'") + ]; + }; + + networks.ollama = { + Subnet = "192.168.10.0/24"; + Gateway = "192.168.10.1"; }; }; + + # containers.ollama = { + # image = "ollama/ollama:latest"; + # # TODO: volume for models! + # extraOptions = ["--network=host" "--device=nvidia.com/gpu=all"]; + # }; } diff --git a/home/programs/openwebui.nix b/home/programs/openwebui.nix new file mode 100644 index 0000000..4b035a1 --- /dev/null +++ b/home/programs/openwebui.nix @@ -0,0 +1,40 @@ +{ + lib, + pkgs, + ... +}: let + port = 3021; +in { + imports = [./ollama.nix]; + + localWebApps = { + openwebui = { + name = "OpenWebUI"; + genericName = "LLM"; + icon = ../icons/openwebui.png; + inherit port; + requires.containers = ["openwebui" "ollama"]; + }; + }; + + services.podman = { + containers.openwebui = let + str = builtins.toString; + in { + # serviceName = "openwebui"; + image = "ghcr.io/open-webui/open-webui:main"; + ports = ["${str port}:${str port}"]; + environment = { + WEBUI_AUTH = "False"; + PORT = "${str port}"; + }; + autostart = false; + networks = ["ollama"]; + unitConfig = {Requires = ["podman-ollama.service"];}; + extraOptions = [ + "--health-cmd" + (lib.escapeShellArg "bash -c 'cat < /dev/null > /dev/tcp/localhost/${str port}'") + ]; + }; + }; +} diff --git a/home/programs/stable-diffusion.nix b/home/programs/stable-diffusion.nix index 8fe7b6f..051a37f 100644 --- a/home/programs/stable-diffusion.nix +++ b/home/programs/stable-diffusion.nix @@ -9,15 +9,12 @@ in { localWebApps = { stable-diffusion = { - name = "Stable Diffusion (ComfyUI)"; - genericName = "Stable Diffusion"; + name = "Stable Diffusion"; + genericName = "Image Generator"; icon = ../icons/comfyui.png; id = 5; port = 7860; - service = { - WorkingDirectory = "${homeDirectory}/code/etc/stable-diffusion-webui-docker"; - ExecStart = "${getExe pkgs.docker} compose --profile comfy up --build"; - }; + requires = ["stable-diffusion"]; }; }; } diff --git a/home/util/containers.nix b/home/util/containers.nix new file mode 100644 index 0000000..83dcddd --- /dev/null +++ b/home/util/containers.nix @@ -0,0 +1,365 @@ +{ + config, + lib, + pkgs, + ... +}: let + containerOptions = {...}: { + options = { + pullPolicy = mkOption { + type = with types; str; + description = "Podman container pulling policy"; + default = "newer"; + }; + image = mkOption { + type = with types; str; + description = "OCI image to run."; + example = "library/hello-world"; + }; + + imageFile = mkOption { + type = with types; nullOr package; + default = null; + description = '' + Path to an image file to load before running the image. This can + be used to bypass pulling the image from the registry. + + The `image` attribute must match the name and + tag of the image contained in this file, as they will be used to + run the container with that image. If they do not match, the + image will be pulled from the registry as usual. + ''; + example = literalExpression "pkgs.dockerTools.buildImage {...};"; + }; + + login = { + username = mkOption { + type = with types; nullOr str; + default = null; + description = "Username for login."; + }; + + passwordFile = mkOption { + type = with types; nullOr str; + default = null; + description = "Path to file containing password."; + example = "/etc/nixos/dockerhub-password.txt"; + }; + + registry = mkOption { + type = with types; nullOr str; + default = null; + description = "Registry where to login to."; + example = "https://docker.pkg.github.com"; + }; + }; + + cmd = mkOption { + type = with types; listOf str; + default = []; + description = "Commandline arguments to pass to the image's entrypoint."; + example = literalExpression '' + ["--port=9000"] + ''; + }; + + labels = mkOption { + type = with types; attrsOf str; + default = {}; + description = "Labels to attach to the container at runtime."; + example = literalExpression '' + { + "traefik.https.routers.example.rule" = "Host(`example.container`)"; + } + ''; + }; + + entrypoint = mkOption { + type = with types; nullOr str; + description = "Override the default entrypoint of the image."; + default = null; + example = "/bin/my-app"; + }; + + environment = mkOption { + type = with types; attrsOf str; + default = {}; + description = "Environment variables to set for this container."; + example = literalExpression '' + { + DATABASE_HOST = "db.example.com"; + DATABASE_PORT = "3306"; + } + ''; + }; + + environmentFiles = mkOption { + type = with types; listOf path; + default = []; + description = "Environment files for this container."; + example = literalExpression '' + [ + /path/to/.env + /path/to/.env.secret + ] + ''; + }; + + log-driver = mkOption { + type = types.str; + default = "journald"; + description = '' + Logging driver for the container. The default of + `"journald"` means that the container's logs will be + handled as part of the systemd unit. + + For more details and a full list of logging drivers, refer to podman documentation. + + For Docker: + [Docker engine documentation](https://docs.docker.com/engine/reference/run/#logging-drivers---log-driver) + + For Podman: + Refer to the docker-run(1) man page. + ''; + }; + + ports = mkOption { + type = with types; listOf str; + default = []; + description = '' + Network ports to publish from the container to the outer host. + + Valid formats: + - `::` + - `::` + - `:` + - `` + + Both `hostPort` and `containerPort` can be specified as a range of + ports. When specifying ranges for both, the number of container + ports in the range must match the number of host ports in the + range. Example: `1234-1236:1234-1236/tcp` + + When specifying a range for `hostPort` only, the `containerPort` + must *not* be a range. In this case, the container port is published + somewhere within the specified `hostPort` range. + Example: `1234-1236:1234/tcp` + + Refer to the + [Docker engine documentation](https://docs.docker.com/engine/reference/run/#expose-incoming-ports) for full details. + ''; + example = literalExpression '' + [ + "8080:9000" + ] + ''; + }; + + user = mkOption { + type = with types; nullOr str; + default = null; + description = '' + Override the username or UID (and optionally groupname or GID) used + in the container. + ''; + example = "nobody:nogroup"; + }; + + volumes = mkOption { + type = with types; listOf str; + default = []; + description = '' + List of volumes to attach to this container. + + Note that this is a list of `"src:dst"` strings to + allow for `src` to refer to `/nix/store` paths, which + would be difficult with an attribute set. There are + also a variety of mount options available as a third + field; please refer to the + [docker engine documentation](https://docs.docker.com/engine/reference/run/#volume-shared-filesystems) for details. + ''; + example = literalExpression '' + [ + "volume_name:/path/inside/container" + "/path/on/host:/path/inside/container" + ] + ''; + }; + + workdir = mkOption { + type = with types; nullOr str; + default = null; + description = "Override the default working directory for the container."; + example = "/var/lib/hello_world"; + }; + + dependsOn = mkOption { + type = with types; listOf str; + default = []; + description = '' + Define which other containers this one depends on. They will be added to both After and Requires for the unit. + + Use the same name as the attribute under `virtualisation.oci-containers.containers`. + ''; + example = literalExpression '' + containers = { + node1 = {}; + node2 = { + dependsOn = [ "node1" ]; + } + } + ''; + }; + + hostname = mkOption { + type = with types; nullOr str; + default = null; + description = "The hostname of the container."; + example = "hello-world"; + }; + + preRunExtraOptions = mkOption { + type = with types; listOf str; + default = []; + description = "Extra options for podman that go before the `run` argument."; + example = ["--runtime" "runsc"]; + }; + + extraOptions = mkOption { + type = with types; listOf str; + default = []; + description = "Extra options for podman run`."; + example = literalExpression '' + ["--network=host"] + ''; + }; + + autoStart = mkOption { + type = types.bool; + default = false; + description = '' + When enabled, the container is automatically started on boot. + If this option is set to false, the container has to be started on-demand via its service. + ''; + }; + }; + }; + + mkService = name: container: let + podman = lib.getExe pkgs.podman; + rm = lib.getExe' pkgs.coreutils "rm"; + printf = lib.getExe' pkgs.coreutils "printf"; + getId = ''"$(${lib.getExe' pkgs.coreutils "id"} -u)"''; + dependsOn = map (x: "podman-${x}.service") container.dependsOn; + escapedName = lib.escapeShellArg name; + preStartScript = pkgs.writeShellApplication { + name = "pre-start"; + runtimeInputs = []; + text = '' + ${printf} "Running pre-start script.." + ${podman} rm -f ${name} || true + ${lib.optionalString (container.imageFile != null) '' + ${podman} load -i ${container.imageFile} + ''} + ${rm} -f /run/user/${getId}/podman-${escapedName}.ctr-id + ${printf} " success.\nStarting Podman...\n" + ''; + }; + script = concatStringsSep " \\\n " ( + [ + "exec ${podman} " + ] + ++ map escapeShellArg container.preRunExtraOptions + ++ [ + "run" + "--log-level=debug" + "--rm" + "--name=${escapedName}" + "--log-driver=${container.log-driver}" + ] + ++ optional (container.entrypoint != null) + "--entrypoint=${escapeShellArg container.entrypoint}" + ++ optional (container.hostname != null) + "--hostname=${escapeShellArg container.hostname}" + ++ optional (container.pullPolicy != null) + "--pull=${container.pullPolicy}" + ++ [ + "--cidfile=/run/user/${getId}/podman-${escapedName}.ctr-id" + # "--sdnotify=ignore" + "--cgroups=no-conmon" + "--sdnotify=conmon" + "-d" + "--replace" + ] + ++ (mapAttrsToList (k: v: "-e ${escapeShellArg k}=${escapeShellArg v}") container.environment) + ++ map (f: "--env-file ${escapeShellArg f}") container.environmentFiles + ++ map (p: "-p ${escapeShellArg p}") container.ports + ++ optional (container.user != null) "-u ${escapeShellArg container.user}" + ++ map (v: "-v ${escapeShellArg v}") container.volumes + ++ (mapAttrsToList (k: v: "-l ${escapeShellArg k}=${escapeShellArg v}") container.labels) + ++ optional (container.workdir != null) "-w ${escapeShellArg container.workdir}" + ++ map escapeShellArg container.extraOptions + ++ [container.image] + ++ map escapeShellArg container.cmd + ); + + inherit (lib) concatStringsSep escapeShellArg optional optionalAttrs optionalString mapAttrsToList; + in { + Unit = { + WantedBy = [] ++ lib.optional (container.autoStart) "default.target"; # graphical-session instead maybe? + After = dependsOn; + Requires = dependsOn; + # StopWhenUnneeded = true; + }; + # TODO make network target.. + # wants = lib.optional (container.imageFile == null) "network-online.target"; + # after = lib.optionals (container.imageFile == null) [ "network-online.target" ] + # ++ dependsOn; + # environment = proxy_env; + + Service = { + ### There is no generalized way of supporting `reload` for docker + ### containers. Some containers may respond well to SIGHUP sent to their + ### init process, but it is not guaranteed; some apps have other reload + ### mechanisms, some don't have a reload signal at all, and some docker + ### images just have broken signal handling. The best compromise in this + ### case is probably to leave ExecReload undefined, so `systemctl reload` + ### will at least result in an error instead of potentially undefined + ### behaviour. + ### + ### Advanced users can still override this part of the unit to implement + ### a custom reload handler, since the result of all this is a normal + ### systemd service from the perspective of the NixOS module system. + ### + # ExecReload = ...; + ### + ExecStartPre = ["${preStartScript}/bin/pre-start"]; + ExecStart = [ + "${pkgs.writeShellScript "start" script}" + ]; + ExecStop = [ + "${podman} stop --ignore --cidfile=/run/user/${getId}/podman-${escapedName}.ctr-id" + "${podman} rm -f --ignore --cidfile=/run/user/${getId}/podman-${escapedName}.ctr-id" + ]; + # TimeoutStartSec = 0; + # TimeoutStopSec = 120; + # Restart = "always"; + Environment = ["PODMAN_SYSTEMD_UNIT=podman-${name}.service"]; + Type = "notify"; + NotifyAccess = "all"; + # Type = "exec"; + }; + }; + + cfg = config.containers; + inherit (lib) mapAttrs' nameValuePair mkOption types mkIf literalExpression; +in { + options.containers = mkOption { + default = {}; + type = with types; attrsOf (submodule containerOptions); + }; + + config = mkIf (cfg != {}) { + systemd.user.services = mapAttrs' (k: v: nameValuePair "podman-${k}" (mkService k v)) cfg; + }; +} diff --git a/util/cosmic.nix b/home/util/cosmic.nix similarity index 51% rename from util/cosmic.nix rename to home/util/cosmic.nix index e5f50aa..81e9b60 100644 --- a/util/cosmic.nix +++ b/home/util/cosmic.nix @@ -3,7 +3,7 @@ config, ... }: let - inherit (lib) filterAttrs concatStrings concatStringsSep mapAttrsToList concatLists foldlAttrs concatMapAttrs mapAttrs' nameValuePair boolToString; + inherit (lib) filterAttrs concatStrings concatStringsSep mapAttrsToList concatLists foldlAttrs concatMapAttrs mapAttrs mapAttrs' nameValuePair boolToString; inherit (builtins) typeOf toString stringLength; # build up serialisation machinery from here for various types @@ -79,75 +79,98 @@ then concatStrings [s.type "(" (toString s.data) ")"] else s; - # set up boilerplate for keybinding config file - cosmic-bindings = a: - struct { - key_bindings = mapBindings a; - data_control_enabled = false; - }; mapCosmicSettings = application: options: mapAttrs' (k: v: - nameValuePair "xdg/cosmic/${application}/v${options.version}/${k}" { + nameValuePair "cosmic/${application}/v${options.version}/${k}" { enable = true; text = serialise.${typeOf v} v; }) options.option; + # deconstructKeybindAttr = attr: mapAttrs' ( + # name: value: + # ) attr; + # rec_attr = lib.types.attrsOf (lib.types.oneOf lib.types.string rec_attr); in { - options.services.desktopManager.cosmic.keybindings = with lib; - mkOption { - default = []; - type = with types; - listOf (submodule { - options = { - modifiers = mkOption { - type = listOf str; - default = []; - }; - key = mkOption { - type = nullOr str; - default = null; - }; - action = mkOption { - type = either str (submodule { - options = { - type = mkOption { - type = str; - }; - data = mkOption { - type = oneOf [str int]; - default = ""; - }; - }; - }); - }; - }; - }); - }; + options.cosmic = { + enable = with lib; + mkOption { + default = false; + type = types.bool; + }; - options.services.desktopManager.cosmic.otherSettings = with lib; - mkOption { - default = {}; - type = with types; - attrsOf (submodule { - options = { - version = mkOption { - type = str; - default = "1"; - }; - option = mkOption { - type = attrsOf anything; - }; - }; - }); - }; + defaultKeybindings = with lib; + mkOption { + default = true; + type = types.bool; + }; - config.environment.etc = + # binds = with lib; + # mkOption { + # default = {}; + # type = with types; rec_attr; + # }; + + keybindings = with lib; + mkOption { + default = []; + type = with types; + listOf (submodule { + options = { + modifiers = mkOption { + type = listOf str; + default = []; + }; + key = mkOption { + type = nullOr str; + default = null; + }; + action = mkOption { + type = either str (submodule { + options = { + type = mkOption { + type = str; + }; + data = mkOption { + type = oneOf [str int]; + default = ""; + }; + }; + }); + }; + }; + }); + }; + + otherSettings = with lib; + mkOption { + default = {}; + type = with types; + attrsOf (submodule { + options = { + version = mkOption { + type = str; + default = "1"; + }; + option = mkOption { + type = attrsOf anything; + }; + }; + }); + }; + }; + + # TODO we need to split between system_actions, workspaces, custom + config.xdg.configFile = { - "cosmic-comp/config.ron".text = cosmic-bindings config.services.desktopManager.cosmic.keybindings; + "cosmic/com.system76.CosmicSettings.Shortcuts/v1/custom".text = mapBindings config.cosmic.keybindings; + "cosmic/com.system76.CosmicSettings.Shortcuts/v1/defaults" = { + text = "{}"; + enable = !config.cosmic.defaultKeybindings; + }; } // concatMapAttrs ( application: options: mapCosmicSettings application options ) - config.services.desktopManager.cosmic.otherSettings; + config.cosmic.otherSettings; } diff --git a/home/util/firefox-webapp.nix b/home/util/firefox-webapp.nix index f76cdb0..1eeece3 100644 --- a/home/util/firefox-webapp.nix +++ b/home/util/firefox-webapp.nix @@ -4,15 +4,22 @@ ... }: let inherit (builtins) getAttr stringLength substring; - inherit (lib) mkOption getExe; + inherit (lib) mkOption getExe listToAttrs attrsToList imap; inherit (lib.attrsets) filterAttrs mapAttrs mapAttrs' nameValuePair; inherit (lib.strings) concatStringsSep toUpper; + enumerate = a: + listToAttrs (imap (id: { + name, + value, + }: { + inherit name; + value = value // {inherit id;}; + }) (attrsToList a)); make-app-profiles = cfg: mapAttrs' (name: cfg: nameValuePair "home-manager-webapp-${name}" { inherit (cfg) id; - userChrome = '' @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); @@ -82,10 +89,10 @@ in { description = "The URL of the webapp to launch."; }; - id = mkOption { - type = int; - description = "The Firefox profile ID to set."; - }; + # id = mkOption { + # type = int; + # description = "The Firefox profile ID to set."; + # }; hidden = mkOption { type = bool; @@ -174,7 +181,7 @@ in { }; config = { - programs.firefox.profiles = make-app-profiles config.programs.firefox.webapps; + programs.firefox.profiles = make-app-profiles (enumerate config.programs.firefox.webapps); xdg.desktopEntries = mapAttrs (name: cfg: { diff --git a/home/util/local-webapp.nix b/home/util/local-webapp.nix index c546e82..b78e5af 100644 --- a/home/util/local-webapp.nix +++ b/home/util/local-webapp.nix @@ -7,32 +7,84 @@ inherit (lib) mkOption; inherit (lib.attrsets) mapAttrs mapAttrs' nameValuePair; inherit (lib) getExe getExe'; - # make a firefox webapp entry for the client app + # make a firefox webapp + hidden .desktop entry for the client app make-firefox = cfg: mapAttrs' ( name: cfg: nameValuePair "${name}-client" { - inherit (cfg) name id; + inherit (cfg) name; url = "http://127.0.0.1:${builtins.toString cfg.port}"; extraSettings = config.programs.firefox.profiles.default.settings; hidden = true; } ) cfg; - # make a systemd service for running the backend - make-systemd = cfg: + # make a systemd service for running the frontend + make-systemd-service = cfg: + mapAttrs' ( + name: cfg: + if + (cfg.service + != null) + then + nameValuePair "${cfg.name}-frontend" { + Unit = { + Description = "${cfg.name} Frontend"; + WantedBy = lib.mkForce []; + }; + + Service = cfg.service; + } + else nameValuePair "" {} + ) + cfg; + # modify systemd units to be PartOf this target + modify-systemd-services = cfg: + lib.listToAttrs (lib.flatten (lib.mapAttrsToList ( + name: cfg: (map ( + req: { + name = "${req}"; + value = { + Unit = { + PartOf = "${lib.toLower cfg.name}.target"; + }; + }; + } + ) + cfg.requires.services) + ) + cfg)); + modify-quadlets = cfg: + lib.listToAttrs (lib.flatten (lib.mapAttrsToList ( + name: cfg: (map ( + req: { + name = "${req}"; + value = { + unitConfig = { + PartOf = "${lib.toLower cfg.name}.target"; + }; + }; + } + ) + cfg.requires.containers) + ) + cfg)); + # make a systemd target to collate dependencies + make-systemd-target = cfg: mapAttrs ( name: cfg: { Unit = { - Description = "${cfg.name} Backend"; + Description = "${cfg.name} Target"; WantedBy = lib.mkForce []; + Requires = + (map (req: req + ".service") cfg.requires.services) + ++ (map (req: "podman-" + req + ".service") cfg.requires.containers); }; - Service = cfg.service; } ) cfg; - # make desktop shortcuts and a script which will handle starting both the above + # make desktop shortcuts and a script which will handle starting everything make-xdg = cfg: mapAttrs ( name: cfg: { @@ -42,45 +94,72 @@ notify-send = "${getExe' pkgs.libnotify "notify-send"} -a \"${cfg.name}\""; systemctl = "${getExe' pkgs.systemd "systemctl"}"; dex = "${getExe pkgs.dex}"; - curl = "${getExe pkgs.curl}"; + podman = "${getExe pkgs.podman}"; + makeContainerCheck = container: ''[ "$(${podman} inspect -f {{.State.Health.Status}} ${container})" == "healthy" ]''; + # makeContainerCheck = container: '' + # [ ${podman} inspect -f {{.State.Status}} ${container})" != "running" ] + # ''; + containerChecks = + if (cfg.requires.containers != []) + then + '' + container_checks() { + if '' + + (lib.concatMapStringsSep " && " + (container: makeContainerCheck container) + cfg.requires.containers) + + '' + ; then + return 0 + else + return 1 + fi + } + '' + else '' + container_checks() { + return 0 + } + ''; in pkgs.writeShellScript "${name}" '' set -euo pipefail - ${notify-send} "Launching backend.." "Please be patient." - ${systemctl} --user start ${name} - attempts=0 - success=false - while [[ $attempts -lt $((20*9)) ]]; do - if [[ $(${curl} -sf http://127.0.0.1:${builtins.toString cfg.port} --output /dev/null; printf $?) -eq 0 ]]; then - ${notify-send} "Backend up." "Launching client.." - success=true - break - else - attempts=$((attempts+1)) - if [[ $(($attempts % 20)) -eq 0 ]]; then - ${notify-send} "Launching backend.." "Still launching.. ($((attempts/2))s)" - fi + exit_error() { + ${notify-send} -w "Failure" $1 + exit 1 + } + + ${containerChecks} + + ${notify-send} "Launching ${name} backend.." "Please be patient." + ${systemctl} --user start ${name}.target || exit_error "Failed to launch!" + + checks=0 + until container_checks; do + sleep 2 + checks=$((checks+1)) + if [ $((checks%10)) -eq 0 ]; then + ${notify-send} "Waiting for backend." + fi + if [ $checks -ge 60 ]; then + ${systemctl} --no-block --user stop ${name}.target + exit_error "Failed to launch!" fi - sleep 0.5 done - if [[ ! $success ]]; then - ${notify-send} "Failure" "Failed to launch backend!" - ${systemctl} --user kill ${name} - exit 1 - fi - + ${notify-send} "Launching ${name}.." ${dex} -w ~/.nix-profile/share/applications/${name}-client.desktop ${notify-send} "Goodbye" "Shutting down." - ${systemctl} --user stop ${name} + ${systemctl} --user stop ${name}.target exit 0 ''}"; } ) cfg; + cfg = config.localWebApps; in { options.localWebApps = mkOption { default = {}; @@ -104,29 +183,59 @@ in { default = null; }; - id = mkOption { - type = int; - description = "Firefox profile ID for the webapp's client"; + requires = mkOption { + type = nullOr (submodule { + options = { + containers = mkOption { + type = listOf str; + default = []; + }; + services = mkOption { + type = listOf str; + default = []; + }; + }; + }); + default = null; + description = "Containers or services this app requires."; + }; + + service = mkOption { + type = nullOr (submodule { + options = { + execStartPre = mkOption { + type = nullOr str; + default = null; + }; + execStart = mkOption { + type = nullOr str; + default = null; + }; + execStop = mkOption { + type = nullOr str; + default = null; + }; + }; + }); + default = null; + description = "Submodule containing exec[StartPre/Start/Stop] commands for any required systemd service"; }; port = mkOption { type = int; description = "Local port the webapp should host on."; }; - - service = mkOption { - type = attrsOf str; - description = "The service settings for systemd user service. Requires at least ExecStart."; - }; }; }); }; config = { - programs.firefox.webapps = make-firefox config.localWebApps; + programs.firefox.webapps = make-firefox cfg; - systemd.user.services = make-systemd config.localWebApps; + systemd.user.targets = make-systemd-target cfg; + systemd.user.services = (make-systemd-service cfg) // (modify-systemd-services cfg); + services.podman.containers = modify-quadlets cfg; - xdg.desktopEntries = make-xdg config.localWebApps; + xdg.desktopEntries = make-xdg cfg; }; } diff --git a/system/adrift.nix b/system/adrift.nix index b3fad37..fb6e2db 100644 --- a/system/adrift.nix +++ b/system/adrift.nix @@ -12,6 +12,9 @@ ./configuration.nix ]; + nix.settings.trusted-users = ["plank"]; + programs.nh.flake = "/home/plank/.nix"; + boot.kernelParams = [ "mitigations=off" "quiet" diff --git a/system/configuration.nix b/system/configuration.nix index 8c5bb93..a85951e 100644 --- a/system/configuration.nix +++ b/system/configuration.nix @@ -17,7 +17,6 @@ outputs.overlays.rice inputs.helix.overlays.default inputs.nixd.overlays.default - inputs.nix-ld-rs.overlays.default ]; config = { allowUnfree = true; @@ -29,7 +28,7 @@ # add flake inputs to our registry to allow global use registry = lib.mapAttrs (_: value: {flake = value;}) inputs; settings = { - trusted-users = ["bolt" "plank"]; + # trusted-users = ["bolt" "plank"]; experimental-features = "nix-command flakes"; substitute = true; }; @@ -37,11 +36,6 @@ keep-outputs = true keep-derivations = true ''; - gc = { - automatic = true; - dates = "daily"; - options = "--delete-older-than 3d"; - }; optimise.automatic = true; package = pkgs.lix; }; @@ -64,8 +58,11 @@ services.libinput.enable = true; - hardware.opengl.enable = true; - hardware.opengl.driSupport32Bit = true; + # busted as hell + # services.usbmuxd.enable = true; # for iphone + + hardware.graphics.enable = true; + hardware.graphics.enable32Bit = true; services.udisks2.enable = true; @@ -82,10 +79,20 @@ curl eza git + + # broken \/ + # libimobiledevice + # ifuse ]; services.atuin.enable = true; + programs.nh = { + enable = true; + clean.enable = true; + clean.extraArgs = "--keep-since 3d --keep 3"; + }; + programs.nix-index-database.comma.enable = true; programs.nix-index.enableZshIntegration = false; programs.nix-index.enableBashIntegration = false; @@ -94,13 +101,7 @@ programs.dconf.enable = true; services.gvfs.enable = true; - programs.nix-ld = { - enable = true; - package = pkgs.nix-ld-rs; - }; - # give cpuset to user systemd.services."user@".serviceConfig.Delegate = "memory pids cpu cpuset"; - - system.stateVersion = "22.11"; # Did you read the comment? + systemd.user.extraConfig = "LogLevel=debug"; } diff --git a/system/modules/cosmic.nix b/system/modules/cosmic.nix index c626157..e95fd7e 100644 --- a/system/modules/cosmic.nix +++ b/system/modules/cosmic.nix @@ -1,114 +1,6 @@ -{ - pkgs, - lib, - ... -}: let - inherit (lib) range mapAttrsToList; - inherit (builtins) toString; - workspaceRange = range 1 6; - makeWorkspaceBinding = modifiers: action: - map (i: { - inherit modifiers; - key = toString i; - action = { - type = action; - data = i; - }; - }) - workspaceRange; - focusWsBindings = makeWorkspaceBinding ["Super"] "Workspace"; - moveWsBindings = makeWorkspaceBinding ["Super" "Shift"] "SendToWorkspace"; - - hjkl = { - "h" = "Left"; - "j" = "Down"; - "k" = "Up"; - "l" = "Right"; - }; - makeDirBinding = modifiers: action: - mapAttrsToList ( - key: dir: { - inherit key modifiers; - action = { - type = action; - data = dir; - }; - } - ) - hjkl; - focusBindings = makeDirBinding ["Super"] "Focus"; - moveBindings = makeDirBinding ["Super" "Shift"] "Move"; - winManagementBindings = - focusWsBindings - ++ moveWsBindings - ++ focusBindings - ++ moveBindings; - genBinding = key: modifiers: action: { - inherit key modifiers action; - }; - genSpawnBinding = key: modifiers: app: { - inherit key modifiers; - action = { - type = "Spawn"; - data = app; - }; - }; -in { - imports = [ - ../../util/cosmic.nix - ]; +{pkgs, ...}: { services.desktopManager.cosmic = { enable = true; - otherSettings = { - "com.system76.CosmicPanel.Dock" = { - option.opacity = 0.8; - }; - }; - keybindings = - winManagementBindings - ++ [ - (genBinding "q" ["Super" "Shift"] "Close") - (genBinding "w" ["Super"] "ToggleStacking") - (genBinding "s" ["Super"] "ToggleOrientation") - (genBinding "space" ["Super"] "ToggleWindowFloating") - (genBinding "space" ["Super" "Shift"] "Maximize") - (genBinding "minus" ["Super"] "Minimize") - (genBinding "r" ["Super"] { - type = "Resizing"; - data = "Outwards"; - }) - (genBinding "r" ["Super" "Shift"] { - type = "Resizing"; - data = "Inwards"; - }) - (genBinding "tab" ["Super"] "NextOutput") - (genBinding "tab" ["Super" "Shift"] "MoveToNextOutput") - (genBinding "grave" ["Super"] "PreviousOutput") - (genBinding "grave" ["Super" "Shift"] "MoveToPreviousOutput") - (genSpawnBinding "f" ["Super"] "firefox") - (genSpawnBinding "e" ["Super"] "nautilus") - (genSpawnBinding "equal" ["Super"] "keepassxc") - (genSpawnBinding "return" ["Super"] "kitty") - (genSpawnBinding "s" ["Super" "Shift"] "cosmic-screenshot") - (genSpawnBinding null ["Super"] "cosmic-launcher") - (genSpawnBinding "d" ["Super"] "cosmic-app-library") - (genSpawnBinding "XF86AudioRaiseVolume" [] "amixer sset Master 5%+") - (genSpawnBinding "XF86AudioLowerVolume" [] "amixer sset Master 5%-") - (genSpawnBinding "XF86AudioMute" [] "amixer sset Master toggle") - (genSpawnBinding "XF86AudioNext" [] "playerctl next") - (genSpawnBinding "XF86AudioPrev" [] "playerctl previous") - (genSpawnBinding "XF86AudioPlay" [] "playerctl play-pause") - (genSpawnBinding "XF86AudioStop" [] "playerctl stop") - ( - genSpawnBinding "XF86MonBrightnessUp" [] - "busctl --user call com.system76.CosmicSettingsDaemon /com/system76/CosmicSettingsDaemon com.system76.CosmicSettingsDaemon IncreaseDisplayBrightness" - ) - ( - genSpawnBinding "XF86MonBrightnessDown" [] - "busctl --user call com.system76.CosmicSettingsDaemon /com/system76/CosmicSettingsDaemon com.system76.CosmicSettingsDaemon DecreaseDisplayBrightness" - ) - (genSpawnBinding "e" ["Super" "Shift"] "wlogout") - ]; }; environment.cosmic.excludePackages = with pkgs; [ cosmic-store diff --git a/system/modules/network.nix b/system/modules/network.nix index a56a39b..b8a49bc 100644 --- a/system/modules/network.nix +++ b/system/modules/network.nix @@ -6,7 +6,8 @@ fallbackDns = ["103.1.206.179" "168.138.8.38" "168.138.12.137"]; dnssec = "false"; }; - services.mullvad-vpn.enable = true; + # services.mullvad-vpn.enable = true; + # systemd.services.mullvad-daemon.environment.TALPID_NET_CLS_MOUNT_DIR = "/opt/net-cls-v1"; networking.firewall = { checkReversePath = "loose"; }; diff --git a/system/modules/niri.nix b/system/modules/niri.nix new file mode 100644 index 0000000..beedda4 --- /dev/null +++ b/system/modules/niri.nix @@ -0,0 +1,6 @@ +{pkgs, ...}: { + programs.niri = { + enable = true; + package = pkgs.niri-unstable; + }; +} diff --git a/system/modules/stable-diffusion.nix b/system/modules/stable-diffusion.nix new file mode 100644 index 0000000..999a5de --- /dev/null +++ b/system/modules/stable-diffusion.nix @@ -0,0 +1,21 @@ +{ + lib, + pkgs, + stable-diffusion, + automatic-webui, + ... +}: { + systemd.services.stable-diffusion = { + description = "stable diffusion + AUTOMATIC1111 ui"; + serviceConfig = { + }; + }; + # virtualisation.oci-containers.containers = { + # # this is only the backend + # stable-diffusion = { + # image = "holaflenain/stable-diffusion:latest"; + # ports = ["7860:7860"]; + # autoStart = false; + # }; + # }; +} diff --git a/system/quiver.nix b/system/quiver.nix index c9b5d05..33baefc 100644 --- a/system/quiver.nix +++ b/system/quiver.nix @@ -8,9 +8,16 @@ ./configuration.nix ]; + system.stateVersion = "22.11"; # Did you read the comment? + + networking.hostName = "quiver"; + users.users.bolt = { isNormalUser = true; - extraGroups = ["wheel" "podman" "docker"]; # Enable ‘sudo’ for the user. + extraGroups = [ + "wheel" + "podman" + ]; }; boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "usbcore" "sd_mod"]; @@ -29,7 +36,6 @@ "vt.global_cursor_default=0" ]; - # boot.kernelPackages = pkgs.linuxPackages_cachyos; boot.kernelPackages = pkgs.linuxPackages_xanmod_latest; boot.supportedFilesystems = { ntfs = true; @@ -39,42 +45,41 @@ boot.loader.systemd-boot.configurationLimit = 5; boot.loader.efi.canTouchEfiVariables = true; - # boot.plymouth = with pkgs.rice.plymouth; { - # inherit font theme themePackages; - # enable = true; - # }; - security.tpm2.enable = true; networking.useDHCP = lib.mkDefault true; hardware.cpu.amd.updateMicrocode = true; + environment.pathsToLink = ["/share/xdg-desktop-portal" "/share/applications"]; environment.sessionVariables = { NIXOS_OZONE_WL = "1"; ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE = "fg=5"; - GBM_BACKEND = "nvidia-drm"; - NVD_BACKEND = "direct"; - __GLX_VENDOR_LIBRARY_NAME = "nvidia"; - LIBVA_DRIVER_NAME = "nvidia"; - __GL_GSYNC_ALLOWED = "1"; - __GL_VRR_ALLOWED = "1"; + # GBM_BACKEND = "nvidia-drm"; + # NVD_BACKEND = "direct"; + # __GLX_VENDOR_LIBRARY_NAME = "nvidia"; + # LIBVA_DRIVER_NAME = "nvidia"; + # __GL_GSYNC_ALLOWED = "1"; + # __GL_VRR_ALLOWED = "1"; EDITOR = "hx"; }; + nix.settings.trusted-users = ["bolt"]; + + virtualisation.oci-containers.backend = "podman"; + hardware.nvidia-container-toolkit.enable = true; virtualisation = { podman = { enable = true; - # dockerSocket.enable = true; - # enableNvidia = true; + dockerSocket.enable = true; defaultNetwork.settings.dns_enabled = true; }; - docker = { - enable = true; - enableNvidia = true; - enableOnBoot = true; - extraOptions = "--add-runtime nvidia=/run/current-system/sw/bin/nvidia-container-runtime"; - }; + # docker = { + # enable = true; + # enableOnBoot = true; + # enableNvidia = true; + # extraOptions = "--add-runtime nvidia=/run/current-system/sw/bin/nvidia-container-runtime"; + # }; }; services.minidlna = { @@ -87,12 +92,13 @@ }; services.xserver.videoDrivers = ["nvidia"]; + # TODO figure out why i can't resume properly hardware.nvidia = { - package = config.boot.kernelPackages.nvidiaPackages.stable; + package = config.boot.kernelPackages.nvidiaPackages.latest; modesetting.enable = true; - powerManagement.enable = true; + # powerManagement.enable = true; open = false; - nvidiaPersistenced = true; + # nvidiaPersistenced = true; }; programs.xwayland.enable = true; @@ -118,22 +124,22 @@ xclip ]; - networking.hostName = "quiver"; # Define your hostname. + fileSystems = { + "/" = { + device = "/dev/disk/by-uuid/b993b463-c131-4ef1-9aba-0e3eadaa2f9a"; + fsType = "btrfs"; + }; - fileSystems."/" = { - device = "/dev/disk/by-uuid/b993b463-c131-4ef1-9aba-0e3eadaa2f9a"; - fsType = "btrfs"; - }; + "/boot" = { + device = "/dev/disk/by-uuid/6B75-AF9F"; + fsType = "vfat"; + }; - fileSystems."/boot" = { - device = "/dev/disk/by-uuid/6B75-AF9F"; - fsType = "vfat"; - }; - - fileSystems."/data" = { - device = "/dev/disk/by-uuid/39D4F78C658E8B56"; - fsType = "ntfs"; - options = ["rw" "uid=1000" "gid=100"]; + "/data" = { + device = "/dev/disk/by-uuid/39D4F78C658E8B56"; + fsType = "ntfs"; + options = ["rw" "uid=1000" "gid=100"]; + }; }; swapDevices = [