Skip to content

Commit c554d34

Browse files
isomarcterycee
authored andcommitted
lorri: add Darwin daemon
Add a Darwin daemon for lorri.
1 parent 2d1bac5 commit c554d34

7 files changed

Lines changed: 234 additions & 119 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{ pkgs, ... }: {
2+
time = "2026-08-13T20:59:31+00:00";
3+
condition = pkgs.stdenv.hostPlatform.isDarwin;
4+
message = ''
5+
A lorri daemon for darwin is now available.
6+
7+
Enable it with: `services.lorri.enable = true`
8+
'';
9+
}

modules/services/lorri.nix

Lines changed: 169 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ in
1818
options.services.lorri = {
1919
enable = lib.mkEnableOption "lorri build daemon";
2020

21-
enableNotifications = lib.mkEnableOption "lorri build notifications";
21+
enableNotifications = lib.mkOption {
22+
type = lib.types.bool;
23+
default = false;
24+
example = true;
25+
description = ''
26+
Whether to enable lorri build notifications.
27+
Note, this is unsupported on Darwin.
28+
'';
29+
};
2230

2331
package = lib.mkPackageOption pkgs "lorri" { };
2432

@@ -29,126 +37,168 @@ in
2937
example = lib.literalExpression "pkgs.nixVersions.unstable";
3038
description = "Which nix package to use.";
3139
};
32-
};
33-
34-
config = lib.mkIf cfg.enable {
35-
assertions = [
36-
(lib.hm.assertions.assertPlatform "services.lorri" pkgs lib.platforms.linux)
37-
];
3840

39-
home.packages = [ cfg.package ];
40-
41-
systemd.user = {
42-
services.lorri = {
43-
Unit = {
44-
Description = "lorri build daemon";
45-
Requires = "lorri.socket";
46-
After = "lorri.socket";
47-
RefuseManualStart = true;
48-
};
41+
extraEnvVariables = lib.mkOption {
42+
type = lib.types.attrsOf lib.types.str;
43+
default = { };
44+
description = "Extra environment variables to pass to the daemon.";
45+
};
46+
};
4947

50-
Service = {
51-
ExecStart = "${cfg.package}/bin/lorri daemon";
52-
PrivateTmp = true;
53-
ProtectSystem = "strict";
54-
ProtectHome = "read-only";
55-
ReadWritePaths = [
56-
# /run/user/1000 for the socket
57-
"%t"
58-
# Needs to update own cache
59-
"%C/lorri"
60-
# Needs %C/nix/fetcher-cache-v1.sqlite
61-
"%C/nix"
62-
];
63-
CacheDirectory = [ "lorri" ];
64-
Restart = "on-failure";
65-
Environment =
66-
let
67-
path =
68-
with pkgs;
69-
lib.makeSearchPath "bin" [
70-
cfg.nixPackage
71-
gitMinimal
72-
gnutar
73-
gzip
48+
config = lib.mkIf cfg.enable (
49+
let
50+
path =
51+
with pkgs;
52+
lib.makeSearchPath "bin" [
53+
cfg.nixPackage
54+
gitMinimal
55+
gnutar
56+
gzip
57+
];
58+
in
59+
lib.mkMerge [
60+
{
61+
home.packages = [ cfg.package ];
62+
}
63+
64+
(lib.mkIf pkgs.stdenv.isLinux (
65+
let
66+
extraEnvList = lib.mapAttrsToList (k: v: "${k}=${v}") cfg.extraEnvVariables;
67+
in
68+
{
69+
systemd.user = {
70+
services.lorri = {
71+
Unit = {
72+
Description = "lorri build daemon";
73+
Requires = "lorri.socket";
74+
After = "lorri.socket";
75+
RefuseManualStart = true;
76+
};
77+
78+
Service = {
79+
ExecStart = "${cfg.package}/bin/lorri daemon";
80+
PrivateTmp = true;
81+
ProtectSystem = "strict";
82+
ProtectHome = "read-only";
83+
ReadWritePaths = [
84+
# /run/user/1000 for the socket
85+
"%t"
86+
# Needs to update own cache
87+
"%C/lorri"
88+
# Needs %C/nix/fetcher-cache-v1.sqlite
89+
"%C/nix"
7490
];
75-
in
76-
[ "PATH=${path}" ];
77-
};
78-
};
79-
80-
sockets.lorri = {
81-
Unit = {
82-
Description = "Socket for lorri build daemon";
83-
};
84-
85-
Socket = {
86-
ListenStream = "%t/lorri/daemon.socket";
87-
RuntimeDirectory = "lorri";
91+
CacheDirectory = [ "lorri" ];
92+
Restart = "on-failure";
93+
Environment = [ "PATH=${path}" ] ++ extraEnvList;
94+
};
95+
};
96+
97+
sockets.lorri = {
98+
Unit = {
99+
Description = "Socket for lorri build daemon";
100+
};
101+
102+
Socket = {
103+
ListenStream = "%t/lorri/daemon.socket";
104+
RuntimeDirectory = "lorri";
105+
};
106+
107+
Install = {
108+
WantedBy = [ "sockets.target" ];
109+
};
110+
};
111+
112+
services.lorri-notify = lib.mkIf cfg.enableNotifications {
113+
Unit = {
114+
Description = "lorri build notifications";
115+
After = "lorri.service";
116+
Requires = "lorri.service";
117+
};
118+
119+
Service = {
120+
# Don't start until lorri daemon is actually running
121+
ExecStartPre = pkgs.writeShellScript "lorri-notify-check" ''
122+
lorri info --shell-file . | grep 'Lorri Daemon Status:.*running'
123+
'';
124+
RestartSec = "5s";
125+
126+
ExecStart =
127+
let
128+
jqFile = ''
129+
(
130+
(.Started? | values | ["Build starting", .nix_file, "emblem-synchronizing"]),
131+
(.Completed? | values | ["Build complete", .nix_file, "checkmark"]),
132+
(.Failure? | values | ["Build failed", .nix_file, "dialog-error"])
133+
)
134+
| @tsv
135+
'';
136+
137+
notifyScript = pkgs.writeShellScript "lorri-notify" ''
138+
set -o pipefail
139+
lorri internal stream-events --kind live \
140+
| jq --unbuffered -r '${jqFile}' \
141+
| while IFS=$'\t' read -r status nixFile icon; do
142+
notify-send --app-name "Lorri" --hint=int:transient:1 \
143+
--icon "$icon" "$status" "$nixFile"
144+
done
145+
'';
146+
in
147+
toString notifyScript;
148+
Restart = "on-failure";
149+
Environment =
150+
let
151+
path = lib.makeSearchPath "bin" (
152+
with pkgs;
153+
[
154+
bash
155+
gnugrep
156+
jq
157+
libnotify
158+
cfg.package
159+
]
160+
);
161+
in
162+
[ "PATH=${path}" ];
163+
};
164+
165+
Install = {
166+
WantedBy = [ "lorri.service" ];
167+
};
168+
};
169+
};
170+
}
171+
))
172+
173+
(lib.mkIf pkgs.stdenv.isDarwin {
174+
warnings =
175+
if cfg.enableNotifications then
176+
[
177+
"services.lorri.enableNotifications is not currently supported for Darwin."
178+
]
179+
else
180+
[ ];
181+
launchd.agents.lorri = {
182+
enable = true;
183+
config = {
184+
ProgramArguments = [
185+
"${cfg.package}/bin/lorri"
186+
"daemon"
187+
];
188+
189+
EnvironmentVariables = {
190+
PATH = "${path}";
191+
}
192+
// cfg.extraEnvVariables;
193+
194+
RunAtLoad = true;
195+
KeepAlive = {
196+
Crashed = true;
197+
SuccessfulExit = false;
198+
};
199+
};
88200
};
89-
90-
Install = {
91-
WantedBy = [ "sockets.target" ];
92-
};
93-
};
94-
95-
services.lorri-notify = lib.mkIf cfg.enableNotifications {
96-
Unit = {
97-
Description = "lorri build notifications";
98-
After = "lorri.service";
99-
Requires = "lorri.service";
100-
};
101-
102-
Service = {
103-
# Don't start until lorri daemon is actually running
104-
ExecStartPre = pkgs.writeShellScript "lorri-notify-check" ''
105-
lorri info --shell-file . | grep 'Lorri Daemon Status:.*running'
106-
'';
107-
RestartSec = "5s";
108-
109-
ExecStart =
110-
let
111-
jqFile = ''
112-
(
113-
(.Started? | values | ["Build starting", .nix_file, "emblem-synchronizing"]),
114-
(.Completed? | values | ["Build complete", .nix_file, "checkmark"]),
115-
(.Failure? | values | ["Build failed", .nix_file, "dialog-error"])
116-
)
117-
| @tsv
118-
'';
119-
120-
notifyScript = pkgs.writeShellScript "lorri-notify" ''
121-
set -o pipefail
122-
lorri internal stream-events --kind live \
123-
| jq --unbuffered -r '${jqFile}' \
124-
| while IFS=$'\t' read -r status nixFile icon; do
125-
notify-send --app-name "Lorri" --hint=int:transient:1 \
126-
--icon "$icon" "$status" "$nixFile"
127-
done
128-
'';
129-
in
130-
toString notifyScript;
131-
Restart = "on-failure";
132-
Environment =
133-
let
134-
path = lib.makeSearchPath "bin" (
135-
with pkgs;
136-
[
137-
bash
138-
gnugrep
139-
jq
140-
libnotify
141-
cfg.package
142-
]
143-
);
144-
in
145-
"PATH=${path}";
146-
};
147-
148-
Install = {
149-
WantedBy = [ "lorri.service" ];
150-
};
151-
};
152-
};
153-
};
201+
})
202+
]
203+
);
154204
}

