]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
Unify snbk snapshot operation command implementation 1091/head
authorCheng-Ling Lai <jamesljlster@gmail.com>
Sat, 17 Jan 2026 16:46:34 +0000 (00:46 +0800)
committerCheng-Ling Lai <jamesljlster@gmail.com>
Fri, 23 Jan 2026 02:00:57 +0000 (10:00 +0800)
client/snbk/cmd-delete.cc
client/snbk/cmd-restore.cc
client/snbk/cmd-transfer-and-delete.cc
client/snbk/cmd-transfer.cc
client/snbk/utils.cc
client/snbk/utils.h

index 64893e3b64807f33949f6725abc94f02c51842d3..e51ca7bbfe7371197137517baf68f8bd04ff30db 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 SUSE LLC
+ * Copyright (c) [2024-2026] SUSE LLC
  *
  * All Rights Reserved.
  *
 
 
 #include <iostream>
-#include <regex>
 
-#include <snapper/AppUtil.h>
-
-#include "../proxy/errors.h"
 #include "../utils/text.h"
 
-#include "BackupConfig.h"
-#include "GlobalOptions.h"
-#include "TheBigThing.h"
 #include "utils.h"
 
 
 namespace snapper
 {
-
-    using namespace std;
-
-
-    void
-    help_delete()
-    {
-       cout << "  " << _("Delete:") << '\n'
-            << "\t" << _("snbk delete [numbers]") << '\n'
-            << '\n';
-    }
-
-
-    void
-    command_delete(const GlobalOptions& global_options, GetOpts& get_opts, BackupConfigs& backup_configs,
-                  ProxySnappers* snappers)
+    namespace
     {
-       ParsedOpts opts = get_opts.parse("delete", GetOpts::no_options);
+       class SnapshotDelete : public SnapshotOperation
+       {
+       public:
 
-       vector<unsigned int> nums = parse_nums(get_opts);
+           SnapshotDelete(const GlobalOptions& global_options, GetOpts& get_opts,
+                          const BackupConfigs& backup_configs, ProxySnappers* snappers)
+               : SnapshotOperation(global_options, get_opts, backup_configs, snappers)
+           {
+           }
 
-       unsigned int errors = 0;
+       protected:
 
-       for (const BackupConfig& backup_config : backup_configs)
-       {
-           if (!global_options.quiet())
-               cout << sformat(_("Running delete for backup config '%s'."),
-                               backup_config.name.c_str()) << endl;
+           const char* command() const override { return "delete"; }
 
-           try
+           void run_all(TheBigThings& the_big_things, const BackupConfig& backup_config,
+                        bool quiet, bool verbose) const override
            {
-               TheBigThings the_big_things(backup_config, snappers, global_options.verbose());
-
-               if (nums.empty())
-               {
-                   the_big_things.remove(backup_config, global_options.quiet(), global_options.quiet());
-               }
-               else
-               {
-                   for (unsigned int num : nums)
-                   {
-                       TheBigThings::iterator it = the_big_things.find(num);
-                       if (it == the_big_things.end())
-                       {
-                           string error = sformat(_("Snapshot number %d not found."), num);
-                           SN_THROW(Exception(error));
-                       }
-
-                       it->remove(backup_config, global_options.quiet());
-                   }
-               }
+               the_big_things.remove(backup_config, quiet, verbose);
            }
-           catch (const DBus::ErrorException& e)
+
+           void run_single(TheBigThing& the_big_thing, const BackupConfig& backup_config,
+                           TheBigThings& the_big_things, bool quiet) const override
            {
-               SN_CAUGHT(e);
+               the_big_thing.remove(backup_config, quiet);
+           }
 
-               cerr << error_description(e) << endl;
+           const char* msg_running() const override
+           {
+               return _("Running delete for backup config '%s'.");
+           }
 
-               ++errors;
+           const char* msg_failed() const override
+           {
+               return _("Running delete for backup config '%s' failed.");
            }
-           catch (const Exception& e)
+
+           const char* msg_error_summary() const override
            {
-               SN_CAUGHT(e);
+               return _("Running delete failed for %d of %ld backup config.",
+                        "Running delete failed for %d of %ld backup configs.",
+                        backup_configs.size());
+           }
+       };
 
-               cerr << e.what() << '\n';
+    } // namespace
 
-               cerr << sformat(_("Running delete for backup config '%s' failed."),
-                               backup_config.name.c_str()) << endl;
+    using namespace std;
 
-               ++errors;
-           }
-       }
 
