diff --git a/.envrc b/.envrc index a6b1f81..f5141c2 100644 --- a/.envrc +++ b/.envrc @@ -1,4 +1,3 @@ -# shellcheck shell=bash if ! has nix_direnv_version || ! nix_direnv_version 3.0.0; then source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.0/direnvrc" "sha256-21TMnI2xWX7HkSTjFFri2UaohXVj854mgvWapWrxRXg=" fi diff --git a/.typos.toml b/.typos.toml new file mode 100644 index 0000000..2f82d13 --- /dev/null +++ b/.typos.toml @@ -0,0 +1,7 @@ +[default] +extend-ignore-re = [ + # spellchecker:disable-line + "(?Rm)^.*(#|//|--)\\s*spellchecker:disable-line$", + # spellchecker: + "(?s)(#|//|--)\\s*spellchecker:off.*?\\n\\s*(#|//|--)\\s*spellchecker:on", +] diff --git a/flake.lock b/flake.lock index b84e16d..7112362 100644 --- a/flake.lock +++ b/flake.lock @@ -14,11 +14,11 @@ ] }, "locked": { - "lastModified": 1762618334, - "narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=", + "lastModified": 1723293904, + "narHash": "sha256-b+uqzj+Wa6xgMS9aNbX4I+sXeb5biPDi39VgvSFqFvU=", "owner": "ryantm", "repo": "agenix", - "rev": "fcdea223397448d35d9b31f798479227e80183f6", + "rev": "f6291c5935fdc4e0bef208cfc0dcab7e3f7a1c41", "type": "github" }, "original": { @@ -36,11 +36,11 @@ ] }, "locked": { - "lastModified": 1744478979, - "narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=", + "lastModified": 1700795494, + "narHash": "sha256-gzGLZSiOhf155FW7262kdHo2YDeugp3VuIFb4/GGng0=", "owner": "lnl7", "repo": "nix-darwin", - "rev": "43975d782b418ebf4969e9ccba82466728c2851b", + "rev": "4b9b83d5a92e8c1fbfd8eb27eda375908c11ec4d", "type": "github" }, "original": { @@ -53,11 +53,11 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1761588595, - "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", "owner": "edolstra", "repo": "flake-compat", - "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", "type": "github" }, "original": { @@ -73,11 +73,11 @@ ] }, "locked": { - "lastModified": 1763759067, - "narHash": "sha256-LlLt2Jo/gMNYAwOgdRQBrsRoOz7BPRkzvNaI/fzXi2Q=", + "lastModified": 1726153070, + "narHash": "sha256-HO4zgY0ekfwO5bX0QH/3kJ/h4KvUDFZg8YpkNwIbg1U=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "2cccadc7357c0ba201788ae99c4dfa90728ef5e0", + "rev": "bcef6817a8b2aa20a5a6dbb19b43e63c5bf8619a", "type": "github" }, "original": { @@ -94,11 +94,11 @@ ] }, "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "type": "github" }, "original": { @@ -108,33 +108,10 @@ "type": "github" } }, - "git-hooks": { - "inputs": { - "flake-compat": "flake-compat", - "gitignore": "gitignore", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1763988335, - "narHash": "sha256-QlcnByMc8KBjpU37rbq5iP7Cp97HvjRP0ucfdh+M4Qc=", - "owner": "cachix", - "repo": "git-hooks.nix", - "rev": "50b9238891e388c9fdc6a5c49e49c42533a1b5ce", - "type": "github" - }, - "original": { - "owner": "cachix", - "ref": "master", - "repo": "git-hooks.nix", - "type": "github" - } - }, "gitignore": { "inputs": { "nixpkgs": [ - "git-hooks", + "pre-commit-hooks", "nixpkgs" ] }, @@ -159,11 +136,11 @@ ] }, "locked": { - "lastModified": 1764361670, - "narHash": "sha256-jgWzgpIaHbL3USIq0gihZeuy1lLf2YSfwvWEwnfAJUw=", + "lastModified": 1727246346, + "narHash": "sha256-TcUaKtya339Asu+g6KTJ8h7KiKcKXKp2V+At+7tksyY=", "owner": "nix-community", "repo": "home-manager", - "rev": "780be8ef503a28939cf9dc7996b48ffb1a3e04c6", + "rev": "1e22ef1518fb175d762006f9cae7f6312b8caedb", "type": "github" }, "original": { @@ -175,11 +152,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1764242076, - "narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=", + "lastModified": 1726937504, + "narHash": "sha256-bvGoiQBvponpZh8ClUcmJ6QnsNKw0EMrCQJARK3bI1c=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2fad6eac6077f03fe109c4d4eb171cf96791faa4", + "rev": "9357f4f23713673f310988025d9dc261c20e70c6", "type": "github" }, "original": { @@ -190,38 +167,56 @@ } }, "nur": { - "inputs": { - "flake-parts": [ - "flake-parts" - ], - "nixpkgs": [ - "nixpkgs" - ] - }, "locked": { - "lastModified": 1764449851, - "narHash": "sha256-VnodC1+3KML8MYLLnK84E6U2Fz4ioNacOeQd1pMCSTw=", + "lastModified": 1727272134, + "narHash": "sha256-q8xoi2eO23zhOmgBtJTj0QlcABoMeVB0CAWufTR3wyw=", "owner": "nix-community", "repo": "NUR", - "rev": "b1781c0aa8935d8d1f35d228bcc7127fcebcd363", + "rev": "8dbbe7f3575d0ff0998f92f811fb8bf4e3f0d3b1", "type": "github" }, "original": { "owner": "nix-community", - "ref": "main", + "ref": "master", "repo": "NUR", "type": "github" } }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1726745158, + "narHash": "sha256-D5AegvGoEjt4rkKedmxlSEmC+nNLMBPWFxvmYnVLhjk=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "4e743a6920eab45e8ba0fbe49dc459f1423a4b74", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "master", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, "root": { "inputs": { "agenix": "agenix", "flake-parts": "flake-parts", "futils": "futils", - "git-hooks": "git-hooks", "home-manager": "home-manager", "nixpkgs": "nixpkgs", "nur": "nur", + "pre-commit-hooks": "pre-commit-hooks", "systems": "systems" } }, diff --git a/flake.nix b/flake.nix index 0bdd180..a07ee15 100644 --- a/flake.nix +++ b/flake.nix @@ -54,20 +54,17 @@ type = "github"; owner = "nix-community"; repo = "NUR"; - ref = "main"; - inputs = { - flake-parts.follows = "flake-parts"; - nixpkgs.follows = "nixpkgs"; - }; + ref = "master"; }; - git-hooks = { + pre-commit-hooks = { type = "github"; owner = "cachix"; - repo = "git-hooks.nix"; + repo = "pre-commit-hooks.nix"; ref = "master"; inputs = { nixpkgs.follows = "nixpkgs"; + nixpkgs-stable.follows = "nixpkgs"; }; }; diff --git a/flake/checks.nix b/flake/checks.nix index 73e64d5..1684ca1 100644 --- a/flake/checks.nix +++ b/flake/checks.nix @@ -1,7 +1,7 @@ { inputs, ... }: { imports = [ - inputs.git-hooks.flakeModule + inputs.pre-commit-hooks.flakeModule ]; perSystem = { ... }: { @@ -26,6 +26,10 @@ stylua = { enable = true; }; + + typos = { + enable = true; + }; }; }; }; diff --git a/flake/dev-shells.nix b/flake/dev-shells.nix index 87464a4..d5f5989 100644 --- a/flake/dev-shells.nix +++ b/flake/dev-shells.nix @@ -6,6 +6,7 @@ name = "NixOS-config"; nativeBuildInputs = with pkgs; [ + gitAndTools.pre-commit nixpkgs-fmt ]; diff --git a/flake/home-manager.nix b/flake/home-manager.nix index 88a74e8..34af375 100644 --- a/flake/home-manager.nix +++ b/flake/home-manager.nix @@ -3,11 +3,6 @@ let defaultModules = [ # Include generic settings "${self}/modules/home" - { - nixpkgs.overlays = (lib.attrValues self.overlays) ++ [ - inputs.nur.overlays.default - ]; - } { # Basic user information defaults home.username = lib.mkDefault "ambroisie"; @@ -22,15 +17,22 @@ let ]; mkHome = name: system: inputs.home-manager.lib.homeManagerConfiguration { - pkgs = inputs.nixpkgs.legacyPackages.${system}; + # Work-around for home-manager + # * not letting me set `lib` as an extraSpecialArgs + # * not respecting `nixpkgs.overlays` [1] + # [1]: https://github.com/nix-community/home-manager/issues/2954 + pkgs = import inputs.nixpkgs { + inherit system; + + overlays = (lib.attrValues self.overlays) ++ [ + inputs.nur.overlay + ]; + }; modules = defaultModules ++ [ "${self}/hosts/homes/${name}" ]; - # Use my extended lib in NixOS configuration - inherit (self) lib; - extraSpecialArgs = { # Inject inputs to use them in global registry inherit inputs; diff --git a/flake/nixos.nix b/flake/nixos.nix index 0fbd3a6..b48b551 100644 --- a/flake/nixos.nix +++ b/flake/nixos.nix @@ -3,11 +3,11 @@ let defaultModules = [ { # Let 'nixos-version --json' know about the Git revision - system.configurationRevision = self.rev or self.dirtyRev or "dirty"; + system.configurationRevision = self.rev or "dirty"; } { nixpkgs.overlays = (lib.attrValues self.overlays) ++ [ - inputs.nur.overlays.default + inputs.nur.overlay ]; } # Include generic settings @@ -15,10 +15,8 @@ let ]; buildHost = name: system: lib.nixosSystem { + inherit system; modules = defaultModules ++ [ - { - nixpkgs.hostPlatform = system; - } "${self}/hosts/nixos/${name}" ]; specialArgs = { diff --git a/flake/overlays.nix b/flake/overlays.nix index c10afc3..0c47989 100644 --- a/flake/overlays.nix +++ b/flake/overlays.nix @@ -1,4 +1,4 @@ -{ self, lib, ... }: +{ self, ... }: let default-overlays = import "${self}/overlays"; @@ -8,7 +8,7 @@ let # Expose my custom packages pkgs = _final: prev: { - ambroisie = lib.recurseIntoAttrs (import "${self}/pkgs" { pkgs = prev; }); + ambroisie = prev.recurseIntoAttrs (import "${self}/pkgs" { pkgs = prev; }); }; }; in diff --git a/hosts/homes/ambroisie@bazin/default.nix b/hosts/homes/ambroisie@bazin/default.nix index 365b70d..f52fbce 100644 --- a/hosts/homes/ambroisie@bazin/default.nix +++ b/hosts/homes/ambroisie@bazin/default.nix @@ -4,20 +4,6 @@ services.gpg-agent.enable = lib.mkForce false; my.home = { - atuin = { - package = pkgs.stdenv.mkDerivation { - pname = "atuin"; - version = "18.4.0"; - - buildCommand = '' - mkdir -p $out/bin - ln -s /usr/bin/atuin $out/bin/atuin - ''; - - meta.mainProgram = "atuin"; - }; - }; - git = { package = pkgs.emptyDirectory; }; diff --git a/hosts/homes/ambroisie@mousqueton/default.nix b/hosts/homes/ambroisie@mousqueton/default.nix index 1383618..44e62e6 100644 --- a/hosts/homes/ambroisie@mousqueton/default.nix +++ b/hosts/homes/ambroisie@mousqueton/default.nix @@ -7,20 +7,6 @@ services.gpg-agent.enable = lib.mkForce false; my.home = { - atuin = { - package = pkgs.stdenv.mkDerivation { - pname = "atuin"; - version = "18.4.0"; - - buildCommand = '' - mkdir -p $out/bin - ln -s /usr/bin/atuin $out/bin/atuin - ''; - - meta.mainProgram = "atuin"; - }; - }; - git = { package = pkgs.emptyDirectory; }; @@ -29,9 +15,6 @@ # I use scripts that use the passthrough sequence often on this host enablePassthrough = true; - # Frequent reboots mean that session persistence can be handy - enableResurrect = true; - terminalFeatures = { # HTerm uses `xterm-256color` as its `$TERM`, so use that here xterm-256color = { }; diff --git a/hosts/nixos/aramis/home.nix b/hosts/nixos/aramis/home.nix index e8c99e4..64b63ce 100644 --- a/hosts/nixos/aramis/home.nix +++ b/hosts/nixos/aramis/home.nix @@ -18,7 +18,9 @@ # Machine specific packages packages.additionalPackages = with pkgs; [ element-desktop # Matrix client + jellyfin-media-player # Wraps the webui and mpv together pavucontrol # Audio mixer GUI + transgui # Transmission remote ]; # Minimal video player mpv.enable = true; @@ -26,8 +28,6 @@ nm-applet.enable = true; # Terminal terminal.program = "alacritty"; - # Transmission remote - trgui.enable = true; # Zathura document viewer zathura.enable = true; }; diff --git a/hosts/nixos/porthos/secrets/acme/dns-key.age b/hosts/nixos/porthos/secrets/acme/dns-key.age index d7f159e..fce2a84 100644 --- a/hosts/nixos/porthos/secrets/acme/dns-key.age +++ b/hosts/nixos/porthos/secrets/acme/dns-key.age @@ -1,9 +1,8 @@ age-encryption.org/v1 --> ssh-ed25519 cKojmg Ec0xt1uJTva8MxUdoTVX5m3uWaIiRlodf345FEM7Uzs -aJIneWFJPB5HVeoUGp57agXih9YeZ6xMEbyQ+zJtWQY --> ssh-ed25519 jPowng B5XotRgv7s/FUegGhceBj7EoukewNUOIFl4TFRQf1EQ -PgGCBd/Pqwp7ayqi7okHBGF1SfFpwT4KlHJ/np6p2uQ ---- AeLgwGz6k3OABb53cXNaCU/sgI4FlU1s6p8PhAaFOlg -1CԹULfI1Hmb}m šg0`XG>\>8rz+Y`ʢ.JBU!z¸Z50*ٟI] I -ĵo۰g¿tncz[{ -j&NNo{ -eP=L 6.SP:e \ No newline at end of file +-> ssh-ed25519 cKojmg bQFr9oAnbo1rI/MpUV8wQz/Xj7iZY4ZU+Swf0nSIQFw +zama2XJ0gdvUlD2GHMhmZqHSxHe+dKSfXnHoWDcSw7Y +-> ssh-ed25519 jPowng gitUwSKTNKWLSxnwa185O7x/u0ul93g8wPESdZaKRk8 +uvBIfAUkZp5sg6rfeEGvL5ZDV8m2uSEotW02kjPN3Hw +--- SZxe5f/CUZBvPQa2Sz/UBY3L68rMkIGGRuZPk7YE+Vg +r&{~v?}= +}+ SQM[]k MAtmM/Ls|ޅmCiYC}x \ No newline at end of file diff --git a/hosts/nixos/porthos/secrets/matrix/sliding-sync-secret.age b/hosts/nixos/porthos/secrets/matrix/sliding-sync-secret.age new file mode 100644 index 0000000..e938cfa --- /dev/null +++ b/hosts/nixos/porthos/secrets/matrix/sliding-sync-secret.age @@ -0,0 +1,8 @@ +age-encryption.org/v1 +-> ssh-ed25519 cKojmg xRtF3XVc7yPicAV/E4U7mn0itvD0h1BWBTjwunuoe2E +OkB9sjGB3ulH4Feuyj3Ed0DBG4+mghW/Qpum9oXL/8c +-> ssh-ed25519 jPowng 1r8drqhz1yZdTq0Kvqya+ArU1C2fkN7Gg9LiWWfeUFg +cjbxntVwHvqLaJpiKs/Y8ojeb6e3/cLFcsoeuoobfFg +--- B1qA2PylJBrdZxZtCzlU2kRPvxLM+IrXTvR+ERxVtTY +"W9bg~/b4ՆI +} -NC7vWb?8=wB UpJClOșnO\ \ No newline at end of file diff --git a/hosts/nixos/porthos/secrets/secrets.nix b/hosts/nixos/porthos/secrets/secrets.nix index f1842b4..a8a9819 100644 --- a/hosts/nixos/porthos/secrets/secrets.nix +++ b/hosts/nixos/porthos/secrets/secrets.nix @@ -48,6 +48,9 @@ in owner = "matrix-synapse"; publicKeys = all; }; + "matrix/sliding-sync-secret.age" = { + publicKeys = all; + }; "mealie/mail.age" = { publicKeys = all; @@ -80,12 +83,18 @@ in "pyload/credentials.age".publicKeys = all; - "servarr/autobrr/session-secret.age".publicKeys = all; - "servarr/cross-seed/configuration.json.age".publicKeys = all; - - "sso/auth-key.age".publicKeys = all; - "sso/ambroisie/password-hash.age".publicKeys = all; - "sso/ambroisie/totp-secret.age".publicKeys = all; + "sso/auth-key.age" = { + owner = "nginx-sso"; + publicKeys = all; + }; + "sso/ambroisie/password-hash.age" = { + owner = "nginx-sso"; + publicKeys = all; + }; + "sso/ambroisie/totp-secret.age" = { + owner = "nginx-sso"; + publicKeys = all; + }; "tandoor-recipes/secret-key.age".publicKeys = all; diff --git a/hosts/nixos/porthos/secrets/servarr/autobrr/session-secret.age b/hosts/nixos/porthos/secrets/servarr/autobrr/session-secret.age deleted file mode 100644 index e98b94a..0000000 --- a/hosts/nixos/porthos/secrets/servarr/autobrr/session-secret.age +++ /dev/null @@ -1,7 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 cKojmg bu09lB+fjaPP31cUQZP6EqSPuseucgNK7k9vAS08iS0 -+NGL+b2QD/qGo6hqHvosAXzHZtDvfodmPdcgnrKlD1o --> ssh-ed25519 jPowng QDCdRBGWhtdvvMCiDH52cZHz1/W7aomhTatZ4+9IKwI -Ou3jjV/O55G1CPgGS33l3eWhhYWrVdwVNPSiE14d5rE ---- q0ssmpG50OX1WaNSInc2hbtH3DbTwQGDU74VGEoMh94 -mCƑ'hK./Xu(g$'M{fK !MZoR՝͟;yb \ No newline at end of file diff --git a/hosts/nixos/porthos/secrets/servarr/cross-seed/configuration.json.age b/hosts/nixos/porthos/secrets/servarr/cross-seed/configuration.json.age deleted file mode 100644 index 94fdf97..0000000 Binary files a/hosts/nixos/porthos/secrets/servarr/cross-seed/configuration.json.age and /dev/null differ diff --git a/hosts/nixos/porthos/services.nix b/hosts/nixos/porthos/services.nix index 96f15d3..7a38cea 100644 --- a/hosts/nixos/porthos/services.nix +++ b/hosts/nixos/porthos/services.nix @@ -51,9 +51,9 @@ in passwordFile = secrets."forgejo/mail-password".path; }; }; - # Home inventory - homebox = { - enable = true; + # Meta-indexers + indexers = { + prowlarr.enable = true; }; # Jellyfin media server jellyfin.enable = true; @@ -69,6 +69,9 @@ in mailConfigFile = secrets."matrix/mail".path; # Only necessary when doing the initial registration secretFile = secrets."matrix/secret".path; + slidingSync = { + secretFile = secrets."matrix/sliding-sync-secret".path; + }; }; mealie = { enable = true; @@ -95,9 +98,6 @@ in nextcloud = { enable = true; passwordFile = secrets."nextcloud/password".path; - collabora = { - enable = true; - }; }; nix-cache = { enable = true; @@ -132,6 +132,13 @@ in enable = true; loginFile = secrets."pdf-edit/login".path; }; + # Podcast automatic downloader + podgrab = { + enable = true; + passwordFile = secrets."podgrab/password".path; + dataDir = "/data/media/podcasts"; + port = 9598; + }; # Regular backups postgresql-backup.enable = true; pyload = { @@ -144,27 +151,19 @@ in sabnzbd.enable = true; # The whole *arr software suite servarr = { - enableAll = true; - autobrr = { - sessionSecretFile = secrets."servarr/autobrr/session-secret".path; - }; - cross-seed = { - secretSettingsFile = secrets."servarr/cross-seed/configuration.json".path; - }; + enable = true; # ... But not Lidarr because I don't care for music that much lidarr = { enable = false; }; - # I only use Prowlarr nowadays - jackett = { - enable = false; - }; - nzbhydra = { - enable = false; - }; }; # Because I still need to play sysadmin ssh-server.enable = true; + # Recipe manager + tandoor-recipes = { + enable = true; + secretKeyFile = secrets."tandoor-recipes/secret-key".path; + }; # Torrent client and webui transmission = { enable = true; diff --git a/modules/home/atuin/default.nix b/modules/home/atuin/default.nix index 40d2b04..3f06263 100644 --- a/modules/home/atuin/default.nix +++ b/modules/home/atuin/default.nix @@ -6,11 +6,8 @@ in options.my.home.atuin = with lib; { enable = my.mkDisableOption "atuin configuration"; + # I want the full experience by default package = mkPackageOption pkgs "atuin" { }; - - daemon = { - enable = my.mkDisableOption "atuin daemon"; - }; }; config = lib.mkIf cfg.enable { @@ -18,18 +15,12 @@ in enable = true; inherit (cfg) package; - daemon = lib.mkIf cfg.daemon.enable { - enable = true; - }; - flags = [ # I *despise* this hijacking of the up key, even though I use Ctrl-p "--disable-up-arrow" ]; settings = { - # Reasonable date format - dialect = "uk"; # The package is managed by Nix update_check = false; # I don't care for the fancy display diff --git a/modules/home/default.nix b/modules/home/default.nix index ad3b979..c8183cf 100644 --- a/modules/home/default.nix +++ b/modules/home/default.nix @@ -8,7 +8,6 @@ ./bluetooth ./calibre ./comma - ./delta ./dircolors ./direnv ./discord @@ -38,7 +37,6 @@ ./ssh ./terminal ./tmux - ./trgui ./udiskie ./vim ./wget @@ -52,6 +50,9 @@ # First sane reproducible version home.stateVersion = "20.09"; + # Who am I? + home.username = "ambroisie"; + # Start services automatically systemd.user.startServices = "sd-switch"; } diff --git a/modules/home/delta/default.nix b/modules/home/delta/default.nix deleted file mode 100644 index e76edc6..0000000 --- a/modules/home/delta/default.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ config, pkgs, lib, ... }: -let - cfg = config.my.home.delta; -in -{ - options.my.home.delta = with lib; { - enable = my.mkDisableOption "delta configuration"; - - package = mkPackageOption pkgs "delta" { }; - - git = { - enable = my.mkDisableOption "git integration"; - }; - }; - - config = lib.mkIf cfg.enable { - programs.delta = { - enable = true; - - inherit (cfg) package; - - enableGitIntegration = cfg.git.enable; - - options = { - features = "diff-highlight decorations"; - - # Less jarring style for `diff-highlight` emulation - diff-highlight = { - minus-style = "red"; - minus-non-emph-style = "red"; - minus-emph-style = "bold red 52"; - - plus-style = "green"; - plus-non-emph-style = "green"; - plus-emph-style = "bold green 22"; - - whitespace-error-style = "reverse red"; - }; - - # Personal preference for easier reading - decorations = { - commit-style = "raw"; # Do not recolor meta information - keep-plus-minus-markers = true; - paging = "always"; - }; - }; - }; - }; -} diff --git a/modules/home/direnv/lib/android.sh b/modules/home/direnv/lib/android.sh index 9344aea..fa2f856 100644 --- a/modules/home/direnv/lib/android.sh +++ b/modules/home/direnv/lib/android.sh @@ -1,4 +1,4 @@ -# shellcheck shell=bash +#shellcheck shell=bash # shellcheck disable=2155 use_android() { @@ -32,16 +32,10 @@ use_android() { -b|--build-tools) build_tools_version="$2" shift 2 - if ! [ -e "$ANDROID_HOME/build-tools/$build_tools_version" ]; then - log_error "use_android: build-tools version '$build_tools_version' does not exist" - fi ;; -n|--ndk) ndk_version="$2" shift 2 - if ! [ -e "$ANDROID_HOME/ndk/$ndk_version" ]; then - log_error "use_android: NDK version '$ndk_version' does not exist" - fi ;; --) shift diff --git a/modules/home/direnv/lib/nix.sh b/modules/home/direnv/lib/nix.sh index 4b6c547..a65eb31 100644 --- a/modules/home/direnv/lib/nix.sh +++ b/modules/home/direnv/lib/nix.sh @@ -1,4 +1,4 @@ -# shellcheck shell=bash +#shellcheck shell=bash use_pkgs() { if ! has nix; then diff --git a/modules/home/direnv/lib/postgres.sh b/modules/home/direnv/lib/postgres.sh index 46e171d..c2e6a8f 100644 --- a/modules/home/direnv/lib/postgres.sh +++ b/modules/home/direnv/lib/postgres.sh @@ -1,4 +1,4 @@ -# shellcheck shell=bash +#shellcheck shell=bash layout_postgres() { if ! has postgres || ! has initdb; then diff --git a/modules/home/direnv/lib/python.sh b/modules/home/direnv/lib/python.sh index b1be8a9..d1e67a2 100644 --- a/modules/home/direnv/lib/python.sh +++ b/modules/home/direnv/lib/python.sh @@ -1,4 +1,4 @@ -# shellcheck shell=bash +#shellcheck shell=bash layout_poetry() { if ! has poetry; then @@ -46,12 +46,11 @@ layout_uv() { fi # create venv if it doesn't exist - uv venv -q --allow-existing + uv venv -q export VIRTUAL_ENV export UV_ACTIVE=1 PATH_add "$VIRTUAL_ENV/bin" watch_file pyproject.toml watch_file uv.lock - watch_file .python-version } diff --git a/modules/home/discord/default.nix b/modules/home/discord/default.nix index f9892df..bfa5d40 100644 --- a/modules/home/discord/default.nix +++ b/modules/home/discord/default.nix @@ -1,6 +1,8 @@ { config, lib, pkgs, ... }: let cfg = config.my.home.discord; + + jsonFormat = pkgs.formats.json { }; in { options.my.home.discord = with lib; { @@ -10,15 +12,14 @@ in }; config = lib.mkIf cfg.enable { - programs.discord = { - enable = true; + home.packages = with pkgs; [ + cfg.package + ]; - inherit (cfg) package; - - settings = { + xdg.configFile."discord/settings.json".source = + jsonFormat.generate "discord.json" { # Do not keep me from using the app just to force an update SKIP_HOST_UPDATE = true; }; - }; }; } diff --git a/modules/home/firefox/default.nix b/modules/home/firefox/default.nix index 6346dc9..02c74f2 100644 --- a/modules/home/firefox/default.nix +++ b/modules/home/firefox/default.nix @@ -61,21 +61,19 @@ in "ui.systemUsesDarkTheme" = true; # Dark mode }; - extensions = { - packages = with pkgs.nur.repos.rycee.firefox-addons; ([ - bitwarden - consent-o-matic - form-history-control - reddit-comment-collapser - reddit-enhancement-suite - refined-github - sponsorblock - ublock-origin - ] - ++ lib.optional (cfg.tridactyl.enable) tridactyl - ++ lib.optional (cfg.ff2mpv.enable) ff2mpv - ); - }; + extensions = with pkgs.nur.repos.rycee.firefox-addons; ([ + bitwarden + consent-o-matic + form-history-control + reddit-comment-collapser + reddit-enhancement-suite + refined-github + sponsorblock + ublock-origin + ] + ++ lib.optional (cfg.tridactyl.enable) tridactyl + ++ lib.optional (cfg.ff2mpv.enable) ff2mpv + ); }; }; }; diff --git a/modules/home/firefox/tridactyl/default.nix b/modules/home/firefox/tridactyl/default.nix index 26ddfad..35b58c2 100644 --- a/modules/home/firefox/tridactyl/default.nix +++ b/modules/home/firefox/tridactyl/default.nix @@ -12,7 +12,9 @@ let in { config = lib.mkIf cfg.enable { - xdg.configFile."tridactyl/tridactylrc".source = pkgs.replaceVars ./tridactylrc { + xdg.configFile."tridactyl/tridactylrc".source = pkgs.substituteAll { + src = ./tridactylrc; + editorcmd = lib.concatStringsSep " " [ # Use my configured terminal term diff --git a/modules/home/git/default.nix b/modules/home/git/default.nix index c3a51a0..1bb2215 100644 --- a/modules/home/git/default.nix +++ b/modules/home/git/default.nix @@ -21,31 +21,57 @@ in config.programs.git = lib.mkIf cfg.enable { enable = true; + # Who am I? + userEmail = mkMailAddress "bruno" "belanyi.fr"; + userName = "Bruno BELANYI"; + inherit (cfg) package; + aliases = { + git = "!git"; + lol = "log --graph --decorate --pretty=oneline --abbrev-commit --topo-order"; + lola = "lol --all"; + assume = "update-index --assume-unchanged"; + unassume = "update-index --no-assume-unchanged"; + assumed = "!git ls-files -v | grep ^h | cut -c 3-"; + pick = "log -p -G"; + push-new = "!git push -u origin " + + ''"$(git branch | grep '^* ' | cut -f2- -d' ')"''; + root = "git rev-parse --show-toplevel"; + }; + lfs.enable = true; + delta = { + enable = true; + + options = { + features = "diff-highlight decorations"; + + # Less jarring style for `diff-highlight` emulation + diff-highlight = { + minus-style = "red"; + minus-non-emph-style = "red"; + minus-emph-style = "bold red 52"; + + plus-style = "green"; + plus-non-emph-style = "green"; + plus-emph-style = "bold green 22"; + + whitespace-error-style = "reverse red"; + }; + + # Personal preference for easier reading + decorations = { + commit-style = "raw"; # Do not recolor meta information + keep-plus-minus-markers = true; + paging = "always"; + }; + }; + }; + # There's more - settings = { - # Who am I? - user = { - email = mkMailAddress "bruno" "belanyi.fr"; - name = "Bruno BELANYI"; - }; - - alias = { - git = "!git"; - lol = "log --graph --decorate --pretty=oneline --abbrev-commit --topo-order"; - lola = "lol --all"; - assume = "update-index --assume-unchanged"; - unassume = "update-index --no-assume-unchanged"; - assumed = "!git ls-files -v | grep ^h | cut -c 3-"; - pick = "log -p -G"; - push-new = "!git push -u origin " - + ''"$(git branch | grep '^* ' | cut -f2- -d' ')"''; - root = "git rev-parse --show-toplevel"; - }; - + extraConfig = { # Makes it a bit more readable blame = { coloring = "repeatedLines"; @@ -97,6 +123,11 @@ in defaultBranch = "main"; }; + # Local configuration, not-versioned + include = { + path = "config.local"; + }; + merge = { conflictStyle = "zdiff3"; }; @@ -136,8 +167,8 @@ in }; }; - includes = lib.mkAfter [ - # Multiple identities + # Multiple identities + includes = [ { condition = "gitdir:~/git/EPITA/"; contents = { @@ -156,10 +187,6 @@ in }; }; } - # Local configuration, not-versioned - { - path = "config.local"; - } ]; ignores = diff --git a/modules/home/gpg/default.nix b/modules/home/gpg/default.nix index 2a00baf..51c865a 100644 --- a/modules/home/gpg/default.nix +++ b/modules/home/gpg/default.nix @@ -17,7 +17,7 @@ in services.gpg-agent = { enable = true; enableSshSupport = true; # One agent to rule them all - pinentry.package = cfg.pinentry; + pinentryPackage = cfg.pinentry; extraConfig = '' allow-loopback-pinentry ''; diff --git a/modules/home/jq/default.nix b/modules/home/jq/default.nix index 53e5986..57e266f 100644 --- a/modules/home/jq/default.nix +++ b/modules/home/jq/default.nix @@ -17,7 +17,6 @@ in strings = "0;32"; arrays = "1;39"; objects = "1;39"; - objectKeys = "1;34"; }; }; } diff --git a/modules/home/mail/accounts/default.nix b/modules/home/mail/accounts/default.nix index 5216ad5..202b9bc 100644 --- a/modules/home/mail/accounts/default.nix +++ b/modules/home/mail/accounts/default.nix @@ -26,7 +26,20 @@ let }; migaduConfig = { - flavor = "migadu.com"; + imap = { + host = "imap.migadu.com"; + port = 993; + tls = { + enable = true; + }; + }; + smtp = { + host = "smtp.migadu.com"; + port = 465; + tls = { + enable = true; + }; + }; }; gmailConfig = { diff --git a/modules/home/nix/default.nix b/modules/home/nix/default.nix index 2f435a8..c0bbcc8 100644 --- a/modules/home/nix/default.nix +++ b/modules/home/nix/default.nix @@ -22,10 +22,6 @@ in options.my.home.nix = with lib; { enable = my.mkDisableOption "nix configuration"; - gc = { - enable = my.mkDisableOption "nix GC configuration"; - }; - cache = { selfHosted = my.mkDisableOption "self-hosted cache"; }; @@ -64,22 +60,6 @@ in }; } - (lib.mkIf cfg.gc.enable { - nix.gc = { - automatic = true; - - # Every week, with some wiggle room - dates = "weekly"; - randomizedDelaySec = "10min"; - - # Use a persistent timer for e.g: laptops - persistent = true; - - # Delete old profiles automatically after 15 days - options = "--delete-older-than 15d"; - }; - }) - (lib.mkIf cfg.cache.selfHosted { nix = { settings = { diff --git a/modules/home/packages/default.nix b/modules/home/packages/default.nix index 43f7111..1362a06 100644 --- a/modules/home/packages/default.nix +++ b/modules/home/packages/default.nix @@ -1,7 +1,6 @@ -{ config, lib, pkgs, osConfig, ... }: +{ config, lib, pkgs, ... }: let cfg = config.my.home.packages; - useGlobalPkgs = osConfig.home-manager.useGlobalPkgs or false; in { options.my.home.packages = with lib; { @@ -27,10 +26,9 @@ in fd file ripgrep - tree ] ++ cfg.additionalPackages); - nixpkgs.config = lib.mkIf (!useGlobalPkgs) { + nixpkgs.config = { inherit (cfg) allowAliases allowUnfree; }; }; diff --git a/modules/home/pager/default.nix b/modules/home/pager/default.nix index e84dcb7..1119440 100644 --- a/modules/home/pager/default.nix +++ b/modules/home/pager/default.nix @@ -16,11 +16,7 @@ in LESS = "-R -+X -c"; # Better XDG compliance LESSHISTFILE = "${config.xdg.stateHome}/less/history"; + LESSKEY = "${config.xdg.configHome}/less/lesskey"; }; - - xdg.configFile."lesskey".text = '' - # Quit without clearing the screen on `Q` - Q toggle-option -!^Predraw-on-quit\nq - ''; }; } diff --git a/modules/home/secrets/github/token.age b/modules/home/secrets/github/token.age index 3e8bb5a..1d36ccd 100644 Binary files a/modules/home/secrets/github/token.age and b/modules/home/secrets/github/token.age differ diff --git a/modules/home/secrets/secrets.nix b/modules/home/secrets/secrets.nix index 27cdb4e..f474342 100644 --- a/modules/home/secrets/secrets.nix +++ b/modules/home/secrets/secrets.nix @@ -1,6 +1,6 @@ # Common secrets let - keys = import ../../../keys; + keys = import ../../keys; all = builtins.attrValues keys.users; in diff --git a/modules/home/ssh/default.nix b/modules/home/ssh/default.nix index b0b4167..748b195 100644 --- a/modules/home/ssh/default.nix +++ b/modules/home/ssh/default.nix @@ -17,7 +17,6 @@ in { programs.ssh = { enable = true; - enableDefaultConfig = false; includes = [ # Local configuration, not-versioned @@ -54,12 +53,11 @@ in identityFile = "~/.ssh/shared_rsa"; user = "ambroisie"; }; - - # `*` is automatically made the last match block by the module - "*" = { - addKeysToAgent = "yes"; - }; }; + + extraConfig = '' + AddKeysToAgent yes + ''; }; } diff --git a/modules/home/tmux/default.nix b/modules/home/tmux/default.nix index e3e3daf..71ce4ca 100644 --- a/modules/home/tmux/default.nix +++ b/modules/home/tmux/default.nix @@ -6,7 +6,7 @@ let (config.my.home.wm.windowManager != null) ]; - mkTerminalFeature = opt: flag: + mkTerminalFlags = opt: flag: let mkFlag = term: ''set -as terminal-features ",${term}:${flag}"''; enabledTerminals = lib.filterAttrs (_: v: v.${opt}) cfg.terminalFeatures; @@ -20,8 +20,6 @@ in enablePassthrough = mkEnableOption "tmux DCS passthrough sequence"; - enableResurrect = mkEnableOption "tmux-resurrect plugin"; - terminalFeatures = mkOption { type = with types; attrsOf (submodule { options = { @@ -48,21 +46,18 @@ in keyMode = "vi"; # Home-row keys and other niceties clock24 = true; # I'm one of those heathens escapeTime = 0; # Let vim do its thing instead - historyLimit = 1000000; # Bigger buffer - mouse = false; # I dislike mouse support - focusEvents = true; # Report focus events + historyLimit = 100000; # Bigger buffer terminal = "tmux-256color"; # I want accurate termcap info - aggressiveResize = true; # Automatic resize when switching client size - plugins = with pkgs.tmuxPlugins; builtins.filter (attr: attr != { }) [ + plugins = with pkgs.tmuxPlugins; [ # Open high-lighted files in copy mode open # Better pane management pain-control # Better session management sessionist - # X clipboard integration { + # X clipboard integration plugin = yank; extraConfig = '' # Use 'clipboard' because of misbehaving apps (e.g: firefox) @@ -71,8 +66,8 @@ in set -g @yank_action 'copy-pipe' ''; } - # Show when prefix has been pressed { + # Show when prefix has been pressed plugin = prefix-highlight; extraConfig = '' # Also show when I'm in copy or sync mode @@ -82,23 +77,9 @@ in set -g status-right '#{prefix_highlight} %a %Y-%m-%d %H:%M' ''; } - # Resurrect sessions - (lib.optionalAttrs cfg.enableResurrect { - plugin = resurrect; - extraConfig = '' - set -g @resurrect-dir '${config.xdg.stateHome}/tmux/resurrect' - ''; - }) ]; extraConfig = '' - # Refresh configuration - bind-key -N "Source tmux.conf" R source-file ${config.xdg.configHome}/tmux/tmux.conf \; display-message "Sourced tmux.conf!" - - # Accept sloppy Ctrl key when switching windows, on top of default mapping - bind-key -N "Select the previous window" C-p previous-window - bind-key -N "Select the next window" C-n next-window - # Better vim mode bind-key -T copy-mode-vi 'v' send -X begin-selection ${ @@ -123,9 +104,9 @@ in } # Force OSC8 hyperlinks for each relevant $TERM - ${mkTerminalFeature "hyperlinks" "hyperlinks"} + ${mkTerminalFlags "hyperlinks" "hyperlinks"} # Force 24-bit color for each relevant $TERM - ${mkTerminalFeature "trueColor" "RGB"} + ${mkTerminalFlags "trueColor" "RGB"} ''; }; } diff --git a/modules/home/trgui/default.nix b/modules/home/trgui/default.nix deleted file mode 100644 index ee545a9..0000000 --- a/modules/home/trgui/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ config, lib, pkgs, ... }: -let - cfg = config.my.home.trgui; -in -{ - options.my.home.trgui = with lib; { - enable = mkEnableOption "Transmission GUI onfiguration"; - - package = mkPackageOption pkgs "TrguiNG" { default = "trgui-ng"; }; - }; - - config = lib.mkIf cfg.enable { - home.packages = with pkgs; [ - cfg.package - ]; - }; -} diff --git a/modules/home/vim/after/ftplugin/query.vim b/modules/home/vim/after/ftplugin/query.vim deleted file mode 100644 index fd2ac73..0000000 --- a/modules/home/vim/after/ftplugin/query.vim +++ /dev/null @@ -1,6 +0,0 @@ -" Create the `b:undo_ftplugin` variable if it doesn't exist -call ftplugined#check_undo_ft() - -" Use a small indentation value on query files -setlocal shiftwidth=2 -let b:undo_ftplugin.='|setlocal shiftwidth<' diff --git a/modules/home/vim/after/plugin/mappings/unimpaired.lua b/modules/home/vim/after/plugin/mappings/unimpaired.lua index 765b6b1..6716a82 100644 --- a/modules/home/vim/after/plugin/mappings/unimpaired.lua +++ b/modules/home/vim/after/plugin/mappings/unimpaired.lua @@ -31,6 +31,8 @@ local keys = { { "[u", desc = "URL encode" }, { "[x", desc = "XML encode" }, { "[y", desc = "C string encode" }, + -- Custom + { "[d", lsp.goto_prev_diagnostic, desc = "Previous diagnostic" }, -- Next { "]", group = "Next" }, @@ -60,6 +62,8 @@ local keys = { { "]u", desc = "URL decode" }, { "]x", desc = "XML decode" }, { "]y", desc = "C string decode" }, + -- Custom + { "]d", lsp.goto_next_diagnostic, desc = "Next diagnostic" }, -- Enable option { "[o", group = "Enable option" }, @@ -105,13 +109,13 @@ local keys = { { "yoc", desc = "Cursor line" }, { "yod", desc = "Diff" }, { "yof", "FormatToggle", desc = "LSP Formatting" }, - { "yoh", desc = "Search high-lighting" }, + { "yoh", desc = "Search high-lighting" }, -- spellchecker:disable-line { "yoi", desc = "Case insensitive search" }, { "yol", desc = "List mode" }, { "yon", desc = "Line numbers" }, { "yop", "(qf_loc_toggle)", desc = "Location list" }, { "yoq", "(qf_qf_toggle)", desc = "Quickfix list" }, - { "yor", desc = "Relative line numbers" }, + { "yor", desc = "Relative line numbers" }, -- spellchecker:disable-line { "you", desc = "Cursor column" }, { "yov", desc = "Virtual editing" }, { "yow", desc = "Text wrapping" }, diff --git a/modules/home/vim/after/queries/gitcommit/highlights.scm b/modules/home/vim/after/queries/gitcommit/highlights.scm deleted file mode 100644 index 05162c9..0000000 --- a/modules/home/vim/after/queries/gitcommit/highlights.scm +++ /dev/null @@ -1,6 +0,0 @@ -; extends - -; Highlight over-extended subject lines (rely on wrapping for message body) -((subject) @comment.error - (#vim-match? @comment.error ".\{50,}") - (#offset! @comment.error 0 50 0 0)) diff --git a/modules/home/vim/default.nix b/modules/home/vim/default.nix index 930a853..a063483 100644 --- a/modules/home/vim/default.nix +++ b/modules/home/vim/default.nix @@ -59,6 +59,7 @@ in # LSP and linting nvim-lspconfig # Easy LSP configuration lsp-format-nvim # Simplified formatting configuration + lsp_lines-nvim # Show diagnostics *over* regions none-ls-nvim # LSP integration for linters and formatters nvim-treesitter.withAllGrammars # Better highlighting nvim-treesitter-textobjects # More textobjects @@ -66,6 +67,7 @@ in # Completion luasnip # Snippet manager compatible with LSP + friendly-snippets # LSP snippets collection nvim-cmp # Completion engine cmp-async-path # More responsive path completion cmp-buffer # Words from open buffers @@ -80,6 +82,7 @@ in nvim-surround # Deal with pairs, now in Lua oil-nvim # Better alternative to NetrW telescope-fzf-native-nvim # Use 'fzf' fuzzy matching algorithm + telescope-lsp-handlers-nvim # Use 'telescope' for various LSP actions telescope-nvim # Fuzzy finder interface which-key-nvim # Show available mappings ]; @@ -97,9 +100,6 @@ in # Shell bash-language-server shfmt - - # Generic - typos-lsp ]; }; diff --git a/modules/home/vim/ftdetect/glsl.lua b/modules/home/vim/ftdetect/glsl.lua new file mode 100644 index 0000000..2f4f1dd --- /dev/null +++ b/modules/home/vim/ftdetect/glsl.lua @@ -0,0 +1,7 @@ +-- Use GLSL filetype for common shader file extensions +vim.filetype.add({ + extension = { + frag = "glsl", + vert = "glsl", + }, +}) diff --git a/modules/home/vim/init.vim b/modules/home/vim/init.vim index 1142925..8202cad 100644 --- a/modules/home/vim/init.vim +++ b/modules/home/vim/init.vim @@ -68,6 +68,8 @@ set listchars=tab:>─,trail:·,nbsp:¤ " Use patience diff set diffopt+=algorithm:patience +" Align similar lines in each hunk +set diffopt+=linematch:50 " Don't redraw when executing macros set lazyredraw @@ -81,6 +83,9 @@ set updatetime=250 " Disable all mouse integrations set mouse= +" Set dark mode by default +set background=dark + " Setup some overrides for gruvbox lua << EOF local gruvbox = require("gruvbox") @@ -97,11 +102,7 @@ gruvbox.setup({ DiffText = { fg = colors.yellow, bg = colors.bg0 }, -- Directories "pop" better in blue Directory = { link = "GruvboxBlueBold" }, - }, - italic = { - -- Comments should not be italic, for e.g: box drawing - comments = false, - }, + } }) EOF " Use my preferred colorscheme diff --git a/modules/home/vim/lua/ambroisie/lsp.lua b/modules/home/vim/lua/ambroisie/lsp.lua index fef0487..eb53da6 100644 --- a/modules/home/vim/lua/ambroisie/lsp.lua +++ b/modules/home/vim/lua/ambroisie/lsp.lua @@ -3,6 +3,43 @@ local M = {} -- Simplified LSP formatting configuration local lsp_format = require("lsp-format") +--- Move to the next/previous diagnostic, automatically showing the diagnostics +--- float if necessary. +--- @param forward bool whether to go forward or backwards +local function goto_diagnostic(forward) + vim.validate({ + forward = { forward, "boolean" }, + }) + + local opts = { + float = false, + } + + -- Only show floating diagnostics if they are otherwise not displayed + local config = vim.diagnostic.config() + if not (config.virtual_text or config.virtual_lines) then + opts.float = true + end + + if forward then + vim.diagnostic.goto_next(opts) + else + vim.diagnostic.goto_prev(opts) + end +end + +--- Move to the next diagnostic, automatically showing the diagnostics float if +--- necessary. +M.goto_next_diagnostic = function() + goto_diagnostic(true) +end + +--- Move to the previous diagnostic, automatically showing the diagnostics float +--- if necessary. +M.goto_prev_diagnostic = function() + goto_diagnostic(false) +end + --- shared LSP configuration callback --- @param client native client configuration --- @param bufnr int? buffer number of the attached client @@ -42,10 +79,6 @@ M.on_attach = function(client, bufnr) vim.diagnostic.config({ virtual_text = text, virtual_lines = lines, - jump = { - -- Show float on jump if no diagnostic text is otherwise shown - float = not (text or lines), - }, }) end @@ -53,10 +86,6 @@ M.on_attach = function(client, bufnr) vim.diagnostic.open_float(nil, { scope = "buffer" }) end - local function toggle_inlay_hints() - vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled()) - end - local keys = { buffer = bufnr, -- LSP navigation @@ -71,7 +100,6 @@ M.on_attach = function(client, bufnr) { "ca", vim.lsp.buf.code_action, desc = "Code actions" }, { "cd", cycle_diagnostics_display, desc = "Cycle diagnostics display" }, { "cD", show_buffer_diagnostics, desc = "Show buffer diagnostics" }, - { "ch", toggle_inlay_hints, desc = "Toggle inlay hints" }, { "cr", vim.lsp.buf.rename, desc = "Rename symbol" }, { "cs", vim.lsp.buf.signature_help, desc = "Show signature" }, { "ct", vim.lsp.buf.type_definition, desc = "Go to type definition" }, diff --git a/modules/home/vim/lua/ambroisie/utils.lua b/modules/home/vim/lua/ambroisie/utils.lua index 0ee7c83..c9e9292 100644 --- a/modules/home/vim/lua/ambroisie/utils.lua +++ b/modules/home/vim/lua/ambroisie/utils.lua @@ -38,7 +38,7 @@ end --- @param bufnr int? buffer number --- @return table all active LSP client names M.list_lsp_clients = function(bufnr) - local clients = vim.lsp.get_clients({ bufnr = bufnr }) + local clients = vim.lsp.get_active_clients({ bufnr = bufnr }) local names = {} for _, client in ipairs(clients) do diff --git a/modules/home/vim/plugin/numbertoggle.lua b/modules/home/vim/plugin/numbertoggle.lua index b1e3df2..8042710 100644 --- a/modules/home/vim/plugin/numbertoggle.lua +++ b/modules/home/vim/plugin/numbertoggle.lua @@ -22,3 +22,13 @@ vim.api.nvim_create_autocmd({ "BufLeave", "FocusLost", "InsertEnter", "WinLeave" end end, }) + +-- Never show the sign column in a terminal buffer +vim.api.nvim_create_autocmd({ "TermOpen" }, { + pattern = "*", + group = numbertoggle, + callback = function() + vim.opt.number = false + vim.opt.relativenumber = false + end, +}) diff --git a/modules/home/vim/plugin/settings/fastfold.lua b/modules/home/vim/plugin/settings/fastfold.lua new file mode 100644 index 0000000..78ee937 --- /dev/null +++ b/modules/home/vim/plugin/settings/fastfold.lua @@ -0,0 +1,5 @@ +-- Intercept all fold commands +-- stylua: ignore +vim.g.fastfold_fold_command_suffixes = { + "x", "X", "a", "A", "o", "O", "c", "C", "r", "R", "m", "M", "i", "n", "N", +} diff --git a/modules/home/vim/plugin/settings/lsp-lines.lua b/modules/home/vim/plugin/settings/lsp-lines.lua new file mode 100644 index 0000000..9c79818 --- /dev/null +++ b/modules/home/vim/plugin/settings/lsp-lines.lua @@ -0,0 +1,3 @@ +local lsp_lines = require("lsp_lines") + +lsp_lines.setup() diff --git a/modules/home/vim/plugin/settings/lspconfig.lua b/modules/home/vim/plugin/settings/lspconfig.lua index 1596e84..2f355f4 100644 --- a/modules/home/vim/plugin/settings/lspconfig.lua +++ b/modules/home/vim/plugin/settings/lspconfig.lua @@ -1,3 +1,4 @@ +local lspconfig = require("lspconfig") local lsp = require("ambroisie.lsp") local utils = require("ambroisie.utils") @@ -15,57 +16,71 @@ vim.diagnostic.config({ update_in_insert = false, -- Show highest severity first severity_sort = true, - jump = { - -- Show float on diagnostic jumps - float = true, - }, }) -- Inform servers we are able to do completion, snippets, etc... local capabilities = require("cmp_nvim_lsp").default_capabilities() --- Shared configuration -vim.lsp.config("*", { - capabilities = capabilities, - on_attach = lsp.on_attach, -}) - -local servers = { - -- C/C++ - clangd = {}, - -- Haskell - hls = {}, - -- Nix - nil_ls = {}, - -- Python - pyright = {}, - ruff = {}, - -- Rust - rust_analyzer = {}, - -- Shell - bashls = { - filetypes = { "bash", "sh", "zsh" }, - settings = { - bashIde = { - shfmt = { - -- Simplify the code - simplifyCode = true, - -- Indent switch cases - caseIndent = true, - }, - }, - }, - }, - -- Starlark - starpls = {}, - -- Generic - harper_ls = {}, - typos_lsp = {}, -} - -for server, config in pairs(servers) do - if not vim.tbl_isempty(config) then - vim.lsp.config(server, config) - end - vim.lsp.enable(server) +-- C/C++ +if utils.is_executable("clangd") then + lspconfig.clangd.setup({ + capabilities = capabilities, + on_attach = lsp.on_attach, + }) +end + +-- Haskell +if utils.is_executable("haskell-language-server-wrapper") then + lspconfig.hls.setup({ + capabilities = capabilities, + on_attach = lsp.on_attach, + }) +end + +-- Nix +if utils.is_executable("nil") then + lspconfig.nil_ls.setup({ + capabilities = capabilities, + on_attach = lsp.on_attach, + }) +end + +-- Python +if utils.is_executable("pyright") then + lspconfig.pyright.setup({ + capabilities = capabilities, + on_attach = lsp.on_attach, + }) +end + +if utils.is_executable("ruff") then + lspconfig.ruff.setup({ + capabilities = capabilities, + on_attach = lsp.on_attach, + }) +end + +-- Rust +if utils.is_executable("rust-analyzer") then + lspconfig.rust_analyzer.setup({ + capabilities = capabilities, + on_attach = lsp.on_attach, + }) +end + +-- Shell +if utils.is_executable("bash-language-server") then + lspconfig.bashls.setup({ + filetypes = { "bash", "sh", "zsh" }, + capabilities = capabilities, + on_attach = lsp.on_attach, + }) +end + +-- Starlark +if utils.is_executable("starpls") then + lspconfig.starpls.setup({ + capabilities = capabilities, + on_attach = lsp.on_attach, + }) end diff --git a/modules/home/vim/plugin/settings/lualine.lua b/modules/home/vim/plugin/settings/lualine.lua index bbe4647..5219a95 100644 --- a/modules/home/vim/plugin/settings/lualine.lua +++ b/modules/home/vim/plugin/settings/lualine.lua @@ -1,5 +1,4 @@ local lualine = require("lualine") -local oil = require("oil") local utils = require("ambroisie.utils") local function list_spell_languages() @@ -31,7 +30,7 @@ lualine.setup({ { "mode" }, }, lualine_b = { - { "branch" }, + { "FugitiveHead" }, { "filename", symbols = { readonly = "🔒" } }, }, lualine_c = { @@ -58,21 +57,5 @@ lualine.setup({ extensions = { "fugitive", "quickfix", - { - sections = { - lualine_a = { - { "mode" }, - }, - lualine_b = { - { "branch" }, - }, - lualine_c = { - function() - return vim.fn.fnamemodify(oil.get_current_dir(), ":~") - end, - }, - }, - filetypes = { "oil" }, - }, }, }) diff --git a/modules/home/vim/plugin/settings/luasnip.lua b/modules/home/vim/plugin/settings/luasnip.lua new file mode 100644 index 0000000..80309d7 --- /dev/null +++ b/modules/home/vim/plugin/settings/luasnip.lua @@ -0,0 +1 @@ +require("luasnip.loaders.from_vscode").lazy_load() diff --git a/modules/home/vim/plugin/settings/null-ls.lua b/modules/home/vim/plugin/settings/null-ls.lua index 258a209..eadf16a 100644 --- a/modules/home/vim/plugin/settings/null-ls.lua +++ b/modules/home/vim/plugin/settings/null-ls.lua @@ -46,3 +46,29 @@ null_ls.register({ condition = utils.is_executable_condition("isort"), }), }) + +-- Shell (non-POSIX) +null_ls.register({ + null_ls.builtins.formatting.shfmt.with({ + -- Indent with 4 spaces, simplify the code, indent switch cases, + -- add space after redirection, use bash dialect + extra_args = { "-i", "4", "-s", "-ci", "-sr", "-ln", "bash" }, + -- Restrict to bash and zsh + filetypes = { "bash", "zsh" }, + -- Only used if available + condition = utils.is_executable_condition("shfmt"), + }), +}) + +-- Shell (POSIX) +null_ls.register({ + null_ls.builtins.formatting.shfmt.with({ + -- Indent with 4 spaces, simplify the code, indent switch cases, + -- add space after redirection, use POSIX + extra_args = { "-i", "4", "-s", "-ci", "-sr", "-ln", "posix" }, + -- Restrict to POSIX sh + filetypes = { "sh" }, + -- Only used if available + condition = utils.is_executable_condition("shfmt"), + }), +}) diff --git a/modules/home/vim/plugin/settings/oil.lua b/modules/home/vim/plugin/settings/oil.lua index 74d5007..a160725 100644 --- a/modules/home/vim/plugin/settings/oil.lua +++ b/modules/home/vim/plugin/settings/oil.lua @@ -4,8 +4,6 @@ local wk = require("which-key") local detail = false oil.setup({ - -- Don't show icons - columns = {}, view_options = { -- Show files and directories that start with "." by default show_hidden = true, diff --git a/modules/home/vim/plugin/settings/telescope.lua b/modules/home/vim/plugin/settings/telescope.lua index 810d51c..1a23928 100644 --- a/modules/home/vim/plugin/settings/telescope.lua +++ b/modules/home/vim/plugin/settings/telescope.lua @@ -23,6 +23,7 @@ telescope.setup({ }) telescope.load_extension("fzf") +telescope.load_extension("lsp_handlers") local keys = { { "f", group = "Fuzzy finder" }, diff --git a/modules/home/vim/plugin/signtoggle.lua b/modules/home/vim/plugin/signtoggle.lua index 3deca34..9765a81 100644 --- a/modules/home/vim/plugin/signtoggle.lua +++ b/modules/home/vim/plugin/signtoggle.lua @@ -1,21 +1,26 @@ local signtoggle = vim.api.nvim_create_augroup("signtoggle", { clear = true }) --- Only show sign column for the currently focused buffer, if it has a number column +-- Only show sign column for the currently focused buffer vim.api.nvim_create_autocmd({ "BufEnter", "FocusGained", "WinEnter" }, { pattern = "*", group = signtoggle, callback = function() - if vim.opt.number:get() then - vim.opt.signcolumn = "yes" - end + vim.opt.signcolumn = "yes" end, }) vim.api.nvim_create_autocmd({ "BufLeave", "FocusLost", "WinLeave" }, { pattern = "*", group = signtoggle, callback = function() - if vim.opt.number:get() then - vim.opt.signcolumn = "no" - end + vim.opt.signcolumn = "no" + end, +}) + +-- Never show the sign column in a terminal buffer +vim.api.nvim_create_autocmd({ "TermOpen" }, { + pattern = "*", + group = signtoggle, + callback = function() + vim.opt.signcolumn = "no" end, }) diff --git a/modules/home/wm/i3/default.nix b/modules/home/wm/i3/default.nix index 5f22bbe..1c2b8e9 100644 --- a/modules/home/wm/i3/default.nix +++ b/modules/home/wm/i3/default.nix @@ -12,8 +12,7 @@ let movementKeys = [ "Left" "Down" "Up" "Right" ]; vimMovementKeys = [ "h" "j" "k" "l" ]; shutdownMode = - "(l)ock, (e)xit, switch_(u)ser, (h)ibernate, (r)eboot, (Shift+s)hutdown"; - + "(l)ock, (e)xit, switch_(u)ser, (h)ibernate, (r)eboot, (Shift+s)hutdown"; # spellchecker:disable-line # Takes an attrset of bindings for movement keys, transforms it to Vim keys toVimKeyBindings = let @@ -127,11 +126,9 @@ in { class = "^Blueman-.*$"; } { title = "^htop$"; } { class = "^Thunderbird$"; instance = "Mailnews"; window_role = "filterlist"; } - { class = "^firefox$"; instance = "Places"; window_role = "Organizer"; } - { class = "^pavucontrol.*$"; } + { class = "^Pavucontrol.*$"; } { class = "^Arandr$"; } - { class = "^\\.blueman-manager-wrapped$"; } - { class = "^\\.arandr-wrapped$"; } + { class = ".?blueman-manager.*$"; } ]; }; @@ -373,7 +370,8 @@ in }; startup = [ - # NOTE: rely on systemd user services instead... + # FIXME + # { commdand; always; notification; } ]; window = { diff --git a/modules/home/wm/i3bar/default.nix b/modules/home/wm/i3bar/default.nix index 5ae0e7d..2080704 100644 --- a/modules/home/wm/i3bar/default.nix +++ b/modules/home/wm/i3bar/default.nix @@ -49,7 +49,7 @@ in }) (lib.optionalAttrs config.my.home.bluetooth.enable { block = "bluetooth"; - mac = "F7:78:BA:76:52:F7"; + mac = "F7:78:BA:76:52:F7"; # spellchecker:disable-line format = " $icon MX Ergo{ $percentage|} "; disconnected_format = ""; }) diff --git a/modules/home/xdg/default.nix b/modules/home/xdg/default.nix index 7a0c517..270200e 100644 --- a/modules/home/xdg/default.nix +++ b/modules/home/xdg/default.nix @@ -30,10 +30,11 @@ in }; # A tidy home is a tidy mind dataFile = { - "tig/.keep".text = ""; # `tig` uses `XDG_DATA_HOME` specifically... + "bash/.keep".text = ""; + "gdb/.keep".text = ""; + "tig/.keep".text = ""; }; stateFile = { - "bash/.keep".text = ""; "python/.keep".text = ""; }; }; @@ -56,7 +57,4 @@ in XCOMPOSECACHE = "${dataHome}/X11/xcompose"; _JAVA_OPTIONS = "-Djava.util.prefs.userRoot=${configHome}/java"; }; - - # Some modules *optionally* use `XDG_*_HOME` when told to - config.home.preferXdgDirectories = lib.mkIf cfg.enable true; } diff --git a/modules/home/zsh/default.nix b/modules/home/zsh/default.nix index 9524262..11b6cb2 100644 --- a/modules/home/zsh/default.nix +++ b/modules/home/zsh/default.nix @@ -1,6 +1,14 @@ { config, pkgs, lib, ... }: let cfg = config.my.home.zsh; + + # Have a nice relative path for XDG_CONFIG_HOME, without leading `/` + relativeXdgConfig = + let + noHome = lib.removePrefix config.home.homeDirectory; + noSlash = lib.removePrefix "/"; + in + noSlash (noHome config.xdg.configHome); in { options.my.home.zsh = with lib; { @@ -8,22 +16,16 @@ in launchTmux = mkEnableOption "auto launch tmux at shell start"; - completionSync = { - enable = mkEnableOption "zsh-completion-sync plugin"; - }; - notify = { enable = mkEnableOption "zsh-done notification"; exclude = mkOption { type = with types; listOf str; default = [ - "bat" "delta" "direnv reload" "fg" "git (?!push|pull|fetch)" - "home-manager (?!switch|build)" "htop" "less" "man" @@ -55,7 +57,7 @@ in programs.zsh = { enable = true; - dotDir = "${config.xdg.configHome}/zsh"; # Don't clutter $HOME + dotDir = "${relativeXdgConfig}/zsh"; # Don't clutter $HOME enableCompletion = true; history = { @@ -72,7 +74,7 @@ in plugins = [ { name = "fast-syntax-highlighting"; - file = "share/zsh/plugins/fast-syntax-highlighting/fast-syntax-highlighting.plugin.zsh"; + file = "share/zsh/site-functions/fast-syntax-highlighting.plugin.zsh"; src = pkgs.zsh-fast-syntax-highlighting; } { @@ -85,26 +87,28 @@ in # Modal editing is life, but CLI benefits from emacs gymnastics defaultKeymap = "emacs"; - initContent = lib.mkMerge [ - # Make those happen early to avoid doing double the work - (lib.mkBefore (lib.optionalString cfg.launchTmux '' - # Launch tmux unless already inside one - if [ -z "$TMUX" ]; then - exec tmux new-session - fi - '')) + # Make those happen early to avoid doing double the work + initExtraFirst = lib.mkBefore '' + ${ + lib.optionalString cfg.launchTmux '' + # Launch tmux unless already inside one + if [ -z "$TMUX" ]; then + exec tmux new-session + fi + '' + } + ''; - (lib.mkAfter '' - source ${./completion-styles.zsh} - source ${./extra-mappings.zsh} - source ${./options.zsh} + initExtra = lib.mkAfter '' + source ${./completion-styles.zsh} + source ${./extra-mappings.zsh} + source ${./options.zsh} - # Source local configuration - if [ -f "$ZDOTDIR/zshrc.local" ]; then - source "$ZDOTDIR/zshrc.local" - fi - '') - ]; + # Source local configuration + if [ -f "$ZDOTDIR/zshrc.local" ]; then + source "$ZDOTDIR/zshrc.local" + fi + ''; localVariables = { # I like having the full path @@ -122,18 +126,6 @@ in }; } - (lib.mkIf cfg.completionSync.enable { - programs.zsh = { - plugins = [ - { - name = "zsh-completion-sync"; - file = "share/zsh-completion-sync/zsh-completion-sync.plugin.zsh"; - src = pkgs.zsh-completion-sync; - } - ]; - }; - }) - (lib.mkIf cfg.notify.enable { programs.zsh = { plugins = [ @@ -159,7 +151,7 @@ in }; # Use OSC-777 to send the notification through SSH - initContent = lib.mkIf cfg.notify.ssh.useOsc777 '' + initExtra = lib.mkIf cfg.notify.ssh.useOsc777 '' done_send_notification() { local exit_status="$1" local title="$2" diff --git a/modules/nixos/hardware/bluetooth/default.nix b/modules/nixos/hardware/bluetooth/default.nix index b14ac21..e9b1991 100644 --- a/modules/nixos/hardware/bluetooth/default.nix +++ b/modules/nixos/hardware/bluetooth/default.nix @@ -20,7 +20,7 @@ in # Support for additional bluetooth codecs (lib.mkIf cfg.loadExtraCodecs { - services.pulseaudio = { + hardware.pulseaudio = { extraModules = [ pkgs.pulseaudio-modules-bt ]; package = pkgs.pulseaudioFull; }; diff --git a/modules/nixos/hardware/graphics/default.nix b/modules/nixos/hardware/graphics/default.nix index 7d8b359..89bb1cd 100644 --- a/modules/nixos/hardware/graphics/default.nix +++ b/modules/nixos/hardware/graphics/default.nix @@ -33,8 +33,9 @@ in # AMD GPU (lib.mkIf (cfg.gpuFlavor == "amd") { + boot.initrd.kernelModules = lib.mkIf cfg.amd.enableKernelModule [ "amdgpu" ]; + hardware.amdgpu = { - initrd.enable = cfg.amd.enableKernelModule; # Vulkan amdvlk = lib.mkIf cfg.amd.amdvlk { enable = true; diff --git a/modules/nixos/hardware/sound/default.nix b/modules/nixos/hardware/sound/default.nix index cd453de..e8ba7f7 100644 --- a/modules/nixos/hardware/sound/default.nix +++ b/modules/nixos/hardware/sound/default.nix @@ -54,7 +54,10 @@ in # Pulseaudio setup (lib.mkIf cfg.pulse.enable { - services.pulseaudio.enable = true; + # ALSA + sound.enable = true; + + hardware.pulseaudio.enable = true; }) ]); } diff --git a/modules/nixos/profiles/wm/default.nix b/modules/nixos/profiles/wm/default.nix index bca4d70..c227328 100644 --- a/modules/nixos/profiles/wm/default.nix +++ b/modules/nixos/profiles/wm/default.nix @@ -24,8 +24,6 @@ in my.home.udiskie.enable = true; # udiskie fails if it can't find this dbus service services.udisks2.enable = true; - # Ensure i3lock can actually unlock the session - security.pam.services.i3lock.enable = true; }) ]; } diff --git a/modules/nixos/profiles/x/default.nix b/modules/nixos/profiles/x/default.nix index 874f36f..ea77939 100644 --- a/modules/nixos/profiles/x/default.nix +++ b/modules/nixos/profiles/x/default.nix @@ -13,7 +13,7 @@ in # Nice wallpaper services.xserver.displayManager.lightdm.background = let - wallpapers = "${pkgs.kdePackages.plasma-workspace-wallpapers}/share/wallpapers"; + wallpapers = "${pkgs.plasma5Packages.plasma-workspace-wallpapers}/share/wallpapers"; in "${wallpapers}/summer_1am/contents/images/2560x1600.jpg"; diff --git a/modules/nixos/services/aria/default.nix b/modules/nixos/services/aria/default.nix index acbf0b7..2d1b3e2 100644 --- a/modules/nixos/services/aria/default.nix +++ b/modules/nixos/services/aria/default.nix @@ -65,7 +65,9 @@ in aria-rpc = { port = cfg.rpcPort; # Proxy websockets for RPC - websocketsLocations = [ "/" ]; + extraConfig = { + locations."/".proxyWebsockets = true; + }; }; }; diff --git a/modules/nixos/services/audiobookshelf/default.nix b/modules/nixos/services/audiobookshelf/default.nix index 04ec8b9..da9ec55 100644 --- a/modules/nixos/services/audiobookshelf/default.nix +++ b/modules/nixos/services/audiobookshelf/default.nix @@ -30,7 +30,9 @@ in audiobookshelf = { inherit (cfg) port; # Proxy websockets for RPC - websocketsLocations = [ "/" ]; + extraConfig = { + locations."/".proxyWebsockets = true; + }; }; }; diff --git a/modules/nixos/services/default.nix b/modules/nixos/services/default.nix index e03eca1..1211ee6 100644 --- a/modules/nixos/services/default.nix +++ b/modules/nixos/services/default.nix @@ -14,9 +14,8 @@ ./forgejo ./gitea ./grocy - ./homebox + ./indexers ./jellyfin - ./komga ./lohr ./matrix ./mealie @@ -38,7 +37,6 @@ ./servarr ./ssh-server ./tandoor-recipes - ./thelounge ./tlp ./transmission ./vikunja diff --git a/modules/nixos/services/drone/server/default.nix b/modules/nixos/services/drone/server/default.nix index d6148f4..a3a1e49 100644 --- a/modules/nixos/services/drone/server/default.nix +++ b/modules/nixos/services/drone/server/default.nix @@ -6,8 +6,8 @@ in config = lib.mkIf cfg.enable { systemd.services.drone-server = { wantedBy = [ "multi-user.target" ]; - after = [ "postgresql.target" ]; - requires = [ "postgresql.target" ]; + after = [ "postgresql.service" ]; + requires = [ "postgresql.service" ]; serviceConfig = { EnvironmentFile = [ cfg.secretFile diff --git a/modules/nixos/services/homebox/default.nix b/modules/nixos/services/homebox/default.nix deleted file mode 100644 index 524a6d7..0000000 --- a/modules/nixos/services/homebox/default.nix +++ /dev/null @@ -1,48 +0,0 @@ -# Home inventory made easy -{ config, lib, ... }: -let - cfg = config.my.services.homebox; -in -{ - options.my.services.homebox = with lib; { - enable = mkEnableOption "Homebox home inventory"; - - port = mkOption { - type = types.port; - default = 7745; - example = 8080; - description = "Internal port for webui"; - }; - }; - - config = lib.mkIf cfg.enable { - services.homebox = { - enable = true; - - # Automatic PostgreSQL provisioning - database = { - createLocally = true; - }; - - settings = { - # FIXME: mailer? - HBOX_WEB_PORT = toString cfg.port; - }; - }; - - my.services.nginx.virtualHosts = { - homebox = { - inherit (cfg) port; - websocketsLocations = [ "/api" ]; - }; - }; - - my.services.backup = { - paths = [ - (lib.removePrefix "file://" config.services.homebox.settings.HBOX_STORAGE_CONN_STRING) - ]; - }; - - # NOTE: unfortunately homebox does not log connection failures for fail2ban - }; -} diff --git a/modules/nixos/services/indexers/default.nix b/modules/nixos/services/indexers/default.nix new file mode 100644 index 0000000..8a42345 --- /dev/null +++ b/modules/nixos/services/indexers/default.nix @@ -0,0 +1,78 @@ +# Torrent and usenet meta-indexers +{ config, lib, ... }: +let + cfg = config.my.services.indexers; + + jackettPort = 9117; + nzbhydraPort = 5076; + prowlarrPort = 9696; +in +{ + options.my.services.indexers = with lib; { + jackett.enable = mkEnableOption "Jackett torrent meta-indexer"; + nzbhydra.enable = mkEnableOption "NZBHydra2 usenet meta-indexer"; + prowlarr.enable = mkEnableOption "Prowlarr torrent & usenet meta-indexer"; + }; + + config = lib.mkMerge [ + (lib.mkIf cfg.jackett.enable { + services.jackett = { + enable = true; + }; + + # Jackett wants to eat *all* my RAM if left to its own devices + systemd.services.jackett = { + serviceConfig = { + MemoryHigh = "15%"; + MemoryMax = "25%"; + }; + }; + + my.services.nginx.virtualHosts = { + jackett = { + port = jackettPort; + }; + }; + }) + + (lib.mkIf cfg.nzbhydra.enable { + services.nzbhydra2 = { + enable = true; + }; + + my.services.nginx.virtualHosts = { + nzbhydra = { + port = nzbhydraPort; + }; + }; + }) + + (lib.mkIf cfg.prowlarr.enable { + services.prowlarr = { + enable = true; + }; + + my.services.nginx.virtualHosts = { + prowlarr = { + port = prowlarrPort; + }; + }; + + services.fail2ban.jails = { + prowlarr = '' + enabled = true + filter = prowlarr + action = iptables-allports + ''; + }; + + environment.etc = { + "fail2ban/filter.d/prowlarr.conf".text = '' + [Definition] + failregex = ^.*\|Warn\|Auth\|Auth-Failure ip username .*$ + journalmatch = _SYSTEMD_UNIT=prowlarr.service + ''; + }; + }) + ]; +} diff --git a/modules/nixos/services/jellyfin/default.nix b/modules/nixos/services/jellyfin/default.nix index 6edeb67..e8910a5 100644 --- a/modules/nixos/services/jellyfin/default.nix +++ b/modules/nixos/services/jellyfin/default.nix @@ -27,13 +27,17 @@ in my.services.nginx.virtualHosts = { jellyfin = { port = 8096; - websocketsLocations = [ "/socket" ]; extraConfig = { locations."/" = { extraConfig = '' proxy_buffering off; ''; }; + # Too bad for the repetition... + locations."/socket" = { + proxyPass = "http://127.0.0.1:8096/"; + proxyWebsockets = true; + }; }; }; }; diff --git a/modules/nixos/services/komga/default.nix b/modules/nixos/services/komga/default.nix deleted file mode 100644 index 9af3cd1..0000000 --- a/modules/nixos/services/komga/default.nix +++ /dev/null @@ -1,55 +0,0 @@ -# A Comics/Manga media server -{ config, lib, ... }: -let - cfg = config.my.services.komga; -in -{ - options.my.services.komga = with lib; { - enable = mkEnableOption "Komga comics server"; - - port = mkOption { - type = types.port; - default = 4584; - example = 8080; - description = "Internal port for webui"; - }; - }; - - config = lib.mkIf cfg.enable { - services.komga = { - enable = true; - - group = "media"; - - settings = { - server.port = cfg.port; - logging.level.org.gotson.komga = "DEBUG"; # Needed for fail2ban - }; - }; - - # Set-up media group - users.groups.media = { }; - - my.services.nginx.virtualHosts = { - komga = { - inherit (cfg) port; - }; - }; - - services.fail2ban.jails = { - komga = '' - enabled = true - filter = komga - port = http,https - ''; - }; - - environment.etc = { - "fail2ban/filter.d/komga.conf".text = '' - [Definition] - failregex = ^.* ip=,.*Bad credentials.*$ - journalmatch = _SYSTEMD_UNIT=komga.service - ''; - }; - }; -} diff --git a/modules/nixos/services/matrix/bridges.nix b/modules/nixos/services/matrix/bridges.nix deleted file mode 100644 index 70f4118..0000000 --- a/modules/nixos/services/matrix/bridges.nix +++ /dev/null @@ -1,143 +0,0 @@ -# Matrix bridges for some services I use -{ config, lib, ... }: -let - cfg = config.my.services.matrix.bridges; - synapseCfg = config.services.matrix-synapse; - - domain = config.networking.domain; - serverName = synapseCfg.settings.server_name; - - mkBridgeOption = n: lib.mkEnableOption "${n} bridge" // { default = cfg.enable; }; - mkPortOption = n: default: lib.mkOption { - type = lib.types.port; - inherit default; - example = 8080; - description = "${n} bridge port"; - }; - mkEnvironmentFileOption = n: lib.mkOption { - type = lib.types.str; - example = "/run/secret/matrix/${lib.toLower n}-bridge-secrets.env"; - description = '' - Path to a file which should contain the secret values for ${n} bridge. - - Using through the following format: - - ``` - MATRIX_APPSERVICE_AS_TOKEN= - MATRIX_APPSERVICE_HS_TOKEN= - ``` - - Each bridge should use a different set of secrets, as they each register - their own independent double-puppetting appservice. - ''; - }; -in -{ - options.my.services.matrix.bridges = with lib; { - enable = mkEnableOption "bridges configuration"; - - admin = mkOption { - type = types.str; - default = "ambroisie"; - example = "admin"; - description = "Local username for the admin"; - }; - - facebook = { - enable = mkBridgeOption "Facebook"; - - port = mkPortOption "Facebook" 29321; - - environmentFile = mkEnvironmentFileOption "Facebook"; - }; - }; - - config = lib.mkMerge [ - (lib.mkIf cfg.facebook.enable { - services.mautrix-meta.instances.facebook = { - enable = true; - # Automatically register the bridge with synapse - registerToSynapse = true; - - # Provide `AS_TOKEN`, `HS_TOKEN` - inherit (cfg.facebook) environmentFile; - - settings = { - homeserver = { - domain = serverName; - address = "http://localhost:${toString config.my.services.matrix.port}"; - }; - - appservice = { - hostname = "localhost"; - inherit (cfg.facebook) port; - address = "http://localhost:${toString cfg.facebook.port}"; - public_address = "https://facebook-bridge.${domain}"; - - as_token = "$MATRIX_APPSERVICE_AS_TOKEN"; - hs_token = "$MATRIX_APPSERVICE_HS_TOKEN"; - - bot = { - username = "fbbot"; - }; - }; - - backfill = { - enabled = true; - }; - - bridge = { - delivery_receipts = true; - permissions = { - "*" = "relay"; - ${serverName} = "user"; - "@${cfg.admin}:${serverName}" = "admin"; - }; - }; - - database = { - type = "postgres"; - uri = "postgres:///mautrix-meta-facebook?host=/var/run/postgresql/"; - }; - - double_puppet = { - secrets = { - ${serverName} = "as_token:$MATRIX_APPSERVICE_AS_TOKEN"; - }; - }; - - network = { - # Don't be picky on Facebook/Messenger - allow_messenger_com_on_fb = true; - displayname_template = ''{{or .DisplayName .Username "Unknown user"}} (FB)''; - }; - - provisioning = { - shared_secret = "disable"; - }; - }; - }; - - services.postgresql = { - enable = true; - ensureDatabases = [ "mautrix-meta-facebook" ]; - ensureUsers = [{ - name = "mautrix-meta-facebook"; - ensureDBOwnership = true; - }]; - }; - - systemd.services.mautrix-meta-facebook = { - wants = [ "postgres.service" ]; - after = [ "postgres.service" ]; - }; - - my.services.nginx.virtualHosts = { - # Proxy to the bridge - "facebook-bridge" = { - inherit (cfg.facebook) port; - }; - }; - }) - ]; -} diff --git a/modules/nixos/services/matrix/default.nix b/modules/nixos/services/matrix/default.nix index 97dec2e..b958f76 100644 --- a/modules/nixos/services/matrix/default.nix +++ b/modules/nixos/services/matrix/default.nix @@ -1,49 +1,24 @@ -# Matrix homeserver setup. +# Matrix homeserver setup, using different endpoints for federation and client +# traffic. The main trick for this is defining two nginx servers endpoints for +# matrix.domain.com, each listening on different ports. +# +# Configuration shamelessly stolen from [1] +# +# [1]: https://github.com/alarsyo/nixos-config/blob/main/services/matrix.nix { config, lib, pkgs, ... }: let cfg = config.my.services.matrix; - adminPkg = pkgs.synapse-admin-etkecc; - + federationPort = { public = 8448; private = 11338; }; + clientPort = { public = 443; private = 11339; }; domain = config.networking.domain; matrixDomain = "matrix.${domain}"; - - serverConfig = { - "m.server" = "${matrixDomain}:443"; - }; - clientConfig = { - "m.homeserver" = { - "base_url" = "https://${matrixDomain}"; - "server_name" = domain; - }; - "m.identity_server" = { - "base_url" = "https://vector.im"; - }; - }; - - # ACAO required to allow element-web on any URL to request this json file - mkWellKnown = data: '' - default_type application/json; - add_header Access-Control-Allow-Origin *; - return 200 '${builtins.toJSON data}'; - ''; in { - imports = [ - ./bridges.nix - ]; - options.my.services.matrix = with lib; { enable = mkEnableOption "Matrix Synapse"; - port = mkOption { - type = types.port; - default = 8448; - example = 8008; - description = "Internal port for listeners"; - }; - secretFile = mkOption { type = with types; nullOr str; default = null; @@ -51,6 +26,21 @@ in description = "Shared secret to register users"; }; + slidingSync = { + port = mkOption { + type = types.port; + default = 8009; + example = 8084; + description = "Port used by sliding sync server"; + }; + + secretFile = mkOption { + type = types.str; + example = "/var/lib/matrix/sliding-sync-secret-file.env"; + description = "Secret file which contains SYNCV3_SECRET definition"; + }; + }; + mailConfigFile = mkOption { type = types.str; example = "/var/lib/matrix/email-config.yaml"; @@ -83,22 +73,22 @@ in enable_registration = false; listeners = [ + # Federation { - inherit (cfg) port; bind_addresses = [ "::1" ]; - type = "http"; - tls = false; + port = federationPort.private; + tls = false; # Terminated by nginx. x_forwarded = true; - resources = [ - { - names = [ "client" ]; - compress = true; - } - { - names = [ "federation" ]; - compress = false; - } - ]; + resources = [{ names = [ "federation" ]; compress = false; }]; + } + + # Client + { + bind_addresses = [ "::1" ]; + port = clientPort.private; + tls = false; # Terminated by nginx. + x_forwarded = true; + resources = [{ names = [ "client" ]; compress = false; }]; } ]; @@ -116,17 +106,38 @@ in ] ++ lib.optional (cfg.secretFile != null) cfg.secretFile; }; + services.matrix-sliding-sync = { + enable = true; + + settings = { + SYNCV3_SERVER = "https://${matrixDomain}"; + SYNCV3_BINDADDR = "127.0.0.1:${toString cfg.slidingSync.port}"; + }; + + environmentFile = cfg.slidingSync.secretFile; + }; + my.services.nginx.virtualHosts = { # Element Web app deployment chat = { root = pkgs.element-web.override { conf = { - default_server_config = clientConfig; - show_labs_settings = true; - default_country_code = "FR"; # cocorico - room_directory = { + default_server_config = { + "m.homeserver" = { + "base_url" = "https://${matrixDomain}"; + "server_name" = domain; + }; + "m.identity_server" = { + "base_url" = "https://vector.im"; + }; + "org.matrix.msc3575.proxy" = { + "url" = "https://matrix-sync.${domain}"; + }; + }; + showLabsSettings = true; + defaultCountryCode = "FR"; # cocorico + roomDirectory = { "servers" = [ - domain "matrix.org" "mozilla.org" ]; @@ -134,54 +145,109 @@ in }; }; }; - matrix = { - # Somewhat unused, but necessary for port collision detection - inherit (cfg) port; - - extraConfig = { - locations = { - # Or do a redirect instead of the 404, or whatever is appropriate - # for you. But do not put a Matrix Web client here! See the - # Element web section above. - "/".return = "404"; - - "/_matrix".proxyPass = "http://[::1]:${toString cfg.port}"; - "/_synapse".proxyPass = "http://[::1]:${toString cfg.port}"; - - "= /admin".return = "307 /admin/"; - "/admin/" = { - alias = "${adminPkg}/"; - priority = 500; - tryFiles = "$uri $uri/ /index.html"; - }; - "~ ^/admin/.*\\.(?:css|js|jpg|jpeg|gif|png|svg|ico|woff|woff2|ttf|eot|webp)$" = { - priority = 400; - root = adminPkg; - extraConfig = '' - rewrite ^/admin/(.*)$ /$1 break; - expires 30d; - more_set_headers "Cache-Control: public"; - ''; - }; - }; - }; + # Dummy VHosts for port collision detection + matrix-federation = { + port = federationPort.private; + }; + matrix-client = { + port = clientPort.private; + }; + # Sliding sync + matrix-sync = { + inherit (cfg.slidingSync) port; }; }; - # Setup well-known locations + # Those are too complicated to use my wrapper... services.nginx.virtualHosts = { + ${matrixDomain} = { + onlySSL = true; + useACMEHost = domain; + + locations = + let + proxyToClientPort = { + proxyPass = "http://[::1]:${toString clientPort.private}"; + }; + in + { + # Or do a redirect instead of the 404, or whatever is appropriate + # for you. But do not put a Matrix Web client here! See the + # Element web section below. + "/".return = "404"; + + "/_matrix" = proxyToClientPort; + "/_synapse/client" = proxyToClientPort; + + # Sliding sync + "~ ^/(client/|_matrix/client/unstable/org.matrix.msc3575/sync)" = { + proxyPass = "http://${config.services.matrix-sliding-sync.settings.SYNCV3_BINDADDR}"; + }; + }; + + listen = [ + { addr = "0.0.0.0"; port = clientPort.public; ssl = true; } + { addr = "[::]"; port = clientPort.public; ssl = true; } + ]; + + }; + + # same as above, but listening on the federation port + "${matrixDomain}_federation" = { + onlySSL = true; + serverName = matrixDomain; + useACMEHost = domain; + + locations."/".return = "404"; + + locations."/_matrix" = { + proxyPass = "http://[::1]:${toString federationPort.private}"; + }; + + listen = [ + { addr = "0.0.0.0"; port = federationPort.public; ssl = true; } + { addr = "[::]"; port = federationPort.public; ssl = true; } + ]; + }; + "${domain}" = { forceSSL = true; useACMEHost = domain; - locations."= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; - locations."= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig; + locations."= /.well-known/matrix/server".extraConfig = + let + server = { "m.server" = "${matrixDomain}:${toString federationPort.public}"; }; + in + '' + add_header Content-Type application/json; + return 200 '${builtins.toJSON server}'; + ''; + + locations."= /.well-known/matrix/client".extraConfig = + let + client = { + "m.homeserver" = { "base_url" = "https://${matrixDomain}"; }; + "m.identity_server" = { "base_url" = "https://vector.im"; }; + "org.matrix.msc3575.proxy" = { "url" = "https://matrix-sync.${domain}"; }; + }; + # ACAO required to allow element-web on any URL to request this json file + in + '' + add_header Content-Type application/json; + add_header Access-Control-Allow-Origin *; + return 200 '${builtins.toJSON client}'; + ''; }; }; # For administration tools. environment.systemPackages = [ pkgs.matrix-synapse ]; + networking.firewall.allowedTCPPorts = [ + clientPort.public + federationPort.public + ]; + my.services.backup = { paths = [ config.services.matrix-synapse.dataDir diff --git a/modules/nixos/services/mealie/default.nix b/modules/nixos/services/mealie/default.nix index f3774e1..664d5ba 100644 --- a/modules/nixos/services/mealie/default.nix +++ b/modules/nixos/services/mealie/default.nix @@ -32,15 +32,33 @@ in BASE_URL = "https://mealie.${config.networking.domain}"; TZ = config.time.timeZone; ALLOw_SIGNUP = "false"; - TOKEN_TIME = 24 * 180; # 180 days - }; - # Automatic PostgreSQL provisioning - database = { - createLocally = true; + # Use PostgreSQL + DB_ENGINE = "postgres"; + # Make it work with socket auth + POSTGRES_URL_OVERRIDE = "postgresql://mealie:@/mealie?host=/run/postgresql"; }; }; + systemd.services = { + mealie = { + after = [ "postgresql.service" ]; + requires = [ "postgresql.service" ]; + }; + }; + + # Set-up database + services.postgresql = { + enable = true; + ensureDatabases = [ "mealie" ]; + ensureUsers = [ + { + name = "mealie"; + ensureDBOwnership = true; + } + ]; + }; + my.services.nginx.virtualHosts = { mealie = { inherit (cfg) port; @@ -54,12 +72,6 @@ in }; }; - my.services.backup = { - paths = [ - "/var/lib/mealie" - ]; - }; - services.fail2ban.jails = { mealie = '' enabled = true diff --git a/modules/nixos/services/nextcloud/collabora.nix b/modules/nixos/services/nextcloud/collabora.nix deleted file mode 100644 index 408b232..0000000 --- a/modules/nixos/services/nextcloud/collabora.nix +++ /dev/null @@ -1,56 +0,0 @@ -# Document editor with Nextcloud -{ config, lib, ... }: -let - cfg = config.my.services.nextcloud.collabora; -in -{ - options.my.services.nextcloud.collabora = with lib; { - enable = mkEnableOption "Collabora integration"; - - port = mkOption { - type = types.port; - default = 9980; - example = 8080; - description = "Internal port for API"; - }; - }; - - config = lib.mkIf cfg.enable { - services.nextcloud = { - extraApps = { - inherit (config.services.nextcloud.package.packages.apps) richdocuments; - }; - }; - - services.collabora-online = { - enable = true; - inherit (cfg) port; - - aliasGroups = [ - { - host = "https://collabora.${config.networking.domain}"; - # Allow using from nextcloud - aliases = [ "https://${config.services.nextcloud.hostName}" ]; - } - ]; - - settings = { - # Rely on reverse proxy for SSL - ssl = { - enable = false; - termination = true; - }; - }; - }; - - my.services.nginx.virtualHosts = { - collabora = { - inherit (cfg) port; - websocketsLocations = [ - "~ ^/cool/(.*)/ws$" - "^~ /cool/adminws" - ]; - }; - }; - }; -} diff --git a/modules/nixos/services/nextcloud/default.nix b/modules/nixos/services/nextcloud/default.nix index 24515ff..d173fc0 100644 --- a/modules/nixos/services/nextcloud/default.nix +++ b/modules/nixos/services/nextcloud/default.nix @@ -4,10 +4,6 @@ let cfg = config.my.services.nextcloud; in { - imports = [ - ./collabora.nix - ]; - options.my.services.nextcloud = with lib; { enable = mkEnableOption "Nextcloud"; maxSize = mkOption { @@ -35,7 +31,7 @@ in config = lib.mkIf cfg.enable { services.nextcloud = { enable = true; - package = pkgs.nextcloud32; + package = pkgs.nextcloud29; hostName = "nextcloud.${config.networking.domain}"; home = "/var/lib/nextcloud"; maxUploadSize = cfg.maxSize; @@ -44,15 +40,11 @@ in adminuser = cfg.admin; adminpassFile = cfg.passwordFile; dbtype = "pgsql"; + dbhost = "/run/postgresql"; }; https = true; - # Automatic PostgreSQL provisioning - database = { - createLocally = true; - }; - settings = { overwriteprotocol = "https"; # Nginx only allows SSL }; @@ -62,16 +54,22 @@ in # Allow using the push service without hard-coding my IP in the configuration bendDomainToLocalhost = true; }; + }; - extraApps = { - inherit (config.services.nextcloud.package.packages.apps) - calendar - contacts - deck - tasks - ; - # notify_push is automatically installed by the module - }; + services.postgresql = { + enable = true; + ensureDatabases = [ "nextcloud" ]; + ensureUsers = [ + { + name = "nextcloud"; + ensureDBOwnership = true; + } + ]; + }; + + systemd.services."nextcloud-setup" = { + requires = [ "postgresql.service" ]; + after = [ "postgresql.service" ]; }; # The service above configures the domain, no need for my wrapper diff --git a/modules/nixos/services/nginx/default.nix b/modules/nixos/services/nginx/default.nix index ff530b0..e305b29 100644 --- a/modules/nixos/services/nginx/default.nix +++ b/modules/nixos/services/nginx/default.nix @@ -17,16 +17,6 @@ let ''; }; - websocketsLocations = mkOption { - type = with types; listOf str; - default = [ ]; - example = [ "/socket" ]; - description = '' - Which locations on this virtual host should be configured for - websockets. - ''; - }; - port = mkOption { type = with types; nullOr port; default = null; @@ -70,13 +60,10 @@ let extraConfig = mkOption { type = types.attrs; # FIXME: forward type of virtualHosts example = { - extraConfig = '' - add_header X-Clacks-Overhead "GNU Terry Pratchett"; - ''; - - locations."/".extraConfig = '' - client_max_body_size 1G; - ''; + locations."/socket" = { + proxyPass = "http://127.0.0.1:8096/"; + proxyWebsockets = true; + }; }; default = { }; description = '' @@ -87,6 +74,10 @@ let }); in { + imports = [ + ./sso + ]; + options.my.services.nginx = with lib; { enable = mkEnableOption "Nginx"; @@ -95,7 +86,7 @@ in type = types.str; example = "/var/lib/acme/creds.env"; description = '' - OVH API key file as an 'EnvironmentFile' (see `systemd.exec(5)`) + Gandi API key file as an 'EnvironmentFile' (see `systemd.exec(5)`) ''; }; }; @@ -117,7 +108,12 @@ in }; jellyfin = { port = 8096; - websocketsLocations = [ "/socket" ]; + extraConfig = { + locations."/socket" = { + proxyPass = "http://127.0.0.1:8096/"; + proxyWebsockets = true; + }; + }; }; }; description = '' @@ -199,19 +195,6 @@ in } configured. ''; })) - ++ (lib.flip lib.mapAttrsToList cfg.virtualHosts (_: { subdomain, ... } @ args: - let - proxyPass = [ "port" "socket" ]; - proxyPassUsed = lib.any (v: args.${v} != null) proxyPass; - in - { - assertion = args.websocketsLocations != [ ] -> proxyPassUsed; - message = '' - Subdomain '${subdomain}' can only use 'websocketsLocations' with one of ${ - lib.concatStringsSep ", " (builtins.map (v: "'${v}'") proxyPass) - }. - ''; - })) ++ ( let ports = lib.my.mapFilter @@ -253,18 +236,11 @@ in recommendedOptimisation = true; recommendedProxySettings = true; recommendedTlsSettings = true; + recommendedZstdSettings = true; virtualHosts = let domain = config.networking.domain; - mkProxyPass = { websocketsLocations, ... }: proxyPass: - let - websockets = lib.genAttrs websocketsLocations (_: { - inherit proxyPass; - proxyWebsockets = true; - }); - in - { "/" = { inherit proxyPass; }; } // websockets; mkVHost = ({ subdomain, ... } @ args: lib.nameValuePair "${subdomain}.${domain}" (lib.my.recursiveMerge [ @@ -275,7 +251,8 @@ in } # Proxy to port (lib.optionalAttrs (args.port != null) { - locations = mkProxyPass args "http://127.0.0.1:${toString args.port}"; + locations."/".proxyPass = + "http://127.0.0.1:${toString args.port}"; }) # Serve filesystem content (lib.optionalAttrs (args.root != null) { @@ -283,7 +260,8 @@ in }) # Serve to UNIX socket (lib.optionalAttrs (args.socket != null) { - locations = mkProxyPass args "http://unix:${args.socket}"; + locations."/".proxyPass = + "http://unix:${args.socket}"; }) # Redirect to a different domain (lib.optionalAttrs (args.redirect != null) { @@ -303,7 +281,6 @@ in locations."/" = { extraConfig = - # FIXME: check that X-User is dropped otherwise (args.extraConfig.locations."/".extraConfig or "") + '' # Use SSO auth_request /sso-auth; @@ -437,14 +414,13 @@ in { "${domain}" = { extraDomainNames = [ "*.${domain}" ]; - dnsProvider = "ovh"; - dnsPropagationCheck = false; # OVH is slow + dnsProvider = "gandiv5"; inherit (cfg.acme) credentialsFile; }; }; }; - systemd.services."acme-order-renew-${domain}" = { + systemd.services."acme-${domain}" = { serviceConfig = { Environment = [ # Since I do a "weird" setup with a wildcard CNAME diff --git a/modules/nixos/services/nginx/sso/default.nix b/modules/nixos/services/nginx/sso/default.nix new file mode 100644 index 0000000..d60e31b --- /dev/null +++ b/modules/nixos/services/nginx/sso/default.nix @@ -0,0 +1,84 @@ +# I must override the module to allow having runtime secrets +{ config, lib, pkgs, utils, ... }: +let + cfg = config.services.nginx.sso; + pkg = lib.getBin cfg.package; + confPath = "/var/lib/nginx-sso/config.json"; +in +{ + disabledModules = [ "services/security/nginx-sso.nix" ]; + + + options.services.nginx.sso = with lib; { + enable = mkEnableOption "nginx-sso service"; + + package = mkOption { + type = types.package; + default = pkgs.nginx-sso; + defaultText = "pkgs.nginx-sso"; + description = '' + The nginx-sso package that should be used. + ''; + }; + + configuration = mkOption { + type = types.attrsOf types.unspecified; + default = { }; + example = literalExample '' + { + listen = { addr = "127.0.0.1"; port = 8080; }; + + providers.token.tokens = { + myuser = "MyToken"; + }; + + acl = { + rule_sets = [ + { + rules = [ { field = "x-application"; equals = "MyApp"; } ]; + allow = [ "myuser" ]; + } + ]; + }; + } + ''; + description = '' + nginx-sso configuration + (documentation) + as a Nix attribute set. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.nginx-sso = { + description = "Nginx SSO Backend"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + StateDirectory = "nginx-sso"; + WorkingDirectory = "/var/lib/nginx-sso"; + # The files to be merged might not have the correct permissions + ExecStartPre = pkgs.writeShellScript "merge-nginx-sso-config" '' + rm -f '${confPath}' + ${utils.genJqSecretsReplacementSnippet cfg.configuration confPath} + ''; + ExecStart = lib.mkForce '' + ${lib.getExe pkg} \ + --config ${confPath} \ + --frontend-dir ${pkg}/share/frontend + ''; + Restart = "always"; + User = "nginx-sso"; + Group = "nginx-sso"; + }; + }; + + users.users.nginx-sso = { + isSystemUser = true; + group = "nginx-sso"; + }; + + users.groups.nginx-sso = { }; + }; +} diff --git a/modules/nixos/services/paperless/default.nix b/modules/nixos/services/paperless/default.nix index 1195977..f62879a 100644 --- a/modules/nixos/services/paperless/default.nix +++ b/modules/nixos/services/paperless/default.nix @@ -1,4 +1,4 @@ -{ config, lib, ... }: +{ config, lib, pkgs, ... }: let cfg = config.my.services.paperless; in @@ -52,39 +52,91 @@ in mediaDir = lib.mkIf (cfg.documentPath != null) cfg.documentPath; - settings = { - # Use SSO - PAPERLESS_ENABLE_HTTP_REMOTE_USER = true; - PAPERLESS_ENABLE_HTTP_REMOTE_USER_API = true; - PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME = "HTTP_X_USER"; + settings = + let + paperlessDomain = "paperless.${config.networking.domain}"; + in + { + # Use SSO + PAPERLESS_ENABLE_HTTP_REMOTE_USER = true; + PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME = "HTTP_X_USER"; - # Security settings - PAPERLESS_URL = "https://paperless.${config.networking.domain}"; - PAPERLESS_USE_X_FORWARD_HOST = true; - PAPERLESS_PROXY_SSL_HEADER = [ "HTTP_X_FORWARDED_PROTO" "https" ]; + # Use PostgreSQL + PAPERLESS_DBHOST = "/run/postgresql"; + PAPERLESS_DBUSER = "paperless"; + PAPERLESS_DBNAME = "paperless"; - # OCR settings - PAPERLESS_OCR_LANGUAGE = "fra+eng"; + # Security settings + PAPERLESS_ALLOWED_HOSTS = paperlessDomain; + PAPERLESS_CORS_ALLOWED_HOSTS = "https://${paperlessDomain}"; - # Workers - PAPERLESS_TASK_WORKERS = 3; - PAPERLESS_THREADS_PER_WORKER = 4; + # OCR settings + PAPERLESS_OCR_LANGUAGE = "fra+eng"; - # Misc - PAPERLESS_TIME_ZONE = config.time.timeZone; - PAPERLESS_ADMIN_USER = cfg.username; - }; + # Workers + PAPERLESS_TASK_WORKERS = 3; + PAPERLESS_THREADS_PER_WORKER = 4; + + # Misc + PAPERLESS_TIME_ZONE = config.time.timeZone; + PAPERLESS_ADMIN_USER = cfg.username; + + # Fix classifier hangs + LD_LIBRARY_PATH = "${lib.getLib pkgs.mkl}/lib"; + }; # Admin password passwordFile = cfg.passwordFile; + }; - # Secret key - environmentFile = cfg.secretKeyFile; + systemd.services = { + paperless-scheduler = { + requires = [ "postgresql.service" ]; + after = [ "postgresql.service" ]; - # Automatic PostgreSQL provisioning - database = { - createLocally = true; + serviceConfig = { + EnvironmentFile = cfg.secretKeyFile; + }; }; + + paperless-consumer = { + requires = [ "postgresql.service" ]; + after = [ "postgresql.service" ]; + + serviceConfig = { + EnvironmentFile = cfg.secretKeyFile; + }; + }; + + paperless-web = { + requires = [ "postgresql.service" ]; + after = [ "postgresql.service" ]; + + serviceConfig = { + EnvironmentFile = cfg.secretKeyFile; + }; + }; + + paperless-task-queue = { + requires = [ "postgresql.service" ]; + after = [ "postgresql.service" ]; + + serviceConfig = { + EnvironmentFile = cfg.secretKeyFile; + }; + }; + }; + + # Set-up database + services.postgresql = { + enable = true; + ensureDatabases = [ "paperless" ]; + ensureUsers = [ + { + name = "paperless"; + ensureDBOwnership = true; + } + ]; }; # Set-up media group @@ -100,7 +152,11 @@ in sso = { enable = true; }; - websocketsLocations = [ "/" ]; + + # Enable websockets on root + extraConfig = { + locations."/".proxyWebsockets = true; + }; }; }; diff --git a/modules/nixos/services/postgresql/default.nix b/modules/nixos/services/postgresql/default.nix index 1dca164..bbe46d4 100644 --- a/modules/nixos/services/postgresql/default.nix +++ b/modules/nixos/services/postgresql/default.nix @@ -14,7 +14,7 @@ in # Let other services enable postgres when they need it (lib.mkIf cfg.enable { services.postgresql = { - package = pkgs.postgresql_17; + package = pkgs.postgresql_13; }; }) @@ -23,15 +23,15 @@ in environment.systemPackages = let pgCfg = config.services.postgresql; - newPackage' = pkgs.postgresql_17; + newPackage' = pkgs.postgresql_13; oldPackage = if pgCfg.enableJIT then pgCfg.package.withJIT else pgCfg.package; oldData = pgCfg.dataDir; - oldBin = "${if pgCfg.extensions == [] then oldPackage else oldPackage.withPackages pgCfg.extensions}/bin"; + oldBin = "${if pgCfg.extraPlugins == [] then oldPackage else oldPackage.withPackages pgCfg.extraPlugins}/bin"; newPackage = if pgCfg.enableJIT then newPackage'.withJIT else newPackage'; newData = "/var/lib/postgresql/${newPackage.psqlSchema}"; - newBin = "${if pgCfg.extensions == [] then newPackage else newPackage.withPackages pgCfg.extensions}/bin"; + newBin = "${if pgCfg.extraPlugins == [] then newPackage else newPackage.withPackages pgCfg.extraPlugins}/bin"; in [ (pkgs.writeScriptBin "upgrade-pg-cluster" '' diff --git a/modules/nixos/services/pyload/default.nix b/modules/nixos/services/pyload/default.nix index 7257d0f..88889bf 100644 --- a/modules/nixos/services/pyload/default.nix +++ b/modules/nixos/services/pyload/default.nix @@ -53,20 +53,6 @@ in }; }; - services.fail2ban.jails = { - pyload = '' - enabled = true - filter = pyload - port = http,https - ''; - }; - - environment.etc = { - "fail2ban/filter.d/pyload.conf".text = '' - [Definition] - failregex = ^.*Login failed for user '.*' \[CLIENT: \]$ - journalmatch = _SYSTEMD_UNIT=pyload.service - ''; - }; + # FIXME: fail2ban }; } diff --git a/modules/nixos/services/servarr/autobrr.nix b/modules/nixos/services/servarr/autobrr.nix deleted file mode 100644 index c3370cb..0000000 --- a/modules/nixos/services/servarr/autobrr.nix +++ /dev/null @@ -1,63 +0,0 @@ -# IRC-based indexer -{ config, lib, ... }: -let - cfg = config.my.services.servarr.autobrr; -in -{ - options.my.services.servarr.autobrr = with lib; { - enable = mkEnableOption "autobrr IRC announce tracker" // { - default = config.my.services.servarr.enableAll; - }; - - port = mkOption { - type = types.port; - default = 7474; - example = 8080; - description = "Internal port for webui"; - }; - - sessionSecretFile = mkOption { - type = types.str; - example = "/run/secrets/autobrr-secret.txt"; - description = '' - File containing the session secret. - ''; - }; - }; - - config = lib.mkIf cfg.enable { - services.autobrr = { - enable = true; - - settings = { - inherit (cfg) port; - checkForUpdates = false; - }; - - secretFile = cfg.sessionSecretFile; - }; - - my.services.nginx.virtualHosts = { - autobrr = { - inherit (cfg) port; - websocketsLocations = [ "/api" ]; - }; - }; - - services.fail2ban.jails = { - autobrr = '' - enabled = true - filter = autobrr - action = iptables-allports - ''; - }; - - environment.etc = { - "fail2ban/filter.d/autobrr.conf".text = '' - [Definition] - failregex = "message":"Auth: Failed login attempt username: \[.*\] ip: " - journalmatch = _SYSTEMD_UNIT=autobrr.service - ''; - }; - }; -} diff --git a/modules/nixos/services/servarr/bazarr.nix b/modules/nixos/services/servarr/bazarr.nix deleted file mode 100644 index 637da0c..0000000 --- a/modules/nixos/services/servarr/bazarr.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ config, lib, ... }: -let - cfg = config.my.services.servarr.bazarr; -in -{ - options.my.services.servarr.bazarr = with lib; { - enable = lib.mkEnableOption "Bazarr" // { - default = config.my.services.servarr.enableAll; - }; - - port = mkOption { - type = types.port; - default = 6767; - example = 8080; - description = "Internal port for webui"; - }; - }; - - config = lib.mkIf cfg.enable { - services.bazarr = { - enable = true; - group = "media"; - listenPort = cfg.port; - }; - - # Set-up media group - users.groups.media = { }; - - my.services.nginx.virtualHosts = { - bazarr = { - inherit (cfg) port; - }; - }; - - # Bazarr does not log authentication failures... - }; -} diff --git a/modules/nixos/services/servarr/cross-seed.nix b/modules/nixos/services/servarr/cross-seed.nix deleted file mode 100644 index 74f216a..0000000 --- a/modules/nixos/services/servarr/cross-seed.nix +++ /dev/null @@ -1,96 +0,0 @@ -# Automatic cross-seeding for video media -{ config, lib, ... }: -let - cfg = config.my.services.servarr.cross-seed; -in -{ - options.my.services.servarr.cross-seed = with lib; { - enable = mkEnableOption "cross-seed daemon" // { - default = config.my.services.servarr.enableAll; - }; - - port = mkOption { - type = types.port; - default = 2468; - example = 8080; - description = "Internal port for daemon"; - }; - - linkDirectory = mkOption { - type = types.str; - default = "/data/downloads/complete/links"; - example = "/var/lib/cross-seed/links"; - description = "Link directory"; - }; - - secretSettingsFile = mkOption { - type = types.str; - example = "/run/secrets/cross-seed-secrets.json"; - description = '' - File containing secret settings. - ''; - }; - }; - - config = lib.mkIf cfg.enable { - services.cross-seed = { - enable = true; - group = "media"; - - # Rely on recommended defaults for tracker snatches etc... - useGenConfigDefaults = true; - - settings = { - inherit (cfg) port; - host = "127.0.0.1"; - - # Inject torrents to client directly - action = "inject"; - # Query the client for torrents to match - useClientTorrents = true; - # Use hardlinks - linkType = "hardlink"; - # Use configured link directory - linkDirs = [ cfg.linkDirectory ]; - # Match as many torrents as possible - matchMode = "partial"; - # Cross-seed full season if at least 50% of episodes are already downloaded - seasonFromEpisodes = 0.5; - }; - - settingsFile = cfg.secretSettingsFile; - }; - - systemd.services.cross-seed = { - serviceConfig = { - # Loose umask to make cross-seed links readable by `media` - UMask = "0002"; - }; - }; - - # Set-up media group - users.groups.media = { }; - - my.services.nginx.virtualHosts = { - cross-seed = { - inherit (cfg) port; - }; - }; - - services.fail2ban.jails = { - cross-seed = '' - enabled = true - filter = cross-seed - action = iptables-allports - ''; - }; - - environment.etc = { - "fail2ban/filter.d/cross-seed.conf".text = '' - [Definition] - failregex = ^.*Unauthorized API access attempt to .* from $ - journalmatch = _SYSTEMD_UNIT=cross-seed.service - ''; - }; - }; -} diff --git a/modules/nixos/services/servarr/default.nix b/modules/nixos/services/servarr/default.nix index dca57cf..e25d9cf 100644 --- a/modules/nixos/services/servarr/default.nix +++ b/modules/nixos/services/servarr/default.nix @@ -2,22 +2,99 @@ # Relevant link [1]. # # [1]: https://youtu.be/I26Ql-uX6AM -{ lib, ... }: -{ - imports = [ - ./autobrr.nix - ./bazarr.nix - ./cross-seed.nix - ./jackett.nix - ./nzbhydra.nix - ./prowlarr.nix - (import ./starr.nix "lidarr") - (import ./starr.nix "radarr") - (import ./starr.nix "readarr") - (import ./starr.nix "sonarr") - ]; +{ config, lib, ... }: +let + cfg = config.my.services.servarr; - options.my.services.servarr = { - enableAll = lib.mkEnableOption "media automation suite"; + ports = { + bazarr = 6767; + lidarr = 8686; + radarr = 7878; + readarr = 8787; + sonarr = 8989; }; + + mkService = service: { + services.${service} = { + enable = true; + group = "media"; + }; + }; + + mkRedirection = service: { + my.services.nginx.virtualHosts = { + ${service} = { + port = ports.${service}; + }; + }; + }; + + mkFail2Ban = service: lib.mkIf cfg.${service}.enable { + services.fail2ban.jails = { + ${service} = '' + enabled = true + filter = ${service} + action = iptables-allports + ''; + }; + + environment.etc = { + "fail2ban/filter.d/${service}.conf".text = '' + [Definition] + failregex = ^.*\|Warn\|Auth\|Auth-Failure ip username .*$ + journalmatch = _SYSTEMD_UNIT=${service}.service + ''; + }; + }; + + mkFullConfig = service: lib.mkIf cfg.${service}.enable (lib.mkMerge [ + (mkService service) + (mkRedirection service) + ]); +in +{ + options.my.services.servarr = { + enable = lib.mkEnableOption "Media automation"; + + bazarr = { + enable = lib.my.mkDisableOption "Bazarr"; + }; + + lidarr = { + enable = lib.my.mkDisableOption "Lidarr"; + }; + + radarr = { + enable = lib.my.mkDisableOption "Radarr"; + }; + + readarr = { + enable = lib.my.mkDisableOption "Readarr"; + }; + + sonarr = { + enable = lib.my.mkDisableOption "Sonarr"; + }; + }; + + config = lib.mkIf cfg.enable (lib.mkMerge [ + { + # Set-up media group + users.groups.media = { }; + } + # Bazarr does not log authentication failures... + (mkFullConfig "bazarr") + # Lidarr for music + (mkFullConfig "lidarr") + (mkFail2Ban "lidarr") + # Radarr for movies + (mkFullConfig "radarr") + (mkFail2Ban "radarr") + # Readarr for books + (mkFullConfig "readarr") + (mkFail2Ban "readarr") + # Sonarr for shows + (mkFullConfig "sonarr") + (mkFail2Ban "sonarr") + ]); } diff --git a/modules/nixos/services/servarr/jackett.nix b/modules/nixos/services/servarr/jackett.nix deleted file mode 100644 index 481cd3d..0000000 --- a/modules/nixos/services/servarr/jackett.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ config, lib, ... }: -let - cfg = config.my.services.servarr.jackett; -in -{ - options.my.services.servarr.jackett = with lib; { - enable = lib.mkEnableOption "Jackett" // { - default = config.my.services.servarr.enableAll; - }; - - port = mkOption { - type = types.port; - default = 9117; - example = 8080; - description = "Internal port for webui"; - }; - }; - - config = lib.mkIf cfg.enable { - services.jackett = { - enable = true; - inherit (cfg) port; - }; - - # Jackett wants to eat *all* my RAM if left to its own devices - systemd.services.jackett = { - serviceConfig = { - MemoryHigh = "15%"; - MemoryMax = "25%"; - }; - }; - - my.services.nginx.virtualHosts = { - jackett = { - inherit (cfg) port; - }; - }; - - # Jackett does not log authentication failures... - }; -} diff --git a/modules/nixos/services/servarr/nzbhydra.nix b/modules/nixos/services/servarr/nzbhydra.nix deleted file mode 100644 index 7b63986..0000000 --- a/modules/nixos/services/servarr/nzbhydra.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ config, lib, ... }: -let - cfg = config.my.services.servarr.nzbhydra; -in -{ - options.my.services.servarr.nzbhydra = with lib; { - enable = lib.mkEnableOption "NZBHydra2" // { - default = config.my.services.servarr.enableAll; - }; - }; - - config = lib.mkIf cfg.enable { - services.nzbhydra2 = { - enable = true; - }; - - my.services.nginx.virtualHosts = { - nzbhydra = { - port = 5076; - websocketsLocations = [ "/" ]; - }; - }; - - # NZBHydra2 does not log authentication failures... - }; -} diff --git a/modules/nixos/services/servarr/prowlarr.nix b/modules/nixos/services/servarr/prowlarr.nix deleted file mode 100644 index ce044c6..0000000 --- a/modules/nixos/services/servarr/prowlarr.nix +++ /dev/null @@ -1,53 +0,0 @@ -# Torrent and NZB indexer -{ config, lib, ... }: -let - cfg = config.my.services.servarr.prowlarr; -in -{ - options.my.services.servarr.prowlarr = with lib; { - enable = lib.mkEnableOption "Prowlarr" // { - default = config.my.services.servarr.enableAll; - }; - - port = mkOption { - type = types.port; - default = 9696; - example = 8080; - description = "Internal port for webui"; - }; - }; - - config = lib.mkIf cfg.enable { - services.prowlarr = { - enable = true; - - settings = { - server = { - port = cfg.port; - }; - }; - }; - - my.services.nginx.virtualHosts = { - prowlarr = { - inherit (cfg) port; - }; - }; - - services.fail2ban.jails = { - prowlarr = '' - enabled = true - filter = prowlarr - action = iptables-allports - ''; - }; - - environment.etc = { - "fail2ban/filter.d/prowlarr.conf".text = '' - [Definition] - failregex = ^.*\|Warn\|Auth\|Auth-Failure ip username .*$ - journalmatch = _SYSTEMD_UNIT=prowlarr.service - ''; - }; - }; -} diff --git a/modules/nixos/services/servarr/starr.nix b/modules/nixos/services/servarr/starr.nix deleted file mode 100644 index 2bf7c11..0000000 --- a/modules/nixos/services/servarr/starr.nix +++ /dev/null @@ -1,64 +0,0 @@ -# Templated *arr configuration -starr: -{ config, lib, ... }: -let - cfg = config.my.services.servarr.${starr}; - ports = { - lidarr = 8686; - radarr = 7878; - readarr = 8787; - sonarr = 8989; - }; -in -{ - options.my.services.servarr.${starr} = with lib; { - enable = lib.mkEnableOption (lib.toSentenceCase starr) // { - default = config.my.services.servarr.enableAll; - }; - - port = mkOption { - type = types.port; - default = ports.${starr}; - example = 8080; - description = "Internal port for webui"; - }; - }; - - config = lib.mkIf cfg.enable { - services.${starr} = { - enable = true; - group = "media"; - - settings = { - server = { - port = cfg.port; - }; - }; - }; - - # Set-up media group - users.groups.media = { }; - - my.services.nginx.virtualHosts = { - ${starr} = { - port = cfg.port; - }; - }; - - services.fail2ban.jails = { - ${starr} = '' - enabled = true - filter = ${starr} - action = iptables-allports - ''; - }; - - environment.etc = { - "fail2ban/filter.d/${starr}.conf".text = '' - [Definition] - failregex = ^.*\|Warn\|Auth\|Auth-Failure ip username .*$ - journalmatch = _SYSTEMD_UNIT=${starr}.service - ''; - }; - }; -} diff --git a/modules/nixos/services/tandoor-recipes/default.nix b/modules/nixos/services/tandoor-recipes/default.nix index 4b4ed1a..3447bee 100644 --- a/modules/nixos/services/tandoor-recipes/default.nix +++ b/modules/nixos/services/tandoor-recipes/default.nix @@ -26,16 +26,18 @@ in services.tandoor-recipes = { enable = true; - database = { - createLocally = true; - }; - port = cfg.port; extraConfig = let tandoorRecipesDomain = "recipes.${config.networking.domain}"; in { + # Use PostgreSQL + DB_ENGINE = "django.db.backends.postgresql"; + POSTGRES_HOST = "/run/postgresql"; + POSTGRES_USER = "tandoor_recipes"; + POSTGRES_DB = "tandoor_recipes"; + # Security settings ALLOWED_HOSTS = tandoorRecipesDomain; CSRF_TRUSTED_ORIGINS = "https://${tandoorRecipesDomain}"; @@ -47,12 +49,27 @@ in systemd.services = { tandoor-recipes = { + after = [ "postgresql.service" ]; + requires = [ "postgresql.service" ]; + serviceConfig = { EnvironmentFile = cfg.secretKeyFile; }; }; }; + # Set-up database + services.postgresql = { + enable = true; + ensureDatabases = [ "tandoor_recipes" ]; + ensureUsers = [ + { + name = "tandoor_recipes"; + ensureDBOwnership = true; + } + ]; + }; + my.services.nginx.virtualHosts = { recipes = { inherit (cfg) port; diff --git a/modules/nixos/services/thelounge/default.nix b/modules/nixos/services/thelounge/default.nix deleted file mode 100644 index e224839..0000000 --- a/modules/nixos/services/thelounge/default.nix +++ /dev/null @@ -1,59 +0,0 @@ -# Web IRC client -{ config, lib, ... }: -let - cfg = config.my.services.thelounge; -in -{ - options.my.services.thelounge = with lib; { - enable = mkEnableOption "The Lounge, a self-hosted web IRC client"; - - port = mkOption { - type = types.port; - default = 9050; - example = 4242; - description = "The port on which The Lounge will listen for incoming HTTP traffic."; - }; - }; - - config = lib.mkIf cfg.enable { - services.thelounge = { - enable = true; - inherit (cfg) port; - - extraConfig = { - reverseProxy = true; - }; - }; - - my.services.nginx.virtualHosts = { - irc = { - inherit (cfg) port; - # Proxy websockets for RPC - websocketsLocations = [ "/" ]; - - extraConfig = { - locations."/".extraConfig = '' - proxy_read_timeout 1d; - ''; - }; - }; - }; - - services.fail2ban.jails = { - thelounge = '' - enabled = true - filter = thelounge - port = http,https - ''; - }; - - environment.etc = { - "fail2ban/filter.d/thelounge.conf".text = '' - [Definition] - failregex = Authentication failed for user .* from $ - Authentication for non existing user attempted from $ - journalmatch = _SYSTEMD_UNIT=thelounge.service - ''; - }; - }; -} diff --git a/modules/nixos/services/transmission/default.nix b/modules/nixos/services/transmission/default.nix index 6a7fbc7..ac8b24d 100644 --- a/modules/nixos/services/transmission/default.nix +++ b/modules/nixos/services/transmission/default.nix @@ -47,7 +47,6 @@ in enable = true; package = pkgs.transmission_4; group = "media"; - webHome = pkgs.trgui-ng-web; downloadDirPermissions = "775"; @@ -66,19 +65,13 @@ in # Proxied behind Nginx. rpc-whitelist-enabled = true; rpc-whitelist = "127.0.0.1"; - - umask = "002"; # To go with `downloadDirPermissions` }; }; + # Transmission wants to eat *all* my RAM if left to its own devices systemd.services.transmission = { serviceConfig = { - # Transmission wants to eat *all* my RAM if left to its own devices MemoryMax = "33%"; - # Avoid errors due to high number of open files. - LimitNOFILE = 1048576; - # Longer stop timeout to finish all torrents - TimeoutStopSec = "5m"; }; }; diff --git a/modules/nixos/services/woodpecker/server/default.nix b/modules/nixos/services/woodpecker/server/default.nix index caf0179..adf533e 100644 --- a/modules/nixos/services/woodpecker/server/default.nix +++ b/modules/nixos/services/woodpecker/server/default.nix @@ -24,8 +24,8 @@ in }; systemd.services.woodpecker-server = { - after = [ "postgresql.target" ]; - requires = [ "postgresql.target" ]; + after = [ "postgresql.service" ]; + requires = [ "postgresql.service" ]; serviceConfig = { # Set username for DB access diff --git a/modules/nixos/system/nix/default.nix b/modules/nixos/system/nix/default.nix index 12a395e..ad13539 100644 --- a/modules/nixos/system/nix/default.nix +++ b/modules/nixos/system/nix/default.nix @@ -22,10 +22,6 @@ in options.my.system.nix = with lib; { enable = my.mkDisableOption "nix configuration"; - gc = { - enable = my.mkDisableOption "nix GC configuration"; - }; - cache = { selfHosted = my.mkDisableOption "self-hosted cache"; }; @@ -66,22 +62,6 @@ in }; } - (lib.mkIf cfg.gc.enable { - nix.gc = { - automatic = true; - - # Every week, with some wiggle room - dates = "weekly"; - randomizedDelaySec = "10min"; - - # Use a persistent timer for e.g: laptops - persistent = true; - - # Delete old profiles automatically after 15 days - options = "--delete-older-than 15d"; - }; - }) - (lib.mkIf cfg.cache.selfHosted { nix = { settings = { diff --git a/modules/nixos/system/packages/default.nix b/modules/nixos/system/packages/default.nix index 6a78ff6..ebea06f 100644 --- a/modules/nixos/system/packages/default.nix +++ b/modules/nixos/system/packages/default.nix @@ -1,5 +1,5 @@ # Common packages -{ config, lib, ... }: +{ config, lib, pkgs, ... }: let cfg = config.my.system.packages; in @@ -13,6 +13,10 @@ in }; config = lib.mkIf cfg.enable { + environment.systemPackages = with pkgs; [ + wget + ]; + programs = { vim = { enable = true; diff --git a/pkgs/bw-pass/bw-pass b/pkgs/bw-pass/bw-pass index 0e974b7..124714a 100755 --- a/pkgs/bw-pass/bw-pass +++ b/pkgs/bw-pass/bw-pass @@ -66,7 +66,7 @@ query_password() { printf '%s\n' "$PASSWORD" } -if [ $# -lt 1 ] || [ $# -gt 2 ]; then +if [ $# -lt 1 ] || [ $# -gt 2 ]; then usage exit 1 fi diff --git a/pkgs/cgt-calc/default.nix b/pkgs/cgt-calc/default.nix new file mode 100644 index 0000000..9966944 --- /dev/null +++ b/pkgs/cgt-calc/default.nix @@ -0,0 +1,47 @@ +{ lib +, fetchFromGitHub +, python3Packages +, withTeXLive ? true +, texliveSmall +}: +python3Packages.buildPythonApplication rec { + pname = "cgt-calc"; + version = "1.13.0"; + pyproject = true; + + src = fetchFromGitHub { + owner = "KapJI"; + repo = "capital-gains-calculator"; + rev = "v${version}"; + hash = "sha256-y/Y05wG89nccXyxfjqazyPJhd8dOkfwRJre+Rzx97Hw="; + }; + + build-system = with python3Packages; [ + poetry-core + ]; + + dependencies = with python3Packages; [ + defusedxml + jinja2 + pandas + requests + types-requests + yfinance + ]; + + makeWrapperArgs = lib.optionals withTeXLive [ + "--prefix" + "PATH" + ":" + "${lib.getBin texliveSmall}/bin" + ]; + + meta = with lib; { + description = "UK capital gains tax calculator"; + homepage = "https://github.com/KapJI/capital-gains-calculator"; + license = with licenses; [ mit ]; + mainProgram = "cgt-calc"; + maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.unix; + }; +} diff --git a/pkgs/change-audio/change-audio b/pkgs/change-audio/change-audio index 5a1fb9c..612fecf 100755 --- a/pkgs/change-audio/change-audio +++ b/pkgs/change-audio/change-audio @@ -62,7 +62,7 @@ do_toggle() { } case "$1" in - up | down) + up|down) do_change_volume "$@" ;; toggle) diff --git a/pkgs/comma/comma b/pkgs/comma/comma index b03a7f2..4367a26 100755 --- a/pkgs/comma/comma +++ b/pkgs/comma/comma @@ -12,9 +12,9 @@ usage() { find_program() { local CANDIDATE - CANDIDATE="$(nix-locate --minimal --at-root --whole-name "/bin/$1")" + CANDIDATE="$(nix-locate --top-level --minimal --at-root --whole-name "/bin/$1")" if [ "$(printf '%s\n' "$CANDIDATE" | wc -l)" -gt 1 ]; then - CANDIDATE="$(printf '%s' "$CANDIDATE" | "${COMMA_PICKER:-fzf-tmux}")" + CANDIDATE="$(printf '%s' "$CANDIDATE" | fzf-tmux)" fi printf '%s' "$CANDIDATE" } diff --git a/pkgs/default.nix b/pkgs/default.nix index 6b7fce1..949bcf7 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -2,6 +2,8 @@ pkgs.lib.makeScope pkgs.newScope (pkgs: { bw-pass = pkgs.callPackage ./bw-pass { }; + cgt-calc = pkgs.callPackage ./cgt-calc { }; + change-audio = pkgs.callPackage ./change-audio { }; change-backlight = pkgs.callPackage ./change-backlight { }; diff --git a/pkgs/diff-flake/diff-flake b/pkgs/diff-flake/diff-flake index a2a3513..0572b4e 100755 --- a/pkgs/diff-flake/diff-flake +++ b/pkgs/diff-flake/diff-flake @@ -81,23 +81,23 @@ parse_args() { shift case "$opt" in - -h | --help) + -h|--help) usage exit ;; - -f | --flake-output) + -f|--flake-output) FLAKE_OUTPUTS+=("$1") shift ;; - -o | --output) + -o|--output) OUTPUT_FILE="$1" shift ;; - -n | --new-rev) + -n|--new-rev) NEW_REV="$(git rev-parse "$1")" shift ;; - -p | --previous-rev) + -p|--previous-rev) PREVIOUS_REV="$(git rev-parse "$1")" shift ;; @@ -157,7 +157,7 @@ list_dev_shells() { } diff_output() { - local PREV NEW + local PREV NEW; PREV="$(mktemp --dry-run)" NEW="$(mktemp --dry-run)" @@ -169,7 +169,7 @@ diff_output() { printf 'Closure diff for `%s`:\n```\n' "$1" nix store diff-closures "$PREV" "$NEW" | sanitize_output printf '```\n\n' - } >>"$OUTPUT_FILE" + } >> "$OUTPUT_FILE" } parse_args "$@" diff --git a/pkgs/lohr/default.nix b/pkgs/lohr/default.nix index d8545e0..b89ccff 100644 --- a/pkgs/lohr/default.nix +++ b/pkgs/lohr/default.nix @@ -10,7 +10,7 @@ rustPlatform.buildRustPackage rec { hash = "sha256-dunQgtap+XCK5LoSyOqIY/6p6HizBeiyPWNuCffwjDU="; }; - cargoHash = "sha256-R3/N/43+bGx6acE/rhBcrk6kS5zQu8NJ1sVvKJJkK9w="; + cargoHash = "sha256-EUhyrhPe+mUgMmm4o+bxRIiSNReJRfw+/O1fPr8r7lo="; meta = with lib; { description = "Git mirroring daemon"; diff --git a/pkgs/osc52/osc52 b/pkgs/osc52/osc52 index de3a982..f64ccb6 100755 --- a/pkgs/osc52/osc52 +++ b/pkgs/osc52/osc52 @@ -15,7 +15,7 @@ usage() { exec 1>&2 fi - cat <&2 fi - cat < Send a notification (title and message) to the host system using the OSC 777 escape sequence: diff --git a/templates/c++-cmake/.envrc b/templates/c++-cmake/.envrc old mode 100755 new mode 100644 index 390d06d..de77fcb --- a/templates/c++-cmake/.envrc +++ b/templates/c++-cmake/.envrc @@ -1,4 +1,3 @@ -# shellcheck shell=bash if ! has nix_direnv_version || ! nix_direnv_version 3.0.0; then source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.0/direnvrc" "sha256-21TMnI2xWX7HkSTjFFri2UaohXVj854mgvWapWrxRXg=" fi diff --git a/templates/c++-cmake/flake.nix b/templates/c++-cmake/flake.nix index 7796f5e..db3b35c 100644 --- a/templates/c++-cmake/flake.nix +++ b/templates/c++-cmake/flake.nix @@ -16,18 +16,19 @@ ref = "nixos-unstable"; }; - git-hooks = { + pre-commit-hooks = { type = "github"; owner = "cachix"; - repo = "git-hooks.nix"; + repo = "pre-commit-hooks.nix"; ref = "master"; inputs = { + flake-utils.follows = "futils"; nixpkgs.follows = "nixpkgs"; }; }; }; - outputs = { self, futils, nixpkgs, git-hooks }: + outputs = { self, futils, nixpkgs, pre-commit-hooks }: { overlays = { default = final: _prev: { @@ -68,7 +69,7 @@ ]; }; - pre-commit = git-hooks.lib.${system}.run { + pre-commit = pre-commit-hooks.lib.${system}.run { src = self; hooks = { @@ -91,12 +92,12 @@ devShells = { default = pkgs.mkShell { - inputsFrom = [ - self.packages.${system}.project + inputsFrom = with self.packages.${system}; [ + project ]; packages = with pkgs; [ - self.checks.${system}.pre-commit.enabledPackages + clang-tools ]; inherit (pre-commit) shellHook; diff --git a/templates/c++-meson/.envrc b/templates/c++-meson/.envrc index 390d06d..de77fcb 100644 --- a/templates/c++-meson/.envrc +++ b/templates/c++-meson/.envrc @@ -1,4 +1,3 @@ -# shellcheck shell=bash if ! has nix_direnv_version || ! nix_direnv_version 3.0.0; then source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.0/direnvrc" "sha256-21TMnI2xWX7HkSTjFFri2UaohXVj854mgvWapWrxRXg=" fi diff --git a/templates/c++-meson/flake.nix b/templates/c++-meson/flake.nix index cb14eb5..5957c62 100644 --- a/templates/c++-meson/flake.nix +++ b/templates/c++-meson/flake.nix @@ -16,18 +16,19 @@ ref = "nixos-unstable"; }; - git-hooks = { + pre-commit-hooks = { type = "github"; owner = "cachix"; - repo = "git-hooks.nix"; + repo = "pre-commit-hooks.nix"; ref = "master"; inputs = { + flake-utils.follows = "futils"; nixpkgs.follows = "nixpkgs"; }; }; }; - outputs = { self, futils, nixpkgs, git-hooks }: + outputs = { self, futils, nixpkgs, pre-commit-hooks }: { overlays = { default = final: _prev: { @@ -68,7 +69,7 @@ ]; }; - pre-commit = git-hooks.lib.${system}.run { + pre-commit = pre-commit-hooks.lib.${system}.run { src = self; hooks = { @@ -91,12 +92,12 @@ devShells = { default = pkgs.mkShell { - inputsFrom = [ - self.packages.${system}.project + inputsFrom = with self.packages.${system}; [ + project ]; packages = with pkgs; [ - self.checks.${system}.pre-commit.enabledPackages + clang-tools ]; inherit (pre-commit) shellHook; diff --git a/templates/default.nix b/templates/default.nix index 51864cd..44db753 100644 --- a/templates/default.nix +++ b/templates/default.nix @@ -7,10 +7,6 @@ path = ./c++-meson; description = "A C++ project using Meson"; }; - "python-uv" = { - path = ./python-uv; - description = "A Python project using uv"; - }; "rust-cargo" = { path = ./rust-cargo; description = "A Rust project using Cargo"; diff --git a/templates/python-uv/.envrc b/templates/python-uv/.envrc deleted file mode 100644 index 390d06d..0000000 --- a/templates/python-uv/.envrc +++ /dev/null @@ -1,6 +0,0 @@ -# shellcheck shell=bash -if ! has nix_direnv_version || ! nix_direnv_version 3.0.0; then - source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.0/direnvrc" "sha256-21TMnI2xWX7HkSTjFFri2UaohXVj854mgvWapWrxRXg=" -fi - -use flake diff --git a/templates/python-uv/.gitignore b/templates/python-uv/.gitignore deleted file mode 100644 index c79d1e8..0000000 --- a/templates/python-uv/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Virtual environments -.venv - -# Nix generated files -/.pre-commit-config.yaml -/result diff --git a/templates/python-uv/.woodpecker/check.yml b/templates/python-uv/.woodpecker/check.yml deleted file mode 100644 index 272c0e4..0000000 --- a/templates/python-uv/.woodpecker/check.yml +++ /dev/null @@ -1,31 +0,0 @@ -labels: - backend: local - -steps: -- name: pre-commit check - image: bash - commands: - - nix develop --command pre-commit run --all - -- name: nix flake check - image: bash - commands: - - nix flake check - -- name: notify - image: bash - environment: - ADDRESS: - from_secret: matrix_homeserver - ROOM: - from_secret: matrix_roomid - USER: - from_secret: matrix_username - PASS: - from_secret: matrix_password - commands: - - nix run github:ambroisie/matrix-notifier - when: - status: - - failure - - success diff --git a/templates/python-uv/flake.nix b/templates/python-uv/flake.nix deleted file mode 100644 index 5059e64..0000000 --- a/templates/python-uv/flake.nix +++ /dev/null @@ -1,112 +0,0 @@ -{ - description = "A Python project"; - - inputs = { - futils = { - type = "github"; - owner = "numtide"; - repo = "flake-utils"; - ref = "main"; - }; - - nixpkgs = { - type = "github"; - owner = "NixOS"; - repo = "nixpkgs"; - ref = "nixos-unstable"; - }; - - git-hooks = { - type = "github"; - owner = "cachix"; - repo = "git-hooks.nix"; - ref = "master"; - inputs = { - nixpkgs.follows = "nixpkgs"; - }; - }; - }; - - outputs = { self, futils, nixpkgs, git-hooks }: - { - overlays = { - default = final: _prev: { - project = with final; python3.pkgs.buildPythonApplication { - pname = "project"; - version = (final.lib.importTOML ./pyproject.toml).project.version; - pyproject = true; - - src = self; - - build-system = with python3.pkgs; [ setuptools ]; - - pythonImportsCheck = [ "project" ]; - - meta = with lib; { - description = "A Python project"; - homepage = "https://git.belanyi.fr/ambroisie/project"; - license = licenses.mit; - maintainers = with maintainers; [ ambroisie ]; - }; - }; - }; - }; - } // futils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { - inherit system; - overlays = [ - self.overlays.default - ]; - }; - - pre-commit = git-hooks.lib.${system}.run { - src = self; - - hooks = { - mypy = { - enable = true; - }; - - nixpkgs-fmt = { - enable = true; - }; - - ruff = { - enable = true; - }; - - ruff-format = { - enable = true; - }; - }; - }; - in - { - checks = { - inherit (self.packages.${system}) project; - - inherit pre-commit; - }; - - devShells = { - default = pkgs.mkShell { - inputsFrom = [ - self.packages.${system}.project - ]; - - packages = with pkgs; [ - uv - self.checks.${system}.pre-commit.enabledPackages - ]; - - inherit (pre-commit) shellHook; - }; - }; - - packages = futils.lib.flattenTree { - default = pkgs.project; - inherit (pkgs) project; - }; - }); -} diff --git a/templates/python-uv/pyproject.toml b/templates/python-uv/pyproject.toml deleted file mode 100644 index 7b2d896..0000000 --- a/templates/python-uv/pyproject.toml +++ /dev/null @@ -1,17 +0,0 @@ -[build-system] -requires = ["setuptools"] -build-backend = "setuptools.build_meta" - - -[project] -name = "project" -version = "0.0.0" -description = "project description" -requires-python = ">=3.12" -dependencies = [] - -[project.scripts] -project = "project:main" - -[dependency-groups] -dev = [] diff --git a/templates/python-uv/src/project/__init__.py b/templates/python-uv/src/project/__init__.py deleted file mode 100644 index b06117d..0000000 --- a/templates/python-uv/src/project/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -def main() -> None: - print("Hello, world!") diff --git a/templates/rust-cargo/.envrc b/templates/rust-cargo/.envrc index 390d06d..de77fcb 100644 --- a/templates/rust-cargo/.envrc +++ b/templates/rust-cargo/.envrc @@ -1,4 +1,3 @@ -# shellcheck shell=bash if ! has nix_direnv_version || ! nix_direnv_version 3.0.0; then source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.0/direnvrc" "sha256-21TMnI2xWX7HkSTjFFri2UaohXVj854mgvWapWrxRXg=" fi diff --git a/templates/rust-cargo/flake.nix b/templates/rust-cargo/flake.nix index efd8358..6d50369 100644 --- a/templates/rust-cargo/flake.nix +++ b/templates/rust-cargo/flake.nix @@ -16,18 +16,19 @@ ref = "nixos-unstable"; }; - git-hooks = { + pre-commit-hooks = { type = "github"; owner = "cachix"; - repo = "git-hooks.nix"; + repo = "pre-commit-hooks.nix"; ref = "master"; inputs = { + flake-utils.follows = "futils"; nixpkgs.follows = "nixpkgs"; }; }; }; - outputs = { self, futils, nixpkgs, git-hooks }: + outputs = { self, futils, nixpkgs, pre-commit-hooks }: { overlays = { default = final: _prev: { @@ -59,7 +60,7 @@ ]; }; - pre-commit = git-hooks.lib.${system}.run { + pre-commit = pre-commit-hooks.lib.${system}.run { src = self; hooks = { @@ -87,13 +88,14 @@ devShells = { default = pkgs.mkShell { - inputsFrom = [ - self.packages.${system}.project + inputsFrom = with self.packages.${system}; [ + project ]; packages = with pkgs; [ + clippy rust-analyzer - self.checks.${system}.pre-commit.enabledPackages + rustfmt ]; RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";