{ config, lib, pkgs, ... }: let cfg = config.programs.rclone; targetName = "rclone"; mkSystemdDependencyOption = { default, ... }: lib.mkOption { type = lib.types.attrsOf (lib.types.listOf lib.types.str); description = "The systemd services this sync depends on."; example = { secrets = [ "sops-nix.service" ]; }; inherit default; }; mkProvider = { secretLoader ? ({ ... }: ""), envLoader ? ({ ... }: { }), configLoader ? ({ ... }: { }), options ? {}, ... }: { inherit secretLoader envLoader configLoader options ; }; syncProviders = { nextcloud = mkProvider { options = lib.types.submodule ( (mkOwncloudOptions { })); }; proton = mkProvider {}; manual = mkProvider {}; }; syncType = lib.types.submodule ( { config, name, ... }: { options = { type = lib.mkOption { description = "The type of the sync"; type = lib.types.enum (builtins.attrNames syncProviders); default = "manual"; }; autoStart = lib.mkOption { type = lib.types.bool; description = "Whether to start this sync automatically."; default = true; }; providerOptions = lib.mkOption { description = "The options of the sync"; type = lib.types.oneOf [ (builtins.map (provider: provider.options) syncProviders) ]; }; 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; }; }; config = { environment = syncProviders.${config.type}.envLoader config; secretsScript = syncProviders.${config.type}.secretLoader config; config = syncProviders.${config.type}.configLoader config; }; }); in { options = { programs.rclone = { enable = lib.mkEnableOption "rclone"; systemdDependencies = mkSystemdDependencyOption { default = {}; }; configs = lib.mkOption { type = lib.types.attrsOf syncType; description = "The synchronizations to set up."; default = {}; }; }; }; 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 (name: sync: let serviceName = "rclone-sync-${name}"; in { ${serviceName} = { Unit = { Description = "${sync.type}"; }; Service = { Environment = lib.mapAttrsToList (key: val: (lib.escapeShellArg "${key}=${val}")) sync.environment; ExecStart = let 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); }; }; }) cfg.configs); targets.${targetName} = { Unit = { Description = "rclone Mounts"; Documentation = "man:rclone(1)"; }; }; }; }; }