rclone: add launchd mount/serve sidecar agents for Darwin

Adds the Darwin launchd mount/serve sidecar agents together with the
mount sidecar generation test.
This commit is contained in:
jiezhuzzz
2026-05-19 12:37:34 -05:00
committed by Austin Horstman
parent d4e015754e
commit 13e1296711
3 changed files with 132 additions and 0 deletions
+62
View File
@@ -126,6 +126,61 @@ let
) "default.target";
};
# Builder for a per-sidecar launchd agent. Returns the value half
# of a `nameValuePair` (the agent attrs).
mkLaunchdSidecar =
{
sidecarType,
remoteName,
sidecar,
sidecarPath,
isMount,
cmdName,
}:
let
label = "rclone-${cmdName}:${replaceIllegalChars sidecarPath}@${remoteName}";
runAtLoad = if isMount then sidecar.autoMount else sidecar.autoStart;
rcloneArgs =
[
(lib.getExe cfg.package)
cmdName
]
++ (lib.cli.toCommandLineGNU { } sidecar.options)
++ (
if isMount then
[
"${remoteName}:${sidecarPath}"
sidecar.mountPoint
]
else
[
sidecar.protocol
"${remoteName}:${sidecarPath}"
]
);
in
{
enable = true;
config = {
ProgramArguments =
[ (lib.getExe rcloneSidecarWrapper) ]
++ (lib.optionals isMount [
"--mkdir"
sidecar.mountPoint
])
++ rcloneArgs;
RunAtLoad = runAtLoad;
KeepAlive = {
SuccessfulExit = false;
Crashed = true;
};
StandardOutPath = "${config.home.homeDirectory}/Library/Logs/rclone/${label}.log";
StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/rclone/${label}.err.log";
EnvironmentVariables =
if sidecar.logLevel != null then { RCLONE_LOG_LEVEL = sidecar.logLevel; } else null;
};
};
# Iterate cfg.remotes × remote.${sidecarType}, applying the supplied
# value builder. Produces an attrset keyed by service name.
mkRcloneSidecars =
@@ -185,6 +240,11 @@ let
sleep 1
done
if [ "''${1:-}" = "--mkdir" ]; then
mkdir -p "$2"
shift 2
fi
exec "$@"
'';
};
@@ -568,6 +628,8 @@ in
];
launchd.agents = lib.mkMerge [
mkLaunchdConfigService
(mkRcloneSidecars "mounts" mkLaunchdSidecar)
(mkRcloneSidecars "serve" mkLaunchdSidecar)
];
};
}
@@ -6,3 +6,6 @@
rclone-mount-service-generation = ./mount-service-generation.nix;
rclone-serve-service-generation = ./serve-service-generation.nix;
}
// lib.optionalAttrs pkgs.stdenv.hostPlatform.isDarwin {
rclone-mount-service-generation-darwin = ./mount-service-generation-darwin.nix;
}
@@ -0,0 +1,67 @@
_: {
programs.rclone = {
enable = true;
remotes.sftp-remote = {
config = {
type = "sftp";
host = "backup-server.example.com";
user = "alice";
key_file = "/Users/alice/.ssh/id_ed25519";
};
mounts = {
"documents/work" = {
enable = true;
mountPoint = "/Users/alice/mounts/work-docs";
logLevel = "INFO";
options = {
dir-cache-time = "5000h";
poll-interval = "10s";
umask = "002";
};
};
"disabled-mount" = {
enable = false;
mountPoint = "/Users/alice/mounts/disabled";
};
};
};
};
nmt.script = ''
plist="LaunchAgents/org.nix-community.home.rclone-mount:documents.work@sftp-remote.plist"
assertFileExists "$plist"
# rclone command line is wrapped by the launchd module in
# `/bin/sh -c "/bin/wait4path /nix/store && exec <args>"`,
# then by our rclone-sidecar-wrapper. Check for the meaningful
# substrings rather than the full quoted form.
assertFileContains "$plist" "rclone-sidecar-wrapper"
assertFileContains "$plist" "/bin/rclone"
assertFileContains "$plist" "mount"
assertFileContains "$plist" "&apos;--cache-dir=/home/hm-user/.cache/rclone&apos;"
assertFileContains "$plist" "&apos;--vfs-cache-mode=full&apos;"
assertFileContains "$plist" "&apos;--dir-cache-time=5000h&apos;"
assertFileContains "$plist" "&apos;--poll-interval=10s&apos;"
assertFileContains "$plist" "&apos;--umask=002&apos;"
assertFileContains "$plist" "sftp-remote:documents/work"
assertFileContains "$plist" "/Users/alice/mounts/work-docs"
# Mount sidecars pre-create the mount point via the wrapper's --mkdir flag.
assertFileContains "$plist" "rclone-sidecar-wrapper --mkdir"
# Lifecycle keys
assertFileContains "$plist" "<key>RunAtLoad</key>"
assertFileContains "$plist" "<key>KeepAlive</key>"
assertFileContains "$plist" "<key>Crashed</key>"
# Logs route under ~/Library/Logs/rclone/
assertFileContains "$plist" "Library/Logs/rclone"
# Log level surfaces as an environment variable
assertFileContains "$plist" "RCLONE_LOG_LEVEL"
assertFileContains "$plist" "INFO"
# Disabled mount produces no plist
assertPathNotExists "LaunchAgents/org.nix-community.home.rclone-mount:disabled-mount@sftp-remote.plist"
'';
}