{ config, lib, pkgs, ... }: let cfg = config.programs.rclone; targetName = "rclone"; mkIfNotNull = value: result: lib.mkIf (value != null) result; mkSystemdDependencyOption = { default, global ? false, ... }: lib.mkOption { type = lib.types.attrsOf (lib.types.listOf lib.types.str); description = "The systemd services ${ if global then "all" else "this" } sync${ if global then "s" else "" } depend${ if global then "" else "s" } on."; example = { secrets = [ "sops-nix.service" ]; }; inherit default; }; mkProvider = ( { config, ... }: { options = { path = lib.mkOption { type = lib.types.str; description = "The path to mount the remote file system to."; }; autoStart = lib.mkOption { type = lib.types.bool; description = "Whether to start this sync automatically."; default = true; }; systemdDependencies = mkSystemdDependencyOption { default = cfg.systemdDependencies; }; environment = lib.mkOption { type = lib.types.attrsOf lib.types.envVar; description = "The environment variables to pass to the service."; default = { }; }; secretsScript = lib.mkOption { type = lib.types.lines; description = "A script for loading secrets before launching the sync."; default = []; }; config = lib.mkOption { type = lib.types.attrs; description = "The rclone config to use for creating the mount."; visible = false; }; }; }); mkWebdavProvider = ( { displayName, vendor, ... }: ( { config, ... }: { imports = [ mkProvider ]; options = { vendor = lib.mkOption { type = lib.types.str; description = "The vendor of the WebDAV share."; default = vendor; }; url = lib.mkOption { type = lib.types.str; description = "The WebDAV URL of the ${displayName} server."; default = null; }; username = lib.mkOption { type = lib.types.nullOr lib.types.str; description = "The user name for logging in to the ${displayName} server."; default = null; }; obscuredPassword = lib.mkOption { type = lib.types.nullOr lib.types.str; description = "The password obscured using the `rclone obscure` command for logging in to the ${displayName} server."; default = null; }; obscuredPasswordFile = lib.mkOption { type = lib.types.nullOr (lib.types.either lib.types.path lib.types.str); description = "The path to a file containing the password obscured using the `rclone obscure` command for logging in to the ${displayName} server."; default = null; }; }; config = { config = lib.mkMerge [ { inherit vendor; url = config.url; } (mkIfNotNull config.username { user = config.username; }) (mkIfNotNull config.obscuredPassword { pass = config.obscuredPassword; }) ]; }; })); syncProviders = { nextcloud = rec { displayName = "Nextcloud"; module = mkWebdavProvider { inherit displayName; vendor = "nextcloud"; }; }; }; in { options = { programs.rclone = { enable = lib.mkEnableOption "rclone"; systemdDependencies = mkSystemdDependencyOption { default = {}; global = true; }; configs = (builtins.mapAttrs (name: provider: lib.mkOption { type = lib.types.attrsOf (lib.types.submodule provider.module); description = "The ${provider.displayName} synchronizations to set up."; default = { }; }) syncProviders); }; }; config = { home.packages = lib.optional cfg.enable pkgs.rclone; systemd.user = lib.optionalAttrs cfg.enable { enable = true; services = { rclone = { Unit = { Description = "rclone Starter"; Documentation = "man:rclone(1)"; }; Service = { Type = "simple"; ExecStartPre = let script = pkgs.writeShellScriptBin "rclone-pre" '' sleep 10 ''; in (lib.getExe script); ExecStart = let script = pkgs.writeShellScriptBin "rclone" '' systemctl --user start rclone.target ''; in (lib.getExe script); }; }; } // ( lib.attrsets.concatMapAttrs (providerName: configs: lib.attrsets.concatMapAttrs (name: sync: let serviceName = "rclone-${providerName}-sync-${name}"; in { ${serviceName} = { Unit = { Description = "rclone sync service for ${name} at using ${providerName}"; }; Service = { Environment = lib.mapAttrsToList (key: val: (lib.escapeShellArg "${key}=${val}")) sync.environment; ExecStart = let configFile = pkgs.writeText "${serviceName}.conf" (lib.generators.toINI { } { name = sync.config; }); script = pkgs.writeShellScriptBin serviceName '' ${sync.secretsScript} bash -c echo hello world ''; in (lib.getExe script); }; Install = { WantedBy = lib.optional sync.autoStart "${targetName}.target"; After = builtins.concatLists(builtins.attrValues sync.systemdDependencies); }; }; }) configs) cfg.configs); targets.${targetName} = { Unit = { Description = "rclone Mounts"; Documentation = "man:rclone(1)"; }; }; }; }; }