diff --git a/Tools/RemoteSynchronization/Program.cs b/Tools/RemoteSynchronization/Program.cs index e09ff28c4..7a97bedb3 100644 --- a/Tools/RemoteSynchronization/Program.cs +++ b/Tools/RemoteSynchronization/Program.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2025, The Duplicati Team +// Copyright (C) 2025, The Duplicati Team // https://duplicati.com, hello@duplicati.com // // Permission is hereby granted, free of charge, to any person obtaining a @@ -32,6 +32,9 @@ using System.Threading.Tasks; namespace RemoteSynchronization { + /// + /// Remote synchronization tool. + /// public class Program { // Default values for the options @@ -56,7 +59,25 @@ namespace RemoteSynchronization var confirm_opt = new Option(aliases: ["--confirm"], description: "Automatically confirm the operation", getDefaultValue: () => DEFAULT_CONFIRM); var global_opts = OptionWithMultipleTokens(aliases: ["--global-options"], description: "Global options all backends. May be overridden by backend specific options (src-options, dst-options)"); - var root_cmd = new RootCommand("Remote Synchronization Tool"); + var root_cmd = new RootCommand(@"Remote Synchronization Tool + +This tool synchronizes two remote backends. The tool assumes that the intent is +to have the destination match the source. + +If the destination has files that are not in the source, they will be deleted +(or renamed if the retention option is set). + +If the destination has files that are in the source but are different in size or +has a newer timestamp, they will be overwritten by the source files. + +If the force option is set, the destination will be overwritten by the source, +regardless of the state of the files. It will also skip the initial comparison, +and delete (or rename) all files in the destination. + +If the verify option is set, the files will be downloaded and compared after +uploading to ensure that the files are correct. Files that already exist in the +destination will be verified before being overwritten (if they seemingly match). + "); root_cmd.AddArgument(src_arg); root_cmd.AddArgument(dst_arg); root_cmd.AddOption(dry_run_opt); @@ -83,6 +104,7 @@ namespace RemoteSynchronization private static async Task Run(string src, string dst, Dictionary options) { + // Parse the known options for this tool var dry_run = options["dry-run"] as bool? ?? DEFAULT_DRY_RUN; var verify = options["verify"] as bool? ?? DEFAULT_VERIFY; var retries = options["retry"] as int? ?? DEFAULT_RETRY; @@ -90,6 +112,7 @@ namespace RemoteSynchronization var retention = options["retention"] as bool? ?? DEFAULT_RETENTION; var confirm = options["confirm"] as bool? ?? DEFAULT_CONFIRM; + // Unpack and parse the multi token options Dictionary global_options = (options["global-options"] as List) ?.Select(x => x.Split("=")) .ToDictionary(x => x[0], x => x[1]) @@ -107,6 +130,7 @@ namespace RemoteSynchronization foreach (var x in global_options) src_opts[x.Key] = dst_opts[x.Key] = x.Value; + // Load the backends using var b1 = Duplicati.Library.DynamicLoader.BackendLoader.GetBackend(src, src_opts); var b1s = b1 as IStreamingBackend; System.Diagnostics.Debug.Assert(b1s != null); @@ -214,7 +238,6 @@ namespace RemoteSynchronization // introduce these checks as a post processing step? Especially the database consistency check, as that is often recreated from the index files. // TODO This tool shouldn't handle it, but for convenience, it should support making the seperate call to the regular Duplicati on the destination backend, which alread carries this functionality. - // Forcefully synchronize the remote backends private static async Task<(long, IEnumerable)> CopyAsync(IStreamingBackend b_src, IStreamingBackend b_dst, IEnumerable files, bool dry_run, bool verify) { long successful_copies = 0; @@ -377,7 +400,7 @@ namespace RemoteSynchronization } catch (Exception e) { - Console.WriteLine($"Error renaming {f.Name}: {e.Message}"); + Console.WriteLine($"Error during renaming of {f.Name}: {e.Message}"); } } return successful_renames; @@ -411,7 +434,7 @@ namespace RemoteSynchronization catch (Exception e) { errors.Add(f); - Console.WriteLine($"Error verifying {f.Name}: {e.Message}"); + Console.WriteLine($"Error during verification of {f.Name}: {e.Message}"); } }