1
0
Fork 0
mirror of https://github.com/nix-community/home-manager.git synced 2025-03-09 02:06:53 +00:00

syncthing: remove with lib

This commit is contained in:
Austin Horstman 2025-02-13 10:50:17 -06:00
parent 20fac9bbdf
commit 5031c6d297

View file

@ -1,13 +1,13 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
with lib;
let let
inherit (lib) literalExpression mkOption mkEnableOption mkPackageOption types;
cfg = config.services.syncthing; cfg = config.services.syncthing;
settingsFormat = pkgs.formats.json { }; settingsFormat = pkgs.formats.json { };
cleanedConfig = cleanedConfig =
converge (filterAttrsRecursive (_: v: v != null && v != { })) cfg.settings; lib.converge (lib.filterAttrsRecursive (_: v: v != null && v != { }))
cfg.settings;
isUnixGui = (builtins.substring 0 1 cfg.guiAddress) == "/"; isUnixGui = (builtins.substring 0 1 cfg.guiAddress) == "/";
@ -26,17 +26,17 @@ let
else else
"${cfg.guiAddress}${path}"; "${cfg.guiAddress}${path}";
devices = mapAttrsToList (_: device: device // { deviceID = device.id; }) devices = lib.mapAttrsToList (_: device: device // { deviceID = device.id; })
cfg.settings.devices; cfg.settings.devices;
folders = mapAttrsToList (_: folder: folders = lib.mapAttrsToList (_: folder:
folder // { folder // {
devices = map (device: devices = map (device:
if builtins.isString device then { if builtins.isString device then {
deviceId = cfg.settings.devices.${device}.id; deviceId = cfg.settings.devices.${device}.id;
} else } else
device) folder.devices; device) folder.devices;
}) (filterAttrs (_: folder: folder.enable) cfg.settings.folders); }) (lib.filterAttrs (_: folder: folder.enable) cfg.settings.folders);
jq = lib.getExe pkgs.jq; jq = lib.getExe pkgs.jq;
sleep = lib.getExe' pkgs.coreutils "sleep"; sleep = lib.getExe' pkgs.coreutils "sleep";
@ -91,7 +91,7 @@ let
} [ } [
# Now for each of these attributes, write the curl commands that are # Now for each of these attributes, write the curl commands that are
# identical to both folders and devices. # identical to both folders and devices.
(mapAttrs (conf_type: s: (lib.mapAttrs (conf_type: s:
# We iterate the `conf` list now, and run a curl -X POST command for each, that # We iterate the `conf` list now, and run a curl -X POST command for each, that
# should update that device/folder only. # should update that device/folder only.
lib.pipe s.conf [ lib.pipe s.conf [
@ -167,9 +167,9 @@ let
syncthingArgs = defaultSyncthingArgs ++ cfg.extraOptions; syncthingArgs = defaultSyncthingArgs ++ cfg.extraOptions;
in { in {
meta.maintainers = [ maintainers.rycee ]; meta.maintainers = [ lib.maintainers.rycee ];
options = with types; { options = {
services.syncthing = { services.syncthing = {
enable = mkEnableOption '' enable = mkEnableOption ''
Syncthing, a self-hosted open-source alternative to Dropbox and Bittorrent Sync. Syncthing, a self-hosted open-source alternative to Dropbox and Bittorrent Sync.
@ -177,7 +177,7 @@ in {
''; '';
cert = mkOption { cert = mkOption {
type = nullOr str; type = with types; nullOr str;
default = null; default = null;
description = '' description = ''
Path to the `cert.pem` file, which will be copied into Syncthing's Path to the `cert.pem` file, which will be copied into Syncthing's
@ -186,7 +186,7 @@ in {
}; };
key = mkOption { key = mkOption {
type = nullOr str; type = with types; nullOr str;
default = null; default = null;
description = '' description = ''
Path to the `key.pem` file, which will be copied into Syncthing's Path to the `key.pem` file, which will be copied into Syncthing's
@ -195,7 +195,7 @@ in {
}; };
passwordFile = mkOption { passwordFile = mkOption {
type = nullOr path; type = with types; nullOr path;
default = null; default = null;
description = '' description = ''
Path to the gui password file. Path to the gui password file.
@ -203,7 +203,7 @@ in {
}; };
overrideDevices = mkOption { overrideDevices = mkOption {
type = bool; type = types.bool;
default = true; default = true;
description = '' description = ''
Whether to delete the devices which are not configured via the Whether to delete the devices which are not configured via the
@ -214,7 +214,7 @@ in {
}; };
overrideFolders = mkOption { overrideFolders = mkOption {
type = bool; type = types.bool;
default = true; default = true;
description = '' description = ''
Whether to delete the folders which are not configured via the Whether to delete the folders which are not configured via the
@ -225,7 +225,7 @@ in {
}; };
settings = mkOption { settings = mkOption {
type = submodule { type = types.submodule {
freeformType = settingsFormat.type; freeformType = settingsFormat.type;
options = { options = {
# global options # global options
@ -234,11 +234,11 @@ in {
description = '' description = ''
The options element contains all other global configuration options The options element contains all other global configuration options
''; '';
type = submodule ({ name, ... }: { type = types.submodule {
freeformType = settingsFormat.type; freeformType = settingsFormat.type;
options = { options = {
localAnnounceEnabled = mkOption { localAnnounceEnabled = mkOption {
type = nullOr bool; type = with types; nullOr bool;
default = null; default = null;
description = '' description = ''
Whether to send announcements to the local LAN, also use such announcements to find other devices. Whether to send announcements to the local LAN, also use such announcements to find other devices.
@ -246,7 +246,7 @@ in {
}; };
localAnnouncePort = mkOption { localAnnouncePort = mkOption {
type = nullOr int; type = with types; nullOr int;
default = null; default = null;
description = '' description = ''
The port on which to listen and send IPv4 broadcast announcements to. The port on which to listen and send IPv4 broadcast announcements to.
@ -254,7 +254,7 @@ in {
}; };
relaysEnabled = mkOption { relaysEnabled = mkOption {
type = nullOr bool; type = with types; nullOr bool;
default = null; default = null;
description = '' description = ''
When true, relays will be connected to and potentially used for device to device connections. When true, relays will be connected to and potentially used for device to device connections.
@ -262,7 +262,7 @@ in {
}; };
urAccepted = mkOption { urAccepted = mkOption {
type = nullOr int; type = with types; nullOr int;
default = null; default = null;
description = '' description = ''
Whether the user has accepted to submit anonymous usage data. Whether the user has accepted to submit anonymous usage data.
@ -272,7 +272,7 @@ in {
}; };
limitBandwidthInLan = mkOption { limitBandwidthInLan = mkOption {
type = nullOr bool; type = with types; nullOr bool;
default = null; default = null;
description = '' description = ''
Whether to apply bandwidth limits to devices in the same broadcast domain as the local device. Whether to apply bandwidth limits to devices in the same broadcast domain as the local device.
@ -280,7 +280,7 @@ in {
}; };
maxFolderConcurrency = mkOption { maxFolderConcurrency = mkOption {
type = nullOr int; type = with types; nullOr int;
default = null; default = null;
description = '' description = ''
This option controls how many folders may concurrently be in I/O-intensive operations such as syncing or scanning. This option controls how many folders may concurrently be in I/O-intensive operations such as syncing or scanning.
@ -288,7 +288,7 @@ in {
''; '';
}; };
}; };
}); };
}; };
# device settings # device settings
@ -308,12 +308,12 @@ in {
addresses = [ "tcp://192.168.0.10:51820" ]; addresses = [ "tcp://192.168.0.10:51820" ];
}; };
}; };
type = attrsOf (submodule ({ name, ... }: { type = types.attrsOf (types.submodule ({ name, ... }: {
freeformType = settingsFormat.type; freeformType = settingsFormat.type;
options = { options = {
name = mkOption { name = mkOption {
type = str; type = types.str;
default = name; default = name;
description = '' description = ''
The name of the device. The name of the device.
@ -321,14 +321,14 @@ in {
}; };
id = mkOption { id = mkOption {
type = str; type = types.str;
description = '' description = ''
The device ID. See <https://docs.syncthing.net/dev/device-ids.html>. The device ID. See <https://docs.syncthing.net/dev/device-ids.html>.
''; '';
}; };
autoAcceptFolders = mkOption { autoAcceptFolders = mkOption {
type = bool; type = types.bool;
default = false; default = false;
description = '' description = ''
Automatically create or share folders that this device advertises at the default path. Automatically create or share folders that this device advertises at the default path.
@ -358,12 +358,12 @@ in {
}; };
} }
''; '';
type = attrsOf (submodule ({ name, ... }: { type = types.attrsOf (types.submodule ({ name, ... }: {
freeformType = settingsFormat.type; freeformType = settingsFormat.type;
options = { options = {
enable = mkOption { enable = mkOption {
type = bool; type = types.bool;
default = true; default = true;
description = '' description = ''
Whether to share this folder. Whether to share this folder.
@ -373,11 +373,12 @@ in {
}; };
path = mkOption { path = mkOption {
type = str // { type = types.str // {
check = x: check = x:
str.check x types.str.check x && (lib.substring 0 1 x == "/"
&& (substring 0 1 x == "/" || substring 0 2 x == "~/"); || lib.substring 0 2 x == "~/");
description = str.description + " starting with / or ~/"; description = types.str.description
+ " starting with / or ~/";
}; };
default = name; default = name;
description = '' description = ''
@ -388,7 +389,7 @@ in {
}; };
id = mkOption { id = mkOption {
type = str; type = types.str;
default = name; default = name;
description = '' description = ''
The ID of the folder. Must be the same on all devices. The ID of the folder. Must be the same on all devices.
@ -396,7 +397,7 @@ in {
}; };
label = mkOption { label = mkOption {
type = str; type = types.str;
default = name; default = name;
description = '' description = ''
The label of the folder. The label of the folder.
@ -404,7 +405,7 @@ in {
}; };
type = mkOption { type = mkOption {
type = enum [ type = types.enum [
"sendreceive" "sendreceive"
"sendonly" "sendonly"
"receiveonly" "receiveonly"
@ -418,7 +419,7 @@ in {
}; };
devices = mkOption { devices = mkOption {
type = listOf str; type = with types; listOf str;
default = [ ]; default = [ ];
description = '' description = ''
The devices this folder should be shared with. Each device must The devices this folder should be shared with. Each device must
@ -490,7 +491,7 @@ in {
}; };
copyOwnershipFromParent = mkOption { copyOwnershipFromParent = mkOption {
type = bool; type = types.bool;
default = false; default = false;
description = '' description = ''
On Unix systems, tries to copy file/folder ownership from On Unix systems, tries to copy file/folder ownership from
@ -541,7 +542,7 @@ in {
}; };
guiAddress = mkOption { guiAddress = mkOption {
type = str; type = types.str;
default = "127.0.0.1:8384"; default = "127.0.0.1:8384";
description = '' description = ''
The address to serve the web interface at. The address to serve the web interface at.
@ -561,7 +562,7 @@ in {
}; };
extraOptions = mkOption { extraOptions = mkOption {
type = listOf str; type = with types; listOf str;
default = [ ]; default = [ ];
example = [ "--reset-deltas" ]; example = [ "--reset-deltas" ];
description = '' description = ''
@ -604,9 +605,9 @@ in {
}; };
}; };
config = mkMerge [ config = lib.mkMerge [
(mkIf cfg.enable { (lib.mkIf cfg.enable {
home.packages = [ (getOutput "man" cfg.package) ]; home.packages = [ (lib.getOutput "man" cfg.package) ];
systemd.user.services = { systemd.user.services = {
syncthing = { syncthing = {
@ -618,28 +619,28 @@ in {
}; };
Service = { Service = {
ExecStartPre = mkIf (cfg.cert != null || cfg.key != null) "+${ ExecStartPre = lib.mkIf (cfg.cert != null || cfg.key != null) "+${
pkgs.writers.writeBash "syncthing-copy-keys" '' pkgs.writers.writeBash "syncthing-copy-keys" ''
syncthing_dir="''${XDG_STATE_HOME:-$HOME/.local/state}/syncthing" syncthing_dir="''${XDG_STATE_HOME:-$HOME/.local/state}/syncthing"
${install} -dm700 "$syncthing_dir" ${install} -dm700 "$syncthing_dir"
${optionalString (cfg.cert != null) '' ${lib.optionalString (cfg.cert != null) ''
${install} -Dm400 ${ ${install} -Dm400 ${
toString cfg.cert toString cfg.cert
} "$syncthing_dir/cert.pem" } "$syncthing_dir/cert.pem"
''} ''}
${optionalString (cfg.key != null) '' ${lib.optionalString (cfg.key != null) ''
${install} -Dm400 ${ ${install} -Dm400 ${
toString cfg.key toString cfg.key
} "$syncthing_dir/key.pem" } "$syncthing_dir/key.pem"
''} ''}
'' ''
}"; }";
ExecStart = escapeShellArgs syncthingArgs; ExecStart = lib.escapeShellArgs syncthingArgs;
Restart = "on-failure"; Restart = "on-failure";
SuccessExitStatus = [ 3 4 ]; SuccessExitStatus = [ 3 4 ];
RestartForceExitStatus = [ 3 4 ]; RestartForceExitStatus = [ 3 4 ];
Environment = Environment =
mkIf (cfg.allProxy != null) { all_proxy = cfg.allProxy; }; lib.mkIf (cfg.allProxy != null) { all_proxy = cfg.allProxy; };
# Sandboxing. # Sandboxing.
LockPersonality = true; LockPersonality = true;
@ -654,7 +655,7 @@ in {
Install = { WantedBy = [ "default.target" ]; }; Install = { WantedBy = [ "default.target" ]; };
}; };
syncthing-init = mkIf (cleanedConfig != { }) { syncthing-init = lib.mkIf (cleanedConfig != { }) {
Unit = { Unit = {
Description = "Syncthing configuration updater"; Description = "Syncthing configuration updater";
Requires = [ "syncthing.service" ]; Requires = [ "syncthing.service" ];
@ -685,10 +686,10 @@ in {
}; };
}) })
(mkIf (isAttrs cfg.tray && cfg.tray.enable) { (lib.mkIf (lib.isAttrs cfg.tray && cfg.tray.enable) {
assertions = [ assertions = [
(hm.assertions.assertPlatform "services.syncthing.tray" pkgs (lib.hm.assertions.assertPlatform "services.syncthing.tray" pkgs
platforms.linux) lib.platforms.linux)
]; ];
systemd.user.services = { systemd.user.services = {
@ -710,10 +711,10 @@ in {
}) })
# deprecated # deprecated
(mkIf (isBool cfg.tray && cfg.tray) { (lib.mkIf (lib.isBool cfg.tray && cfg.tray) {
assertions = [ assertions = [
(hm.assertions.assertPlatform "services.syncthing.tray" pkgs (lib.hm.assertions.assertPlatform "services.syncthing.tray" pkgs
platforms.linux) lib.platforms.linux)
]; ];
systemd.user.services = { systemd.user.services = {