···2425- [Apache Guacamole](https://guacamole.apache.org/), a cross-platform, clientless remote desktop gateway. Available as [services.guacamole-server](#opt-services.guacamole-server.enable) and [services.guacamole-client](#opt-services.guacamole-client.enable) services.
260027- [trust-dns](https://trust-dns.org/), a Rust based DNS server built to be safe and secure from the ground up. Available as [services.trust-dns](#opt-services.trust-dns.enable).
2829- [osquery](https://www.osquery.io/), a SQL powered operating system instrumentation, monitoring, and analytics.
3031- [ebusd](https://ebusd.eu), a daemon for handling communication with eBUS devices connected to a 2-wire bus system (“energy bus” used by numerous heating systems). Available as [services.ebusd](#opt-services.ebusd.enable).
03233## Backward Incompatibilities {#sec-release-23.11-incompatibilities}
34
···2425- [Apache Guacamole](https://guacamole.apache.org/), a cross-platform, clientless remote desktop gateway. Available as [services.guacamole-server](#opt-services.guacamole-server.enable) and [services.guacamole-client](#opt-services.guacamole-client.enable) services.
2627+- [pgBouncer](https://www.pgbouncer.org), a PostgreSQL connection pooler. Available as [services.pgbouncer](#opt-services.pgbouncer.enable).
28+29- [trust-dns](https://trust-dns.org/), a Rust based DNS server built to be safe and secure from the ground up. Available as [services.trust-dns](#opt-services.trust-dns.enable).
3031- [osquery](https://www.osquery.io/), a SQL powered operating system instrumentation, monitoring, and analytics.
3233- [ebusd](https://ebusd.eu), a daemon for handling communication with eBUS devices connected to a 2-wire bus system (“energy bus” used by numerous heating systems). Available as [services.ebusd](#opt-services.ebusd.enable).
34+3536## Backward Incompatibilities {#sec-release-23.11-incompatibilities}
37
···1+{ lib, pkgs, config, ... } :
2+3+with lib;
4+5+let
6+ cfg = config.services.pgbouncer;
7+8+ confFile = pkgs.writeTextFile {
9+ name = "pgbouncer.ini";
10+ text = ''
11+ [databases]
12+ ${concatStringsSep "\n"
13+ (mapAttrsToList (dbname : settings : "${dbname} = ${settings}") cfg.databases)}
14+15+ [users]
16+ ${concatStringsSep "\n"
17+ (mapAttrsToList (username : settings : "${username} = ${settings}") cfg.users)}
18+19+ [peers]
20+ ${concatStringsSep "\n"
21+ (mapAttrsToList (peerid : settings : "${peerid} = ${settings}") cfg.peers)}
22+23+ [pgbouncer]
24+ # general
25+ ${optionalString (cfg.ignoreStartupParameters != null) "ignore_startup_parameters = ${cfg.ignoreStartupParameters}"}
26+ listen_port = ${toString cfg.listenPort}
27+ ${optionalString (cfg.listenAddress != null) "listen_addr = ${cfg.listenAddress}"}
28+ pool_mode = ${cfg.poolMode}
29+ max_client_conn = ${toString cfg.maxClientConn}
30+ default_pool_size = ${toString cfg.defaultPoolSize}
31+ max_user_connections = ${toString cfg.maxUserConnections}
32+ max_db_connections = ${toString cfg.maxDbConnections}
33+34+ #auth
35+ auth_type = ${cfg.authType}
36+ ${optionalString (cfg.authHbaFile != null) "auth_hba_file = ${cfg.authHbaFile}"}
37+ ${optionalString (cfg.authFile != null) "auth_file = ${cfg.authFile}"}
38+ ${optionalString (cfg.authUser != null) "auth_user = ${cfg.authUser}"}
39+ ${optionalString (cfg.authQuery != null) "auth_query = ${cfg.authQuery}"}
40+ ${optionalString (cfg.authDbname != null) "auth_dbname = ${cfg.authDbname}"}
41+42+ # TLS
43+ ${optionalString (cfg.tls.client != null) ''
44+ client_tls_sslmode = ${cfg.tls.client.sslmode}
45+ client_tls_key_file = ${cfg.tls.client.keyFile}
46+ client_tls_cert_file = ${cfg.tls.client.certFile}
47+ client_tls_ca_file = ${cfg.tls.client.caFile}
48+ ''}
49+ ${optionalString (cfg.tls.server != null) ''
50+ server_tls_sslmode = ${cfg.tls.server.sslmode}
51+ server_tls_key_file = ${cfg.tls.server.keyFile}
52+ server_tls_cert_file = ${cfg.tls.server.certFile}
53+ server_tls_ca_file = ${cfg.tls.server.caFile}
54+ ''}
55+56+ # log
57+ ${optionalString (cfg.logFile != null) "logfile = ${cfg.homeDir}/${cfg.logFile}"}
58+ ${optionalString (cfg.syslog != null) ''
59+ syslog = ${if cfg.syslog.enable then "1" else "0"}
60+ syslog_ident = ${cfg.syslog.syslogIdent}
61+ syslog_facility = ${cfg.syslog.syslogFacility}
62+ ''}
63+ ${optionalString (cfg.verbose != null) "verbose = ${toString cfg.verbose}"}
64+65+ # console access
66+ ${optionalString (cfg.adminUsers != null) "admin_users = ${cfg.adminUsers}"}
67+ ${optionalString (cfg.statsUsers != null) "stats_users = ${cfg.statsUsers}"}
68+69+ # linux
70+ pidfile = /run/pgbouncer/pgbouncer.pid
71+72+ # extra
73+ ${cfg.extraConfig}
74+ '';
75+ };
76+77+in {
78+79+ options.services.pgbouncer = {
80+81+ # NixOS settings
82+83+ enable = mkEnableOption (lib.mdDoc "PostgreSQL connection pooler");
84+85+ package = mkOption {
86+ type = types.package;
87+ default = pkgs.pgbouncer;
88+ defaultText = literalExpression "pkgs.pgbouncer";
89+ description = lib.mdDoc ''
90+ The pgbouncer package to use.
91+ '';
92+ };
93+94+ openFirewall = mkOption {
95+ type = types.bool;
96+ default = false;
97+ description = lib.mdDoc ''
98+ Whether to automatically open the specified TCP port in the firewall.
99+ '';
100+ };
101+102+ # Generic settings
103+104+ logFile = mkOption {
105+ type = types.nullOr types.str;
106+ default = "pgbouncer.log";
107+ description = lib.mdDoc ''
108+ Specifies the log file.
109+ Either this or syslog has to be specified.
110+ '';
111+ };
112+113+ listenAddress = mkOption {
114+ type = types.nullOr types.commas;
115+ example = "*";
116+ default = null;
117+ description = lib.mdDoc ''
118+ Specifies a list (comma-separated) of addresses where to listen for TCP connections.
119+ You may also use * meaning “listen on all addresses”.
120+ When not set, only Unix socket connections are accepted.
121+122+ Addresses can be specified numerically (IPv4/IPv6) or by name.
123+ '';
124+ };
125+126+ listenPort = mkOption {
127+ type = types.port;
128+ default = 6432;
129+ description = lib.mdDoc ''
130+ Which port to listen on. Applies to both TCP and Unix sockets.
131+ '';
132+ };
133+134+ poolMode = mkOption {
135+ type = types.enum [ "session" "transaction" "statement" ];
136+ default = "session";
137+ description = lib.mdDoc ''
138+ Specifies when a server connection can be reused by other clients.
139+140+ session
141+ Server is released back to pool after client disconnects. Default.
142+ transaction
143+ Server is released back to pool after transaction finishes.
144+ statement
145+ Server is released back to pool after query finishes.
146+ Transactions spanning multiple statements are disallowed in this mode.
147+ '';
148+ };
149+150+ maxClientConn = mkOption {
151+ type = types.int;
152+ default = 100;
153+ description = lib.mdDoc ''
154+ Maximum number of client connections allowed.
155+156+ When this setting is increased, then the file descriptor limits in the operating system
157+ might also have to be increased. Note that the number of file descriptors potentially
158+ used is more than maxClientConn. If each user connects under its own user name to the server,
159+ the theoretical maximum used is:
160+ maxClientConn + (max pool_size * total databases * total users)
161+162+ If a database user is specified in the connection string (all users connect under the same user name),
163+ the theoretical maximum is:
164+ maxClientConn + (max pool_size * total databases)
165+166+ The theoretical maximum should never be reached, unless somebody deliberately crafts a special load for it.
167+ Still, it means you should set the number of file descriptors to a safely high number.
168+ '';
169+ };
170+171+ defaultPoolSize = mkOption {
172+ type = types.int;
173+ default = 20;
174+ description = lib.mdDoc ''
175+ How many server connections to allow per user/database pair.
176+ Can be overridden in the per-database configuration.
177+ '';
178+ };
179+180+ maxDbConnections = mkOption {
181+ type = types.int;
182+ default = 0;
183+ description = lib.mdDoc ''
184+ Do not allow more than this many server connections per database (regardless of user).
185+ This considers the PgBouncer database that the client has connected to,
186+ not the PostgreSQL database of the outgoing connection.
187+188+ This can also be set per database in the [databases] section.
189+190+ Note that when you hit the limit, closing a client connection to one pool will
191+ not immediately allow a server connection to be established for another pool,
192+ because the server connection for the first pool is still open.
193+ Once the server connection closes (due to idle timeout),
194+ a new server connection will immediately be opened for the waiting pool.
195+196+ 0 = unlimited
197+ '';
198+ };
199+200+ maxUserConnections = mkOption {
201+ type = types.int;
202+ default = 0;
203+ description = lib.mdDoc ''
204+ Do not allow more than this many server connections per user (regardless of database).
205+ This considers the PgBouncer user that is associated with a pool,
206+ which is either the user specified for the server connection
207+ or in absence of that the user the client has connected as.
208+209+ This can also be set per user in the [users] section.
210+211+ Note that when you hit the limit, closing a client connection to one pool
212+ will not immediately allow a server connection to be established for another pool,
213+ because the server connection for the first pool is still open.
214+ Once the server connection closes (due to idle timeout), a new server connection
215+ will immediately be opened for the waiting pool.
216+217+ 0 = unlimited
218+ '';
219+ };
220+221+ ignoreStartupParameters = mkOption {
222+ type = types.nullOr types.commas;
223+ example = "extra_float_digits";
224+ default = null;
225+ description = lib.mdDoc ''
226+ By default, PgBouncer allows only parameters it can keep track of in startup packets:
227+ client_encoding, datestyle, timezone and standard_conforming_strings.
228+229+ All others parameters will raise an error.
230+ To allow others parameters, they can be specified here, so that PgBouncer knows that
231+ they are handled by the admin and it can ignore them.
232+233+ If you need to specify multiple values, use a comma-separated list.
234+235+ IMPORTANT: When using prometheus-pgbouncer-exporter, you need:
236+ extra_float_digits
237+ <https://github.com/prometheus-community/pgbouncer_exporter#pgbouncer-configuration>
238+ '';
239+ };
240+241+ # Section [databases]
242+ databases = mkOption {
243+ type = types.attrsOf types.str;
244+ default = {};
245+ example = {
246+ exampledb = "host=/run/postgresql/ port=5432 auth_user=exampleuser dbname=exampledb sslmode=require";
247+ bardb = "host=localhost dbname=bazdb";
248+ foodb = "host=host1.example.com port=5432";
249+ };
250+ description = lib.mdDoc ''
251+ Detailed information about PostgreSQL database definitions:
252+ <https://www.pgbouncer.org/config.html#section-databases>
253+ '';
254+ };
255+256+ # Section [users]
257+ users = mkOption {
258+ type = types.attrsOf types.str;
259+ default = {};
260+ example = {
261+ user1 = "pool_mode=session";
262+ };
263+ description = lib.mdDoc ''
264+ Optional.
265+266+ Detailed information about PostgreSQL user definitions:
267+ <https://www.pgbouncer.org/config.html#section-users>
268+ '';
269+ };
270+271+ # Section [peers]
272+ peers = mkOption {
273+ type = types.attrsOf types.str;
274+ default = {};
275+ example = {
276+ "1" = "host=host1.example.com";
277+ "2" = "host=/tmp/pgbouncer-2 port=5555";
278+ };
279+ description = lib.mdDoc ''
280+ Optional.
281+282+ Detailed information about PostgreSQL database definitions:
283+ <https://www.pgbouncer.org/config.html#section-peers>
284+ '';
285+ };
286+287+ # Authentication settings
288+ authType = mkOption {
289+ type = types.enum [ "cert" "md5" "scram-sha-256" "plain" "trust" "any" "hba" "pam" ];
290+ default = "md5";
291+ description = lib.mdDoc ''
292+ How to authenticate users.
293+294+ cert
295+ Client must connect over TLS connection with a valid client certificate.
296+ The user name is then taken from the CommonName field from the certificate.
297+ md5
298+ Use MD5-based password check. This is the default authentication method.
299+ authFile may contain both MD5-encrypted and plain-text passwords.
300+ If md5 is configured and a user has a SCRAM secret, then SCRAM authentication is used automatically instead.
301+ scram-sha-256
302+ Use password check with SCRAM-SHA-256. authFile has to contain SCRAM secrets or plain-text passwords.
303+ plain
304+ The clear-text password is sent over the wire. Deprecated.
305+ trust
306+ No authentication is done. The user name must still exist in authFile.
307+ any
308+ Like the trust method, but the user name given is ignored.
309+ Requires that all databases are configured to log in as a specific user.
310+ Additionally, the console database allows any user to log in as admin.
311+ hba
312+ The actual authentication type is loaded from authHbaFile.
313+ This allows different authentication methods for different access paths,
314+ for example: connections over Unix socket use the peer auth method, connections over TCP must use TLS.
315+ pam
316+ PAM is used to authenticate users, authFile is ignored.
317+ This method is not compatible with databases using the authUser option.
318+ The service name reported to PAM is “pgbouncer”. pam is not supported in the HBA configuration file.
319+ '';
320+ };
321+322+ authHbaFile = mkOption {
323+ type = types.nullOr types.path;
324+ default = null;
325+ example = "/secrets/pgbouncer_hba";
326+ description = lib.mdDoc ''
327+ HBA configuration file to use when authType is hba.
328+329+ See HBA file format details:
330+ <https://www.pgbouncer.org/config.html#hba-file-format>
331+ '';
332+ };
333+334+ authFile = mkOption {
335+ type = types.nullOr types.path;
336+ default = null;
337+ example = "/secrets/pgbouncer_authfile";
338+ description = lib.mdDoc ''
339+ The name of the file to load user names and passwords from.
340+341+ See section Authentication file format details:
342+ <https://www.pgbouncer.org/config.html#authentication-file-format>
343+344+ Most authentication types require that either authFile or authUser be set;
345+ otherwise there would be no users defined.
346+ '';
347+ };
348+349+ authUser = mkOption {
350+ type = types.nullOr types.str;
351+ default = null;
352+ example = "pgbouncer";
353+ description = lib.mdDoc ''
354+ If authUser is set, then any user not specified in authFile will be queried
355+ through the authQuery query from pg_shadow in the database, using authUser.
356+ The password of authUser will be taken from authFile.
357+ (If the authUser does not require a password then it does not need to be defined in authFile.)
358+359+ Direct access to pg_shadow requires admin rights.
360+ It's preferable to use a non-superuser that calls a SECURITY DEFINER function instead.
361+ '';
362+ };
363+364+ authQuery = mkOption {
365+ type = types.nullOr types.str;
366+ default = null;
367+ example = "SELECT usename, passwd FROM pg_shadow WHERE usename=$1";
368+ description = lib.mdDoc ''
369+ Query to load user's password from database.
370+371+ Direct access to pg_shadow requires admin rights.
372+ It's preferable to use a non-superuser that calls a SECURITY DEFINER function instead.
373+374+ Note that the query is run inside the target database.
375+ So if a function is used, it needs to be installed into each database.
376+ '';
377+ };
378+379+ authDbname = mkOption {
380+ type = types.nullOr types.str;
381+ default = null;
382+ example = "authdb";
383+ description = lib.mdDoc ''
384+ Database name in the [database] section to be used for authentication purposes.
385+ This option can be either global or overriden in the connection string if this parameter is specified.
386+ '';
387+ };
388+389+ # TLS settings
390+ tls.client = mkOption {
391+ type = types.nullOr (types.submodule {
392+ options = {
393+ sslmode = mkOption {
394+ type = types.enum [ "disable" "allow" "prefer" "require" "verify-ca" "verify-full" ];
395+ default = "disable";
396+ description = lib.mdDoc ''
397+ TLS mode to use for connections from clients.
398+ TLS connections are disabled by default.
399+400+ When enabled, tls.client.keyFile and tls.client.certFile
401+ must be also configured to set up the key and certificate
402+ PgBouncer uses to accept client connections.
403+404+ disable
405+ Plain TCP. If client requests TLS, it's ignored. Default.
406+ allow
407+ If client requests TLS, it is used. If not, plain TCP is used.
408+ If the client presents a client certificate, it is not validated.
409+ prefer
410+ Same as allow.
411+ require
412+ Client must use TLS. If not, the client connection is rejected.
413+ If the client presents a client certificate, it is not validated.
414+ verify-ca
415+ Client must use TLS with valid client certificate.
416+ verify-full
417+ Same as verify-ca
418+ '';
419+ };
420+ certFile = mkOption {
421+ type = types.path;
422+ example = "/secrets/pgbouncer.key";
423+ description = lib.mdDoc "Path to certificate for private key. Clients can validate it";
424+ };
425+ keyFile = mkOption {
426+ type = types.path;
427+ example = "/secrets/pgbouncer.crt";
428+ description = lib.mdDoc "Path to private key for PgBouncer to accept client connections";
429+ };
430+ caFile = mkOption {
431+ type = types.path;
432+ example = "/secrets/pgbouncer.crt";
433+ description = lib.mdDoc "Path to root certificate file to validate client certificates";
434+ };
435+ };
436+ });
437+ default = null;
438+ description = lib.mdDoc ''
439+ <https://www.pgbouncer.org/config.html#tls-settings>
440+ '';
441+ };
442+443+ tls.server = mkOption {
444+ type = types.nullOr (types.submodule {
445+ options = {
446+ sslmode = mkOption {
447+ type = types.enum [ "disable" "allow" "prefer" "require" "verify-ca" "verify-full" ];
448+ default = "disable";
449+ description = lib.mdDoc ''
450+ TLS mode to use for connections to PostgreSQL servers.
451+ TLS connections are disabled by default.
452+453+ disable
454+ Plain TCP. TLS is not even requested from the server. Default.
455+ allow
456+ FIXME: if server rejects plain, try TLS?
457+ prefer
458+ TLS connection is always requested first from PostgreSQL.
459+ If refused, the connection will be established over plain TCP.
460+ Server certificate is not validated.
461+ require
462+ Connection must go over TLS. If server rejects it, plain TCP is not attempted.
463+ Server certificate is not validated.
464+ verify-ca
465+ Connection must go over TLS and server certificate must be valid according to tls.server.caFile.
466+ Server host name is not checked against certificate.
467+ verify-full
468+ Connection must go over TLS and server certificate must be valid according to tls.server.caFile.
469+ Server host name must match certificate information.
470+ '';
471+ };
472+ certFile = mkOption {
473+ type = types.path;
474+ example = "/secrets/pgbouncer_server.key";
475+ description = lib.mdDoc "Certificate for private key. PostgreSQL server can validate it.";
476+ };
477+ keyFile = mkOption {
478+ type = types.path;
479+ example = "/secrets/pgbouncer_server.crt";
480+ description = lib.mdDoc "Private key for PgBouncer to authenticate against PostgreSQL server.";
481+ };
482+ caFile = mkOption {
483+ type = types.path;
484+ example = "/secrets/pgbouncer_server.crt";
485+ description = lib.mdDoc "Root certificate file to validate PostgreSQL server certificates.";
486+ };
487+ };
488+ });
489+ default = null;
490+ description = lib.mdDoc ''
491+ <https://www.pgbouncer.org/config.html#tls-settings>
492+ '';
493+ };
494+495+ # Log settings
496+ syslog = mkOption {
497+ type = types.nullOr (types.submodule {
498+ options = {
499+ enable = mkOption {
500+ type = types.bool;
501+ default = false;
502+ description = lib.mdDoc ''
503+ Toggles syslog on/off.
504+ '';
505+ };
506+ syslogIdent = mkOption {
507+ type = types.str;
508+ default = "pgbouncer";
509+ description = lib.mdDoc ''
510+ Under what name to send logs to syslog.
511+ '';
512+ };
513+ syslogFacility = mkOption {
514+ type = types.enum [ "auth" "authpriv" "daemon" "user" "local0" "local1" "local2" "local3" "local4" "local5" "local6" "local7" ];
515+ default = "daemon";
516+ description = lib.mdDoc ''
517+ Under what facility to send logs to syslog.
518+ '';
519+ };
520+ };
521+ });
522+ default = null;
523+ description = lib.mdDoc ''
524+ <https://www.pgbouncer.org/config.html#log-settings>
525+ '';
526+ };
527+528+ verbose = lib.mkOption {
529+ type = lib.types.int;
530+ default = 0;
531+ description = lib.mdDoc ''
532+ Increase verbosity. Mirrors the “-v” switch on the command line.
533+ '';
534+ };
535+536+ # Console access control
537+ adminUsers = mkOption {
538+ type = types.nullOr types.commas;
539+ default = null;
540+ description = lib.mdDoc ''
541+ Comma-separated list of database users that are allowed to connect and run all commands on the console.
542+ Ignored when authType is any, in which case any user name is allowed in as admin.
543+ '';
544+ };
545+546+ statsUsers = mkOption {
547+ type = types.nullOr types.commas;
548+ default = null;
549+ description = lib.mdDoc ''
550+ Comma-separated list of database users that are allowed to connect and run read-only queries on the console.
551+ That means all SHOW commands except SHOW FDS.
552+ '';
553+ };
554+555+ # Linux settings
556+ openFilesLimit = lib.mkOption {
557+ type = lib.types.int;
558+ default = 65536;
559+ description = lib.mdDoc ''
560+ Maximum number of open files.
561+ '';
562+ };
563+564+ user = mkOption {
565+ type = types.str;
566+ default = "pgbouncer";
567+ description = lib.mdDoc ''
568+ The user pgbouncer is run as.
569+ '';
570+ };
571+572+ group = mkOption {
573+ type = types.str;
574+ default = "pgbouncer";
575+ description = lib.mdDoc ''
576+ The group pgbouncer is run as.
577+ '';
578+ };
579+580+ homeDir = mkOption {
581+ type = types.path;
582+ default = "/var/lib/pgbouncer";
583+ description = lib.mdDoc ''
584+ Specifies the home directory.
585+ '';
586+ };
587+588+ # Extra settings
589+ extraConfig = mkOption {
590+ type = types.lines;
591+ description = lib.mdDoc ''
592+ Any additional text to be appended to config.ini
593+ <https://www.pgbouncer.org/config.html>.
594+ '';
595+ default = "";
596+ };
597+ };
598+599+ config = mkIf cfg.enable {
600+ users.groups.${cfg.group} = { };
601+ users.users.${cfg.user} = {
602+ description = "PgBouncer service user";
603+ group = cfg.group;
604+ home = cfg.homeDir;
605+ createHome = true;
606+ isSystemUser = true;
607+ };
608+609+ systemd.services.pgbouncer = {
610+ description = "PgBouncer - PostgreSQL connection pooler";
611+ wants = [ "postgresql.service" ];
612+ after = [ "postgresql.service" ];
613+ wantedBy = [ "multi-user.target" ];
614+ serviceConfig = {
615+ Type = "forking";
616+ User = cfg.user;
617+ Group = cfg.group;
618+ ExecStart = "${pkgs.pgbouncer}/bin/pgbouncer -d ${confFile}";
619+ ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID";
620+ RuntimeDirectory = "pgbouncer";
621+ PIDFile = "/run/pgbouncer/pgbouncer.pid";
622+ LimitNOFILE = cfg.openFilesLimit;
623+ };
624+ };
625+626+ networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
627+628+ };
629+630+ meta.maintainers = [ maintainers._1000101 ];
631+632+}
+1-1
nixos/modules/services/misc/cgminer.nix
···11 mapAttrsToList (n: v: ''"${n}": "${(concatStringsSep "," (map convType v))}"'')
12 (foldAttrs (n: a: [n] ++ a) [] cfg.hardware);
13 mergedConfig = with builtins;
14- mapAttrsToList (n: v: ''"${n}": ${if isBool v then "" else ''"''}${convType v}${if isBool v then "" else ''"''}'')
15 cfg.config;
1617 cgminerConfig = pkgs.writeText "cgminer.conf" ''
···11 mapAttrsToList (n: v: ''"${n}": "${(concatStringsSep "," (map convType v))}"'')
12 (foldAttrs (n: a: [n] ++ a) [] cfg.hardware);
13 mergedConfig = with builtins;
14+ mapAttrsToList (n: v: ''"${n}": ${if isBool v then convType v else ''"${convType v}"''}'')
15 cfg.config;
1617 cgminerConfig = pkgs.writeText "cgminer.conf" ''
+3-3
nixos/modules/services/misc/sourcehut/default.nix
···8 settingsFormat = pkgs.formats.ini {
9 listToValue = concatMapStringsSep "," (generators.mkValueStringDefault {});
10 mkKeyValue = k: v:
11- if v == null then ""
12- else generators.mkKeyValueDefault {
13 mkValueString = v:
14 if v == true then "yes"
15 else if v == false then "no"
16 else generators.mkValueStringDefault {} v;
17- } "=" k v;
18 };
19 configIniOfService = srv: settingsFormat.generate "sourcehut-${srv}-config.ini"
20 # Each service needs access to only a subset of sections (and secrets).
···8 settingsFormat = pkgs.formats.ini {
9 listToValue = concatMapStringsSep "," (generators.mkValueStringDefault {});
10 mkKeyValue = k: v:
11+ optionalString (v != null)
12+ (generators.mkKeyValueDefault {
13 mkValueString = v:
14 if v == true then "yes"
15 else if v == false then "no"
16 else generators.mkValueStringDefault {} v;
17+ } "=" k v);
18 };
19 configIniOfService = srv: settingsFormat.generate "sourcehut-${srv}-config.ini"
20 # Each service needs access to only a subset of sections (and secrets).
···137 '';
138139 yesOrNo = b: if b then "yes" else "no";
140- maybeString = prefix: x: if x == null then "" else ''${prefix} "${x}"'';
141- maybeToString = prefix: x: if x == null then "" else ''${prefix} ${toString x}'';
142 forEach = pre: l: concatMapStrings (x: pre + x + "\n") l;
143144
···137 '';
138139 yesOrNo = b: if b then "yes" else "no";
140+ maybeString = prefix: x: optionalString (x != null) ''${prefix} "${x}"'';
141+ maybeToString = prefix: x: optionalString (x != null) ''${prefix} ${toString x}'';
142 forEach = pre: l: concatMapStrings (x: pre + x + "\n") l;
143144
···100 };
101 };
102103- optionalKV = k: v: if v == null then "" else "${k} = ${builtins.toString v}";
104105 renderPhocOutput = name: output: let
106 modelines = if builtins.isList output.modeline
···100 };
101 };
102103+ optionalKV = k: v: optionalString (v != null) "${k} = ${builtins.toString v}";
104105 renderPhocOutput = name: output: let
106 modelines = if builtins.isList output.modeline
+3-4
nixos/modules/system/boot/kernel_config.nix
···70 let
71 val = if item.freeform != null then item.freeform else item.tristate;
72 in
73- if val == null
74- then ""
75- else if (item.optional)
76 then "${key}? ${mkValue val}\n"
77- else "${key} ${mkValue val}\n";
7879 mkConf = cfg: concatStrings (mapAttrsToList mkConfigLine cfg);
80 in mkConf exprs;
···70 let
71 val = if item.freeform != null then item.freeform else item.tristate;
72 in
73+ optionalString (val != null)
74+ (if (item.optional)
075 then "${key}? ${mkValue val}\n"
76+ else "${key} ${mkValue val}\n");
7778 mkConf = cfg: concatStrings (mapAttrsToList mkConfigLine cfg);
79 in mkConf exprs;
···4243 writeTmpfiles = { rules, user ? null }:
44 let
45- suffix = if user == null then "" else "-${user}";
46 in
47 pkgs.writeTextFile {
48 name = "nixos-user-tmpfiles.d${suffix}";
···4243 writeTmpfiles = { rules, user ? null }:
44 let
45+ suffix = optionalString (user != null) "-${user}";
46 in
47 pkgs.writeTextFile {
48 name = "nixos-user-tmpfiles.d${suffix}";
···59 bintoolsVersion = lib.getVersion bintools;
60 bintoolsName = lib.removePrefix targetPrefix (lib.getName bintools);
6162- libc_bin = if libc == null then "" else getBin libc;
63- libc_dev = if libc == null then "" else getDev libc;
64- libc_lib = if libc == null then "" else getLib libc;
65- bintools_bin = if nativeTools then "" else getBin bintools;
66 # The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
67- coreutils_bin = if nativeTools then "" else getBin coreutils;
6869 # See description in cc-wrapper.
70 suffixSalt = replaceStrings ["-" "."] ["_" "_"] targetPlatform.config;
···103stdenv.mkDerivation {
104 pname = targetPrefix
105 + (if name != "" then name else "${bintoolsName}-wrapper");
106- version = if bintools == null then "" else bintoolsVersion;
107108 preferLocalBuild = true;
109···265 # install the wrapper, you get tools like objdump (same for any
266 # binaries of libc).
267 + optionalString (!nativeTools) ''
268- printWords ${bintools_bin} ${if libc == null then "" else libc_bin} > $out/nix-support/propagated-user-env-packages
269 ''
270271 ##
···381 # for substitution in utils.bash
382 expandResponseParams = "${expand-response-params}/bin/expand-response-params";
383 shell = getBin shell + shell.shellPath or "";
384- gnugrep_bin = if nativeTools then "" else gnugrep;
385 wrapperName = "BINTOOLS_WRAPPER";
386 inherit dynamicLinker targetPrefix suffixSalt coreutils_bin;
387 inherit bintools_bin libc_bin libc_dev libc_lib;
···59 bintoolsVersion = lib.getVersion bintools;
60 bintoolsName = lib.removePrefix targetPrefix (lib.getName bintools);
6162+ libc_bin = lib.optionalString (libc != null) (getBin libc);
63+ libc_dev = lib.optionalString (libc != null) (getDev libc);
64+ libc_lib = lib.optionalString (libc != null) (getLib libc);
65+ bintools_bin = lib.optionalString (!nativeTools) (getBin bintools);
66 # The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
67+ coreutils_bin = lib.optionalString (!nativeTools) (getBin coreutils);
6869 # See description in cc-wrapper.
70 suffixSalt = replaceStrings ["-" "."] ["_" "_"] targetPlatform.config;
···103stdenv.mkDerivation {
104 pname = targetPrefix
105 + (if name != "" then name else "${bintoolsName}-wrapper");
106+ version = lib.optionalString (bintools != null) bintoolsVersion;
107108 preferLocalBuild = true;
109···265 # install the wrapper, you get tools like objdump (same for any
266 # binaries of libc).
267 + optionalString (!nativeTools) ''
268+ printWords ${bintools_bin} ${lib.optionalString (libc != null) libc_bin} > $out/nix-support/propagated-user-env-packages
269 ''
270271 ##
···381 # for substitution in utils.bash
382 expandResponseParams = "${expand-response-params}/bin/expand-response-params";
383 shell = getBin shell + shell.shellPath or "";
384+ gnugrep_bin = lib.optionalString (!nativeTools) gnugrep;
385 wrapperName = "BINTOOLS_WRAPPER";
386 inherit dynamicLinker targetPrefix suffixSalt coreutils_bin;
387 inherit bintools_bin libc_bin libc_dev libc_lib;
+7-7
pkgs/build-support/cc-wrapper/default.nix
···75 ccVersion = lib.getVersion cc;
76 ccName = lib.removePrefix targetPrefix (lib.getName cc);
7778- libc_bin = if libc == null then "" else getBin libc;
79- libc_dev = if libc == null then "" else getDev libc;
80- libc_lib = if libc == null then "" else getLib libc;
81 cc_solib = getLib cc
82 + optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}";
8384 # The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
85- coreutils_bin = if nativeTools then "" else getBin coreutils;
8687 # The "suffix salt" is a arbitrary string added in the end of env vars
88 # defined by cc-wrapper's hooks so that multiple cc-wrappers can be used
···176stdenv.mkDerivation {
177 pname = targetPrefix
178 + (if name != "" then name else "${ccName}-wrapper");
179- version = if cc == null then "" else ccVersion;
180181 preferLocalBuild = true;
182···612 # for substitution in utils.bash
613 expandResponseParams = "${expand-response-params}/bin/expand-response-params";
614 shell = getBin shell + shell.shellPath or "";
615- gnugrep_bin = if nativeTools then "" else gnugrep;
616 # stdenv.cc.cc should not be null and we have nothing better for now.
617 # if the native impure bootstrap is gotten rid of this can become `inherit cc;` again.
618- cc = if nativeTools then "" else cc;
619 wrapperName = "CC_WRAPPER";
620 inherit suffixSalt coreutils_bin bintools;
621 inherit libc_bin libc_dev libc_lib;
···75 ccVersion = lib.getVersion cc;
76 ccName = lib.removePrefix targetPrefix (lib.getName cc);
7778+ libc_bin = optionalString (libc != null) (getBin libc);
79+ libc_dev = optionalString (libc != null) (getDev libc);
80+ libc_lib = optionalString (libc != null) (getLib libc);
81 cc_solib = getLib cc
82 + optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}";
8384 # The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
85+ coreutils_bin = optionalString (!nativeTools) (getBin coreutils);
8687 # The "suffix salt" is a arbitrary string added in the end of env vars
88 # defined by cc-wrapper's hooks so that multiple cc-wrappers can be used
···176stdenv.mkDerivation {
177 pname = targetPrefix
178 + (if name != "" then name else "${ccName}-wrapper");
179+ version = optionalString (cc != null) ccVersion;
180181 preferLocalBuild = true;
182···612 # for substitution in utils.bash
613 expandResponseParams = "${expand-response-params}/bin/expand-response-params";
614 shell = getBin shell + shell.shellPath or "";
615+ gnugrep_bin = optionalString (!nativeTools) gnugrep;
616 # stdenv.cc.cc should not be null and we have nothing better for now.
617 # if the native impure bootstrap is gotten rid of this can become `inherit cc;` again.
618+ cc = optionalString (!nativeTools) cc;
619 wrapperName = "CC_WRAPPER";
620 inherit suffixSalt coreutils_bin bintools;
621 inherit libc_bin libc_dev libc_lib;
+1-1
pkgs/build-support/docker/default.nix
···594 nativeBuildInputs = [ jshon pigz jq moreutils ];
595 # Image name must be lowercase
596 imageName = lib.toLower name;
597- imageTag = if tag == null then "" else tag;
598 inherit fromImage baseJson;
599 layerClosure = writeReferencesToFile layer;
600 passthru.buildArgs = args;
···53 disabled = pythonAtLeast "3.11";
5455 src = let
56- pyVerNoDot = lib.strings.stringAsChars (x: if x == "." then "" else x) python.pythonVersion;
57 platform = if stdenv.isDarwin then "mac" else "linux";
58 unit = if cudaSupport then "gpu" else "cpu";
59 key = "${platform}_py_${pyVerNoDot}_${unit}";
···53 disabled = pythonAtLeast "3.11";
5455 src = let
56+ pyVerNoDot = lib.strings.stringAsChars (x: lib.optionalString (x != ".") x) python.pythonVersion;
57 platform = if stdenv.isDarwin then "mac" else "linux";
58 unit = if cudaSupport then "gpu" else "cpu";
59 key = "${platform}_py_${pyVerNoDot}_${unit}";
···70 assert gemFiles.gemdir != null; "cp -a ${gemFiles.gemdir}/* $out/") #*/
71 );
7273- maybeCopyAll = pkgname: if pkgname == null then "" else
74- let
75- mainGem = gems.${pkgname} or (throw "bundlerEnv: gem ${pkgname} not found");
76- in
77- copyIfBundledByPath mainGem;
07879 # We have to normalize the Gemfile.lock, otherwise bundler tries to be
80 # helpful by doing so at run time, causing executables to immediately bail
···70 assert gemFiles.gemdir != null; "cp -a ${gemFiles.gemdir}/* $out/") #*/
71 );
7273+ maybeCopyAll = pkgname: lib.optionalString (pkgname != null) (
74+ let
75+ mainGem = gems.${pkgname} or (throw "bundlerEnv: gem ${pkgname} not found");
76+ in
77+ copyIfBundledByPath mainGem
78+ );
7980 # We have to normalize the Gemfile.lock, otherwise bundler tries to be
81 # helpful by doing so at run time, causing executables to immediately bail
···1+{ lib
2+, buildGoModule
3+, fetchFromGitHub
4+}:
5+6+buildGoModule rec {
7+ pname = "mox";
8+ version = "0.0.5";
9+10+ src = fetchFromGitHub {
11+ owner = "mjl-";
12+ repo = "mox";
13+ rev = "v${version}";
14+ hash = "sha256-f5/K6cPqJJkbdiVCNGOTd9Fjx2/gvSZCxeR6nnEaeJw=";
15+ };
16+17+ # set the version during buildtime
18+ patches = [ ./version.patch ];
19+20+ vendorHash = null;
21+22+ ldflags = [
23+ "-s"
24+ "-w"
25+ "-X github.com/mjl-/mox/moxvar.Version=${version}"
26+ ];
27+28+ meta = {
29+ description = "Modern full-featured open source secure mail server for low-maintenance self-hosted email";
30+ homepage = "https://github.com/mjl-/mox";
31+ license = lib.licenses.mit;
32+ maintainers = with lib.maintainers; [ dit7ya ];
33+ };
34+}
+45
pkgs/servers/mail/mox/version.patch
···000000000000000000000000000000000000000000000
···1+diff --git a/moxvar/version.go b/moxvar/version.go
2+index 8c6bac8..69b5f7c 100644
3+--- a/moxvar/version.go
4++++ b/moxvar/version.go
5+@@ -1,38 +1,5 @@
6+ // Package moxvar provides the version number of a mox build.
7+ package moxvar
8+9+-import (
10+- "runtime/debug"
11+-)
12+-
13+-// Version is set at runtime based on the Go module used to build.
14+-var Version = "(devel)"
15+-
16+-func init() {
17+- buildInfo, ok := debug.ReadBuildInfo()
18+- if !ok {
19+- return
20+- }
21+- Version = buildInfo.Main.Version
22+- if Version == "(devel)" {
23+- var vcsRev, vcsMod string
24+- for _, setting := range buildInfo.Settings {
25+- if setting.Key == "vcs.revision" {
26+- vcsRev = setting.Value
27+- } else if setting.Key == "vcs.modified" {
28+- vcsMod = setting.Value
29+- }
30+- }
31+- if vcsRev == "" {
32+- return
33+- }
34+- Version = vcsRev
35+- switch vcsMod {
36+- case "false":
37+- case "true":
38+- Version += "+modifications"
39+- default:
40+- Version += "+unknown"
41+- }
42+- }
43+-}
44++// Version is set via a build flag
45++var Version string;