diff options
-rw-r--r-- | overlays/worktime/default.nix | 7 | ||||
-rw-r--r-- | user-profiles/feeds/default.nix | 25 | ||||
-rw-r--r-- | user-profiles/feeds/imm-notmuch-insert.py | 37 | ||||
-rw-r--r-- | user-profiles/feeds/module.nix | 114 |
4 files changed, 166 insertions, 17 deletions
diff --git a/overlays/worktime/default.nix b/overlays/worktime/default.nix index ab6fb40a..a8fe79c6 100644 --- a/overlays/worktime/default.nix +++ b/overlays/worktime/default.nix | |||
@@ -3,7 +3,7 @@ final: prev: { | |||
3 | name = "worktime"; | 3 | name = "worktime"; |
4 | src = ./worktime.py; | 4 | src = ./worktime.py; |
5 | 5 | ||
6 | phases = [ "buildPhase" "installPhase" ]; | 6 | phases = [ "buildPhase" "checkPhase" "installPhase" ]; |
7 | 7 | ||
8 | python = prev.python39.withPackages (ps: with ps; [pyxdg dateutil uritools requests configparser tabulate]); | 8 | python = prev.python39.withPackages (ps: with ps; [pyxdg dateutil uritools requests configparser tabulate]); |
9 | 9 | ||
@@ -11,6 +11,11 @@ final: prev: { | |||
11 | substituteAll $src worktime | 11 | substituteAll $src worktime |
12 | ''; | 12 | ''; |
13 | 13 | ||
14 | doCheck = true; | ||
15 | checkPhase = '' | ||
16 | ${python}/bin/python -m py_compile worktime | ||
17 | ''; | ||
18 | |||
14 | installPhase = '' | 19 | installPhase = '' |
15 | install -m 0755 -D -t $out/bin \ | 20 | install -m 0755 -D -t $out/bin \ |
16 | worktime | 21 | worktime |
diff --git a/user-profiles/feeds/default.nix b/user-profiles/feeds/default.nix index cfecf17e..82be90c7 100644 --- a/user-profiles/feeds/default.nix +++ b/user-profiles/feeds/default.nix | |||
@@ -1,18 +1,11 @@ | |||
1 | { config, flakeInputs, userName, pkgs, lib, ... }: | 1 | { config, flakeInputs, pkgs, lib, userName, customUtils, ... }: |
2 | 2 | { | |
3 | with lib; | 3 | home-manager.users.${userName} = {...}: { |
4 | 4 | imports = [ | |
5 | let | 5 | (customUtils.overrideModuleArgs |
6 | cfg = config.home-manager.users.${userName}; | 6 | (import ./module.nix) |
7 | inherit (flakeInputs.home-manager.lib) hm; | 7 | (inputs: inputs // { inherit flakeInputs; inherit (config.nixpkgs) system; }) |
8 | 8 | ) | |
9 | imm = flakeInputs.imm.defaultPackage.${config.nixpkgs.system}; | 9 | ]; |
10 | in { | ||
11 | config.home-manager.users.${userName} = { | ||
12 | home.packages = [ imm ]; | ||
13 | |||
14 | home.activation.createImm = hm.dag.entryAfter ["writeBoundary"] '' | ||
15 | $DRY_RUN_CMD mkdir -p $VERBOSE_ARG ${cfg.xdg.configHome}/imm | ||
16 | ''; | ||
17 | }; | 10 | }; |
18 | } | 11 | } |
diff --git a/user-profiles/feeds/imm-notmuch-insert.py b/user-profiles/feeds/imm-notmuch-insert.py new file mode 100644 index 00000000..855f3a83 --- /dev/null +++ b/user-profiles/feeds/imm-notmuch-insert.py | |||
@@ -0,0 +1,37 @@ | |||
1 | #!@python@/bin/python | ||
2 | |||
3 | import json | ||
4 | import sys | ||
5 | import subprocess | ||
6 | from io import StringIO | ||
7 | from email.message import EmailMessage | ||
8 | import configparser | ||
9 | from os import environ | ||
10 | from dateutil.parser import isoparse | ||
11 | |||
12 | def main(): | ||
13 | notmuchConfig = configparser.ConfigParser() | ||
14 | notmuchConfig.read(environ.get('NOTMUCH_CONFIG')) | ||
15 | |||
16 | callbackMessage = json.load(sys.stdin) | ||
17 | |||
18 | msg = EmailMessage() | ||
19 | authors = ', '.join(map(lambda author: author['name'], callbackMessage['feed_item']['authors'])) | ||
20 | msg['From'] = f"{callbackMessage['feed_definition']['title']} ({authors}) <imm@imm.invalid>" | ||
21 | msg['To'] = f"{notmuchConfig['user']['name']} <{notmuchConfig['user']['primary_email']}>" | ||
22 | msg['Subject'] = callbackMessage['feed_item']['title'] | ||
23 | msg['Message-ID'] = f"{callbackMessage['feed_item']['identifier']@imm.invalid}" | ||
24 | for link in callbackMessage['feed_item']['links']: | ||
25 | msg.add_header('Link', link) | ||
26 | if 'date' in callbackMessage['feed_item']: | ||
27 | date = isoparse(callbackMessage['feed_item']['date']) | ||
28 | msg['Date'] = date.strftime('%a, %e %b %Y %T %z') | ||
29 | |||
30 | subprocess.run( | ||
31 | args=['notmuch', 'insert'], | ||
32 | check=True, | ||
33 | stdin=StringIO(bytes(msg)) | ||
34 | ) | ||
35 | |||
36 | if __name__ == '__main__': | ||
37 | sys.exit(main()) | ||
diff --git a/user-profiles/feeds/module.nix b/user-profiles/feeds/module.nix new file mode 100644 index 00000000..7a29331b --- /dev/null +++ b/user-profiles/feeds/module.nix | |||
@@ -0,0 +1,114 @@ | |||
1 | { config, flakeInputs, pkgs, lib, system, ... }: | ||
2 | |||
3 | with lib; | ||
4 | |||
5 | let | ||
6 | inherit (flakeInputs.home-manager.lib) hm; | ||
7 | |||
8 | configPath = "${config.xdg.configHome}/feeds/notmuchrc"; | ||
9 | databasePath = "${config.xdg.dataHome}/feeds"; | ||
10 | |||
11 | imm = flakeInputs.imm.defaultPackage.${system}; | ||
12 | immWrapped = pkgs.runCommand "${imm.name}-wrapped-${config.home.username}" | ||
13 | { nativeBuildInputs = with pkgs; [ makeWrapper imm ]; | ||
14 | } '' | ||
15 | mkdir -p $out/bin | ||
16 | makeWrapper ${imm}/bin/imm $out/bin/imm \ | ||
17 | --add-flags --callbacks=${notmuchCallbacks} | ||
18 | ''; | ||
19 | |||
20 | notmuchCallbacks = pkgs.writeText "imm-callbacks-${config.home.username}.dhall" '' | ||
21 | let Callback : Type = | ||
22 | { _executable : Text | ||
23 | , _arguments : List Text | ||
24 | } | ||
25 | |||
26 | let notmuchInsert = | ||
27 | { _executable = "${immNotmuchInsert}/bin/imm-notmuch-insert" | ||
28 | , _arguments = [] | ||
29 | } | ||
30 | |||
31 | let config : List Callback = [ notmuchInsert ] | ||
32 | in config | ||
33 | ''; | ||
34 | |||
35 | immNotmuchInsert = pkgs.stdenv.mkDerivation rec { | ||
36 | name = "imm-notmuch-insert-${config.home.username}"; | ||
37 | src = ./imm-notmuch-insert.py; | ||
38 | |||
39 | phases = [ "buildPhase" "checkPhase" "installPhase" "fixupPhase" ]; | ||
40 | |||
41 | python = pkgs.python39.withPackages (ps: with ps; [ configparser ]); | ||
42 | |||
43 | nativeBuildInputs = with pkgs; [ makeWrapper ]; | ||
44 | |||
45 | buildPhase = '' | ||
46 | substituteAll $src imm-notmuch-insert | ||
47 | ''; | ||
48 | |||
49 | doCheck = true; | ||
50 | checkPhase = '' | ||
51 | ${python}/bin/python -m py_compile imm-notmuch-insert | ||
52 | ''; | ||
53 | |||
54 | installPhase = '' | ||
55 | install -m 0755 -D -t $out/bin \ | ||
56 | imm-notmuch-insert | ||
57 | ''; | ||
58 | |||
59 | fixupPhase = '' | ||
60 | wrapProgram $out/bin/imm-notmuch-insert \ | ||
61 | --prefix PATH : ${pkgs.notmuch}/bin \ | ||
62 | --set NOTMUCH_CONFIG ${configPath} | ||
63 | ''; | ||
64 | }; | ||
65 | |||
66 | mkIniKeyValue = key: value: | ||
67 | let | ||
68 | tweakVal = v: | ||
69 | if isString v then | ||
70 | v | ||
71 | else if isList v then | ||
72 | concatMapStringsSep ";" tweakVal v | ||
73 | else if isBool v then | ||
74 | (if v then "true" else "false") | ||
75 | else | ||
76 | toString v; | ||
77 | in "${key}=${tweakVal value}"; | ||
78 | |||
79 | notmuchIni = { | ||
80 | database = { path = databasePath; }; | ||
81 | |||
82 | maildir = { synchronize_flags = false; }; | ||
83 | |||
84 | new = { | ||
85 | ignore = []; | ||
86 | tags = ["new"]; | ||
87 | }; | ||
88 | |||
89 | user = { | ||
90 | name = config.home.username; | ||
91 | primary_email = "${config.home.username}@imm.invalid"; | ||
92 | }; | ||
93 | |||
94 | search = { exclude_tags = ["deleted"]; }; | ||
95 | }; | ||
96 | in { | ||
97 | config = { | ||
98 | home.packages = [ immWrapped ]; | ||
99 | |||
100 | home.activation.createImm = hm.dag.entryAfter ["writeBoundary"] '' | ||
101 | $DRY_RUN_CMD mkdir -p $VERBOSE_ARG ${config.xdg.configHome}/imm | ||
102 | ''; | ||
103 | |||
104 | xdg.configFile."feeds/notmuchrc".text = | ||
105 | let toIni = generators.toINI { mkKeyValue = mkIniKeyValue; }; | ||
106 | in '' | ||
107 | # Generated by Home Manager. | ||
108 | '' + toIni notmuchIni; | ||
109 | |||
110 | home.activation.createFeedsDatabase = hm.dag.entryAfter ["writeBoundary"] '' | ||
111 | $DRY_RUN_CMD mkdir -p $VERBOSE_ARG ${databasePath} | ||
112 | ''; | ||
113 | }; | ||
114 | } | ||