-       if (errors != 0)
-       {
-           string error = sformat(_("Running delete failed for %d of %ld backup config.",
-                                    "Running delete failed for %d of %ld backup configs.",
-                                    backup_configs.size()), errors, backup_configs.size());
+    void
+    help_delete()
+    {
+       cout << "  " << _("Delete:") << '\n'
+            << "\t" << _("snbk delete [numbers]") << '\n'
+            << '\n';
+    }
 
-           SN_THROW(Exception(error));
-       }
+
+    void
+    command_delete(const GlobalOptions& global_options, GetOpts& get_opts, BackupConfigs& backup_configs,
+                  ProxySnappers* snappers)
+    {
+       SnapshotDelete snapshot_operation(global_options, get_opts, backup_configs,
+                                         snappers);
+       snapshot_operation();
     }
 
 }
index 8b041573bf6ffea63f3d79215c30206434ddfbcb..74452b772b6fe445afd849f51391da67fa8d54db 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 SUSE LLC
+ * Copyright (c) [2024-2026] SUSE LLC
  *
  * All Rights Reserved.
  *
 
 
 #include <iostream>
-#include <regex>
 
-#include <snapper/AppUtil.h>
-
-#include "../proxy/errors.h"
 #include "../utils/text.h"
 
-#include "BackupConfig.h"
-#include "GlobalOptions.h"
-#include "TheBigThing.h"
 #include "utils.h"
 
 
 namespace snapper
 {
+    namespace
+    {
+       class SnapshotRestore : public SnapshotOperation
+       {
+       public:
+
+           SnapshotRestore(const GlobalOptions& global_options, GetOpts& get_opts,
+                           const BackupConfigs& backup_configs, ProxySnappers* snappers)
+               : SnapshotOperation(global_options, get_opts, backup_configs, snappers)
+           {
+           }
+
+       protected:
+
+           const char* command() const override { return "restore"; }
+
+           void prerequisite() const override
+           {
+               if (backup_configs.size() != 1)
+               {
+                   SN_THROW(OptionsException(
+                       _("A backup-config must be specified to run this command.")));
+               }
+           }
+
+           void run_all(TheBigThings& the_big_things, const BackupConfig& backup_config,
+                        bool quiet, bool verbose) const override
+           {
+               the_big_things.restore(backup_config, quiet, verbose);
+           }
+
+           void run_single(TheBigThing& the_big_thing, const BackupConfig& backup_config,
+                           TheBigThings& the_big_things, bool quiet) const override
+           {
+               the_big_thing.restore(backup_config, the_big_things, quiet);
+           }
+
+           const char* msg_running() const override
+           {
+               return _("Running restore for backup config '%s'.");
+           }
+
+           const char* msg_failed() const override
+           {
+               return _("Running restore for backup config '%s' failed.");
+           }
+
+           const char* msg_error_summary() const override
+           {
+               return _("Running restore failed for %d of %ld backup config.",
+                        "Running restore failed for %d of %ld backup configs.",
+                        backup_configs.size());
+           }
+       };
+
+    } // namespace
 
     using namespace std;
 
@@ -59,82 +108,9 @@ namespace snapper
     command_restore(const GlobalOptions& global_options, GetOpts& get_opts,
                    BackupConfigs& backup_configs, ProxySnappers* snappers)
     {
-       ParsedOpts opts = get_opts.parse("restore", GetOpts::no_options);
-
-       if (backup_configs.size() != 1)
-       {
-           SN_THROW(OptionsException(_("A backup-config must be specified to run this "
-                                       "command.")));
-       }
-
-       vector<unsigned int> nums = parse_nums(get_opts);
-
-       unsigned int errors = 0;
-
-       for (const BackupConfig& backup_config : backup_configs)
-       {
-           if (!global_options.quiet())
-               cout << sformat(_("Running restore for backup config '%s'."),
-                               backup_config.name.c_str()) << endl;
-
-           try
-           {
-               TheBigThings the_big_things(backup_config, snappers,
-                                           global_options.verbose());
-
-               if (nums.empty())
-               {
-                   the_big_things.restore(backup_config, global_options.quiet(),
-                                          global_options.quiet());
-               }
-               else
-               {
-                   for (unsigned int num : nums)
-                   {
-                       TheBigThings::iterator it = the_big_things.find(num);
-                       if (it == the_big_things.end())
-                       {
-                           string error = sformat(_("Snapshot number %d not found."),
-                                                  num);
-                           SN_THROW(Exception(error));
-                       }
-
-                       it->restore(backup_config, the_big_things,
-                                   global_options.quiet());
-                   }
-               }
-           }
-           catch (const DBus::ErrorException& e)
-           {
-               SN_CAUGHT(e);
-
-               cerr << error_description(e) << endl;
-
-               ++errors;
-           }
-           catch (const Exception& e)
-           {
-               SN_CAUGHT(e);
-
-               cerr << e.what() << '\n';
-
-               cerr << sformat(_("Running restore for backup config '%s' failed."),
-                               backup_config.name.c_str()) << endl;
-
-               ++errors;
-           }
-       }
-
-       if (errors != 0)
-       {
-           string error = sformat(
-               _("Running restore failed for %d of %ld backup config.",
-                 "Running restore failed for %d of %ld backup configs.",
-                 backup_configs.size()), errors, backup_configs.size()
-           );
-
-           SN_THROW(Exception(error));
-       }
+       SnapshotRestore snapshot_operation(global_options, get_opts, backup_configs,
+                                          snappers);
+       snapshot_operation();
     }
 
 }
