diff --git a/Duplicati/CommandLine/ServerUtil/Commands/DeleteBackup.cs b/Duplicati/CommandLine/ServerUtil/Commands/DeleteBackup.cs new file mode 100644 index 000000000..4624fb7ed --- /dev/null +++ b/Duplicati/CommandLine/ServerUtil/Commands/DeleteBackup.cs @@ -0,0 +1,62 @@ +// Copyright (C) 2025, 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.CommandLine; +using System.CommandLine.NamingConventionBinder; + +namespace Duplicati.CommandLine.ServerUtil.Commands; + +public static class DeleteBackup +{ + public static Command Create() => + new Command("delete", "Deletes a backup") + { + new Argument("backup", "The backup to delete, either ID or exact name (case-insensitive)") { + Arity = ArgumentArity.ExactlyOne + }, + new Option(name: "--delete-remote-files", description: "Delete remote files associated with the backup", getDefaultValue: () => false), + new Option(name: "--delete-local-db", description: "Delete local database associated with the backup", getDefaultValue: () => false), + new Option(name: "--force", description: "Force deletion even if the backup is running at the moment", getDefaultValue: () => false),, + new Option("--quiet", "Do not print progress messages") { + IsRequired = false + } + } + .WithHandler(CommandHandler.Create(async (settings, output, backup, deleteRemoteFiles, deleteLocalDb, force, quiet) => + { + var connection = await settings.GetConnection(output); + + var matchingBackup = (await connection.ListBackups()) + .FirstOrDefault(b => string.Equals(b.Name, backup, StringComparison.OrdinalIgnoreCase) || string.Equals(b.ID, backup)); + + if (matchingBackup == null) + throw new UserReportedException("No backup found with supplied ID or name"); + + if (!quiet) + output.AppendConsoleMessage($"Deleting backup {matchingBackup.Name} (ID: {matchingBackup.ID})"); + + await connection.DeleteBackup(matchingBackup.ID, deleteRemoteFiles: deleteRemoteFiles, deleteLocalDb: deleteLocalDb, force: force); + + if (!quiet) + output.AppendConsoleMessage($"Deleted"); + + output.SetResult(true); + })); +} diff --git a/Duplicati/CommandLine/ServerUtil/Connection.cs b/Duplicati/CommandLine/ServerUtil/Connection.cs index fb24a2235..038afccd4 100644 --- a/Duplicati/CommandLine/ServerUtil/Connection.cs +++ b/Duplicati/CommandLine/ServerUtil/Connection.cs @@ -421,6 +421,20 @@ public class Connection await EnsureSuccessStatusCodeWithParsing(response); } + /// + /// Deletes a backup + /// + /// The ID of the backup + /// Whether to delete remote files + /// Whether to delete the local database + /// Whether to force the deletion even if the backup is running at the moment + /// The task + public async Task DeleteBackup(string backupId, bool deleteRemoteFiles, bool deleteLocalDb, bool force) + { + var response = await client.DeleteAsync($"backup/{Uri.EscapeDataString(backupId)}?delete-remote-files={deleteRemoteFiles}&delete-local-db={deleteLocalDb}&force={force}"); + await EnsureSuccessStatusCodeWithParsing(response); + } + /// /// Gets the server state /// diff --git a/Duplicati/CommandLine/ServerUtil/Program.cs b/Duplicati/CommandLine/ServerUtil/Program.cs index c879e228f..0fa8ab26a 100644 --- a/Duplicati/CommandLine/ServerUtil/Program.cs +++ b/Duplicati/CommandLine/ServerUtil/Program.cs @@ -46,6 +46,7 @@ public static class Program { Pause.Create(), Resume.Create(), + DeleteBackup.Create(), ListBackups.Create(), RunBackup.Create(), Login.Create(), @@ -97,4 +98,4 @@ public static class Program .UseAdditionalHelpAliases() .Build().InvokeAsync(args); } -} \ No newline at end of file +}