From 8e25c6e2abda796ea20d8b2700ceebfbf2426edd Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Fri, 26 Apr 2024 14:32:41 +0200 Subject: [PATCH] Reduced dynamic scanning with static linking. Cleaned up some `proj` files. Added caching to options. --- ...Duplicati.CommandLine.BackendTester.csproj | 35 ++--- .../Duplicati.CommandLine.BackendTool.csproj | 15 +- .../CLI/Duplicati.CommandLine.csproj | 48 ++----- .../Duplicati.CommandLine.RecoveryTool.csproj | 19 +-- .../Duplicati.GUI.TrayIcon.csproj | 67 +++------ Duplicati/Library/Backends/BackendModules.cs | 62 +++++++++ .../Duplicati.Library.Backends.csproj | 2 + Duplicati/Library/Backends/WebModules.cs | 41 ++++++ .../Library/Compression/CompressionModules.cs | 36 +++++ .../Duplicati.Library.Compression.csproj | 1 + .../Library/DynamicLoader/BackendLoader.cs | 79 +++++------ .../DynamicLoader/CompressionLoader.cs | 59 ++++---- .../Duplicati.Library.DynamicLoader.csproj | 7 +- .../Library/DynamicLoader/DynamicLoader.cs | 131 ++++++++++++------ .../Library/DynamicLoader/EncryptionLoader.cs | 59 ++++---- .../Library/DynamicLoader/GenericLoader.cs | 48 ++++--- Duplicati/Library/DynamicLoader/WebLoader.cs | 8 +- .../Duplicati.Library.Encryption.csproj | 1 + .../Library/Encryption/EncryptionModules.cs | 36 +++++ .../Duplicati.Library.Interface.csproj | 1 + Duplicati/Library/Interface/IBackend.cs | 49 +++---- Duplicati/Library/Interface/ICompression.cs | 49 +++---- Duplicati/Library/Interface/IDynamicModule.cs | 35 +++++ Duplicati/Library/Interface/IEncryption.cs | 48 +++---- Duplicati/Library/Interface/IGenericModule.cs | 49 +++---- Duplicati/Library/Interface/IWebModule.cs | 11 +- Duplicati/Library/Main/Controller.cs | 77 +++++----- .../Main/Duplicati.Library.Main.csproj | 27 ++-- .../Duplicati.Library.Modules.Builtin.csproj | 1 + .../Library/Modules/Builtin/GenericModules.cs | 42 ++++++ Duplicati/Server/Duplicati.Server.csproj | 58 +++----- Duplicati/UnitTest/Duplicati.UnitTest.csproj | 64 +++------ Duplicati/UnitTest/RandomErrorBackend.cs | 3 +- Duplicati/UnitTest/SizeOmittingBackend.cs | 6 +- ...Duplicati.CommandLine.BackendTester.csproj | 3 +- .../Duplicati.CommandLine.BackendTool.csproj | 3 +- ...i.CommandLine.ConfigurationImporter.csproj | 3 +- .../Duplicati.CommandLine.RecoveryTool.csproj | 3 +- .../Duplicati.CommandLine.csproj | 3 +- 39 files changed, 726 insertions(+), 563 deletions(-) create mode 100644 Duplicati/Library/Backends/BackendModules.cs create mode 100644 Duplicati/Library/Backends/WebModules.cs create mode 100644 Duplicati/Library/Compression/CompressionModules.cs create mode 100644 Duplicati/Library/Encryption/EncryptionModules.cs create mode 100644 Duplicati/Library/Interface/IDynamicModule.cs create mode 100644 Duplicati/Library/Modules/Builtin/GenericModules.cs diff --git a/Duplicati/CommandLine/BackendTester/Duplicati.CommandLine.BackendTester.csproj b/Duplicati/CommandLine/BackendTester/Duplicati.CommandLine.BackendTester.csproj index 72c126e05..900907483 100644 --- a/Duplicati/CommandLine/BackendTester/Duplicati.CommandLine.BackendTester.csproj +++ b/Duplicati/CommandLine/BackendTester/Duplicati.CommandLine.BackendTester.csproj @@ -7,31 +7,16 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + diff --git a/Duplicati/CommandLine/BackendTool/Duplicati.CommandLine.BackendTool.csproj b/Duplicati/CommandLine/BackendTool/Duplicati.CommandLine.BackendTool.csproj index 60564fccf..f265daf71 100644 --- a/Duplicati/CommandLine/BackendTool/Duplicati.CommandLine.BackendTool.csproj +++ b/Duplicati/CommandLine/BackendTool/Duplicati.CommandLine.BackendTool.csproj @@ -6,17 +6,10 @@ - - - - - - - - - - - + + + + diff --git a/Duplicati/CommandLine/CLI/Duplicati.CommandLine.csproj b/Duplicati/CommandLine/CLI/Duplicati.CommandLine.csproj index 66db07b96..7b6f5b54f 100644 --- a/Duplicati/CommandLine/CLI/Duplicati.CommandLine.csproj +++ b/Duplicati/CommandLine/CLI/Duplicati.CommandLine.csproj @@ -8,41 +8,19 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj b/Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj index 5d3fc9af7..4e024910e 100644 --- a/Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj +++ b/Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj @@ -7,21 +7,10 @@ - - - - - - - - - - - - - - - + + + + diff --git a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj index 83f645575..7115fcf39 100644 --- a/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj +++ b/Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj @@ -51,52 +51,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/Duplicati/Library/Backends/BackendModules.cs b/Duplicati/Library/Backends/BackendModules.cs new file mode 100644 index 000000000..5b4029a46 --- /dev/null +++ b/Duplicati/Library/Backends/BackendModules.cs @@ -0,0 +1,62 @@ +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System.Collections.Generic; +using Duplicati.Library.Interface; + +namespace Duplicati.Library.Backends; + +public static class BackendModules +{ + /// + /// The list of all built-in backend modules + /// + public static IReadOnlyList BuiltInBackendModules => [ + new Backend.AliyunOSS.OSS(), + new Backend.AlternativeFTP.AlternativeFtpBackend(), + new Backend.AzureBlob.AzureBlobBackend(), + new Backend.Backblaze.B2(), + new Backend.Box.BoxBackend(), + new Backend.CloudFiles(), + new Backend.Dropbox(), + new Backend.FTP(), + new Backend.File(), + new Backend.GoogleCloudStorage.GoogleCloudStorage(), + new Backend.GoogleDrive.GoogleDrive(), + new Backend.Idrivee2Backend(), + new Backend.Jottacloud(), + new Backend.Mega.MegaBackend(), + new Backend.MicrosoftGroup(), + new Backend.OneDriveV2(), + new Backend.OpenStack.OpenStackStorage(), + new Backend.Rclone(), + new Backend.S3(), + new Backend.SSHv2(), + new Backend.OneDriveForBusinessBackend(), + new Backend.SharePointBackend(), + new Backend.SharePointV2(), + new Backend.Sia.Sia(), + new Backend.Storj.Storj(), + new Backend.TahoeBackend(), + new Backend.TencentCOS.COS(), + new Backend.WEBDAV() + ]; +} diff --git a/Duplicati/Library/Backends/Duplicati.Library.Backends.csproj b/Duplicati/Library/Backends/Duplicati.Library.Backends.csproj index e62ce2ac6..b5b6ef7d4 100644 --- a/Duplicati/Library/Backends/Duplicati.Library.Backends.csproj +++ b/Duplicati/Library/Backends/Duplicati.Library.Backends.csproj @@ -2,6 +2,7 @@ net8.0 Central reference to all backends + Duplicati.Library.Backend @@ -28,5 +29,6 @@ + \ No newline at end of file diff --git a/Duplicati/Library/Backends/WebModules.cs b/Duplicati/Library/Backends/WebModules.cs new file mode 100644 index 000000000..7f20db18c --- /dev/null +++ b/Duplicati/Library/Backends/WebModules.cs @@ -0,0 +1,41 @@ +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System.Collections.Generic; +using Duplicati.Library.Interface; + +namespace Duplicati.Library.Backend; + +public static class WebModules +{ + /// + /// The list of all built-in web modules + /// + public static IReadOnlyList BuiltInWebModules => [ + new GoogleServices.GCSConfig(), + new OpenStack.SwiftConfig(), + new S3Config(), + new S3IAM(), + new KeyGenerator(), + new KeyUploader(), + new Storj.StorjConfig(), + ]; +} diff --git a/Duplicati/Library/Compression/CompressionModules.cs b/Duplicati/Library/Compression/CompressionModules.cs new file mode 100644 index 000000000..8504dafed --- /dev/null +++ b/Duplicati/Library/Compression/CompressionModules.cs @@ -0,0 +1,36 @@ +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System.Collections.Generic; +using Duplicati.Library.Interface; + +namespace Duplicati.Library.Compression; + +public static class CompressionModules +{ + /// + /// The list of all built-in compression modules + /// + public static IReadOnlyList BuiltInCompressionModules => [ + new FileArchiveZip(), + new SevenZipCompression() + ]; +} diff --git a/Duplicati/Library/Compression/Duplicati.Library.Compression.csproj b/Duplicati/Library/Compression/Duplicati.Library.Compression.csproj index bc4f4cb60..93b74c746 100644 --- a/Duplicati/Library/Compression/Duplicati.Library.Compression.csproj +++ b/Duplicati/Library/Compression/Duplicati.Library.Compression.csproj @@ -3,6 +3,7 @@ net8.0 Library + Duplicati.Library.Compression diff --git a/Duplicati/Library/DynamicLoader/BackendLoader.cs b/Duplicati/Library/DynamicLoader/BackendLoader.cs index aaf391073..592bb9706 100644 --- a/Duplicati/Library/DynamicLoader/BackendLoader.cs +++ b/Duplicati/Library/DynamicLoader/BackendLoader.cs @@ -1,32 +1,30 @@ -// Copyright (C) 2024, The Duplicati Team -// https://duplicati.com, hello@duplicati.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; -using System.Text; using Duplicati.Library.Interface; -using System.Collections.Specialized; -using System.Web; using System.Linq; using System.Runtime.ExceptionServices; +using Duplicati.Library.Backends; namespace Duplicati.Library.DynamicLoader { @@ -53,10 +51,12 @@ namespace Duplicati.Library.DynamicLoader /// /// Returns the subfolders searched for backends /// - protected override string[] Subfolders - { - get { return new string[] {"backends"}; } - } + protected override string[] Subfolders => ["backends"]; + + /// + /// The built-in modules + /// + protected override IEnumerable BuiltInModules => BackendModules.BuiltInBackendModules; /// /// Instanciates a specific backend, given the url and options @@ -67,9 +67,9 @@ namespace Duplicati.Library.DynamicLoader public IBackend GetBackend(string url, Dictionary options) { var uri = new Utility.Uri(url); - + LoadInterfaces(); - + var newOpts = new Dictionary(options); foreach (var key in uri.QueryParameters.AllKeys) newOpts[key] = uri.QueryParameters[key]; @@ -108,7 +108,7 @@ namespace Duplicati.Library.DynamicLoader throw; } - + return null; } } @@ -118,27 +118,28 @@ namespace Duplicati.Library.DynamicLoader /// /// The url to find commands for /// The supported commands or null if the url scheme was not supported - public IList GetSupportedCommands(string url) + public IReadOnlyList GetSupportedCommands(string url) { var uri = new Utility.Uri(url); LoadInterfaces(); + // TODO: The loading logic is replicated in the "GetBackend" method, should be refactored lock (m_lock) { IBackend b; if (m_interfaces.TryGetValue(uri.Scheme, out b) && b != null) - return b.SupportedCommands; + return GetSupportedCommandsCached(b).ToList(); else if (uri.Scheme.EndsWith("s", StringComparison.Ordinal)) { var tmpscheme = uri.Scheme.Substring(0, uri.Scheme.Length - 1); - if (m_interfaces.ContainsKey(tmpscheme)) - return m_interfaces[tmpscheme].SupportedCommands; + if (m_interfaces.TryGetValue(tmpscheme, out b) && b != null) + return GetSupportedCommandsCached(b).ToList(); } - + return null; } - } + } } /// @@ -152,18 +153,18 @@ namespace Duplicati.Library.DynamicLoader /// Gets a list of loaded backends, the instances can be used to extract interface information, not used to interact with the backend. /// public static IBackend[] Backends { get { return _backendLoader.Interfaces; } } - + /// /// Gets a list of keys supported /// public static string[] Keys { get { return _backendLoader.Keys; } } - + /// /// Gets the supported commands for a given backend /// /// The url to find the commands for /// The supported commands or null if the url is not supported - public static IList GetSupportedCommands(string url) + public static IReadOnlyList GetSupportedCommands(string url) { if (string.IsNullOrEmpty(url)) throw new ArgumentNullException(nameof(url)); diff --git a/Duplicati/Library/DynamicLoader/CompressionLoader.cs b/Duplicati/Library/DynamicLoader/CompressionLoader.cs index e8df01329..7d14916bd 100644 --- a/Duplicati/Library/DynamicLoader/CompressionLoader.cs +++ b/Duplicati/Library/DynamicLoader/CompressionLoader.cs @@ -1,28 +1,29 @@ -// Copyright (C) 2024, The Duplicati Team -// https://duplicati.com, hello@duplicati.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; using System.IO; -using System.Text; +using System.Linq; +using Duplicati.Library.Compression; using Duplicati.Library.Interface; namespace Duplicati.Library.DynamicLoader @@ -50,10 +51,12 @@ namespace Duplicati.Library.DynamicLoader /// /// Returns the subfolders searched for compression modules /// - protected override string[] Subfolders - { - get { return new string[] { "compression" }; } - } + protected override string[] Subfolders => ["compression"]; + + /// + /// The built-in modules + /// + protected override IEnumerable BuiltInModules => CompressionModules.BuiltInCompressionModules; /// /// Instanciates a specific compression module, given the file extension and options @@ -84,7 +87,7 @@ namespace Duplicati.Library.DynamicLoader /// /// The key to find commands for /// The supported commands or null if the key was not found - public IList GetSupportedCommands(string key) + public IReadOnlyList GetSupportedCommands(string key) { if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key)); @@ -95,7 +98,7 @@ namespace Duplicati.Library.DynamicLoader { ICompression b; if (m_interfaces.TryGetValue(key, out b) && b != null) - return b.SupportedCommands; + return GetSupportedCommandsCached(b).ToList(); else return null; } @@ -124,7 +127,7 @@ namespace Duplicati.Library.DynamicLoader /// /// The compression module to find the commands for /// The supported commands or null if the key is not supported - public static IList GetSupportedCommands(string key) + public static IReadOnlyList GetSupportedCommands(string key) { return _compressionLoader.GetSupportedCommands(key); } diff --git a/Duplicati/Library/DynamicLoader/Duplicati.Library.DynamicLoader.csproj b/Duplicati/Library/DynamicLoader/Duplicati.Library.DynamicLoader.csproj index 8d2fac9c0..897783392 100644 --- a/Duplicati/Library/DynamicLoader/Duplicati.Library.DynamicLoader.csproj +++ b/Duplicati/Library/DynamicLoader/Duplicati.Library.DynamicLoader.csproj @@ -5,11 +5,16 @@ Library - + + + + + + diff --git a/Duplicati/Library/DynamicLoader/DynamicLoader.cs b/Duplicati/Library/DynamicLoader/DynamicLoader.cs index d345b27bb..4a6e8d4ee 100644 --- a/Duplicati/Library/DynamicLoader/DynamicLoader.cs +++ b/Duplicati/Library/DynamicLoader/DynamicLoader.cs @@ -1,28 +1,31 @@ -// Copyright (C) 2024, The Duplicati Team -// https://duplicati.com, hello@duplicati.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Reflection; -using System.Text; +using Duplicati.Library.AutoUpdater; +using Duplicati.Library.Interface; namespace Duplicati.Library.DynamicLoader { @@ -30,7 +33,7 @@ namespace Duplicati.Library.DynamicLoader /// This class supports dynamic loading of instances of a given interface /// /// The interface that the class loads - internal abstract class DynamicLoader where T : class + internal abstract class DynamicLoader where T : class, IDynamicModule { /// /// The tag used for logging @@ -47,6 +50,11 @@ namespace Duplicati.Library.DynamicLoader /// protected Dictionary m_interfaces; + /// + /// List of supported commands + /// + protected Dictionary> m_supportedCommands = new(); + /// /// Function to extract the key value from the interface /// @@ -59,6 +67,11 @@ namespace Duplicati.Library.DynamicLoader /// protected abstract string[] Subfolders { get; } + /// + /// The list of statically included modules + /// + protected abstract IEnumerable BuiltInModules { get; } + /// /// Construct a new instance of the dynamic loader, /// does not load anything @@ -76,10 +89,14 @@ namespace Duplicati.Library.DynamicLoader lock (m_lock) if (m_interfaces == null) { - Dictionary interfaces = new Dictionary(); - //When loading, the subfolder matches are places last in the + var interfaces = new Dictionary(); + // When loading, inject the built-ins first, so they can be replaced by subfolder matches + foreach (T b in BuiltInModules) + interfaces[GetInterfaceKey(b)] = b; + + // When loading, the subfolder matches are placed last in the // resulting list, and thus applied last to the lookup, - // meaning that they can replace the stock versions + // meaning that they can replace the built-in versions foreach (T b in FindInterfaceImplementors(Subfolders)) interfaces[GetInterfaceKey(b)] = b; @@ -93,22 +110,34 @@ namespace Duplicati.Library.DynamicLoader /// /// Any additional folders besides the assembly path to search in /// A list of instanciated classes which implements the interface - private List FindInterfaceImplementors(string[] additionalfolders) + private IEnumerable FindInterfaceImplementors(string[] additionalfolders) { - List interfaces = new List(); + var interfaces = new List(); - string path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); - List files = new List(); - files.AddRange(System.IO.Directory.GetFiles(path, "*.dll")); + // Search in these folders for modules + var root_paths = new[] { + Path.Combine(UpdaterManager.INSTALLATIONDIR, "modules"), + Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) ?? string.Empty, + AutoUpdateSettings.AppName, + "modules" + ), + Environment.GetEnvironmentVariable($"{AutoUpdateSettings.AppName}_MODULE_PATH") + } + .Where(x => !string.IsNullOrEmpty(x) && Directory.Exists(x)); - //We can override with subfolders - if (additionalfolders != null) - foreach (string s in additionalfolders) - { - string subpath = System.IO.Path.Combine(path, s); - if (System.IO.Directory.Exists(subpath)) - files.AddRange(System.IO.Directory.GetFiles(subpath, "*.dll")); - } + // In each folder we look, search only in the subfolders containing the modules + var files = new List(); + foreach (var path in root_paths) + { + if (additionalfolders != null) + foreach (string s in additionalfolders) + { + string subpath = System.IO.Path.Combine(path, s); + if (System.IO.Directory.Exists(subpath)) + files.AddRange(System.IO.Directory.GetFiles(subpath, "*.dll")); + } + } foreach (string s in files) { @@ -119,8 +148,8 @@ namespace Duplicati.Library.DynamicLoader //Since the lookup dictionary applies the modules in the order returned // and the subfolders are probed last, a module in the subfolder // will take the place of a stock module, if both use same key - System.Reflection.Assembly asm = System.Reflection.Assembly.LoadFile(s); - if (asm != System.Reflection.Assembly.GetExecutingAssembly()) + Assembly asm = Assembly.LoadFile(s); + if (asm != Assembly.GetExecutingAssembly()) { foreach (Type t in asm.GetExportedTypes()) try @@ -143,8 +172,8 @@ namespace Duplicati.Library.DynamicLoader } } } - catch(Exception ex) - { + catch (Exception ex) + { ex = GetActualException(ex); // Since this is locating the assemblies that have the proper interface, it isn't an error to not. // This was loading the log with errors about additional DLL's that are not plugins and do not have manifests. @@ -170,7 +199,7 @@ namespace Duplicati.Library.DynamicLoader get { LoadInterfaces(); - lock(m_lock) + lock (m_lock) return new List(m_interfaces.Values).ToArray(); } } @@ -188,5 +217,21 @@ namespace Duplicati.Library.DynamicLoader } } + /// + /// Returns the supported commands from the item, applying caching + /// + /// The item to get the supported commands for + /// The list of supported commands + protected IEnumerable GetSupportedCommandsCached(T item) + { + var type = item.GetType(); + lock (m_lock) + { + if (m_supportedCommands.TryGetValue(type, out var commands)) + return commands; + + return m_supportedCommands[type] = item.SupportedCommands.ToList().AsReadOnly(); + } + } } } diff --git a/Duplicati/Library/DynamicLoader/EncryptionLoader.cs b/Duplicati/Library/DynamicLoader/EncryptionLoader.cs index 34872b7ad..4c5cf7af2 100644 --- a/Duplicati/Library/DynamicLoader/EncryptionLoader.cs +++ b/Duplicati/Library/DynamicLoader/EncryptionLoader.cs @@ -1,27 +1,28 @@ -// Copyright (C) 2024, The Duplicati Team -// https://duplicati.com, hello@duplicati.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; -using System.Text; +using System.Linq; +using Duplicati.Library.Encryption; using Duplicati.Library.Interface; namespace Duplicati.Library.DynamicLoader @@ -49,10 +50,12 @@ namespace Duplicati.Library.DynamicLoader /// /// Returns the subfolders searched for encryption modules /// - protected override string[] Subfolders - { - get { return new string[] { "encryption" }; } - } + protected override string[] Subfolders => ["encryption"]; + + /// + /// The built-in modules + /// + protected override IEnumerable BuiltInModules => EncryptionModules.BuiltInEncryptionModules; /// /// Instanciates a specific encryption module, given the file extension and options @@ -82,7 +85,7 @@ namespace Duplicati.Library.DynamicLoader /// /// The key to find commands for /// The supported commands or null if the key was not found - public IList GetSupportedCommands(string key) + public IReadOnlyList GetSupportedCommands(string key) { if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key)); @@ -93,7 +96,7 @@ namespace Duplicati.Library.DynamicLoader { IEncryption b; if (m_interfaces.TryGetValue(key, out b) && b != null) - return b.SupportedCommands; + return GetSupportedCommandsCached(b).ToList(); else return null; } @@ -122,7 +125,7 @@ namespace Duplicati.Library.DynamicLoader /// /// The encryption module to find the commands for /// The supported commands or null if the key is not supported - public static IList GetSupportedCommands(string key) + public static IReadOnlyList GetSupportedCommands(string key) { return _encryptionLoader.GetSupportedCommands(key); } diff --git a/Duplicati/Library/DynamicLoader/GenericLoader.cs b/Duplicati/Library/DynamicLoader/GenericLoader.cs index b5dbe2460..f4fbc95c9 100644 --- a/Duplicati/Library/DynamicLoader/GenericLoader.cs +++ b/Duplicati/Library/DynamicLoader/GenericLoader.cs @@ -1,28 +1,27 @@ -// Copyright (C) 2024, The Duplicati Team -// https://duplicati.com, hello@duplicati.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. -using System; using System.Collections.Generic; -using System.Text; using Duplicati.Library.Interface; +using Duplicati.Library.Modules.Builtin; namespace Duplicati.Library.DynamicLoader { @@ -53,6 +52,11 @@ namespace Duplicati.Library.DynamicLoader { get { return new string[] { "modules" }; } } + + /// + /// The built-in modules + /// + protected override IEnumerable BuiltInModules => GenericModules.BuiltInGenericModules; } #region Public static API diff --git a/Duplicati/Library/DynamicLoader/WebLoader.cs b/Duplicati/Library/DynamicLoader/WebLoader.cs index 3e5c5b874..05dd639bd 100644 --- a/Duplicati/Library/DynamicLoader/WebLoader.cs +++ b/Duplicati/Library/DynamicLoader/WebLoader.cs @@ -19,9 +19,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using System; using System.Collections.Generic; -using System.Text; +using Duplicati.Library.Backend; using Duplicati.Library.Interface; namespace Duplicati.Library.DynamicLoader @@ -50,6 +49,11 @@ namespace Duplicati.Library.DynamicLoader { get { return new string[] { "webmodules" }; } } + + /// + /// The built-in modules + /// + override protected IEnumerable BuiltInModules => WebModules.BuiltInWebModules; } #region Public static API diff --git a/Duplicati/Library/Encryption/Duplicati.Library.Encryption.csproj b/Duplicati/Library/Encryption/Duplicati.Library.Encryption.csproj index 12cdf35f5..41494f4f5 100644 --- a/Duplicati/Library/Encryption/Duplicati.Library.Encryption.csproj +++ b/Duplicati/Library/Encryption/Duplicati.Library.Encryption.csproj @@ -3,6 +3,7 @@ net8.0 Library + Duplicati.Library.Encryption diff --git a/Duplicati/Library/Encryption/EncryptionModules.cs b/Duplicati/Library/Encryption/EncryptionModules.cs new file mode 100644 index 000000000..a04327939 --- /dev/null +++ b/Duplicati/Library/Encryption/EncryptionModules.cs @@ -0,0 +1,36 @@ +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System.Collections.Generic; +using Duplicati.Library.Interface; + +namespace Duplicati.Library.Encryption; + +public static class EncryptionModules +{ + /// + /// The list of all built-in encryption modules + /// + public static IReadOnlyList BuiltInEncryptionModules => [ + new AESEncryption(), + new GPGEncryption() + ]; +} diff --git a/Duplicati/Library/Interface/Duplicati.Library.Interface.csproj b/Duplicati/Library/Interface/Duplicati.Library.Interface.csproj index 7fbac15eb..fc0bf10ad 100644 --- a/Duplicati/Library/Interface/Duplicati.Library.Interface.csproj +++ b/Duplicati/Library/Interface/Duplicati.Library.Interface.csproj @@ -3,6 +3,7 @@ net8.0 Library + Duplicati.Library.Interface diff --git a/Duplicati/Library/Interface/IBackend.cs b/Duplicati/Library/Interface/IBackend.cs index 75d6f1f5e..24476f78a 100644 --- a/Duplicati/Library/Interface/IBackend.cs +++ b/Duplicati/Library/Interface/IBackend.cs @@ -1,23 +1,23 @@ -// Copyright (C) 2024, The Duplicati Team -// https://duplicati.com, hello@duplicati.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; @@ -36,12 +36,12 @@ namespace Duplicati.Library.Interface /// The other constructor is used to do the actual work. /// An instance is never reused. /// - public interface IBackend : IDisposable + public interface IBackend : IDynamicModule, IDisposable { /// /// The localized name to display for this backend /// - string DisplayName { get;} + string DisplayName { get; } /// /// The protocol key, eg. ftp, http or ssh @@ -75,11 +75,6 @@ namespace Duplicati.Library.Interface /// The remote filename, relative to the URL void Delete(string remotename); - /// - /// Gets a list of supported commandline arguments - /// - IList SupportedCommands { get; } - /// /// A localized description of the backend, for display in the usage information /// diff --git a/Duplicati/Library/Interface/ICompression.cs b/Duplicati/Library/Interface/ICompression.cs index 1a331a358..2d2a87139 100644 --- a/Duplicati/Library/Interface/ICompression.cs +++ b/Duplicati/Library/Interface/ICompression.cs @@ -1,28 +1,26 @@ -// Copyright (C) 2024, The Duplicati Team -// https://duplicati.com, hello@duplicati.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; -using System.IO; -using System.Text; namespace Duplicati.Library.Interface { @@ -143,7 +141,7 @@ namespace Duplicati.Library.Interface /// The other constructor is used to do the actual work. /// The input file may not exist or have zero length, in which case it should be created. /// - public interface ICompression : IDisposable, IArchiveReader, IArchiveWriter + public interface ICompression : IDynamicModule, IDisposable, IArchiveReader, IArchiveWriter { /// /// The total size of the archive. @@ -164,10 +162,5 @@ namespace Duplicati.Library.Interface /// A localized description of the compression module /// string Description { get; } - - /// - /// Gets a list of supported commandline arguments - /// - IList SupportedCommands { get; } } } diff --git a/Duplicati/Library/Interface/IDynamicModule.cs b/Duplicati/Library/Interface/IDynamicModule.cs new file mode 100644 index 000000000..c38cf4d4d --- /dev/null +++ b/Duplicati/Library/Interface/IDynamicModule.cs @@ -0,0 +1,35 @@ +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System.Collections.Generic; + +namespace Duplicati.Library.Interface; + +/// +/// Common interface for dynamic modules +/// +public interface IDynamicModule +{ + /// + /// Gets a list of supported commandline arguments + /// + IList SupportedCommands { get; } +} diff --git a/Duplicati/Library/Interface/IEncryption.cs b/Duplicati/Library/Interface/IEncryption.cs index cdde76121..422900082 100644 --- a/Duplicati/Library/Interface/IEncryption.cs +++ b/Duplicati/Library/Interface/IEncryption.cs @@ -1,27 +1,26 @@ -// Copyright (C) 2024, The Duplicati Team -// https://duplicati.com, hello@duplicati.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; -using System.Text; using System.IO; namespace Duplicati.Library.Interface @@ -37,7 +36,7 @@ namespace Duplicati.Library.Interface /// The other constructor is used to do the actual work. /// An instance can be used to encrypt or decrypt multiple files/streams. /// - public interface IEncryption : IDisposable + public interface IEncryption : IDynamicModule, IDisposable { /// /// Encrypts the contents of the inputfile, and saves the result as the outputfile. @@ -96,11 +95,6 @@ namespace Duplicati.Library.Interface /// string Description { get; } - /// - /// Gets a list of supported commandline arguments - /// - IList SupportedCommands { get; } - /// /// Returns the size in bytes of the overhead that will be added to a file of the given size when encrypted /// diff --git a/Duplicati/Library/Interface/IGenericModule.cs b/Duplicati/Library/Interface/IGenericModule.cs index d24f7f99c..c29444d4d 100644 --- a/Duplicati/Library/Interface/IGenericModule.cs +++ b/Duplicati/Library/Interface/IGenericModule.cs @@ -1,27 +1,25 @@ -// Copyright (C) 2024, The Duplicati Team -// https://duplicati.com, hello@duplicati.com -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. -using System; using System.Collections.Generic; -using System.Text; namespace Duplicati.Library.Interface { @@ -36,7 +34,7 @@ namespace Duplicati.Library.Interface /// All instances where the Configure method is called will be disposed, /// if they implement the IDisposable interface as well. /// - public interface IGenericModule + public interface IGenericModule : IDynamicModule { /// /// The module key, used to activate or deactivate the module on the commandline @@ -60,11 +58,6 @@ namespace Duplicati.Library.Interface /// bool LoadAsDefault { get; } - /// - /// Gets a list of supported commandline arguments - /// - IList SupportedCommands { get; } - /// /// This method is the interception where the module can interact with the execution environment and modify the settings. /// diff --git a/Duplicati/Library/Interface/IWebModule.cs b/Duplicati/Library/Interface/IWebModule.cs index 0208f122f..2af3f4c25 100644 --- a/Duplicati/Library/Interface/IWebModule.cs +++ b/Duplicati/Library/Interface/IWebModule.cs @@ -24,7 +24,7 @@ using System.Collections.Generic; namespace Duplicati.Library.Interface { - public interface IWebModule + public interface IWebModule : IDynamicModule { /// /// The module key, used to activate or deactivate the module on the commandline @@ -40,19 +40,14 @@ namespace Duplicati.Library.Interface /// A localized description of the module /// string Description { get; } - - /// - /// Gets a list of supported commandline arguments - /// - IList SupportedCommands { get; } - + /// /// Execute the specified command with the given options. /// /// The options to use /// A list of output values IDictionary Execute(IDictionary options); - + } } diff --git a/Duplicati/Library/Main/Controller.cs b/Duplicati/Library/Main/Controller.cs index 020e52e07..b2c93204c 100644 --- a/Duplicati/Library/Main/Controller.cs +++ b/Duplicati/Library/Main/Controller.cs @@ -123,7 +123,8 @@ namespace Duplicati.Library.Main CheckAutoCompactInterval(); CheckAutoVacuumInterval(); - return RunAction(new BackupResults(), ref inputsources, ref filter, (result) => { + return RunAction(new BackupResults(), ref inputsources, ref filter, (result) => + { using (var h = new Operation.BackupHandler(m_backend, m_options, result)) { @@ -138,7 +139,8 @@ namespace Duplicati.Library.Main public Library.Interface.IRestoreResults Restore(string[] paths, Library.Utility.IFilter filter = null) { - return RunAction(new RestoreResults(), ref paths, ref filter, (result) => { + return RunAction(new RestoreResults(), ref paths, ref filter, (result) => + { new Operation.RestoreHandler(m_backend, m_options, result).Run(paths, filter); Library.UsageReporter.Reporter.Report("RESTORE_FILECOUNT", result.RestoredFiles); @@ -149,21 +151,24 @@ namespace Duplicati.Library.Main public Duplicati.Library.Interface.IRestoreControlFilesResults RestoreControlFiles(IEnumerable files = null, Library.Utility.IFilter filter = null) { - return RunAction(new RestoreControlFilesResults(), ref filter, (result) => { + return RunAction(new RestoreControlFilesResults(), ref filter, (result) => + { new Operation.RestoreControlFilesHandler(m_backend, m_options, result).Run(files, filter); }); } public Duplicati.Library.Interface.IDeleteResults Delete() { - return RunAction(new DeleteResults(), (result) => { + return RunAction(new DeleteResults(), (result) => + { new Operation.DeleteHandler(m_backend, m_options, result).Run(); }); } public Duplicati.Library.Interface.IRepairResults Repair(Library.Utility.IFilter filter = null) { - return RunAction(new RepairResults(), ref filter, (result) => { + return RunAction(new RepairResults(), ref filter, (result) => + { new Operation.RepairHandler(m_backend, m_options, result).Run(filter); }); } @@ -180,14 +185,16 @@ namespace Duplicati.Library.Main public Duplicati.Library.Interface.IListResults List(IEnumerable filterstrings, Library.Utility.IFilter filter) { - return RunAction(new ListResults(), ref filter, (result) => { + return RunAction(new ListResults(), ref filter, (result) => + { new Operation.ListFilesHandler(m_backend, m_options, result).Run(filterstrings, filter); }); } public Duplicati.Library.Interface.IListResults ListControlFiles(IEnumerable filterstrings, Library.Utility.IFilter filter) { - return RunAction(new ListResults(), ref filter, (result) => { + return RunAction(new ListResults(), ref filter, (result) => + { new Operation.ListControlFilesHandler(m_backend, m_options, result).Run(filterstrings, filter); }); } @@ -254,7 +261,8 @@ namespace Duplicati.Library.Main { CheckAutoVacuumInterval(); - return RunAction(new CompactResults(), (result) => { + return RunAction(new CompactResults(), (result) => + { new Operation.CompactHandler(m_backend, m_options, result).Run(); }); } @@ -263,8 +271,9 @@ namespace Duplicati.Library.Main { var filelistfilter = Operation.RestoreHandler.FilterNumberedFilelist(m_options.Time, m_options.Version, singleTimeMatch: true); - return RunAction(new RecreateDatabaseResults(), ref filter, (result) => { - using(var h = new Operation.RecreateDatabaseHandler(m_backend, m_options, result)) + return RunAction(new RecreateDatabaseResults(), ref filter, (result) => + { + using (var h = new Operation.RecreateDatabaseHandler(m_backend, m_options, result)) h.RunUpdate(filter, filelistfilter); }); } @@ -273,7 +282,8 @@ namespace Duplicati.Library.Main { var t = new string[] { targetpath }; - return RunAction(new CreateLogDatabaseResults(), ref t, (result) => { + return RunAction(new CreateLogDatabaseResults(), ref t, (result) => + { new Operation.CreateBugReportHandler(t[0], m_options, result).Run(); }); } @@ -282,14 +292,16 @@ namespace Duplicati.Library.Main { var t = new string[] { baseVersion, targetVersion }; - return RunAction(new ListChangesResults(), ref t, ref filter, (result) => { + return RunAction(new ListChangesResults(), ref t, ref filter, (result) => + { new Operation.ListChangesHandler(m_backend, m_options, result).Run(t[0], t[1], filterstrings, filter, callback); }); } public Duplicati.Library.Interface.IListAffectedResults ListAffected(List args, Action callback = null) { - return RunAction(new ListAffectedResults(), (result) => { + return RunAction(new ListAffectedResults(), (result) => + { new Operation.ListAffected(m_options, result).Run(args, callback); }); } @@ -298,8 +310,9 @@ namespace Duplicati.Library.Main { if (!m_options.RawOptions.ContainsKey("full-remote-verification")) m_options.RawOptions["full-remote-verification"] = "true"; - - return RunAction(new TestResults(), (result) => { + + return RunAction(new TestResults(), (result) => + { new Operation.TestHandler(m_backend, m_options, result).Run(samples); }); } @@ -322,7 +335,8 @@ namespace Duplicati.Library.Main public Library.Interface.ISystemInfoResults SystemInfo() { - return RunAction(new SystemInfoResults(), result => { + return RunAction(new SystemInfoResults(), result => + { Operation.SystemInfoHandler.Run(result); }); } @@ -368,7 +382,7 @@ namespace Duplicati.Library.Main ) .Select(x => x.Key) ); - + /// Forward all messages from the email module to the message sink var filtertag = Logging.Log.LogTagFromType(); using (Logging.Log.StartScope(m_messageSink.WriteMessage, x => x.FilterTag.Contains(filtertag))) @@ -383,7 +397,8 @@ namespace Duplicati.Library.Main public Library.Interface.IVacuumResults Vacuum() { - return RunAction(new VacuumResults(), result => { + return RunAction(new VacuumResults(), result => + { new Operation.VacuumHandler(m_options, result).Run(); }); } @@ -429,14 +444,14 @@ namespace Duplicati.Library.Main using (new ProcessController(m_options)) using (new Logging.Timer(LOGTAG, string.Format("Run{0}", result.MainOperation), string.Format("Running {0}", result.MainOperation))) - using(new CoCoL.IsolatedChannelScope()) - using(m_options.ConcurrencyMaxThreads <= 0 ? null : new CoCoL.CappedThreadedThreadPool(m_options.ConcurrencyMaxThreads)) + using (new CoCoL.IsolatedChannelScope()) + using (m_options.ConcurrencyMaxThreads <= 0 ? null : new CoCoL.CappedThreadedThreadPool(m_options.ConcurrencyMaxThreads)) method(result); if (result.EndTime.Ticks == 0) result.EndTime = DateTime.UtcNow; result.SetDatabase(null); - if(result is BasicResults r) + if (result is BasicResults r) { r.Interrupted = false; } @@ -611,7 +626,7 @@ namespace Duplicati.Library.Main // Make the filter read-n-write able in the generic modules var pristinefilter = string.Join(System.IO.Path.PathSeparator.ToString(), FilterExpression.Serialize(filter)); m_options.RawOptions["filter"] = pristinefilter; - + // Store the URL connection options separately, as these should only be visible to modules implementing IConnectionModule var conopts = new Dictionary(m_options.RawOptions); var qp = new Library.Utility.Uri(m_backend).QueryParameters; @@ -792,11 +807,11 @@ namespace Duplicati.Library.Main // Throw url-encoded options into the mix //TODO: This can hide values if both commandline and url-parameters supply the same key var ext = new Library.Utility.Uri(m_backend).QueryParameters; - foreach(var k in ext.AllKeys) + foreach (var k in ext.AllKeys) ropts[k] = ext[k]; //Now run through all supported options, and look for deprecated options - foreach (IList l in new IList[] { + foreach (var l in new IEnumerable[] { m_options.SupportedCommands, DynamicLoader.BackendLoader.GetSupportedCommands(m_backend), m_options.NoEncryption ? null : DynamicLoader.EncryptionLoader.GetSupportedCommands(m_options.EncryptionModule), @@ -872,12 +887,12 @@ namespace Duplicati.Library.Main //TODO: Based on the action, see if all options are relevant } - /// - /// Helper method that expands the users chosen source input paths, - /// and removes duplicate paths - /// - /// The expanded and filtered sources. - private string[] ExpandInputSources(string[] inputsources, IFilter filter) + /// + /// Helper method that expands the users chosen source input paths, + /// and removes duplicate paths + /// + /// The expanded and filtered sources. + private string[] ExpandInputSources(string[] inputsources, IFilter filter) { if (inputsources == null || inputsources.Length == 0) throw new Duplicati.Library.Interface.UserInformationException(Strings.Controller.NoSourceFoldersError, "NoSourceFolders"); @@ -1061,7 +1076,7 @@ namespace Duplicati.Library.Main else if (arg.Type == Duplicati.Library.Interface.CommandLineArgument.ArgumentType.Flags) { bool validatedAllFlags = false; - var flags = (value ?? string.Empty).ToLowerInvariant().Split(new[] {","}, StringSplitOptions.None).Select(flag => flag.Trim()).Distinct(); + var flags = (value ?? string.Empty).ToLowerInvariant().Split(new[] { "," }, StringSplitOptions.None).Select(flag => flag.Trim()).Distinct(); var validFlags = arg.ValidValues ?? new string[0]; foreach (var flag in flags) diff --git a/Duplicati/Library/Main/Duplicati.Library.Main.csproj b/Duplicati/Library/Main/Duplicati.Library.Main.csproj index 725c9a43c..515d612e8 100644 --- a/Duplicati/Library/Main/Duplicati.Library.Main.csproj +++ b/Duplicati/Library/Main/Duplicati.Library.Main.csproj @@ -8,24 +8,15 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/Duplicati/Library/Modules/Builtin/Duplicati.Library.Modules.Builtin.csproj b/Duplicati/Library/Modules/Builtin/Duplicati.Library.Modules.Builtin.csproj index e2f8ad4a8..4a27be489 100644 --- a/Duplicati/Library/Modules/Builtin/Duplicati.Library.Modules.Builtin.csproj +++ b/Duplicati/Library/Modules/Builtin/Duplicati.Library.Modules.Builtin.csproj @@ -3,6 +3,7 @@ net8.0 Library + Duplicati.Library.Modules.Builtin diff --git a/Duplicati/Library/Modules/Builtin/GenericModules.cs b/Duplicati/Library/Modules/Builtin/GenericModules.cs new file mode 100644 index 000000000..f7d3a1807 --- /dev/null +++ b/Duplicati/Library/Modules/Builtin/GenericModules.cs @@ -0,0 +1,42 @@ +// Copyright (C) 2024, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System.Collections.Generic; +using Duplicati.Library.Interface; + +namespace Duplicati.Library.Modules.Builtin; + +public static class GenericModules +{ + /// + /// The list of all built-in generic modules + /// + public static IReadOnlyList BuiltInGenericModules => [ + new ConsolePasswordInput(), + new HttpOptions(), + new HyperVOptions(), + new MSSQLOptions(), + new RunScript(), + new SendHttpMessage(), + new SendJabberMessage(), + new SendMail(), + ]; +} diff --git a/Duplicati/Server/Duplicati.Server.csproj b/Duplicati/Server/Duplicati.Server.csproj index 60418e880..256182eb9 100644 --- a/Duplicati/Server/Duplicati.Server.csproj +++ b/Duplicati/Server/Duplicati.Server.csproj @@ -18,48 +18,24 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + diff --git a/Duplicati/UnitTest/Duplicati.UnitTest.csproj b/Duplicati/UnitTest/Duplicati.UnitTest.csproj index 93554334a..755c3accb 100644 --- a/Duplicati/UnitTest/Duplicati.UnitTest.csproj +++ b/Duplicati/UnitTest/Duplicati.UnitTest.csproj @@ -14,51 +14,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/Duplicati/UnitTest/RandomErrorBackend.cs b/Duplicati/UnitTest/RandomErrorBackend.cs index 4d90a1941..104fb63c0 100644 --- a/Duplicati/UnitTest/RandomErrorBackend.cs +++ b/Duplicati/UnitTest/RandomErrorBackend.cs @@ -23,6 +23,7 @@ using Duplicati.Library.Interface; using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -127,7 +128,7 @@ namespace Duplicati.UnitTest get { if (m_backend == null) - try { return Duplicati.Library.DynamicLoader.BackendLoader.GetSupportedCommands(WrappedBackend + "://"); } + try { return Duplicati.Library.DynamicLoader.BackendLoader.GetSupportedCommands(WrappedBackend + "://").ToList(); } catch { } return m_backend.SupportedCommands; diff --git a/Duplicati/UnitTest/SizeOmittingBackend.cs b/Duplicati/UnitTest/SizeOmittingBackend.cs index f50c2a2ac..1801b0e15 100644 --- a/Duplicati/UnitTest/SizeOmittingBackend.cs +++ b/Duplicati/UnitTest/SizeOmittingBackend.cs @@ -112,8 +112,8 @@ namespace Duplicati.UnitTest get { if (m_backend == null) - try { return Duplicati.Library.DynamicLoader.BackendLoader.GetSupportedCommands(WrappedBackend + "://"); } - catch { } + try { return Duplicati.Library.DynamicLoader.BackendLoader.GetSupportedCommands(WrappedBackend + "://").ToList(); } + catch { } return m_backend.SupportedCommands; } @@ -131,7 +131,7 @@ namespace Duplicati.UnitTest { if (m_backend != null) try { m_backend.Dispose(); } - finally { m_backend = null; } + finally { m_backend = null; } } #endregion } diff --git a/Executables/net8/Duplicati.CommandLine.BackendTester/Duplicati.CommandLine.BackendTester.csproj b/Executables/net8/Duplicati.CommandLine.BackendTester/Duplicati.CommandLine.BackendTester.csproj index 61422bfae..67a4cae20 100644 --- a/Executables/net8/Duplicati.CommandLine.BackendTester/Duplicati.CommandLine.BackendTester.csproj +++ b/Executables/net8/Duplicati.CommandLine.BackendTester/Duplicati.CommandLine.BackendTester.csproj @@ -7,8 +7,7 @@ - - + diff --git a/Executables/net8/Duplicati.CommandLine.BackendTool/Duplicati.CommandLine.BackendTool.csproj b/Executables/net8/Duplicati.CommandLine.BackendTool/Duplicati.CommandLine.BackendTool.csproj index 3388efe5d..f177e375f 100644 --- a/Executables/net8/Duplicati.CommandLine.BackendTool/Duplicati.CommandLine.BackendTool.csproj +++ b/Executables/net8/Duplicati.CommandLine.BackendTool/Duplicati.CommandLine.BackendTool.csproj @@ -7,8 +7,7 @@ - - + diff --git a/Executables/net8/Duplicati.CommandLine.ConfigurationImporter/Duplicati.CommandLine.ConfigurationImporter.csproj b/Executables/net8/Duplicati.CommandLine.ConfigurationImporter/Duplicati.CommandLine.ConfigurationImporter.csproj index 6f71d33f5..0bb0f5098 100644 --- a/Executables/net8/Duplicati.CommandLine.ConfigurationImporter/Duplicati.CommandLine.ConfigurationImporter.csproj +++ b/Executables/net8/Duplicati.CommandLine.ConfigurationImporter/Duplicati.CommandLine.ConfigurationImporter.csproj @@ -7,8 +7,7 @@ - - + diff --git a/Executables/net8/Duplicati.CommandLine.RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj b/Executables/net8/Duplicati.CommandLine.RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj index 6909d652e..3e084f36b 100644 --- a/Executables/net8/Duplicati.CommandLine.RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj +++ b/Executables/net8/Duplicati.CommandLine.RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj @@ -7,8 +7,7 @@ - - + diff --git a/Executables/net8/Duplicati.CommandLine/Duplicati.CommandLine.csproj b/Executables/net8/Duplicati.CommandLine/Duplicati.CommandLine.csproj index ffe763801..fd8006df1 100644 --- a/Executables/net8/Duplicati.CommandLine/Duplicati.CommandLine.csproj +++ b/Executables/net8/Duplicati.CommandLine/Duplicati.CommandLine.csproj @@ -7,8 +7,7 @@ - - +