index e1e6ffb312a5fb763982a00a4d785677762fa0d6..64927b9aba54eb27dd99df128bfc2b42ee3abe0f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 SUSE LLC
+ * Copyright (c) [2024-2026] SUSE LLC
  *
  * All Rights Reserved.
  *
 
 #include <iostream>
 
-#include <snapper/AppUtil.h>
-
-#include "../proxy/errors.h"
 #include "../utils/text.h"
 
-#include "BackupConfig.h"
-#include "GlobalOptions.h"
-#include "TheBigThing.h"
+#include "utils.h"
 
 
 namespace snapper
 {
-
-    using namespace std;
-
-
-    void
-    help_transfer_and_delete()
+    namespace
     {
-       cout << "  " << _("Transfer and delete:") << '\n'
-            << "\t" << _("snbk transfer-and-delete") << '\n'
-            << '\n';
-    }
-
-
-    void
-    command_transfer_and_delete(const GlobalOptions& global_options, GetOpts& get_opts, BackupConfigs& backup_configs,
-                               ProxySnappers* snappers)
-    {
-       ParsedOpts opts = get_opts.parse("transfer-and-delete", GetOpts::no_options);
-
-       if (get_opts.has_args())
+       class SnapshotTransferAndDelete : public SnapshotOperation
        {
-           SN_THROW(OptionsException(_("Command 'transfer-and-delete' does not take arguments.")));
-       }
+       public:
 
-       unsigned int errors = 0;
+           SnapshotTransferAndDelete(const GlobalOptions& global_options,
+                                     GetOpts& get_opts,
+                                     const BackupConfigs& backup_configs,
+                                     ProxySnappers* snappers)
+               : SnapshotOperation(global_options, get_opts, backup_configs, snappers)
+           {
+           }
 
-       for (const BackupConfig& backup_config : backup_configs)
-       {
-           if (!global_options.quiet())
-               cout << sformat(_("Running transfer and delete for backup config '%s'."),
-                               backup_config.name.c_str()) << endl;
+       protected:
 
-           try
+           const char* command() const override { return "transfer-and-delete"; }
+
+           void prerequisite() const override
            {
-               TheBigThings the_big_things(backup_config, snappers, global_options.verbose());
+               if (get_opts.has_args())
+               {
+                   SN_THROW(OptionsException(
+                       _("Command 'transfer-and-delete' does not take arguments.")));
+               }
+           }
 
-               the_big_things.transfer(backup_config, global_options.quiet(), global_options.quiet());
-               the_big_things.remove(backup_config, global_options.quiet(), global_options.quiet());
+           void run_all(TheBigThings& the_big_things, const BackupConfig& backup_config,
+                        bool quiet, bool verbose) const override
+           {
+               the_big_things.transfer(backup_config, global_options.quiet(),
+                                       global_options.quiet());
+               the_big_things.remove(backup_config, global_options.quiet(),
+                                     global_options.quiet());
            }
-           catch (const DBus::ErrorException& e)
+
+           void run_single(TheBigThing& the_big_thing, const BackupConfig& backup_config,
+                           TheBigThings& the_big_things, bool quiet) const override
            {
-               SN_CAUGHT(e);
+               SN_THROW(Exception(_("Command 'transfer-and-delete' does not support "
+                                    "operating on a single snapshot.")));
+           }
 
-               cerr << error_description(e) << endl;
+           const char* msg_running() const override
+           {
+               return _("Running transfer and delete for backup config '%s'.");
+           }
 
-               ++errors;
+           const char* msg_failed() const override
+           {
+               return _("Running transfer and delete for backup config '%s' failed.");
            }
-           catch (const Exception& e)
+
+           const char* msg_error_summary() const override
            {
-               SN_CAUGHT(e);
+               return _(
+                   "Running transfer and delete failed for %d of %ld backup config.",
+                   "Running transfer and delete failed for %d of %ld backup configs.",
+                   backup_configs.size());
+           }
+       };
 
-               cerr << e.what() << '\n';
+    } // namespace
 
-               cerr << sformat(_("Running transfer and delete for backup config '%s' failed."),
-                               backup_config.name.c_str()) << endl;
+    using namespace std;
 
-               ++errors;
-           }
-       }
 
