diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index b192230..0000000 --- a/.drone.yml +++ /dev/null @@ -1,27 +0,0 @@ ---- -kind: pipeline -type: exec -name: NixOS config check - -steps: -- name: nix flake check - commands: - - nix flake check - -- name: notifiy - commands: - - nix run .#matrix-notifier - environment: - ADDRESS: - from_secret: matrix_homeserver - ROOM: - from_secret: matrix_roomid - USER: - from_secret: matrix_username - PASS: - from_secret: matrix_password - when: - status: - - failure - - success -... diff --git a/.envrc b/.envrc index 4b297a5..95ed6fb 100644 --- a/.envrc +++ b/.envrc @@ -1,9 +1,10 @@ -use_flake() { - watch_file flake.nix - watch_file flake.lock - eval "$(nix print-dev-env)" -} +if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs=" +fi -ulimit -s unlimited # Bypass current bug in `nix` flakes evaluation use flake + +watch_file ./flake/checks.nix +watch_file ./flake/dev-shells.nix + eval "$shellHooks" diff --git a/.stylua.toml b/.stylua.toml new file mode 100644 index 0000000..394e884 --- /dev/null +++ b/.stylua.toml @@ -0,0 +1 @@ +indent_type = "Spaces" diff --git a/.woodpecker/check.yml b/.woodpecker/check.yml new file mode 100644 index 0000000..d7c5dff --- /dev/null +++ b/.woodpecker/check.yml @@ -0,0 +1,26 @@ +labels: + backend: local + +pipeline: +- name: nix flake check + image: bash + commands: + - nix flake check + +- name: notifiy + image: bash + secrets: + - source: matrix_homeserver + target: address + - source: matrix_roomid + target: room + - source: matrix_username + target: user + - source: matrix_password + target: pass + commands: + - nix run '.#matrix-notifier' + when: + status: + - failure + - success diff --git a/bootstrap.sh b/bootstrap.sh index df41c29..b1c418e 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,5 +1,5 @@ #!/usr/bin/env nix-shell -#! nix-shell -i bash -p bitwarden-cli git gnupg jq nixFlakes +#! nix-shell -i bash -p bitwarden-cli git gnupg jq nix # Command failure is script failure set -e @@ -58,8 +58,8 @@ get_ssh() { get_doc "SysAdmin/SSH" "shared-key-public" "$HOME/.ssh/shared_rsa.pub" 644 get_doc "SysAdmin/SSH" "shared-key-private" "$HOME/.ssh/shared_rsa" 600 - get_doc "SysAdmin/SSH" "agenix-public" "$HOME/.ssh/id_ed25519.pub" 644 - get_doc "SysAdmin/SSH" "agenix-private" "$HOME/.ssh/id_ed25519" 600 + get_doc "SysAdmin/SSH" "agenix-public" "$HOME/.ssh/agenix.pub" 644 + get_doc "SysAdmin/SSH" "agenix-private" "$HOME/.ssh/agenix" 600 } get_pgp() { @@ -87,15 +87,6 @@ get_creds() { get_pgp } -setup_gpg() { - info 'Setting up loopback pinentry for GnuPG' - echo "allow-loopback-pinentry" > ~/.gnupg/gpg-agent.conf - - info 'Signing dummy message to ensure GnuPG key is usable by `git-crypt`' - echo whatever | gpg --clearsign --armor --pinentry loopback --output /dev/null -} - [ -z "$NOCREDS" ] && get_creds -[ -z "$NOGPG" ] && setup_gpg nix --experimental-features 'nix-command flakes' develop diff --git a/flake.lock b/flake.lock index db60e45..b3c3e01 100644 --- a/flake.lock +++ b/flake.lock @@ -2,16 +2,20 @@ "nodes": { "agenix": { "inputs": { + "darwin": "darwin", + "home-manager": [ + "home-manager" + ], "nixpkgs": [ "nixpkgs" ] }, "locked": { - "lastModified": 1646105662, - "narHash": "sha256-jdXCZbGZL0SWWi29GnAOFHUh/QvvP0IyaVLv1ZTDkBI=", + "lastModified": 1690228878, + "narHash": "sha256-9Xe7JV0krp4RJC9W9W9WutZVlw6BlHTFMiUP/k48LQY=", "owner": "ryantm", "repo": "agenix", - "rev": "297cd58b418249240b9f1f155d52b1b17f292884", + "rev": "d8c973fd228949736dedf61b7f8cc1ece3236792", "type": "github" }, "original": { @@ -21,22 +25,105 @@ "type": "github" } }, - "futils": { + "darwin": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, "locked": { - "lastModified": 1644229661, - "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=", + "lastModified": 1673295039, + "narHash": "sha256-AsdYgE8/GPwcelGgrntlijMg4t3hLFJFCRF3tL5WVjA=", + "owner": "lnl7", + "repo": "nix-darwin", + "rev": "87b9d090ad39b25b2400029c64825fc2a8868943", + "type": "github" + }, + "original": { + "owner": "lnl7", + "ref": "master", + "repo": "nix-darwin", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1690933134, + "narHash": "sha256-ab989mN63fQZBFrkk4Q8bYxQCktuHmBIBqUG1jl6/FQ=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "59cf3f1447cfc75087e7273b04b31e689a8599fb", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "ref": "main", + "repo": "flake-parts", + "type": "github" + } + }, + "futils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1689068808, + "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", "owner": "numtide", "repo": "flake-utils", - "rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797", + "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", "type": "github" }, "original": { "owner": "numtide", - "ref": "master", + "ref": "main", "repo": "flake-utils", "type": "github" } }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1660459072, + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -44,11 +131,11 @@ ] }, "locked": { - "lastModified": 1646559628, - "narHash": "sha256-WDoqxH/IPTV8CkI15wwzvXYgXq9UPr8xd8WKziuaynw=", + "lastModified": 1691039228, + "narHash": "sha256-iPNZJ1LvfUf1Y456ewC0DXgf99TNssG8OLObOyqxO6M=", "owner": "nix-community", "repo": "home-manager", - "rev": "afe96e7433c513bf82375d41473c57d1f66b4e68", + "rev": "86dd48d70a2e2c17e84e747ba4faa92453e68d4a", "type": "github" }, "original": { @@ -60,11 +147,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1646497237, - "narHash": "sha256-Ccpot1h/rV8MgcngDp5OrdmLTMaUTbStZTR5/sI7zW0=", + "lastModified": 1691006197, + "narHash": "sha256-DbtxVWPt+ZP5W0Usg7jAyTomIM//c3Jtfa59Ht7AV8s=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "062a0c5437b68f950b081bbfc8a699d57a4ee026", + "rev": "66aedfd010204949cb225cf749be08cb13ce1813", "type": "github" }, "original": { @@ -76,11 +163,11 @@ }, "nur": { "locked": { - "lastModified": 1646721260, - "narHash": "sha256-r8ZWtEwiRxLKOtsT2yvU9Rs1oqL/RsSkPkgupXsw1bU=", + "lastModified": 1691139289, + "narHash": "sha256-cZtqvYztpGwLtAsfrzY2VeTfFdW3HBwX7m1KV2Zy2nw=", "owner": "nix-community", "repo": "NUR", - "rev": "25adb63e9381cb0342cdbe2d2d56266f4974a2c5", + "rev": "cb20b89d5b355c53a18dd149e7104a67381c7c17", "type": "github" }, "original": { @@ -92,19 +179,24 @@ }, "pre-commit-hooks": { "inputs": { + "flake-compat": "flake-compat", "flake-utils": [ "futils" ], + "gitignore": "gitignore", "nixpkgs": [ "nixpkgs" + ], + "nixpkgs-stable": [ + "nixpkgs" ] }, "locked": { - "lastModified": 1646153636, - "narHash": "sha256-AlWHMzK+xJ1mG267FdT8dCq/HvLCA6jwmx2ZUy5O8tY=", + "lastModified": 1691093055, + "narHash": "sha256-sjNWYpDHc6vx+/M0WbBZKltR0Avh2S43UiDbmYtfHt0=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "b6bc0b21e1617e2b07d8205e7fae7224036dfa4b", + "rev": "ebb43bdacd1af8954d04869c77bc3b61fde515e4", "type": "github" }, "original": { @@ -117,12 +209,28 @@ "root": { "inputs": { "agenix": "agenix", + "flake-parts": "flake-parts", "futils": "futils", "home-manager": "home-manager", "nixpkgs": "nixpkgs", "nur": "nur", "pre-commit-hooks": "pre-commit-hooks" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 3b8c722..8e46ea3 100644 --- a/flake.nix +++ b/flake.nix @@ -7,15 +7,26 @@ repo = "agenix"; ref = "main"; inputs = { + home-manager.follows = "home-manager"; nixpkgs.follows = "nixpkgs"; }; }; + flake-parts = { + type = "github"; + owner = "hercules-ci"; + repo = "flake-parts"; + ref = "main"; + inputs = { + nixpkgs-lib.follows = "nixpkgs"; + }; + }; + futils = { type = "github"; owner = "numtide"; repo = "flake-utils"; - ref = "master"; + ref = "main"; }; home-manager = { @@ -50,116 +61,11 @@ inputs = { flake-utils.follows = "futils"; nixpkgs.follows = "nixpkgs"; + nixpkgs-stable.follows = "nixpkgs"; }; }; }; - outputs = - inputs @ - { self - , agenix - , futils - , home-manager - , nixpkgs - , nur - , pre-commit-hooks - }: - let - inherit (futils.lib) eachDefaultSystem; - - lib = nixpkgs.lib.extend (self: super: { - my = import ./lib { inherit inputs; pkgs = nixpkgs; lib = self; }; - }); - - defaultModules = [ - ({ ... }: { - # Let 'nixos-version --json' know about the Git revision - system.configurationRevision = self.rev or "dirty"; - }) - { - nixpkgs.overlays = (lib.attrValues self.overlays) ++ [ - nur.overlay - ]; - } - # Include generic settings - ./modules - # Include bundles of settings - ./profiles - ]; - - buildHost = name: system: lib.nixosSystem { - inherit system; - modules = defaultModules ++ [ - (./. + "/machines/${name}") - ]; - specialArgs = { - # Use my extended lib in NixOS configuration - inherit lib; - # Inject inputs to use them in global registry - inherit inputs; - }; - }; - in - eachDefaultSystem - (system: - let - pkgs = nixpkgs.legacyPackages.${system}; - in - rec { - apps = { - diff-flake = futils.lib.mkApp { drv = packages.diff-flake; }; - }; - - checks = { - pre-commit = pre-commit-hooks.lib.${system}.run { - src = ./.; - - hooks = { - nixpkgs-fmt = { - enable = true; - }; - - shellcheck = { - enable = true; - }; - }; - }; - }; - - defaultApp = apps.diff-flake; - - devShell = pkgs.mkShell { - name = "NixOS-config"; - - nativeBuildInputs = with pkgs; [ - gitAndTools.pre-commit - nixpkgs-fmt - ]; - - inherit (self.checks.${system}.pre-commit) shellHook; - }; - - packages = - let - inherit (futils.lib) filterPackages flattenTree; - packages = import ./pkgs { inherit pkgs; }; - flattenedPackages = flattenTree packages; - finalPackages = filterPackages system flattenedPackages; - in - finalPackages; - }) // { - overlay = self.overlays.pkgs; - - overlays = import ./overlays // { - lib = final: prev: { inherit lib; }; - pkgs = final: prev: { - ambroisie = prev.recurseIntoAttrs (import ./pkgs { pkgs = prev; }); - }; - }; - - nixosConfigurations = lib.mapAttrs buildHost { - aramis = "x86_64-linux"; - porthos = "x86_64-linux"; - }; - }; + # Can't eta-reduce a flake outputs... + outputs = inputs: import ./flake inputs; } diff --git a/flake/apps.nix b/flake/apps.nix new file mode 100644 index 0000000..f8dc2de --- /dev/null +++ b/flake/apps.nix @@ -0,0 +1,9 @@ +{ inputs, ... }: +{ + perSystem = { self', ... }: { + apps = { + diff-flake = inputs.futils.lib.mkApp { drv = self'.packages.diff-flake; }; + default = self'.apps.diff-flake; + }; + }; +} diff --git a/flake/checks.nix b/flake/checks.nix new file mode 100644 index 0000000..98e49bd --- /dev/null +++ b/flake/checks.nix @@ -0,0 +1,33 @@ +{ inputs, ... }: +{ + imports = [ + inputs.pre-commit-hooks.flakeModule + ]; + + perSystem = { ... }: { + pre-commit = { + # Add itself to `nix flake check` + check.enable = true; + + settings = { + hooks = { + deadnix = { + enable = true; + }; + + nixpkgs-fmt = { + enable = true; + }; + + shellcheck = { + enable = true; + }; + + stylua = { + enable = true; + }; + }; + }; + }; + }; +} diff --git a/flake/default.nix b/flake/default.nix new file mode 100644 index 0000000..65102e1 --- /dev/null +++ b/flake/default.nix @@ -0,0 +1,22 @@ +{ flake-parts +, futils +, ... +} @ inputs: +let + mySystems = futils.lib.defaultSystems; +in +flake-parts.lib.mkFlake { inherit inputs; } { + systems = mySystems; + + imports = [ + ./apps.nix + ./checks.nix + ./dev-shells.nix + ./home-manager.nix + ./lib.nix + ./nixos.nix + ./overlays.nix + ./packages.nix + ./templates.nix + ]; +} diff --git a/flake/dev-shells.nix b/flake/dev-shells.nix new file mode 100644 index 0000000..d5f5989 --- /dev/null +++ b/flake/dev-shells.nix @@ -0,0 +1,19 @@ +{ ... }: +{ + perSystem = { config, pkgs, ... }: { + devShells = { + default = pkgs.mkShellNoCC { + name = "NixOS-config"; + + nativeBuildInputs = with pkgs; [ + gitAndTools.pre-commit + nixpkgs-fmt + ]; + + shellHook = '' + ${config.pre-commit.installationScript} + ''; + }; + }; + }; +} diff --git a/flake/home-manager.nix b/flake/home-manager.nix new file mode 100644 index 0000000..c55c8dd --- /dev/null +++ b/flake/home-manager.nix @@ -0,0 +1,61 @@ +{ self, inputs, lib, ... }: +let + defaultModules = [ + # Include generic settings + "${self}/home" + { + # Basic user information defaults + home.username = lib.mkDefault "ambroisie"; + home.homeDirectory = lib.mkDefault "/home/ambroisie"; + + # Make it a Linux installation by default + targets.genericLinux.enable = lib.mkDefault true; + + # Enable home-manager + programs.home-manager.enable = true; + } + ]; + + mkHome = name: system: inputs.home-manager.lib.homeManagerConfiguration { + # 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}" + ]; + + extraSpecialArgs = { + # Inject inputs to use them in global registry + inherit inputs; + }; + }; + + hosts = { + "ambroisie@ambroisie" = "x86_64-linux"; # Unfortunate naming here... + }; +in +{ + perSystem = { system, ... }: { + # Work-around for https://github.com/nix-community/home-manager/issues/3075 + legacyPackages = { + homeConfigurations = + let + filteredHosts = lib.filterAttrs (_: v: v == system) hosts; + allHosts = filteredHosts // { + # Default configuration + ambroisie = system; + }; + in + lib.mapAttrs mkHome allHosts; + }; + }; +} diff --git a/flake/lib.nix b/flake/lib.nix new file mode 100644 index 0000000..12e89c3 --- /dev/null +++ b/flake/lib.nix @@ -0,0 +1,11 @@ +{ self, inputs, ... }: +let + inherit (inputs) nixpkgs; + + lib = nixpkgs.lib.extend (final: _: { + my = import "${self}/lib" { inherit inputs; pkgs = nixpkgs; lib = final; }; + }); +in +{ + flake.lib = lib; +} diff --git a/flake/nixos.nix b/flake/nixos.nix new file mode 100644 index 0000000..9eb6388 --- /dev/null +++ b/flake/nixos.nix @@ -0,0 +1,39 @@ +{ self, inputs, ... }: +let + inherit (self) lib; + + defaultModules = [ + { + # Let 'nixos-version --json' know about the Git revision + system.configurationRevision = self.rev or "dirty"; + } + { + nixpkgs.overlays = (lib.attrValues self.overlays) ++ [ + inputs.nur.overlay + ]; + } + # Include generic settings + "${self}/modules" + # Include bundles of settings + "${self}/profiles" + ]; + + buildHost = name: system: lib.nixosSystem { + inherit system; + modules = defaultModules ++ [ + "${self}/hosts/nixos/${name}" + ]; + specialArgs = { + # Use my extended lib in NixOS configuration + inherit lib; + # Inject inputs to use them in global registry + inherit inputs; + }; + }; +in +{ + flake.nixosConfigurations = lib.mapAttrs buildHost { + aramis = "x86_64-linux"; + porthos = "x86_64-linux"; + }; +} diff --git a/flake/overlays.nix b/flake/overlays.nix new file mode 100644 index 0000000..0c47989 --- /dev/null +++ b/flake/overlays.nix @@ -0,0 +1,17 @@ +{ self, ... }: +let + default-overlays = import "${self}/overlays"; + + additional-overlays = { + # Expose my expanded library + lib = _final: _prev: { inherit (self) lib; }; + + # Expose my custom packages + pkgs = _final: prev: { + ambroisie = prev.recurseIntoAttrs (import "${self}/pkgs" { pkgs = prev; }); + }; + }; +in +{ + flake.overlays = default-overlays // additional-overlays; +} diff --git a/flake/packages.nix b/flake/packages.nix new file mode 100644 index 0000000..3515071 --- /dev/null +++ b/flake/packages.nix @@ -0,0 +1,13 @@ +{ self, inputs, ... }: +{ + perSystem = { pkgs, system, ... }: { + packages = + let + inherit (inputs.futils.lib) filterPackages flattenTree; + packages = import "${self}/pkgs" { inherit pkgs; }; + flattenedPackages = flattenTree packages; + finalPackages = filterPackages system flattenedPackages; + in + finalPackages; + }; +} diff --git a/flake/templates.nix b/flake/templates.nix new file mode 100644 index 0000000..28e534e --- /dev/null +++ b/flake/templates.nix @@ -0,0 +1,4 @@ +{ self, ... }: +{ + flake.templates = import "${self}/templates"; +} diff --git a/home/aliases/default.nix b/home/aliases/default.nix new file mode 100644 index 0000000..259f148 --- /dev/null +++ b/home/aliases/default.nix @@ -0,0 +1,26 @@ +{ config, lib, ... }: +let + cfg = config.my.home.aliases; +in +{ + options.my.home.aliases = with lib; { + enable = my.mkDisableOption "shell aliases configuration"; + }; + + config = lib.mkIf cfg.enable { + home = { + shellAliases = { + # I like pretty colors + diff = "diff --color=auto"; + grep = "grep --color=auto"; + egrep = "egrep --color=auto"; + fgrep = "fgrep --color=auto"; + ls = "ls --color=auto"; + + # Well-known ls aliases + l = "ls -alh"; + ll = "ls -l"; + }; + }; + }; +} diff --git a/home/atuin/default.nix b/home/atuin/default.nix new file mode 100644 index 0000000..19a6fb9 --- /dev/null +++ b/home/atuin/default.nix @@ -0,0 +1,31 @@ +{ config, lib, ... }: +let + cfg = config.my.home.atuin; +in +{ + options.my.home.atuin = with lib; { + enable = my.mkDisableOption "atuin configuration"; + }; + + config = lib.mkIf cfg.enable { + programs.atuin = { + enable = true; + + flags = [ + # I *despise* this hijacking of the up key, even though I use Ctrl-p + "--disable-up-arrow" + ]; + + settings = { + # The package is managed by Nix + update_check = false; + # I don't care for the fancy display + style = "compact"; + # Get closer to fzf's fuzzy search + search_mode = "skim"; + # Show long command lines at the bottom + show_preview = true; + }; + }; + }; +} diff --git a/home/bat/default.nix b/home/bat/default.nix index ac58c06..67d80c2 100644 --- a/home/bat/default.nix +++ b/home/bat/default.nix @@ -3,8 +3,8 @@ let cfg = config.my.home.bat; in { - options.my.home.bat = with lib.my; { - enable = mkDisableOption "bat configuration"; + options.my.home.bat = with lib; { + enable = my.mkDisableOption "bat configuration"; }; config.programs.bat = lib.mkIf cfg.enable { diff --git a/home/bitwarden/default.nix b/home/bitwarden/default.nix new file mode 100644 index 0000000..c709f7b --- /dev/null +++ b/home/bitwarden/default.nix @@ -0,0 +1,27 @@ +{ config, lib, ... }: +let + cfg = config.my.home.bitwarden; +in +{ + options.my.home.bitwarden = with lib; { + enable = my.mkDisableOption "bitwarden configuration"; + + pinentry = mkOption { + type = types.str; + default = "tty"; + example = "gtk2"; + description = "Which pinentry interface to use"; + }; + }; + + config = lib.mkIf cfg.enable { + programs.rbw = { + enable = true; + + settings = { + email = lib.my.mkMailAddress "bruno" "belanyi.fr"; + inherit (cfg) pinentry; + }; + }; + }; +} diff --git a/home/calibre/default.nix b/home/calibre/default.nix new file mode 100644 index 0000000..e0f2069 --- /dev/null +++ b/home/calibre/default.nix @@ -0,0 +1,15 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.my.home.calibre; +in +{ + options.my.home.calibre = with lib; { + enable = mkEnableOption "calibre configuration"; + }; + + config = lib.mkIf cfg.enable { + home.packages = with pkgs; [ + calibre # NOTE: relies on my overlay to add necessary plug-in dependencies + ]; + }; +} diff --git a/home/default.nix b/home/default.nix index 82d2cc3..8ba3a8d 100644 --- a/home/default.nix +++ b/home/default.nix @@ -1,15 +1,21 @@ { ... }: { imports = [ + ./aliases + ./atuin ./bat + ./bitwarden ./bluetooth + ./calibre ./comma + ./dircolors ./direnv ./discord ./documentation ./feh ./firefox ./flameshot + ./fzf ./gammastep ./gdb ./git @@ -19,11 +25,14 @@ ./jq ./mail ./mpv + ./nix ./nix-index + ./nixpkgs ./nm-applet ./packages ./pager ./power-alert + ./secrets ./ssh ./terminal ./tmux diff --git a/home/dircolors/default.nix b/home/dircolors/default.nix new file mode 100644 index 0000000..876b413 --- /dev/null +++ b/home/dircolors/default.nix @@ -0,0 +1,15 @@ +{ config, lib, ... }: +let + cfg = config.my.home.dircolors; +in +{ + options.my.home.dircolors = with lib; { + enable = my.mkDisableOption "dircolors configuration"; + }; + + config = lib.mkIf cfg.enable { + programs.dircolors = { + enable = true; + }; + }; +} diff --git a/home/direnv/default.nix b/home/direnv/default.nix index 86409f0..93a1f3b 100644 --- a/home/direnv/default.nix +++ b/home/direnv/default.nix @@ -3,15 +3,44 @@ let cfg = config.my.home.direnv; in { - options.my.home.direnv = with lib.my; { - enable = mkDisableOption "direnv configuration"; + options.my.home.direnv = with lib; { + enable = my.mkDisableOption "direnv configuration"; + + defaultFlake = mkOption { + type = types.str; + default = "pkgs"; + example = "nixpkgs"; + description = '' + Which flake from the registry should be used for + use pkgs by default. + ''; + }; }; - config.programs.direnv = lib.mkIf cfg.enable { - enable = true; - nix-direnv = { - # A better `use_nix` + config = lib.mkIf cfg.enable { + programs.direnv = { enable = true; + nix-direnv = { + # A better `use_nix` + enable = true; + }; + }; + + xdg.configFile = + let + libDir = ./lib; + contents = builtins.readDir libDir; + names = lib.attrNames contents; + files = lib.filter (name: contents.${name} == "regular") names; + linkLibFile = name: + lib.nameValuePair + "direnv/lib/${name}" + { source = libDir + "/${name}"; }; + in + lib.my.genAttrs' files linkLibFile; + + home.sessionVariables = { + DIRENV_DEFAULT_FLAKE = cfg.defaultFlake; }; }; } diff --git a/home/direnv/lib/nix.sh b/home/direnv/lib/nix.sh new file mode 100644 index 0000000..2d40b20 --- /dev/null +++ b/home/direnv/lib/nix.sh @@ -0,0 +1,32 @@ +#shellcheck shell=bash + +use_pkgs() { + if ! has nix; then + # shellcheck disable=2016 + log_error 'use_pkgs: `nix` is not in PATH' + return 1 + fi + + # Use user-provided default value, or fallback to nixpkgs + local DEFAULT_FLAKE="${DIRENV_DEFAULT_FLAKE:-nixpkgs}" + + # Allow changing the default flake through a command line switch + if [ "$1" = "-f" ] || [ "$1" = "--flake" ]; then + DEFAULT_FLAKE="$2" + shift 2 + fi + + + # Allow specifying a full installable, or just a package name and use the default flake + local packages=() + for pkg; do + if [[ $pkg =~ .*#.* ]]; then + packages+=("$pkg") + else + packages+=("$DEFAULT_FLAKE#$pkg") + fi + done + + # shellcheck disable=2154 + direnv_load nix shell "${packages[@]}" --command "$direnv" dump +} diff --git a/home/direnv/lib/postgres.sh b/home/direnv/lib/postgres.sh new file mode 100644 index 0000000..c2e6a8f --- /dev/null +++ b/home/direnv/lib/postgres.sh @@ -0,0 +1,22 @@ +#shellcheck shell=bash + +layout_postgres() { + if ! has postgres || ! has initdb; then + # shellcheck disable=2016 + log_error 'layout_postgres: `postgres` and `initdb` are not in PATH' + return 1 + fi + + # shellcheck disable=2155 + export PGDATA="$(direnv_layout_dir)/postgres" + export PGHOST="$PGDATA" + + if [[ ! -d "$PGDATA" ]]; then + initdb + cat >> "$PGDATA/postgresql.conf" << EOF +listen_addresses = '' +unix_socket_directories = '$PGHOST' +EOF + echo "CREATE DATABASE $USER;" | postgres --single -E postgres + fi +} diff --git a/home/direnv/lib/python.sh b/home/direnv/lib/python.sh new file mode 100644 index 0000000..15a273f --- /dev/null +++ b/home/direnv/lib/python.sh @@ -0,0 +1,25 @@ +#shellcheck shell=bash + +layout_poetry() { + if ! has poetry; then + # shellcheck disable=2016 + log_error 'layout_poetry: `poetry` is not in PATH' + return 1 + fi + + if [[ ! -f pyproject.toml ]]; then + # shellcheck disable=2016 + log_error 'layout_poetry: no pyproject.toml found. Use `poetry new` or `poetry init` to create one first' + return 1 + fi + + # create venv if it doesn't exist + poetry run true + + # shellcheck disable=2155 + export VIRTUAL_ENV=$(poetry env info --path) + export POETRY_ACTIVE=1 + PATH_add "$VIRTUAL_ENV/bin" + watch_file pyproject.toml + watch_file poetry.lock +} diff --git a/home/documentation/default.nix b/home/documentation/default.nix index e31665f..1a305e0 100644 --- a/home/documentation/default.nix +++ b/home/documentation/default.nix @@ -3,8 +3,8 @@ let cfg = config.my.home.documentation; in { - options.my.home.documentation = with lib.my; { - enable = mkDisableOption "documentation integration"; + options.my.home.documentation = with lib; { + enable = my.mkDisableOption "documentation integration"; }; # Add documentation for user packages diff --git a/home/firefox/default.nix b/home/firefox/default.nix index 41389b5..7374b63 100644 --- a/home/firefox/default.nix +++ b/home/firefox/default.nix @@ -57,28 +57,27 @@ in "browser.newtabpage.activity-stream.section.highlights.includePocket" = false; # Disable pocket "extensions.pocket.enabled" = false; # Disable pocket "media.eme.enabled" = true; # Enable DRM - "media.gmp-widevinecdm.visible" = true; # Enable DRM "media.gmp-widevinecdm.enabled" = true; # Enable DRM + "media.gmp-widevinecdm.visible" = true; # Enable DRM "signon.autofillForms" = false; # Disable built-in form-filling "signon.rememberSignons" = false; # Disable built-in password manager "ui.systemUsesDarkTheme" = true; # Dark mode }; + + 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 + ); }; }; - - extensions = with pkgs.nur.repos.rycee.firefox-addons; ([ - bitwarden - consent-o-matic - form-history-control - https-everywhere - 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/home/firefox/tridactyl/default.nix b/home/firefox/tridactyl/default.nix index fd8e3fb..35b58c2 100644 --- a/home/firefox/tridactyl/default.nix +++ b/home/firefox/tridactyl/default.nix @@ -1,9 +1,28 @@ -{ config, lib, ... }: +{ config, lib, pkgs, ... }: let cfg = config.my.home.firefox.tridactyl; + + term = config.my.home.terminal.program; + + vimCommandLine = { + alacritty = ''-e "vim" "%f" "+normal!%lGzv%c|"''; + # Termite wants the whole command in a single argument... + termite = ''-e "vim %f '+normal!%lGzv%c|'"''; + }; in { config = lib.mkIf cfg.enable { - xdg.configFile."tridactyl/tridactylrc".source = ./tridactylrc; + xdg.configFile."tridactyl/tridactylrc".source = pkgs.substituteAll { + src = ./tridactylrc; + + editorcmd = lib.concatStringsSep " " [ + # Use my configured terminal + term + # Make it easy to pick out with a window class name + "--class tridactyl_editor" + # Open vim with the cursor in the correct position + vimCommandLine.${term} + ]; + }; }; } diff --git a/home/firefox/tridactyl/tridactylrc b/home/firefox/tridactyl/tridactylrc index dc59a2e..31d3cb7 100644 --- a/home/firefox/tridactyl/tridactylrc +++ b/home/firefox/tridactyl/tridactylrc @@ -5,14 +5,18 @@ colorscheme dark " Make tridactyl open Vim in my prefered terminal -" FIXME: make it follow my prefered terminal -set editorcmd termite --class tridactyl_editor -e 'vim %f' +set editorcmd @editorcmd@ + +" Remove editor file after use +alias editor_rm composite editor | jsb -p tri.native.run(`rm -f '${JS_ARG[0]}'`) +bind --mode=insert editor_rm +bind --mode=input editor_rm " }}} " Binds {{{ " Reddit et al. {{{ " Toggle comments on Reddit, Hacker News, Lobste.rs -bind ;c hint -c [class*="expand"],[class*="togg"],[class="comment_folder"] +bind ;c hint -Jc [class*="expand"],[class*="togg"],[class="comment_folder"] " Make `gu` take me back to subreddit from comments bindurl reddit.com gu urlparent 3 @@ -22,8 +26,8 @@ bindurl www.google.com f hint -Jc #search div:not(.action-menu) > a bindurl www.google.com F hint -Jbc #search div:not(.action-menu) > a " Only hint search results on DuckDuckGo -bindurl ^https://duckduckgo.com f hint -Jc [class~=result__a] -bindurl ^https://duckduckgo.com F hint -Jbc [class~=result__a] +bindurl ^https://duckduckgo.com f hint -Jc [data-testid="result-title-a"] +bindurl ^https://duckduckgo.com F hint -Jbc [data-testid="result-title-a"] " Only hint item pages on Hacker News bindurl news.ycombinator.com ;f hint -Jc .age > a @@ -65,6 +69,8 @@ unbind " Redirections {{{ " Always redirect Reddit to the old site autocmd DocStart ^http(s?)://www.reddit.com js tri.excmds.urlmodify("-t", "www", "old") +" Use a better Twitter front-end +autocmd DocStart ^http(s?)://twitter.com js tri.excmds.urlmodify("-t", "twitter.com", "nitter.net") " }}} " Disabled websites {{{ diff --git a/home/fzf/default.nix b/home/fzf/default.nix new file mode 100644 index 0000000..b7e308f --- /dev/null +++ b/home/fzf/default.nix @@ -0,0 +1,15 @@ +{ config, lib, ... }: +let + cfg = config.my.home.fzf; +in +{ + options.my.home.fzf = with lib; { + enable = my.mkDisableOption "fzf configuration"; + }; + + config = lib.mkIf cfg.enable { + programs.fzf = { + enable = true; + }; + }; +} diff --git a/home/gdb/default.nix b/home/gdb/default.nix index f6db2e7..c498048 100644 --- a/home/gdb/default.nix +++ b/home/gdb/default.nix @@ -26,11 +26,7 @@ in gdb ]; - # FIXME: waiting for commit 64aaad6349d2b2c45063a5383f877ce9a3a0c354 xdg.configFile."gdb/gdbinit".source = ./gdbinit; - - # FIXME: remove once `gdb` is updated from version 10.2 - home.file.".gdbinit".source = ./gdbinit; }) (lib.mkIf cfg.rr.enable { diff --git a/home/gdb/gdbinit b/home/gdb/gdbinit index bdf7bfd..86e8c3c 100644 --- a/home/gdb/gdbinit +++ b/home/gdb/gdbinit @@ -19,6 +19,6 @@ set print demangle on set auto-load python-scripts # Allow autoloading project-local .gdbinit files -set auto-load safe-path ~/git/ +add-auto-load-safe-path ~/git/ # Allow autoloading from the Nix store -set auto-load safe-path /nix/store +add-auto-load-safe-path /nix/store diff --git a/home/git/default.ignore b/home/git/default.ignore index 77aedcc..d80996e 100644 --- a/home/git/default.ignore +++ b/home/git/default.ignore @@ -28,3 +28,7 @@ compile_commands.json # Direnv files .envrc .direnv/ + +# Project-local neovim configuration files +.nvim.lua +.nvimrc diff --git a/home/git/default.nix b/home/git/default.nix index 6f4434b..4dba01e 100644 --- a/home/git/default.nix +++ b/home/git/default.nix @@ -5,14 +5,14 @@ let inherit (lib.my) mkMailAddress; in { - options.my.home.git = with lib.my; { - enable = mkDisableOption "git configuration"; + options.my.home.git = with lib; { + enable = my.mkDisableOption "git configuration"; }; - config.home.packages = with pkgs.gitAndTools; lib.mkIf cfg.enable [ - gitAndTools.git-absorb - gitAndTools.git-revise - gitAndTools.tig + config.home.packages = with pkgs; lib.mkIf cfg.enable [ + git-absorb + git-revise + tig ]; config.programs.git = lib.mkIf cfg.enable { @@ -23,7 +23,7 @@ in userName = "Bruno BELANYI"; # I want the full experience - package = pkgs.gitAndTools.gitFull; + package = pkgs.gitFull; aliases = { git = "!git"; @@ -35,6 +35,7 @@ in 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; @@ -120,6 +121,15 @@ in defaultBranch = "main"; }; + # Local configuration, not-versioned + include = { + path = "config.local"; + }; + + merge = { + conflictStyle = "zdiff3"; + }; + pull = { # Avoid useless merge commits rebase = true; @@ -137,8 +147,8 @@ in }; url = { - "git@gitea.belanyi.fr:" = { - insteadOf = "https://gitea.belanyi.fr/"; + "git@git.belanyi.fr:" = { + insteadOf = "https://git.belanyi.fr/"; }; "git@github.com:" = { @@ -162,6 +172,15 @@ in }; }; } + { + condition = "gitdir:~/git/work/"; + contents = { + user = { + name = "Bruno BELANYI"; + email = mkMailAddress "ambroisie" "google.com"; + }; + }; + } ]; ignores = diff --git a/home/gpg/default.nix b/home/gpg/default.nix index d48c200..7eadf48 100644 --- a/home/gpg/default.nix +++ b/home/gpg/default.nix @@ -27,5 +27,10 @@ in allow-loopback-pinentry ''; }; + + home.shellAliases = { + # Sometime `gpg-agent` errors out... + reset-agent = "gpg-connect-agent updatestartuptty /bye"; + }; }; } diff --git a/home/htop/default.nix b/home/htop/default.nix index c4b33a9..570fa47 100644 --- a/home/htop/default.nix +++ b/home/htop/default.nix @@ -3,8 +3,8 @@ let cfg = config.my.home.htop; in { - options.my.home.htop = with lib.my; { - enable = mkDisableOption "htop configuration"; + options.my.home.htop = with lib; { + enable = my.mkDisableOption "htop configuration"; }; config.programs.htop = lib.mkIf cfg.enable { diff --git a/home/jq/default.nix b/home/jq/default.nix index d8bd59b..57e266f 100644 --- a/home/jq/default.nix +++ b/home/jq/default.nix @@ -3,8 +3,8 @@ let cfg = config.my.home.jq; in { - options.my.home.jq = with lib.my; { - enable = mkDisableOption "jq configuration"; + options.my.home.jq = with lib; { + enable = my.mkDisableOption "jq configuration"; }; config.programs.jq = lib.mkIf cfg.enable { diff --git a/home/mail/accounts/default.nix b/home/mail/accounts/default.nix index 80d95ae..e7663d8 100644 --- a/home/mail/accounts/default.nix +++ b/home/mail/accounts/default.nix @@ -8,7 +8,7 @@ let realName = lib.mkDefault "Bruno BELANYI"; userName = lib.mkDefault (mkMailAddress address domain); passwordCommand = - lib.mkDefault [ "${pkgs.ambroisie.bw-pass}/bin/bw-pass" "Mail" passName ]; + lib.mkDefault [ (lib.getExe pkgs.ambroisie.rbw-pass) "Mail" passName ]; address = mkMailAddress address domain; aliases = builtins.map (lib.flip mkMailAddress domain) aliases; @@ -17,6 +17,9 @@ let himalaya = { enable = cfg.himalaya.enable; + # FIXME: try to actually configure it at some point + backend = "imap"; + sender = "smtp"; }; msmtp = { @@ -51,21 +54,7 @@ let }; office365Config = { - imap = { - host = "outlook.office365.com"; - port = 993; - tls = { - enable = true; - }; - }; - smtp = { - host = "outlook.office365.com"; - port = 587; - tls = { - enable = true; - useStartTls = true; - }; - }; + flavor = "outlook.office365.com"; }; in { diff --git a/home/mail/default.nix b/home/mail/default.nix index ac44593..14f086a 100644 --- a/home/mail/default.nix +++ b/home/mail/default.nix @@ -15,7 +15,7 @@ in enable = my.mkDisableOption "email configuration"; himalaya = { - enable = mkRelatedOption "himalaya configuration"; + enable = mkEnableOption "himalaya configuration"; }; msmtp = { diff --git a/home/mail/himalaya/default.nix b/home/mail/himalaya/default.nix index c2d3b05..849a415 100644 --- a/home/mail/himalaya/default.nix +++ b/home/mail/himalaya/default.nix @@ -9,7 +9,7 @@ in settings = { notify-cmd = let - notify-send = "${pkgs.libnotify}/bin/notify-send"; + notify-send = lib.getExe pkgs.libnotify; in pkgs.writeScript "mail-notifier" '' SENDER="$1" diff --git a/home/nix-index/default.nix b/home/nix-index/default.nix index ae6f338..383621e 100644 --- a/home/nix-index/default.nix +++ b/home/nix-index/default.nix @@ -3,8 +3,8 @@ let cfg = config.my.home.nix-index; in { - options.my.home.nix-index = with lib.my; { - enable = mkDisableOption "nix-index configuration"; + options.my.home.nix-index = with lib; { + enable = my.mkDisableOption "nix-index configuration"; }; config.programs.nix-index = lib.mkIf cfg.enable { diff --git a/home/nix/default.nix b/home/nix/default.nix new file mode 100644 index 0000000..9ccbdc5 --- /dev/null +++ b/home/nix/default.nix @@ -0,0 +1,82 @@ +# Nix related settings +{ config, inputs, lib, pkgs, ... }: +let + cfg = config.my.home.nix; + + channels = lib.my.merge [ + { + # Allow me to use my custom package using `nix run self#pkg` + self = inputs.self; + # Add NUR to run some packages that are only present there + nur = inputs.nur; + # Use pinned nixpkgs when using `nix run pkgs#` + pkgs = inputs.nixpkgs; + } + (lib.optionalAttrs cfg.overrideNixpkgs { + # ... And with `nix run nixpkgs#` + nixpkgs = inputs.nixpkgs; + }) + ]; +in +{ + options.my.home.nix = with lib; { + enable = my.mkDisableOption "nix configuration"; + + linkInputs = my.mkDisableOption "link inputs to `$XDG_CONFIG_HOME/nix/inputs`"; + + addToRegistry = my.mkDisableOption "add inputs and self to registry"; + + addToNixPath = my.mkDisableOption "add inputs and self to nix path"; + + overrideNixpkgs = my.mkDisableOption "point nixpkgs to pinned system version"; + }; + + config = lib.mkIf cfg.enable (lib.mkMerge [ + { + assertions = [ + { + assertion = cfg.addToNixPath -> cfg.linkInputs; + message = '' + enabling `my.home.nix.addToNixPath` needs to have + `my.home.nix.linkInputs = true` + ''; + } + ]; + } + + { + nix = { + package = lib.mkDefault pkgs.nix; # NixOS module sets it unconditionally + + settings = { + experimental-features = [ "nix-command" "flakes" ]; + }; + }; + } + + (lib.mkIf cfg.addToRegistry { + nix.registry = + let + makeEntry = v: { flake = v; }; + makeEntries = lib.mapAttrs (lib.const makeEntry); + in + makeEntries channels; + }) + + (lib.mkIf cfg.linkInputs { + xdg.configFile = + let + makeLink = n: v: { + name = "nix/inputs/${n}"; + value = { source = v.outPath; }; + }; + makeLinks = lib.mapAttrs' makeLink; + in + makeLinks channels; + }) + + (lib.mkIf cfg.addToNixPath { + home.sessionVariables.NIX_PATH = "${config.xdg.configHome}/nix/inputs\${NIX_PATH:+:$NIX_PATH}"; + }) + ]); +} diff --git a/home/nixpkgs/default.nix b/home/nixpkgs/default.nix new file mode 100644 index 0000000..720fc9b --- /dev/null +++ b/home/nixpkgs/default.nix @@ -0,0 +1,20 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.my.home.nixpkgs; +in +{ + options.my.home.nixpkgs = with lib; { + enable = mkEnableOption "nixpkgs configuration"; + }; + + config = lib.mkIf cfg.enable { + home.packages = with pkgs; [ + nixpkgs-review + ]; + + home.sessionVariables = { + GITHUB_TOKEN = ''$(cat "${config.age.secrets."github/token".path}")''; + GITHUB_API_TOKEN = ''$(cat "${config.age.secrets."github/token".path}")''; + }; + }; +} diff --git a/home/packages/default.nix b/home/packages/default.nix index 434cb0d..0cfa3b3 100644 --- a/home/packages/default.nix +++ b/home/packages/default.nix @@ -22,7 +22,5 @@ in file mosh ripgrep - rr - termite.terminfo ] ++ cfg.additionalPackages); } diff --git a/home/pager/default.nix b/home/pager/default.nix index 00d29c0..aa72587 100644 --- a/home/pager/default.nix +++ b/home/pager/default.nix @@ -3,8 +3,8 @@ let cfg = config.my.home.pager; in { - options.my.home.pager = with lib.my; { - enable = mkDisableOption "pager configuration"; + options.my.home.pager = with lib; { + enable = my.mkDisableOption "pager configuration"; }; @@ -14,23 +14,8 @@ in PAGER = "less"; # Clear the screen on start and exit LESS = "-R -+X -c"; - }; - - programs.zsh.localVariables = { - # Colored man pages - LESS_TERMCAP_mb = "$(tput bold; tput setaf 2)"; - LESS_TERMCAP_md = "$(tput bold; tput setaf 6)"; - LESS_TERMCAP_me = "$(tput sgr0)"; - LESS_TERMCAP_so = "$(tput bold; tput setaf 3; tput setab 4)"; - LESS_TERMCAP_se = "$(tput rmso; tput sgr0)"; - LESS_TERMCAP_us = "$(tput bold; tput setaf 2)"; - LESS_TERMCAP_ue = "$(tput rmul; tput sgr0)"; - LESS_TERMCAP_mr = "$(tput rev)"; - LESS_TERMCAP_mh = "$(tput dim)"; - LESS_TERMCAP_ZN = "$(tput ssubm)"; - LESS_TERMCAP_ZV = "$(tput rsubm)"; - LESS_TERMCAP_ZO = "$(tput ssupm)"; - LESS_TERMCAP_ZW = "$(tput rsupm)"; + # Better XDG compliance + LESSHISTFILE = "${config.xdg.dataHome}/less/history"; }; }; } diff --git a/home/secrets/default.nix b/home/secrets/default.nix new file mode 100644 index 0000000..7c0c0a1 --- /dev/null +++ b/home/secrets/default.nix @@ -0,0 +1,25 @@ +{ config, inputs, lib, options, ... }: + +{ + imports = [ + inputs.agenix.homeManagerModules.age + ]; + + config.age = { + secrets = + let + toName = lib.removeSuffix ".age"; + toSecret = name: { ... }: { + file = ./. + "/${name}"; + }; + convertSecrets = n: v: lib.nameValuePair (toName n) (toSecret n v); + secrets = import ./secrets.nix; + in + lib.mapAttrs' convertSecrets secrets; + + # Add my usual agenix key to the defaults + identityPaths = options.age.identityPaths.default ++ [ + "${config.home.homeDirectory}/.ssh/agenix" + ]; + }; +} diff --git a/home/secrets/github/token.age b/home/secrets/github/token.age new file mode 100644 index 0000000..1d36ccd Binary files /dev/null and b/home/secrets/github/token.age differ diff --git a/home/secrets/secrets.nix b/home/secrets/secrets.nix new file mode 100644 index 0000000..f474342 --- /dev/null +++ b/home/secrets/secrets.nix @@ -0,0 +1,9 @@ +# Common secrets +let + keys = import ../../keys; + + all = builtins.attrValues keys.users; +in +{ + "github/token.age".publicKeys = all; +} diff --git a/home/ssh/default.nix b/home/ssh/default.nix index cbfd30c..123190f 100644 --- a/home/ssh/default.nix +++ b/home/ssh/default.nix @@ -3,13 +3,18 @@ let cfg = config.my.home.ssh; in { - options.my.home.ssh = with lib.my; { - enable = mkDisableOption "ssh configuration"; + options.my.home.ssh = with lib; { + enable = my.mkDisableOption "ssh configuration"; }; config.programs.ssh = lib.mkIf cfg.enable { enable = true; + includes = [ + # Local configuration, not-versioned + "config.local" + ]; + matchBlocks = { "github.com" = { hostname = "github.com"; @@ -29,8 +34,8 @@ in user = "git"; }; - "gitea.belanyi.fr" = { - hostname = "gitea.belanyi.fr"; + "git.belanyi.fr" = { + hostname = "git.belanyi.fr"; identityFile = "~/.ssh/shared_rsa"; user = "git"; }; @@ -40,12 +45,6 @@ in identityFile = "~/.ssh/shared_rsa"; user = "ambroisie"; }; - - work = { - hostname = "workspaces.dgexsol.fr"; - identityFile = "~/.ssh/shared_rsa"; - user = "bruno_belanyi"; - }; }; extraConfig = '' diff --git a/home/terminal/alacritty/default.nix b/home/terminal/alacritty/default.nix new file mode 100644 index 0000000..daf3e80 --- /dev/null +++ b/home/terminal/alacritty/default.nix @@ -0,0 +1,52 @@ +{ config, lib, ... }: +let + cfg = config.my.home.terminal; +in +{ + config = lib.mkIf (cfg.program == "alacritty") { + programs.alacritty = { + enable = true; + + settings = { + font = { + size = 5.5; + }; + + colors = { + primary = { + background = cfg.colors.background; + foreground = cfg.colors.foreground; + + bright_foreground = cfg.colors.foregroundBold; + }; + + cursor = { + cursor = cfg.colors.cursor; + }; + + normal = { + black = cfg.colors.black; + red = cfg.colors.red; + green = cfg.colors.green; + yellow = cfg.colors.yellow; + blue = cfg.colors.blue; + magenta = cfg.colors.magenta; + cyan = cfg.colors.cyan; + white = cfg.colors.white; + }; + + bright = { + black = cfg.colors.blackBold; + red = cfg.colors.redBold; + green = cfg.colors.greenBold; + yellow = cfg.colors.yellowBold; + blue = cfg.colors.blueBold; + magenta = cfg.colors.magentaBold; + cyan = cfg.colors.cyanBold; + white = cfg.colors.whiteBold; + }; + }; + }; + }; + }; +} diff --git a/home/terminal/default.nix b/home/terminal/default.nix index 68ff44e..20f36b5 100644 --- a/home/terminal/default.nix +++ b/home/terminal/default.nix @@ -10,13 +10,14 @@ let in { imports = [ + ./alacritty ./termite ]; options.my.home = with lib; { terminal = { program = mkOption { - type = with types; nullOr (enum [ "termite" ]); + type = with types; nullOr (enum [ "alacritty" "termite" ]); default = null; example = "termite"; description = "Which terminal to use for home session"; diff --git a/home/tmux/default.nix b/home/tmux/default.nix index f9b711c..70f037f 100644 --- a/home/tmux/default.nix +++ b/home/tmux/default.nix @@ -1,11 +1,16 @@ { config, lib, pkgs, ... }: let cfg = config.my.home.tmux; - hasGUI = config.my.home.x.enable || (config.my.home.wm != null); + hasGUI = lib.any lib.id [ + config.my.home.x.enable + (config.my.home.wm.windowManager != null) + ]; in { - options.my.home.tmux = with lib.my; { - enable = mkDisableOption "tmux terminal multiplexer"; + options.my.home.tmux = with lib; { + enable = my.mkDisableOption "tmux terminal multiplexer"; + + enabledPassthrough = mkEnableOption "tmux DCS passthrough sequence"; }; config.programs.tmux = lib.mkIf cfg.enable { @@ -24,7 +29,7 @@ in pain-control # Better session management sessionist - (lib.optionalAttrs hasGUI { + { # X clipboard integration plugin = yank; extraConfig = '' @@ -33,7 +38,7 @@ in # Stay in copy mode after yanking set -g @yank_action 'copy-pipe' ''; - }) + } { # Show when prefix has been pressed plugin = prefix-highlight; @@ -57,6 +62,19 @@ in } # Block selection in vim mode bind-key -Tcopy-mode-vi 'C-v' send -X begin-selection \; send -X rectangle-toggle + + # Allow any application to send OSC52 escapes to set the clipboard + set -s set-clipboard on + + # Longer session names in status bar + set -g status-left-length 16 + + ${ + lib.optionalString cfg.enabledPassthrough '' + # Allow any application to use the tmux DCS for passthrough + set -g allow-passthrough on + '' + } ''; }; } diff --git a/home/vim/after/ftplugin/pandoc.vim b/home/vim/after/ftplugin/markdown.vim similarity index 100% rename from home/vim/after/ftplugin/pandoc.vim rename to home/vim/after/ftplugin/markdown.vim diff --git a/home/vim/after/ftplugin/nix.vim b/home/vim/after/ftplugin/nix.vim new file mode 100644 index 0000000..fb6126e --- /dev/null +++ b/home/vim/after/ftplugin/nix.vim @@ -0,0 +1,6 @@ +" Create the `b:undo_ftplugin` variable if it doesn't exist +call ftplugined#check_undo_ft() + +" Use a small indentation value on Nix files +setlocal shiftwidth=2 +let b:undo_ftplugin.='|setlocal shiftwidth<' diff --git a/home/vim/after/ftplugin/tiger.vim b/home/vim/after/ftplugin/tiger.vim new file mode 100644 index 0000000..81c2cfc --- /dev/null +++ b/home/vim/after/ftplugin/tiger.vim @@ -0,0 +1,6 @@ +" Create the `b:undo_ftplugin` variable if it doesn't exist +call ftplugined#check_undo_ft() + +" Use a small indentation value on tiger files +setlocal shiftwidth=2 +let b:undo_ftplugin.='|setlocal shiftwidth<' diff --git a/home/vim/after/plugin/mappings/commentary.vim b/home/vim/after/plugin/mappings/commentary.lua similarity index 94% rename from home/vim/after/plugin/mappings/commentary.vim rename to home/vim/after/plugin/mappings/commentary.lua index 219d661..6ed3b89 100644 --- a/home/vim/after/plugin/mappings/commentary.vim +++ b/home/vim/after/plugin/mappings/commentary.lua @@ -1,4 +1,3 @@ -lua << EOF local wk = require("which-key") local keys = { @@ -9,4 +8,3 @@ local keys = { } wk.register(keys, { prefix = "gc" }) -EOF diff --git a/home/vim/after/plugin/mappings/misc.vim b/home/vim/after/plugin/mappings/misc.lua similarity index 91% rename from home/vim/after/plugin/mappings/misc.vim rename to home/vim/after/plugin/mappings/misc.lua index c7fcc8a..6aa25a2 100644 --- a/home/vim/after/plugin/mappings/misc.vim +++ b/home/vim/after/plugin/mappings/misc.lua @@ -1,4 +1,3 @@ -lua << EOF local wk = require("which-key") local keys = { @@ -6,4 +5,3 @@ local keys = { } wk.register(keys, { prefix = "" }) -EOF diff --git a/home/vim/after/plugin/mappings/telescope.vim b/home/vim/after/plugin/mappings/telescope.lua similarity index 97% rename from home/vim/after/plugin/mappings/telescope.vim rename to home/vim/after/plugin/mappings/telescope.lua index 98551f9..e0d38a7 100644 --- a/home/vim/after/plugin/mappings/telescope.vim +++ b/home/vim/after/plugin/mappings/telescope.lua @@ -1,4 +1,3 @@ -lua << EOF local wk = require("which-key") local telescope = require("telescope") local telescope_builtin = require("telescope.builtin") @@ -16,5 +15,3 @@ local keys = { } wk.register(keys, { prefix = "" }) -EOF - diff --git a/home/vim/after/plugin/mappings/tree-sitter-textobjects.vim b/home/vim/after/plugin/mappings/tree-sitter-textobjects.lua similarity index 98% rename from home/vim/after/plugin/mappings/tree-sitter-textobjects.vim rename to home/vim/after/plugin/mappings/tree-sitter-textobjects.lua index 9cabd91..631731c 100644 --- a/home/vim/after/plugin/mappings/tree-sitter-textobjects.vim +++ b/home/vim/after/plugin/mappings/tree-sitter-textobjects.lua @@ -1,4 +1,3 @@ -lua << EOF local wk = require("which-key") local motions = { @@ -29,4 +28,3 @@ local objects = { wk.register(motions, { mode = "n" }) wk.register(objects, { mode = "o" }) -EOF diff --git a/home/vim/after/plugin/mappings/unimpaired.vim b/home/vim/after/plugin/mappings/unimpaired.lua similarity index 83% rename from home/vim/after/plugin/mappings/unimpaired.vim rename to home/vim/after/plugin/mappings/unimpaired.lua index c4bb35b..f502056 100644 --- a/home/vim/after/plugin/mappings/unimpaired.vim +++ b/home/vim/after/plugin/mappings/unimpaired.lua @@ -1,6 +1,7 @@ -lua << EOF local wk = require("which-key") +local lsp = require("ambroisie.lsp") + local keys = { -- Edition and navigation mappins ["["] = { @@ -31,7 +32,7 @@ local keys = { x = "XML encode", y = "C string encode", -- Custom - d = { vim.diagnostic.goto_prev, "Previous diagnostic" } + d = { lsp.goto_prev_diagnostic, "Previous diagnostic" }, }, ["]"] = { name = "Next", @@ -61,7 +62,7 @@ local keys = { x = "XML decode", y = "C string decode", -- Custom - d = { vim.diagnostic.goto_next, "Next diagnostic" } + d = { lsp.goto_next_diagnostic, "Next diagnostic" }, }, -- Option mappings @@ -70,13 +71,14 @@ local keys = { b = "Light background", c = "Cursor line", d = "Diff", - e = { "lwindow", "Location list" }, - f = { "cwindow", "Quickfix list" }, + f = { "FormatEnable", "LSP Formatting" }, h = "Search high-lighting", i = "Case insensitive search", l = "List mode", n = "Line numbers", r = "Relative line numbers", + p = { "lwindow", "Location list" }, + q = { "cwindow", "Quickfix list" }, u = "Cursor column", v = "Virtual editing", w = "Text wrapping", @@ -88,12 +90,13 @@ local keys = { b = "Light background", c = "Cursor line", d = "Diff", - e = { "lclose", "Location list" }, - f = { "cclose", "Quickfix list" }, + f = { "FormatDisable", "LSP Formatting" }, h = "Search high-lighting", i = "Case insensitive search", l = "List mode", n = "Line numbers", + p = { "lclose", "Location list" }, + q = { "cclose", "Quickfix list" }, r = "Relative line numbers", u = "Cursor column", v = "Virtual editing", @@ -106,12 +109,13 @@ local keys = { b = "Light background", c = "Cursor line", d = "Diff", - e = { "(qf_loc_toggle)", "Location list" }, - f = { "(qf_qf_toggle)", "Quickfix list" }, + f = { "FormatToggle", "LSP Formatting" }, h = "Search high-lighting", i = "Case insensitive search", l = "List mode", n = "Line numbers", + p = { "(qf_loc_toggle)", "Location list" }, + q = { "(qf_qf_toggle)", "Quickfix list" }, r = "Relative line numbers", u = "Cursor column", v = "Virtual editing", @@ -122,4 +126,3 @@ local keys = { } wk.register(keys) -EOF diff --git a/home/vim/default.nix b/home/vim/default.nix index 4bd1886..3bd2469 100644 --- a/home/vim/default.nix +++ b/home/vim/default.nix @@ -18,12 +18,16 @@ let ]; in { - options.my.home.vim = with lib.my; { - enable = mkDisableOption "vim configuration"; + options.my.home.vim = with lib; { + enable = my.mkDisableOption "vim configuration"; }; config.programs.neovim = lib.mkIf cfg.enable { enable = true; + + # This is the best editor + defaultEditor = true; + # All the aliases viAlias = true; vimAlias = true; @@ -31,7 +35,7 @@ in plugins = with pkgs.vimPlugins; [ # Theming - vim-gruvbox8 # Nice dark theme + gruvbox-nvim # Nice dark theme lualine-nvim # A lua-based status line lualine-lsp-progress # Show progress for LSP servers @@ -42,7 +46,6 @@ in vim-git # Sane git syntax files vim-repeat # Enanche '.' for plugins vim-rsi # Readline mappings - vim-surround # Deal with pairs vim-unimpaired # Some ex command mappings vim-vinegar # Better netrw @@ -51,38 +54,41 @@ in vim-beancount vim-jsonnet vim-nix - vim-pandoc - vim-pandoc-syntax vim-toml # General enhancements vim-qf # Better quick-fix list + nvim-osc52 # Send clipboard data through terminal escape for SSH # Other wrappers git-messenger-vim # A simple blame window # LSP and linting + nvim-lspconfig # Easy LSP configuration + lsp-format-nvim # Simplified formatting configuration lsp_lines-nvim # Show diagnostics *over* regions null-ls-nvim # LSP integration for linters and formatters - (nvim-treesitter.withPlugins (_: pkgs.tree-sitter.allGrammars)) # Better highlighting + nvim-treesitter.withAllGrammars # Better highlighting nvim-treesitter-textobjects # More textobjects nvim-ts-context-commentstring # Comment string in nested language blocks plenary-nvim # 'null-ls', 'telescope' dependency # Completion + luasnip # Snippet manager compatible with LSP + friendly-snippets # LSP snippets collection nvim-cmp # Completion engine cmp-buffer # Words from open buffers cmp-nvim-lsp # LSP suggestions cmp-nvim-lua # NeoVim lua API cmp-path # Path name suggestions cmp-under-comparator # Sort items that start with '_' lower - friendly-snippets # LSP snippets collection - luasnip # Snippet manager compatible with LSP + cmp_luasnip # Snippet suggestions from LuaSnip # UX improvements dressing-nvim # Integrate native UI hooks with Telescope etc... gitsigns-nvim # Fast git UI integration nvim-notify # Better notification API + nvim-surround # Deal with pairs, now in Lua telescope-fzf-native-nvim # Use 'fzf' fuzzy matching algorithm telescope-lsp-handlers-nvim # Use 'telescope' for various LSP actions telescope-nvim # Fuzzy finder interface diff --git a/home/vim/ftdetect/automake.lua b/home/vim/ftdetect/automake.lua new file mode 100644 index 0000000..cfa15d2 --- /dev/null +++ b/home/vim/ftdetect/automake.lua @@ -0,0 +1,6 @@ +-- Use Automake filetype for `local.am` files, explicit `set` to force override +vim.filetype.add({ + filename = { + ["local.am"] = "automake", + }, +}) diff --git a/home/vim/ftdetect/automake.vim b/home/vim/ftdetect/automake.vim deleted file mode 100644 index 5cc73b0..0000000 --- a/home/vim/ftdetect/automake.vim +++ /dev/null @@ -1,2 +0,0 @@ -" Use Automake filetype for `local.am` files, explicit `set` to force override -au BufNewFile,BufRead local.am set filetype=automake diff --git a/home/vim/ftdetect/direnv.lua b/home/vim/ftdetect/direnv.lua new file mode 100644 index 0000000..fba9748 --- /dev/null +++ b/home/vim/ftdetect/direnv.lua @@ -0,0 +1,6 @@ +-- Use bash filetype for `.envrc` files +vim.filetype.add({ + filename = { + [".envrc"] = "bash", + }, +}) diff --git a/home/vim/ftdetect/kbuild.lua b/home/vim/ftdetect/kbuild.lua new file mode 100644 index 0000000..799570e --- /dev/null +++ b/home/vim/ftdetect/kbuild.lua @@ -0,0 +1,6 @@ +-- Kbuild is just a Makefile under a different name +vim.filetype.add({ + filename = { + ["Kbuild"] = "make", + }, +}) diff --git a/home/vim/ftdetect/kconfig.lua b/home/vim/ftdetect/kconfig.lua new file mode 100644 index 0000000..d51e964 --- /dev/null +++ b/home/vim/ftdetect/kconfig.lua @@ -0,0 +1,6 @@ +-- Mconfig is just Kconfig +vim.filetype.add({ + filename = { + ["Mconfig"] = "kconfig", + }, +}) diff --git a/home/vim/ftdetect/tiger.lua b/home/vim/ftdetect/tiger.lua new file mode 100644 index 0000000..a261103 --- /dev/null +++ b/home/vim/ftdetect/tiger.lua @@ -0,0 +1,7 @@ +-- Use Tiger filetype for programs and header files +vim.filetype.add({ + extension = { + tig = "tiger", + tih = "tiger", + }, +}) diff --git a/home/vim/ftdetect/tikz.lua b/home/vim/ftdetect/tikz.lua new file mode 100644 index 0000000..93b7db0 --- /dev/null +++ b/home/vim/ftdetect/tikz.lua @@ -0,0 +1,6 @@ +-- Use LaTeX filetype for TikZ files +vim.filetype.add({ + extension = { + tikz = "tex", + }, +}) diff --git a/home/vim/ftdetect/tikz.vim b/home/vim/ftdetect/tikz.vim deleted file mode 100644 index 7327b11..0000000 --- a/home/vim/ftdetect/tikz.vim +++ /dev/null @@ -1,2 +0,0 @@ -" Use LaTeX filetype for TikZ files -au BufNewFile,BufRead *.tikz setfiletype tex diff --git a/home/vim/init.vim b/home/vim/init.vim index ab5f648..bd63d25 100644 --- a/home/vim/init.vim +++ b/home/vim/init.vim @@ -66,6 +66,11 @@ set list " Show a tab as an arrow, trailing spaces as ¤, non-breaking spaces as dots 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 @@ -75,15 +80,16 @@ set timeoutlen=500 " Timeout quickly for CursorHold events (and also swap file) set updatetime=250 +" Disable all mouse integrations +set mouse= + " Set dark mode by default set background=dark -" Include plug-in integration -let g:gruvbox_plugin_hi_groups=1 -" Include filetype integration -let g:gruvbox_filetype_hi_groups=1 +" 24 bit colors +set termguicolors " Use my preferred colorscheme -colorscheme gruvbox8 +colorscheme gruvbox " }}} " Search parameters {{{ @@ -96,12 +102,10 @@ set ignorecase set smartcase " }}} -" Import settings when inside a git repository {{{ +" Project-local settings {{{ """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -let git_settings=system("git config --get vim.settings") -if strlen(git_settings) - exe "set" git_settings -endif +" Securely read `.nvim.lua` or `.nvimrc`. +set exrc " }}} " vim: foldmethod=marker diff --git a/home/vim/lua/ambroisie/lsp.lua b/home/vim/lua/ambroisie/lsp.lua index 27e5e44..7ef6e26 100644 --- a/home/vim/lua/ambroisie/lsp.lua +++ b/home/vim/lua/ambroisie/lsp.lua @@ -1,40 +1,51 @@ 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 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 attched client M.on_attach = function(client, bufnr) - -- Diagnostics - vim.diagnostic.config({ - -- Disable virtual test next to affected regions - virtual_text = false, - -- Show diagnostics signs - signs = true, - -- Underline offending regions - underline = true, - -- Do not bother me in the middle of insertion - update_in_insert = false, - -- Show highest severity first - severity_sort = true, - }) - - vim.cmd([[ - augroup DiagnosticsHover - autocmd! * - " Show diagnostics on "hover" - autocmd CursorHold,CursorHoldI lua vim.diagnostic.open_float(nil, {focus=false, scope="cursor"}) - augroup END - ]]) - -- Format on save - if client.resolved_capabilities.document_formatting then - vim.cmd([[ - augroup LspFormatting - autocmd! * - autocmd BufWritePre lua vim.lsp.buf.formatting_sync() - augroup END - ]]) - end + lsp_format.on_attach(client, bufnr) -- Mappings local wk = require("which-key") @@ -44,16 +55,41 @@ M.on_attach = function(client, bufnr) utils.dump(vim.lsp.buf.list_workspace_folders()) end - local function show_line_diagnostics() - vim.diagnostic.open_float(nil, { scope="line" }) + local function cycle_diagnostics_display() + -- Cycle from: + -- * nothing displayed + -- * single diagnostic at the end of the line (`virtual_text`) + -- * full diagnostics using virtual text (`virtual_lines`) + local text = vim.diagnostic.config().virtual_text + local lines = vim.diagnostic.config().virtual_lines + + -- Text -> Lines transition + if text then + text = false + lines = true + -- Lines -> Nothing transition + elseif lines then + text = false + lines = false + -- Nothing -> Text transition + else + text = true + lines = false + end + + vim.diagnostic.config({ + virtual_text = text, + virtual_lines = lines, + }) end local function show_buffer_diagnostics() - vim.diagnostic.open_float(nil, { scope="buffer" }) + vim.diagnostic.open_float(nil, { scope = "buffer" }) end local keys = { K = { vim.lsp.buf.hover, "Show symbol information" }, + [""] = { vim.lsp.buf.signature_help, "Show signature information" }, ["gd"] = { vim.lsp.buf.definition, "Go to definition" }, ["gD"] = { vim.lsp.buf.declaration, "Go to declaration" }, ["gi"] = { vim.lsp.buf.implementation, "Go to implementation" }, @@ -62,7 +98,7 @@ M.on_attach = function(client, bufnr) ["c"] = { name = "Code", a = { vim.lsp.buf.code_action, "Code actions" }, - d = { show_line_diagnostics, "Show line diagnostics" }, + d = { cycle_diagnostics_display, "Cycle diagnostics display" }, D = { show_buffer_diagnostics, "Show buffer diagnostics" }, r = { vim.lsp.buf.rename, "Rename symbol" }, s = { vim.lsp.buf.signature_help, "Show signature" }, @@ -79,5 +115,4 @@ M.on_attach = function(client, bufnr) wk.register(keys, { buffer = bufnr }) end - return M diff --git a/home/vim/lua/ambroisie/utils.lua b/home/vim/lua/ambroisie/utils.lua index 88f3d27..984c730 100644 --- a/home/vim/lua/ambroisie/utils.lua +++ b/home/vim/lua/ambroisie/utils.lua @@ -17,7 +17,27 @@ end ---@param cmd string? command to check ---@return fun(cmd: string): boolean executable M.is_executable_condition = function(cmd) - return function() return M.is_executable(cmd) end + return function() + return M.is_executable(cmd) + end +end + +-- whether or not we are currently in an SSH connection +-- @return boolean ssh connection +M.is_ssh = function() + local variables = { + "SSH_CONNECTION", + "SSH_CLIENT", + "SSH_TTY", + } + + for _, var in ipairs(variables) do + if string.len(os.getenv(var) or "") ~= 0 then + return true + end + end + + return false end -- list all active LSP clients for current buffer diff --git a/home/vim/plugin/abbreviations.lua b/home/vim/plugin/abbreviations.lua new file mode 100644 index 0000000..f6d6ac3 --- /dev/null +++ b/home/vim/plugin/abbreviations.lua @@ -0,0 +1,9 @@ +local abbreviations = { + -- A few things that are hard to write in ASCII + ["(R)"] = "©", + ["(TM)"] = "™", +} + +for text, result in pairs(abbreviations) do + vim.cmd.abbreviate(text, result) +end diff --git a/home/vim/plugin/abbreviations.vim b/home/vim/plugin/abbreviations.vim deleted file mode 100644 index 5d36434..0000000 --- a/home/vim/plugin/abbreviations.vim +++ /dev/null @@ -1,5 +0,0 @@ -" A few useful sets of abbreviations - -" A few things that are hard to write in ASCII -abbreviate (R) © -abbreviate (TM) ™ diff --git a/home/vim/plugin/numbertoggle.lua b/home/vim/plugin/numbertoggle.lua new file mode 100644 index 0000000..1f97fc8 --- /dev/null +++ b/home/vim/plugin/numbertoggle.lua @@ -0,0 +1,23 @@ +-- Show lines numbers +vim.opt.number = true + +local numbertoggle = vim.api.nvim_create_augroup("numbertoggle", { clear = true }) + +-- Toggle numbers between relative and absolute when changing buffers +vim.api.nvim_create_autocmd({ "BufEnter", "FocusGained", "InsertLeave", "WinEnter" }, { + pattern = "*", + group = numbertoggle, + command = "if &nu | setlocal rnu | endif", +}) +vim.api.nvim_create_autocmd({ "BufLeave", "FocusLost", "InsertEnter", "WinLeave" }, { + pattern = "*", + group = numbertoggle, + command = "if &nu | setlocal nornu | endif", +}) + +-- Never show the sign column in a terminal buffer +vim.api.nvim_create_autocmd({ "TermOpen" }, { + pattern = "*", + group = numbertoggle, + command = "setlocal nonu nornu", +}) diff --git a/home/vim/plugin/numbertoggle.vim b/home/vim/plugin/numbertoggle.vim deleted file mode 100644 index d9a969d..0000000 --- a/home/vim/plugin/numbertoggle.vim +++ /dev/null @@ -1,13 +0,0 @@ -" Idea for toggling taken from jeffkreeftmeijer - -" Show line numbers -set number - -augroup numbertoggle - autocmd! - " Toggle numbers between relative and absolute when changing buffers - autocmd BufEnter,FocusGained,InsertLeave,WinEnter * if &nu | set rnu | endif - autocmd BufLeave,FocusLost,InsertEnter,WinLeave * if &nu | set nornu | endif - " Disable line numbers and relative line numbers in terminal - autocmd TermOpen * setlocal nonu nornu -augroup END diff --git a/home/vim/plugin/settings/completion.vim b/home/vim/plugin/settings/completion.lua similarity index 89% rename from home/vim/plugin/settings/completion.vim rename to home/vim/plugin/settings/completion.lua index 9a3d7e6..2d150e8 100644 --- a/home/vim/plugin/settings/completion.vim +++ b/home/vim/plugin/settings/completion.lua @@ -1,7 +1,6 @@ -" Show completion menu in all cases, and don't select anything -set completeopt=menu,menuone,noselect +-- Show completion menu in all cases, and don't select anything +vim.opt.completeopt = { "menu", "menuone", "noselect" } -lua << EOF local cmp = require("cmp") local cmp_under_comparator = require("cmp-under-comparator") local luasnip = require("luasnip") @@ -29,7 +28,7 @@ cmp.setup({ end, [""] = cmp.mapping(cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }), { "i", "c" }), [""] = cmp.mapping(cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }), { "i", "c" }), - [""] = cmp.mapping.scroll_docs(-5), + [""] = cmp.mapping.scroll_docs(-5), [""] = cmp.mapping.scroll_docs(5), [""] = cmp.mapping.confirm({ behavior = cmp.ConfirmBehavior.Insert, select = false }), [""] = cmp.mapping.abort(), @@ -57,5 +56,7 @@ cmp.setup({ cmp.config.compare.order, }, }, + experimental = { + ghost_text = true, + }, }) -EOF diff --git a/home/vim/plugin/settings/dressing.vim b/home/vim/plugin/settings/dressing.lua similarity index 88% rename from home/vim/plugin/settings/dressing.vim rename to home/vim/plugin/settings/dressing.lua index 9508126..3928a59 100644 --- a/home/vim/plugin/settings/dressing.vim +++ b/home/vim/plugin/settings/dressing.lua @@ -1,8 +1,6 @@ -lua << EOF local dressing = require("dressing") dressing.setup({ -- Use a relative prompt size prefer_width = 0.4, }) -EOF diff --git a/home/vim/plugin/settings/fastfold.lua b/home/vim/plugin/settings/fastfold.lua new file mode 100644 index 0000000..78ee937 --- /dev/null +++ b/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/home/vim/plugin/settings/fastfold.vim b/home/vim/plugin/settings/fastfold.vim deleted file mode 100644 index a1f1787..0000000 --- a/home/vim/plugin/settings/fastfold.vim +++ /dev/null @@ -1,5 +0,0 @@ -" Intercept all fold commands -let g:fastfold_fold_command_suffixes=[ - \ 'x', 'X', 'a', 'A', 'o', 'O', 'c', 'C', - \ 'r', 'R', 'm', 'M', 'i', 'n', 'N' - \ ] diff --git a/home/vim/plugin/settings/formatting.lua b/home/vim/plugin/settings/formatting.lua new file mode 100644 index 0000000..1bb896b --- /dev/null +++ b/home/vim/plugin/settings/formatting.lua @@ -0,0 +1,3 @@ +local lsp_format = require("lsp-format") + +lsp_format.setup({}) diff --git a/home/vim/plugin/settings/git.lua b/home/vim/plugin/settings/git.lua new file mode 100644 index 0000000..4dbebca --- /dev/null +++ b/home/vim/plugin/settings/git.lua @@ -0,0 +1,58 @@ +local gitsigns = require("gitsigns") +local wk = require("which-key") + +gitsigns.setup({ + current_line_blame_opts = { + -- Show the blame quickly + delay = 100, + }, +}) + +local keys = { + -- Navigation + ["[c"] = { "&diff ? '[c' : 'Gitsigns prev_hunk'", "Previous hunk/diff", expr = true }, + ["]c"] = { "&diff ? ']c' : 'Gitsigns next_hunk'", "Next hunk/diff", expr = true }, + + -- Commands + ["g"] = { + name = "Git", + -- Actions + b = { gitsigns.toggle_current_line_blame, "Toggle blame virtual text" }, + d = { gitsigns.diffthis, "Diff buffer" }, + -- stylua: ignore + D = { function() gitsigns.diffthis("~") end, "Diff buffer against last commit" }, + g = { "Git", "Git status" }, + h = { gitsigns.toggle_deleted, "Show deleted hunks" }, + L = { ":spT:Gllog --follow -- %:p", "Current buffer log" }, + m = { "(git-messenger)", "Current line blame" }, + p = { gitsigns.preview_hunk, "Preview hunk" }, + r = { gitsigns.reset_hunk, "Restore hunk" }, + R = { gitsigns.reset_buffer, "Restore buffer" }, + s = { gitsigns.stage_hunk, "Stage hunk" }, + S = { gitsigns.stage_buffer, "Stage buffer" }, + u = { gitsigns.undo_stage_hunk, "Undo stage hunk" }, + ["["] = { gitsigns.prev_hunk, "Previous hunk" }, + ["]"] = { gitsigns.next_hunk, "Next hunk" }, + }, +} + +local objects = { + ["ih"] = { gitsigns.select_hunk, "Git hunk" }, +} + +local visual = { + ["ih"] = { gitsigns.select_hunk, "Git hunk" }, + + -- Only the actual command can make use of the visual selection... + ["g"] = { + name = "Git", + p = { ":Gitsigns preview_hunk", "Preview selection" }, + r = { ":Gitsigns reset_hunk", "Restore selection" }, + s = { ":Gitsigns stage_hunk", "Stage selection" }, + u = { ":Gitsigns undo_stage_hunk", "Undo stage selection" }, + }, +} + +wk.register(keys, { buffer = bufnr }) +wk.register(objects, { buffer = bufnr, mode = "o" }) +wk.register(visual, { buffer = bufnr, mode = "x" }) diff --git a/home/vim/plugin/settings/git.vim b/home/vim/plugin/settings/git.vim deleted file mode 100644 index 0deba6a..0000000 --- a/home/vim/plugin/settings/git.vim +++ /dev/null @@ -1,66 +0,0 @@ -lua << EOF -local gitsigns = require('gitsigns') - -gitsigns.setup({ - -- I dislike the full-green sign column when this happens - attach_to_untracked = false, - - current_line_blame_opts = { - -- Show the blame quickly - delay = 100, - }, - - on_attach = function(bufnr) - local wk = require("which-key") - - local keys = { - -- Navigation - ["[c"] = { "&diff ? '[c' : 'Gitsigns prev_hunk'", "Previous hunk/diff", expr = true }, - ["]c"] = { "&diff ? ']c' : 'Gitsigns next_hunk'", "Next hunk/diff", expr = true }, - - - -- Commands - ["g"] = { - name = "Git", - -- Actions - b = { gitsigns.toggle_current_line_blame, "Toggle blame virtual text" }, - d = { gitsigns.diffthis, "Diff buffer" }, - D = { function() gitsigns.diffthis("~") end, "Diff buffer against last commit" }, - g = { "Git", "Git status" }, - h = { gitsigns.toggle_deleted, "Show deleted hunks" }, - L = { ":spT:Gllog --follow -- %:p", "Current buffer log" }, - m = { "(git-messenger)", "Current line blame" }, - p = { gitsigns.preview_hunk, "Preview hunk" }, - r = { gitsigns.reset_hunk, "Restore hunk" }, - R = { gitsigns.reset_buffer, "Restore buffer" }, - s = { gitsigns.stage_hunk, "Stage hunk" }, - S = { gitsigns.stage_buffer, "Stage buffer" }, - u = { gitsigns.undo_stage_hunk, "Undo stage hunk" }, - ["["] = { gitsigns.prev_hunk, "Previous hunk" }, - ["]"] = { gitsigns.next_hunk, "Next hunk" }, - }, - } - - local objects = { - ["ih"] = { gitsigns.select_hunk, "Git hunk" }, - } - - local visual = { - ["ih"] = { gitsigns.select_hunk, "Git hunk" }, - - -- Only the actual command can make use of the visual selection... - ["g"] = { - name = "Git", - p = { ":Gitsigns preview_hunk", "Preview selection" }, - r = { ":Gitsigns reset_hunk", "Restore selection" }, - s = { ":Gitsigns stage_hunk", "Stage selection" }, - u = { ":Gitsigns undo_stage_hunk", "Undo stage selection" }, - }, - } - - wk.register(keys, { buffer = bufnr }) - wk.register(objects, { buffer = bufnr, mode = "o" }) - wk.register(visual, { buffer = bufnr, mode = "x" }) - end, -}) -EOF diff --git a/home/vim/plugin/settings/lsp-lines.lua b/home/vim/plugin/settings/lsp-lines.lua new file mode 100644 index 0000000..9c79818 --- /dev/null +++ b/home/vim/plugin/settings/lsp-lines.lua @@ -0,0 +1,3 @@ +local lsp_lines = require("lsp_lines") + +lsp_lines.setup() diff --git a/home/vim/plugin/settings/lspconfig.vim b/home/vim/plugin/settings/lspconfig.lua similarity index 55% rename from home/vim/plugin/settings/lspconfig.vim rename to home/vim/plugin/settings/lspconfig.lua index dc706cc..794a765 100644 --- a/home/vim/plugin/settings/lspconfig.vim +++ b/home/vim/plugin/settings/lspconfig.lua @@ -1,11 +1,25 @@ -lua << EOF local lspconfig = require("lspconfig") local lsp = require("ambroisie.lsp") local utils = require("ambroisie.utils") +-- Diagnostics +vim.diagnostic.config({ + -- Disable virtual test next to affected regions + virtual_text = false, + -- Also disable virtual diagnostics under the affected regions + virtual_lines = false, + -- Show diagnostics signs + signs = true, + -- Underline offending regions + underline = true, + -- Do not bother me in the middle of insertion + update_in_insert = false, + -- Show highest severity first + severity_sort = true, +}) + -- Inform servers we are able to do completion, snippets, etc... -local capabilities = vim.lsp.protocol.make_client_capabilities() -capabilities = require("cmp_nvim_lsp").update_capabilities(capabilities) +local capabilities = require("cmp_nvim_lsp").default_capabilities() -- C/C++ if utils.is_executable("clangd") then @@ -16,6 +30,13 @@ if utils.is_executable("clangd") then end -- Nix +if utils.is_executable("nil") then + lspconfig.nil_ls.setup({ + capabilities = capabilities, + on_attach = lsp.on_attach, + }) +end + if utils.is_executable("rnix-lsp") then lspconfig.rnix.setup({ capabilities = capabilities, @@ -38,4 +59,3 @@ if utils.is_executable("rust-analyzer") then on_attach = lsp.on_attach, }) end -EOF diff --git a/home/vim/plugin/settings/lualine.vim b/home/vim/plugin/settings/lualine.lua similarity index 97% rename from home/vim/plugin/settings/lualine.vim rename to home/vim/plugin/settings/lualine.lua index 0273c78..fdaccda 100644 --- a/home/vim/plugin/settings/lualine.vim +++ b/home/vim/plugin/settings/lualine.lua @@ -1,4 +1,3 @@ -lua << EOF local lualine = require("lualine") local utils = require("ambroisie.utils") @@ -31,7 +30,7 @@ lualine.setup({ { "mode" }, }, lualine_b = { - { "branch" }, + { "FugitiveHead" }, { "filename", symbols = { readonly = "🔒" } }, }, lualine_c = { @@ -60,4 +59,3 @@ lualine.setup({ "quickfix", }, }) -EOF diff --git a/home/vim/plugin/settings/luasnip.lua b/home/vim/plugin/settings/luasnip.lua new file mode 100644 index 0000000..80309d7 --- /dev/null +++ b/home/vim/plugin/settings/luasnip.lua @@ -0,0 +1 @@ +require("luasnip.loaders.from_vscode").lazy_load() diff --git a/home/vim/plugin/settings/luasnip.vim b/home/vim/plugin/settings/luasnip.vim deleted file mode 100644 index 9527d22..0000000 --- a/home/vim/plugin/settings/luasnip.vim +++ /dev/null @@ -1,3 +0,0 @@ -lua << EOF -require("luasnip.loaders.from_vscode").load() -EOF diff --git a/home/vim/plugin/settings/notify.lua b/home/vim/plugin/settings/notify.lua new file mode 100644 index 0000000..b68c90f --- /dev/null +++ b/home/vim/plugin/settings/notify.lua @@ -0,0 +1,14 @@ +local notify = require("notify") + +notify.setup({ + icons = { + DEBUG = "D", + ERROR = "E", + INFO = "I", + TRACE = "T", + WARN = "W", + }, + stages = "slide", +}) + +vim.notify = notify diff --git a/home/vim/plugin/settings/notify.vim b/home/vim/plugin/settings/notify.vim deleted file mode 100644 index d60927f..0000000 --- a/home/vim/plugin/settings/notify.vim +++ /dev/null @@ -1,9 +0,0 @@ -lua << EOF -local notify = require("notify") - -notify.setup({ - stages = "slide", -}) - -vim.notify = notify -EOF diff --git a/home/vim/plugin/settings/null-ls.vim b/home/vim/plugin/settings/null-ls.lua similarity index 80% rename from home/vim/plugin/settings/null-ls.vim rename to home/vim/plugin/settings/null-ls.lua index bec8124..0eaa55c 100644 --- a/home/vim/plugin/settings/null-ls.vim +++ b/home/vim/plugin/settings/null-ls.lua @@ -1,4 +1,3 @@ -lua << EOF local null_ls = require("null-ls") local lsp = require("ambroisie.lsp") local utils = require("ambroisie.utils") @@ -7,6 +6,18 @@ null_ls.setup({ on_attach = lsp.on_attach, }) +-- Bazel +null_ls.register({ + null_ls.builtins.diagnostics.buildifier.with({ + -- Only used if available + condition = utils.is_executable_condition("buildifier"), + }), + null_ls.builtins.formatting.buildifier.with({ + -- Only used if available + condition = utils.is_executable_condition("buildifier"), + }), +}) + -- C, C++ null_ls.register({ null_ls.builtins.formatting.clang_format.with({ @@ -30,7 +41,9 @@ null_ls.register({ null_ls.builtins.formatting.nixpkgs_fmt.with({ -- Only used if available, but prefer rnix if available condition = function() - return utils.is_executable("nixpkgs-fmt") and not utils.is_executable("rnix-lsp") + return utils.is_executable("nixpkgs-fmt") + and not utils.is_executable("rnix-lsp") + and not utils.is_executable("nil") end, }), }) @@ -38,8 +51,14 @@ null_ls.register({ -- Python null_ls.register({ null_ls.builtins.diagnostics.flake8.with({ + -- Only used if available, but prefer pflake8 if available + condition = function() + return utils.is_executable("flake8") and not utils.is_executable("pflake8") + end, + }), + null_ls.builtins.diagnostics.pyproject_flake8.with({ -- Only used if available - condition = utils.is_executable_condition("flake8"), + condition = utils.is_executable_condition("pflake8"), }), null_ls.builtins.diagnostics.mypy.with({ -- Only used if available @@ -60,7 +79,6 @@ null_ls.register({ }), }) - -- Shell (non-POSIX) null_ls.register({ null_ls.builtins.code_actions.shellcheck.with({ @@ -93,7 +111,7 @@ null_ls.register({ -- Shell (POSIX) null_ls.register({ null_ls.builtins.code_actions.shellcheck.with({ - -- Restrict to POSIX sh + -- Restrict to POSIX sh filetypes = { "sh" }, -- Only used if available condition = utils.is_executable_condition("shellcheck"), @@ -112,8 +130,9 @@ null_ls.register({ -- 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"), }), }) -EOF diff --git a/home/vim/plugin/settings/pandoc.vim b/home/vim/plugin/settings/pandoc.vim deleted file mode 100644 index 71b750c..0000000 --- a/home/vim/plugin/settings/pandoc.vim +++ /dev/null @@ -1,20 +0,0 @@ -" Which code-block languages should I expect to be high-lighted. -let g:pandoc#syntax#codeblocks#embeds#langs=[ - \ "bash=sh", - \ "c", - \ "cpp", - \ "go", - \ "haskell", - \ "python", - \ "rust", - \ "sh", - \ "vim", - \ "yaml", - \ "tex", - \ "toml", - \ "perl", - \ "json", - \ "latex=tex", - \ "make", - \ "makefile=make", - \ ] diff --git a/home/vim/plugin/settings/ssh.lua b/home/vim/plugin/settings/ssh.lua new file mode 100644 index 0000000..992a707 --- /dev/null +++ b/home/vim/plugin/settings/ssh.lua @@ -0,0 +1,17 @@ +if not require("ambroisie.utils").is_ssh() then + return +end + +local function copy(lines, _) + require("osc52").copy(table.concat(lines, "\n")) +end + +local function paste() + return { vim.fn.split(vim.fn.getreg(""), "\n"), vim.fn.getregtype("") } +end + +vim.g.clipboard = { + name = "osc52", + copy = { ["+"] = copy, ["*"] = copy }, + paste = { ["+"] = paste, ["*"] = paste }, +} diff --git a/home/vim/plugin/settings/surround.lua b/home/vim/plugin/settings/surround.lua new file mode 100644 index 0000000..3585a12 --- /dev/null +++ b/home/vim/plugin/settings/surround.lua @@ -0,0 +1,3 @@ +require("nvim-surround").setup({ + -- No configuration at the moment +}) diff --git a/home/vim/plugin/settings/telescope.vim b/home/vim/plugin/settings/telescope.lua similarity index 60% rename from home/vim/plugin/settings/telescope.vim rename to home/vim/plugin/settings/telescope.lua index 084aeb4..ed8ebc7 100644 --- a/home/vim/plugin/settings/telescope.vim +++ b/home/vim/plugin/settings/telescope.lua @@ -1,7 +1,15 @@ -lua << EOF local telescope = require("telescope") telescope.setup({ + defaults = { + mappings = { + i = { + [""] = "which_key", + -- I want the normal readline mappings rather than scrolling + [""] = false, + }, + }, + }, extensions = { fzf = { fuzzy = true, @@ -15,4 +23,3 @@ telescope.setup({ telescope.load_extension("fzf") telescope.load_extension("lsp_handlers") telescope.load_extension("notify") -EOF diff --git a/home/vim/plugin/settings/tree-sitter.vim b/home/vim/plugin/settings/tree-sitter.lua similarity index 99% rename from home/vim/plugin/settings/tree-sitter.vim rename to home/vim/plugin/settings/tree-sitter.lua index 1204185..0d84abd 100644 --- a/home/vim/plugin/settings/tree-sitter.vim +++ b/home/vim/plugin/settings/tree-sitter.lua @@ -1,4 +1,3 @@ -lua << EOF local ts_config = require("nvim-treesitter.configs") ts_config.setup({ highlight = { @@ -55,4 +54,3 @@ ts_config.setup({ }, }, }) -EOF diff --git a/home/vim/plugin/settings/which-key.vim b/home/vim/plugin/settings/which-key.lua similarity index 74% rename from home/vim/plugin/settings/which-key.vim rename to home/vim/plugin/settings/which-key.lua index 505bdc4..2edfd70 100644 --- a/home/vim/plugin/settings/which-key.vim +++ b/home/vim/plugin/settings/which-key.lua @@ -1,4 +1,2 @@ -lua << EOF local wk = require("which-key") wk.setup() -EOF diff --git a/home/vim/plugin/signtoggle.lua b/home/vim/plugin/signtoggle.lua new file mode 100644 index 0000000..d6a26e2 --- /dev/null +++ b/home/vim/plugin/signtoggle.lua @@ -0,0 +1,20 @@ +local signtoggle = vim.api.nvim_create_augroup("signtoggle", { clear = true }) + +-- Only show sign column for the currently focused buffer +vim.api.nvim_create_autocmd({ "BufEnter", "FocusGained", "WinEnter" }, { + pattern = "*", + group = signtoggle, + command = "setlocal signcolumn=yes", +}) +vim.api.nvim_create_autocmd({ "BufLeave", "FocusLost", "WinLeave" }, { + pattern = "*", + group = signtoggle, + command = "setlocal signcolumn=yes", +}) + +-- Never show the sign column in a terminal buffer +vim.api.nvim_create_autocmd({ "TermOpen" }, { + pattern = "*", + group = signtoggle, + command = "setlocal signcolumn=no", +}) diff --git a/home/vim/plugin/signtoggle.vim b/home/vim/plugin/signtoggle.vim deleted file mode 100644 index c2f0183..0000000 --- a/home/vim/plugin/signtoggle.vim +++ /dev/null @@ -1,8 +0,0 @@ -augroup signtoggle - autocmd! - " Only show the sign column for the current focused buffer - autocmd BufEnter,FocusGained,WinEnter * set signcolumn=yes - autocmd BufLeave,FocusLost,WinLeave * set signcolumn=no - " Disable the sign column in terminal - autocmd TermOpen * setlocal signcolumn=no -augroup END diff --git a/home/wm/cursor/default.nix b/home/wm/cursor/default.nix new file mode 100644 index 0000000..9426232 --- /dev/null +++ b/home/wm/cursor/default.nix @@ -0,0 +1,23 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.my.home.wm.cursor; + + cfg_x = config.my.home.x; + cfg_gtk = config.my.home.gtk; +in +{ + config = lib.mkIf cfg.enable { + home.pointerCursor = { + package = pkgs.ambroisie.vimix-cursors; + name = "Vimix-cursors"; + + x11 = { + inherit (cfg_x) enable; + }; + + gtk = { + inherit (cfg_gtk) enable; + }; + }; + }; +} diff --git a/home/wm/default.nix b/home/wm/default.nix index 1d5a371..6a615e5 100644 --- a/home/wm/default.nix +++ b/home/wm/default.nix @@ -10,6 +10,7 @@ let in { imports = [ + ./cursor ./dunst ./i3 ./i3bar @@ -25,6 +26,10 @@ in description = "Which window manager to use for home session"; }; + cursor = { + enable = mkRelatedOption "dunst configuration" [ "i3" ]; + }; + dunst = { enable = mkRelatedOption "dunst configuration" [ "i3" ]; }; @@ -42,8 +47,8 @@ in command = mkOption { type = types.str; - default = "${pkgs.i3lock}/bin/i3lock -n -c 000000"; - example = "\${pkgs.i3lock}/bin/i3lock -n -i lock.png"; + default = "${lib.getExe pkgs.i3lock} -n -c 000000"; + example = "\${lib.getExe pkgs.i3lock} -n -i lock.png"; description = "Locker command to run"; }; diff --git a/home/wm/i3/default.nix b/home/wm/i3/default.nix index c92285f..d1dbe2c 100644 --- a/home/wm/i3/default.nix +++ b/home/wm/i3/default.nix @@ -27,13 +27,13 @@ let genMovementBindings = f: addVimKeyBindings (lib.my.genAttrs' movementKeys f); # Used in multiple scripts to show messages through keybindings - notify-send = "${pkgs.libnotify}/bin/notify-send"; + notify-send = lib.getExe pkgs.libnotify; # Screen backlight management - changeBacklight = "${pkgs.ambroisie.change-backlight}/bin/change-backlight"; + changeBacklight = lib.getExe pkgs.ambroisie.change-backlight; # Audio and volume management - changeAudio = "${pkgs.ambroisie.change-audio}/bin/change-audio"; + changeAudio = lib.getExe pkgs.ambroisie.change-audio; # Lock management toggleXautolock = @@ -61,8 +61,8 @@ in ambroisie.dragger # drag-and-drop from the CLI ambroisie.i3-get-window-criteria # little helper for i3 configuration arandr # Used by a mapping - pamixer # Used by a mapping playerctl # Used by a mapping + xdotool # Used by 'rofi-rbw', in a mapping ]; xsession.windowManager.i3 = { @@ -73,14 +73,12 @@ in bars = let - barConfigPath = - config.xdg.configFile."i3status-rust/config-top.toml".target; - i3status-rs = - "${config.programs.i3status-rust.package}/bin/i3status-rs"; + i3status-rs = lib.getExe config.programs.i3status-rust.package; in + assert [ "top" ] == lib.attrNames config.programs.i3status-rust.bars; [ { - statusCommand = "${i3status-rs} ${barConfigPath}"; + statusCommand = "${i3status-rs} config-top.toml"; trayOutput = "primary"; position = "top"; @@ -175,6 +173,10 @@ in "${modifier}+Control+space" = "floating toggle"; # Change focus between tiling/floating "${modifier}+space" = "focus mode_toggle"; + # Center floating window + "${modifier}+c" = "move absolute position center"; + # Center floating window + "${modifier}+Shift+s" = "sticky toggle"; } { # Focus parent container @@ -187,11 +189,12 @@ in "${modifier}+d" = "exec rofi -show drun -disable-history"; "${modifier}+Shift+d" = "exec rofi -show run -disable-history"; "${modifier}+p" = "exec --no-startup-id flameshot gui"; + "${modifier}+Ctrl+p" = "exec ${lib.getExe pkgs.rofi-rbw}"; "${modifier}+Shift+p" = "exec rofi -show emoji"; "${modifier}+b" = let inherit (config.my.home.bluetooth) enable; - prog = "${pkgs.ambroisie.rofi-bluetooth}/bin/rofi-bluetooth"; + prog = lib.getExe pkgs.rofi-bluetooth; in lib.mkIf enable "exec ${prog}"; }) @@ -370,6 +373,16 @@ in # FIXME # { commdand; always; notification; } ]; + + window = { + commands = [ + # Make htop window bigger + { + criteria = { title = "^htop$"; }; + command = "resize set 80 ppt 80 ppt, move position center"; + } + ]; + }; }; }; }; diff --git a/home/wm/i3bar/default.nix b/home/wm/i3bar/default.nix index a330134..05b0f50 100644 --- a/home/wm/i3bar/default.nix +++ b/home/wm/i3bar/default.nix @@ -5,7 +5,7 @@ in { config = lib.mkIf cfg.enable { home.packages = with pkgs; [ - alsaUtils # Used by `sound` block + alsa-utils # Used by `sound` block lm_sensors # Used by `temperature` block font-awesome # Icon font ]; @@ -20,28 +20,52 @@ in blocks = builtins.filter (attr: attr != { }) [ { block = "music"; - buttons = [ "prev" "play" "next" ]; - max_width = 50; - dynamic_width = true; - hide_when_empty = true; + # This format seems to remove the block when not playing, somehow + format = "{ $icon $combo.str(max_w:50,rot_interval:0.5) $prev $play $next |}"; + click = [ + { + button = "play"; + action = "music_play"; + } + { + button = "prev"; + action = "music_prev"; + } + { + button = "next"; + action = "music_next"; + } + ]; } (lib.optionalAttrs config.my.home.bluetooth.enable { block = "bluetooth"; mac = "4C:87:5D:06:40:D9"; - hide_disconnected = true; - format = "Boson {percentage}"; + format = " $icon Boson{ $percentage|} "; + disconnected_format = ""; + }) + (lib.optionalAttrs config.my.home.bluetooth.enable { + block = "bluetooth"; + mac = "38:18:4C:BE:8E:97"; + format = " $icon Muon{ $percentage|} "; + disconnected_format = ""; }) (lib.optionalAttrs config.my.home.bluetooth.enable { block = "bluetooth"; mac = "94:DB:56:00:EE:93"; - hide_disconnected = true; - format = "Protons {percentage}"; + format = " $icon Protons{ $percentage|} "; + disconnected_format = ""; + }) + (lib.optionalAttrs config.my.home.bluetooth.enable { + block = "bluetooth"; + mac = "88:C9:E8:6B:B7:55"; + format = " $icon Quarks{ $percentage|} "; + disconnected_format = ""; }) (lib.optionalAttrs config.my.home.bluetooth.enable { block = "bluetooth"; mac = "F7:78:BA:76:52:F7"; - hide_disconnected = true; - format = "MX Ergo {percentage}"; + format = " $icon MX Ergo{ $percentage|} "; + disconnected_format = ""; }) { block = "cpu"; @@ -51,7 +75,7 @@ in } { block = "net"; - format = "{ssid} {ip} {signal_strength}"; + format = " $icon{| $ssid|} $ip{| $signal_strength|} "; } { block = "backlight"; @@ -59,17 +83,19 @@ in } { block = "battery"; - format = "{percentage} ({time})"; - full_format = "{percentage}"; + format = " $icon $percentage{ ($time)|} "; + empty_format = " $icon $percentage{ ($time)|} "; + not_charging_format = " $icon $percentage "; + full_format = " $icon $percentage "; } { block = "temperature"; - collapsed = false; + format_alt = " $icon "; } { block = "sound"; device_kind = "source"; # Microphone status - format = ""; # Only show icon + format = " $icon "; } { block = "sound"; @@ -77,7 +103,8 @@ in } { block = "time"; - format = "%F %T"; + format = " $icon $timestamp.datetime(f:'%F %T') "; + interval = 5; } ]; }; diff --git a/home/wm/screen-lock/default.nix b/home/wm/screen-lock/default.nix index 95060b8..3b2ead6 100644 --- a/home/wm/screen-lock/default.nix +++ b/home/wm/screen-lock/default.nix @@ -5,7 +5,7 @@ let notficationCmd = let duration = toString (cfg.notify.delay * 1000); - notifyCmd = "${pkgs.libnotify}/bin/notify-send -u critical -t ${duration}"; + notifyCmd = "${lib.getExe pkgs.libnotify} -u critical -t ${duration}"; in # Needs to be surrounded by quotes for systemd to launch it correctly ''"${notifyCmd} -- 'Locking in ${toString cfg.notify.delay} seconds'"''; diff --git a/home/x/cursor/default.nix b/home/x/cursor/default.nix deleted file mode 100644 index 4762199..0000000 --- a/home/x/cursor/default.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ config, lib, pkgs, ... }: -let - cfg = config.my.home.x; -in -{ - config = lib.mkIf cfg.enable { - xsession.pointerCursor = { - package = pkgs.ambroisie.vimix-cursors; - name = "Vimix-cursors"; - }; - }; -} diff --git a/home/x/default.nix b/home/x/default.nix index ac66a50..0312bc4 100644 --- a/home/x/default.nix +++ b/home/x/default.nix @@ -4,7 +4,6 @@ let in { imports = [ - ./cursor ./keyboard ]; diff --git a/home/xdg/default.nix b/home/xdg/default.nix index 1aa69ac..3fd8dc9 100644 --- a/home/xdg/default.nix +++ b/home/xdg/default.nix @@ -3,8 +3,8 @@ let cfg = config.my.home.xdg; in { - options.my.home.xdg = with lib.my; { - enable = mkDisableOption "XDG configuration"; + options.my.home.xdg = with lib; { + enable = my.mkDisableOption "XDG configuration"; }; config.xdg = lib.mkIf cfg.enable { @@ -38,6 +38,7 @@ in # I want a tidier home config.home.sessionVariables = with config.xdg; lib.mkIf cfg.enable { + ANDROID_HOME = "${dataHome}/android"; CARGO_HOME = "${dataHome}/cargo"; DOCKER_CONFIG = "${configHome}/docker"; GDBHISTFILE = "${dataHome}/gdb/gdb_history"; @@ -45,6 +46,8 @@ in INPUTRC = "${configHome}/readline/inputrc"; LESSHISTFILE = "${dataHome}/less/history"; LESSKEY = "${configHome}/less/lesskey"; - WGETRC = "${configHome}/wgetrc"; + PSQL_HISTORY = "${dataHome}/psql_history"; + REDISCLI_HISTFILE = "${dataHome}/redis/rediscli_history"; + XCOMPOSECACHE = "${dataHome}/X11/xcompose"; }; } diff --git a/home/zsh/completion-styles.zsh b/home/zsh/completion-styles.zsh index a0181a5..156bc2c 100644 --- a/home/zsh/completion-styles.zsh +++ b/home/zsh/completion-styles.zsh @@ -8,6 +8,8 @@ zstyle ':completion:*' menu select zstyle ':completion:*' group-name '' # Keep directories and files separated zstyle ':completion:*' list-dirs-first true +# Expand '//' to '/' +zstyle ':completion:*' squeeze-slashes true # Add colors to processes for kill completion zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#)*=0=01;31' diff --git a/home/zsh/default.nix b/home/zsh/default.nix index 27ea8bc..4cadb57 100644 --- a/home/zsh/default.nix +++ b/home/zsh/default.nix @@ -1,10 +1,20 @@ { 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.my; { - enable = mkDisableOption "zsh configuration"; + options.my.home.zsh = with lib; { + enable = my.mkDisableOption "zsh configuration"; + + launchTmux = mkEnableOption "auto launch tmux at shell start"; }; config = lib.mkIf cfg.enable { @@ -14,20 +24,21 @@ in programs.zsh = { enable = true; - dotDir = ".config/zsh"; # Don't clutter $HOME + dotDir = "${relativeXdgConfig}/zsh"; # Don't clutter $HOME enableCompletion = true; history = { size = 500000; save = 500000; - extended = false; + extended = true; + expireDuplicatesFirst = true; ignoreSpace = true; ignoreDups = true; share = false; path = "${config.xdg.dataHome}/zsh/zsh_history"; }; - plugins = with pkgs; [ + plugins = [ { name = "fast-syntax-highlighting"; file = "share/zsh/site-functions/fast-syntax-highlighting.plugin.zsh"; @@ -35,12 +46,8 @@ in } { name = "agkozak-zsh-prompt"; - src = fetchFromGitHub { - owner = "agkozak"; - repo = "agkozak-zsh-prompt"; - rev = "v3.9.0"; - sha256 = "sha256-VTRL+8ph2eI7iPht15epkLggAgtLGxB3DORFTW5GrhE="; - }; + file = "share/zsh/site-functions/agkozak-zsh-prompt.plugin.zsh"; + src = pkgs.agkozak-zsh-prompt; } ]; @@ -48,20 +55,27 @@ in defaultKeymap = "emacs"; # Make those happen early to avoid doing double the work - initExtraFirst = - lib.optionalString config.my.home.tmux.enable '' - # Launch tmux unless already inside one - if [ -z "$TMUX" ]; then - exec tmux new-session - fi - '' - ; + initExtraFirst = '' + ${ + lib.optionalString cfg.launchTmux '' + # Launch tmux unless already inside one + if [ -z "$TMUX" ]; then + exec tmux new-session + fi + '' + } + ''; - initExtra = lib.concatMapStrings builtins.readFile [ - ./completion-styles.zsh - ./extra-mappings.zsh - ./options.zsh - ]; + initExtra = '' + 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 + ''; localVariables = { # I like having the full path @@ -74,26 +88,8 @@ in AGKOZAK_LEFT_PROMPT_ONLY = 1; }; - shellAliases = { - # Sometime `gpg-agent` errors out... - reset-agent = "gpg-connect-agent updatestartuptty /bye"; - }; - - # Enable VTE integration when using one of the affected shells - enableVteIntegration = - builtins.any (name: config.my.home.terminal.program == name) [ - "termite" - ]; - }; - - # Fuzzy-wuzzy - programs.fzf = { - enable = true; - enableZshIntegration = true; - }; - - programs.dircolors = { - enable = true; + # Enable VTE integration + enableVteIntegration = true; }; }; } diff --git a/home/zsh/extra-mappings.zsh b/home/zsh/extra-mappings.zsh index 8f7cc4a..3456e13 100644 --- a/home/zsh/extra-mappings.zsh +++ b/home/zsh/extra-mappings.zsh @@ -1,8 +1,7 @@ -# Fix delete key not working -bindkey "\e[3~" delete-char +# shellcheck disable=2154 # Fix Ctrl+u killing from the cursor instead of the whole line -bindkey \^U backward-kill-line +bindkey '^u' backward-kill-line # Use Ctrl+x-(Ctrl+)e to edit the current command line in VISUAL/EDITOR autoload -U edit-command-line @@ -10,5 +9,124 @@ zle -N edit-command-line bindkey '^xe' edit-command-line bindkey '^x^e' edit-command-line +# The expression: (( ${+terminfo} )) should never fail, but does if we +# don't have a tty, perhaps due to a bug in the zsh/terminfo module. +if ! { [ "$TERM" != emacs ] && (( ${+terminfo} )) 2>/dev/null; }; then + return +fi + +# Make sure that the terminal is in application mode when zle is active, since +# only then values from $terminfo are valid +if (( ${+terminfo[smkx]} )) && (( ${+terminfo[rmkx]} )); then + autoload -Uz add-zle-hook-widget + + zle_application_mode_start() { echoti smkx; } + zle_application_mode_stop() { echoti rmkx; } + + add-zle-hook-widget -Uz zle-line-init zle_application_mode_start + add-zle-hook-widget -Uz zle-line-finish zle_application_mode_stop +fi + + +# Fix delete key not working +if [ -n "${terminfo[kdch1]}" ]; then + bindkey -M emacs "${terminfo[kdch1]}" delete-char + bindkey -M viins "${terminfo[kdch1]}" delete-char + bindkey -M vicmd "${terminfo[kdch1]}" delete-char +else + bindkey -M emacs "^[[3~" delete-char + bindkey -M viins "^[[3~" delete-char + bindkey -M vicmd "^[[3~" delete-char + + bindkey -M emacs "^[3;5~" delete-char + bindkey -M viins "^[3;5~" delete-char + bindkey -M vicmd "^[3;5~" delete-char +fi + +# Ctrl-Delete to delete a whole word forward +if [ -n "${terminfo[kdl1]}" ]; then + bindkey -M emacs "${terminfo[kdl1]}" kill-word + bindkey -M viins "${terminfo[kdl1]}" kill-word + bindkey -M vicmd "${terminfo[kdl1]}" kill-word +else + bindkey -M emacs '^[[3;5~' kill-word + bindkey -M viins '^[[3;5~' kill-word + bindkey -M vicmd '^[[3;5~' kill-word +fi + # Enable Shift-Tab to go backwards in completion list -bindkey '^[[Z' reverse-menu-complete +if [ -n "${terminfo[kcbt]}" ]; then + bindkey -M emacs "${terminfo[kcbt]}" reverse-menu-complete + bindkey -M viins "${terminfo[kcbt]}" reverse-menu-complete + bindkey -M vicmd "${terminfo[kcbt]}" reverse-menu-complete +else + bindkey -M emacs '^[[Z' reverse-menu-complete + bindkey -M viins '^[[Z' reverse-menu-complete + bindkey -M vicmd '^[[Z' reverse-menu-complete +fi + +# Ctrl-Left moves backward one word +if [ -n "${terminfo[kLFT5]}" ]; then + bindkey -M emacs "${terminfo[kLFT5]}" backward-word + bindkey -M viins "${terminfo[kLFT5]}" backward-word + bindkey -M vicmd "${terminfo[kLFT5]}" backward-word +else + bindkey -M emacs '^[[1;5D' backward-word + bindkey -M viins '^[[1;5D' backward-word + bindkey -M vicmd '^[[1;5D' backward-word +fi + +# Ctrl-Right moves forward one word +if [ -n "${terminfo[kRIT5]}" ]; then + bindkey -M emacs "${terminfo[kRIT5]}" forward-word + bindkey -M viins "${terminfo[kRIT5]}" forward-word + bindkey -M vicmd "${terminfo[kRIT5]}" forward-word +else + bindkey -M emacs '^[[1;5C' forward-word + bindkey -M viins '^[[1;5C' forward-word + bindkey -M vicmd '^[[1;5C' forward-word +fi + +# PageUp goes backwards in history +if [ -n "${terminfo[kpp]}" ]; then + bindkey -M emacs "${terminfo[kpp]}" up-line-or-history + bindkey -M viins "${terminfo[kpp]}" up-line-or-history + bindkey -M vicmd "${terminfo[kpp]}" up-line-or-history +else + bindkey -M emacs "^[[5~" up-line-or-history + bindkey -M viins "^[[5~" up-line-or-history + bindkey -M vicmd "^[[5~" up-line-or-history +fi + +# PageDown goes forward in history +if [ -n "${terminfo[knp]}" ]; then + bindkey -M emacs "${terminfo[knp]}" down-line-or-history + bindkey -M viins "${terminfo[knp]}" down-line-or-history + bindkey -M vicmd "${terminfo[knp]}" down-line-or-history +else + bindkey -M emacs "^[[6~" down-line-or-history + bindkey -M viins "^[[6~" down-line-or-history + bindkey -M vicmd "^[[6~" down-line-or-history +fi + +# Home goes to the beginning of the line +if [ -n "${terminfo[khome]}" ]; then + bindkey -M emacs "${terminfo[khome]}" beginning-of-line + bindkey -M viins "${terminfo[khome]}" beginning-of-line + bindkey -M vicmd "${terminfo[khome]}" beginning-of-line +else + bindkey -M emacs "^[[1~" beginning-of-line + bindkey -M viins "^[[1~" beginning-of-line + bindkey -M vicmd "^[[1~" beginning-of-line +fi + +# End goes to the end of the line +if [ -n "${terminfo[kend]}" ]; then + bindkey -M emacs "${terminfo[kend]}" end-of-line + bindkey -M viins "${terminfo[kend]}" end-of-line + bindkey -M vicmd "${terminfo[kend]}" end-of-line +else + bindkey -M emacs "^[[4~" end-of-line + bindkey -M viins "^[[4~" end-of-line + bindkey -M vicmd "^[[4~" end-of-line +fi diff --git a/home/zsh/options.zsh b/home/zsh/options.zsh index e1e31f4..82047ff 100644 --- a/home/zsh/options.zsh +++ b/home/zsh/options.zsh @@ -1,16 +1,18 @@ # Show an error when a globbing expansion doesn't find any match setopt nomatch # List on ambiguous completion and Insert first match immediately -setopt autolist menucomplete +setopt auto_list menu_complete # Use pushd when cd-ing around -setopt autopushd pushdminus pushdsilent +setopt auto_pushd pushd_minus pushd_silent # Use single quotes in string without the weird escape tricks -setopt rcquotes +setopt rc_quotes # Single word commands can resume an existing job -setopt autoresume +setopt auto_resume +# Show history expansion before running a command +setopt hist_verify # Append commands to history as they are exectuted setopt inc_append_history_time # Remove useless whitespace from commands setopt hist_reduce_blanks # Those options aren't wanted -unsetopt beep extendedglob notify +unsetopt beep extended_glob notify diff --git a/hosts/homes/ambroisie/default.nix b/hosts/homes/ambroisie/default.nix new file mode 100644 index 0000000..42ea5b8 --- /dev/null +++ b/hosts/homes/ambroisie/default.nix @@ -0,0 +1,5 @@ +# Default home-manager configuration +{ ... }: +{ + # Default configuration, nothing to do +} diff --git a/hosts/homes/ambroisie@ambroisie/default.nix b/hosts/homes/ambroisie@ambroisie/default.nix new file mode 100644 index 0000000..94efc09 --- /dev/null +++ b/hosts/homes/ambroisie@ambroisie/default.nix @@ -0,0 +1,17 @@ +# Google Cloudtop configuration +{ lib, pkgs, ... }: +{ + # Google specific configuration + home.homeDirectory = "/usr/local/google/home/ambroisie"; + + # Some tooling (e.g: SSH) need to use this library + home.sessionVariables = { + LD_PRELOAD = "/lib/x86_64-linux-gnu/libnss_cache.so.2\${LD_PRELOAD:+:}$LD_PRELOAD"; + }; + + systemd.user.sessionVariables = { + LD_PRELOAD = "/lib/x86_64-linux-gnu/libnss_cache.so.2\${LD_PRELOAD:+:}$LD_PRELOAD"; + }; + + programs.git.package = lib.mkForce pkgs.emptyDirectory; +} diff --git a/machines/aramis/boot.nix b/hosts/nixos/aramis/boot.nix similarity index 100% rename from machines/aramis/boot.nix rename to hosts/nixos/aramis/boot.nix diff --git a/machines/aramis/default.nix b/hosts/nixos/aramis/default.nix similarity index 89% rename from machines/aramis/default.nix rename to hosts/nixos/aramis/default.nix index e2211f4..c72fb11 100644 --- a/machines/aramis/default.nix +++ b/hosts/nixos/aramis/default.nix @@ -12,15 +12,13 @@ ./networking.nix ./profiles.nix ./programs.nix + ./secrets ./services.nix ./sound.nix ]; # Set your time zone. - time.timeZone = "Europe/Paris"; - - # Enable CUPS to print documents. - services.printing.enable = true; + time.timeZone = "Europe/London"; # This value determines the NixOS release from which the default # settings for stateful data, like file locations and database versions diff --git a/machines/aramis/hardware.nix b/hosts/nixos/aramis/hardware.nix similarity index 79% rename from machines/aramis/hardware.nix rename to hosts/nixos/aramis/hardware.nix index 3ca556c..c66b426 100644 --- a/machines/aramis/hardware.nix +++ b/hosts/nixos/aramis/hardware.nix @@ -22,13 +22,19 @@ powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; - hardware = { - cpu.intel.updateMicrocode = true; + my.hardware = { + firmware = { + cpuFlavor = "intel"; + }; + }; + hardware = { trackpoint = { enable = true; emulateWheel = true; # Holding middle buttons allows scrolling + + device = "TPPS/2 Elan TrackPoint"; # Use the correct device name }; }; } diff --git a/machines/aramis/home.nix b/hosts/nixos/aramis/home.nix similarity index 78% rename from machines/aramis/home.nix rename to hosts/nixos/aramis/home.nix index 1c816a7..66a0892 100644 --- a/machines/aramis/home.nix +++ b/hosts/nixos/aramis/home.nix @@ -1,6 +1,10 @@ { pkgs, ... }: { my.home = { + # Use graphical pinentry + bitwarden.pinentry = "gtk2"; + # Ebook library + calibre.enable = true; # Some amount of social life discord.enable = true; # Image viewver @@ -13,18 +17,17 @@ gpg.pinentry = "gtk2"; # Machine specific packages packages.additionalPackages = with pkgs; [ + element-desktop # Matrix client jellyfin-media-player # Wraps the webui and mpv together pavucontrol # Audio mixer GUI - quasselClient # IRC client - teams # Work requires it... transgui # Transmission remote ]; # Minimal video player mpv.enable = true; # Network-Manager applet nm-applet.enable = true; - # Termite terminal - terminal.program = "termite"; + # Terminal + terminal.program = "alacritty"; # Zathura document viewer zathura.enable = true; }; diff --git a/machines/aramis/install.sh b/hosts/nixos/aramis/install.sh similarity index 100% rename from machines/aramis/install.sh rename to hosts/nixos/aramis/install.sh diff --git a/machines/aramis/networking.nix b/hosts/nixos/aramis/networking.nix similarity index 84% rename from machines/aramis/networking.nix rename to hosts/nixos/aramis/networking.nix index 2759e9c..fbf4c6b 100644 --- a/machines/aramis/networking.nix +++ b/hosts/nixos/aramis/networking.nix @@ -7,11 +7,6 @@ # Per-interface useDHCP will be mandatory in the future, so this generated config # replicates the default behaviour. useDHCP = false; - - interfaces = { - enp0s31f6.useDHCP = true; - wlp0s20f3.useDHCP = true; - }; }; my.hardware.networking = { diff --git a/machines/aramis/profiles.nix b/hosts/nixos/aramis/profiles.nix similarity index 81% rename from machines/aramis/profiles.nix rename to hosts/nixos/aramis/profiles.nix index 4d2ac7d..d86da5a 100644 --- a/machines/aramis/profiles.nix +++ b/hosts/nixos/aramis/profiles.nix @@ -9,6 +9,8 @@ gtk.enable = true; # Laptop specific configuration laptop.enable = true; + # Printers are hell, but so is the unability to print + printing.enable = true; # i3 configuration wm.windowManager = "i3"; # X configuration diff --git a/machines/aramis/programs.nix b/hosts/nixos/aramis/programs.nix similarity index 100% rename from machines/aramis/programs.nix rename to hosts/nixos/aramis/programs.nix diff --git a/hosts/nixos/aramis/secrets/default.nix b/hosts/nixos/aramis/secrets/default.nix new file mode 100644 index 0000000..c6f02dc --- /dev/null +++ b/hosts/nixos/aramis/secrets/default.nix @@ -0,0 +1,25 @@ +{ config, lib, ... }: + +{ + config.age = { + secrets = + let + toName = lib.removeSuffix ".age"; + userExists = u: builtins.hasAttr u config.users.users; + # Only set the user if it exists, to avoid warnings + userIfExists = u: if userExists u then u else "root"; + toSecret = name: { owner ? "root", ... }: { + file = ./. + "/${name}"; + owner = lib.mkDefault (userIfExists owner); + }; + convertSecrets = n: v: lib.nameValuePair (toName n) (toSecret n v); + secrets = import ./secrets.nix; + in + lib.mapAttrs' convertSecrets secrets; + + identityPaths = [ + # Due to being a laptop, this host does not itself have any SSH keys + "/home/ambroisie/.ssh/agenix" + ]; + }; +} diff --git a/hosts/nixos/aramis/secrets/secrets.nix b/hosts/nixos/aramis/secrets/secrets.nix new file mode 100644 index 0000000..ce159a5 --- /dev/null +++ b/hosts/nixos/aramis/secrets/secrets.nix @@ -0,0 +1,13 @@ +# Host-specific secrets +let + keys = import ../../../../keys; + + all = [ + # This host is a laptop, it does not have a host key + # Allow me to modify the secrets anywhere + keys.users.ambroisie + ]; +in +{ + "wireguard/private-key.age".publicKeys = all; +} diff --git a/modules/secrets/wireguard/aramis/private-key.age b/hosts/nixos/aramis/secrets/wireguard/private-key.age similarity index 100% rename from modules/secrets/wireguard/aramis/private-key.age rename to hosts/nixos/aramis/secrets/wireguard/private-key.age diff --git a/machines/aramis/services.nix b/hosts/nixos/aramis/services.nix similarity index 100% rename from machines/aramis/services.nix rename to hosts/nixos/aramis/services.nix diff --git a/machines/aramis/sound.nix b/hosts/nixos/aramis/sound.nix similarity index 100% rename from machines/aramis/sound.nix rename to hosts/nixos/aramis/sound.nix diff --git a/machines/porthos/boot.nix b/hosts/nixos/porthos/boot.nix similarity index 84% rename from machines/porthos/boot.nix rename to hosts/nixos/porthos/boot.nix index 3b56eb9..fbc5db7 100644 --- a/machines/porthos/boot.nix +++ b/hosts/nixos/porthos/boot.nix @@ -6,9 +6,8 @@ # Use the GRUB 2 boot loader. loader.grub = { enable = true; - version = 2; # Define on which hard drive you want to install Grub. - device = "/dev/sda"; + device = "/dev/disk/by-id/ata-HGST_HUS724020ALA640_PN2181P6J58M1P"; }; initrd = { diff --git a/machines/porthos/default.nix b/hosts/nixos/porthos/default.nix similarity index 96% rename from machines/porthos/default.nix rename to hosts/nixos/porthos/default.nix index abfc01a..326d1cd 100644 --- a/machines/porthos/default.nix +++ b/hosts/nixos/porthos/default.nix @@ -5,7 +5,9 @@ imports = [ ./boot.nix ./hardware.nix + ./home.nix ./networking.nix + ./secrets ./services.nix ./users.nix ]; diff --git a/machines/porthos/hardware.nix b/hosts/nixos/porthos/hardware.nix similarity index 100% rename from machines/porthos/hardware.nix rename to hosts/nixos/porthos/hardware.nix diff --git a/hosts/nixos/porthos/home.nix b/hosts/nixos/porthos/home.nix new file mode 100644 index 0000000..53d5d25 --- /dev/null +++ b/hosts/nixos/porthos/home.nix @@ -0,0 +1,7 @@ +{ ... }: +{ + my.home = { + # Always start a tmux session when opening a shell session + zsh.launchTmux = true; + }; +} diff --git a/machines/porthos/install.sh b/hosts/nixos/porthos/install.sh similarity index 95% rename from machines/porthos/install.sh rename to hosts/nixos/porthos/install.sh index 44ea787..de87aa7 100644 --- a/machines/porthos/install.sh +++ b/hosts/nixos/porthos/install.sh @@ -46,7 +46,7 @@ vim /mnt/etc/nixos/hardware-configuration.nix mkdir -p /mnt/home/ambroisie/git/nix/config cd /mnt/home/ambroisie/git/nix/config -nix-env -iA nixos.git nixos.nixFlakes nixos.git-crypt +nix-env -iA nixos.git nixos.nix nixos.git-crypt git clone . # Assuming you set up GPG key correctly git crypt unlock diff --git a/machines/porthos/networking.nix b/hosts/nixos/porthos/networking.nix similarity index 100% rename from machines/porthos/networking.nix rename to hosts/nixos/porthos/networking.nix diff --git a/modules/secrets/acme/dns-key.age b/hosts/nixos/porthos/secrets/acme/dns-key.age similarity index 100% rename from modules/secrets/acme/dns-key.age rename to hosts/nixos/porthos/secrets/acme/dns-key.age diff --git a/modules/secrets/backup/credentials.age b/hosts/nixos/porthos/secrets/backup/credentials.age similarity index 100% rename from modules/secrets/backup/credentials.age rename to hosts/nixos/porthos/secrets/backup/credentials.age diff --git a/modules/secrets/backup/password.age b/hosts/nixos/porthos/secrets/backup/password.age similarity index 100% rename from modules/secrets/backup/password.age rename to hosts/nixos/porthos/secrets/backup/password.age diff --git a/hosts/nixos/porthos/secrets/default.nix b/hosts/nixos/porthos/secrets/default.nix new file mode 100644 index 0000000..83af695 --- /dev/null +++ b/hosts/nixos/porthos/secrets/default.nix @@ -0,0 +1,20 @@ +{ config, lib, ... }: + +{ + config.age = { + secrets = + let + toName = lib.removeSuffix ".age"; + userExists = u: builtins.hasAttr u config.users.users; + # Only set the user if it exists, to avoid warnings + userIfExists = u: if userExists u then u else "root"; + toSecret = name: { owner ? "root", ... }: { + file = ./. + "/${name}"; + owner = lib.mkDefault (userIfExists owner); + }; + convertSecrets = n: v: lib.nameValuePair (toName n) (toSecret n v); + secrets = import ./secrets.nix; + in + lib.mapAttrs' convertSecrets secrets; + }; +} diff --git a/hosts/nixos/porthos/secrets/drone/gitea.age b/hosts/nixos/porthos/secrets/drone/gitea.age new file mode 100644 index 0000000..90ff83b --- /dev/null +++ b/hosts/nixos/porthos/secrets/drone/gitea.age @@ -0,0 +1,10 @@ +age-encryption.org/v1 +-> ssh-ed25519 jPowng 3HjtINU02yfyvpaoTtCG/G3cgymFvKWf3qf/grw/+24 +G+KnHtrt5A3U1ICTpSceoE+FJSj6hAb4mjp2DkfDWr0 +-> ssh-ed25519 cKojmg CXrsCxJxWNIhvvwYjZ1rrSYTwLNMR3kWdPk5ExHEfFA +OJi3tFcnpdGvxc8ETcGt4lbFJiUU+lR3AqN4Y8PItDk +-> p-grease 7 AQO{DHzj j$B&+ dc +Q7zhy6hOfkEh6XgYNHQrH3zma1BLxnEKDopPAOnBoPFRfi7c +--- ZsL5zf7/jJ6yPor9j1V0iV/bXxgAsxlXsxDYwCqrLSk +AO&z?;\1f*='!.VV=ιvzY"P ; )K0Bs}hR=O*M2o \ No newline at end of file diff --git a/modules/secrets/drone/secret.age b/hosts/nixos/porthos/secrets/drone/secret.age similarity index 100% rename from modules/secrets/drone/secret.age rename to hosts/nixos/porthos/secrets/drone/secret.age diff --git a/modules/secrets/drone/ssh/private-key.age b/hosts/nixos/porthos/secrets/drone/ssh/private-key.age similarity index 100% rename from modules/secrets/drone/ssh/private-key.age rename to hosts/nixos/porthos/secrets/drone/ssh/private-key.age diff --git a/hosts/nixos/porthos/secrets/gitea/mail-password.age b/hosts/nixos/porthos/secrets/gitea/mail-password.age new file mode 100644 index 0000000..915f8e9 --- /dev/null +++ b/hosts/nixos/porthos/secrets/gitea/mail-password.age @@ -0,0 +1,9 @@ +age-encryption.org/v1 +-> ssh-ed25519 jPowng BkIjie2KrwDLaZYYIguCs7TPA/wQy+YPguikuhfye0M +7viTA/EGYB/jRKQm6fFd86DMd4j+Jxsaw/xQ1T8ZKNo +-> ssh-ed25519 cKojmg t1Y8bZvPccNAX8vWQLTfCyOJIBXN515vyfFrEI2EVww +bJEjpIWrKeQrA/JfY7FRdB6hpHwR/aG4Vya1ChFNBKs +-> jK/-grease Oz.R ?;)G ], +AuHk9TcC9kl0dg8/L6UfHIk3e9fgGwSTJAJpVgInhok +--- 47z9lol5MtpX0IsO/0ggLDMcNVfl4lNNvoHUSwOU/18 +)gЪeu! - TYAM+GbMe@|A,&E!܆p=P=9P!Q|r \ No newline at end of file diff --git a/modules/secrets/lohr/secret.age b/hosts/nixos/porthos/secrets/lohr/secret.age similarity index 100% rename from modules/secrets/lohr/secret.age rename to hosts/nixos/porthos/secrets/lohr/secret.age diff --git a/modules/secrets/lohr/ssh-key.age b/hosts/nixos/porthos/secrets/lohr/ssh-key.age similarity index 100% rename from modules/secrets/lohr/ssh-key.age rename to hosts/nixos/porthos/secrets/lohr/ssh-key.age diff --git a/modules/secrets/matrix/mail.age b/hosts/nixos/porthos/secrets/matrix/mail.age similarity index 100% rename from modules/secrets/matrix/mail.age rename to hosts/nixos/porthos/secrets/matrix/mail.age diff --git a/hosts/nixos/porthos/secrets/matrix/secret.age b/hosts/nixos/porthos/secrets/matrix/secret.age new file mode 100644 index 0000000..539c33e Binary files /dev/null and b/hosts/nixos/porthos/secrets/matrix/secret.age differ diff --git a/modules/secrets/miniflux/credentials.age b/hosts/nixos/porthos/secrets/miniflux/credentials.age similarity index 100% rename from modules/secrets/miniflux/credentials.age rename to hosts/nixos/porthos/secrets/miniflux/credentials.age diff --git a/modules/secrets/monitoring/password.age b/hosts/nixos/porthos/secrets/monitoring/password.age similarity index 100% rename from modules/secrets/monitoring/password.age rename to hosts/nixos/porthos/secrets/monitoring/password.age diff --git a/hosts/nixos/porthos/secrets/monitoring/secret-key.age b/hosts/nixos/porthos/secrets/monitoring/secret-key.age new file mode 100644 index 0000000..4cef94f Binary files /dev/null and b/hosts/nixos/porthos/secrets/monitoring/secret-key.age differ diff --git a/modules/secrets/nextcloud/password.age b/hosts/nixos/porthos/secrets/nextcloud/password.age similarity index 100% rename from modules/secrets/nextcloud/password.age rename to hosts/nixos/porthos/secrets/nextcloud/password.age diff --git a/hosts/nixos/porthos/secrets/nix-serve/cache-key.age b/hosts/nixos/porthos/secrets/nix-serve/cache-key.age new file mode 100644 index 0000000..e0fb5be Binary files /dev/null and b/hosts/nixos/porthos/secrets/nix-serve/cache-key.age differ diff --git a/modules/secrets/paperless/password.age b/hosts/nixos/porthos/secrets/paperless/password.age similarity index 100% rename from modules/secrets/paperless/password.age rename to hosts/nixos/porthos/secrets/paperless/password.age diff --git a/modules/secrets/paperless/secret-key.age b/hosts/nixos/porthos/secrets/paperless/secret-key.age similarity index 100% rename from modules/secrets/paperless/secret-key.age rename to hosts/nixos/porthos/secrets/paperless/secret-key.age diff --git a/modules/secrets/podgrab/password.age b/hosts/nixos/porthos/secrets/podgrab/password.age similarity index 100% rename from modules/secrets/podgrab/password.age rename to hosts/nixos/porthos/secrets/podgrab/password.age diff --git a/hosts/nixos/porthos/secrets/secrets.nix b/hosts/nixos/porthos/secrets/secrets.nix new file mode 100644 index 0000000..498aebf --- /dev/null +++ b/hosts/nixos/porthos/secrets/secrets.nix @@ -0,0 +1,77 @@ +# Host-specific secrets +let + keys = import ../../../../keys; + + all = [ + # Host key + keys.hosts.porthos + # Allow me to modify the secrets anywhere + keys.users.ambroisie + ]; +in +{ + "acme/dns-key.age".publicKeys = all; + + "backup/password.age".publicKeys = all; + "backup/credentials.age".publicKeys = all; + + "drone/gitea.age".publicKeys = all; + "drone/secret.age".publicKeys = all; + "drone/ssh/private-key.age".publicKeys = all; + + "gitea/mail-password.age" = { + owner = "git"; + publicKeys = all; + }; + + "lohr/secret.age".publicKeys = all; + "lohr/ssh-key.age".publicKeys = all; + + "matrix/mail.age" = { + owner = "matrix-synapse"; + publicKeys = all; + }; + "matrix/secret.age" = { + owner = "matrix-synapse"; + publicKeys = all; + }; + + "miniflux/credentials.age".publicKeys = all; + + "monitoring/password.age" = { + owner = "grafana"; + publicKeys = all; + }; + "monitoring/secret-key.age" = { + owner = "grafana"; + publicKeys = all; + }; + + "nextcloud/password.age" = { + owner = "nextcloud"; + publicKeys = all; + }; + + "nix-serve/cache-key.age".publicKeys = all; + + "paperless/password.age".publicKeys = all; + "paperless/secret-key.age".publicKeys = all; + + "podgrab/password.age".publicKeys = all; + + "sso/auth-key.age".publicKeys = all; + "sso/ambroisie/password-hash.age".publicKeys = all; + "sso/ambroisie/totp-secret.age".publicKeys = all; + + "tandoor-recipes/secret-key.age".publicKeys = all; + + "transmission/credentials.age".publicKeys = all; + + "vikunja/mail.age".publicKeys = all; + + "wireguard/private-key.age".publicKeys = all; + + "woodpecker/gitea.age".publicKeys = all; + "woodpecker/secret.age".publicKeys = all; + "woodpecker/ssh/private-key.age".publicKeys = all; +} diff --git a/modules/secrets/sso/ambroisie/password-hash.age b/hosts/nixos/porthos/secrets/sso/ambroisie/password-hash.age similarity index 100% rename from modules/secrets/sso/ambroisie/password-hash.age rename to hosts/nixos/porthos/secrets/sso/ambroisie/password-hash.age diff --git a/modules/secrets/sso/ambroisie/totp-secret.age b/hosts/nixos/porthos/secrets/sso/ambroisie/totp-secret.age similarity index 100% rename from modules/secrets/sso/ambroisie/totp-secret.age rename to hosts/nixos/porthos/secrets/sso/ambroisie/totp-secret.age diff --git a/modules/secrets/sso/auth-key.age b/hosts/nixos/porthos/secrets/sso/auth-key.age similarity index 100% rename from modules/secrets/sso/auth-key.age rename to hosts/nixos/porthos/secrets/sso/auth-key.age diff --git a/modules/secrets/sso/default.nix b/hosts/nixos/porthos/secrets/sso/default.nix similarity index 100% rename from modules/secrets/sso/default.nix rename to hosts/nixos/porthos/secrets/sso/default.nix diff --git a/hosts/nixos/porthos/secrets/tandoor-recipes/secret-key.age b/hosts/nixos/porthos/secrets/tandoor-recipes/secret-key.age new file mode 100644 index 0000000..2ec147d Binary files /dev/null and b/hosts/nixos/porthos/secrets/tandoor-recipes/secret-key.age differ diff --git a/modules/secrets/transmission/credentials.age b/hosts/nixos/porthos/secrets/transmission/credentials.age similarity index 100% rename from modules/secrets/transmission/credentials.age rename to hosts/nixos/porthos/secrets/transmission/credentials.age diff --git a/hosts/nixos/porthos/secrets/vikunja/mail.age b/hosts/nixos/porthos/secrets/vikunja/mail.age new file mode 100644 index 0000000..4c83acd Binary files /dev/null and b/hosts/nixos/porthos/secrets/vikunja/mail.age differ diff --git a/modules/secrets/wireguard/porthos/private-key.age b/hosts/nixos/porthos/secrets/wireguard/private-key.age similarity index 100% rename from modules/secrets/wireguard/porthos/private-key.age rename to hosts/nixos/porthos/secrets/wireguard/private-key.age diff --git a/hosts/nixos/porthos/secrets/woodpecker/gitea.age b/hosts/nixos/porthos/secrets/woodpecker/gitea.age new file mode 100644 index 0000000..e6ede6c Binary files /dev/null and b/hosts/nixos/porthos/secrets/woodpecker/gitea.age differ diff --git a/hosts/nixos/porthos/secrets/woodpecker/secret.age b/hosts/nixos/porthos/secrets/woodpecker/secret.age new file mode 100644 index 0000000..63a4862 --- /dev/null +++ b/hosts/nixos/porthos/secrets/woodpecker/secret.age @@ -0,0 +1,10 @@ +age-encryption.org/v1 +-> ssh-ed25519 jPowng yz0I+AazPmamF7NOnwYNrPE/ArarU01jd2mVDJUPSTY +6Y/YQ7gb8cAZf3zT9SKOorvfUnU7kYff+gHh8fG2mY8 +-> ssh-ed25519 cKojmg 0FZU9v8eHsVeE+EoX9Y4IgfIj/8+45waPaSnSDb961I +L6SzJoh5xqai45scoVAa6v9zslBGFYNnZY044d470uQ +-> I[G-grease p +AMRQY1alSzHi/PLL80kcvnM1Z9YNfoUo9u5alWXYMyzrRsg+vXjMuBvAXg3fmnzr +wdOowTYMRV+jEG8vzkcQTsv+f7JIyo4DvOOaPyGfWMl1 +--- ih3IAFPcN1JP3FP1vcRGnPrfk91yrnIX0m/Szkbcf7Q +mWr_\)Ͱ]QxMs/݃ݪ6kYxMyJG)i2_'֜HF.g_e5#utՠ7jP'Tޥ8\IWUK1ں9 \ No newline at end of file diff --git a/hosts/nixos/porthos/secrets/woodpecker/ssh/private-key.age b/hosts/nixos/porthos/secrets/woodpecker/ssh/private-key.age new file mode 100644 index 0000000..0211701 Binary files /dev/null and b/hosts/nixos/porthos/secrets/woodpecker/ssh/private-key.age differ diff --git a/machines/porthos/services.nix b/hosts/nixos/porthos/services.nix similarity index 77% rename from machines/porthos/services.nix rename to hosts/nixos/porthos/services.nix index 4f3f345..e4cae5e 100644 --- a/machines/porthos/services.nix +++ b/hosts/nixos/porthos/services.nix @@ -1,5 +1,5 @@ # Deployed services -{ config, ... }: +{ config, lib, ... }: let secrets = config.age.secrets; in @@ -34,12 +34,24 @@ in secretFile = secrets."drone/gitea".path; sharedSecretFile = secrets."drone/secret".path; }; + # Auto-ban spammy bots and incorrect logins + fail2ban = { + enable = true; + }; # Flood UI for transmission flood = { enable = true; }; # Gitea forge - gitea.enable = true; + gitea = { + enable = true; + mail = { + enable = true; + host = "smtp.migadu.com:465"; + user = lib.my.mkMailAddress "gitea" "belanyi.fr"; + passwordFile = secrets."gitea/mail-password".path; + }; + }; # Meta-indexers indexers = { prowlarr.enable = true; @@ -57,7 +69,7 @@ in enable = true; mailConfigFile = secrets."matrix/mail".path; # Only necessary when doing the initial registration - # secret = "change-me"; + secretFile = secrets."matrix/secret".path; }; miniflux = { enable = true; @@ -68,6 +80,7 @@ in enable = true; grafana = { passwordFile = secrets."monitoring/password".path; + secretKeyFile = secrets."monitoring/secret-key".path; }; }; # FLOSS music streaming server @@ -80,6 +93,10 @@ in enable = true; passwordFile = secrets."nextcloud/password".path; }; + nix-serve = { + enable = true; + secretKeyFile = secrets."nix-serve/cache-key".path; + }; nginx = { enable = true; acme = { @@ -114,14 +131,17 @@ in }; # Regular backups postgresql-backup.enable = true; - # An IRC client daemon - quassel.enable = true; # RSS provider for websites that do not provide any feeds rss-bridge.enable = true; # Usenet client sabnzbd.enable = true; # Because I stilll 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; @@ -132,5 +152,14 @@ in enable = true; startAtBoot = true; # Server must be started to ensure clients can connect }; + woodpecker = { + enable = true; + # Avoid clashes with drone + port = 3035; + rpcPort = 3036; + runners = [ "docker" "exec" ]; + secretFile = secrets."woodpecker/gitea".path; + sharedSecretFile = secrets."woodpecker/secret".path; + }; }; } diff --git a/machines/porthos/ssh/drone.pub b/hosts/nixos/porthos/ssh/drone.pub similarity index 100% rename from machines/porthos/ssh/drone.pub rename to hosts/nixos/porthos/ssh/drone.pub diff --git a/machines/porthos/users.nix b/hosts/nixos/porthos/users.nix similarity index 100% rename from machines/porthos/users.nix rename to hosts/nixos/porthos/users.nix diff --git a/keys/default.nix b/keys/default.nix new file mode 100644 index 0000000..a538328 --- /dev/null +++ b/keys/default.nix @@ -0,0 +1,39 @@ +# Populate agenix keys from a central location +let + inherit (builtins) + mapAttrs + readDir + readFile + stringLength + substring + ; + + removeSuffix = suffix: str: + let + sufLen = stringLength suffix; + sLen = stringLength str; + in + if sufLen <= sLen && suffix == substring (sLen - sufLen) sufLen str then + substring 0 (sLen - sufLen) str + else + str; + + + readKeys = dir: + let + files = readDir dir; + readNoNewlines = f: removeSuffix "\n" (readFile f); + readKey = name: readNoNewlines (dir + "/${name}"); + in + mapAttrs (n: _: readKey n) files; + + hosts = readKeys ./hosts; + users = readKeys ./users; +in +{ + inherit + hosts + users; + + all = (builtins.attrValues hosts) ++ (builtins.attrValues users); +} diff --git a/keys/hosts/porthos b/keys/hosts/porthos new file mode 100644 index 0000000..7156513 --- /dev/null +++ b/keys/hosts/porthos @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICGzznQ3LSmBYHx6fXthgMDiTcU5i/Nvj020SbmhzAFb root@porthos diff --git a/keys/users/ambroisie b/keys/users/ambroisie new file mode 100644 index 0000000..cf08a3c --- /dev/null +++ b/keys/users/ambroisie @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMIVd6Oh08iUNb1vTULbxGpevnh++wxsWW9wqhaDryIq ambroisie@agenix diff --git a/lib/attrs.nix b/lib/attrs.nix index 75114b2..31686ac 100644 --- a/lib/attrs.nix +++ b/lib/attrs.nix @@ -26,6 +26,13 @@ in # attrs genAttrs' = values: f: listToAttrs (map f values); + # Merge a list of attrs non-recursively, later values override previous ones. + # + # merge :: + # [ attrs ] + # attrs + merge = foldl (a: b: a // b) { }; + # Merge a list of attrs recursively, later values override previous ones. # # recursiveMerge :: diff --git a/lib/default.nix b/lib/default.nix index fa37c23..894e351 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -15,6 +15,4 @@ let mapModules ./. (file: import file { inherit self lib pkgs inputs; }) ); in -mylib.extend (self: super: - foldr (a: b: a // b) { } (attrValues super) -) +mylib.extend (_self: super: foldr (a: b: a // b) { } (attrValues super)) diff --git a/lib/ip.nix b/lib/ip.nix index 2af3fef..fcafd72 100644 --- a/lib/ip.nix +++ b/lib/ip.nix @@ -100,7 +100,7 @@ rec { # Pretty print a parsed subnet into a human readable form prettySubnet4 = { baseIp, cidr, ... }: "${prettyIp4 baseIp}/${toString cidr}"; - # Get the nth address from an IPv4 range, without checking if it is in range + # Get the nth address from an IPv4 range nthInRange4 = { from, to }: n: let carry = lhs: { carry, acc }: @@ -112,8 +112,15 @@ rec { acc = [ (mod totVal 256) ] ++ acc; }; carried = foldr carry { carry = n; acc = [ ]; } from; + checkInRange = + if (to - from) < n + then + warn '' + nthInRange4: '${n}'-th address outside of range (${prettyIp4 from}, ${prettyIp4 to}) + '' + else id; in - carried.acc; + checkInRange carried.acc; # Convert an IPv4 range into a list of all its constituent addresses rangeIp4 = diff --git a/lib/strings.nix b/lib/strings.nix index 2a3ec77..a1f74e4 100644 --- a/lib/strings.nix +++ b/lib/strings.nix @@ -1,6 +1,4 @@ { ... }: -let -in { # Make an email address from the name and domain stems # diff --git a/modules/hardware/bluetooth/default.nix b/modules/hardware/bluetooth/default.nix index ffe0fbe..2d840f9 100644 --- a/modules/hardware/bluetooth/default.nix +++ b/modules/hardware/bluetooth/default.nix @@ -25,41 +25,22 @@ in package = pkgs.pulseaudioFull; }; - services.pipewire = { - media-session.config.bluez-monitor.rules = [ - { - # Matches all cards - matches = [{ "device.name" = "~bluez_card.*"; }]; - actions = { - "update-props" = { - "bluez5.reconnect-profiles" = [ - "hfp_hf" - "hsp_hs" - "a2dp_sink" - ]; - # mSBC provides better audio + microphone - "bluez5.msbc-support" = true; - # SBC XQ provides better audio - "bluez5.sbc-xq-support" = true; - }; - }; + environment.etc = { + "wireplumber/bluetooth.lua.d/51-bluez-config.lua".text = '' + bluez_monitor.properties = { + -- SBC XQ provides better audio + ["bluez5.enable-sbc-xq"] = true, + + -- mSBC provides better audio + microphone + ["bluez5.enable-msbc"] = true, + + -- Synchronize volume with bluetooth device + ["bluez5.enable-hw-volume"] = true, + + -- FIXME: Some devices may now support both hsp_ag and hfp_ag + ["bluez5.headset-roles"] = "[ hsp_hs hsp_ag hfp_hf hfp_ag ]" } - { - matches = [ - # Matches all sources - { - "node.name" = "~bluez_input.*"; - } - # Matches all outputs - { - "node.name" = "~bluez_output.*"; - } - ]; - actions = { - "node.pause-on-idle" = false; - }; - } - ]; + ''; }; }) diff --git a/modules/hardware/default.nix b/modules/hardware/default.nix index 9ab5d40..2a686f7 100644 --- a/modules/hardware/default.nix +++ b/modules/hardware/default.nix @@ -5,6 +5,7 @@ imports = [ ./bluetooth ./ergodox + ./firmware ./mx-ergo ./networking ./sound diff --git a/modules/hardware/firmware/default.nix b/modules/hardware/firmware/default.nix new file mode 100644 index 0000000..a77135c --- /dev/null +++ b/modules/hardware/firmware/default.nix @@ -0,0 +1,38 @@ +{ config, lib, ... }: +let + cfg = config.my.hardware.firmware; +in +{ + options.my.hardware.firmware = with lib; { + enable = my.mkDisableOption "firmware configuration"; + + cpuFlavor = mkOption { + type = with types; nullOr (enum [ "intel" "amd" ]); + default = null; + example = "intel"; + description = "Which kind of CPU to activate micro-code updates"; + }; + }; + + config = lib.mkIf cfg.enable (lib.mkMerge [ + { + hardware = { + enableRedistributableFirmware = true; + }; + } + + # Intel CPU + (lib.mkIf (cfg.cpuFlavor == "intel") { + hardware = { + cpu.intel.updateMicrocode = true; + }; + }) + + # AMD CPU + (lib.mkIf (cfg.cpuFlavor == "amd") { + hardware = { + cpu.amd.updateMicrocode = true; + }; + }) + ]); +} diff --git a/modules/home/default.nix b/modules/home/default.nix index a287f35..1e0e0aa 100644 --- a/modules/home/default.nix +++ b/modules/home/default.nix @@ -7,7 +7,7 @@ let in { imports = [ - inputs.home-manager.nixosModule # enable home-manager options + inputs.home-manager.nixosModules.home-manager # enable home-manager options (lib.mkAliasOptionModule aliasPath actualPath) # simplify setting home options ]; diff --git a/modules/programs/steam/default.nix b/modules/programs/steam/default.nix index dbdc0ce..0c7f9da 100644 --- a/modules/programs/steam/default.nix +++ b/modules/programs/steam/default.nix @@ -1,6 +1,8 @@ { config, lib, pkgs, ... }: let cfg = config.my.programs.steam; + + steam = pkgs.steam; in { options.my.programs.steam = with lib; { @@ -23,16 +25,14 @@ in environment.systemPackages = builtins.map lib.hiPrio [ # Respect XDG conventions, leave my HOME alone - (pkgs.writeScriptBin "steam" '' - #!/bin/sh + (pkgs.writeShellScriptBin "steam" '' mkdir -p "${cfg.dataDir}" - HOME="${cfg.dataDir}" exec ${pkgs.steam}/bin/steam "$@" + HOME="${cfg.dataDir}" exec ${lib.getExe steam} "$@" '') # Same, for GOG and other such games - (pkgs.writeScriptBin "steam-run" '' - #!/bin/sh + (pkgs.writeShellScriptBin "steam-run" '' mkdir -p "${cfg.dataDir}" - HOME="${cfg.dataDir}" exec ${pkgs.steam-run-native}/bin/steam-run "$@" + HOME="${cfg.dataDir}" exec ${lib.getExe steam.run} "$@" '') ]; }; diff --git a/modules/secrets/default.nix b/modules/secrets/default.nix index e8cb866..c7d6f65 100644 --- a/modules/secrets/default.nix +++ b/modules/secrets/default.nix @@ -1,4 +1,4 @@ -{ config, inputs, lib, options, ... }: +{ config, inputs, lib, ... }: { imports = [ @@ -20,10 +20,5 @@ secrets = import ./secrets.nix; in lib.mapAttrs' convertSecrets secrets; - - identityPaths = options.age.identityPaths.default ++ [ - # FIXME: hard-coded path, could be inexistent - "/home/ambroisie/.ssh/id_ed25519" - ]; }; } diff --git a/modules/secrets/drone/gitea.age b/modules/secrets/drone/gitea.age deleted file mode 100644 index d1c14e7..0000000 --- a/modules/secrets/drone/gitea.age +++ /dev/null @@ -1,10 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 cKojmg vLLu1kbzyGxr5sU/Dl4xf0uGO+gVsvODiqEJU21lwyI -LbJO4Go+8G7/UtFWjv+x7Nqhn7n+kge/oHP8dGCBnM8 --> ssh-ed25519 jPowng obxX4ojPwp/DaerFzVbK5hUnshebh/chriT3a7uqYEw -x9jpbBefJZHz8o1lEkr48XhT7sVAM5tq3tZ8M91CDDo --> eZ.G`B3W-grease 6k|.\v -D0u3P4oCpPNnueqZAAYn71xEUGWlavwLTrEXJ+2tdYOX6BwwFReOlMZWIA+FikmZ -8Pg7dHnbYPWc33jMjv3UnNsxCGUsDw9C9NkI5vfZSLvUxQ ---- Cea09ivsGZeoWif7xbdrvfoGsoiD+tRh7HQsOL75cqE -tFa|G,o6$U"wi߹Swgh6^*=[g1%Vup-{`P(?&QV#KeX4dK:xt0LsbÆ6ޜ [ #E[>)|cwq+cw1$^I(wG9>jI(y!@OƉkEz]Pk \ No newline at end of file diff --git a/modules/secrets/matrix/secret.age b/modules/secrets/matrix/secret.age deleted file mode 100644 index a287435..0000000 --- a/modules/secrets/matrix/secret.age +++ /dev/null @@ -1,9 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 cKojmg ociW6AZww4nfW0Dw0DB0WNgQbJ3MNkHPPZlA0z+o/mI -THAz89pjyrkxJB9tPQGgEwZrZX9OudWMnyzr0JiwzTA --> ssh-ed25519 jPowng 1werbtuWK0DUFxq9mAWp/QzMHC1B8UfadutvK6+j9XE -YmAwYo3X00gMB9AyQfOsR82CUPAtxfuzCzP4OyYFxjc --> 8g-grease N9DR4 .U< ---- Cwh2hPrM2RzRroJRw3XrP1khcpL0leTXfJ+T7WG57To -±jϰLDF xux1 -U/oGgo)*/d"L#RhWP \ No newline at end of file diff --git a/modules/secrets/secrets.nix b/modules/secrets/secrets.nix index d8e289e..0e685d9 100644 --- a/modules/secrets/secrets.nix +++ b/modules/secrets/secrets.nix @@ -1,61 +1,10 @@ +# Common secrets let - # FIXME: read them from directories - ambroisie = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMIVd6Oh08iUNb1vTULbxGpevnh++wxsWW9wqhaDryIq ambroisie@agenix"; - users = [ ambroisie ]; + keys = import ../../keys; - porthos = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICGzznQ3LSmBYHx6fXthgMDiTcU5i/Nvj020SbmhzAFb root@porthos"; - machines = [ porthos ]; - - all = users ++ machines; + inherit (keys) all; in { - "acme/dns-key.age".publicKeys = all; - - "backup/password.age".publicKeys = all; - "backup/credentials.age".publicKeys = all; - - "drone/gitea.age".publicKeys = all; - "drone/secret.age".publicKeys = all; - "drone/ssh/private-key.age".publicKeys = all; - - "lohr/secret.age".publicKeys = all; - "lohr/ssh-key.age".publicKeys = all; - - "matrix/mail.age" = { - owner = "matrix-synapse"; - publicKeys = all; - }; - "matrix/secret.age".publicKeys = all; - - "miniflux/credentials.age".publicKeys = all; - - "monitoring/password.age" = { - owner = "grafana"; - publicKeys = all; - }; - - "nextcloud/password.age" = { - # Must be readable by the service - owner = "nextcloud"; - publicKeys = all; - }; - - "paperless/password.age".publicKeys = all; - "paperless/secret-key.age".publicKeys = all; - - "podgrab/password.age".publicKeys = all; - - "sso/auth-key.age".publicKeys = all; - "sso/ambroisie/password-hash.age".publicKeys = all; - "sso/ambroisie/totp-secret.age".publicKeys = all; - - "transmission/credentials.age".publicKeys = all; - "users/ambroisie/hashed-password.age".publicKeys = all; "users/root/hashed-password.age".publicKeys = all; - - "wireguard/aramis/private-key.age".publicKeys = all; - "wireguard/milady/private-key.age".publicKeys = all; - "wireguard/porthos/private-key.age".publicKeys = all; - "wireguard/richelieu/private-key.age".publicKeys = all; } diff --git a/modules/secrets/wireguard/default.nix b/modules/secrets/wireguard/default.nix deleted file mode 100644 index 1dbde9f..0000000 --- a/modules/secrets/wireguard/default.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ lib, ... }: -let - peerSpec = { - # "Server" - porthos = { - clientNum = 1; - externalIp = "91.121.177.163"; - }; - - # "Clients" - aramis = { - clientNum = 2; - }; - - richelieu = { - clientNum = 3; - }; - }; - - makePeer = name: attrs: with lib; { - inherit (attrs) clientNum; - publicKey = fileContents (./. + "/${name}/public.key"); - privateKey = fileContents (./. + "/${name}/secret.key"); - } // optionalAttrs (attrs ? externalIp) { - inherit (attrs) externalIp; - }; -in -{ - peers = builtins.mapAttrs makePeer peerSpec; -} diff --git a/modules/services/blog/default.nix b/modules/services/blog/default.nix index 9149917..4b646c3 100644 --- a/modules/services/blog/default.nix +++ b/modules/services/blog/default.nix @@ -23,7 +23,20 @@ in forceSSL = true; useACMEHost = domain; root = "/var/www/blog"; - default = true; # Redirect to my blog + + # http://www.gnuterrypratchett.com/ + extraConfig = '' + add_header X-Clacks-Overhead "GNU Terry Pratchett"; + ''; + }; + + # Dummy vhost to redirect all unknown (sub-)domains to my blog + "_" = { + forceSSL = true; + useACMEHost = domain; + default = true; + + locations."/".return = "302 https://belanyi.fr$request_uri"; }; }; diff --git a/modules/services/calibre-web/default.nix b/modules/services/calibre-web/default.nix index e6ba10d..858851c 100644 --- a/modules/services/calibre-web/default.nix +++ b/modules/services/calibre-web/default.nix @@ -53,5 +53,21 @@ in cfg.libraryPath ]; }; + + services.fail2ban.jails = { + calibre-web = '' + enabled = true + filter = calibre-web + port = http,https + ''; + }; + + environment.etc = { + "fail2ban/filter.d/calibre-web.conf".text = '' + [Definition] + failregex = ^.*Login failed for user ".*" IP-address: $ + journalmatch = _SYSTEMD_UNIT=calibre-web.service + ''; + }; }; } diff --git a/modules/services/default.nix b/modules/services/default.nix index 4ed40f0..86badf5 100644 --- a/modules/services/default.nix +++ b/modules/services/default.nix @@ -7,8 +7,10 @@ ./blog ./calibre-web ./drone + ./fail2ban ./flood ./gitea + ./grocy ./indexers ./jellyfin ./lohr @@ -18,17 +20,21 @@ ./navidrome ./nextcloud ./nginx + ./nix-serve ./paperless ./pirate ./podgrab - ./postgresql-backup ./postgresql + ./postgresql-backup ./quassel ./rss-bridge ./sabnzbd ./ssh-server + ./tandoor-recipes ./tlp ./transmission + ./vikunja ./wireguard + ./woodpecker ]; } diff --git a/modules/services/drone/runner-docker/default.nix b/modules/services/drone/runner-docker/default.nix index 0f2e3b3..e53c608 100644 --- a/modules/services/drone/runner-docker/default.nix +++ b/modules/services/drone/runner-docker/default.nix @@ -2,7 +2,6 @@ let cfg = config.my.services.drone; hasRunner = (name: builtins.elem name cfg.runners); - dockerPkg = pkgs.drone-runner-docker; in { config = lib.mkIf (cfg.enable && hasRunner "docker") { @@ -25,14 +24,14 @@ in EnvironmentFile = [ cfg.sharedSecretFile ]; - ExecStart = "${dockerPkg}/bin/drone-runner-docker"; + ExecStart = lib.getExe pkgs.drone-runner-docker; User = "drone-runner-docker"; Group = "drone-runner-docker"; }; }; # Make sure it is activated in that case - virtualisation.docker.enable = true; + my.system.docker.enable = true; users.users.drone-runner-docker = { isSystemUser = true; diff --git a/modules/services/drone/runner-exec/default.nix b/modules/services/drone/runner-exec/default.nix index 6c776b4..a9bb563 100644 --- a/modules/services/drone/runner-exec/default.nix +++ b/modules/services/drone/runner-exec/default.nix @@ -2,7 +2,6 @@ let cfg = config.my.services.drone; hasRunner = (name: builtins.elem name cfg.runners); - execPkg = pkgs.drone-runner-exec; in { config = lib.mkIf (cfg.enable && hasRunner "exec") { @@ -15,14 +14,14 @@ in git gnutar bash - nixUnstable + nix gzip ]; path = with pkgs; [ git gnutar bash - nixUnstable + nix gzip ]; serviceConfig = { @@ -53,7 +52,7 @@ in EnvironmentFile = [ cfg.sharedSecretFile ]; - ExecStart = "${execPkg}/bin/drone-runner-exec"; + ExecStart = lib.getExe pkgs.drone-runner-exec; User = "drone-runner-exec"; Group = "drone-runner-exec"; }; diff --git a/modules/services/fail2ban/default.nix b/modules/services/fail2ban/default.nix new file mode 100644 index 0000000..d62b9e2 --- /dev/null +++ b/modules/services/fail2ban/default.nix @@ -0,0 +1,37 @@ +# A minimalist, opinionated feed reader +{ config, lib, ... }: +let + cfg = config.my.services.fail2ban; + wgNetCfg = config.my.services.wireguard.net; +in +{ + options.my.services.fail2ban = with lib; { + enable = mkEnableOption "fail2ban daemon"; + }; + + config = lib.mkIf cfg.enable { + services.fail2ban = { + enable = true; + + ignoreIP = [ + # Wireguard IPs + "${wgNetCfg.v4.subnet}.0/${toString wgNetCfg.v4.mask}" + "${wgNetCfg.v6.subnet}::/${toString wgNetCfg.v6.mask}" + # Loopback addresses + "127.0.0.0/8" + ]; + + maxretry = 5; + + bantime-increment = { + enable = true; + rndtime = "5m"; # Use 5 minute jitter to avoid unban evasion + }; + + jails.DEFAULT.settings = { + findtime = "4h"; + bantime = "10m"; + }; + }; + }; +} diff --git a/modules/services/flood/default.nix b/modules/services/flood/default.nix index ae8e219..ff5d941 100644 --- a/modules/services/flood/default.nix +++ b/modules/services/flood/default.nix @@ -30,7 +30,7 @@ in serviceConfig = { ExecStart = lib.concatStringsSep " " [ - "${pkgs.flood}/bin/flood" + (lib.getExe pkgs.flood) "--port ${builtins.toString cfg.port}" "--rundir /var/lib/${cfg.stateDir}" ]; diff --git a/modules/services/gitea/default.nix b/modules/services/gitea/default.nix index 0ece12c..28a448d 100644 --- a/modules/services/gitea/default.nix +++ b/modules/services/gitea/default.nix @@ -12,29 +12,55 @@ in example = 8080; description = "Internal port"; }; + mail = { + enable = mkEnableOption { + description = "mailer configuration"; + }; + host = mkOption { + type = types.str; + example = "smtp.example.com:465"; + description = "Host for the mail account"; + }; + user = mkOption { + type = types.str; + example = "gitea@example.com"; + description = "User for the mail account"; + }; + passwordFile = mkOption { + type = types.str; + example = "/run/secrets/gitea-mail-password.txt"; + description = "Password for the mail account"; + }; + type = mkOption { + type = types.str; + default = "smtp"; + example = "smtp"; + description = "Password for the mail account"; + }; + tls = mkOption { + type = types.bool; + default = true; + example = false; + description = "Use TLS for connection"; + }; + }; }; config = lib.mkIf cfg.enable { services.gitea = let - giteaDomain = "gitea.${config.networking.domain}"; + inherit (config.networking) domain; + giteaDomain = "git.${domain}"; in { enable = true; appName = "Ambroisie's forge"; - httpPort = cfg.port; - domain = giteaDomain; - rootUrl = "https://${giteaDomain}"; user = "git"; lfs.enable = true; useWizard = false; - disableRegistration = true; - - # only send cookies via HTTPS - cookieSecure = true; database = { type = "postgres"; # Automatic setup @@ -45,6 +71,34 @@ in # but it produces a single .zip file that's not very backup friendly. # I configure my backup system manually below. dump.enable = false; + + mailerPasswordFile = lib.mkIf cfg.mail.enable cfg.mail.passwordFile; + + settings = { + server = { + HTTP_PORT = cfg.port; + DOMAIN = giteaDomain; + ROOT_URL = "https://${giteaDomain}"; + }; + + mailer = lib.mkIf cfg.mail.enable { + ENABLED = true; + HOST = cfg.mail.host; + FROM = cfg.mail.user; + USER = cfg.mail.user; + MAILER_TYPE = cfg.mail.type; + IS_TLS_ENABLED = cfg.mail.tls; + }; + + service = { + DISABLE_REGISTRATION = true; + }; + + session = { + # only send cookies via HTTPS + COOKIE_SECURE = true; + }; + }; }; users.users.git = { @@ -61,11 +115,16 @@ in }; users.groups.git = { }; - # Proxy to Gitea my.services.nginx.virtualHosts = [ + # Proxy to Gitea + { + subdomain = "git"; + inherit (cfg) port; + } + # Redirect `gitea.` to actual forge subdomain { subdomain = "gitea"; - inherit (cfg) port; + redirect = config.services.gitea.settings.server.ROOT_URL; } ]; @@ -75,5 +134,21 @@ in config.services.gitea.repositoryRoot ]; }; + + services.fail2ban.jails = { + gitea = '' + enabled = true + filter = gitea + action = iptables-allports + ''; + }; + + environment.etc = { + "fail2ban/filter.d/gitea.conf".text = '' + [Definition] + failregex = ^.*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from $ + journalmatch = _SYSTEMD_UNIT=gitea.service + ''; + }; }; } diff --git a/modules/services/grocy/default.nix b/modules/services/grocy/default.nix new file mode 100644 index 0000000..87927d6 --- /dev/null +++ b/modules/services/grocy/default.nix @@ -0,0 +1,40 @@ +# Groceries and household management +{ config, lib, ... }: +let + cfg = config.my.services.grocy; + grocyDomain = "grocy.${config.networking.domain}"; +in +{ + options.my.services.grocy = with lib; { + enable = mkEnableOption "Grocy household ERP"; + }; + + config = lib.mkIf cfg.enable { + services.grocy = { + enable = true; + + # The service sets up the reverse proxy automatically + hostName = grocyDomain; + + # Configure SSL by hand + nginx = { + enableSSL = false; + }; + + settings = { + currency = "EUR"; + culture = "en"; + calendar = { + # Start on Monday + firstDayOfWeek = 1; + showWeekNumber = true; + }; + }; + }; + + services.nginx.virtualHosts."${grocyDomain}" = { + forceSSL = true; + useACMEHost = config.networking.domain; + }; + }; +} diff --git a/modules/services/lohr/default.nix b/modules/services/lohr/default.nix index af218ac..245567c 100644 --- a/modules/services/lohr/default.nix +++ b/modules/services/lohr/default.nix @@ -4,8 +4,6 @@ let cfg = config.my.services.lohr; settingsFormat = pkgs.formats.yaml { }; - lohrPkg = pkgs.ambroisie.lohr; - lohrStateDirectory = "lohr"; lohrHome = "/var/lib/lohr/"; in @@ -80,7 +78,7 @@ in let configFile = settingsFormat.generate "lohr-config.yaml" cfg.setting; in - "${lohrPkg}/bin/lohr --config ${configFile}"; + "${lib.getExe pkgs.ambroisie.lohr} --config ${configFile}"; StateDirectory = lohrStateDirectory; WorkingDirectory = lohrHome; User = "lohr"; @@ -88,6 +86,7 @@ in }; path = with pkgs; [ git + openssh ]; }; diff --git a/modules/services/matrix/default.nix b/modules/services/matrix/default.nix index 6adcd00..c73afed 100644 --- a/modules/services/matrix/default.nix +++ b/modules/services/matrix/default.nix @@ -7,7 +7,6 @@ # [1]: https://github.com/alarsyo/nixos-config/blob/main/services/matrix.nix { config, lib, pkgs, ... }: -with lib; let cfg = config.my.services.matrix; @@ -56,7 +55,6 @@ in public_baseurl = "https://matrix.${domain}"; enable_registration = false; - # registration_shared_secret = cfg.secret; # FIXME: use a secret file for this listeners = [ # Federation @@ -150,7 +148,7 @@ in }; # same as above, but listening on the federation port - "matrix.${domain}_federation" = rec { + "matrix.${domain}_federation" = { onlySSL = true; serverName = "matrix.${domain}"; useACMEHost = domain; @@ -165,7 +163,6 @@ in { addr = "0.0.0.0"; port = federationPort.public; ssl = true; } { addr = "[::]"; port = federationPort.public; ssl = true; } ]; - }; "${domain}" = { diff --git a/modules/services/monitoring/default.nix b/modules/services/monitoring/default.nix index ba5adf3..829bfe0 100644 --- a/modules/services/monitoring/default.nix +++ b/modules/services/monitoring/default.nix @@ -27,6 +27,12 @@ in example = "/var/lib/grafana/password.txt"; description = "Admin password stored in a file"; }; + + secretKeyFile = mkOption { + type = types.str; + example = "/var/lib/grafana/secret_key.txt"; + description = "Secret key stored in a file"; + }; }; prometheus = { @@ -49,19 +55,26 @@ in config = lib.mkIf cfg.enable { services.grafana = { enable = true; - domain = "monitoring.${config.networking.domain}"; - port = cfg.grafana.port; - addr = "127.0.0.1"; # Proxied through Nginx - security = { - adminUser = cfg.grafana.username; - adminPasswordFile = cfg.grafana.passwordFile; + settings = { + server = { + domain = "monitoring.${config.networking.domain}"; + root_url = "https://monitoring.${config.networking.domain}/"; + http_port = cfg.grafana.port; + http_addr = "127.0.0.1"; # Proxied through Nginx + }; + + security = { + admin_user = cfg.grafana.username; + admin_password = "$__file{${cfg.grafana.passwordFile}}"; + secret_key = "$__file{${cfg.grafana.secretKeyFile}}"; + }; }; provision = { enable = true; - datasources = [ + datasources.settings.datasources = [ { name = "Prometheus"; type = "prometheus"; @@ -72,7 +85,7 @@ in } ]; - dashboards = [ + dashboards.settings.providers = [ { name = "Node Exporter"; options.path = pkgs.nur.repos.alarsyo.grafanaDashboards.node-exporter; diff --git a/modules/services/nextcloud/default.nix b/modules/services/nextcloud/default.nix index 976d21f..1477c13 100644 --- a/modules/services/nextcloud/default.nix +++ b/modules/services/nextcloud/default.nix @@ -31,10 +31,12 @@ in config = lib.mkIf cfg.enable { services.nextcloud = { enable = true; - package = pkgs.nextcloud23; + package = pkgs.nextcloud27; hostName = "nextcloud.${config.networking.domain}"; home = "/var/lib/nextcloud"; maxUploadSize = cfg.maxSize; + enableBrokenCiphersForSSE = false; + configureRedis = true; config = { adminuser = cfg.admin; adminpassFile = cfg.passwordFile; @@ -42,6 +44,12 @@ in dbhost = "/run/postgresql"; overwriteProtocol = "https"; # Nginx only allows SSL }; + + notify_push = { + enable = true; + # Allow using the push service without hard-coding my IP in the configuration + bendDomainToLocalhost = true; + }; }; services.postgresql = { diff --git a/modules/services/nginx/default.nix b/modules/services/nginx/default.nix index d99ff2d..dcaaa0f 100644 --- a/modules/services/nginx/default.nix +++ b/modules/services/nginx/default.nix @@ -3,6 +3,8 @@ let cfg = config.my.services.nginx; + domain = config.networking.domain; + virtualHostOption = with lib; types.submodule { options = { subdomain = mkOption { @@ -24,6 +26,15 @@ let ''; }; + redirect = mkOption { + type = with types; nullOr str; + default = null; + example = "https://example.com"; + description = '' + Which domain to redirect to (301 response), for this virtual host. + ''; + }; + root = mkOption { type = with types; nullOr path; default = null; @@ -34,6 +45,16 @@ let ''; }; + socket = mkOption { + type = with types; nullOr path; + default = null; + example = "FIXME"; + description = '' + The UNIX socket for this virtual host. This option is incompatible + with `port`. + ''; + }; + sso = { enable = mkEnableOption "SSO authentication"; }; @@ -174,7 +195,7 @@ in assertions = [ ] ++ (lib.flip builtins.map cfg.virtualHosts ({ subdomain, ... } @ args: let - conflicts = [ "port" "root" ]; + conflicts = [ "port" "root" "socket" "redirect" ]; optionsNotNull = builtins.map (v: args.${v} != null) conflicts; optionsSet = lib.filter lib.id optionsNotNull; in @@ -222,10 +243,12 @@ in enable = true; statusPage = true; # For monitoring scraping. + recommendedBrotliSettings = true; recommendedGzipSettings = true; recommendedOptimisation = true; - recommendedTlsSettings = true; recommendedProxySettings = true; + recommendedTlsSettings = true; + recommendedZstdSettings = true; virtualHosts = let @@ -247,6 +270,15 @@ in (lib.optionalAttrs (args.root != null) { inherit (args) root; }) + # Serve to UNIX socket + (lib.optionalAttrs (args.socket != null) { + locations."/".proxyPass = + "http://unix:${args.socket}"; + }) + # Redirect to a different domain + (lib.optionalAttrs (args.redirect != null) { + locations."/".return = "301 ${args.redirect}$request_uri"; + }) # VHost specific configuration args.extraConfig # SSO configuration @@ -392,10 +424,6 @@ in acceptTerms = true; # Use DNS wildcard certificate certs = - let - domain = config.networking.domain; - in - with pkgs; { "${domain}" = { extraDomainNames = [ "*.${domain}" ]; @@ -405,7 +433,16 @@ in }; }; - services.grafana.provision.dashboards = lib.mkIf cfg.monitoring.enable [ + systemd.services."acme-${domain}" = { + serviceConfig = { + Environment = [ + # Since I do a "weird" setup with a wildcard CNAME + "LEGO_DISABLE_CNAME_SUPPORT=true" + ]; + }; + }; + + services.grafana.provision.dashboards.settings.providers = lib.mkIf cfg.monitoring.enable [ { name = "NGINX"; options.path = pkgs.nur.repos.alarsyo.grafanaDashboards.nginx; diff --git a/modules/services/nginx/sso/default.nix b/modules/services/nginx/sso/default.nix index 13292ec..4a78282 100644 --- a/modules/services/nginx/sso/default.nix +++ b/modules/services/nginx/sso/default.nix @@ -59,8 +59,7 @@ in StateDirectory = "nginx-sso"; WorkingDirectory = "/var/lib/nginx-sso"; # The files to be merged might not have the correct permissions - ExecStartPre = ''+${pkgs.writeScript "merge-nginx-sso-config" '' - #!${pkgs.bash}/bin/bash + ExecStartPre = ''+${pkgs.writeShellScript "merge-nginx-sso-config" '' rm -f '${confPath}' ${utils.genJqSecretsReplacementSnippet cfg.configuration confPath} @@ -70,7 +69,7 @@ in '' }''; ExecStart = lib.mkForce '' - ${pkg}/bin/nginx-sso \ + ${lib.getExe pkg} \ --config ${confPath} \ --frontend-dir ${pkg}/share/frontend ''; diff --git a/modules/services/nix-serve/default.nix b/modules/services/nix-serve/default.nix new file mode 100644 index 0000000..0cf1573 --- /dev/null +++ b/modules/services/nix-serve/default.nix @@ -0,0 +1,57 @@ +# Binary cache through nix-serve +{ config, lib, pkgs, ... }: +let + cfg = config.my.services.nix-serve; +in +{ + options.my.services.nix-serve = with lib; { + enable = mkEnableOption "nix-serve binary cache"; + + port = mkOption { + type = types.port; + default = 5000; + example = 8080; + description = "Internal port for serving cache"; + }; + + secretKeyFile = mkOption { + type = types.str; + example = "/run/secrets/nix-serve"; + description = "Secret signing key for the cache"; + }; + + priority = mkOption { + type = types.int; + default = 50; + example = 30; + description = '' + Which priority to assign to this cache. Lower number is higher priority. + The official nixpkgs hydra cache is priority 40. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + services.nix-serve = { + enable = true; + + bindAddress = "127.0.0.1"; + + inherit (cfg) + port + secretKeyFile + ; + + package = pkgs.nix-serve-ng; + + extraParams = "--priority=${toString cfg.priority}"; + }; + + my.services.nginx.virtualHosts = [ + { + subdomain = "cache"; + inherit (cfg) port; + } + ]; + }; +} diff --git a/modules/services/paperless/default.nix b/modules/services/paperless/default.nix index e9ec6a3..c9d6220 100644 --- a/modules/services/paperless/default.nix +++ b/modules/services/paperless/default.nix @@ -45,7 +45,7 @@ in }; config = lib.mkIf cfg.enable { - services.paperless-ng = { + services.paperless = { enable = true; port = cfg.port; @@ -83,16 +83,40 @@ in }; systemd.services = { - paperless-ng-server.serviceConfig = { - EnvironmentFile = cfg.secretKeyFile; + paperless-scheduler = { + requires = [ "postgresql.service" ]; + after = [ "postgresql.service" ]; + + serviceConfig = { + EnvironmentFile = cfg.secretKeyFile; + }; }; - paperless-ng-consumer.serviceConfig = { - EnvironmentFile = cfg.secretKeyFile; + paperless-consumer = { + requires = [ "postgresql.service" ]; + after = [ "postgresql.service" ]; + + serviceConfig = { + EnvironmentFile = cfg.secretKeyFile; + }; }; - paperless-ng-web.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; + }; }; }; @@ -111,13 +135,7 @@ in # Set-up media group users.groups.media = { }; - systemd.services.paperless-ng-server = { - # Make sure the DB is available - after = [ "postgresql.service" ]; - }; - - - users.users.${config.services.paperless-ng.user} = { + users.users.${config.services.paperless.user} = { extraGroups = [ "media" ]; }; @@ -138,8 +156,8 @@ in my.services.backup = { paths = [ - config.services.paperless-ng.dataDir - config.services.paperless-ng.mediaDir + config.services.paperless.dataDir + config.services.paperless.mediaDir ]; }; }; diff --git a/modules/services/sabnzbd/default.nix b/modules/services/sabnzbd/default.nix index b9b99cf..7ab145f 100644 --- a/modules/services/sabnzbd/default.nix +++ b/modules/services/sabnzbd/default.nix @@ -24,5 +24,34 @@ in inherit port; } ]; + + services.fail2ban.jails = { + sabnzbd = '' + enabled = true + filter = sabnzbd + port = http,https + # Unfortunately, sabnzbd does not log to systemd journal + backend = auto + logpath = /var/lib/sabnzbd/logs/sabnzbd.log + ''; + }; + + environment.etc = { + # FIXME: path to log file + "fail2ban/filter.d/sabnzbd.conf".text = '' + [Definition] + failregex = ^.*WARNING.*API Key incorrect, Use the api key from Config->General in your 3rd party program: .* \(X-Forwarded-For: \) .*$ + ^.*WARNING.*API Key incorrect, Use the api key from Config->General in your 3rd party program: .*$ + ^.*WARNING.*API Key missing, please enter the api key from Config->General into your 3rd party program: .* \(X-Forwarded-For: \) .*$ + ^.*WARNING.*API Key missing, please enter the api key from Config->General into your 3rd party program: .*$ + ^.*WARNING.*Refused connection from: .* \(X-Forwarded-For: \) .*$ + ^.*WARNING.*Refused connection from: .*$ + ^.*WARNING.*Refused connection with hostname ".*" from: .* \(X-Forwarded-For: \) .*$ + ^.*WARNING.*Refused connection with hostname ".*" from: .*$ + ^.*WARNING.*Unsuccessful login attempt from .* \(X-Forwarded-For: \) .*$ + ^.*WARNING.*Unsuccessful login attempt from .*$ + journalmatch = _SYSTEMD_UNIT=sabnzbd.service + ''; + }; }; } diff --git a/modules/services/ssh-server/default.nix b/modules/services/ssh-server/default.nix index a41a673..9ae0fa8 100644 --- a/modules/services/ssh-server/default.nix +++ b/modules/services/ssh-server/default.nix @@ -12,9 +12,12 @@ in services.openssh = { # Enable the OpenSSH daemon. enable = true; - # Be more secure - permitRootLogin = "no"; - passwordAuthentication = false; + + settings = { + # Be more secure + PermitRootLogin = "no"; + PasswordAuthentication = false; + }; }; # Opens the relevant UDP ports. diff --git a/modules/services/tandoor-recipes/default.nix b/modules/services/tandoor-recipes/default.nix new file mode 100644 index 0000000..d78bef3 --- /dev/null +++ b/modules/services/tandoor-recipes/default.nix @@ -0,0 +1,79 @@ +{ config, lib, ... }: +let + cfg = config.my.services.tandoor-recipes; +in +{ + options.my.services.tandoor-recipes = with lib; { + enable = mkEnableOption "Tandoor Recipes service"; + + port = mkOption { + type = types.port; + default = 4536; + example = 8080; + description = "Internal port for webui"; + }; + + secretKeyFile = mkOption { + type = types.str; + example = "/var/lib/tandoor-recipes/secret-key.env"; + description = '' + Secret key as an 'EnvironmentFile' (see `systemd.exec(5)`) + ''; + }; + }; + + config = lib.mkIf cfg.enable { + services.tandoor-recipes = { + enable = 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}"; + + # Misc + TIMEZONE = config.time.timeZone; + }; + }; + + systemd.services = { + tandoor-recipes = { + after = [ "postgresql.service" ]; + + serviceConfig = { + EnvironmentFile = cfg.secretKeyFile; + }; + }; + }; + + # Set-up database + services.postgresql = { + enable = true; + ensureDatabases = [ "tandoor_recipes" ]; + ensureUsers = [ + { + name = "tandoor_recipes"; + ensurePermissions."DATABASE tandoor_recipes" = "ALL PRIVILEGES"; + } + ]; + }; + + my.services.nginx.virtualHosts = [ + { + subdomain = "recipes"; + inherit (cfg) port; + } + ]; + }; +} diff --git a/modules/services/transmission/default.nix b/modules/services/transmission/default.nix index cac075f..dcba0aa 100644 --- a/modules/services/transmission/default.nix +++ b/modules/services/transmission/default.nix @@ -67,6 +67,13 @@ in }; }; + # Transmission wants to eat *all* my RAM if left to its own devices + systemd.services.transmission = { + serviceConfig = { + MemoryMax = "33%"; + }; + }; + # Set-up media group users.groups.media = { }; diff --git a/modules/services/vikunja/default.nix b/modules/services/vikunja/default.nix new file mode 100644 index 0000000..1cdef5f --- /dev/null +++ b/modules/services/vikunja/default.nix @@ -0,0 +1,123 @@ +# Todo and kanban app +{ config, lib, ... }: +let + cfg = config.my.services.vikunja; + subdomain = "todo"; + vikunjaDomain = "${subdomain}.${config.networking.domain}"; + socketPath = "/run/vikunja/vikunja.socket"; +in +{ + options.my.services.vikunja = with lib; { + enable = mkEnableOption "Vikunja todo app"; + + mail = { + enable = mkEnableOption { + description = "mailer configuration"; + }; + + configFile = mkOption { + type = types.str; + example = "/run/secrets/vikunja-mail-config.env"; + description = "Configuration for the mailer connection, using environment variables."; + }; + }; + }; + + config = lib.mkIf cfg.enable { + services.vikunja = { + enable = true; + + frontendScheme = "https"; + frontendHostname = vikunjaDomain; + + setupNginx = false; + + database = { + type = "postgres"; + user = "vikunja"; + database = "vikunja"; + host = "/run/postgresql"; + }; + + settings = { + service = { + # Only allow registration of users through the CLI + enableregistration = false; + # Ues the host's timezone + timezone = config.time.timeZone; + # Use UNIX socket for serving the API + unixsocket = socketPath; + unixsocketmode = "0o660"; + }; + + mailer = { + enabled = cfg.mail.enable; + }; + }; + + environmentFiles = lib.optional cfg.mail.enable cfg.mail.configFile; + }; + + # This is a weird setup + my.services.nginx.virtualHosts = [ + { + inherit subdomain; + # Serve the root for the web-ui + root = config.services.vikunja.package-frontend; + + extraConfig = { + locations = { + "/" = { + tryFiles = "try_files $uri $uri/ /"; + }; + + # Serve the API through a UNIX socket + "~* ^/(api|dav|\\.well-known)/" = { + proxyPass = "http://unix:${socketPath}"; + extraConfig = '' + client_max_body_size 20M; + ''; + }; + }; + }; + } + ]; + + systemd.services.vikunja-api = { + serviceConfig = { + # Use a system user to simplify using the CLI + DynamicUser = lib.mkForce false; + # Set the user for postgres authentication + User = "vikunja"; + # Create /run/vikunja/ to serve the UNIX socket + RuntimeDirectory = "vikunja"; + }; + }; + + users.users.vikunja = { + description = "Vikunja Service"; + group = "vikunja"; + isSystemUser = true; + }; + users.groups.vikunja = { }; + + # Allow nginx to access the UNIX socket + users.users.nginx.extraGroups = [ "vikunja" ]; + + services.postgresql = { + ensureDatabases = [ "vikunja" ]; + ensureUsers = [ + { + name = "vikunja"; + ensurePermissions = { "DATABASE vikunja" = "ALL PRIVILEGES"; }; + } + ]; + }; + + my.services.backup = { + paths = [ + config.services.vikunja.settings.files.basepath + ]; + }; + }; +} diff --git a/modules/services/wireguard/default.nix b/modules/services/wireguard/default.nix index 656fdb2..fc5518d 100644 --- a/modules/services/wireguard/default.nix +++ b/modules/services/wireguard/default.nix @@ -8,40 +8,31 @@ let secrets = config.age.secrets; hostName = config.networking.hostName; - peers = - let - mkPeer = name: attrs: { - inherit (attrs) clientNum publicKey; - privateKeyFile = secrets."wireguard/${name}/private-key".path; - } // lib.optionalAttrs (attrs ? externalIp) { - inherit (attrs) externalIp; - }; - in - lib.mapAttrs mkPeer { - # "Server" - porthos = { - clientNum = 1; - publicKey = "PLdgsizztddri0LYtjuNHr5r2E8D+yI+gM8cm5WDfHQ="; - externalIp = "91.121.177.163"; - }; - - # "Clients" - aramis = { - clientNum = 2; - publicKey = "QJSWIBS1mXTpxYybLlKu/Y5wy0GFbUfn4yPzpF1DZDc="; - }; - - richelieu = { - clientNum = 3; - publicKey = "w4IADAj2Tt7Qe95a0RxDv9ovg/Dr/f3q1LrVOPF48Rk="; - }; - - # Sarah's iPhone - milady = { - clientNum = 4; - publicKey = "3MKEu4F6o8kww54xeAao5Uet86fv8z/QsZ2L2mOzqDQ="; - }; + peers = { + # "Server" + porthos = { + clientNum = 1; + publicKey = "PLdgsizztddri0LYtjuNHr5r2E8D+yI+gM8cm5WDfHQ="; + externalIp = "91.121.177.163"; }; + + # "Clients" + aramis = { + clientNum = 2; + publicKey = "QJSWIBS1mXTpxYybLlKu/Y5wy0GFbUfn4yPzpF1DZDc="; + }; + + richelieu = { + clientNum = 3; + publicKey = "w4IADAj2Tt7Qe95a0RxDv9ovg/Dr/f3q1LrVOPF48Rk="; + }; + + # Sarah's iPhone + milady = { + clientNum = 4; + publicKey = "3MKEu4F6o8kww54xeAao5Uet86fv8z/QsZ2L2mOzqDQ="; + }; + }; thisPeer = peers."${hostName}"; thisPeerIsServer = thisPeer ? externalIp; # Only connect to clients from server, and only connect to server from clients @@ -60,7 +51,7 @@ let "${v4.subnet}.${toString thisPeer.clientNum}/${toString v4.mask}" "${v6.subnet}::${toString thisPeer.clientNum}/${toHexString v6.mask}" ]; - inherit (thisPeer) privateKeyFile; + privateKeyFile = secrets."wireguard/private-key".path; peers = let diff --git a/modules/secrets/wireguard/milady/private-key.age b/modules/services/wireguard/keys/milady/private-key.age similarity index 100% rename from modules/secrets/wireguard/milady/private-key.age rename to modules/services/wireguard/keys/milady/private-key.age diff --git a/modules/secrets/wireguard/richelieu/private-key.age b/modules/services/wireguard/keys/richelieu/private-key.age similarity index 100% rename from modules/secrets/wireguard/richelieu/private-key.age rename to modules/services/wireguard/keys/richelieu/private-key.age diff --git a/modules/services/wireguard/keys/secrets.nix b/modules/services/wireguard/keys/secrets.nix new file mode 100644 index 0000000..3985477 --- /dev/null +++ b/modules/services/wireguard/keys/secrets.nix @@ -0,0 +1,15 @@ +# Extra wireguard keys that are not hosts NixOS hosts +let + keys = import ../../../../keys; + + all = [ + keys.users.ambroisie + ]; +in +{ + # Sarah's iPhone + "milady/private-key.age".publicKeys = all; + + # My Android phone + "richelieu/private-key.age".publicKeys = all; +} diff --git a/modules/services/woodpecker/agent-docker/default.nix b/modules/services/woodpecker/agent-docker/default.nix new file mode 100644 index 0000000..b18d075 --- /dev/null +++ b/modules/services/woodpecker/agent-docker/default.nix @@ -0,0 +1,45 @@ +{ config, lib, ... }: +let + cfg = config.my.services.woodpecker; + + hasRunner = (name: builtins.elem name cfg.runners); +in +{ + config = lib.mkIf (cfg.enable && hasRunner "docker") { + services.woodpecker-agents = { + agents.docker = { + enable = true; + + environment = { + WOODPECKER_SERVER = "localhost:${toString cfg.rpcPort}"; + WOODPECKER_MAX_WORKFLOWS = "10"; + WOODPECKER_BACKEND = "docker"; + WOODPECKER_FILTER_LABELS = "type=docker"; + WOODPECKER_HEALTHCHECK = "false"; + }; + + environmentFile = [ cfg.sharedSecretFile ]; + + extraGroups = [ "docker" ]; + }; + }; + + # Make sure it is activated in that case + my.system.docker.enable = true; + + # FIXME: figure out the issue + services.unbound.resolveLocalQueries = false; + + # Adjust runner service for nix usage + systemd.services.woodpecker-agent-docker = { + after = [ "docker.socket" ]; # Needs the socket to be available + # might break deployment + restartIfChanged = false; + serviceConfig = { + BindPaths = [ + "/var/run/docker.sock" + ]; + }; + }; + }; +} diff --git a/modules/services/woodpecker/agent-exec/default.nix b/modules/services/woodpecker/agent-exec/default.nix new file mode 100644 index 0000000..ad30188 --- /dev/null +++ b/modules/services/woodpecker/agent-exec/default.nix @@ -0,0 +1,64 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.my.services.woodpecker; + + hasRunner = (name: builtins.elem name cfg.runners); +in +{ + config = lib.mkIf (cfg.enable && hasRunner "exec") { + services.woodpecker-agents = { + agents.exec = { + enable = true; + + environment = { + WOODPECKER_SERVER = "localhost:${toString cfg.rpcPort}"; + WOODPECKER_MAX_WORKFLOWS = "10"; + WOODPECKER_BACKEND = "local"; + WOODPECKER_FILTER_LABELS = "type=exec"; + WOODPECKER_HEALTHCHECK = "false"; + + NIX_REMOTE = "daemon"; + PAGER = "cat"; + }; + + environmentFile = [ cfg.sharedSecretFile ]; + }; + }; + + # Adjust runner service for nix usage + systemd.services.woodpecker-agent-exec = { + # Might break deployment + restartIfChanged = false; + + path = with pkgs; [ + woodpecker-plugin-git + bash + coreutils + git + git-lfs + gnutar + gzip + nix + ]; + + serviceConfig = { + # Same option as upstream, without @setuid + SystemCallFilter = lib.mkForce "~@clock @privileged @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @reboot @swap"; + + BindPaths = [ + "/nix/var/nix/daemon-socket/socket" + "/run/nscd/socket" + ]; + BindReadOnlyPaths = [ + "/etc/passwd:/etc/passwd" + "/etc/group:/etc/group" + "/etc/nix:/etc/nix" + "${config.environment.etc."ssh/ssh_known_hosts".source}:/etc/ssh/ssh_known_hosts" + "/etc/machine-id" + # channels are dynamic paths in the nix store, therefore we need to bind mount the whole thing + "/nix/" + ]; + }; + }; + }; +} diff --git a/modules/services/woodpecker/default.nix b/modules/services/woodpecker/default.nix new file mode 100644 index 0000000..34ffca6 --- /dev/null +++ b/modules/services/woodpecker/default.nix @@ -0,0 +1,46 @@ +{ lib, ... }: +{ + imports = [ + ./agent-docker + ./agent-exec + ./server + ]; + + options.my.services.woodpecker = with lib; { + enable = mkEnableOption "Woodpecker CI"; + runners = mkOption { + type = with types; listOf (enum [ "exec" "docker" ]); + default = [ ]; + example = [ "exec" "docker" ]; + description = "Types of runners to enable"; + }; + admin = mkOption { + type = types.str; + default = "ambroisie"; + example = "admin"; + description = "Name of the admin user"; + }; + port = mkOption { + type = types.port; + default = 3030; + example = 8080; + description = "Internal port of the Woodpecker UI"; + }; + rpcPort = mkOption { + type = types.port; + default = 3031; + example = 8080; + description = "Internal port of the Woodpecker UI"; + }; + secretFile = mkOption { + type = types.str; + example = "/run/secrets/woodpecker.env"; + description = "Secrets to inject into Woodpecker server"; + }; + sharedSecretFile = mkOption { + type = types.str; + example = "/run/secrets/woodpecker.env"; + description = "Shared RPC secret to inject into server and runners"; + }; + }; +} diff --git a/modules/services/woodpecker/server/default.nix b/modules/services/woodpecker/server/default.nix new file mode 100644 index 0000000..152e707 --- /dev/null +++ b/modules/services/woodpecker/server/default.nix @@ -0,0 +1,66 @@ +{ config, lib, ... }: +let + cfg = config.my.services.woodpecker; +in +{ + config = lib.mkIf cfg.enable { + services.woodpecker-server = { + enable = true; + + environment = { + WOODPECKER_OPEN = "true"; + WOODPECKER_HOST = "https://woodpecker.${config.networking.domain}"; + WOODPECKER_DATABASE_DRIVER = "postgres"; + WOODPECKER_DATABASE_DATASOURCE = "postgres:///woodpecker?host=/run/postgresql"; + WOODPECKER_ADMIN = "${cfg.admin}"; + WOODPECKER_SERVER_ADDR = ":${toString cfg.port}"; + WOODPECKER_GRPC_ADDR = ":${toString cfg.rpcPort}"; + + WOODPECKER_GITEA = "true"; + WOODPECKER_GITEA_URL = config.services.gitea.settings.server.ROOT_URL; + + WOODPECKER_LOG_LEVEL = "debug"; + }; + }; + + systemd.services.woodpecker-server = { + serviceConfig = { + # Set username for DB access + User = "woodpecker"; + + BindPaths = [ + # Allow access to DB path + "/run/postgresql" + ]; + + EnvironmentFile = [ + cfg.secretFile + cfg.sharedSecretFile + ]; + }; + }; + + services.postgresql = { + enable = true; + ensureDatabases = [ "woodpecker" ]; + ensureUsers = [{ + name = "woodpecker"; + ensurePermissions = { + "DATABASE woodpecker" = "ALL PRIVILEGES"; + }; + }]; + }; + + my.services.nginx.virtualHosts = [ + { + subdomain = "woodpecker"; + inherit (cfg) port; + } + # I might want to be able to RPC from other hosts in the future + { + subdomain = "woodpecker-rpc"; + port = cfg.rpcPort; + } + ]; + }; +} diff --git a/modules/system/boot/default.nix b/modules/system/boot/default.nix index 0fed267..3d8495e 100644 --- a/modules/system/boot/default.nix +++ b/modules/system/boot/default.nix @@ -13,9 +13,11 @@ in config = { boot = { - cleanTmpDir = cfg.tmp.clean; + tmp = { + cleanOnBoot = cfg.tmp.clean; - tmpOnTmpfs = cfg.tmp.tmpfs; + useTmpfs = cfg.tmp.tmpfs; + }; }; }; } diff --git a/modules/system/default.nix b/modules/system/default.nix index 3c81cac..9fe3b57 100644 --- a/modules/system/default.nix +++ b/modules/system/default.nix @@ -4,6 +4,7 @@ { imports = [ ./boot + ./docker ./documentation ./language ./nix diff --git a/modules/system/docker/default.nix b/modules/system/docker/default.nix new file mode 100644 index 0000000..f051814 --- /dev/null +++ b/modules/system/docker/default.nix @@ -0,0 +1,27 @@ +# Podman related settings +{ config, lib, ... }: +let + cfg = config.my.system.docker; +in +{ + options.my.system.docker = with lib; { + enable = mkEnableOption "docker configuration"; + }; + + config = lib.mkIf cfg.enable { + virtualisation.docker = { + enable = true; + + # Remove unused data on a weekly basis + autoPrune = { + enable = true; + + dates = "weekly"; + + flags = [ + "--all" + ]; + }; + }; + }; +} diff --git a/modules/system/documentation/default.nix b/modules/system/documentation/default.nix index 74886ad..304c811 100644 --- a/modules/system/documentation/default.nix +++ b/modules/system/documentation/default.nix @@ -3,20 +3,20 @@ let cfg = config.my.system.documentation; in { - options.my.system.documentation = with lib.my; { - enable = mkDisableOption "Documentation integration"; + options.my.system.documentation = with lib; { + enable = my.mkDisableOption "Documentation integration"; - dev.enable = mkDisableOption "Documentation aimed at developers"; + dev.enable = my.mkDisableOption "Documentation aimed at developers"; - info.enable = mkDisableOption "Documentation aimed at developers"; + info.enable = my.mkDisableOption "Documentation aimed at developers"; man = { - enable = mkDisableOption "Documentation aimed at developers"; + enable = my.mkDisableOption "Documentation aimed at developers"; - linux = mkDisableOption "Linux man pages (section 2 & 3)"; + linux = my.mkDisableOption "Linux man pages (section 2 & 3)"; }; - nixos.enable = mkDisableOption "NixOS documentation"; + nixos.enable = my.mkDisableOption "NixOS documentation"; }; config = lib.mkIf cfg.enable { diff --git a/modules/system/nix/default.nix b/modules/system/nix/default.nix index 16db0b4..47d6499 100644 --- a/modules/system/nix/default.nix +++ b/modules/system/nix/default.nix @@ -2,20 +2,57 @@ { config, inputs, lib, options, pkgs, ... }: let cfg = config.my.system.nix; + + channels = lib.my.merge [ + { + # Allow me to use my custom package using `nix run self#pkg` + self = inputs.self; + # Add NUR to run some packages that are only present there + nur = inputs.nur; + # Use pinned nixpkgs when using `nix run pkgs#` + pkgs = inputs.nixpkgs; + } + (lib.optionalAttrs cfg.inputs.overrideNixpkgs { + # ... And with `nix run nixpkgs#` + nixpkgs = inputs.nixpkgs; + }) + ]; in { options.my.system.nix = with lib; { enable = my.mkDisableOption "nix configuration"; - addToRegistry = my.mkDisableOption "add inputs and self to registry"; + cache = { + selfHosted = my.mkDisableOption "self-hosted cache"; + }; - addToNixPath = my.mkDisableOption "add inputs and self to nix path"; + inputs = { + link = my.mkDisableOption "link inputs to `/etc/nix/inputs/`"; + + addToRegistry = my.mkDisableOption "add inputs and self to registry"; + + addToNixPath = my.mkDisableOption "add inputs and self to nix path"; + + overrideNixpkgs = my.mkDisableOption "point nixpkgs to pinned system version"; + }; }; config = lib.mkIf cfg.enable (lib.mkMerge [ + { + assertions = [ + { + assertion = cfg.inputs.addToNixPath -> cfg.inputs.link; + message = '' + enabling `my.system.nix.inputs.addToNixPath` needs to have + `my.system.nix.inputs.link = true` + ''; + } + ]; + } + { nix = { - package = pkgs.nixFlakes; + package = pkgs.nix; settings = { experimental-features = [ "nix-command" "flakes" ]; @@ -23,23 +60,48 @@ in }; } - (lib.mkIf cfg.addToRegistry { - nix.registry = { - # Allow me to use my custom package using `nix run self#pkg` - self.flake = inputs.self; - # Use pinned nixpkgs when using `nix run pkgs#` - pkgs.flake = inputs.nixpkgs; - # Add NUR to run some packages that are only present there - nur.flake = inputs.nur; + (lib.mkIf cfg.cache.selfHosted { + nix = { + settings = { + # The NixOS module adds the official Hydra cache by default + # No need to use `extra-*` options. + substituters = [ + "https://cache.belanyi.fr/" + ]; + + trusted-public-keys = [ + "cache.belanyi.fr:LPhrTqufwfxTceg1nRWueDWf7/2zSVY9K00pq2UI7tw=" + ]; + }; }; }) - (lib.mkIf cfg.addToNixPath { - nix.nixPath = options.nix.nixPath.default ++ [ - "self=${inputs.self}" - "pkgs=${inputs.nixpkgs}" - "nur=${inputs.nur}" - ]; + (lib.mkIf cfg.inputs.addToRegistry { + nix.registry = + let + makeEntry = v: { flake = v; }; + makeEntries = lib.mapAttrs (lib.const makeEntry); + in + makeEntries channels; + }) + + (lib.mkIf cfg.inputs.link { + environment.etc = + let + makeLink = n: v: { + name = "nix/inputs/${n}"; + value = { source = v.outPath; }; + }; + makeLinks = lib.mapAttrs' makeLink; + in + makeLinks channels; + }) + + (lib.mkIf cfg.inputs.addToNixPath { + nix.nixPath = [ + "/etc/nix/inputs" + ] + ++ options.nix.nixPath.default; }) ]); } diff --git a/modules/system/packages/default.nix b/modules/system/packages/default.nix index ceb85dd..5c29aa0 100644 --- a/modules/system/packages/default.nix +++ b/modules/system/packages/default.nix @@ -7,6 +7,8 @@ in options.my.system.packages = with lib; { enable = my.mkDisableOption "packages configuration"; + allowAliases = mkEnableOption "allow package aliases"; + allowUnfree = my.mkDisableOption "allow unfree packages"; }; @@ -27,7 +29,7 @@ in }; nixpkgs.config = { - allowUnfree = cfg.allowUnfree; # Because I don't care *that* much. + inherit (cfg) allowAliases allowUnfree; }; }; } diff --git a/modules/system/podman/default.nix b/modules/system/podman/default.nix index c267ec6..52630c7 100644 --- a/modules/system/podman/default.nix +++ b/modules/system/podman/default.nix @@ -1,5 +1,5 @@ # Podman related settings -{ config, inputs, lib, options, pkgs, ... }: +{ config, lib, ... }: let cfg = config.my.system.podman; in @@ -9,6 +9,16 @@ in }; config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.enable -> !config.my.system.docker.enable; + message = '' + `config.my.system.podman` is incompatible with + `config.my.system.docker`. + ''; + } + ]; + virtualisation.podman = { enable = true; @@ -19,7 +29,20 @@ in dockerSocket.enable = true; # Allow DNS resolution in the default network - defaultNetwork.dnsname.enable = true; + defaultNetwork.settings = { + dns_enabled = true; + }; + + # Remove unused data on a weekly basis + autoPrune = { + enable = true; + + dates = "weekly"; + + flags = [ + "--all" + ]; + }; }; }; } diff --git a/modules/system/users/default.nix b/modules/system/users/default.nix index 3fa5b2e..27557bd 100644 --- a/modules/system/users/default.nix +++ b/modules/system/users/default.nix @@ -27,6 +27,7 @@ in shell = pkgs.zsh; extraGroups = groupsIfExist [ "audio" # sound control + "docker" # usage of `docker` socket "media" # access to media files "networkmanager" # wireless configuration "plugdev" # usage of ZSA keyboard tools diff --git a/overlays/default.nix b/overlays/default.nix index 3f5a246..683e021 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -1,5 +1,6 @@ -{ - sabnzbd-fix-missing-packages = import ./sabnzbd-fix-missing-dependencies; - - transgui-fix-duplicate-status = import ./transgui-fix-duplicate-status; -} +# Automatically import all overlays in the directory +let + files = builtins.readDir ./.; + overlays = builtins.removeAttrs files [ "default.nix" ]; +in +builtins.mapAttrs (name: _: import "${./.}/${name}") overlays diff --git a/overlays/sabnzbd-fix-missing-dependencies/default.nix b/overlays/sabnzbd-fix-missing-dependencies/default.nix deleted file mode 100644 index e2e8eec..0000000 --- a/overlays/sabnzbd-fix-missing-dependencies/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -final: prev: -{ - sabnzbd = final.callPackage ./sabnzbd.nix { }; -} diff --git a/overlays/sabnzbd-fix-missing-dependencies/sabnzbd.nix b/overlays/sabnzbd-fix-missing-dependencies/sabnzbd.nix deleted file mode 100644 index 3da9b28..0000000 --- a/overlays/sabnzbd-fix-missing-dependencies/sabnzbd.nix +++ /dev/null @@ -1,60 +0,0 @@ -{ lib -, stdenv -, fetchFromGitHub -, python3 -, par2cmdline -, unzip -, unrar -, p7zip -, makeWrapper -}: - -let - pythonEnv = python3.withPackages (ps: with ps; [ - chardet - cheetah3 - cherrypy - configobj - cryptography - feedparser - guessit - puremagic - sabyenc3 - ]); - path = lib.makeBinPath [ par2cmdline unrar unzip p7zip ]; -in -stdenv.mkDerivation rec { - version = "3.4.0"; - pname = "sabnzbd"; - - src = fetchFromGitHub { - owner = pname; - repo = pname; - rev = version; - sha256 = "sha256-zax+PuvCmYOlEhRmiCp7UOd9VI0i8dbgTPyTtqLuGUM="; - }; - - nativeBuildInputs = [ makeWrapper ]; - buildInputs = [ pythonEnv ]; - - installPhase = '' - runHook preInstall - - mkdir -p $out - cp -R * $out/ - mkdir $out/bin - echo "${pythonEnv}/bin/python $out/SABnzbd.py \$*" > $out/bin/sabnzbd - chmod +x $out/bin/sabnzbd - wrapProgram $out/bin/sabnzbd --set PATH ${path} - - runHook postInstall - ''; - - meta = with lib; { - description = "Usenet NZB downloader, par2 repairer and auto extracting server"; - homepage = "https://sabnzbd.org"; - license = licenses.gpl2Plus; - platforms = platforms.linux; - maintainers = with lib.maintainers; [ fridh ]; - }; -} diff --git a/overlays/transgui-fix-duplicate-status/default.nix b/overlays/transgui-fix-duplicate-status/default.nix deleted file mode 100644 index 85036ce..0000000 --- a/overlays/transgui-fix-duplicate-status/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -final: prev: -{ - transgui = prev.transgui.overrideAttrs (oldAttrs: { - patches = (oldAttrs.patches or [ ]) ++ [ - (final.fetchpatch { - url = "https://patch-diff.githubusercontent.com/raw/transmission-remote-gui/transgui/pull/1354.patch"; - sha256 = "sha256-Q4DAduqnTtNI0Zw9NIWpE8L0G8RusvPbZ3iW29k7XXA="; - }) - ]; - }); -} diff --git a/pkgs/bw-pass/default.nix b/pkgs/bw-pass/default.nix index b11e7ea..9b959f5 100644 --- a/pkgs/bw-pass/default.nix +++ b/pkgs/bw-pass/default.nix @@ -1,20 +1,17 @@ -{ lib, bitwarden-cli, coreutils, jq, keyutils, makeWrapper, rofi, shellcheck, stdenvNoCC }: +{ lib, bitwarden-cli, coreutils, jq, keyutils, makeWrapper, rofi, stdenvNoCC }: stdenvNoCC.mkDerivation rec { pname = "bw-pass"; version = "0.1.0"; src = ./bw-pass; - buildInputs = [ + nativeBuildInputs = [ makeWrapper - shellcheck ]; dontUnpack = true; - buildPhase = '' - shellcheck $src - ''; + dontBuild = true; installPhase = '' mkdir -p $out/bin @@ -37,9 +34,10 @@ stdenvNoCC.mkDerivation rec { meta = with lib; { description = "A simple script to query a password from bitwarden"; - homepage = "https://gitea.belanyi.fr/ambroisie/nix-config"; + homepage = "https://git.belanyi.fr/ambroisie/nix-config"; license = with licenses; [ mit ]; - platforms = platforms.linux; + mainProgram = "bw-pass"; maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.linux; }; } diff --git a/pkgs/change-audio/default.nix b/pkgs/change-audio/default.nix index d2e76b0..12814e1 100644 --- a/pkgs/change-audio/default.nix +++ b/pkgs/change-audio/default.nix @@ -1,20 +1,17 @@ -{ lib, libnotify, makeWrapper, pamixer, shellcheck, stdenvNoCC }: +{ lib, libnotify, makeWrapper, pamixer, stdenvNoCC }: stdenvNoCC.mkDerivation rec { pname = "change-audio"; version = "0.3.0"; src = ./change-audio; - buildInputs = [ + nativeBuildInputs = [ makeWrapper - shellcheck ]; dontUnpack = true; - buildPhase = '' - shellcheck $src - ''; + dontBuild = true; installPhase = '' mkdir -p $out/bin @@ -36,9 +33,10 @@ stdenvNoCC.mkDerivation rec { description = '' A script to change the volume and notify about it ''; - homepage = "https://gitea.belanyi.fr/ambroisie/nix-config"; + homepage = "https://git.belanyi.fr/ambroisie/nix-config"; license = with licenses; [ mit ]; - platforms = platforms.linux; + mainProgram = "change-audio"; maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.linux; }; } diff --git a/pkgs/change-backlight/default.nix b/pkgs/change-backlight/default.nix index 799c814..1f8c88c 100644 --- a/pkgs/change-backlight/default.nix +++ b/pkgs/change-backlight/default.nix @@ -1,20 +1,17 @@ -{ lib, brightnessctl, libnotify, makeWrapper, shellcheck, stdenvNoCC }: +{ lib, brightnessctl, libnotify, makeWrapper, stdenvNoCC }: stdenvNoCC.mkDerivation rec { pname = "change-backlight"; version = "0.1.0"; src = ./change-backlight; - buildInputs = [ + nativeBuildInputs = [ makeWrapper - shellcheck ]; dontUnpack = true; - buildPhase = '' - shellcheck $src - ''; + dontBuild = true; installPhase = '' mkdir -p $out/bin @@ -36,9 +33,10 @@ stdenvNoCC.mkDerivation rec { description = '' A script to change a screen's brightness and notify about it ''; - homepage = "https://gitea.belanyi.fr/ambroisie/nix-config"; + homepage = "https://git.belanyi.fr/ambroisie/nix-config"; license = with licenses; [ mit ]; - platforms = platforms.linux; + mainProgram = "change-backlight"; maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.linux; }; } diff --git a/pkgs/comma/default.nix b/pkgs/comma/default.nix index 1c10eb2..32e09d0 100644 --- a/pkgs/comma/default.nix +++ b/pkgs/comma/default.nix @@ -1,20 +1,17 @@ -{ lib, fzf, makeWrapper, nix-index, shellcheck, stdenvNoCC }: +{ lib, fzf, makeWrapper, nix-index, stdenvNoCC }: stdenvNoCC.mkDerivation rec { pname = "comma"; version = "0.1.0"; src = ./comma; - buildInputs = [ + nativeBuildInputs = [ makeWrapper - shellcheck ]; dontUnpack = true; - buildPhase = '' - shellcheck $src - ''; + dontBuild = true; installPhase = '' mkdir -p $out/bin @@ -33,11 +30,11 @@ stdenvNoCC.mkDerivation rec { ''; meta = with lib; { - mainProgram = ","; description = "A simple script inspired by Shopify's comma, for modern Nix"; - homepage = "https://gitea.belanyi.fr/ambroisie/nix-config"; + homepage = "https://git.belanyi.fr/ambroisie/nix-config"; license = with licenses; [ mit ]; - platforms = platforms.unix; + mainProgram = ","; maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.unix; }; } diff --git a/pkgs/default.nix b/pkgs/default.nix index af39384..c9e755a 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -12,23 +12,21 @@ pkgs.lib.makeScope pkgs.newScope (pkgs: { dragger = pkgs.callPackage ./dragger { }; + drone-rsync = pkgs.callPackage ./drone-rsync { }; + drone-scp = pkgs.callPackage ./drone-scp { }; ff2mpv-go = pkgs.callPackage ./ff2mpv-go { }; - havm = pkgs.callPackage ./havm { }; - i3-get-window-criteria = pkgs.callPackage ./i3-get-window-criteria { }; lohr = pkgs.callPackage ./lohr { }; matrix-notifier = pkgs.callPackage ./matrix-notifier { }; - nolimips = pkgs.callPackage ./nolimips { }; + osc52 = pkgs.callPackage ./osc52 { }; - psst = pkgs.callPackage ./psst { }; - - rofi-bluetooth = pkgs.callPackage ./rofi-bluetooth { }; + rbw-pass = pkgs.callPackage ./rbw-pass { }; unbound-zones-adblock = pkgs.callPackage ./unbound-zones-adblock { }; @@ -37,4 +35,6 @@ pkgs.lib.makeScope pkgs.newScope (pkgs: { vimix-cursors = pkgs.callPackage ./vimix-cursors { }; volantes-cursors = pkgs.callPackage ./volantes-cursors { }; + + wifi-qr = pkgs.callPackage ./wifi-qr { }; }) diff --git a/pkgs/diff-flake/default.nix b/pkgs/diff-flake/default.nix index c085e67..9cccd20 100644 --- a/pkgs/diff-flake/default.nix +++ b/pkgs/diff-flake/default.nix @@ -1,20 +1,17 @@ -{ lib, coreutils, git, gnused, makeWrapper, shellcheck, stdenvNoCC }: +{ lib, coreutils, git, gnused, makeWrapper, stdenvNoCC }: stdenvNoCC.mkDerivation rec { pname = "diff-flake"; - version = "0.1.0"; + version = "0.4.0"; src = ./diff-flake; - buildInputs = [ + nativeBuildInputs = [ makeWrapper - shellcheck ]; dontUnpack = true; - buildPhase = '' - shellcheck $src - ''; + dontBuild = true; installPhase = '' mkdir -p $out/bin @@ -35,9 +32,10 @@ stdenvNoCC.mkDerivation rec { meta = with lib; { description = "Nix flake helper to visualize changes in closures"; - homepage = "https://gitea.belanyi.fr/ambroisie/nix-config"; + homepage = "https://git.belanyi.fr/ambroisie/nix-config"; license = with licenses; [ mit ]; - platforms = platforms.unix; + mainProgram = "diff-flake"; maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.unix; }; } diff --git a/pkgs/diff-flake/diff-flake b/pkgs/diff-flake/diff-flake index ef03122..0572b4e 100755 --- a/pkgs/diff-flake/diff-flake +++ b/pkgs/diff-flake/diff-flake @@ -20,19 +20,21 @@ sanitize_output() { fi } -add_shell() { - local SYSTEM - if [ $# -gt 0 ] && [ -n "$1" ]; then - SYSTEM="$1" - else - SYSTEM="$(nix eval --raw --impure --expr 'builtins.currentSystem')" - fi - # Use 'inputDerivation' attribute to make sure that it is build-able - FLAKE_OUTPUTS+=("devShell.$SYSTEM.inputDerivation") +current_system() { + nix eval --raw --impure --expr 'builtins.currentSystem' +} + +add_home() { + FLAKE_OUTPUTS+=("homeConfigurations.\"$1\".activationPackage") } add_host() { - FLAKE_OUTPUTS+=("nixosConfigurations.$1.config.system.build.toplevel") + FLAKE_OUTPUTS+=("nixosConfigurations.\"$1\".config.system.build.toplevel") +} + +add_shell() { + # Use 'inputDerivation' attribute to make sure that it is build-able + FLAKE_OUTPUTS+=("devShells.\"$(current_system)\".\"$1\".inputDerivation") } usage() { @@ -52,17 +54,21 @@ usage() { print_err " -p, --previous-rev" print_err " which git revision should be considered the 'previous' state," print_err " defaults to HEAD~" + print_err " --home [name]" + print_err " specify the name of a home-manager output configuration whose" + print_err " closure should be diffed, can be used multiple times" + print_err " if no configuration name is given, defaults to current username" print_err " --host [name]" print_err " specify the name of a NixOS output configuration whose" print_err " closure should be diffed, can be used multiple times" print_err " if no host name is given, defaults to current hostname" - print_err " --shell [system]" - print_err " specify a specific system's devShell output whose closure" + print_err " --shell [name]" + print_err " specify a specific devShell configuration name whose closure" print_err " should be diffed, can be used multiple times" - print_err " if no system is given, defaults to current system" + print_err " if no name is given, defaults to 'default'" print_err "" print_err "when no flake outputs are specified, automatically queries for" - print_err "all NixOS configurations, and devShell for current system" + print_err "all NixOS configurations, and devShells for current system" } is_option() { @@ -95,6 +101,14 @@ parse_args() { PREVIOUS_REV="$(git rev-parse "$1")" shift ;; + --home) + if [ $# -gt 0 ] && ! is_option "$1"; then + add_home "$1" + shift + else + add_home "$USER" + fi + ;; --host) if [ $# -gt 0 ] && ! is_option "$1"; then add_host "$1" @@ -108,7 +122,7 @@ parse_args() { add_shell "$1" shift else - add_shell + add_shell "default" fi ;; --) @@ -124,12 +138,24 @@ parse_args() { done } +list_home_configurations() { + nix eval '.#homeConfigurations' \ + --apply 'attrs: with builtins; concatStringsSep "\n" (attrNames attrs)' \ + --raw +} + list_nixos_configurations() { nix eval '.#nixosConfigurations' \ --apply 'attrs: with builtins; concatStringsSep "\n" (attrNames attrs)' \ --raw } +list_dev_shells() { + nix eval ".#devShells.\"$(current_system)\"" \ + --apply 'attrs: with builtins; concatStringsSep "\n" (attrNames attrs)' \ + --raw +} + diff_output() { local PREV NEW; PREV="$(mktemp --dry-run)" @@ -149,10 +175,15 @@ diff_output() { parse_args "$@" if [ "${#FLAKE_OUTPUTS[@]}" -eq 0 ]; then + for home in $(list_home_configurations); do + add_home "$home" + done for host in $(list_nixos_configurations); do add_host "$host" done - add_shell + for shell in $(list_dev_shells); do + add_shell "$shell" + done fi for out in "${FLAKE_OUTPUTS[@]}"; do diff --git a/pkgs/dragger/default.nix b/pkgs/dragger/default.nix index cd0d453..9eda7df 100644 --- a/pkgs/dragger/default.nix +++ b/pkgs/dragger/default.nix @@ -7,7 +7,7 @@ qt5.mkDerivation rec { owner = "ambroisie"; repo = "dragger"; rev = "v${version}"; - sha256 = "sha256-WAC720DxfkQxy1BeeGzE6IerFb4ejoMRAPEJv5HGDHM="; + hash = "sha256-WAC720DxfkQxy1BeeGzE6IerFb4ejoMRAPEJv5HGDHM="; }; configurePhase = '' @@ -21,9 +21,10 @@ qt5.mkDerivation rec { meta = with lib; { description = "A CLI drag-and-drop tool"; - homepage = "https://gitea.belanyi.fr/ambroisie/dragger"; + homepage = "https://git.belanyi.fr/ambroisie/dragger"; license = licenses.mit; - maintainers = [ ambroisie ]; + mainProgram = "dragger"; + maintainers = with maintainers; [ ambroisie ]; platforms = platforms.linux; }; } diff --git a/pkgs/drone-rsync/default.nix b/pkgs/drone-rsync/default.nix new file mode 100644 index 0000000..a7c2cbc --- /dev/null +++ b/pkgs/drone-rsync/default.nix @@ -0,0 +1,41 @@ +{ lib, makeWrapper, openssh, rsync, sshpass, stdenvNoCC }: +stdenvNoCC.mkDerivation rec { + pname = "drone-rsync"; + version = "0.1.0"; + + src = ./drone-rsync; + + nativeBuildInputs = [ + makeWrapper + ]; + + dontUnpack = true; + + dontBuild = true; + + installPhase = '' + mkdir -p $out/bin + cp $src $out/bin/${pname} + chmod a+x $out/bin/${pname} + ''; + + wrapperPath = lib.makeBinPath [ + openssh + rsync + sshpass + ]; + + fixupPhase = '' + patchShebangs $out/bin/${pname} + wrapProgram $out/bin/${pname} --prefix PATH : "${wrapperPath}" + ''; + + meta = with lib; { + description = "Helper script to run rsync in a CI pipeline"; + homepage = "https://git.belanyi.fr/ambroisie/nix-config"; + license = with licenses; [ mit ]; + mainProgram = "drone-rsync"; + maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.unix; + }; +} diff --git a/pkgs/drone-rsync/drone-rsync b/pkgs/drone-rsync/drone-rsync new file mode 100755 index 0000000..b6491e7 --- /dev/null +++ b/pkgs/drone-rsync/drone-rsync @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ARGS=( + # Show readable progress in log + --verbose + --human-readable + --progress + # Have a one-to-one copy + --archive + --compress + --recursive + --delete + # Configure ssh client + --rsh "ssh -p ${SYNC_PORT:-22} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" +) + +eval "$(ssh-agent)" +SSHPASS="${SYNC_PASSPHRASE:-}" sshpass -P 'passphrase' -v -e ssh-add <(echo "${SYNC_KEY}") + +if [ -n "${SYNC_DRY_RUN:-}" ]; then + ARGS+=(--dry-run) +fi + +# shellcheck disable=2086 +# FIXME: have a safer way to allow globbing the source +rsync \ + "${ARGS[@]}" \ + ${SYNC_SOURCE} \ + "${SYNC_USERNAME}@${SYNC_HOST}:${SYNC_TARGET}" diff --git a/pkgs/drone-scp/default.nix b/pkgs/drone-scp/default.nix index 863befd..7437b06 100644 --- a/pkgs/drone-scp/default.nix +++ b/pkgs/drone-scp/default.nix @@ -1,16 +1,16 @@ { lib, buildGoModule, fetchFromGitHub }: buildGoModule rec { pname = "drone-scp"; - version = "1.6.2"; + version = "1.6.3"; src = fetchFromGitHub { owner = "appleboy"; repo = "drone-scp"; rev = "v${version}"; - sha256 = "sha256-PNy1HA2qW4RY/VRHhuj/tIrdTuB7COr0Cuzurku+DZw="; + hash = "sha256-ELjPqoRR4O6gmc/PgthQuSXuSTQNzBZoAUT80zVVbV0="; }; - vendorSha256 = "sha256-7Aro6g3Tka0Cbi9LpqvKpQXlbxnHQWsMOkkNpENKh0U="; + vendorHash = "sha256-/c103hTJ/Qdz2KTkdl/ACvAaSSTKcl1DQY3+Us6OxaI="; doCheck = false; # Needs a specific user... @@ -20,5 +20,6 @@ buildGoModule rec { ''; homepage = "https://github.com/appleboy/drone-scp"; license = licenses.mit; + mainProgram = "drone-scp"; }; } diff --git a/pkgs/ff2mpv-go/default.nix b/pkgs/ff2mpv-go/default.nix index 3dc229c..8c59bf5 100644 --- a/pkgs/ff2mpv-go/default.nix +++ b/pkgs/ff2mpv-go/default.nix @@ -6,13 +6,13 @@ buildGoModule rec { src = fetchgit { url = "https://git.clsr.net/util/ff2mpv-go/"; rev = "v${version}"; - sha256 = "sha256-e/AuOA3isFTyBf97Zwtr16yo49UdYzvktV5PKB/eH/s="; + hash = "sha256-e/AuOA3isFTyBf97Zwtr16yo49UdYzvktV5PKB/eH/s="; }; - vendorSha256 = "sha256-pQpattmS9VmO3ZIQUFn66az8GSmB4IvYhTTCFn6SUmo="; + vendorHash = null; postPatch = '' - sed -i -e 's,"mpv","${mpv}/bin/mpv",' ff2mpv.go + sed -i -e 's,"mpv","${lib.getExe mpv}",' ff2mpv.go ''; postInstall = '' @@ -26,5 +26,6 @@ buildGoModule rec { ''; homepage = "https://git.clsr.net/util/ff2mpv-go/"; license = licenses.publicDomain; + mainProgram = "ff2mpv-go"; }; } diff --git a/pkgs/havm/default.nix b/pkgs/havm/default.nix deleted file mode 100644 index 51eb9f0..0000000 --- a/pkgs/havm/default.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ lib, fetchurl, ghc, stdenv, which }: -stdenv.mkDerivation rec { - pname = "havm"; - version = "0.28"; - - src = fetchurl { - url = "https://www.lrde.epita.fr/~tiger/download/${pname}-${version}.tar.gz"; - sha256 = "sha256-FDi4FZ8rjGqRkFlROtcJsv+mks7MmIXQGV4bZrwkQrA="; - }; - - nativeBuildInputs = [ - ghc - ]; - - checkInputs = [ - which - ]; - - doCheck = true; - - meta = with lib; { - description = "A simple virtual machine to execute Andrew Appel's HIR/LIR"; - longDescription = '' - HAVM is a virtual machine designed to execute simple register based high - level intermediate code. It is based on the intermediate representations - ("canonicalized" or not) defined by Andrew Appel in his "Modern Compiler - Implementation". - ''; - homepage = "https://www.lrde.epita.fr/wiki/Havm"; - license = licenses.gpl2Plus; - platforms = platforms.all; - maintainers = with maintainers; [ ambroisie ]; - }; -} diff --git a/pkgs/i3-get-window-criteria/default.nix b/pkgs/i3-get-window-criteria/default.nix index acfde93..2fc840d 100644 --- a/pkgs/i3-get-window-criteria/default.nix +++ b/pkgs/i3-get-window-criteria/default.nix @@ -1,20 +1,17 @@ -{ lib, coreutils, gnused, makeWrapper, shellcheck, stdenvNoCC, xorg }: +{ lib, coreutils, gnused, makeWrapper, stdenvNoCC, xorg }: stdenvNoCC.mkDerivation rec { pname = "i3-get-window-criteria"; version = "0.1.0"; src = ./i3-get-window-criteria; - buildInputs = [ + nativeBuildInputs = [ makeWrapper - shellcheck ]; dontUnpack = true; - buildPhase = '' - shellcheck $src - ''; + dontBuild = true; installPhase = '' mkdir -p $out/bin @@ -36,9 +33,10 @@ stdenvNoCC.mkDerivation rec { meta = with lib; { description = "Helper script to query i3 window criterions"; - homepage = "https://gitea.belanyi.fr/ambroisie/nix-config"; + homepage = "https://git.belanyi.fr/ambroisie/nix-config"; license = with licenses; [ mit ]; - platforms = platforms.unix; + mainProgram = "i3-get-window-criteria"; maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.unix; }; } diff --git a/pkgs/lohr/default.nix b/pkgs/lohr/default.nix index c71dbd0..a83b092 100644 --- a/pkgs/lohr/default.nix +++ b/pkgs/lohr/default.nix @@ -1,22 +1,23 @@ { lib, fetchFromGitHub, rustPlatform }: rustPlatform.buildRustPackage rec { pname = "lohr"; - version = "0.4.0"; + version = "0.4.2"; src = fetchFromGitHub { owner = "alarsyo"; repo = "lohr"; rev = "v${version}"; - sha256 = "sha256-MplTVJG+SoeLMXQP+ix/zM3OSHuQmZnunn900YnyCBw="; + hash = "sha256-2pN/Me5fCdE++TzBUswPXzjuUIIB7Uck+Scp361JgE4="; }; - cargoSha256 = "sha256-iuMJj8tqetlmdfsrfudnU1afwUzjls/UdYLq1u0gr+g="; + cargoHash = "sha256-YHg4b6rKcnVJSDoWh9/o+p40NBog65Gd2/UwIDXiUe0="; meta = with lib; { description = "Git mirroring daemon"; homepage = "https://github.com/alarsyo/lohr"; license = with licenses; [ mit asl20 ]; - platforms = platforms.unix; + mainProgram = "lohr"; maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.unix; }; } diff --git a/pkgs/matrix-notifier/default.nix b/pkgs/matrix-notifier/default.nix index 76765a7..a96cb61 100644 --- a/pkgs/matrix-notifier/default.nix +++ b/pkgs/matrix-notifier/default.nix @@ -1,13 +1,13 @@ { lib, curl, jq, fetchFromGitHub, makeWrapper, pandoc, stdenvNoCC }: stdenvNoCC.mkDerivation rec { pname = "matrix-notifier"; - version = "0.2.0"; + version = "0.3.0"; src = fetchFromGitHub { owner = "ambroisie"; repo = "matrix-notifier"; rev = "v${version}"; - sha256 = "sha256-JiKPDrr9wyD2q5Vsac+OkFdvrDkx6mj/oC7XDVnka74="; + hash = "sha256-NE9RO0ep2ibrT9EUPGTnUE3ofdNTCHwelxnX9tCflg0="; }; nativeBuildInputs = [ @@ -36,9 +36,10 @@ stdenvNoCC.mkDerivation rec { A very simple bash script that can be used to send a message to a Matrix room ''; - homepage = "https://gitea.belanyi.fr/ambroisie/${pname}"; + homepage = "https://git.belanyi.fr/ambroisie/${pname}"; license = licenses.mit; - platforms = platforms.unix; + mainProgram = "matrix-notifier"; maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.unix; }; } diff --git a/pkgs/nolimips/default.nix b/pkgs/nolimips/default.nix deleted file mode 100644 index 65d847d..0000000 --- a/pkgs/nolimips/default.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ lib, fetchurl, stdenv }: -stdenv.mkDerivation rec { - pname = "nolimips"; - version = "0.11"; - - src = fetchurl { - url = "https://www.lrde.epita.fr/~tiger/download/${pname}-${version}.tar.gz"; - sha256 = "sha256-OjbfcBwCZtFP0usz8YXA0lN8xs0jS4I19mkh9p7VHc8="; - }; - - doCheck = true; - - meta = with lib; { - description = "A basic MIPS architecture simulator"; - longDescription = '' - A basic MIPS architecture simulator, which implements a few system calls - and supports an arbitrary number of registers. - ''; - homepage = "https://www.lrde.epita.fr/wiki/Nolimips"; - license = licenses.gpl2; - platforms = platforms.all; - maintainers = with maintainers; [ ambroisie ]; - }; -} diff --git a/pkgs/osc52/default.nix b/pkgs/osc52/default.nix new file mode 100644 index 0000000..d4b0c08 --- /dev/null +++ b/pkgs/osc52/default.nix @@ -0,0 +1,41 @@ +{ lib, coreutils, makeWrapper, stdenvNoCC }: +stdenvNoCC.mkDerivation rec { + pname = "osc52"; + version = "0.1.0"; + + src = ./osc52; + + nativeBuildInputs = [ + makeWrapper + ]; + + dontUnpack = true; + + dontBuild = true; + + installPhase = '' + mkdir -p $out/bin + cp $src $out/bin/osc52 + chmod a+x $out/bin/osc52 + ''; + + wrapperPath = lib.makeBinPath [ + coreutils + ]; + + fixupPhase = '' + patchShebangs $out/bin/osc52 + wrapProgram $out/bin/osc52 --prefix PATH : "${wrapperPath}" + ''; + + meta = with lib; { + description = '' + A script to copy strings using the OSC52 escape sequence + ''; + homepage = "https://git.belanyi.fr/ambroisie/nix-config"; + license = with licenses; [ mit ]; + mainProgram = "osc52"; + maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.linux; + }; +} diff --git a/pkgs/osc52/osc52 b/pkgs/osc52/osc52 new file mode 100755 index 0000000..f64ccb6 --- /dev/null +++ b/pkgs/osc52/osc52 @@ -0,0 +1,153 @@ +#!/usr/bin/env bash + +# Max length of the OSC 52 sequence. +: "${OSC52_MAX_SEQUENCE:=100000}" +# Whether to disable tmux/screen DCS escape sequences +: "${OSC52_NO_DCS:=0}" + +die() { + echo "ERROR: $*" + exit 1 +} + +usage() { + if [ $# -gt 0 ]; then + exec 1>&2 + fi + + cat << EOF +Usage: $0 [options] [string] +Send an arbitrary string to the terminal clipboard using the OSC 52 escape +sequence as specified in xterm: + https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands + Section "Operating System Commands", Ps => 52. +The data can either be read from stdin: + $ echo "hello world" | $0 +Or specified on the command line: + $ $0 "hello world" +Options: + -h, --help This screen. + -d, --no-dcs Disable tmux/screen specific DCS sequences, only use OSC 52 + -f, --force Ignore max byte limit (${OSC52_MAX_SEQUENCE}) + -- Stop options processing +EOF + + if [ $# -gt 0 ]; then + echo + die "$@" + else + exit 0 + fi +} + +tmux_seq() { + # shellcheck disable=1003 + printf '\033Ptmux;\033%s\033\\' "$1" +} + +screen_seq() { + # Screen limits the length of string sequences, so we have to break it up. + # Going by the screen history: + # (v4.2.1) Apr 2014 - today: 768 bytes + # Aug 2008 - Apr 2014 (v4.2.0): 512 bytes + # ??? - Aug 2008 (v4.0.3): 256 bytes + local limit=768 + # We go 4 bytes under the limit because we're going to insert two bytes + # before (\eP) and 2 bytes after (\e\) each string. + printf '%s' "$1" | + sed -E "s:.{$((limit - 4))}:&\n:g" | + sed -E -e 's:^:\x1bP:' -e 's:$:\x1b\\:' | + tr -d '\n' +} + +osc52_seq() { + printf '%s' "$1" +} + +print_seq() { + local seq="$1" + + if [ "${OSC52_NO_DCS}" != 0 ]; then + # Override TERM to avoid tmux/screen DCS escape logic + TERM=dummy + fi + + case ${TERM-} in + screen*) + # Since tmux defaults to setting TERM=screen, special case it. + if [ -n "${TMUX-}" ]; then + tmux_seq "${seq}" + else + screen_seq "${seq}" + fi + ;; + tmux*) + tmux_seq "${seq}" + ;; + *) + osc52_seq "${seq}" + ;; + esac +} + +b64enc() { + base64 | tr -d '\n' +} + +copy() { + local str + if [ $# -eq 0 ]; then + str="$(b64enc)" + else + str="$(printf '%s' "$1" | b64enc)" + fi + + if [ "${OSC52_MAX_SEQUENCE}" -gt 0 ]; then + local len=${#str} + if [ "${len}" -gt "${OSC52_MAX_SEQUENCE}" ]; then + die "selection too long to send to terminal:" \ + "${OSC52_MAX_SEQUENCE} limit, ${len} attempted" + fi + fi + + print_seq "$(printf '\033]52;c;%s\a' "${str}")" +} + +main() { + set -e + + local args=() + while [ $# -gt 0 ]; do + case $1 in + -h | --help) + usage + ;; + -f | --force) + OSC52_MAX_SEQUENCE=0 + ;; + -d | --no-dcs) + OSC52_NO_DCS=1 + ;; + --) + shift + args+=("$@") + break + ;; + -*) + usage "Unknown option: $1" + ;; + *) + args+=("$1") + ;; + esac + shift + done + + if [ "${#args[@]}" -gt 1 ]; then + usage "Only supply one argument" + fi + + copy "${args[@]}" +} + +main "$@" diff --git a/pkgs/psst/default.nix b/pkgs/psst/default.nix deleted file mode 100644 index 6eca44b..0000000 --- a/pkgs/psst/default.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ lib, alsa-lib, cairo, dbus, fetchFromGitHub, gtk3, openssl, pkg-config, rustPlatform }: -rustPlatform.buildRustPackage rec { - pname = "psst"; - version = "unstable-2022-01-13"; - - src = fetchFromGitHub { - owner = "jpochyla"; - repo = "psst"; - rev = "8f142a3232a706537c8477bff43d2e52309f6b78"; - sha256 = "sha256-YA9p6KHuZXt43OrfShO5d3Cj8L8GPpczRQlncJqM7QI="; - }; - - nativeBuildInputs = [ - pkg-config - ]; - - buildInputs = [ - alsa-lib - cairo - dbus - gtk3 - openssl - ]; - - cargoSha256 = "sha256-iA/ja7B73JyiXQ9kBzk1C5wtX+HPBrngCS+8rFDHbcs="; - - meta = with lib; { - description = "Fast and multi-platform Spotify client with native GUI"; - homepage = "https://github.com/jpochyla/psst"; - platforms = platforms.linux; - license = with licenses; [ mit ]; - maintainers = with maintainers; [ ambroisie ]; - }; -} diff --git a/pkgs/rbw-pass/default.nix b/pkgs/rbw-pass/default.nix new file mode 100644 index 0000000..6f9ff0a --- /dev/null +++ b/pkgs/rbw-pass/default.nix @@ -0,0 +1,41 @@ +{ lib, coreutils, makeWrapper, rbw, rofi, stdenvNoCC }: +stdenvNoCC.mkDerivation rec { + pname = "rbw-pass"; + version = "0.1.0"; + + src = ./rbw-pass; + + nativeBuildInputs = [ + makeWrapper + ]; + + dontUnpack = true; + + dontBuild = true; + + installPhase = '' + mkdir -p $out/bin + cp $src $out/bin/${pname} + chmod a+x $out/bin/${pname} + ''; + + wrapperPath = lib.makeBinPath [ + rbw + coreutils + rofi + ]; + + fixupPhase = '' + patchShebangs $out/bin/${pname} + wrapProgram $out/bin/${pname} --prefix PATH : "${wrapperPath}" + ''; + + meta = with lib; { + description = "A simple script to query a password from rbw"; + homepage = "https://git.belanyi.fr/ambroisie/nix-config"; + license = with licenses; [ mit ]; + mainProgram = "rbw-pass"; + maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.linux; + }; +} diff --git a/pkgs/rbw-pass/rbw-pass b/pkgs/rbw-pass/rbw-pass new file mode 100755 index 0000000..90e916c --- /dev/null +++ b/pkgs/rbw-pass/rbw-pass @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +usage() { + printf '%s\n' "Usage: bw-pass [directory name] " >&2 +} + +error_out() { + printf '%s\n' "$1" >&2 + rofi -dmenu -no-fixed-num-lines -p "$1" + exit 1 +} + +ensure_logged_in() { + rbw login +} + +query_password() { + # Either use with `query_password + # Or `query_password ` when the account has no directory + + local FOLDER_ARGS=() + local PASSWORD + + # FIXME: no way to enforce filering by "no folder" + if [ $# -eq 2 ]; then + FOLDER_ARGS+=(--folder "$1") + shift + fi + PASSWORD="$(rbw get "${FOLDER_ARGS[@]}" "$1")" + + if [ -z "$PASSWORD" ]; then + error_out "Did not find password for '$1'" + fi + printf '%s\n' "$PASSWORD" +} + +if [ $# -lt 1 ] || [ $# -gt 2 ]; then + usage + exit 1 +fi + +ensure_logged_in +query_password "$@" diff --git a/pkgs/rofi-bluetooth/default.nix b/pkgs/rofi-bluetooth/default.nix deleted file mode 100644 index 2ff40a1..0000000 --- a/pkgs/rofi-bluetooth/default.nix +++ /dev/null @@ -1,40 +0,0 @@ -{ lib, bluez, fetchFromGitHub, makeWrapper, rofi, stdenvNoCC }: -stdenvNoCC.mkDerivation rec { - pname = "rofi-bluetooth"; - version = "unstable-2021-10-15"; - - src = fetchFromGitHub { - owner = "nickclyde"; - repo = "rofi-bluetooth"; - rev = "893db1f2b549e7bc0e9c62e7670314349a29cdf2"; - sha256 = "sha256-3oROJKEQCuSnLfbJ+JSSc9hcmJTPrLHRQJsrUcaOMss="; - }; - - buildInputs = [ - makeWrapper - ]; - - installPhase = '' - mkdir -p $out/bin - cp $src/rofi-bluetooth $out/bin/ - chmod a+x $out/bin/rofi-bluetooth - ''; - - wrapperPath = lib.makeBinPath [ - rofi - bluez - ]; - - fixupPhase = '' - patchShebangs $out/bin/${pname} - wrapProgram $out/bin/${pname} --prefix PATH : "${wrapperPath}" - ''; - - meta = with lib; { - description = "A rofi menu for managing bluetooth connections"; - homepage = "https://github.com/nickclyde/rofi-bluetooth/commit/"; - license = with licenses; [ gpl3Only ]; - platforms = platforms.linux; - maintainers = with maintainers; [ ambroisie ]; - }; -} diff --git a/pkgs/unbound-zones-adblock/default.nix b/pkgs/unbound-zones-adblock/default.nix index ecec917..b8392ae 100644 --- a/pkgs/unbound-zones-adblock/default.nix +++ b/pkgs/unbound-zones-adblock/default.nix @@ -1,5 +1,5 @@ { lib, gawk, stdenvNoCC, unified-hosts-lists }: -stdenvNoCC.mkDerivation rec { +stdenvNoCC.mkDerivation { name = "unbound-zones-adblock"; version = unified-hosts-lists.version; @@ -10,7 +10,7 @@ stdenvNoCC.mkDerivation rec { installPhase = let gawkCmd = lib.concatStringsSep " " [ - ''${gawk}/bin/awk'' + (lib.getExe gawk) '''{sub(/\r$/,"")}'' ''{sub(/^127\.0\.0\.1/,"0.0.0.0")}'' ''BEGIN { OFS = "" }'' @@ -32,7 +32,7 @@ stdenvNoCC.mkDerivation rec { ''; homepage = "https://github.com/StevenBlack/hosts"; license = licenses.mit; - platforms = platforms.all; maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.all; }; } diff --git a/pkgs/unified-hosts-lists/default.nix b/pkgs/unified-hosts-lists/default.nix index 4b0e0c6..06d24ac 100644 --- a/pkgs/unified-hosts-lists/default.nix +++ b/pkgs/unified-hosts-lists/default.nix @@ -1,13 +1,13 @@ { lib, fetchFromGitHub, stdenvNoCC }: stdenvNoCC.mkDerivation rec { pname = "unified-hosts-lists"; - version = "3.9.11"; + version = "3.12.15"; src = fetchFromGitHub { owner = "StevenBlack"; repo = "hosts"; rev = version; - sha256 = "sha256-JFz6M0Mkwoby7I6LLWx0QfvZMzwET2FEQ1OGKQnFfho="; + hash = "sha256-HoNX57lCoIr36B/7HMuazWSWeAPPfWY1oZf6dXnxYIE="; }; dontUnpack = true; @@ -28,7 +28,7 @@ stdenvNoCC.mkDerivation rec { ''; homepage = "https://github.com/StevenBlack/hosts"; license = licenses.mit; - platforms = platforms.all; maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.all; }; } diff --git a/pkgs/vimix-cursors/default.nix b/pkgs/vimix-cursors/default.nix index 1bbbe4e..80424de 100644 --- a/pkgs/vimix-cursors/default.nix +++ b/pkgs/vimix-cursors/default.nix @@ -10,7 +10,7 @@ stdenvNoCC.mkDerivation rec { owner = "vinceliuice"; repo = pname; rev = "27ebb1935944bc986bf8ae85ee3343b8351d9823"; - sha256 = "sha256-bIPRrKaNQ2Eo+T6zv7qeA1z7uRHXezM0yxh+uqA01Gs="; + hash = "sha256-bIPRrKaNQ2Eo+T6zv7qeA1z7uRHXezM0yxh+uqA01Gs="; }; nativeBuildInputs = [ @@ -38,7 +38,7 @@ stdenvNoCC.mkDerivation rec { description = "An X cursor theme inspired by Materia design"; homepage = "https://github.com/vinceliuice/Vimix-cursors"; license = licenses.gpl3Only; - platforms = platforms.linux; maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.linux; }; } diff --git a/pkgs/volantes-cursors/default.nix b/pkgs/volantes-cursors/default.nix index e300a36..b2c7865 100644 --- a/pkgs/volantes-cursors/default.nix +++ b/pkgs/volantes-cursors/default.nix @@ -7,7 +7,7 @@ stdenvNoCC.mkDerivation rec { owner = "varlesh"; repo = pname; rev = "d1d290ff42cc4fa643716551bd0b02582b90fd2f"; - sha256 = "sha256-irMN/enoo90nYLfvSOScZoYdvhZKvqqp+grZB2BQD9o="; + hash = "sha256-irMN/enoo90nYLfvSOScZoYdvhZKvqqp+grZB2BQD9o="; }; nativeBuildInputs = [ @@ -38,7 +38,7 @@ stdenvNoCC.mkDerivation rec { description = "Classic cursor with a flying style"; homepage = "https://github.com/varlesh/volantes-cursors"; license = licenses.gpl2Only; - platforms = platforms.linux; maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.linux; }; } diff --git a/pkgs/wifi-qr/default.nix b/pkgs/wifi-qr/default.nix new file mode 100644 index 0000000..88164e5 --- /dev/null +++ b/pkgs/wifi-qr/default.nix @@ -0,0 +1,81 @@ +{ lib +, fetchFromGitHub +, gnome +, installShellFiles +, makeWrapper +, networkmanager +, qrencode +, stdenvNoCC +, xdg-utils +, zbar +}: +stdenvNoCC.mkDerivation rec { + pname = "wifi-qr"; + version = "unstable-2023-04-19"; + + outputs = [ "out" "man" ]; + + src = fetchFromGitHub { + owner = "kokoye2007"; + repo = "wifi-qr"; + rev = "b81d4a44257252f07e745464879aa5618ae3d434"; + hash = "sha256-oGTAr+raJGpK4PV4GdBxX8fIUE8gcbXw7W0SvQJAee0="; + }; + + nativeBuildInputs = [ + installShellFiles + makeWrapper + ]; + + dontBuild = true; + + dontConfigure = true; + + postPatch = '' + substituteInPlace wifi-qr.desktop \ + --replace "Exec=sh -c 'wifi-qr g'" "Exec=$out/bin/wifi-qr g" \ + --replace "Exec=sh -c 'wifi-qr q'" "Exec=$out/bin/wifi-qr q" \ + --replace "Exec=sh -c 'wifi-qr p'" "Exec=$out/bin/wifi-qr p" \ + --replace "Exec=sh -c 'wifi-qr c'" "Exec=$out/bin/wifi-qr c" \ + --replace "Icon=wifi-qr.svg" "Icon=wifi-qr" + ''; + + installPhase = '' + runHook preInstall + + install -Dm755 wifi-qr $out/bin/wifi-qr + + install -Dm644 wifi-qr.desktop $out/share/applications/wifi-qr.desktop + install -Dm644 wifi-qr.svg $out/share/icons/hicolor/scalable/apps/wifi-qr.svg + + installManPage wifi-qr.1 + + runHook postInstall + ''; + + wrapperPath = lib.makeBinPath [ + gnome.zenity + networkmanager + qrencode + xdg-utils + zbar + ]; + + fixupPhase = '' + runHook preFixup + + patchShebangs $out/bin/wifi-qr + wrapProgram $out/bin/wifi-qr --suffix PATH : "${wrapperPath}" + + runHook postFixup + ''; + + meta = with lib; { + description = "WiFi password sharing via QR codes"; + homepage = "https://github.com/kokoye2007/wifi-qr"; + license = with licenses; [ gpl3Plus ]; + mainProgram = "wifi-qr"; + maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.linux; + }; +} diff --git a/profiles/default.nix b/profiles/default.nix index 43d5a84..f7914a1 100644 --- a/profiles/default.nix +++ b/profiles/default.nix @@ -6,6 +6,7 @@ ./devices ./gtk ./laptop + ./printing ./wm ./x ]; diff --git a/profiles/devices/default.nix b/profiles/devices/default.nix index 54088b3..7dbd299 100644 --- a/profiles/devices/default.nix +++ b/profiles/devices/default.nix @@ -13,5 +13,8 @@ in mx-ergo.enable = true; }; + + # MTP devices auto-mount via file explorers + services.gvfs.enable = true; }; } diff --git a/profiles/gtk/default.nix b/profiles/gtk/default.nix index 61a3edc..a8d6d9a 100644 --- a/profiles/gtk/default.nix +++ b/profiles/gtk/default.nix @@ -4,7 +4,7 @@ let in { options.my.profiles.gtk = with lib; { - enable = mkEnableOption "bluetooth profile"; + enable = mkEnableOption "gtk profile"; }; config = lib.mkIf cfg.enable { diff --git a/profiles/printing/default.nix b/profiles/printing/default.nix new file mode 100644 index 0000000..9965797 --- /dev/null +++ b/profiles/printing/default.nix @@ -0,0 +1,69 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.my.profiles.printing; +in +{ + options.my.profiles.printing = with lib; { + enable = mkEnableOption "printing profile"; + + papersize = mkOption { + type = with types; either str (enum [ + "a3" + "a4" + "a5" + "b5" + "letter" + "legal" + "executive" + "note" + "11x17" + ]); + default = "a4"; + example = "paper"; + description = "preferred paper size"; + }; + + usb = { + enable = my.mkDisableOption "USB printers"; + }; + + network = { + enable = my.mkDisableOption "network printers"; + }; + }; + + config = lib.mkIf cfg.enable { + # Setup CUPS + services.printing = { + enable = true; + + # Drivers are deprecated, but just in case + drivers = with pkgs; [ + gutenprint # Base set of drivers + brlaser # Brother drivers + + # Brother MFC-L3770CDW + mfcl3770cdwlpr + mfcl3770cdwcupswrapper + ]; + }; + + # Setup paper size + systemd.services.cups.serviceConfig.Environment = [ + "PAPERSIZE=${cfg.papersize}" + ]; + + # Allow using USB printers + services.ipp-usb = lib.mkIf cfg.usb.enable { + enable = true; + }; + + # Allow using WiFi printers + services.avahi = lib.mkIf cfg.network.enable { + enable = true; + openFirewall = true; + # Allow resolution of '.local' addresses + nssmdns = true; + }; + }; +} diff --git a/profiles/wm/default.nix b/profiles/wm/default.nix index 473d49d..c227328 100644 --- a/profiles/wm/default.nix +++ b/profiles/wm/default.nix @@ -22,6 +22,8 @@ in my.home.flameshot.enable = true; # Auto disk mounter my.home.udiskie.enable = true; + # udiskie fails if it can't find this dbus service + services.udisks2.enable = true; }) ]; } diff --git a/profiles/x/default.nix b/profiles/x/default.nix index e9d9cfd..ea77939 100644 --- a/profiles/x/default.nix +++ b/profiles/x/default.nix @@ -13,7 +13,7 @@ in # Nice wallpaper services.xserver.displayManager.lightdm.background = let - wallpapers = "${pkgs.plasma-workspace-wallpapers}/share/wallpapers"; + wallpapers = "${pkgs.plasma5Packages.plasma-workspace-wallpapers}/share/wallpapers"; in "${wallpapers}/summer_1am/contents/images/2560x1600.jpg"; diff --git a/templates/c++-cmake/.clang-format b/templates/c++-cmake/.clang-format new file mode 100644 index 0000000..19c58aa --- /dev/null +++ b/templates/c++-cmake/.clang-format @@ -0,0 +1,23 @@ +# vim: ft=yaml +--- +BasedOnStyle: LLVM +IndentWidth: 4 +--- +Language: Cpp +# Force pointers to the type for C++. +DerivePointerAlignment: false +PointerAlignment: Left + +# Short functions should not be on a single line, unless empty +AllowShortFunctionsOnASingleLine: Empty + +# Make them level +AccessModifierOffset: -4 + +# It makes more sense this way +BreakBeforeBinaryOperators: All +BreakBeforeTernaryOperators: true + +# Aesthetic +AlignOperands: AlignAfterOperator +--- diff --git a/templates/c++-cmake/.envrc b/templates/c++-cmake/.envrc new file mode 100644 index 0000000..95ed6fb --- /dev/null +++ b/templates/c++-cmake/.envrc @@ -0,0 +1,10 @@ +if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs=" +fi + +use flake + +watch_file ./flake/checks.nix +watch_file ./flake/dev-shells.nix + +eval "$shellHooks" diff --git a/templates/c++-cmake/.gitignore b/templates/c++-cmake/.gitignore new file mode 100644 index 0000000..09ba440 --- /dev/null +++ b/templates/c++-cmake/.gitignore @@ -0,0 +1,7 @@ +# CMake build directories +/build +/build-* + +# Nix generated files +/.pre-commit-config.yaml +/result diff --git a/templates/c++-cmake/.woodpecker/check.yml b/templates/c++-cmake/.woodpecker/check.yml new file mode 100644 index 0000000..c3b00ef --- /dev/null +++ b/templates/c++-cmake/.woodpecker/check.yml @@ -0,0 +1,26 @@ +labels: + type: exec + +pipeline: +- name: nix flake check + image: bash + commands: + - nix flake check + +- name: notifiy + image: bash + secrets: + - source: matrix_homeserver + target: address + - source: matrix_roomid + target: room + - source: matrix_username + target: user + - source: matrix_password + target: pass + commands: + - nix run '.#matrix-notifier' + when: + status: + - failure + - success diff --git a/templates/c++-cmake/CMakeLists.txt b/templates/c++-cmake/CMakeLists.txt new file mode 100644 index 0000000..122d8b3 --- /dev/null +++ b/templates/c++-cmake/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.10) +project(project VERSION 0.0.0 LANGUAGES CXX) +enable_testing() + +add_library(common_options INTERFACE) +target_compile_features(common_options INTERFACE + cxx_std_20 +) +target_compile_options(common_options INTERFACE + -Wall + -Wextra +) +target_include_directories(common_options INTERFACE + src +) + +add_subdirectory(src) +add_subdirectory(tests) diff --git a/templates/c++-cmake/flake.nix b/templates/c++-cmake/flake.nix new file mode 100644 index 0000000..cb468e7 --- /dev/null +++ b/templates/c++-cmake/flake.nix @@ -0,0 +1,112 @@ +{ + description = "A C++ project"; + + inputs = { + futils = { + type = "github"; + owner = "numtide"; + repo = "flake-utils"; + ref = "main"; + }; + + nixpkgs = { + type = "github"; + owner = "NixOS"; + repo = "nixpkgs"; + ref = "nixos-unstable"; + }; + + pre-commit-hooks = { + type = "github"; + owner = "cachix"; + repo = "pre-commit-hooks.nix"; + ref = "master"; + inputs = { + flake-utils.follows = "futils"; + nixpkgs.follows = "nixpkgs"; + }; + }; + }; + + outputs = { self, futils, nixpkgs, pre-commit-hooks }: + { + overlays = { + default = final: _prev: { + project = with final; stdenv.mkDerivation { + pname = "project"; + version = "0.0.0"; + + src = self; + + nativeBuildInputs = with pkgs; [ + cmake + ninja + pkg-config + ]; + + checkInputs = with pkgs; [ + gtest + ]; + + doCheck = true; + + meta = with lib; { + description = "A C++ project"; + homepage = "https://gitea.belanyi.fr/ambroisie/project"; + license = licenses.mit; + maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.unix; + }; + }; + }; + }; + } // futils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ + self.overlays.default + ]; + }; + + pre-commit = pre-commit-hooks.lib.${system}.run { + src = self; + + hooks = { + nixpkgs-fmt = { + enable = true; + }; + + clang-format = { + enable = true; + }; + }; + }; + in + { + checks = { + inherit (self.packages.${system}) project; + + inherit pre-commit; + }; + + devShells = { + default = pkgs.mkShell { + inputsFrom = with self.packages.${system}; [ + project + ]; + + packages = with pkgs; [ + clang-tools + ]; + + inherit (pre-commit) shellHook; + }; + }; + + packages = futils.lib.flattenTree { + default = pkgs.project; + inherit (pkgs) project; + }; + }); +} diff --git a/templates/c++-cmake/src/CMakeLists.txt b/templates/c++-cmake/src/CMakeLists.txt new file mode 100644 index 0000000..d91cef1 --- /dev/null +++ b/templates/c++-cmake/src/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(project main.cc) +target_link_libraries(project PRIVATE common_options) + +install(TARGETS project) diff --git a/templates/c++-cmake/src/main.cc b/templates/c++-cmake/src/main.cc new file mode 100644 index 0000000..5eb9e4a --- /dev/null +++ b/templates/c++-cmake/src/main.cc @@ -0,0 +1,5 @@ +#include + +int main() { + std::cout << "Hello World!\n"; +} diff --git a/templates/c++-cmake/tests/CMakeLists.txt b/templates/c++-cmake/tests/CMakeLists.txt new file mode 100644 index 0000000..269aea0 --- /dev/null +++ b/templates/c++-cmake/tests/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(unit) diff --git a/templates/c++-cmake/tests/unit/CMakeLists.txt b/templates/c++-cmake/tests/unit/CMakeLists.txt new file mode 100644 index 0000000..bb94448 --- /dev/null +++ b/templates/c++-cmake/tests/unit/CMakeLists.txt @@ -0,0 +1,15 @@ +find_package(GTest) + +if (${GTest_FOUND}) +include(GoogleTest) + +add_executable(dummy_test dummy_test.cc) +target_link_libraries(dummy_test PRIVATE common_options) + +target_link_libraries(dummy_test PRIVATE + GTest::gtest + GTest::gtest_main +) + +gtest_discover_tests(dummy_test) +endif (${GTest_FOUND}) diff --git a/templates/c++-cmake/tests/unit/dummy_test.cc b/templates/c++-cmake/tests/unit/dummy_test.cc new file mode 100644 index 0000000..4573678 --- /dev/null +++ b/templates/c++-cmake/tests/unit/dummy_test.cc @@ -0,0 +1,5 @@ +#include + +TEST(misc, passing) { + ASSERT_EQ(1, 1); +} diff --git a/templates/c++-meson/.clang-format b/templates/c++-meson/.clang-format new file mode 100644 index 0000000..19c58aa --- /dev/null +++ b/templates/c++-meson/.clang-format @@ -0,0 +1,23 @@ +# vim: ft=yaml +--- +BasedOnStyle: LLVM +IndentWidth: 4 +--- +Language: Cpp +# Force pointers to the type for C++. +DerivePointerAlignment: false +PointerAlignment: Left + +# Short functions should not be on a single line, unless empty +AllowShortFunctionsOnASingleLine: Empty + +# Make them level +AccessModifierOffset: -4 + +# It makes more sense this way +BreakBeforeBinaryOperators: All +BreakBeforeTernaryOperators: true + +# Aesthetic +AlignOperands: AlignAfterOperator +--- diff --git a/templates/c++-meson/.envrc b/templates/c++-meson/.envrc new file mode 100644 index 0000000..95ed6fb --- /dev/null +++ b/templates/c++-meson/.envrc @@ -0,0 +1,10 @@ +if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs=" +fi + +use flake + +watch_file ./flake/checks.nix +watch_file ./flake/dev-shells.nix + +eval "$shellHooks" diff --git a/templates/c++-meson/.gitignore b/templates/c++-meson/.gitignore new file mode 100644 index 0000000..09ba440 --- /dev/null +++ b/templates/c++-meson/.gitignore @@ -0,0 +1,7 @@ +# CMake build directories +/build +/build-* + +# Nix generated files +/.pre-commit-config.yaml +/result diff --git a/templates/c++-meson/.woodpecker/check.yml b/templates/c++-meson/.woodpecker/check.yml new file mode 100644 index 0000000..c3b00ef --- /dev/null +++ b/templates/c++-meson/.woodpecker/check.yml @@ -0,0 +1,26 @@ +labels: + type: exec + +pipeline: +- name: nix flake check + image: bash + commands: + - nix flake check + +- name: notifiy + image: bash + secrets: + - source: matrix_homeserver + target: address + - source: matrix_roomid + target: room + - source: matrix_username + target: user + - source: matrix_password + target: pass + commands: + - nix run '.#matrix-notifier' + when: + status: + - failure + - success diff --git a/templates/c++-meson/flake.nix b/templates/c++-meson/flake.nix new file mode 100644 index 0000000..9cfed0d --- /dev/null +++ b/templates/c++-meson/flake.nix @@ -0,0 +1,112 @@ +{ + description = "A C++ project"; + + inputs = { + futils = { + type = "github"; + owner = "numtide"; + repo = "flake-utils"; + ref = "main"; + }; + + nixpkgs = { + type = "github"; + owner = "NixOS"; + repo = "nixpkgs"; + ref = "nixos-unstable"; + }; + + pre-commit-hooks = { + type = "github"; + owner = "cachix"; + repo = "pre-commit-hooks.nix"; + ref = "master"; + inputs = { + flake-utils.follows = "futils"; + nixpkgs.follows = "nixpkgs"; + }; + }; + }; + + outputs = { self, futils, nixpkgs, pre-commit-hooks }: + { + overlays = { + default = final: _prev: { + project = with final; stdenv.mkDerivation { + pname = "project"; + version = "0.0.0"; + + src = self; + + nativeBuildInputs = with pkgs; [ + meson + ninja + pkg-config + ]; + + checkInputs = with pkgs; [ + gtest + ]; + + doCheck = true; + + meta = with lib; { + description = "A C++ project"; + homepage = "https://gitea.belanyi.fr/ambroisie/project"; + license = licenses.mit; + maintainers = with maintainers; [ ambroisie ]; + platforms = platforms.unix; + }; + }; + }; + }; + } // futils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ + self.overlays.default + ]; + }; + + pre-commit = pre-commit-hooks.lib.${system}.run { + src = self; + + hooks = { + nixpkgs-fmt = { + enable = true; + }; + + clang-format = { + enable = true; + }; + }; + }; + in + { + checks = { + inherit (self.packages.${system}) project; + + inherit pre-commit; + }; + + devShells = { + default = pkgs.mkShell { + inputsFrom = with self.packages.${system}; [ + project + ]; + + packages = with pkgs; [ + clang-tools + ]; + + inherit (pre-commit) shellHook; + }; + }; + + packages = futils.lib.flattenTree { + default = pkgs.project; + inherit (pkgs) project; + }; + }); +} diff --git a/templates/c++-meson/meson.build b/templates/c++-meson/meson.build new file mode 100644 index 0000000..bc228c6 --- /dev/null +++ b/templates/c++-meson/meson.build @@ -0,0 +1,13 @@ +project( + 'project', + 'cpp', + version : '0.0.0', + license: 'MIT', + default_options : [ + 'cpp_std=c++20', + 'warning_level=3', + ], +) + +subdir('src') +subdir('tests') diff --git a/templates/c++-meson/src/main.cc b/templates/c++-meson/src/main.cc new file mode 100644 index 0000000..5eb9e4a --- /dev/null +++ b/templates/c++-meson/src/main.cc @@ -0,0 +1,5 @@ +#include + +int main() { + std::cout << "Hello World!\n"; +} diff --git a/templates/c++-meson/src/meson.build b/templates/c++-meson/src/meson.build new file mode 100644 index 0000000..4b2ff23 --- /dev/null +++ b/templates/c++-meson/src/meson.build @@ -0,0 +1,8 @@ +sources = files( + 'main.cc', +) + +executable( + 'project', + sources : sources, +) diff --git a/templates/c++-meson/tests/meson.build b/templates/c++-meson/tests/meson.build new file mode 100644 index 0000000..082b746 --- /dev/null +++ b/templates/c++-meson/tests/meson.build @@ -0,0 +1 @@ +subdir('unit') diff --git a/templates/c++-meson/tests/unit/dummy_test.cc b/templates/c++-meson/tests/unit/dummy_test.cc new file mode 100644 index 0000000..4573678 --- /dev/null +++ b/templates/c++-meson/tests/unit/dummy_test.cc @@ -0,0 +1,5 @@ +#include + +TEST(misc, passing) { + ASSERT_EQ(1, 1); +} diff --git a/templates/c++-meson/tests/unit/meson.build b/templates/c++-meson/tests/unit/meson.build new file mode 100644 index 0000000..44c8a92 --- /dev/null +++ b/templates/c++-meson/tests/unit/meson.build @@ -0,0 +1,13 @@ +gtest_dep = dependency( + 'gtest', + main : true, + required : false, +) + +dummy_test = executable( + 'dummy_test', + 'dummy_test.cc', + dependencies : gtest_dep, +) + +test('dummy test', dummy_test) diff --git a/templates/default.nix b/templates/default.nix new file mode 100644 index 0000000..f58fd72 --- /dev/null +++ b/templates/default.nix @@ -0,0 +1,10 @@ +{ + "c++-cmake" = { + path = ./c++-cmake; + description = "A C++ project using CMake"; + }; + "c++-meson" = { + path = ./c++-meson; + description = "A C++ project using CMake"; + }; +}