-
Notifications
You must be signed in to change notification settings - Fork 7
/
guix.nix
222 lines (195 loc) · 6.66 KB
/
guix.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
{ config, pkgs, lib, ... }:
let
cfg = config.services.guix;
package = cfg.package.override (with cfg; { inherit stateDir storeDir; });
guixBuildUser = id: {
group = cfg.group;
extraGroups = [ cfg.group ];
name = "${cfg.userPrefix}${toString id}";
createHome = false;
description = "Guix build user ${toString id}";
isSystemUser = true;
};
guixBuildUsers = numberOfUsers:
builtins.listToAttrs (map
(user: {
name = user.name;
value = user;
})
(builtins.genList guixBuildUser numberOfUsers));
guixEnv = rec {
ROOT_PROFILE = "${cfg.stateDir}/guix/profiles/per-user/root/current-guix";
DAEMON = "${ROOT_PROFILE}/bin/guix-daemon";
GUIX_LOCPATH = "${ROOT_PROFILE}/lib/locale";
LC_ALL = "en_US.utf8";
};
# The usual list of profiles being used for the best way of integrating
# Guix-built applications throughout the NixOS system. Take note it is sorted
# starting with the profile with the most precedence.
guixProfiles = [
"$HOME/.config/guix/current"
"$HOME/.guix-profile"
guixEnv.ROOT_PROFILE
];
in
{
options.services.guix = with lib; {
enable = mkEnableOption "the Guix daemon service";
group = mkOption {
type = types.str;
default = "guixbuild";
example = "guixbuild";
description = ''
The group of the Guix build user pool.
'';
};
userPrefix = mkOption {
type = types.str;
default = "guixbuilder";
example = "guixbuilder";
description = ''
The name prefix for the Guix build user pool.
'';
};
extraArgs = mkOption {
type = with types; listOf str;
default = [ ];
example = [ "--max-jobs=4" "--debug" ];
description = ''
Extra flags to pass to the Guix daemon service.
'';
};
package = mkOption {
type = types.package;
default = pkgs.guix;
defaultText = "pkgs.guix";
description = ''
The package containing the Guix daemon and command-line interface.
'';
};
storeDir = mkOption {
type = types.str;
default = "/gnu/store";
defaultText = "/gnu/store";
description = ''
The store directory where the Guix service will serve to/from. Take
note Guix cannot take advantage of substitutes if you set it other than
<literal>/gnu/store</literal> since most of the cached builds are
assumed in there.
This will also recompile the package with the specified option so you
better have a good reason to do so.
'';
};
stateDir = mkOption {
type = types.str;
default = "/var";
defaultText = "/var";
description = ''
The state directory where Guix service will store its data such as its
user-specific profiles, cache, and state files.
Changing it other than the default will rebuild the package.
'';
example = "/gnu/var";
};
publish = {
enable = mkEnableOption "substitute server for your Guix store directory";
port = mkOption {
type = types.port;
default = 8181;
description = ''
Port of the substitute server to listen to.
'';
};
user = mkOption {
type = types.str;
default = "nobody";
defaultText = "nobody";
description = ''
Name of the user to change once the server is up.
'';
};
extraArgs = mkOption {
type = with types; listOf str;
description = ''
Extra flags to pass to the substitute server.
'';
default = [];
example = lib.literalExpression ''
[ "--compression=zstd:6" "--repl" ]
'';
};
};
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [ package ];
# Building the user pool for Guix.
users.users = guixBuildUsers 10;
users.groups."${cfg.group}" = { };
# From this point, the script for services involving activating the Guix
# daemon will more likely use the daemon from the Guix root profile which
# is present after doing an update (i.e., 'guix pull'). Otherwise, we'll
# just use the daemon from the derivation.
systemd.services.guix-daemon = {
description = "Build daemon for GNU Guix";
environment = guixEnv;
script = ''
if [ ! -x "$DAEMON" ]; then
DAEMON="${package}/bin/guix-daemon"
GUIX_LOCPATH="${pkgs.glibcLocales}/lib/locale"
fi
exec $DAEMON --build-users-group=${cfg.group} ${
lib.escapeShellArgs cfg.extraArgs
}
'';
serviceConfig = {
RemainAfterExit = "yes";
StandardOutput = "journal";
StandardError = "journal";
TasksMax =
8192; # See <https://lists.gnu.org/archive/html/guix-devel/2016-04/msg00608.html>.
};
wantedBy = [ "multi-user.target" ];
};
systemd.services.guix-publish = lib.mkIf cfg.publish.enable {
description = "Publish the GNU Guix store";
environment = guixEnv;
script = ''
if [ ! -x "$DAEMON" ]; then
DAEMON="${package}/bin/guix-daemon"
GUIX_LOCPATH="${pkgs.glibcLocales}/lib/locale"
fi
exec $DAEMON publish --user=${cfg.publish.user} --port=${cfg.publish.port} ${
lib.escapeShellArgs cfg.publish.extraArgs
}
'';
serviceConfig = {
RemainAfterExit = "yes";
StandardOutput = "journal";
StandardError = "journal";
TasksMax =
1024; # See <https://lists.gnu.org/archive/html/guix-devel/2016-04/msg00608.html>.
};
wantedBy = [ "multi-user.target" ];
};
# Make transferring files from one store to another easier with the usual
# case being most of them are more likely from the official Guix CI
# instance.
system.activationScripts.guix = ''
${package}/bin/guix archive --authorize < \
${package}/share/guix/ci.guix.gnu.org.pub
'';
# GUIX_LOCPATH is basically LOCPATH but for Guix libc which in turn used by
# virtually every Guix-built packages. This is so that Guix-installed
# applications wouldn't use incompatible locale data and not touch its host
# system.
#
# Since it is mainly used by Guix-built packages, we'll have to avoid
# setting this variable to point to Nix-built locale data.
environment.variables.GUIX_LOCPATH = lib.makeSearchPath "lib/locale" guixProfiles;
# What Guix profiles export is very similar to Nix profiles so it is
# acceptable to list it here. Also, it is more likely that the user would
# want to use packages explicitly installed from Guix so we're putting it
# first.
environment.profiles = lib.mkBefore guixProfiles;
};
}