-       if (errors != 0)
-       {
-           string error = sformat(_("Running transfer and delete failed for %d of %ld backup config.",
-                                    "Running transfer and delete failed for %d of %ld backup configs.",
-                                    backup_configs.size()), errors, backup_configs.size());
+    void
+    help_transfer_and_delete()
+    {
+       cout << "  " << _("Transfer and delete:") << '\n'
+            << "\t" << _("snbk transfer-and-delete") << '\n'
+            << '\n';
+    }
 
-           SN_THROW(Exception(error));
-       }
+
+    void
+    command_transfer_and_delete(const GlobalOptions& global_options, GetOpts& get_opts, BackupConfigs& backup_configs,
+                               ProxySnappers* snappers)
+    {
+       SnapshotTransferAndDelete snapshot_operation(global_options, get_opts,
+                                                    backup_configs, snappers);
+       snapshot_operation();
     }
 
 }
index 82e90e0b6b27a9c40ef3b4be5f31cb1afdd584fa..facd8a67e37c7ef4f1780074b280248d4a19c499 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 SUSE LLC
+ * Copyright (c) [2024-2026] SUSE LLC
  *
  * All Rights Reserved.
  *
 
 
 #include <iostream>
-#include <regex>
 
-#include <snapper/AppUtil.h>
-
-#include "../proxy/errors.h"
 #include "../utils/text.h"
 
