Merge pull request #299652 from philiptaron/issue-208242/nixos/lib/systemd

Avoid top-level `with ...;` in `nixos/lib/systemd*`
This commit is contained in:
Florian Klink 2024-04-01 17:19:15 +02:00 committed by GitHub
commit 27968a064c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 261 additions and 114 deletions

View file

@ -1,8 +1,47 @@
{ config, lib, pkgs }:
with lib;
let
inherit (lib)
all
attrByPath
attrNames
concatLists
concatMap
concatMapStrings
concatStrings
concatStringsSep
const
elem
filter
filterAttrs
flip
head
isInt
isList
length
makeBinPath
makeSearchPathOutput
mapAttrs
mapAttrsToList
mkAfter
mkIf
optional
optionalAttrs
optionalString
range
replaceStrings
reverseList
splitString
stringLength
stringToCharacters
tail
toIntBase10
trace
types
;
inherit (lib.strings) toJSON;
cfg = config.systemd;
lndir = "${pkgs.buildPackages.xorg.lndir}/bin/lndir";
systemd = cfg.package;
@ -10,7 +49,7 @@ in rec {
shellEscape = s: (replaceStrings [ "\\" ] [ "\\\\" ] s);
mkPathSafeName = lib.replaceStrings ["@" ":" "\\" "[" "]"] ["-" "-" "-" "" ""];
mkPathSafeName = replaceStrings ["@" ":" "\\" "[" "]"] ["-" "-" "-" "" ""];
# a type for options that take a unit name
unitNameType = types.strMatching "[a-zA-Z0-9@%:_.\\-]+[.](service|socket|device|mount|automount|swap|target|path|timer|scope|slice)";
@ -133,7 +172,7 @@ in rec {
)) attrs;
errors = concatMap (c: c group defs) checks;
in if errors == [] then true
else builtins.trace (concatStringsSep "\n" errors) false;
else trace (concatStringsSep "\n" errors) false;
toOption = x:
if x == true then "true"
@ -220,7 +259,7 @@ in rec {
# upstream unit.
for i in ${toString (mapAttrsToList
(n: v: v.unit)
(lib.filterAttrs (n: v: (attrByPath [ "overrideStrategy" ] "asDropinIfExists" v) == "asDropinIfExists") units))}; do
(filterAttrs (n: v: (attrByPath [ "overrideStrategy" ] "asDropinIfExists" v) == "asDropinIfExists") units))}; do
fn=$(basename $i/*)
if [ -e $out/$fn ]; then
if [ "$(readlink -f $i/$fn)" = /dev/null ]; then
@ -243,7 +282,7 @@ in rec {
# treated as drop-in file.
for i in ${toString (mapAttrsToList
(n: v: v.unit)
(lib.filterAttrs (n: v: v ? overrideStrategy && v.overrideStrategy == "asDropin") units))}; do
(filterAttrs (n: v: v ? overrideStrategy && v.overrideStrategy == "asDropin") units))}; do
fn=$(basename $i/*)
mkdir -p $out/$fn.d
ln -s $i/$fn $out/$fn.d/overrides.conf
@ -384,7 +423,7 @@ in rec {
commonUnitText = def: lines: ''
[Unit]
${attrsToSection def.unitConfig}
'' + lines + lib.optionalString (def.wantedBy != [ ]) ''
'' + lines + optionalString (def.wantedBy != [ ]) ''
[Install]
WantedBy=${concatStringsSep " " def.wantedBy}
@ -406,7 +445,7 @@ in rec {
'' + (let env = cfg.globalEnvironment // def.environment;
in concatMapStrings (n:
let s = optionalString (env.${n} != null)
"Environment=${builtins.toJSON "${n}=${env.${n}}"}\n";
"Environment=${toJSON "${n}=${env.${n}}"}\n";
# systemd max line length is now 1MiB
# https://github.com/systemd/systemd/commit/e6dde451a51dc5aaa7f4d98d39b8fe735f73d2af
in if stringLength s >= 1048576 then throw "The value of the environment variable ${n} in systemd service ${name}.service is too long." else s) (attrNames env))
@ -475,13 +514,13 @@ in rec {
# in that attrset are determined by the supplied format.
definitions = directoryName: format: definitionAttrs:
let
listOfDefinitions = lib.mapAttrsToList
listOfDefinitions = mapAttrsToList
(name: format.generate "${name}.conf")
definitionAttrs;
in
pkgs.runCommand directoryName { } ''
mkdir -p $out
${(lib.concatStringsSep "\n"
${(concatStringsSep "\n"
(map (pkg: "cp ${pkg} $out/${pkg.name}") listOfDefinitions)
)}
'';

View file

@ -1,8 +1,13 @@
{ lib, systemdUtils }:
with lib;
let
inherit (lib)
concatMapStrings
concatStringsSep
flip
optionalString
;
attrsToSection = systemdUtils.lib.attrsToSection;
commonMatchText = def:
optionalString (def.matchConfig != { }) ''

View file

@ -1,47 +1,91 @@
{ lib, systemdUtils, pkgs }:
with systemdUtils.lib;
with systemdUtils.unitOptions;
with lib;
let
inherit (systemdUtils.lib)
automountConfig
makeUnit
mountConfig
stage1ServiceConfig
stage2ServiceConfig
unitConfig
;
inherit (systemdUtils.unitOptions)
concreteUnitOptions
stage1AutomountOptions
stage1CommonUnitOptions
stage1MountOptions
stage1PathOptions
stage1ServiceOptions
stage1SliceOptions
stage1SocketOptions
stage1TimerOptions
stage2AutomountOptions
stage2CommonUnitOptions
stage2MountOptions
stage2PathOptions
stage2ServiceOptions
stage2SliceOptions
stage2SocketOptions
stage2TimerOptions
;
inherit (lib)
mdDoc
mkDefault
mkDerivedConfig
mkEnableOption
mkIf
mkOption
;
inherit (lib.types)
attrsOf
lines
listOf
nullOr
path
submodule
;
in
rec {
units = with types;
attrsOf (submodule ({ name, config, ... }: {
options = concreteUnitOptions;
config = { unit = mkDefault (systemdUtils.lib.makeUnit name config); };
}));
units = attrsOf (submodule ({ name, config, ... }: {
options = concreteUnitOptions;
config = { unit = mkDefault (makeUnit name config); };
}));
services = with types; attrsOf (submodule [ stage2ServiceOptions unitConfig stage2ServiceConfig ]);
initrdServices = with types; attrsOf (submodule [ stage1ServiceOptions unitConfig stage1ServiceConfig ]);
services = attrsOf (submodule [ stage2ServiceOptions unitConfig stage2ServiceConfig ]);
initrdServices = attrsOf (submodule [ stage1ServiceOptions unitConfig stage1ServiceConfig ]);
targets = with types; attrsOf (submodule [ stage2CommonUnitOptions unitConfig ]);
initrdTargets = with types; attrsOf (submodule [ stage1CommonUnitOptions unitConfig ]);
targets = attrsOf (submodule [ stage2CommonUnitOptions unitConfig ]);
initrdTargets = attrsOf (submodule [ stage1CommonUnitOptions unitConfig ]);
sockets = with types; attrsOf (submodule [ stage2SocketOptions unitConfig ]);
initrdSockets = with types; attrsOf (submodule [ stage1SocketOptions unitConfig ]);
sockets = attrsOf (submodule [ stage2SocketOptions unitConfig ]);
initrdSockets = attrsOf (submodule [ stage1SocketOptions unitConfig ]);
timers = with types; attrsOf (submodule [ stage2TimerOptions unitConfig ]);
initrdTimers = with types; attrsOf (submodule [ stage1TimerOptions unitConfig ]);
timers = attrsOf (submodule [ stage2TimerOptions unitConfig ]);
initrdTimers = attrsOf (submodule [ stage1TimerOptions unitConfig ]);
paths = with types; attrsOf (submodule [ stage2PathOptions unitConfig ]);
initrdPaths = with types; attrsOf (submodule [ stage1PathOptions unitConfig ]);
paths = attrsOf (submodule [ stage2PathOptions unitConfig ]);
initrdPaths = attrsOf (submodule [ stage1PathOptions unitConfig ]);
slices = with types; attrsOf (submodule [ stage2SliceOptions unitConfig ]);
initrdSlices = with types; attrsOf (submodule [ stage1SliceOptions unitConfig ]);
slices = attrsOf (submodule [ stage2SliceOptions unitConfig ]);
initrdSlices = attrsOf (submodule [ stage1SliceOptions unitConfig ]);
mounts = with types; listOf (submodule [ stage2MountOptions unitConfig mountConfig ]);
initrdMounts = with types; listOf (submodule [ stage1MountOptions unitConfig mountConfig ]);
mounts = listOf (submodule [ stage2MountOptions unitConfig mountConfig ]);
initrdMounts = listOf (submodule [ stage1MountOptions unitConfig mountConfig ]);
automounts = with types; listOf (submodule [ stage2AutomountOptions unitConfig automountConfig ]);
initrdAutomounts = with types; attrsOf (submodule [ stage1AutomountOptions unitConfig automountConfig ]);
automounts = listOf (submodule [ stage2AutomountOptions unitConfig automountConfig ]);
initrdAutomounts = attrsOf (submodule [ stage1AutomountOptions unitConfig automountConfig ]);
initrdContents = types.attrsOf (types.submodule ({ config, options, name, ... }: {
initrdContents = attrsOf (submodule ({ config, options, name, ... }: {
options = {
enable = mkEnableOption (lib.mdDoc "copying of this file and symlinking it") // { default = true; };
enable = mkEnableOption (mdDoc "copying of this file and symlinking it") // { default = true; };
target = mkOption {
type = types.path;
description = lib.mdDoc ''
type = path;
description = mdDoc ''
Path of the symlink.
'';
default = name;
@ -49,13 +93,13 @@ rec {
text = mkOption {
default = null;
type = types.nullOr types.lines;
description = lib.mdDoc "Text of the file.";
type = nullOr lines;
description = mdDoc "Text of the file.";
};
source = mkOption {
type = types.path;
description = lib.mdDoc "Path of the source file.";
type = path;
description = mdDoc "Path of the source file.";
};
};

View file

@ -1,9 +1,33 @@
{ lib, systemdUtils }:
with systemdUtils.lib;
with lib;
let
inherit (systemdUtils.lib)
assertValueOneOf
automountConfig
checkUnitConfig
makeJobScript
mountConfig
serviceConfig
unitConfig
unitNameType
;
inherit (lib)
any
concatMap
filterOverrides
isList
mdDoc
mergeEqualOption
mkIf
mkMerge
mkOption
mkOptionType
singleton
toList
types
;
checkService = checkUnitConfig "Service" [
(assertValueOneOf "Type" [
"exec" "simple" "forking" "oneshot" "dbus" "notify" "notify-reload" "idle"
@ -31,7 +55,7 @@ in rec {
enable = mkOption {
default = true;
type = types.bool;
description = lib.mdDoc ''
description = mdDoc ''
If set to false, this unit will be a symlink to
/dev/null. This is primarily useful to prevent specific
template instances
@ -45,7 +69,7 @@ in rec {
overrideStrategy = mkOption {
default = "asDropinIfExists";
type = types.enum [ "asDropinIfExists" "asDropin" ];
description = lib.mdDoc ''
description = mdDoc ''
Defines how unit configuration is provided for systemd:
`asDropinIfExists` creates a unit file when no unit file is provided by the package
@ -61,7 +85,7 @@ in rec {
requiredBy = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
Units that require (i.e. depend on and need to go down with) this unit.
As discussed in the `wantedBy` option description this also creates
`.requires` symlinks automatically.
@ -71,7 +95,7 @@ in rec {
upheldBy = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
Keep this unit running as long as the listed units are running. This is a continuously
enforced version of wantedBy.
'';
@ -80,7 +104,7 @@ in rec {
wantedBy = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
Units that want (i.e. depend on) this unit. The default method for
starting a unit by default at boot time is to set this option to
`["multi-user.target"]` for system services. Likewise for user units
@ -98,7 +122,7 @@ in rec {
aliases = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc "Aliases of that unit.";
description = mdDoc "Aliases of that unit.";
};
};
@ -108,12 +132,12 @@ in rec {
text = mkOption {
type = types.nullOr types.str;
default = null;
description = lib.mdDoc "Text of this systemd unit.";
description = mdDoc "Text of this systemd unit.";
};
unit = mkOption {
internal = true;
description = lib.mdDoc "The generated unit.";
description = mdDoc "The generated unit.";
};
};
@ -124,19 +148,19 @@ in rec {
description = mkOption {
default = "";
type = types.singleLineStr;
description = lib.mdDoc "Description of this unit used in systemd messages and progress indicators.";
description = mdDoc "Description of this unit used in systemd messages and progress indicators.";
};
documentation = mkOption {
default = [];
type = types.listOf types.str;
description = lib.mdDoc "A list of URIs referencing documentation for this unit or its configuration.";
description = mdDoc "A list of URIs referencing documentation for this unit or its configuration.";
};
requires = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
Start the specified units when this unit is started, and stop
this unit when the specified units are stopped or fail.
'';
@ -145,7 +169,7 @@ in rec {
wants = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
Start the specified units when this unit is started.
'';
};
@ -153,7 +177,7 @@ in rec {
upholds = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
Keeps the specified running while this unit is running. A continuous version of `wants`.
'';
};
@ -161,7 +185,7 @@ in rec {
after = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
If the specified units are started at the same time as
this unit, delay this unit until they have started.
'';
@ -170,7 +194,7 @@ in rec {
before = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
If the specified units are started at the same time as
this unit, delay them until this unit has started.
'';
@ -179,7 +203,7 @@ in rec {
bindsTo = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
Like requires, but in addition, if the specified units
unexpectedly disappear, this unit will be stopped as well.
'';
@ -188,7 +212,7 @@ in rec {
partOf = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
If the specified units are stopped or restarted, then this
unit is stopped or restarted as well.
'';
@ -197,7 +221,7 @@ in rec {
conflicts = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
If the specified units are started, then this unit is stopped
and vice versa.
'';
@ -206,7 +230,7 @@ in rec {
requisite = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
Similar to requires. However if the units listed are not started,
they will not be started and the transaction will fail.
'';
@ -216,7 +240,7 @@ in rec {
default = {};
example = { RequiresMountsFor = "/data"; };
type = types.attrsOf unitOption;
description = lib.mdDoc ''
description = mdDoc ''
Each attribute in this set specifies an option in the
`[Unit]` section of the unit. See
{manpage}`systemd.unit(5)` for details.
@ -226,7 +250,7 @@ in rec {
onFailure = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
A list of one or more units that are activated when
this unit enters the "failed" state.
'';
@ -235,7 +259,7 @@ in rec {
onSuccess = mkOption {
default = [];
type = types.listOf unitNameType;
description = lib.mdDoc ''
description = mdDoc ''
A list of one or more units that are activated when
this unit enters the "inactive" state.
'';
@ -243,7 +267,7 @@ in rec {
startLimitBurst = mkOption {
type = types.int;
description = lib.mdDoc ''
description = mdDoc ''
Configure unit start rate limiting. Units which are started
more than startLimitBurst times within an interval time
interval are not permitted to start any more.
@ -252,7 +276,7 @@ in rec {
startLimitIntervalSec = mkOption {
type = types.int;
description = lib.mdDoc ''
description = mdDoc ''
Configure unit start rate limiting. Units which are started
more than startLimitBurst times within an interval time
interval are not permitted to start any more.
@ -271,7 +295,7 @@ in rec {
restartTriggers = mkOption {
default = [];
type = types.listOf types.unspecified;
description = lib.mdDoc ''
description = mdDoc ''
An arbitrary list of items such as derivations. If any item
in the list changes between reconfigurations, the service will
be restarted.
@ -281,7 +305,7 @@ in rec {
reloadTriggers = mkOption {
default = [];
type = types.listOf unitOption;
description = lib.mdDoc ''
description = mdDoc ''
An arbitrary list of items such as derivations. If any item
in the list changes between reconfigurations, the service will
be reloaded. If anything but a reload trigger changes in the
@ -299,13 +323,13 @@ in rec {
default = {};
type = with types; attrsOf (nullOr (oneOf [ str path package ]));
example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
description = lib.mdDoc "Environment variables passed to the service's processes.";
description = mdDoc "Environment variables passed to the service's processes.";
};
path = mkOption {
default = [];
type = with types; listOf (oneOf [ package str ]);
description = lib.mdDoc ''
description = mdDoc ''
Packages added to the service's {env}`PATH`
environment variable. Both the {file}`bin`
and {file}`sbin` subdirectories of each
@ -319,7 +343,7 @@ in rec {
{ RestartSec = 5;
};
type = types.addCheck (types.attrsOf unitOption) checkService;
description = lib.mdDoc ''
description = mdDoc ''
Each attribute in this set specifies an option in the
`[Service]` section of the unit. See
{manpage}`systemd.service(5)` for details.
@ -329,14 +353,14 @@ in rec {
script = mkOption {
type = types.lines;
default = "";
description = lib.mdDoc "Shell commands executed as the service's main process.";
description = mdDoc "Shell commands executed as the service's main process.";
};
scriptArgs = mkOption {
type = types.str;
default = "";
example = "%i";
description = lib.mdDoc ''
description = mdDoc ''
Arguments passed to the main process script.
Can contain specifiers (`%` placeholders expanded by systemd, see {manpage}`systemd.unit(5)`).
'';
@ -345,7 +369,7 @@ in rec {
preStart = mkOption {
type = types.lines;
default = "";
description = lib.mdDoc ''
description = mdDoc ''
Shell commands executed before the service's main process
is started.
'';
@ -354,7 +378,7 @@ in rec {
postStart = mkOption {
type = types.lines;
default = "";
description = lib.mdDoc ''
description = mdDoc ''
Shell commands executed after the service's main process
is started.
'';
@ -363,7 +387,7 @@ in rec {
reload = mkOption {
type = types.lines;
default = "";
description = lib.mdDoc ''
description = mdDoc ''
Shell commands executed when the service's main process
is reloaded.
'';
@ -372,7 +396,7 @@ in rec {
preStop = mkOption {
type = types.lines;
default = "";
description = lib.mdDoc ''
description = mdDoc ''
Shell commands executed to stop the service.
'';
};
@ -380,7 +404,7 @@ in rec {
postStop = mkOption {
type = types.lines;
default = "";
description = lib.mdDoc ''
description = mdDoc ''
Shell commands executed after the service's main process
has exited.
'';
@ -389,7 +413,7 @@ in rec {
jobScripts = mkOption {
type = with types; coercedTo path singleton (listOf path);
internal = true;
description = lib.mdDoc "A list of all job script derivations of this unit.";
description = mdDoc "A list of all job script derivations of this unit.";
default = [];
};
@ -434,7 +458,7 @@ in rec {
restartIfChanged = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
description = mdDoc ''
Whether the service should be restarted during a NixOS
configuration switch if its definition has changed.
'';
@ -443,7 +467,7 @@ in rec {
reloadIfChanged = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
description = mdDoc ''
Whether the service should be reloaded during a NixOS
configuration switch if its definition has changed. If
enabled, the value of {option}`restartIfChanged` is
@ -459,7 +483,7 @@ in rec {
stopIfChanged = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
description = mdDoc ''
If set, a changed unit is restarted by calling
{command}`systemctl stop` in the old configuration,
then {command}`systemctl start` in the new one.
@ -475,7 +499,7 @@ in rec {
type = with types; either str (listOf str);
default = [];
example = "Sun 14:00:00";
description = lib.mdDoc ''
description = mdDoc ''
Automatically start this unit at the given date/time, which
must be in the format described in
{manpage}`systemd.time(7)`. This is equivalent
@ -502,7 +526,7 @@ in rec {
default = [];
type = types.listOf types.str;
example = [ "0.0.0.0:993" "/run/my-socket" ];
description = lib.mdDoc ''
description = mdDoc ''
For each item in this list, a `ListenStream`
option in the `[Socket]` section will be created.
'';
@ -512,7 +536,7 @@ in rec {
default = [];
type = types.listOf types.str;
example = [ "0.0.0.0:993" "/run/my-socket" ];
description = lib.mdDoc ''
description = mdDoc ''
For each item in this list, a `ListenDatagram`
option in the `[Socket]` section will be created.
'';
@ -522,7 +546,7 @@ in rec {
default = {};
example = { ListenStream = "/run/my-socket"; };
type = types.attrsOf unitOption;
description = lib.mdDoc ''
description = mdDoc ''
Each attribute in this set specifies an option in the
`[Socket]` section of the unit. See
{manpage}`systemd.socket(5)` for details.
@ -554,7 +578,7 @@ in rec {
default = {};
example = { OnCalendar = "Sun 14:00:00"; Unit = "foo.service"; };
type = types.attrsOf unitOption;
description = lib.mdDoc ''
description = mdDoc ''
Each attribute in this set specifies an option in the
`[Timer]` section of the unit. See
{manpage}`systemd.timer(5)` and
@ -587,7 +611,7 @@ in rec {
default = {};
example = { PathChanged = "/some/path"; Unit = "changedpath.service"; };
type = types.attrsOf unitOption;
description = lib.mdDoc ''
description = mdDoc ''
Each attribute in this set specifies an option in the
`[Path]` section of the unit. See
{manpage}`systemd.path(5)` for details.
@ -618,13 +642,13 @@ in rec {
what = mkOption {
example = "/dev/sda1";
type = types.str;
description = lib.mdDoc "Absolute path of device node, file or other resource. (Mandatory)";
description = mdDoc "Absolute path of device node, file or other resource. (Mandatory)";
};
where = mkOption {
example = "/mnt";
type = types.str;
description = lib.mdDoc ''
description = mdDoc ''
Absolute path of a directory of the mount point.
Will be created if it doesn't exist. (Mandatory)
'';
@ -634,21 +658,21 @@ in rec {
default = "";
example = "ext4";
type = types.str;
description = lib.mdDoc "File system type.";
description = mdDoc "File system type.";
};
options = mkOption {
default = "";
example = "noatime";
type = types.commas;
description = lib.mdDoc "Options used to mount the file system.";
description = mdDoc "Options used to mount the file system.";
};
mountConfig = mkOption {
default = {};
example = { DirectoryMode = "0775"; };
type = types.attrsOf unitOption;
description = lib.mdDoc ''
description = mdDoc ''
Each attribute in this set specifies an option in the
`[Mount]` section of the unit. See
{manpage}`systemd.mount(5)` for details.
@ -678,7 +702,7 @@ in rec {
where = mkOption {
example = "/mnt";
type = types.str;
description = lib.mdDoc ''
description = mdDoc ''
Absolute path of a directory of the mount point.
Will be created if it doesn't exist. (Mandatory)
'';
@ -688,7 +712,7 @@ in rec {
default = {};
example = { DirectoryMode = "0775"; };
type = types.attrsOf unitOption;
description = lib.mdDoc ''
description = mdDoc ''
Each attribute in this set specifies an option in the
`[Automount]` section of the unit. See
{manpage}`systemd.automount(5)` for details.
@ -719,7 +743,7 @@ in rec {
default = {};
example = { MemoryMax = "2G"; };
type = types.attrsOf unitOption;
description = lib.mdDoc ''
description = mdDoc ''
Each attribute in this set specifies an option in the
`[Slice]` section of the unit. See
{manpage}`systemd.slice(5)` for details.

View file

@ -1,9 +1,44 @@
{ lib, config, pkgs }: with lib;
{ lib, config, pkgs }:
let
inherit (lib)
any
attrNames
concatMapStringsSep
concatStringsSep
elem
escapeShellArg
filter
flatten
getName
hasPrefix
hasSuffix
imap0
imap1
isAttrs
isDerivation
isFloat
isInt
isList
isPath
isString
listToAttrs
nameValuePair
optionalString
removePrefix
removeSuffix
replaceStrings
stringToCharacters
types
;
inherit (lib.strings) toJSON normalizePath escapeC;
in
rec {
# Copy configuration files to avoid having the entire sources in the system closure
copyFile = filePath: pkgs.runCommand (builtins.unsafeDiscardStringContext (builtins.baseNameOf filePath)) {} ''
copyFile = filePath: pkgs.runCommand (builtins.unsafeDiscardStringContext (baseNameOf filePath)) {} ''
cp ${filePath} $out
'';
@ -46,11 +81,11 @@ rec {
escapeSystemdPath = s: let
replacePrefix = p: r: s: (if (hasPrefix p s) then r + (removePrefix p s) else s);
trim = s: removeSuffix "/" (removePrefix "/" s);
normalizedPath = strings.normalizePath s;
normalizedPath = normalizePath s;
in
replaceStrings ["/"] ["-"]
(replacePrefix "." (strings.escapeC ["."] ".")
(strings.escapeC (stringToCharacters " !\"#$%&'()*+,;<=>=@[\\]^`{|}~-")
(replacePrefix "." (escapeC ["."] ".")
(escapeC (stringToCharacters " !\"#$%&'()*+,;<=>=@[\\]^`{|}~-")
(if normalizedPath == "/" then normalizedPath else trim normalizedPath)));
# Quotes an argument for use in Exec* service lines.
@ -62,12 +97,12 @@ rec {
# substitution for the directive.
escapeSystemdExecArg = arg:
let
s = if builtins.isPath arg then "${arg}"
else if builtins.isString arg then arg
else if builtins.isInt arg || builtins.isFloat arg || lib.isDerivation arg then toString arg
s = if isPath arg then "${arg}"
else if isString arg then arg
else if isInt arg || isFloat arg || isDerivation arg then toString arg
else throw "escapeSystemdExecArg only allows strings, paths, numbers and derivations";
in
replaceStrings [ "%" "$" ] [ "%%" "$$" ] (builtins.toJSON s);
replaceStrings [ "%" "$" ] [ "%%" "$$" ] (toJSON s);
# Quotes a list of arguments into a single string for use in a Exec*
# line.
@ -197,7 +232,7 @@ rec {
(attrNames secrets))
+ "\n"
+ "${pkgs.jq}/bin/jq >'${output}' "
+ lib.escapeShellArg (stringOrDefault
+ escapeShellArg (stringOrDefault
(concatStringsSep
" | "
(imap1 (index: name: ''${name} = $ENV.secret${toString index}'')
@ -205,7 +240,7 @@ rec {
".")
+ ''
<<'EOF'
${builtins.toJSON set}
${toJSON set}
EOF
(( ! $inherit_errexit_enabled )) && shopt -u inherit_errexit
'';
@ -222,9 +257,9 @@ rec {
*/
removePackagesByName = packages: packagesToRemove:
let
namesToRemove = map lib.getName packagesToRemove;
namesToRemove = map getName packagesToRemove;
in
lib.filter (x: !(builtins.elem (lib.getName x) namesToRemove)) packages;
filter (x: !(elem (getName x) namesToRemove)) packages;
systemdUtils = {
lib = import ./systemd-lib.nix { inherit lib config pkgs; };