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 @@
-
-
+