-#include "BackupConfig.h"
-#include "GlobalOptions.h"
-#include "TheBigThing.h"
 #include "utils.h"
 
 
 namespace snapper
 {
-
-    using namespace std;
-
-
-    void
-    help_transfer()
-    {
-       cout << "  " << _("Transfer:") << '\n'
-            << "\t" << _("snbk transfer [numbers]") << '\n'
-            << '\n';
-    }
-
-
-    void
-    command_transfer(const GlobalOptions& global_options, GetOpts& get_opts, BackupConfigs& backup_configs,
-                    ProxySnappers* snappers)
+    namespace
     {
-       ParsedOpts opts = get_opts.parse("transfer", GetOpts::no_options);
+       class SnapshotTransfer : public SnapshotOperation
+       {
+       public:
 
-       vector<unsigned int> nums = parse_nums(get_opts);
+           SnapshotTransfer(const GlobalOptions& global_options, GetOpts& get_opts,
+                            const BackupConfigs& backup_configs, ProxySnappers* snappers)
+               : SnapshotOperation(global_options, get_opts, backup_configs, snappers)
+           {
+           }
 
-       unsigned int errors = 0;
+       protected:
 
-       for (const BackupConfig& backup_config : backup_configs)
-       {
-           if (!global_options.quiet())
-               cout << sformat(_("Running transfer for backup config '%s'."),
-                               backup_config.name.c_str()) << endl;
+           const char* command() const override { return "transfer"; }
 
-           try
+           void run_all(TheBigThings& the_big_things, const BackupConfig& backup_config,
+                        bool quiet, bool verbose) const override
            {
-               TheBigThings the_big_things(backup_config, snappers, global_options.verbose());
-
-               if (nums.empty())
-               {
-                   the_big_things.transfer(backup_config, global_options.quiet(), global_options.quiet());
-               }
-               else
-               {
-                   for (unsigned int num : nums)
-                   {
-                       TheBigThings::iterator it = the_big_things.find(num);
-                       if (it == the_big_things.end())
-                       {
-                           string error = sformat(_("Snapshot number %d not found."), num);
-                           SN_THROW(Exception(error));
-                       }
-
-                       it->transfer(backup_config, the_big_things, global_options.quiet());
-                   }
-               }
+               the_big_things.transfer(backup_config, quiet, verbose);
            }
-           catch (const DBus::ErrorException& e)
+
+           void run_single(TheBigThing& the_big_thing, const BackupConfig& backup_config,
+                           TheBigThings& the_big_things, bool quiet) const override
            {
-               SN_CAUGHT(e);
+               the_big_thing.transfer(backup_config, the_big_things, quiet);
+           }
 
-               cerr << error_description(e) << endl;
+           const char* msg_running() const override
+           {
+               return _("Running transfer for backup config '%s'.");
+           }
 
-               ++errors;
+           const char* msg_failed() const override
+           {
+               return _("Running transfer for backup config '%s' failed.");
            }
-           catch (const Exception& e)
+
+           const char* msg_error_summary() const override
            {
-               SN_CAUGHT(e);
+               return _("Running transfer failed for %d of %ld backup config.",
+                        "Running transfer failed for %d of %ld backup configs.",
+                        backup_configs.size());
+           }
+       };
 
-               cerr << e.what() << '\n';
+    } // namespace
 
-               cerr << sformat(_("Running transfer for backup config '%s' failed."),
-                               backup_config.name.c_str()) << endl;
+    using namespace std;
 
-               ++errors;
-           }
-       }
 
-       if (errors != 0)
-       {
-           string error = sformat(_("Running transfer failed for %d of %ld backup config.",
-                                    "Running transfer failed for %d of %ld backup configs.",
-                                    backup_configs.size()), errors, backup_configs.size());
+    void
+    help_transfer()
+    {
+       cout << "  " << _("Transfer:") << '\n'
+            << "\t" << _("snbk transfer [numbers]") << '\n'
+            << '\n';
+    }
 
-           SN_THROW(Exception(error));
-       }
+
+    void
+    command_transfer(const GlobalOptions& global_options, GetOpts& get_opts, BackupConfigs& backup_configs,
+                    ProxySnappers* snappers)
+    {
+       SnapshotTransfer snapshot_operation(global_options, get_opts, backup_configs,
+                                           snappers);
+       snapshot_operation();
     }
 
 }
index b79eb00cb25bde0fdf25e9880e2e9488bb131e95..545587dede12ff8b6af5e91aa17f2c33b7c36967 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2024-2025] SUSE LLC
+ * Copyright (c) [2024-2026] SUSE LLC
  *
  * All Rights Reserved.
  *
 
 #include <regex>
 
+#include <snapper/AppUtil.h>
+
+#include "../proxy/errors.h"
 #include "../utils/GetOpts.h"
 #include "../utils/text.h"
 
