treewide: reformat nixfmt-rfc-style
Reformat repository using new nixfmt-rfc-style.
This commit is contained in:
parent
5df48c4255
commit
cba2f9ce95
1051 changed files with 37028 additions and 26594 deletions
|
|
@ -1,4 +1,9 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (pkgs.stdenv.hostPlatform) isDarwin;
|
||||
|
|
@ -8,45 +13,48 @@ let
|
|||
labelPrefix = "org.nix-community.home.";
|
||||
dstDir = "${config.home.homeDirectory}/Library/LaunchAgents";
|
||||
|
||||
launchdConfig = { config, name, ... }: {
|
||||
options = {
|
||||
enable = lib.mkEnableOption name;
|
||||
config = lib.mkOption {
|
||||
type = lib.types.submodule (import ./launchd.nix);
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
ProgramArguments = [ "/usr/bin/say" "Good afternoon" ];
|
||||
StartCalendarInterval = [
|
||||
{
|
||||
Hour = 12;
|
||||
Minute = 0;
|
||||
}
|
||||
];
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Define a launchd job. See {manpage}`launchd.plist(5)` for details.
|
||||
'';
|
||||
launchdConfig =
|
||||
{ config, name, ... }:
|
||||
{
|
||||
options = {
|
||||
enable = lib.mkEnableOption name;
|
||||
config = lib.mkOption {
|
||||
type = lib.types.submodule (import ./launchd.nix);
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
ProgramArguments = [ "/usr/bin/say" "Good afternoon" ];
|
||||
StartCalendarInterval = [
|
||||
{
|
||||
Hour = 12;
|
||||
Minute = 0;
|
||||
}
|
||||
];
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Define a launchd job. See {manpage}`launchd.plist(5)` for details.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
config.Label = lib.mkDefault "${labelPrefix}${name}";
|
||||
};
|
||||
};
|
||||
|
||||
config = { config.Label = lib.mkDefault "${labelPrefix}${name}"; };
|
||||
};
|
||||
|
||||
toAgent = config: pkgs.writeText "${config.Label}.plist" (toPlist { } config);
|
||||
|
||||
agentPlists = lib.mapAttrs'
|
||||
(n: v: lib.nameValuePair "${v.config.Label}.plist" (toAgent v.config))
|
||||
(lib.filterAttrs (n: v: v.enable) cfg.agents);
|
||||
agentPlists = lib.mapAttrs' (n: v: lib.nameValuePair "${v.config.Label}.plist" (toAgent v.config)) (
|
||||
lib.filterAttrs (n: v: v.enable) cfg.agents
|
||||
);
|
||||
|
||||
agentsDrv = pkgs.runCommand "home-manager-agents" { } ''
|
||||
mkdir -p "$out"
|
||||
|
||||
declare -A plists
|
||||
plists=(${
|
||||
lib.concatStringsSep " "
|
||||
(lib.mapAttrsToList (name: value: "['${name}']='${value}'") agentPlists)
|
||||
lib.concatStringsSep " " (lib.mapAttrsToList (name: value: "['${name}']='${value}'") agentPlists)
|
||||
})
|
||||
|
||||
for dest in "''${!plists[@]}"; do
|
||||
|
|
@ -54,8 +62,12 @@ let
|
|||
ln -s "$src" "$out/$dest"
|
||||
done
|
||||
'';
|
||||
in {
|
||||
meta.maintainers = with lib.maintainers; [ khaneliman midchildan ];
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
khaneliman
|
||||
midchildan
|
||||
];
|
||||
|
||||
options.launchd = {
|
||||
enable = lib.mkOption {
|
||||
|
|
@ -77,12 +89,16 @@ in {
|
|||
|
||||
config = lib.mkMerge [
|
||||
{
|
||||
assertions = [{
|
||||
assertion = (cfg.enable && agentPlists != { }) -> isDarwin;
|
||||
message =
|
||||
let names = lib.concatStringsSep ", " (lib.attrNames agentPlists);
|
||||
in "Must use Darwin for modules that require Launchd: " + names;
|
||||
}];
|
||||
assertions = [
|
||||
{
|
||||
assertion = (cfg.enable && agentPlists != { }) -> isDarwin;
|
||||
message =
|
||||
let
|
||||
names = lib.concatStringsSep ", " (lib.attrNames agentPlists);
|
||||
in
|
||||
"Must use Darwin for modules that require Launchd: " + names;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
(lib.mkIf isDarwin {
|
||||
|
|
@ -94,170 +110,170 @@ in {
|
|||
# because it needs to be owned by the user running it.
|
||||
home.activation.setupLaunchAgents =
|
||||
lib.hm.dag.entryAfter [ "writeBoundary" ] # Bash
|
||||
''
|
||||
# Disable errexit to ensure we process all agents even if some fail
|
||||
set +e
|
||||
''
|
||||
# Disable errexit to ensure we process all agents even if some fail
|
||||
set +e
|
||||
|
||||
# Stop an agent if it's running
|
||||
bootoutAgent() {
|
||||
local domain="$1"
|
||||
local agentName="$2"
|
||||
# Stop an agent if it's running
|
||||
bootoutAgent() {
|
||||
local domain="$1"
|
||||
local agentName="$2"
|
||||
|
||||
verboseEcho "Stopping agent '$domain/$agentName'..."
|
||||
local bootout_output
|
||||
bootout_output=$(run /bin/launchctl bootout "$domain/$agentName" 2>&1) || {
|
||||
# Only show warning if it's not the common "No such process" error
|
||||
if [[ "$bootout_output" != *"No such process"* ]]; then
|
||||
warnEcho "Failed to stop agent '$domain/$agentName': $bootout_output"
|
||||
else
|
||||
verboseEcho "Agent '$domain/$agentName' was not running"
|
||||
fi
|
||||
verboseEcho "Stopping agent '$domain/$agentName'..."
|
||||
local bootout_output
|
||||
bootout_output=$(run /bin/launchctl bootout "$domain/$agentName" 2>&1) || {
|
||||
# Only show warning if it's not the common "No such process" error
|
||||
if [[ "$bootout_output" != *"No such process"* ]]; then
|
||||
warnEcho "Failed to stop agent '$domain/$agentName': $bootout_output"
|
||||
else
|
||||
verboseEcho "Agent '$domain/$agentName' was not running"
|
||||
fi
|
||||
}
|
||||
|
||||
# Give the system a moment to fully unload the agent
|
||||
sleep 1
|
||||
}
|
||||
|
||||
# Give the system a moment to fully unload the agent
|
||||
sleep 1
|
||||
}
|
||||
installAndBootstrapAgent() {
|
||||
local srcPath="$1"
|
||||
local dstPath="$2"
|
||||
local domain="$3"
|
||||
local agentName="$4"
|
||||
|
||||
installAndBootstrapAgent() {
|
||||
local srcPath="$1"
|
||||
local dstPath="$2"
|
||||
local domain="$3"
|
||||
local agentName="$4"
|
||||
|
||||
verboseEcho "Installing agent file to $dstPath"
|
||||
if ! run install -Dm444 -T "$srcPath" "$dstPath"; then
|
||||
errorEcho "Failed to install agent file for '$agentName'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
verboseEcho "Starting agent '$domain/$agentName'"
|
||||
local bootstrap_output
|
||||
bootstrap_output=$(run /bin/launchctl bootstrap "$domain" "$dstPath" 2>&1) || {
|
||||
local error_code=$?
|
||||
|
||||
if [[ "$bootstrap_output" == *"Bootstrap failed: 5: Input/output error"* ]]; then
|
||||
errorEcho "Failed to start agent '$domain/$agentName' with I/O error (code 5)"
|
||||
errorEcho "This typically happens when the agent wasn't unloaded before attempting to bootstrap the new agent."
|
||||
else
|
||||
errorEcho "Failed to start agent '$domain/$agentName' with error: $bootstrap_output"
|
||||
verboseEcho "Installing agent file to $dstPath"
|
||||
if ! run install -Dm444 -T "$srcPath" "$dstPath"; then
|
||||
errorEcho "Failed to install agent file for '$agentName'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
verboseEcho "Starting agent '$domain/$agentName'"
|
||||
local bootstrap_output
|
||||
bootstrap_output=$(run /bin/launchctl bootstrap "$domain" "$dstPath" 2>&1) || {
|
||||
local error_code=$?
|
||||
|
||||
verboseEcho "Successfully started agent '$domain/$agentName'"
|
||||
return 0
|
||||
}
|
||||
if [[ "$bootstrap_output" == *"Bootstrap failed: 5: Input/output error"* ]]; then
|
||||
errorEcho "Failed to start agent '$domain/$agentName' with I/O error (code 5)"
|
||||
errorEcho "This typically happens when the agent wasn't unloaded before attempting to bootstrap the new agent."
|
||||
else
|
||||
errorEcho "Failed to start agent '$domain/$agentName' with error: $bootstrap_output"
|
||||
fi
|
||||
|
||||
processAgent() {
|
||||
local srcPath="$1"
|
||||
local dstDir="$2"
|
||||
local domain="$3"
|
||||
return 1
|
||||
}
|
||||
|
||||
local agentFile="''${srcPath##*/}"
|
||||
local agentName="''${agentFile%.plist}"
|
||||
local dstPath="$dstDir/$agentFile"
|
||||
|
||||
# Skip if unchanged
|
||||
if cmp -s "$srcPath" "$dstPath"; then
|
||||
verboseEcho "Agent '$agentName' is already up-to-date"
|
||||
verboseEcho "Successfully started agent '$domain/$agentName'"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
verboseEcho "Processing agent '$agentName'"
|
||||
processAgent() {
|
||||
local srcPath="$1"
|
||||
local dstDir="$2"
|
||||
local domain="$3"
|
||||
|
||||
# Stop/Unload agent if it's already running
|
||||
if [[ -f "$dstPath" ]]; then
|
||||
local agentFile="''${srcPath##*/}"
|
||||
local agentName="''${agentFile%.plist}"
|
||||
local dstPath="$dstDir/$agentFile"
|
||||
|
||||
# Skip if unchanged
|
||||
if cmp -s "$srcPath" "$dstPath"; then
|
||||
verboseEcho "Agent '$agentName' is already up-to-date"
|
||||
return 0
|
||||
fi
|
||||
|
||||
verboseEcho "Processing agent '$agentName'"
|
||||
|
||||
# Stop/Unload agent if it's already running
|
||||
if [[ -f "$dstPath" ]]; then
|
||||
bootoutAgent "$domain" "$agentName"
|
||||
fi
|
||||
|
||||
installAndBootstrapAgent "$srcPath" "$dstPath" "$domain" "$agentName"
|
||||
# Note: We continue processing even if this agent fails
|
||||
return 0
|
||||
}
|
||||
|
||||
removeAgent() {
|
||||
local srcPath="$1"
|
||||
local dstDir="$2"
|
||||
local newDir="$3"
|
||||
local domain="$4"
|
||||
|
||||
local agentFile="''${srcPath##*/}"
|
||||
local agentName="''${agentFile%.plist}"
|
||||
local dstPath="$dstDir/$agentFile"
|
||||
|
||||
if [[ -e "$newDir/$agentFile" ]]; then
|
||||
verboseEcho "Agent '$agentName' still exists in new generation, skipping cleanup"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ ! -e "$dstPath" ]]; then
|
||||
verboseEcho "Agent file '$dstPath' already removed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! cmp -s "$srcPath" "$dstPath"; then
|
||||
warnEcho "Skipping deletion of '$dstPath', since its contents have diverged"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Stop and remove the agent
|
||||
bootoutAgent "$domain" "$agentName"
|
||||
fi
|
||||
|
||||
installAndBootstrapAgent "$srcPath" "$dstPath" "$domain" "$agentName"
|
||||
# Note: We continue processing even if this agent fails
|
||||
return 0
|
||||
}
|
||||
verboseEcho "Removing agent file '$dstPath'"
|
||||
if run rm -f $VERBOSE_ARG "$dstPath"; then
|
||||
verboseEcho "Successfully removed agent file for '$agentName'"
|
||||
else
|
||||
warnEcho "Failed to remove agent file '$dstPath'"
|
||||
fi
|
||||
|
||||
removeAgent() {
|
||||
local srcPath="$1"
|
||||
local dstDir="$2"
|
||||
local newDir="$3"
|
||||
local domain="$4"
|
||||
|
||||
local agentFile="''${srcPath##*/}"
|
||||
local agentName="''${agentFile%.plist}"
|
||||
local dstPath="$dstDir/$agentFile"
|
||||
|
||||
if [[ -e "$newDir/$agentFile" ]]; then
|
||||
verboseEcho "Agent '$agentName' still exists in new generation, skipping cleanup"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ ! -e "$dstPath" ]]; then
|
||||
verboseEcho "Agent file '$dstPath' already removed"
|
||||
return 0
|
||||
fi
|
||||
setupLaunchAgents() {
|
||||
local oldDir newDir dstDir domain
|
||||
|
||||
if ! cmp -s "$srcPath" "$dstPath"; then
|
||||
warnEcho "Skipping deletion of '$dstPath', since its contents have diverged"
|
||||
return 0
|
||||
fi
|
||||
newDir="$(readlink -m "$newGenPath/LaunchAgents")"
|
||||
dstDir=${lib.escapeShellArg dstDir}
|
||||
domain="gui/$UID"
|
||||
|
||||
# Stop and remove the agent
|
||||
bootoutAgent "$domain" "$agentName"
|
||||
|
||||
verboseEcho "Removing agent file '$dstPath'"
|
||||
if run rm -f $VERBOSE_ARG "$dstPath"; then
|
||||
verboseEcho "Successfully removed agent file for '$agentName'"
|
||||
else
|
||||
warnEcho "Failed to remove agent file '$dstPath'"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
setupLaunchAgents() {
|
||||
local oldDir newDir dstDir domain
|
||||
|
||||
newDir="$(readlink -m "$newGenPath/LaunchAgents")"
|
||||
dstDir=${lib.escapeShellArg dstDir}
|
||||
domain="gui/$UID"
|
||||
|
||||
if [[ -n "''${oldGenPath:-}" ]]; then
|
||||
oldDir="$(readlink -m "$oldGenPath/LaunchAgents")"
|
||||
if [[ ! -d "$oldDir" ]]; then
|
||||
verboseEcho "No previous LaunchAgents directory found"
|
||||
if [[ -n "''${oldGenPath:-}" ]]; then
|
||||
oldDir="$(readlink -m "$oldGenPath/LaunchAgents")"
|
||||
if [[ ! -d "$oldDir" ]]; then
|
||||
verboseEcho "No previous LaunchAgents directory found"
|
||||
oldDir=""
|
||||
fi
|
||||
else
|
||||
oldDir=""
|
||||
fi
|
||||
else
|
||||
oldDir=""
|
||||
|
||||
verboseEcho "Setting up LaunchAgents in $dstDir"
|
||||
[[ -d "$dstDir" ]] || run mkdir -p "$dstDir"
|
||||
|
||||
verboseEcho "Processing new/updated LaunchAgents..."
|
||||
find -L "$newDir" -maxdepth 1 -name '*.plist' -type f | while read -r srcPath; do
|
||||
processAgent "$srcPath" "$dstDir" "$domain"
|
||||
done
|
||||
|
||||
# Skip cleanup if there's no previous generation
|
||||
if [[ -z "$oldDir" || ! -d "$oldDir" ]]; then
|
||||
verboseEcho "LaunchAgents setup complete"
|
||||
return
|
||||
fi
|
||||
|
||||
verboseEcho "Cleaning up removed LaunchAgents..."
|
||||
find -L "$oldDir" -maxdepth 1 -name '*.plist' -type f | while read -r srcPath; do
|
||||
removeAgent "$srcPath" "$dstDir" "$newDir" "$domain"
|
||||
done
|
||||
}
|
||||
|
||||
setupLaunchAgents
|
||||
|
||||
# Restore errexit
|
||||
if [[ -o errexit ]]; then
|
||||
set -e
|
||||
fi
|
||||
|
||||
verboseEcho "Setting up LaunchAgents in $dstDir"
|
||||
[[ -d "$dstDir" ]] || run mkdir -p "$dstDir"
|
||||
|
||||
verboseEcho "Processing new/updated LaunchAgents..."
|
||||
find -L "$newDir" -maxdepth 1 -name '*.plist' -type f | while read -r srcPath; do
|
||||
processAgent "$srcPath" "$dstDir" "$domain"
|
||||
done
|
||||
|
||||
# Skip cleanup if there's no previous generation
|
||||
if [[ -z "$oldDir" || ! -d "$oldDir" ]]; then
|
||||
verboseEcho "LaunchAgents setup complete"
|
||||
return
|
||||
fi
|
||||
|
||||
verboseEcho "Cleaning up removed LaunchAgents..."
|
||||
find -L "$oldDir" -maxdepth 1 -name '*.plist' -type f | while read -r srcPath; do
|
||||
removeAgent "$srcPath" "$dstDir" "$newDir" "$domain"
|
||||
done
|
||||
}
|
||||
|
||||
setupLaunchAgents
|
||||
|
||||
# Restore errexit
|
||||
if [[ -o errexit ]]; then
|
||||
set -e
|
||||
fi
|
||||
'';
|
||||
'';
|
||||
})
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ let
|
|||
inherit (lib) types mkOption; # added by Home Manager
|
||||
|
||||
launchdTypes = import ./types.nix { inherit config lib; };
|
||||
in {
|
||||
in
|
||||
{
|
||||
freeformType = with types; attrsOf anything; # added by Home Manager
|
||||
|
||||
options = {
|
||||
|
|
@ -82,23 +83,27 @@ in {
|
|||
|
||||
inetdCompatibility = mkOption {
|
||||
default = null;
|
||||
example = { Wait = true; };
|
||||
example = {
|
||||
Wait = true;
|
||||
};
|
||||
description = ''
|
||||
The presence of this key specifies that the daemon expects to be run as if it were launched from inetd.
|
||||
'';
|
||||
type = types.nullOr (types.submodule {
|
||||
options = {
|
||||
Wait = mkOption {
|
||||
type = types.nullOr (types.either types.bool types.str);
|
||||
default = null;
|
||||
description = ''
|
||||
This flag corresponds to the "wait" or "nowait" option of inetd. If true, then the listening
|
||||
socket is passed via the standard in/out/error file descriptors. If false, then `accept(2)` is
|
||||
called on behalf of the job, and the result is passed via the standard in/out/error descriptors.
|
||||
'';
|
||||
type = types.nullOr (
|
||||
types.submodule {
|
||||
options = {
|
||||
Wait = mkOption {
|
||||
type = types.nullOr (types.either types.bool types.str);
|
||||
default = null;
|
||||
description = ''
|
||||
This flag corresponds to the "wait" or "nowait" option of inetd. If true, then the listening
|
||||
socket is passed via the standard in/out/error file descriptors. If false, then `accept(2)` is
|
||||
called on behalf of the job, and the result is passed via the standard in/out/error descriptors.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
LimitLoadToHosts = mkOption {
|
||||
|
|
@ -120,7 +125,12 @@ in {
|
|||
};
|
||||
|
||||
LimitLoadToSessionType = mkOption {
|
||||
type = types.nullOr (types.oneOf [ types.str (types.listOf types.str) ]);
|
||||
type = types.nullOr (
|
||||
types.oneOf [
|
||||
types.str
|
||||
(types.listOf types.str)
|
||||
]
|
||||
);
|
||||
default = null;
|
||||
description = ''
|
||||
This configuration file only applies to sessions of the type specified. This key is used in concert
|
||||
|
|
@ -177,68 +187,72 @@ in {
|
|||
};
|
||||
|
||||
KeepAlive = mkOption {
|
||||
type = types.nullOr (types.either types.bool (types.submodule {
|
||||
options = {
|
||||
type = types.nullOr (
|
||||
types.either types.bool (
|
||||
types.submodule {
|
||||
options = {
|
||||
|
||||
SuccessfulExit = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
If true, the job will be restarted as long as the program exits and with an exit status of zero.
|
||||
If false, the job will be restarted in the inverse condition. This key implies that "RunAtLoad"
|
||||
is set to true, since the job needs to run at least once before we can get an exit status.
|
||||
'';
|
||||
};
|
||||
SuccessfulExit = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
If true, the job will be restarted as long as the program exits and with an exit status of zero.
|
||||
If false, the job will be restarted in the inverse condition. This key implies that "RunAtLoad"
|
||||
is set to true, since the job needs to run at least once before we can get an exit status.
|
||||
'';
|
||||
};
|
||||
|
||||
NetworkState = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
If true, the job will be kept alive as long as the network is up, where up is defined as at least
|
||||
one non-loopback interface being up and having IPv4 or IPv6 addresses assigned to them. If
|
||||
false, the job will be kept alive in the inverse condition.
|
||||
'';
|
||||
};
|
||||
NetworkState = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
If true, the job will be kept alive as long as the network is up, where up is defined as at least
|
||||
one non-loopback interface being up and having IPv4 or IPv6 addresses assigned to them. If
|
||||
false, the job will be kept alive in the inverse condition.
|
||||
'';
|
||||
};
|
||||
|
||||
PathState = mkOption {
|
||||
type = types.nullOr (types.attrsOf types.bool);
|
||||
default = null;
|
||||
description = ''
|
||||
Each key in this dictionary is a file-system path. If the value of the key is true, then the job
|
||||
will be kept alive as long as the path exists. If false, the job will be kept alive in the
|
||||
inverse condition. The intent of this feature is that two or more jobs may create semaphores in
|
||||
the file-system namespace.
|
||||
'';
|
||||
};
|
||||
PathState = mkOption {
|
||||
type = types.nullOr (types.attrsOf types.bool);
|
||||
default = null;
|
||||
description = ''
|
||||
Each key in this dictionary is a file-system path. If the value of the key is true, then the job
|
||||
will be kept alive as long as the path exists. If false, the job will be kept alive in the
|
||||
inverse condition. The intent of this feature is that two or more jobs may create semaphores in
|
||||
the file-system namespace.
|
||||
'';
|
||||
};
|
||||
|
||||
OtherJobEnabled = mkOption {
|
||||
type = types.nullOr (types.attrsOf types.bool);
|
||||
default = null;
|
||||
description = ''
|
||||
Each key in this dictionary is the label of another job. If the value of the key is true, then
|
||||
this job is kept alive as long as that other job is enabled. Otherwise, if the value is false,
|
||||
then this job is kept alive as long as the other job is disabled. This feature should not be
|
||||
considered a substitute for the use of IPC.
|
||||
'';
|
||||
};
|
||||
OtherJobEnabled = mkOption {
|
||||
type = types.nullOr (types.attrsOf types.bool);
|
||||
default = null;
|
||||
description = ''
|
||||
Each key in this dictionary is the label of another job. If the value of the key is true, then
|
||||
this job is kept alive as long as that other job is enabled. Otherwise, if the value is false,
|
||||
then this job is kept alive as long as the other job is disabled. This feature should not be
|
||||
considered a substitute for the use of IPC.
|
||||
'';
|
||||
};
|
||||
|
||||
Crashed = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
If true, the the job will be restarted as long as it exited due to a signal which is typically
|
||||
associated with a crash (SIGILL, SIGSEGV, etc.). If false, the job will be restarted in the
|
||||
inverse condition.
|
||||
'';
|
||||
};
|
||||
Crashed = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
If true, the the job will be restarted as long as it exited due to a signal which is typically
|
||||
associated with a crash (SIGILL, SIGSEGV, etc.). If false, the job will be restarted in the
|
||||
inverse condition.
|
||||
'';
|
||||
};
|
||||
|
||||
AfterInitialDemand = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
};
|
||||
AfterInitialDemand = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
};
|
||||
|
||||
};
|
||||
}));
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key is used to control whether your job is to be kept continuously running or to let
|
||||
|
|
@ -371,10 +385,12 @@ in {
|
|||
|
||||
StartCalendarInterval = mkOption {
|
||||
default = null;
|
||||
example = [{
|
||||
Hour = 2;
|
||||
Minute = 30;
|
||||
}];
|
||||
example = [
|
||||
{
|
||||
Hour = 2;
|
||||
Minute = 30;
|
||||
}
|
||||
];
|
||||
description = ''
|
||||
This optional key causes the job to be started every calendar interval as specified. The semantics are
|
||||
much like {manpage}`crontab(5)`: Missing attributes are considered to be wildcard. Unlike cron which skips
|
||||
|
|
@ -442,181 +458,187 @@ in {
|
|||
Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`. The following
|
||||
keys apply:
|
||||
'';
|
||||
type = types.nullOr (types.submodule {
|
||||
options = {
|
||||
Core = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The largest size (in bytes) core file that may be created.
|
||||
'';
|
||||
};
|
||||
type = types.nullOr (
|
||||
types.submodule {
|
||||
options = {
|
||||
Core = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The largest size (in bytes) core file that may be created.
|
||||
'';
|
||||
};
|
||||
|
||||
CPU = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum amount of cpu time (in seconds) to be used by each process.
|
||||
'';
|
||||
};
|
||||
CPU = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum amount of cpu time (in seconds) to be used by each process.
|
||||
'';
|
||||
};
|
||||
|
||||
Data = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) of the data segment for a process; this defines how far a program may
|
||||
extend its break with the `sbrk(2)` system call.
|
||||
'';
|
||||
};
|
||||
Data = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) of the data segment for a process; this defines how far a program may
|
||||
extend its break with the `sbrk(2)` system call.
|
||||
'';
|
||||
};
|
||||
|
||||
FileSize = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The largest size (in bytes) file that may be created.
|
||||
'';
|
||||
};
|
||||
FileSize = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The largest size (in bytes) file that may be created.
|
||||
'';
|
||||
};
|
||||
|
||||
MemoryLock = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) which a process may lock into memory using the mlock(2) function.
|
||||
'';
|
||||
};
|
||||
MemoryLock = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) which a process may lock into memory using the mlock(2) function.
|
||||
'';
|
||||
};
|
||||
|
||||
NumberOfFiles = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum number of open files for this process. Setting this value in a system wide daemon
|
||||
will set the `sysctl(3)` kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits)
|
||||
value in addition to the `setrlimit(2)` values.
|
||||
'';
|
||||
};
|
||||
NumberOfFiles = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum number of open files for this process. Setting this value in a system wide daemon
|
||||
will set the `sysctl(3)` kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits)
|
||||
value in addition to the `setrlimit(2)` values.
|
||||
'';
|
||||
};
|
||||
|
||||
NumberOfProcesses = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum number of simultaneous processes for this user id. Setting this value in a system
|
||||
wide daemon will set the `sysctl(3)` kern.maxproc (SoftResourceLimits) or kern.maxprocperuid
|
||||
(HardResourceLimits) value in addition to the `setrlimit(2)` values.
|
||||
'';
|
||||
};
|
||||
NumberOfProcesses = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum number of simultaneous processes for this user id. Setting this value in a system
|
||||
wide daemon will set the `sysctl(3)` kern.maxproc (SoftResourceLimits) or kern.maxprocperuid
|
||||
(HardResourceLimits) value in addition to the `setrlimit(2)` values.
|
||||
'';
|
||||
};
|
||||
|
||||
ResidentSetSize = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) to which a process's resident set size may grow. This imposes a
|
||||
limit on the amount of physical memory to be given to a process; if memory is tight, the system
|
||||
will prefer to take memory from processes that are exceeding their declared resident set size.
|
||||
'';
|
||||
};
|
||||
ResidentSetSize = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) to which a process's resident set size may grow. This imposes a
|
||||
limit on the amount of physical memory to be given to a process; if memory is tight, the system
|
||||
will prefer to take memory from processes that are exceeding their declared resident set size.
|
||||
'';
|
||||
};
|
||||
|
||||
Stack = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) of the stack segment for a process; this defines how far a program's
|
||||
stack segment may be extended. Stack extension is performed automatically by the system.
|
||||
'';
|
||||
Stack = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) of the stack segment for a process; this defines how far a program's
|
||||
stack segment may be extended. Stack extension is performed automatically by the system.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
HardResourceLimits = mkOption {
|
||||
default = null;
|
||||
example = { NumberOfFiles = 4096; };
|
||||
example = {
|
||||
NumberOfFiles = 4096;
|
||||
};
|
||||
description = ''
|
||||
Resource limits to be imposed on the job. These adjust variables set with `setrlimit(2)`. The following
|
||||
keys apply:
|
||||
'';
|
||||
type = types.nullOr (types.submodule {
|
||||
options = {
|
||||
Core = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The largest size (in bytes) core file that may be created.
|
||||
'';
|
||||
};
|
||||
type = types.nullOr (
|
||||
types.submodule {
|
||||
options = {
|
||||
Core = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The largest size (in bytes) core file that may be created.
|
||||
'';
|
||||
};
|
||||
|
||||
CPU = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum amount of cpu time (in seconds) to be used by each process.
|
||||
'';
|
||||
};
|
||||
CPU = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum amount of cpu time (in seconds) to be used by each process.
|
||||
'';
|
||||
};
|
||||
|
||||
Data = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) of the data segment for a process; this defines how far a program may
|
||||
extend its break with the `sbrk(2)` system call.
|
||||
'';
|
||||
};
|
||||
Data = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) of the data segment for a process; this defines how far a program may
|
||||
extend its break with the `sbrk(2)` system call.
|
||||
'';
|
||||
};
|
||||
|
||||
FileSize = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The largest size (in bytes) file that may be created.
|
||||
'';
|
||||
};
|
||||
FileSize = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The largest size (in bytes) file that may be created.
|
||||
'';
|
||||
};
|
||||
|
||||
MemoryLock = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) which a process may lock into memory using the `mlock(2)` function.
|
||||
'';
|
||||
};
|
||||
MemoryLock = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) which a process may lock into memory using the `mlock(2)` function.
|
||||
'';
|
||||
};
|
||||
|
||||
NumberOfFiles = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum number of open files for this process. Setting this value in a system wide daemon
|
||||
will set the `sysctl(3)` kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits)
|
||||
value in addition to the `setrlimit(2)` values.
|
||||
'';
|
||||
};
|
||||
NumberOfFiles = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum number of open files for this process. Setting this value in a system wide daemon
|
||||
will set the `sysctl(3)` kern.maxfiles (SoftResourceLimits) or kern.maxfilesperproc (HardResourceLimits)
|
||||
value in addition to the `setrlimit(2)` values.
|
||||
'';
|
||||
};
|
||||
|
||||
NumberOfProcesses = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum number of simultaneous processes for this user id. Setting this value in a system
|
||||
wide daemon will set the `sysctl(3)` kern.maxproc (SoftResourceLimits) or kern.maxprocperuid
|
||||
(HardResourceLimits) value in addition to the `setrlimit(2)` values.
|
||||
'';
|
||||
};
|
||||
NumberOfProcesses = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum number of simultaneous processes for this user id. Setting this value in a system
|
||||
wide daemon will set the `sysctl(3)` kern.maxproc (SoftResourceLimits) or kern.maxprocperuid
|
||||
(HardResourceLimits) value in addition to the `setrlimit(2)` values.
|
||||
'';
|
||||
};
|
||||
|
||||
ResidentSetSize = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) to which a process's resident set size may grow. This imposes a
|
||||
limit on the amount of physical memory to be given to a process; if memory is tight, the system
|
||||
will prefer to take memory from processes that are exceeding their declared resident set size.
|
||||
'';
|
||||
};
|
||||
ResidentSetSize = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) to which a process's resident set size may grow. This imposes a
|
||||
limit on the amount of physical memory to be given to a process; if memory is tight, the system
|
||||
will prefer to take memory from processes that are exceeding their declared resident set size.
|
||||
'';
|
||||
};
|
||||
|
||||
Stack = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) of the stack segment for a process; this defines how far a program's
|
||||
stack segment may be extended. Stack extension is performed automatically by the system.
|
||||
'';
|
||||
Stack = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
The maximum size (in bytes) of the stack segment for a process; this defines how far a program's
|
||||
stack segment may be extended. Stack extension is performed automatically by the system.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
Nice = mkOption {
|
||||
|
|
@ -628,8 +650,14 @@ in {
|
|||
};
|
||||
|
||||
ProcessType = mkOption {
|
||||
type = types.nullOr
|
||||
(types.enum [ "Background" "Standard" "Adaptive" "Interactive" ]);
|
||||
type = types.nullOr (
|
||||
types.enum [
|
||||
"Background"
|
||||
"Standard"
|
||||
"Adaptive"
|
||||
"Interactive"
|
||||
]
|
||||
);
|
||||
default = null;
|
||||
example = "Background";
|
||||
description = ''
|
||||
|
|
@ -694,7 +722,11 @@ in {
|
|||
|
||||
MachServices = mkOption {
|
||||
default = null;
|
||||
example = { "org.nixos.service" = { ResetAtClose = true; }; };
|
||||
example = {
|
||||
"org.nixos.service" = {
|
||||
ResetAtClose = true;
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
This optional key is used to specify Mach services to be registered with the Mach bootstrap sub-system.
|
||||
Each key in this dictionary should be the name of service to be advertised. The value of the key must
|
||||
|
|
@ -703,32 +735,37 @@ in {
|
|||
Finally, for the job itself, the values will be replaced with Mach ports at the time of check-in with
|
||||
launchd.
|
||||
'';
|
||||
type = types.nullOr (types.attrsOf (types.either types.bool
|
||||
(types.submodule {
|
||||
options = {
|
||||
ResetAtClose = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
If this boolean is false, the port is recycled, thus leaving clients to remain oblivious to the
|
||||
demand nature of job. If the value is set to true, clients receive port death notifications when
|
||||
the job lets go of the receive right. The port will be recreated atomically with respect to bootstrap_look_up()
|
||||
calls, so that clients can trust that after receiving a port death notification,
|
||||
the new port will have already been recreated. Setting the value to true should be done with
|
||||
care. Not all clients may be able to handle this behavior. The default value is false.
|
||||
'';
|
||||
};
|
||||
type = types.nullOr (
|
||||
types.attrsOf (
|
||||
types.either types.bool (
|
||||
types.submodule {
|
||||
options = {
|
||||
ResetAtClose = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
If this boolean is false, the port is recycled, thus leaving clients to remain oblivious to the
|
||||
demand nature of job. If the value is set to true, clients receive port death notifications when
|
||||
the job lets go of the receive right. The port will be recreated atomically with respect to bootstrap_look_up()
|
||||
calls, so that clients can trust that after receiving a port death notification,
|
||||
the new port will have already been recreated. Setting the value to true should be done with
|
||||
care. Not all clients may be able to handle this behavior. The default value is false.
|
||||
'';
|
||||
};
|
||||
|
||||
HideUntilCheckIn = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
Reserve the name in the namespace, but cause bootstrap_look_up() to fail until the job has
|
||||
checked in with launchd.
|
||||
'';
|
||||
};
|
||||
};
|
||||
})));
|
||||
HideUntilCheckIn = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
Reserve the name in the namespace, but cause bootstrap_look_up() to fail until the job has
|
||||
checked in with launchd.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
LaunchEvents = mkOption {
|
||||
|
|
@ -790,109 +827,123 @@ in {
|
|||
|
||||
The parameters below are used as inputs to call `getaddrinfo(3)`.
|
||||
'';
|
||||
type = types.nullOr (types.attrsOf (types.submodule {
|
||||
options = {
|
||||
SockType = mkOption {
|
||||
type = types.nullOr (types.enum [ "stream" "dgram" "seqpacket" ]);
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key tells launchctl what type of socket to create. The default is "stream" and
|
||||
other valid values for this key are "dgram" and "seqpacket" respectively.
|
||||
'';
|
||||
};
|
||||
type = types.nullOr (
|
||||
types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
SockType = mkOption {
|
||||
type = types.nullOr (
|
||||
types.enum [
|
||||
"stream"
|
||||
"dgram"
|
||||
"seqpacket"
|
||||
]
|
||||
);
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key tells launchctl what type of socket to create. The default is "stream" and
|
||||
other valid values for this key are "dgram" and "seqpacket" respectively.
|
||||
'';
|
||||
};
|
||||
|
||||
SockPassive = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key specifies whether `listen(2)` or `connect(2)` should be called on the created file
|
||||
descriptor. The default is true ("to listen").
|
||||
'';
|
||||
};
|
||||
SockPassive = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key specifies whether `listen(2)` or `connect(2)` should be called on the created file
|
||||
descriptor. The default is true ("to listen").
|
||||
'';
|
||||
};
|
||||
|
||||
SockNodeName = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key specifies the node to `connect(2)` or `bind(2)` to.
|
||||
'';
|
||||
};
|
||||
SockNodeName = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key specifies the node to `connect(2)` or `bind(2)` to.
|
||||
'';
|
||||
};
|
||||
|
||||
SockServiceName = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key specifies the service on the node to `connect(2)` or `bind(2)` to.
|
||||
'';
|
||||
};
|
||||
SockServiceName = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key specifies the service on the node to `connect(2)` or `bind(2)` to.
|
||||
'';
|
||||
};
|
||||
|
||||
SockFamily = mkOption {
|
||||
type = types.nullOr (types.enum [ "IPv4" "IPv6" ]);
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key can be used to specifically request that "IPv4" or "IPv6" socket(s) be created.
|
||||
'';
|
||||
};
|
||||
SockFamily = mkOption {
|
||||
type = types.nullOr (
|
||||
types.enum [
|
||||
"IPv4"
|
||||
"IPv6"
|
||||
]
|
||||
);
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key can be used to specifically request that "IPv4" or "IPv6" socket(s) be created.
|
||||
'';
|
||||
};
|
||||
|
||||
SockProtocol = mkOption {
|
||||
type = types.nullOr (types.enum [ "TCP" ]);
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key specifies the protocol to be passed to `socket(2)`. The only value understood by
|
||||
this key at the moment is "TCP".
|
||||
'';
|
||||
};
|
||||
SockProtocol = mkOption {
|
||||
type = types.nullOr (types.enum [ "TCP" ]);
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key specifies the protocol to be passed to `socket(2)`. The only value understood by
|
||||
this key at the moment is "TCP".
|
||||
'';
|
||||
};
|
||||
|
||||
SockPathName = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key implies SockFamily is set to "Unix". It specifies the path to `connect(2)` or
|
||||
`bind(2)` to.
|
||||
'';
|
||||
};
|
||||
SockPathName = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key implies SockFamily is set to "Unix". It specifies the path to `connect(2)` or
|
||||
`bind(2)` to.
|
||||
'';
|
||||
};
|
||||
|
||||
SecureSocketWithKey = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key is a variant of SockPathName. Instead of binding to a known path, a securely
|
||||
generated socket is created and the path is assigned to the environment variable that is inherited
|
||||
by all jobs spawned by launchd.
|
||||
'';
|
||||
};
|
||||
SecureSocketWithKey = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key is a variant of SockPathName. Instead of binding to a known path, a securely
|
||||
generated socket is created and the path is assigned to the environment variable that is inherited
|
||||
by all jobs spawned by launchd.
|
||||
'';
|
||||
};
|
||||
|
||||
SockPathMode = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key specifies the mode of the socket. Known bug: Property lists don't support
|
||||
octal, so please convert the value to decimal.
|
||||
'';
|
||||
};
|
||||
SockPathMode = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key specifies the mode of the socket. Known bug: Property lists don't support
|
||||
octal, so please convert the value to decimal.
|
||||
'';
|
||||
};
|
||||
|
||||
Bonjour = mkOption {
|
||||
type =
|
||||
types.nullOr (types.either types.bool (types.listOf types.str));
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key can be used to request that the service be registered with the
|
||||
`mDNSResponder(8)`. If the value is boolean, the service name is inferred from the SockServiceName.
|
||||
'';
|
||||
};
|
||||
Bonjour = mkOption {
|
||||
type = types.nullOr (types.either types.bool (types.listOf types.str));
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key can be used to request that the service be registered with the
|
||||
`mDNSResponder(8)`. If the value is boolean, the service name is inferred from the SockServiceName.
|
||||
'';
|
||||
};
|
||||
|
||||
MulticastGroup = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key can be used to request that the datagram socket join a multicast group. If the
|
||||
value is a hostname, then `getaddrinfo(3)` will be used to join the correct multicast address for a
|
||||
given socket family. If an explicit IPv4 or IPv6 address is given, it is required that the SockFamily
|
||||
family also be set, otherwise the results are undefined.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}));
|
||||
MulticastGroup = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
This optional key can be used to request that the datagram socket join a multicast group. If the
|
||||
value is a hostname, then `getaddrinfo(3)` will be used to join the correct multicast address for a
|
||||
given socket family. If an explicit IPv4 or IPv6 address is given, it is required that the SockFamily
|
||||
family also be set, otherwise the results are undefined.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,117 +5,146 @@
|
|||
{ lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) imap1 types mkOption showOption mergeDefinitions;
|
||||
inherit (builtins) map filter length deepSeq throw toString concatLists;
|
||||
inherit (lib)
|
||||
imap1
|
||||
types
|
||||
mkOption
|
||||
showOption
|
||||
mergeDefinitions
|
||||
;
|
||||
inherit (builtins)
|
||||
map
|
||||
filter
|
||||
length
|
||||
deepSeq
|
||||
throw
|
||||
toString
|
||||
concatLists
|
||||
;
|
||||
inherit (lib.options) showDefs;
|
||||
wildcardText = lib.literalMD "`*`";
|
||||
|
||||
/* *
|
||||
A type of list which does not allow duplicate elements. The base/inner
|
||||
list type to use (e.g. `types.listOf` or `types.nonEmptyListOf`) is passed
|
||||
via argument `listType`, which must be the final type and not a function.
|
||||
/*
|
||||
*
|
||||
A type of list which does not allow duplicate elements. The base/inner
|
||||
list type to use (e.g. `types.listOf` or `types.nonEmptyListOf`) is passed
|
||||
via argument `listType`, which must be the final type and not a function.
|
||||
|
||||
NOTE: The extra check for duplicates is quadratic and strict, so use this
|
||||
type sparingly and only:
|
||||
NOTE: The extra check for duplicates is quadratic and strict, so use this
|
||||
type sparingly and only:
|
||||
|
||||
* when needed, and
|
||||
* when the list is expected to be recursively short (e.g. < 10 elements)
|
||||
and shallow (i.e. strict evaluation of the list won't take too long)
|
||||
* when needed, and
|
||||
* when the list is expected to be recursively short (e.g. < 10 elements)
|
||||
and shallow (i.e. strict evaluation of the list won't take too long)
|
||||
|
||||
The implementation of this function is similar to that of
|
||||
`types.nonEmptyListOf`.
|
||||
The implementation of this function is similar to that of
|
||||
`types.nonEmptyListOf`.
|
||||
*/
|
||||
types'.uniqueList = listType:
|
||||
listType // {
|
||||
description = "unique ${
|
||||
types.optionDescriptionPhrase (class: class == "noun") listType
|
||||
}";
|
||||
types'.uniqueList =
|
||||
listType:
|
||||
listType
|
||||
// {
|
||||
description = "unique ${types.optionDescriptionPhrase (class: class == "noun") listType}";
|
||||
substSubModules = m: types'.uniqueList (listType.substSubModules m);
|
||||
# This has been taken from the implementation of `types.listOf`, but has
|
||||
# been modified to throw on duplicates. This check cannot be done in the
|
||||
# `check` fn as this check is deep/strict, and because `check` runs
|
||||
# prior to merging.
|
||||
merge = loc: defs:
|
||||
merge =
|
||||
loc: defs:
|
||||
let
|
||||
# Each element of `dupes` is a list. When there are duplicates,
|
||||
# later lists will be duplicates of earlier lists, so just throw on
|
||||
# the first set of duplicates found so that we don't have duplicate
|
||||
# error msgs.
|
||||
checked = filter (li:
|
||||
checked = filter (
|
||||
li:
|
||||
if length li > 1 then
|
||||
throw ''
|
||||
The option `${
|
||||
showOption loc
|
||||
}' contains duplicate entries after merging:
|
||||
The option `${showOption loc}' contains duplicate entries after merging:
|
||||
${showDefs li}''
|
||||
else
|
||||
false) dupes;
|
||||
dupes =
|
||||
map (def: filter (def': def'.value == def.value) merged) merged;
|
||||
merged = filter (x: x ? value) (concatLists (imap1 (n: def:
|
||||
imap1 (m: el:
|
||||
let
|
||||
inherit (def) file;
|
||||
loc' = loc
|
||||
++ [ "[definition ${toString n}-entry ${toString m}]" ];
|
||||
in (mergeDefinitions loc' listType.nestedTypes.elemType [{
|
||||
inherit file;
|
||||
value = el;
|
||||
}]).optionalValue // {
|
||||
inherit loc' file;
|
||||
}) def.value) defs));
|
||||
in deepSeq checked (map (x: x.value) merged);
|
||||
false
|
||||
) dupes;
|
||||
dupes = map (def: filter (def': def'.value == def.value) merged) merged;
|
||||
merged = filter (x: x ? value) (
|
||||
concatLists (
|
||||
imap1 (
|
||||
n: def:
|
||||
imap1 (
|
||||
m: el:
|
||||
let
|
||||
inherit (def) file;
|
||||
loc' = loc ++ [ "[definition ${toString n}-entry ${toString m}]" ];
|
||||
in
|
||||
(mergeDefinitions loc' listType.nestedTypes.elemType [
|
||||
{
|
||||
inherit file;
|
||||
value = el;
|
||||
}
|
||||
]).optionalValue
|
||||
// {
|
||||
inherit loc' file;
|
||||
}
|
||||
) def.value
|
||||
) defs
|
||||
)
|
||||
);
|
||||
in
|
||||
deepSeq checked (map (x: x.value) merged);
|
||||
};
|
||||
in {
|
||||
StartCalendarInterval = let
|
||||
CalendarIntervalEntry = types.submodule {
|
||||
options = {
|
||||
Minute = mkOption {
|
||||
type = types.nullOr (types.ints.between 0 59);
|
||||
default = null;
|
||||
defaultText = wildcardText;
|
||||
description = ''
|
||||
The minute on which this job will be run.
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
StartCalendarInterval =
|
||||
let
|
||||
CalendarIntervalEntry = types.submodule {
|
||||
options = {
|
||||
Minute = mkOption {
|
||||
type = types.nullOr (types.ints.between 0 59);
|
||||
default = null;
|
||||
defaultText = wildcardText;
|
||||
description = ''
|
||||
The minute on which this job will be run.
|
||||
'';
|
||||
};
|
||||
|
||||
Hour = mkOption {
|
||||
type = types.nullOr (types.ints.between 0 23);
|
||||
default = null;
|
||||
defaultText = wildcardText;
|
||||
description = ''
|
||||
The hour on which this job will be run.
|
||||
'';
|
||||
};
|
||||
Hour = mkOption {
|
||||
type = types.nullOr (types.ints.between 0 23);
|
||||
default = null;
|
||||
defaultText = wildcardText;
|
||||
description = ''
|
||||
The hour on which this job will be run.
|
||||
'';
|
||||
};
|
||||
|
||||
Day = mkOption {
|
||||
type = types.nullOr (types.ints.between 1 31);
|
||||
default = null;
|
||||
defaultText = wildcardText;
|
||||
description = ''
|
||||
The day on which this job will be run.
|
||||
'';
|
||||
};
|
||||
Day = mkOption {
|
||||
type = types.nullOr (types.ints.between 1 31);
|
||||
default = null;
|
||||
defaultText = wildcardText;
|
||||
description = ''
|
||||
The day on which this job will be run.
|
||||
'';
|
||||
};
|
||||
|
||||
Weekday = mkOption {
|
||||
type = types.nullOr (types.ints.between 0 7);
|
||||
default = null;
|
||||
defaultText = wildcardText;
|
||||
description = ''
|
||||
The weekday on which this job will be run (0 and 7 are Sunday).
|
||||
'';
|
||||
};
|
||||
Weekday = mkOption {
|
||||
type = types.nullOr (types.ints.between 0 7);
|
||||
default = null;
|
||||
defaultText = wildcardText;
|
||||
description = ''
|
||||
The weekday on which this job will be run (0 and 7 are Sunday).
|
||||
'';
|
||||
};
|
||||
|
||||
Month = mkOption {
|
||||
type = types.nullOr (types.ints.between 1 12);
|
||||
default = null;
|
||||
defaultText = wildcardText;
|
||||
description = ''
|
||||
The month on which this job will be run.
|
||||
'';
|
||||
Month = mkOption {
|
||||
type = types.nullOr (types.ints.between 1 12);
|
||||
default = null;
|
||||
defaultText = wildcardText;
|
||||
description = ''
|
||||
The month on which this job will be run.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
in types.either CalendarIntervalEntry
|
||||
(types'.uniqueList (types.nonEmptyListOf CalendarIntervalEntry));
|
||||
in
|
||||
types.either CalendarIntervalEntry (types'.uniqueList (types.nonEmptyListOf CalendarIntervalEntry));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue