{ config, flakeInputs, pkgs, lib, system, ... }: with lib; let inherit (flakeInputs.home-manager.lib) hm; databasePath = "${config.xdg.dataHome}/feeds"; imm = let hlib = pkgs.haskell.lib; haskellPackages = pkgs.haskellPackages.override { overrides = finalHaskell: prevHaskell: { uri-bytestring = finalHaskell.callCabal2nix "uri-bytestring" (pkgs.fetchFromGitHub { owner = "gkleen"; repo = "uri-bytestring"; rev = "5f7f32c8274bc4d1b81d99582f5148fe3e8b637e"; sha256 = "XLanwyCDIlMuOkpE5LbTNOBfL+1kZX+URfj9Bhs1Nsc="; fetchSubmodules = true; }) {}; atom-conduit = finalHaskell.callCabal2nix "atom-conduit" (pkgs.fetchFromGitHub { owner = "gkleen"; repo = "atom-conduit"; rev = "022f0182a02373f87c06a0a09817c8c41efe2425"; sha256 = "8yEyh3ymqkoM/YP+eBqPq1I5ofzj0Qn7ojL7IWx1DPo="; fetchSubmodules = true; }) {}; rss-conduit = finalHaskell.callCabal2nix "rss-condit" (pkgs.fetchFromGitHub { owner = "gkleen"; repo = "rss-conduit"; rev = "dbb0960a8d3dc519f1607aa0223b3a25a49282ef"; sha256 = "Md1XApZWkdv4JvNoaVnjz0S85LbEC6w9U3PUcwXfu94="; fetchSubmodules = true; }) {}; beam-core = hlib.doJailbreak (finalHaskell.callCabal2nix "beam-core" "${beamSrc}/beam-core" {}); beam-migrate = hlib.doJailbreak (finalHaskell.callCabal2nix "beam-migrate" "${beamSrc}/beam-migrate" {}); beam-sqlite = hlib.doJailbreak (finalHaskell.callCabal2nix "beam-sqlite" "${beamSrc}/beam-sqlite" {}); imm = finalHaskell.callCabal2nix "imm" (pkgs.fetchFromGitHub { owner = "k0ral"; repo = "imm"; rev = "5033879667264cb44cee65671a66f6aa43f249e7"; sha256 = "PG22caLQmAGhLZP49HsazuNd8IFKKaTuhXIQBD8v4Fs="; fetchSubmodules = true; }) {}; }; }; beamSrc = pkgs.fetchFromGitHub { owner = "haskell-beam"; repo = "beam"; rev = "efd464b079755a781c2bb7a2fc030d6c141bbb8a"; sha256 = "8nTuBP/vD0L/qMo4h3XNrGZvpIwXuMVdj40j5gvHU6w="; fetchSubmodules = true; }; in haskellPackages.imm; immWrapped = pkgs.runCommand "${imm.name}-wrapped-${config.home.username}" { nativeBuildInputs = with pkgs; [ makeWrapper ]; } '' mkdir -p $out/bin makeWrapper ${imm}/bin/imm $out/bin/imm \ --add-flags --callbacks=${notmuchCallbacks} ''; notmuchCallbacks = pkgs.writeText "imm-callbacks-${config.home.username}.dhall" '' [ { _executable = "${immNotmuchInsert}/bin/imm-notmuch-insert" , _arguments = [] : List Text } ] ''; immNotmuchInsert = pkgs.stdenv.mkDerivation rec { name = "imm-notmuch-insert-${config.home.username}"; src = ./imm-notmuch-insert.py; phases = [ "buildPhase" "checkPhase" "installPhase" "fixupPhase" ]; python = pkgs.python39.withPackages (ps: with ps; [ configparser python-dateutil html2text ]); nativeBuildInputs = with pkgs; [ makeWrapper ]; buildPhase = '' substituteAll $src imm-notmuch-insert ''; doCheck = true; checkPhase = '' ${python}/bin/python -m py_compile imm-notmuch-insert ''; installPhase = '' install -m 0755 -D -t $out/bin \ imm-notmuch-insert ''; fixupPhase = '' wrapProgram $out/bin/imm-notmuch-insert \ --prefix PATH : ${pkgs.notmuch}/bin \ --set NOTMUCH_CONFIG ${configPath} ''; }; mkIniKeyValue = key: value: let tweakVal = v: if isString v then v else if isList v then concatMapStringsSep ";" tweakVal v else if isBool v then (if v then "true" else "false") else toString v; in "${key}=${tweakVal value}"; notmuchIni = { database = { path = databasePath; }; maildir = { synchronize_flags = false; }; new = { ignore = []; tags = ["new"]; }; user = { name = config.home.username; primary_email = "${config.home.username}@imm.invalid"; }; search = { exclude_tags = ["deleted"]; }; }; configPath = pkgs.writeText "notmuchrc" (generators.toINI { mkKeyValue = mkIniKeyValue; } notmuchIni); afewConfigDir = pkgs.symlinkJoin { name = "afew-config"; paths = [ (pkgs.writeTextDir "config" '' [InboxFilter] '') ]; }; notmuchHooksDir = let afewHook = pkgs.writeShellScript "afew" '' exec -- ${pkgs.afew}/bin/afew -c ${afewConfigDir} -C ${configPath} --tag --new -vv ''; in pkgs.linkFarm "notmuch-hooks" [ { name = "post-new"; path = afewHook; } { name = "post-insert"; path = afewHook; } ]; notmuchWrapped = pkgs.runCommand "${pkgs.notmuch.name}-wrapped-${config.home.username}" { nativeBuildInputs = with pkgs; [ makeWrapper ]; } '' mkdir -p $out/bin makeWrapper ${pkgs.notmuch}/bin/notmuch $out/bin/notmuch-feeds \ --set NOTMUCH_CONFIG ${configPath} ''; alotWrapped = pkgs.runCommand "${pkgs.alot.name}-wrapped-${config.home.username}" { nativeBuildInputs = with pkgs; [ makeWrapper gnused ]; } '' mkdir -p $out/bin makeWrapper ${pkgs.alot}/bin/alot $out/bin/alot-feeds \ --prefix MAILCAPS : ${alotMailcaps} \ --add-flags --config=${alotConfig} \ --add-flags --notmuch-config=${configPath} mkdir $out/share ln -s ${pkgs.alot}/share/alot $out/share mkdir -p $out/share/applications sed -r 's/alot/alot-feeds/g' ${pkgs.alot}/share/applications/alot.desktop > $out/share/applications/alot-feeds.desktop mkdir -p $out/share/zsh/site-functions sed -r 's/alot/alot-feeds/g' ${pkgs.alot}/share/zsh/site-functions/_alot > $out/share/zsh/site-functions/_alot-feeds ''; alotConfig = pkgs.runCommand "alot" { realname = notmuchIni.user.name; address = notmuchIni.user.primary_email; } "substituteAll ${./alot.config} $out"; alotMailcaps = pkgs.writeText "mailcaps" '' text/html; ${pkgs.lynx}/bin/lynx -dump -dont_wrap_pre -assume_charset=utf-8 -display_charset=utf-8 "%s"; nametemplate=%s.html; copiousoutput ''; in { config = { home.packages = [ immWrapped notmuchWrapped pkgs.notmuch.man alotWrapped ]; home.activation.createImm = hm.dag.entryAfter ["writeBoundary"] '' $DRY_RUN_CMD mkdir -p $VERBOSE_ARG ${config.xdg.configHome}/imm ''; home.activation.createFeedsDatabase = hm.dag.entryAfter ["linkGeneration" "writeBoundary"] '' $DRY_RUN_CMD mkdir -p -m 0750 $VERBOSE_ARG ${databasePath} $DRY_RUN_CMD mkdir -p $VERBOSE_ARG ${databasePath}/new ${databasePath}/cur ${databasePath}/tmp if ! [[ -d ${databasePath}/.notmuch ]]; then NOTMUCH_VERBOSE_ARG="--quiet" if [[ -v VERBOSE ]]; then NOTMUCH_VERBOSE_ARG="--verbose" fi NOTMUCH_CONFIG=${configPath} $DRY_RUN_CMD ${pkgs.notmuch}/bin/notmuch new $NOTMUCH_VERBOSE_ARG fi $DRY_RUN_CMD ln -Tsf $VERBOSE_ARG ${notmuchHooksDir} ${databasePath}/.notmuch/hooks ''; systemd.user.services."logrotate-imm" = { Unit = { Description = "Rotate imm logfile"; }; Service = { Type = "oneshot"; ExecStart = '' ${pkgs.logrotate}/bin/logrotate --state ${config.xdg.configHome}/imm/imm.logrotate ${pkgs.writeText "logrotate.conf" '' ${config.xdg.configHome}/imm/imm.log { rotate 5 size 1024k } ''} ''; }; }; systemd.user.timers."logrotate-imm" = { Timer = { OnActiveSec = "6h"; OnUnitActiveSec = "6h"; }; Install = { WantedBy = ["default.target"]; }; }; }; }