+#include "utils.h"
+
 
 namespace snapper
 {
 
-    vector<unsigned int>
-    parse_nums(GetOpts& get_opts)
+    void SnapshotOperation::operator()()
+    {
+       ParsedOpts opts = get_opts.parse(command(), GetOpts::no_options);
+
+       // Run prerequisite step
+       prerequisite();
+
+       // Run the snapshot operation
+       vector<unsigned int> nums = parse_nums();
+
+       unsigned int errors = 0;
+
+       for (const BackupConfig& backup_config : backup_configs)
+       {
+           if (!global_options.quiet())
+               cout << sformat(msg_running(), backup_config.name.c_str()) << endl;
+
+           try
+           {
+               TheBigThings the_big_things(backup_config, snappers,
+                                           global_options.verbose());
+
+               if (nums.empty())
+               {
+                   run_all(the_big_things, backup_config, global_options.quiet(),
+                           global_options.quiet());
+               }
+               else
+               {
+                   for (unsigned int num : nums)
+                   {
+                       TheBigThings::iterator it = the_big_things.find(num);
+                       if (it == the_big_things.end())
+                       {
+                           string error =
+                               sformat(_("Snapshot number %d not found."), num);
+                           SN_THROW(Exception(error));
+                       }
+
+                       run_single(*it, backup_config, the_big_things,
+                                  global_options.quiet());
+                   }
+               }
+           }
+           catch (const DBus::ErrorException& e)
+           {
+               SN_CAUGHT(e);
+
+               cerr << error_description(e) << endl;
+
+               ++errors;
+           }
+           catch (const Exception& e)
+           {
+               SN_CAUGHT(e);
+
+               cerr << e.what() << '\n';
+               cerr << sformat(msg_failed(), backup_config.name.c_str()) << endl;
+
+               ++errors;
+           }
+       }
+
+       if (errors != 0)
+       {
+           string error = sformat(msg_error_summary(), errors, backup_configs.size());
+           SN_THROW(Exception(error));
+       }
+    }
+
+    vector<unsigned int> SnapshotOperation::parse_nums() const
     {
        static const regex num_regex("[0-9]+", regex::extended);
 
@@ -49,4 +123,4 @@ namespace snapper
        return nums;
     }
 
-}
+} // namespace snapper
index a50e28b4a66b4aed332e77672d4d24034a382f29..8cc5b74a4a4db414b13b72a46dc93bc6896dd1ae 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2024-2025] SUSE LLC
+ * Copyright (c) [2024-2026] SUSE LLC
  *
  * All Rights Reserved.
  *
  */
 
 
-#include "../utils/GetOpts.h"
+#include "BackupConfig.h"
+#include "GlobalOptions.h"
+#include "TheBigThing.h"
 
 
 namespace snapper
 {
 
-    vector<unsigned int>
-    parse_nums(GetOpts& get_opts);
+    class SnapshotOperation
+    {
+    public:
 
-}
+       SnapshotOperation(const GlobalOptions& global_options, GetOpts& get_opts,
+                         const BackupConfigs& backup_configs, ProxySnappers* snappers)
+           : global_options(global_options), get_opts(get_opts),
+             backup_configs(backup_configs), snappers(snappers)
+       {
+       }
+
+       virtual ~SnapshotOperation() = default;
+
+       void operator()();
+
+    protected:
+
+       /** Command name of the snapshot operation. */
+       virtual const char* command() const = 0;
+
+       /** Run the optional prerequisite procedures for the snapshot operation. */
+       virtual void prerequisite() const {}
+
+       /** Run the snapshot operation for the entire backup config. */
+       virtual void run_all(TheBigThings& the_big_things,
+                            const BackupConfig& backup_config, bool quiet,
+                            bool verbose) const = 0;
+
+       /** Run the operation for a specific snapshot. */
+       virtual void run_single(TheBigThing& the_big_thing,
+                               const BackupConfig& backup_config,
+                               TheBigThings& the_big_things, bool quiet) const = 0;
+
+       /** Messages related to the snapshot operation. */
+       virtual const char* msg_running() const = 0;
+       virtual const char* msg_failed() const = 0;
+       virtual const char* msg_error_summary() const = 0;
+
+       vector<unsigned int> parse_nums() const;
+
+       const GlobalOptions& global_options;
+       GetOpts& get_opts;
+       const BackupConfigs& backup_configs;
+       ProxySnappers* snappers;
+    };
+
+} // namespace snapper