tests/darwinScrublist.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ let
8080
"google-chrome-dev"
8181
"gradle"
8282
"granted"
83+
"guntar"
8384
"gurk-rs"
8485
"halloy"
8586
"helix"
@@ -117,6 +118,7 @@ let
117118
"librewolf"
118119
"librewolf-unwrapped"
119120
"lieer"
121+
"lorri"
120122
"lsd"
121123
"ludusavi"
122124
"mbsync"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{ lib, pkgs, ... }:
2+
3+
(lib.optionalAttrs pkgs.stdenv.hostPlatform.isDarwin {
4+
lorri-launchd-service = ./launchd-service.nix;
5+
lorri-launchd-extra-env-variables = ./launchd-extra-env-variables.nix;
6+
})
7+
// (lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux {
8+
lorri-systemd-extra-env-variables = ./systemd-extra-env-variables.nix;
9+
})
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
services.lorri = {
3+
enable = true;
4+
extraEnvVariables = {
5+
TEST_ENV_VAR = "test-value";
6+
ANOTHER_ENV_VAR = "another-value";
7+
};
8+
};
9+
10+
nmt.script = ''
11+
serviceFile="LaunchAgents/org.nix-community.home.lorri.plist"
12+
assertFileExists "$serviceFile"
13+
assertFileContains "$serviceFile" "<key>TEST_ENV_VAR</key>"
14+
assertFileContains "$serviceFile" "<string>test-value</string>"
15+
assertFileContains "$serviceFile" "<key>ANOTHER_ENV_VAR</key>"
16+
assertFileContains "$serviceFile" "<string>another-value</string>"
17+
'';
18+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
services.lorri.enable = true;
3+
4+
nmt.script = ''
5+
serviceFile="LaunchAgents/org.nix-community.home.lorri.plist"
6+
assertFileExists "$serviceFile"
7+
assertFileContains "$serviceFile" "/bin/lorri daemon"
8+
assertFileContains "$serviceFile" "<key>RunAtLoad</key>"
9+
assertFileContains "$serviceFile" "<key>KeepAlive</key>"
10+
'';
11+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
services.lorri = {
3+
enable = true;
4+
extraEnvVariables = {
5+
TEST_ENV_VAR = "test-value";
6+
ANOTHER_ENV_VAR = "another-value";
7+
};
8+
};
9+
10+
nmt.script = ''
11+
serviceFile="home-files/.config/systemd/user/lorri.service"
12+
assertFileExists "$serviceFile"
13+
assertFileContains "$serviceFile" "Environment=TEST_ENV_VAR=test-value"
14+
assertFileContains "$serviceFile" "Environment=ANOTHER_ENV_VAR=another-value"
15+
'';
16+
}

0 commit comments

Comments
 (0)