···24242525- [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.
26262727+- [pgBouncer](https://www.pgbouncer.org), a PostgreSQL connection pooler. Available as [services.pgbouncer](#opt-services.pgbouncer.enable).
2828+2729- [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).
28302931- [osquery](https://www.osquery.io/), a SQL powered operating system instrumentation, monitoring, and analytics.
30323133- [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).
3434+32353336## Backward Incompatibilities {#sec-release-23.11-incompatibilities}
3437
···11+{ lib, pkgs, config, ... } :
22+33+with lib;
44+55+let
66+ cfg = config.services.pgbouncer;
77+88+ confFile = pkgs.writeTextFile {
99+ name = "pgbouncer.ini";
1010+ text = ''
1111+ [databases]
1212+ ${concatStringsSep "\n"
1313+ (mapAttrsToList (dbname : settings : "${dbname} = ${settings}") cfg.databases)}
1414+1515+ [users]
1616+ ${concatStringsSep "\n"
1717+ (mapAttrsToList (username : settings : "${username} = ${settings}") cfg.users)}
1818+1919+ [peers]
2020+ ${concatStringsSep "\n"
2121+ (mapAttrsToList (peerid : settings : "${peerid} = ${settings}") cfg.peers)}
2222+2323+ [pgbouncer]
2424+ # general
2525+ ${optionalString (cfg.ignoreStartupParameters != null) "ignore_startup_parameters = ${cfg.ignoreStartupParameters}"}
2626+ listen_port = ${toString cfg.listenPort}
2727+ ${optionalString (cfg.listenAddress != null) "listen_addr = ${cfg.listenAddress}"}
2828+ pool_mode = ${cfg.poolMode}
2929+ max_client_conn = ${toString cfg.maxClientConn}
3030+ default_pool_size = ${toString cfg.defaultPoolSize}
3131+ max_user_connections = ${toString cfg.maxUserConnections}
3232+ max_db_connections = ${toString cfg.maxDbConnections}
3333+3434+ #auth
3535+ auth_type = ${cfg.authType}
3636+ ${optionalString (cfg.authHbaFile != null) "auth_hba_file = ${cfg.authHbaFile}"}
3737+ ${optionalString (cfg.authFile != null) "auth_file = ${cfg.authFile}"}
3838+ ${optionalString (cfg.authUser != null) "auth_user = ${cfg.authUser}"}
3939+ ${optionalString (cfg.authQuery != null) "auth_query = ${cfg.authQuery}"}
4040+ ${optionalString (cfg.authDbname != null) "auth_dbname = ${cfg.authDbname}"}
4141+4242+ # TLS
4343+ ${optionalString (cfg.tls.client != null) ''
4444+ client_tls_sslmode = ${cfg.tls.client.sslmode}
4545+ client_tls_key_file = ${cfg.tls.client.keyFile}
4646+ client_tls_cert_file = ${cfg.tls.client.certFile}
4747+ client_tls_ca_file = ${cfg.tls.client.caFile}
4848+ ''}
4949+ ${optionalString (cfg.tls.server != null) ''
5050+ server_tls_sslmode = ${cfg.tls.server.sslmode}
5151+ server_tls_key_file = ${cfg.tls.server.keyFile}
5252+ server_tls_cert_file = ${cfg.tls.server.certFile}
5353+ server_tls_ca_file = ${cfg.tls.server.caFile}
5454+ ''}
5555+5656+ # log
5757+ ${optionalString (cfg.logFile != null) "logfile = ${cfg.homeDir}/${cfg.logFile}"}
5858+ ${optionalString (cfg.syslog != null) ''
5959+ syslog = ${if cfg.syslog.enable then "1" else "0"}
6060+ syslog_ident = ${cfg.syslog.syslogIdent}
6161+ syslog_facility = ${cfg.syslog.syslogFacility}
6262+ ''}
6363+ ${optionalString (cfg.verbose != null) "verbose = ${toString cfg.verbose}"}
6464+6565+ # console access
6666+ ${optionalString (cfg.adminUsers != null) "admin_users = ${cfg.adminUsers}"}
6767+ ${optionalString (cfg.statsUsers != null) "stats_users = ${cfg.statsUsers}"}
6868+6969+ # linux
7070+ pidfile = /run/pgbouncer/pgbouncer.pid
7171+7272+ # extra
7373+ ${cfg.extraConfig}
7474+ '';
7575+ };
7676+7777+in {
7878+7979+ options.services.pgbouncer = {
8080+8181+ # NixOS settings
8282+8383+ enable = mkEnableOption (lib.mdDoc "PostgreSQL connection pooler");
8484+8585+ package = mkOption {
8686+ type = types.package;
8787+ default = pkgs.pgbouncer;
8888+ defaultText = literalExpression "pkgs.pgbouncer";
8989+ description = lib.mdDoc ''
9090+ The pgbouncer package to use.
9191+ '';
9292+ };
9393+9494+ openFirewall = mkOption {
9595+ type = types.bool;
9696+ default = false;
9797+ description = lib.mdDoc ''
9898+ Whether to automatically open the specified TCP port in the firewall.
9999+ '';
100100+ };
101101+102102+ # Generic settings
103103+104104+ logFile = mkOption {
105105+ type = types.nullOr types.str;
106106+ default = "pgbouncer.log";
107107+ description = lib.mdDoc ''
108108+ Specifies the log file.
109109+ Either this or syslog has to be specified.
110110+ '';
111111+ };
112112+113113+ listenAddress = mkOption {
114114+ type = types.nullOr types.commas;
115115+ example = "*";
116116+ default = null;
117117+ description = lib.mdDoc ''
118118+ Specifies a list (comma-separated) of addresses where to listen for TCP connections.
119119+ You may also use * meaning “listen on all addresses”.
120120+ When not set, only Unix socket connections are accepted.
121121+122122+ Addresses can be specified numerically (IPv4/IPv6) or by name.
123123+ '';
124124+ };
125125+126126+ listenPort = mkOption {
127127+ type = types.port;
128128+ default = 6432;
129129+ description = lib.mdDoc ''
130130+ Which port to listen on. Applies to both TCP and Unix sockets.
131131+ '';
132132+ };
133133+134134+ poolMode = mkOption {
135135+ type = types.enum [ "session" "transaction" "statement" ];
136136+ default = "session";
137137+ description = lib.mdDoc ''
138138+ Specifies when a server connection can be reused by other clients.
139139+140140+ session
141141+ Server is released back to pool after client disconnects. Default.
142142+ transaction
143143+ Server is released back to pool after transaction finishes.
144144+ statement
145145+ Server is released back to pool after query finishes.
146146+ Transactions spanning multiple statements are disallowed in this mode.
147147+ '';
148148+ };
149149+150150+ maxClientConn = mkOption {
151151+ type = types.int;
152152+ default = 100;
153153+ description = lib.mdDoc ''
154154+ Maximum number of client connections allowed.
155155+156156+ When this setting is increased, then the file descriptor limits in the operating system
157157+ might also have to be increased. Note that the number of file descriptors potentially
158158+ used is more than maxClientConn. If each user connects under its own user name to the server,
159159+ the theoretical maximum used is:
160160+ maxClientConn + (max pool_size * total databases * total users)
161161+162162+ If a database user is specified in the connection string (all users connect under the same user name),
163163+ the theoretical maximum is:
164164+ maxClientConn + (max pool_size * total databases)
165165+166166+ The theoretical maximum should never be reached, unless somebody deliberately crafts a special load for it.
167167+ Still, it means you should set the number of file descriptors to a safely high number.
168168+ '';
169169+ };
170170+171171+ defaultPoolSize = mkOption {
172172+ type = types.int;
173173+ default = 20;
174174+ description = lib.mdDoc ''
175175+ How many server connections to allow per user/database pair.
176176+ Can be overridden in the per-database configuration.
177177+ '';
178178+ };
179179+180180+ maxDbConnections = mkOption {
181181+ type = types.int;
182182+ default = 0;
183183+ description = lib.mdDoc ''
184184+ Do not allow more than this many server connections per database (regardless of user).
185185+ This considers the PgBouncer database that the client has connected to,
186186+ not the PostgreSQL database of the outgoing connection.
187187+188188+ This can also be set per database in the [databases] section.
189189+190190+ Note that when you hit the limit, closing a client connection to one pool will
191191+ not immediately allow a server connection to be established for another pool,
192192+ because the server connection for the first pool is still open.
193193+ Once the server connection closes (due to idle timeout),
194194+ a new server connection will immediately be opened for the waiting pool.
195195+196196+ 0 = unlimited
197197+ '';
198198+ };
199199+200200+ maxUserConnections = mkOption {
201201+ type = types.int;
202202+ default = 0;
203203+ description = lib.mdDoc ''
204204+ Do not allow more than this many server connections per user (regardless of database).
205205+ This considers the PgBouncer user that is associated with a pool,
206206+ which is either the user specified for the server connection
207207+ or in absence of that the user the client has connected as.
208208+209209+ This can also be set per user in the [users] section.
210210+211211+ Note that when you hit the limit, closing a client connection to one pool
212212+ will not immediately allow a server connection to be established for another pool,
213213+ because the server connection for the first pool is still open.
214214+ Once the server connection closes (due to idle timeout), a new server connection
215215+ will immediately be opened for the waiting pool.
216216+217217+ 0 = unlimited
218218+ '';
219219+ };
220220+221221+ ignoreStartupParameters = mkOption {
222222+ type = types.nullOr types.commas;
223223+ example = "extra_float_digits";
224224+ default = null;
225225+ description = lib.mdDoc ''
226226+ By default, PgBouncer allows only parameters it can keep track of in startup packets:
227227+ client_encoding, datestyle, timezone and standard_conforming_strings.
228228+229229+ All others parameters will raise an error.
230230+ To allow others parameters, they can be specified here, so that PgBouncer knows that
231231+ they are handled by the admin and it can ignore them.
232232+233233+ If you need to specify multiple values, use a comma-separated list.
234234+235235+ IMPORTANT: When using prometheus-pgbouncer-exporter, you need:
236236+ extra_float_digits
237237+ <https://github.com/prometheus-community/pgbouncer_exporter#pgbouncer-configuration>
238238+ '';
239239+ };
240240+241241+ # Section [databases]
242242+ databases = mkOption {
243243+ type = types.attrsOf types.str;
244244+ default = {};
245245+ example = {
246246+ exampledb = "host=/run/postgresql/ port=5432 auth_user=exampleuser dbname=exampledb sslmode=require";
247247+ bardb = "host=localhost dbname=bazdb";
248248+ foodb = "host=host1.example.com port=5432";
249249+ };
250250+ description = lib.mdDoc ''
251251+ Detailed information about PostgreSQL database definitions:
252252+ <https://www.pgbouncer.org/config.html#section-databases>
253253+ '';
254254+ };
255255+256256+ # Section [users]
257257+ users = mkOption {
258258+ type = types.attrsOf types.str;
259259+ default = {};
260260+ example = {
261261+ user1 = "pool_mode=session";
262262+ };
263263+ description = lib.mdDoc ''
264264+ Optional.
265265+266266+ Detailed information about PostgreSQL user definitions:
267267+ <https://www.pgbouncer.org/config.html#section-users>
268268+ '';
269269+ };
270270+271271+ # Section [peers]
272272+ peers = mkOption {
273273+ type = types.attrsOf types.str;
274274+ default = {};
275275+ example = {
276276+ "1" = "host=host1.example.com";
277277+ "2" = "host=/tmp/pgbouncer-2 port=5555";
278278+ };
279279+ description = lib.mdDoc ''
280280+ Optional.
281281+282282+ Detailed information about PostgreSQL database definitions:
283283+ <https://www.pgbouncer.org/config.html#section-peers>
284284+ '';
285285+ };
286286+287287+ # Authentication settings
288288+ authType = mkOption {
289289+ type = types.enum [ "cert" "md5" "scram-sha-256" "plain" "trust" "any" "hba" "pam" ];
290290+ default = "md5";
291291+ description = lib.mdDoc ''
292292+ How to authenticate users.
293293+294294+ cert
295295+ Client must connect over TLS connection with a valid client certificate.
296296+ The user name is then taken from the CommonName field from the certificate.
297297+ md5
298298+ Use MD5-based password check. This is the default authentication method.
299299+ authFile may contain both MD5-encrypted and plain-text passwords.
300300+ If md5 is configured and a user has a SCRAM secret, then SCRAM authentication is used automatically instead.
301301+ scram-sha-256
302302+ Use password check with SCRAM-SHA-256. authFile has to contain SCRAM secrets or plain-text passwords.
303303+ plain
304304+ The clear-text password is sent over the wire. Deprecated.
305305+ trust
306306+ No authentication is done. The user name must still exist in authFile.
307307+ any
308308+ Like the trust method, but the user name given is ignored.
309309+ Requires that all databases are configured to log in as a specific user.
310310+ Additionally, the console database allows any user to log in as admin.
311311+ hba
312312+ The actual authentication type is loaded from authHbaFile.
313313+ This allows different authentication methods for different access paths,
314314+ for example: connections over Unix socket use the peer auth method, connections over TCP must use TLS.
315315+ pam
316316+ PAM is used to authenticate users, authFile is ignored.
317317+ This method is not compatible with databases using the authUser option.
318318+ The service name reported to PAM is “pgbouncer”. pam is not supported in the HBA configuration file.
319319+ '';
320320+ };
321321+322322+ authHbaFile = mkOption {
323323+ type = types.nullOr types.path;
324324+ default = null;
325325+ example = "/secrets/pgbouncer_hba";
326326+ description = lib.mdDoc ''
327327+ HBA configuration file to use when authType is hba.
328328+329329+ See HBA file format details:
330330+ <https://www.pgbouncer.org/config.html#hba-file-format>
331331+ '';
332332+ };
333333+334334+ authFile = mkOption {
335335+ type = types.nullOr types.path;
336336+ default = null;
337337+ example = "/secrets/pgbouncer_authfile";
338338+ description = lib.mdDoc ''
339339+ The name of the file to load user names and passwords from.
340340+341341+ See section Authentication file format details:
342342+ <https://www.pgbouncer.org/config.html#authentication-file-format>
343343+344344+ Most authentication types require that either authFile or authUser be set;
345345+ otherwise there would be no users defined.
346346+ '';
347347+ };
348348+349349+ authUser = mkOption {
350350+ type = types.nullOr types.str;
351351+ default = null;
352352+ example = "pgbouncer";
353353+ description = lib.mdDoc ''
354354+ If authUser is set, then any user not specified in authFile will be queried
355355+ through the authQuery query from pg_shadow in the database, using authUser.
356356+ The password of authUser will be taken from authFile.
357357+ (If the authUser does not require a password then it does not need to be defined in authFile.)
358358+359359+ Direct access to pg_shadow requires admin rights.
360360+ It's preferable to use a non-superuser that calls a SECURITY DEFINER function instead.
361361+ '';
362362+ };
363363+364364+ authQuery = mkOption {
365365+ type = types.nullOr types.str;
366366+ default = null;
367367+ example = "SELECT usename, passwd FROM pg_shadow WHERE usename=$1";
368368+ description = lib.mdDoc ''
369369+ Query to load user's password from database.
370370+371371+ Direct access to pg_shadow requires admin rights.
372372+ It's preferable to use a non-superuser that calls a SECURITY DEFINER function instead.
373373+374374+ Note that the query is run inside the target database.
375375+ So if a function is used, it needs to be installed into each database.
376376+ '';
377377+ };
378378+379379+ authDbname = mkOption {
380380+ type = types.nullOr types.str;
381381+ default = null;
382382+ example = "authdb";
383383+ description = lib.mdDoc ''
384384+ Database name in the [database] section to be used for authentication purposes.
385385+ This option can be either global or overriden in the connection string if this parameter is specified.
386386+ '';
387387+ };
388388+389389+ # TLS settings
390390+ tls.client = mkOption {
391391+ type = types.nullOr (types.submodule {
392392+ options = {
393393+ sslmode = mkOption {
394394+ type = types.enum [ "disable" "allow" "prefer" "require" "verify-ca" "verify-full" ];
395395+ default = "disable";
396396+ description = lib.mdDoc ''
397397+ TLS mode to use for connections from clients.
398398+ TLS connections are disabled by default.
399399+400400+ When enabled, tls.client.keyFile and tls.client.certFile
401401+ must be also configured to set up the key and certificate
402402+ PgBouncer uses to accept client connections.
403403+404404+ disable
405405+ Plain TCP. If client requests TLS, it's ignored. Default.
406406+ allow
407407+ If client requests TLS, it is used. If not, plain TCP is used.
408408+ If the client presents a client certificate, it is not validated.
409409+ prefer
410410+ Same as allow.
411411+ require
412412+ Client must use TLS. If not, the client connection is rejected.
413413+ If the client presents a client certificate, it is not validated.
414414+ verify-ca
415415+ Client must use TLS with valid client certificate.
416416+ verify-full
417417+ Same as verify-ca
418418+ '';
419419+ };
420420+ certFile = mkOption {
421421+ type = types.path;
422422+ example = "/secrets/pgbouncer.key";
423423+ description = lib.mdDoc "Path to certificate for private key. Clients can validate it";
424424+ };
425425+ keyFile = mkOption {
426426+ type = types.path;
427427+ example = "/secrets/pgbouncer.crt";
428428+ description = lib.mdDoc "Path to private key for PgBouncer to accept client connections";
429429+ };
430430+ caFile = mkOption {
431431+ type = types.path;
432432+ example = "/secrets/pgbouncer.crt";
433433+ description = lib.mdDoc "Path to root certificate file to validate client certificates";
434434+ };
435435+ };
436436+ });
437437+ default = null;
438438+ description = lib.mdDoc ''
439439+ <https://www.pgbouncer.org/config.html#tls-settings>
440440+ '';
441441+ };
442442+443443+ tls.server = mkOption {
444444+ type = types.nullOr (types.submodule {
445445+ options = {
446446+ sslmode = mkOption {
447447+ type = types.enum [ "disable" "allow" "prefer" "require" "verify-ca" "verify-full" ];
448448+ default = "disable";
449449+ description = lib.mdDoc ''
450450+ TLS mode to use for connections to PostgreSQL servers.
451451+ TLS connections are disabled by default.
452452+453453+ disable
454454+ Plain TCP. TLS is not even requested from the server. Default.
455455+ allow
456456+ FIXME: if server rejects plain, try TLS?
457457+ prefer
458458+ TLS connection is always requested first from PostgreSQL.
459459+ If refused, the connection will be established over plain TCP.
460460+ Server certificate is not validated.
461461+ require
462462+ Connection must go over TLS. If server rejects it, plain TCP is not attempted.
463463+ Server certificate is not validated.
464464+ verify-ca
465465+ Connection must go over TLS and server certificate must be valid according to tls.server.caFile.
466466+ Server host name is not checked against certificate.
467467+ verify-full
468468+ Connection must go over TLS and server certificate must be valid according to tls.server.caFile.
469469+ Server host name must match certificate information.
470470+ '';
471471+ };
472472+ certFile = mkOption {
473473+ type = types.path;
474474+ example = "/secrets/pgbouncer_server.key";
475475+ description = lib.mdDoc "Certificate for private key. PostgreSQL server can validate it.";
476476+ };
477477+ keyFile = mkOption {
478478+ type = types.path;
479479+ example = "/secrets/pgbouncer_server.crt";
480480+ description = lib.mdDoc "Private key for PgBouncer to authenticate against PostgreSQL server.";
481481+ };
482482+ caFile = mkOption {
483483+ type = types.path;
484484+ example = "/secrets/pgbouncer_server.crt";
485485+ description = lib.mdDoc "Root certificate file to validate PostgreSQL server certificates.";
486486+ };
487487+ };
488488+ });
489489+ default = null;
490490+ description = lib.mdDoc ''
491491+ <https://www.pgbouncer.org/config.html#tls-settings>
492492+ '';
493493+ };
494494+495495+ # Log settings
496496+ syslog = mkOption {
497497+ type = types.nullOr (types.submodule {
498498+ options = {
499499+ enable = mkOption {
500500+ type = types.bool;
501501+ default = false;
502502+ description = lib.mdDoc ''
503503+ Toggles syslog on/off.
504504+ '';
505505+ };
506506+ syslogIdent = mkOption {
507507+ type = types.str;
508508+ default = "pgbouncer";
509509+ description = lib.mdDoc ''
510510+ Under what name to send logs to syslog.
511511+ '';
512512+ };
513513+ syslogFacility = mkOption {
514514+ type = types.enum [ "auth" "authpriv" "daemon" "user" "local0" "local1" "local2" "local3" "local4" "local5" "local6" "local7" ];
515515+ default = "daemon";
516516+ description = lib.mdDoc ''
517517+ Under what facility to send logs to syslog.
518518+ '';
519519+ };
520520+ };
521521+ });
522522+ default = null;
523523+ description = lib.mdDoc ''
524524+ <https://www.pgbouncer.org/config.html#log-settings>
525525+ '';
526526+ };
527527+528528+ verbose = lib.mkOption {
529529+ type = lib.types.int;
530530+ default = 0;
531531+ description = lib.mdDoc ''
532532+ Increase verbosity. Mirrors the “-v” switch on the command line.
533533+ '';
534534+ };
535535+536536+ # Console access control
537537+ adminUsers = mkOption {
538538+ type = types.nullOr types.commas;
539539+ default = null;
540540+ description = lib.mdDoc ''
541541+ Comma-separated list of database users that are allowed to connect and run all commands on the console.
542542+ Ignored when authType is any, in which case any user name is allowed in as admin.
543543+ '';
544544+ };
545545+546546+ statsUsers = mkOption {
547547+ type = types.nullOr types.commas;
548548+ default = null;
549549+ description = lib.mdDoc ''
550550+ Comma-separated list of database users that are allowed to connect and run read-only queries on the console.
551551+ That means all SHOW commands except SHOW FDS.
552552+ '';
553553+ };
554554+555555+ # Linux settings
556556+ openFilesLimit = lib.mkOption {
557557+ type = lib.types.int;
558558+ default = 65536;
559559+ description = lib.mdDoc ''
560560+ Maximum number of open files.
561561+ '';
562562+ };
563563+564564+ user = mkOption {
565565+ type = types.str;
566566+ default = "pgbouncer";
567567+ description = lib.mdDoc ''
568568+ The user pgbouncer is run as.
569569+ '';
570570+ };
571571+572572+ group = mkOption {
573573+ type = types.str;
574574+ default = "pgbouncer";
575575+ description = lib.mdDoc ''
576576+ The group pgbouncer is run as.
577577+ '';
578578+ };
579579+580580+ homeDir = mkOption {
581581+ type = types.path;
582582+ default = "/var/lib/pgbouncer";
583583+ description = lib.mdDoc ''
584584+ Specifies the home directory.
585585+ '';
586586+ };
587587+588588+ # Extra settings
589589+ extraConfig = mkOption {
590590+ type = types.lines;
591591+ description = lib.mdDoc ''
592592+ Any additional text to be appended to config.ini
593593+ <https://www.pgbouncer.org/config.html>.
594594+ '';
595595+ default = "";
596596+ };
597597+ };
598598+599599+ config = mkIf cfg.enable {
600600+ users.groups.${cfg.group} = { };
601601+ users.users.${cfg.user} = {
602602+ description = "PgBouncer service user";
603603+ group = cfg.group;
604604+ home = cfg.homeDir;
605605+ createHome = true;
606606+ isSystemUser = true;
607607+ };
608608+609609+ systemd.services.pgbouncer = {
610610+ description = "PgBouncer - PostgreSQL connection pooler";
611611+ wants = [ "postgresql.service" ];
612612+ after = [ "postgresql.service" ];
613613+ wantedBy = [ "multi-user.target" ];
614614+ serviceConfig = {
615615+ Type = "forking";
616616+ User = cfg.user;
617617+ Group = cfg.group;
618618+ ExecStart = "${pkgs.pgbouncer}/bin/pgbouncer -d ${confFile}";
619619+ ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID";
620620+ RuntimeDirectory = "pgbouncer";
621621+ PIDFile = "/run/pgbouncer/pgbouncer.pid";
622622+ LimitNOFILE = cfg.openFilesLimit;
623623+ };
624624+ };
625625+626626+ networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
627627+628628+ };
629629+630630+ meta.maintainers = [ maintainers._1000101 ];
631631+632632+}
+1-1
nixos/modules/services/misc/cgminer.nix
···1111 mapAttrsToList (n: v: ''"${n}": "${(concatStringsSep "," (map convType v))}"'')
1212 (foldAttrs (n: a: [n] ++ a) [] cfg.hardware);
1313 mergedConfig = with builtins;
1414- mapAttrsToList (n: v: ''"${n}": ${if isBool v then "" else ''"''}${convType v}${if isBool v then "" else ''"''}'')
1414+ mapAttrsToList (n: v: ''"${n}": ${if isBool v then convType v else ''"${convType v}"''}'')
1515 cfg.config;
16161717 cgminerConfig = pkgs.writeText "cgminer.conf" ''
+3-3
nixos/modules/services/misc/sourcehut/default.nix
···88 settingsFormat = pkgs.formats.ini {
99 listToValue = concatMapStringsSep "," (generators.mkValueStringDefault {});
1010 mkKeyValue = k: v:
1111- if v == null then ""
1212- else generators.mkKeyValueDefault {
1111+ optionalString (v != null)
1212+ (generators.mkKeyValueDefault {
1313 mkValueString = v:
1414 if v == true then "yes"
1515 else if v == false then "no"
1616 else generators.mkValueStringDefault {} v;
1717- } "=" k v;
1717+ } "=" k v);
1818 };
1919 configIniOfService = srv: settingsFormat.generate "sourcehut-${srv}-config.ini"
2020 # Each service needs access to only a subset of sections (and secrets).
···5959 bintoolsVersion = lib.getVersion bintools;
6060 bintoolsName = lib.removePrefix targetPrefix (lib.getName bintools);
61616262- libc_bin = if libc == null then "" else getBin libc;
6363- libc_dev = if libc == null then "" else getDev libc;
6464- libc_lib = if libc == null then "" else getLib libc;
6565- bintools_bin = if nativeTools then "" else getBin bintools;
6262+ libc_bin = lib.optionalString (libc != null) (getBin libc);
6363+ libc_dev = lib.optionalString (libc != null) (getDev libc);
6464+ libc_lib = lib.optionalString (libc != null) (getLib libc);
6565+ bintools_bin = lib.optionalString (!nativeTools) (getBin bintools);
6666 # The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
6767- coreutils_bin = if nativeTools then "" else getBin coreutils;
6767+ coreutils_bin = lib.optionalString (!nativeTools) (getBin coreutils);
68686969 # See description in cc-wrapper.
7070 suffixSalt = replaceStrings ["-" "."] ["_" "_"] targetPlatform.config;
···103103stdenv.mkDerivation {
104104 pname = targetPrefix
105105 + (if name != "" then name else "${bintoolsName}-wrapper");
106106- version = if bintools == null then "" else bintoolsVersion;
106106+ version = lib.optionalString (bintools != null) bintoolsVersion;
107107108108 preferLocalBuild = true;
109109···265265 # install the wrapper, you get tools like objdump (same for any
266266 # binaries of libc).
267267 + optionalString (!nativeTools) ''
268268- printWords ${bintools_bin} ${if libc == null then "" else libc_bin} > $out/nix-support/propagated-user-env-packages
268268+ printWords ${bintools_bin} ${lib.optionalString (libc != null) libc_bin} > $out/nix-support/propagated-user-env-packages
269269 ''
270270271271 ##
···381381 # for substitution in utils.bash
382382 expandResponseParams = "${expand-response-params}/bin/expand-response-params";
383383 shell = getBin shell + shell.shellPath or "";
384384- gnugrep_bin = if nativeTools then "" else gnugrep;
384384+ gnugrep_bin = lib.optionalString (!nativeTools) gnugrep;
385385 wrapperName = "BINTOOLS_WRAPPER";
386386 inherit dynamicLinker targetPrefix suffixSalt coreutils_bin;
387387 inherit bintools_bin libc_bin libc_dev libc_lib;
+7-7
pkgs/build-support/cc-wrapper/default.nix
···7575 ccVersion = lib.getVersion cc;
7676 ccName = lib.removePrefix targetPrefix (lib.getName cc);
77777878- libc_bin = if libc == null then "" else getBin libc;
7979- libc_dev = if libc == null then "" else getDev libc;
8080- libc_lib = if libc == null then "" else getLib libc;
7878+ libc_bin = optionalString (libc != null) (getBin libc);
7979+ libc_dev = optionalString (libc != null) (getDev libc);
8080+ libc_lib = optionalString (libc != null) (getLib libc);
8181 cc_solib = getLib cc
8282 + optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}";
83838484 # The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
8585- coreutils_bin = if nativeTools then "" else getBin coreutils;
8585+ coreutils_bin = optionalString (!nativeTools) (getBin coreutils);
86868787 # The "suffix salt" is a arbitrary string added in the end of env vars
8888 # defined by cc-wrapper's hooks so that multiple cc-wrappers can be used
···176176stdenv.mkDerivation {
177177 pname = targetPrefix
178178 + (if name != "" then name else "${ccName}-wrapper");
179179- version = if cc == null then "" else ccVersion;
179179+ version = optionalString (cc != null) ccVersion;
180180181181 preferLocalBuild = true;
182182···612612 # for substitution in utils.bash
613613 expandResponseParams = "${expand-response-params}/bin/expand-response-params";
614614 shell = getBin shell + shell.shellPath or "";
615615- gnugrep_bin = if nativeTools then "" else gnugrep;
615615+ gnugrep_bin = optionalString (!nativeTools) gnugrep;
616616 # stdenv.cc.cc should not be null and we have nothing better for now.
617617 # if the native impure bootstrap is gotten rid of this can become `inherit cc;` again.
618618- cc = if nativeTools then "" else cc;
618618+ cc = optionalString (!nativeTools) cc;
619619 wrapperName = "CC_WRAPPER";
620620 inherit suffixSalt coreutils_bin bintools;
621621 inherit libc_bin libc_dev libc_lib;
+1-1
pkgs/build-support/docker/default.nix
···594594 nativeBuildInputs = [ jshon pigz jq moreutils ];
595595 # Image name must be lowercase
596596 imageName = lib.toLower name;
597597- imageTag = if tag == null then "" else tag;
597597+ imageTag = lib.optionalString (tag != null) tag;
598598 inherit fromImage baseJson;
599599 layerClosure = writeReferencesToFile layer;
600600 passthru.buildArgs = args;
+1-1
pkgs/build-support/fetchgithub/default.nix
···2424 position = "${position.file}:${toString position.line}";
2525 };
2626 passthruAttrs = removeAttrs args [ "owner" "repo" "rev" "fetchSubmodules" "forceFetchGit" "private" "githubBase" "varPrefix" ];
2727- varBase = "NIX${if varPrefix == null then "" else "_${varPrefix}"}_GITHUB_PRIVATE_";
2727+ varBase = "NIX${lib.optionalString (varPrefix != null) "_${varPrefix}"}_GITHUB_PRIVATE_";
2828 useFetchGit = fetchSubmodules || (leaveDotGit == true) || deepClone || forceFetchGit || (sparseCheckout != []);
2929 # We prefer fetchzip in cases we don't need submodules as the hash
3030 # is more stable in that case.
···7070 assert gemFiles.gemdir != null; "cp -a ${gemFiles.gemdir}/* $out/") #*/
7171 );
72727373- maybeCopyAll = pkgname: if pkgname == null then "" else
7474- let
7575- mainGem = gems.${pkgname} or (throw "bundlerEnv: gem ${pkgname} not found");
7676- in
7777- copyIfBundledByPath mainGem;
7373+ maybeCopyAll = pkgname: lib.optionalString (pkgname != null) (
7474+ let
7575+ mainGem = gems.${pkgname} or (throw "bundlerEnv: gem ${pkgname} not found");
7676+ in
7777+ copyIfBundledByPath mainGem
7878+ );
78797980 # We have to normalize the Gemfile.lock, otherwise bundler tries to be
8081 # helpful by doing so at run time, causing executables to immediately bail
···11+{ lib
22+, buildGoModule
33+, fetchFromGitHub
44+}:
55+66+buildGoModule rec {
77+ pname = "mox";
88+ version = "0.0.5";
99+1010+ src = fetchFromGitHub {
1111+ owner = "mjl-";
1212+ repo = "mox";
1313+ rev = "v${version}";
1414+ hash = "sha256-f5/K6cPqJJkbdiVCNGOTd9Fjx2/gvSZCxeR6nnEaeJw=";
1515+ };
1616+1717+ # set the version during buildtime
1818+ patches = [ ./version.patch ];
1919+2020+ vendorHash = null;
2121+2222+ ldflags = [
2323+ "-s"
2424+ "-w"
2525+ "-X github.com/mjl-/mox/moxvar.Version=${version}"
2626+ ];
2727+2828+ meta = {
2929+ description = "Modern full-featured open source secure mail server for low-maintenance self-hosted email";
3030+ homepage = "https://github.com/mjl-/mox";
3131+ license = lib.licenses.mit;
3232+ maintainers = with lib.maintainers; [ dit7ya ];
3333+ };
3434+}
+45
pkgs/servers/mail/mox/version.patch
···11+diff --git a/moxvar/version.go b/moxvar/version.go
22+index 8c6bac8..69b5f7c 100644
33+--- a/moxvar/version.go
44++++ b/moxvar/version.go
55+@@ -1,38 +1,5 @@
66+ // Package moxvar provides the version number of a mox build.
77+ package moxvar
88+99+-import (
1010+- "runtime/debug"
1111+-)
1212+-
1313+-// Version is set at runtime based on the Go module used to build.
1414+-var Version = "(devel)"
1515+-
1616+-func init() {
1717+- buildInfo, ok := debug.ReadBuildInfo()
1818+- if !ok {
1919+- return
2020+- }
2121+- Version = buildInfo.Main.Version
2222+- if Version == "(devel)" {
2323+- var vcsRev, vcsMod string
2424+- for _, setting := range buildInfo.Settings {
2525+- if setting.Key == "vcs.revision" {
2626+- vcsRev = setting.Value
2727+- } else if setting.Key == "vcs.modified" {
2828+- vcsMod = setting.Value
2929+- }
3030+- }
3131+- if vcsRev == "" {
3232+- return
3333+- }
3434+- Version = vcsRev
3535+- switch vcsMod {
3636+- case "false":
3737+- case "true":
3838+- Version += "+modifications"
3939+- default:
4040+- Version += "+unknown"
4141+- }
4242+- }
4343+-}
4444++// Version is set via a build flag
4545++var Version string;