]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- special rollback for transactional server (bsc#1172273)
authorArvin Schnell <aschnell@suse.de>
Thu, 18 Jun 2020 07:26:45 +0000 (09:26 +0200)
committerArvin Schnell <aschnell@suse.de>
Thu, 18 Jun 2020 07:26:45 +0000 (09:26 +0200)
32 files changed:
VERSION
client/Command.cc
client/Command.h
client/Command/ColumnsOption.cc
client/Command/ColumnsOption.h
client/Command/GetConfig.cc
client/Command/GetConfig.h
client/Command/GetConfig/Options.cc
client/Command/GetConfig/Options.h
client/Command/ListConfigs.cc
client/Command/ListConfigs.h
client/Command/ListConfigs/Options.cc
client/Command/ListConfigs/Options.h
client/Command/ListSnapshots.cc
client/Command/ListSnapshots.h
client/Command/ListSnapshots/Options.cc
client/Command/ListSnapshots/Options.h
client/Command/ListSnapshots/SnappersData.cc
client/Command/ListSnapshots/SnappersData/Table.cc
client/GlobalOptions.cc
client/GlobalOptions.h
client/Options.cc
client/Options.h
client/proxy-dbus.cc
client/proxy-dbus.h
client/proxy-lib.cc
client/proxy-lib.h
client/proxy.h
client/snapper.cc
doc/snapper.xml.in
package/snapper.changes
snapper/Enum.h

diff --git a/VERSION b/VERSION
index 55485e179379afad176ee5c7bf81d2456bd7b8c2..ef50561618332fd82aeacc53dc4292ba32897c52 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.8.9
+0.8.10
index 16afbb30f2fa140b18a9a78a7b18b56e91c368c5..e98b26a7de8ac27ea92e9e84995cfb0854500d75 100644 (file)
@@ -33,15 +33,5 @@ namespace snapper
            _options_parser(options_parser), _global_options(global_options), _snappers(snappers)
        {}
 
-
-       bool Command::has_errors() const
-       {
-           return !errors().empty();
-       }
-
-
-       Command::~Command()
-       {}
-
     }
 }
index 9ce776001b3e85c7c475f052fa1e68f3c755fce1..d7e6393f3724bcd3598623f225e01ced2c8c7694 100644 (file)
@@ -61,13 +61,9 @@ namespace snapper
                return _snappers;
            }
 
-           virtual bool has_errors() const;
-
-           virtual std::vector<std::string> errors() const = 0;
-
            virtual void run() = 0;
 
-           virtual ~Command();
+           virtual ~Command() {}
 
        protected:
 
index 8384c0005a0e0b8bf115bbbefc882e462dbd35ea..ab559cf724d3dbcb06b7a699d8f4428482b3e7b4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2019] SUSE LLC
+ * Copyright (c) [2019-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -19,8 +19,6 @@
  * find current contact information at www.novell.com.
  */
 
-#include <algorithm>
-
 #include <boost/algorithm/string.hpp>
 
 #include "client/Command/ColumnsOption.h"
@@ -33,45 +31,30 @@ namespace snapper
     namespace cli
     {
 
-       vector<string> Command::ColumnsOption::selected_columns() const
+       vector<string>
+       Command::ColumnsOption::selected_columns() const
        {
-           if (_raw_columns.empty())
-               return {};
-
            vector<string> columns;
 
            boost::split(columns, _raw_columns, boost::is_any_of(","), boost::token_compress_on);
 
-           return columns;
-       }
-
-
-       string Command::ColumnsOption::error() const
-       {
-           if (wrong_columns().empty())
-               return "";
-
-           return _("Unknown columns: ") + boost::algorithm::join(wrong_columns(), ", ");
-       }
-
-
-       vector<string> Command::ColumnsOption::wrong_columns() const
-       {
-           vector<string> wrong;
-
-           for (auto column : selected_columns())
+           vector<string> unknowns;
+           for (const string& column : columns)
            {
-               if (wrong_column(column))
-                   wrong.push_back(column);
+               if (find(_all_columns.begin(), _all_columns.end(), column) == _all_columns.end())
+                   unknowns.push_back(column);
            }
 
-           return wrong;
-       }
+           if (!unknowns.empty())
+           {
+               string error = _("Unknown column:", "Unknown columns:", unknowns.size()) + string(" ") +
+                   boost::algorithm::join(unknowns, ", ") + '\n' +
+                   _("Allowed columns are:") + string(" ") + boost::join(_all_columns, ", ");
 
+               SN_THROW(OptionsException(error));
+           }
 
-       bool Command::ColumnsOption::wrong_column(const std::string& column) const
-       {
-           return find(_all_columns.begin(), _all_columns.end(), column) == _all_columns.end();
+           return columns;
        }
 
     }
index 93bcb8d60f222ca7598f2b13d324aef0f3a00031..2fec696adb7e188a47d429e890d0257ddd61db63 100644 (file)
@@ -48,14 +48,8 @@ namespace snapper
 
            std::vector<std::string> selected_columns() const;
 
-           std::string error() const;
-
-           std::vector<std::string> wrong_columns() const;
-
        private:
 
-           bool wrong_column(const std::string& column) const;
-
            const std::vector<std::string>& _all_columns;
 
            std::string _raw_columns;
index f235e081d38b1b0739044471199d2df0893de5b1..1c7434986e96bc52ad3e4dec3b9899e946238526 100644 (file)
@@ -62,12 +62,6 @@ namespace snapper
        }
 
 
-       vector<string> Command::GetConfig::errors() const
-       {
-           return options().errors();
-       }
-
-
        void Command::GetConfig::run()
        {
            if (_options_parser.hasArgs())
@@ -76,12 +70,6 @@ namespace snapper
                exit(EXIT_FAILURE);
            }
 
-           if (options().has_errors())
-           {
-               cerr << options().errors().front() << endl;
-               exit(EXIT_FAILURE);
-           }
-
            string output;
 
            switch (global_options().output_format())
index 6ef727b6053aedb0dcd07a5f54f6d301b8de705c..2c34c1f283c70f71f061d62e59ba1eebafc9d5a7 100644 (file)
@@ -50,8 +50,6 @@ namespace snapper
 
            const Options& options() const;
 
-           virtual std::vector<std::string> errors() const override;
-
            virtual void run() override;
 
            virtual ~GetConfig();
index 006d56126787924df725491a8db2237a448bd426..7294d43c5e7470e977b87fea8c897bc21f7efda7 100644 (file)
@@ -83,20 +83,9 @@ namespace snapper
        }
 
 
-       vector<string> Command::GetConfig::Options::errors() const
-       {
-           vector<string> detected_errors;
-
-           if (!_columns_option.wrong_columns().empty())
-               detected_errors.push_back(_columns_option.error());
-
-           return detected_errors;
-       }
-
-
        string Command::GetConfig::Options::columns_raw() const
        {
-           return has_option("columns") ? get_option("columns")->second : "";
+           return has_option("columns") ? get_argument("columns") : "";
        }
 
     }
index 30bb751786ddd2b8b2578cc3a25cee02f8d2b63d..ac16eb44beebf460ebead18950e9175910cc174b 100644 (file)
@@ -50,8 +50,6 @@ namespace snapper
 
            std::vector<std::string> columns() const;
 
-           virtual std::vector<std::string> errors() const override;
-
        private:
 
            void parse_options();
index 5f070e572278cc4519ce3a1d10433b9f707d7ad1..80830ead7dcb8c25575d4a30c1f89bc9494a4944 100644 (file)
@@ -62,12 +62,6 @@ namespace snapper
        }
 
 
-       vector<string> Command::ListConfigs::errors() const
-       {
-           return options().errors();
-       }
-
-
        void Command::ListConfigs::run()
        {
            if (_options_parser.hasArgs())
@@ -76,12 +70,6 @@ namespace snapper
                exit(EXIT_FAILURE);
            }
 
-           if (options().has_errors())
-           {
-               cerr << options().errors().front() << endl;
-               exit(EXIT_FAILURE);
-           }
-
            string output;
 
            switch (global_options().output_format())
index 25e805eec8b3def043abee798fb9b1d0d7929299..fcdb14e0c139fb6ba3a90ace8bb48e443ea99a03 100644 (file)
@@ -50,8 +50,6 @@ namespace snapper
 
            const Options& options() const;
 
-           virtual std::vector<std::string> errors() const override;
-
            virtual void run() override;
 
            virtual ~ListConfigs();
index 8403e996edd573f885de0b52cee8f7fe6bdfd643..5d2c5fdcf10a5ac3f70a92e3f098b5789309553f 100644 (file)
@@ -84,20 +84,9 @@ namespace snapper
        }
 
 
-       vector<string> Command::ListConfigs::Options::errors() const
-       {
-           vector<string> detected_errors;
-
-           if (!_columns_option.wrong_columns().empty())
-               detected_errors.push_back(_columns_option.error());
-
-           return detected_errors;
-       }
-
-
        string Command::ListConfigs::Options::columns_raw() const
        {
-           return has_option("columns") ? get_option("columns")->second : "";
+           return has_option("columns") ? get_argument("columns") : "";
        }
 
     }
index 531e8dd9896dbe64e9950a966eda0bd90e121bec..4ed369930cd3cf9b4d33d626fe97511eec20fbf7 100644 (file)
@@ -50,8 +50,6 @@ namespace snapper
 
            std::vector<std::string> columns() const;
 
-           virtual std::vector<std::string> errors() const override;
-
        private:
 
            void parse_options();
index c62d005e06d1914f266ef0ba5a817028eb8c77ef..58d11988879ea59110ffe65569f5aa0c8987ff3a 100644 (file)
@@ -62,12 +62,6 @@ namespace snapper
        }
 
 
-       vector<string> Command::ListSnapshots::errors() const
-       {
-           return options().errors();
-       }
-
-
        void Command::ListSnapshots::run()
        {
            if (_options_parser.hasArgs())
@@ -76,12 +70,6 @@ namespace snapper
                exit(EXIT_FAILURE);
            }
 
-           if (options().has_errors())
-           {
-               cerr << options().errors().front() << endl;
-               exit(EXIT_FAILURE);
-           }
-
            string output;
 
            switch (global_options().output_format())
index 4ceaea0fb017c038d72ef06f64cdd56dd5a7d6d6..4849fe1809b5fe848a2d866f30bbd916069c3d40 100644 (file)
@@ -49,8 +49,6 @@ namespace snapper
 
            const Options& options() const;
 
-           virtual std::vector<std::string> errors() const override;
-
            virtual void run() override;
 
            virtual ~ListSnapshots();
index c503d4e801c7b95e3926dd4fff0d2608fc24991c..ab1ea5388e5f071df146d9eb78fc68be8e003069 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2019] SUSE LLC
+ * Copyright (c) [2019-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
  * find current contact information at www.novell.com.
  */
 
-#include <stdexcept>
-
 #include <boost/algorithm/string.hpp>
 
+#include <snapper/AppUtil.h>
+
 #include "client/Command/ListSnapshots/Options.h"
 #include "client/utils/text.h"
 
@@ -123,41 +123,31 @@ namespace snapper
        }
 
 
-       vector<string> Command::ListSnapshots::Options::errors() const
-       {
-           vector<string> detected_errors;
-
-           if (wrong_type())
-               detected_errors.push_back(type_error());
-
-           if (wrong_columns())
-               detected_errors.push_back(columns_error());
-
-           return detected_errors;
-       }
-
-
        Command::ListSnapshots::Options::ListMode
        Command::ListSnapshots::Options::list_mode_value() const
        {
-           string type = has_option("type") ? get_option("type")->second : "";
+           if (!has_option("type"))
+               return ListMode::ALL;
 
-           if (type == "all")
-               return LM_ALL;
+           string str = get_argument("type");
 
-           if (type == "single")
-               return LM_SINGLE;
+           ListMode list_mode;
+           if (!toValue(str, list_mode, false))
+           {
+               string error = sformat(_("Unknown snapshots type %s."), str.c_str()) + '\n' +
+                   sformat(_("Use %s, %s or %s."), toString(ListMode::ALL).c_str(),
+                           toString(ListMode::SINGLE).c_str(), toString(ListMode::PRE_POST).c_str());
 
-           if (type == "pre-post")
-               return LM_PRE_POST;
+               SN_THROW(OptionsException(error));
+           }
 
-           return LM_ALL;
+           return list_mode;
        }
 
 
        string Command::ListSnapshots::Options::columns_raw() const
        {
-           return has_option("columns") ? get_option("columns")->second : "";
+           return has_option("columns") ? get_argument("columns") : "";
        }
 
 
@@ -168,15 +158,15 @@ namespace snapper
 
            switch (list_mode())
            {
-               case LM_ALL:
+               case ListMode::ALL:
                    columns = all_mode_columns(format);
                    break;
 
-               case LM_SINGLE:
+               case ListMode::SINGLE:
                    columns = single_mode_columns(format);
                    break;
 
-               case LM_PRE_POST:
+               case ListMode::PRE_POST:
                    columns = pre_post_mode_columns(format);
                    break;
            }
@@ -331,34 +321,8 @@ namespace snapper
            throw logic_error("unknown output format");
        }
 
+    }
 
-       bool Command::ListSnapshots::Options::wrong_type() const
-       {
-           if (!has_option("type"))
-               return false;
-
-           string type = get_option("type")->second;
-
-           return type != "all" && type != "single" && type != "pre-post";
-       }
-
-
-       bool Command::ListSnapshots::Options::wrong_columns() const
-       {
-           return !_columns_option.wrong_columns().empty();
-       }
-
-
-       string Command::ListSnapshots::Options::type_error() const
-       {
-           return _("Unknown type of snapshots.");
-       }
-
+    const vector<string> EnumInfo<cli::Command::ListSnapshots::Options::ListMode>::names({ "all", "single", "pre-post" });
 
-       string Command::ListSnapshots::Options::columns_error() const
-       {
-           return _columns_option.error();
-       }
-
-    }
 }
index 0bc1d36d30be5dda7cdfc39fa6e5c8b77b0c4642..587b5c3575a62210e7a80aaf5ae1eeefac26d837 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2019] SUSE LLC
+ * Copyright (c) [2019-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -59,31 +59,18 @@ namespace snapper
 
            static const std::vector<std::string> ALL_COLUMNS;
 
-           enum ListMode { LM_ALL, LM_SINGLE, LM_PRE_POST };
+           enum class ListMode { ALL, SINGLE, PRE_POST };
 
            static std::string help_text();
 
            Options(GetOpts& parser);
 
-           ListMode list_mode() const
-           {
-               return _list_mode;
-           }
-
-           bool disable_used_space() const
-           {
-               return _disable_used_space;
-           }
-
-           bool all_configs() const
-           {
-               return _all_configs;
-           }
+           ListMode list_mode() const { return _list_mode; }
+           bool disable_used_space() const { return _disable_used_space; }
+           bool all_configs() const { return _all_configs; }
 
            std::vector<std::string> columns(GlobalOptions::OutputFormat format) const;
 
-           virtual std::vector<std::string> errors() const override;
-
        private:
 
            void parse_options();
@@ -100,14 +87,6 @@ namespace snapper
 
            std::vector<std::string> pre_post_mode_columns(GlobalOptions::OutputFormat format) const;
 
-           bool wrong_type() const;
-
-           bool wrong_columns() const;
-
-           std::string type_error() const;
-
-           std::string columns_error() const;
-
            ListMode _list_mode;
 
            bool _disable_used_space;
@@ -119,6 +98,9 @@ namespace snapper
        };
 
     }
+
+    template <> struct EnumInfo<cli::Command::ListSnapshots::Options::ListMode> { static const vector<string> names; };
+
 }
 
 #endif
index fda2770b792131b626fcd86ed2570f6edd4843b8..dab91b3b7ea18cda8fe1ac647fce9266d726770b 100644 (file)
@@ -79,20 +79,20 @@ namespace snapper
            {
                switch (command().options().list_mode())
                {
-                   case Options::ListMode::LM_ALL:
+                   case Options::ListMode::ALL:
                    {
                        selected.push_back(&snapshot);
                    }
                    break;
 
-                   case Options::ListMode::LM_SINGLE:
+                   case Options::ListMode::SINGLE:
                    {
                        if (snapshot.getType() == SINGLE)
                            selected.push_back(&snapshot);
                    }
                    break;
 
-                   case Options::ListMode::LM_PRE_POST:
+                   case Options::ListMode::PRE_POST:
                    {
                        ProxySnapshots::const_iterator post_it = find_post(snapshot, snapshots);
 
@@ -293,7 +293,7 @@ namespace snapper
        string
        Command::ListSnapshots::SnappersData::date_value(const ProxySnapshot& snapshot) const
        {
-           if (command().options().list_mode() == Options::ListMode::LM_PRE_POST)
+           if (command().options().list_mode() == Options::ListMode::PRE_POST)
                return snapshot_date(snapshot);
 
            return snapshot.isCurrent() ? "" : snapshot_date(snapshot);
index 424214c4942c2f59509727938d44bd86a00689a6..d88dbdc8bed66f4ca07cde8993d3cf9573ac2286 100644 (file)
@@ -75,7 +75,7 @@ namespace snapper
                return _("Subvolume");
 
            if (column == Options::Columns::NUMBER)
-               return list_mode == Options::LM_PRE_POST ? _("Pre #") : _("#");
+               return list_mode == Options::ListMode::PRE_POST ? _("Pre #") : _("#");
 
            if (column == Options::Columns::DEFAULT)
                return _("Default");
@@ -87,7 +87,7 @@ namespace snapper
                return _("Type");
 
            if (column == Options::Columns::DATE)
-               return list_mode == Options::LM_PRE_POST ? _("Pre Date") : _("Date");
+               return list_mode == Options::ListMode::PRE_POST ? _("Pre Date") : _("Date");
 
            if (column == Options::Columns::USER)
                return _("User");
index 7a168ac34f2151515e8b7d3c4a3a0c2fac6b5cb2..5265f0e7504086fd3a97b6dfe911610b583d0765 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2019] SUSE LLC
+ * Copyright (c) [2019-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -36,27 +36,24 @@ namespace snapper
        namespace
        {
 
-           const string CSV_OPTION = "csv";
-
-           const string JSON_OPTION = "json";
-
            const string DEFAULT_CONFIG = "root";
 
            const string DEFAULT_ROOT = "/";
 
-           const option OPTIONS[15] = {
+           const option OPTIONS[] = {
                { "quiet",              no_argument,            0,      'q' },
                { "verbose",            no_argument,            0,      'v' },
                { "utc",                no_argument,            0,      0 },
                { "iso",                no_argument,            0,      0 },
                { "table-style",        required_argument,      0,      't' },
-               { "machine-readable",   required_argument,      0,      0},
-               { "csvout",             no_argument,            0,      0},
-               { "jsonout",            no_argument,            0,      0},
-               { "separator",          required_argument,      0,      0},
+               { "machine-readable",   required_argument,      0,      0 },
+               { "csvout",             no_argument,            0,      0 },
+               { "jsonout",            no_argument,            0,      0 },
+               { "separator",          required_argument,      0,      0 },
                { "config",             required_argument,      0,      'c' },
                { "no-dbus",            no_argument,            0,      0 },
                { "root",               required_argument,      0,      'r' },
+               { "ambit",              required_argument,      0,      'a' },
                { "version",            no_argument,            0,      0 },
                { "help",               no_argument,            0,      'h' },
                { 0, 0, 0, 0 }
@@ -80,14 +77,16 @@ namespace snapper
                + _("\t--config, -c <name>\t\tSet name of config to use.") + '\n'
                + _("\t--no-dbus\t\t\tOperate without DBus.") + '\n'
                + _("\t--root, -r <path>\t\tOperate on target root (works only without DBus).") + '\n'
+               + _("\t--ambit, -a ambit\t\tOperate in the specified ambit.") + '\n'
                + _("\t--version\t\t\tPrint version and exit.") + '\n';
        }
 
 
-       GlobalOptions::GlobalOptions(GetOpts& parser) :
-           Options(parser)
+       GlobalOptions::GlobalOptions(GetOpts& parser)
+           : Options(parser), _ambit(Ambit::AUTO)
        {
            parse_options();
+           check_options();
 
            _quiet = has_option("quiet");
            _verbose = has_option("verbose");
@@ -101,6 +100,7 @@ namespace snapper
            _separator = separator_value();
            _config = config_value();
            _root = root_value();
+           _ambit = ambit_value();
        }
 
 
@@ -110,139 +110,123 @@ namespace snapper
        }
 
 
-       vector<string> GlobalOptions::errors() const
+       void
+       GlobalOptions::check_options() const
        {
-           vector<string> detected_errors;
+           if (has_option("root") && !has_option("no-dbus"))
+           {
+               string error =_("root argument can be used only together with no-dbus.\n"
+                               "Try 'snapper --help' for more information.");
 
-           if (wrong_table_style())
-               detected_errors.push_back(table_style_error());
+               SN_THROW(OptionsException(error));
+           }
+       }
 
-           if (wrong_machine_readable())
-               detected_errors.push_back(machine_readable_error());
 
-           if (missing_no_dbus())
-               detected_errors.push_back(missing_no_dbus_error());
+       TableLineStyle
+       GlobalOptions::table_style_value() const
+       {
+           if (!has_option("table-style"))
+               return TableFormatter::default_style();
 
-           return detected_errors;
-       }
+           string str = get_argument("table-style");
 
+           unsigned long value = stoul(str);
+           if (value >= Table::numStyles)
+           {
+               string error = sformat(_("Invalid table style %s."), str.c_str()) + '\n' +
+                   sformat(_("Use an integer number from %d to %d."), 0, Table::numStyles - 1);
 
-       TableLineStyle GlobalOptions::table_style_value() const
-       {
-           if (has_option("table-style") && !wrong_table_style())
-               return (TableLineStyle) table_style_raw();
+               SN_THROW(OptionsException(error));
+           }
 
-           return TableFormatter::default_style();
+           return (TableLineStyle)(value);
        }
 
 
-       GlobalOptions::OutputFormat GlobalOptions::output_format_value() const
+       GlobalOptions::OutputFormat
+       GlobalOptions::output_format_value() const
        {
-           if (has_option("csvout") || machine_readable_value() == CSV_OPTION)
+           if (has_option("csvout"))
                return OutputFormat::CSV;
 
-           if (has_option("jsonout") || machine_readable_value() == JSON_OPTION)
+           if (has_option("jsonout"))
                return OutputFormat::JSON;
 
-           return OutputFormat::TABLE;
-       }
+           if (!has_option("machine-readable"))
+               return OutputFormat::TABLE;
 
+           string str = get_argument("machine-readable");
 
-       string GlobalOptions::machine_readable_value() const
-       {
-           if (has_option("machine-readable"))
-               return get_option("machine-readable")->second;
+           OutputFormat output_format;
+           if (!toValue(str, output_format, false))
+           {
+               string error = sformat(_("Invalid machine readable format %s."), str.c_str()) + '\n' +
+                   sformat(_("Use %s, %s or %s."), toString(OutputFormat::TABLE).c_str(),
+                           toString(OutputFormat::CSV).c_str(), toString(OutputFormat::JSON).c_str());
 
-           return "";
+               SN_THROW(OptionsException(error));
+           }
+
+           return output_format;
        }
 
 
-       string GlobalOptions::separator_value() const
+       string
+       GlobalOptions::separator_value() const
        {
            if (has_option("separator"))
-               return get_option("separator")->second;
+               return get_argument("separator");
 
            return CsvFormatter::default_separator();
        }
 
 
-       string GlobalOptions::config_value() const
+       string
+       GlobalOptions::config_value() const
        {
            if (has_option("config"))
-               return get_option("config")->second;
+               return get_argument("config");
 
            return DEFAULT_CONFIG;
        }
 
 
-       string GlobalOptions::root_value() const
+       string
+       GlobalOptions::root_value() const
        {
            if (has_option("root"))
-               return get_option("root")->second;
+               return get_argument("root");
 
            return DEFAULT_ROOT;
        }
 
 
-       unsigned int GlobalOptions::table_style_raw() const
-       {
-           return stoul(get_option("table-style")->second);
-       }
-
-
-       bool GlobalOptions::wrong_table_style() const
-       {
-           if (!has_option("table-style"))
-               return false;
-
-           if (table_style_raw() >= Table::numStyles)
-               return true;
-
-           return false;
-       }
-
-
-       bool GlobalOptions::wrong_machine_readable() const
+       GlobalOptions::Ambit
+       GlobalOptions::ambit_value() const
        {
-           if (!has_option("machine-readable"))
-               return false;
-
-           string value = machine_readable_value();
+           if (!has_option("ambit"))
+               return Ambit::AUTO;
 
-           if (value != CSV_OPTION && value != JSON_OPTION)
-               return true;
+           string str = get_argument("ambit");
 
-           return false;
-       }
+           Ambit ambit;
+           if (!toValue(str, ambit, false))
+           {
+               string error = sformat(_("Invalid ambit %s."), str.c_str()) + '\n' +
+                   sformat(_("Use %s, %s or %s."), toString(Ambit::AUTO).c_str(),
+                           toString(Ambit::CLASSIC).c_str(), toString(Ambit::TRANSACTIONAL).c_str());
 
+               SN_THROW(OptionsException(error));
+           }
 
-       bool GlobalOptions::missing_no_dbus() const
-       {
-           return has_option("root") && !has_option("no-dbus");
+           return ambit;
        }
 
+    }
 
-       string GlobalOptions::table_style_error() const
-       {
-           return sformat(_("Invalid table style %d."), table_style_raw()) + " " +
-                  sformat(_("Use an integer number from %d to %d."), 0, Table::numStyles - 1);
-       }
-
-
-       string GlobalOptions::machine_readable_error() const
-       {
-           string format = machine_readable_value();
-
-           return sformat(_("Invalid machine readable format %s."), format.c_str()) + " " +
-                  sformat(_("Use %s or %s."), CSV_OPTION.c_str(), JSON_OPTION.c_str());
-       }
-
+    const vector<string> EnumInfo<cli::GlobalOptions::OutputFormat>::names({ "table", "csv", "json" });
 
-       string GlobalOptions::missing_no_dbus_error() const
-       {
-           return _("root argument can be used only together with no-dbus.\n"
-                    "Try 'snapper --help' for more information.");
-       }
+    const vector<string> EnumInfo<cli::GlobalOptions::Ambit>::names({ "auto", "classic", "transactional" });
 
-    }
 }
index 89c16b9421bcb905b30f437edbf78c3e8981a8ed..86177946f600944327f1ef4da6d14bf64c07b4bf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2019] SUSE LLC
+ * Copyright (c) [2019-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -24,6 +24,8 @@
 
 #include <string>
 
+#include <snapper/Enum.h>
+
 #include "client/Options.h"
 #include "client/utils/GetOpts.h"
 #include "client/utils/Table.h"
@@ -38,132 +40,64 @@ namespace snapper
 
        public:
 
-           enum OutputFormat { TABLE, CSV, JSON };
+           enum class OutputFormat { TABLE, CSV, JSON };
+           enum class Ambit { AUTO, CLASSIC, TRANSACTIONAL };
 
-           static std::string help_text();
+           static string help_text();
 
            GlobalOptions(GetOpts& parser);
 
-           virtual std::vector<std::string> errors() const override;
-
-           bool quiet() const
-           {
-               return _quiet;
-           }
-
-           bool verbose() const
-           {
-               return _verbose;
-           }
-
-           bool utc() const
-           {
-               return _utc;
-           }
-
-           bool iso() const
-           {
-               return _iso;
-           }
-
-           bool no_dbus() const
-           {
-               return _no_dbus;
-           }
-
-           bool version() const
-           {
-               return _version;
-           }
-
-           bool help() const
-           {
-               return _help;
-           }
-
-           TableLineStyle table_style() const
-           {
-               return _table_style;
-           }
-
-           OutputFormat output_format() const
-           {
-               return _output_format;
-           }
-
-           string separator() const
-           {
-               return _separator;
-           }
-
-           string config() const
-           {
-               return _config;
-           }
-
-
-           string root() const
-           {
-               return _root;
-           }
+           bool quiet() const { return _quiet; }
+           bool verbose() const { return _verbose; }
+           bool utc() const { return _utc; }
+           bool iso() const { return _iso; }
+           bool no_dbus() const { return _no_dbus; }
+           bool version() const { return _version; }
+           bool help() const { return _help; }
+           TableLineStyle table_style() const { return _table_style; }
+           OutputFormat output_format() const { return _output_format; }
+           string separator() const { return _separator; }
+           string config() const { return _config; }
+           string root() const { return _root; }
+           Ambit ambit() { return _ambit; }
+
+           void set_ambit(Ambit ambit) { _ambit = ambit; }
 
        private:
 
            void parse_options();
+           void check_options() const;
 
            TableLineStyle table_style_value() const;
-
            OutputFormat output_format_value() const;
-
-           std::string machine_readable_value() const;
-
-           std::string separator_value() const;
-
-           std::string config_value() const;
-
-           std::string root_value() const;
-
-           unsigned int table_style_raw() const;
-
-           bool wrong_table_style() const;
-
-           bool wrong_machine_readable() const;
-
-           bool missing_no_dbus() const;
-
-           std::string table_style_error() const;
-
-           std::string machine_readable_error() const;
-
-           std::string missing_no_dbus_error() const;
+           string separator_value() const;
+           string config_value() const;
+           string root_value() const;
+           Ambit ambit_value() const;
 
            bool _quiet;
-
            bool _verbose;
-
            bool _utc;
-
            bool _iso;
-
            bool _no_dbus;
-
            bool _version;
-
            bool _help;
-
            TableLineStyle _table_style;
-
            OutputFormat _output_format;
-
            string _separator;
-
            string _config;
-
            string _root;
+           Ambit _ambit;
 
        };
 
     }
+
+
+    template <> struct EnumInfo<cli::GlobalOptions::OutputFormat> { static const vector<string> names; };
+
+    template <> struct EnumInfo<cli::GlobalOptions::Ambit> { static const vector<string> names; };
+
 }
 
-#endif
\ No newline at end of file
+#endif
index 0f2f44490a700640f576a20f2742592df6be5060..8e3aea8c4d3e015e79e0ec86f6379857b8288468 100644 (file)
@@ -31,33 +31,22 @@ namespace snapper
     namespace cli
     {
 
-       Options::Options(GetOpts& parser) :
-           _parser(parser), _options()
+       Options::Options(GetOpts& parser)
+           _parser(parser), _options()
        {}
 
 
-       Options::~Options()
-       {}
-
-
-       bool Options::has_option(const string option_name) const
-       {
-           GetOpts::parsed_opts::const_iterator option = get_option(option_name);
-
-           return option != _options.end();
-       }
-
-
-       GetOpts::parsed_opts::const_iterator
-       Options::get_option(const string option_name) const
+       bool
+       Options::has_option(const string& name) const
        {
-           return _options.find(option_name);
+           return _options.find(name) != _options.end();
        }
 
 
-       bool Options::has_errors() const
+       const string&
+       Options::get_argument(const string& name) const
        {
-           return !errors().empty();
+           return _options.find(name)->second;
        }
 
     }
index 10bfe1dd2f35d39207a3a846f280901d1183aa23..7386d6e194c165d570c0952b987b93fcf0a364dd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2019] SUSE LLC
+ * Copyright (c) [2019-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
 #include <string>
 #include <vector>
 
+#include <snapper/Exception.h>
+
 #include "client/utils/GetOpts.h"
 
 namespace snapper
 {
+    using std::string;
+    using std::vector;
+
+
+    struct OptionsException : public Exception
+    {
+        explicit OptionsException(const string& msg) : Exception(msg) {}
+    };
+
+
     namespace cli
     {
 
@@ -39,18 +51,13 @@ namespace snapper
 
            Options(GetOpts& parser);
 
-           virtual bool has_errors() const;
-
-           virtual std::vector<std::string> errors() const = 0;
-
-           virtual ~Options();
+           virtual ~Options() {}
 
        protected:
 
-           bool has_option(const std::string option_name) const;
+           bool has_option(const string& name) const;
 
-           GetOpts::parsed_opts::const_iterator
-           get_option(const std::string option_name) const;
+           const string& get_argument(const string& name) const;
 
            GetOpts& _parser;
 
@@ -61,4 +68,4 @@ namespace snapper
     }
 }
 
-#endif
\ No newline at end of file
+#endif
index 928da45ba39cd001a77911d1d0dc188373184c32..9feab6fb16ffc02ba2723aeb5828b3a5eb4a3f21 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2016-2019] SUSE LLC
+ * Copyright (c) [2016-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -124,6 +124,15 @@ ProxySnapshotsDbus::getDefault()
 }
 
 
+ProxySnapshots::iterator
+ProxySnapshotsDbus::getActive()
+{
+    pair<bool, unsigned int> tmp = command_get_active_snapshot(conn(), configName());
+
+    return tmp.first ? find(tmp.second) : end();
+}
+
+
 ProxySnapshots::const_iterator
 ProxySnapshotsDbus::getActive() const
 {
index 6a2acd742fa2a6f56827d443f2e0f21c247fcb6b..20df621623f4dd7fa41303bd1a9a06574cc3d0aa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2016-2019] SUSE LLC
+ * Copyright (c) [2016-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -96,6 +96,7 @@ public:
     virtual iterator getDefault() override;
     virtual const_iterator getDefault() const override;
 
+    virtual iterator getActive() override;
     virtual const_iterator getActive() const override;
 
     DBus::Connection& conn() const;
index c5bf341a34bf776c03313d1a776bd23b96479c75..aa8157edb4e1a3c00b60e90f5fd857fea427a3ed 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2016-2019] SUSE LLC
+ * Copyright (c) [2016-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -48,6 +48,17 @@ ProxySnapshotsLib::getDefault() const
 }
 
 
+ProxySnapshots::iterator
+ProxySnapshotsLib::getActive()
+{
+    Snapshots& snapshots = backref->snapper->getSnapshots();
+
+    Snapshots::const_iterator tmp = snapshots.getActive();
+
+    return tmp != snapshots.end() ? find(tmp->getNum()) : end();
+}
+
+
 ProxySnapshots::const_iterator
 ProxySnapshotsLib::getActive() const
 {
index 3602e905bb64945370ac7b2c5d9774013efed252..e3b9a6d7c99a6d595fc84a271ff1b5e1b0718d0c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2016-2019] SUSE LLC
+ * Copyright (c) [2016-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -82,6 +82,7 @@ public:
     virtual iterator getDefault() override;
     virtual const_iterator getDefault() const override;
 
+    virtual iterator getActive() override;
     virtual const_iterator getActive() const override;
 
     ProxySnapshotsLib(ProxySnapperLib* backref);
index 606105ecc52f674a8c0b488216443d5e4ef77a59..bf0c1db919e157bd8c6ad987d7823ce4f70b8019 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2016-2019] SUSE LLC
+ * Copyright (c) [2016-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -175,6 +175,7 @@ public:
     virtual iterator getDefault() = 0;
     virtual const_iterator getDefault() const = 0;
 
+    virtual iterator getActive() = 0;
     virtual const_iterator getActive() const = 0;
 
     iterator find(unsigned int i);
index fa76d37cd0e5427f3af2a932b4aee9f57b6f0605..cec688b12d76cc51695d6aff9696afea68af6df8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
- * Copyright (c) [2016-2019] SUSE LLC
+ * Copyright (c) [2016-2020] SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -63,7 +63,7 @@ using namespace std;
 
 struct Cmd
 {
-    typedef void (*cmd_func_t)(cli::GlobalOptions* global_options, ProxySnappers* snappers,
+    typedef void (*cmd_func_t)(cli::GlobalOptions& global_options, ProxySnappers* snappers,
        ProxySnapper* snapper);
 
     typedef void (*help_func_t)();
@@ -170,9 +170,9 @@ help_list_configs()
 
 
 void
-command_list_configs(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper*)
+command_list_configs(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*)
 {
-    cli::Command::ListConfigs command(*global_options, getopts, *snappers);
+    cli::Command::ListConfigs command(global_options, getopts, *snappers);
 
     command.run();
 }
@@ -192,7 +192,7 @@ help_create_config()
 
 
 void
-command_create_config(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper*)
+command_create_config(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*)
 {
     const struct option options[] = {
        { "fstype",             required_argument,      0,      'f' },
@@ -231,7 +231,7 @@ command_create_config(cli::GlobalOptions* global_options, ProxySnappers* snapper
        exit(EXIT_FAILURE);
     }
 
-    snappers->createConfig(global_options->config(), subvolume, fstype, template_name);
+    snappers->createConfig(global_options.config(), subvolume, fstype, template_name);
 }
 
 
@@ -245,7 +245,7 @@ help_delete_config()
 
 
 void
-command_delete_config(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper*)
+command_delete_config(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*)
 {
     getopts.parse("delete-config", GetOpts::no_options);
     if (getopts.hasArgs())
@@ -254,7 +254,7 @@ command_delete_config(cli::GlobalOptions* global_options, ProxySnappers* snapper
        exit(EXIT_FAILURE);
     }
 
-    snappers->deleteConfig(global_options->config());
+    snappers->deleteConfig(global_options.config());
 }
 
 
@@ -266,9 +266,9 @@ help_get_config()
 
 
 void
-command_get_config(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper*)
+command_get_config(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*)
 {
-    cli::Command::GetConfig command(*global_options, getopts, *snappers);
+    cli::Command::GetConfig command(global_options, getopts, *snappers);
 
     command.run();
 }
@@ -284,7 +284,7 @@ help_set_config()
 
 
 void
-command_set_config(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_set_config(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     getopts.parse("set-config", GetOpts::no_options);
     if (!getopts.hasArgs())
@@ -307,9 +307,9 @@ help_list()
 
 
 void
-command_list(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper*)
+command_list(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*)
 {
-    cli::Command::ListSnapshots command(*global_options, getopts, *snappers);
+    cli::Command::ListSnapshots command(global_options, getopts, *snappers);
 
     command.run();
 }
@@ -337,7 +337,7 @@ help_create()
 
 
 void
-command_create(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_create(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     const struct option options[] = {
        { "type",               required_argument,      0,      't' },
@@ -360,11 +360,11 @@ command_create(cli::GlobalOptions* global_options, ProxySnappers* snappers, Prox
        exit(EXIT_FAILURE);
     }
 
-    enum CreateType { CT_SINGLE, CT_PRE, CT_POST, CT_PRE_POST };
+    enum class CreateType { SINGLE, PRE, POST, PRE_POST };
 
     const ProxySnapshots& snapshots = snapper->getSnapshots();
 
-    CreateType type = CT_SINGLE;
+    CreateType type = CreateType::SINGLE;
     ProxySnapshots::const_iterator snapshot1 = snapshots.end();
     ProxySnapshots::const_iterator snapshot2 = snapshots.end();
     bool print_number = false;
@@ -377,13 +377,13 @@ command_create(cli::GlobalOptions* global_options, ProxySnappers* snappers, Prox
     if ((opt = opts.find("type")) != opts.end())
     {
        if (opt->second == "single")
-           type = CT_SINGLE;
+           type = CreateType::SINGLE;
        else if (opt->second == "pre")
-           type = CT_PRE;
+           type = CreateType::PRE;
        else if (opt->second == "post")
-           type = CT_POST;
+           type = CreateType::POST;
        else if (opt->second == "pre-post")
-           type = CT_PRE_POST;
+           type = CreateType::PRE_POST;
        else
        {
            cerr << _("Unknown type of snapshot.") << endl;
@@ -409,7 +409,7 @@ command_create(cli::GlobalOptions* global_options, ProxySnappers* snappers, Prox
     if ((opt = opts.find("command")) != opts.end())
     {
        command = opt->second;
-       type = CT_PRE_POST;
+       type = CreateType::PRE_POST;
     }
 
     if ((opt = opts.find("read-only")) != opts.end())
@@ -421,25 +421,25 @@ command_create(cli::GlobalOptions* global_options, ProxySnappers* snappers, Prox
     if ((opt = opts.find("from")) != opts.end())
        parent = snapshots.findNum(opt->second);
 
-    if (type == CT_POST && snapshot1 == snapshots.end())
+    if (type == CreateType::POST && snapshot1 == snapshots.end())
     {
        cerr << _("Missing or invalid pre-number.") << endl;
        exit(EXIT_FAILURE);
     }
 
-    if (type == CT_PRE_POST && command.empty())
+    if (type == CreateType::PRE_POST && command.empty())
     {
        cerr << _("Missing command argument.") << endl;
        exit(EXIT_FAILURE);
     }
 
-    if (type != CT_SINGLE && !scd.read_only)
+    if (type != CreateType::SINGLE && !scd.read_only)
     {
        cerr << _("Option --read-write only supported for snapshots of type single.") << endl;
        exit(EXIT_FAILURE);
     }
 
-    if (type != CT_SINGLE && parent != snapshots.getCurrent())
+    if (type != CreateType::SINGLE && parent != snapshots.getCurrent())
     {
        cerr << _("Option --from only supported for snapshots of type single.") << endl;
        exit(EXIT_FAILURE);
@@ -447,25 +447,25 @@ command_create(cli::GlobalOptions* global_options, ProxySnappers* snappers, Prox
 
     switch (type)
     {
-       case CT_SINGLE: {
+       case CreateType::SINGLE: {
            snapshot1 = snapper->createSingleSnapshot(parent, scd);
            if (print_number)
                cout << snapshot1->getNum() << endl;
        } break;
 
-       case CT_PRE: {
+       case CreateType::PRE: {
            snapshot1 = snapper->createPreSnapshot(scd);
            if (print_number)
                cout << snapshot1->getNum() << endl;
        } break;
 
-       case CT_POST: {
+       case CreateType::POST: {
            snapshot2 = snapper->createPostSnapshot(snapshot1, scd);
            if (print_number)
                cout << snapshot2->getNum() << endl;
        } break;
 
-       case CT_PRE_POST: {
+       case CreateType::PRE_POST: {
            snapshot1 = snapper->createPreSnapshot(scd);
            system(command.c_str());
            snapshot2 = snapper->createPostSnapshot(snapshot1, scd);
@@ -491,7 +491,7 @@ help_modify()
 
 
 void
-command_modify(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_modify(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     const struct option options[] = {
        { "description",        required_argument,      0,      'd' },
@@ -575,7 +575,7 @@ filter_undeletables(ProxySnapshots& snapshots, vector<ProxySnapshots::iterator>&
 
 
 void
-command_delete(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_delete(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     const struct option options[] = {
        { "sync",               no_argument,            0,      's' },
@@ -632,7 +632,7 @@ command_delete(cli::GlobalOptions* global_options, ProxySnappers* snappers, Prox
 
     filter_undeletables(snapshots, nums);
 
-    snapper->deleteSnapshots(nums, global_options->verbose());
+    snapper->deleteSnapshots(nums, global_options.verbose());
 
     if (sync)
        snapper->syncFilesystem();
@@ -649,7 +649,7 @@ help_mount()
 
 
 void
-command_mount(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_mount(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     getopts.parse("mount", GetOpts::no_options);
     if (!getopts.hasArgs())
@@ -678,7 +678,7 @@ help_umount()
 
 
 void
-command_umount(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_umount(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     getopts.parse("umount", GetOpts::no_options);
     if (!getopts.hasArgs())
@@ -710,7 +710,7 @@ help_status()
 
 
 void
-command_status(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_status(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     const struct option options[] = {
        { "output",             required_argument,      0,      'o' },
@@ -778,7 +778,7 @@ help_diff()
 
 
 void
-command_diff(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_diff(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     const struct option options[] = {
        { "input",              required_argument,      0,      'i' },
@@ -843,7 +843,7 @@ help_undo()
 
 
 void
-command_undo(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_undo(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     const struct option options[] = {
        { "input",              required_argument,      0,      'i' },
@@ -918,7 +918,7 @@ command_undo(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxyS
            exit(EXIT_FAILURE);
        }
 
-       if (global_options->verbose())
+       if (global_options.verbose())
        {
            switch (it1->action)
            {
@@ -997,7 +997,7 @@ help_rollback()
 
 
 void
-command_rollback(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_rollback(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     const struct option options[] = {
        { "print-number",       no_argument,            0,      'p' },
@@ -1046,7 +1046,7 @@ command_rollback(cli::GlobalOptions* global_options, ProxySnappers* snappers, Pr
 
     ProxyConfig config = snapper->getConfig();
 
-    const Filesystem* filesystem = getFilesystem(config, global_options->root());
+    const Filesystem* filesystem = getFilesystem(config, global_options.root());
     if (filesystem->fstype() != "btrfs")
     {
        cerr << _("Command 'rollback' only available for btrfs.") << endl;
@@ -1065,78 +1065,138 @@ command_rollback(cli::GlobalOptions* global_options, ProxySnappers* snappers, Pr
 
     ProxySnapshots::iterator previous_default = snapshots.getDefault();
 
+    if (global_options.ambit() == cli::GlobalOptions::Ambit::AUTO)
+    {
+       if (filesystem->isSnapshotReadOnly(previous_default->getNum()))
+           global_options.set_ambit(cli::GlobalOptions::Ambit::TRANSACTIONAL);
+       else
+           global_options.set_ambit(cli::GlobalOptions::Ambit::CLASSIC);
+    }
+
+    if (!global_options.quiet())
+       cout << sformat(_("Ambit is %s."), toString(global_options.ambit()).c_str()) << endl;
+
     if (previous_default != snapshots.end() && scd1.description == default_description1)
         scd1.description += sformat(" of #%d", previous_default->getNum());
 
-    ProxySnapshots::const_iterator snapshot1 = snapshots.end();
-    ProxySnapshots::const_iterator snapshot2 = snapshots.end();
-
-    if (getopts.numArgs() == 0)
+    switch (global_options.ambit())
     {
-       if (!global_options->quiet())
-           cout << _("Creating read-only snapshot of default subvolume.") << flush;
+       case cli::GlobalOptions::Ambit::CLASSIC:
+       {
+           ProxySnapshots::const_iterator snapshot1 = snapshots.end();
+           ProxySnapshots::const_iterator snapshot2 = snapshots.end();
 
-       scd1.read_only = true;
-       snapshot1 = snapper->createSingleSnapshotOfDefault(scd1);
+           if (getopts.numArgs() == 0)
+           {
+               if (!global_options.quiet())
+                   cout << _("Creating read-only snapshot of default subvolume.") << flush;
 
-       if (!global_options->quiet())
-           cout << " " << sformat(_("(Snapshot %d.)"), snapshot1->getNum()) << endl;
+               scd1.read_only = true;
+               snapshot1 = snapper->createSingleSnapshotOfDefault(scd1);
 
-       if (!global_options->quiet())
-           cout << _("Creating read-write snapshot of current subvolume.") << flush;
+               if (!global_options.quiet())
+                   cout << " " << sformat(_("(Snapshot %d.)"), snapshot1->getNum()) << endl;
 
-       ProxySnapshots::const_iterator active = snapshots.getActive();
-       if (active != snapshots.end() && scd2.description == default_description2)
-           scd2.description += sformat(" of #%d", active->getNum());
+               if (!global_options.quiet())
+                   cout << _("Creating read-write snapshot of current subvolume.") << flush;
 
-       scd2.read_only = false;
-       snapshot2 = snapper->createSingleSnapshot(snapshots.getCurrent(), scd2);
+               ProxySnapshots::const_iterator active = snapshots.getActive();
+               if (active != snapshots.end() && scd2.description == default_description2)
+                   scd2.description += sformat(" of #%d", active->getNum());
 
-       if (!global_options->quiet())
-           cout << " " << sformat(_("(Snapshot %d.)"), snapshot2->getNum()) << endl;
-    }
-    else
-    {
-       ProxySnapshots::const_iterator tmp = snapshots.findNum(getopts.popArg());
+               scd2.read_only = false;
+               snapshot2 = snapper->createSingleSnapshot(snapshots.getCurrent(), scd2);
 
-       if (!global_options->quiet())
-           cout << _("Creating read-only snapshot of current system.") << flush;
+               if (!global_options.quiet())
+                   cout << " " << sformat(_("(Snapshot %d.)"), snapshot2->getNum()) << endl;
+           }
+           else
+           {
+               ProxySnapshots::const_iterator tmp = snapshots.findNum(getopts.popArg());
 
-       snapshot1 = snapper->createSingleSnapshot(scd1);
+               if (!global_options.quiet())
+                   cout << _("Creating read-only snapshot of current system.") << flush;
 
-       if (!global_options->quiet())
-           cout << " " << sformat(_("(Snapshot %d.)"), snapshot1->getNum()) << endl;
+               snapshot1 = snapper->createSingleSnapshot(scd1);
 
-       if (!global_options->quiet())
-           cout << sformat(_("Creating read-write snapshot of snapshot %d."), tmp->getNum()) << flush;
+               if (!global_options.quiet())
+                   cout << " " << sformat(_("(Snapshot %d.)"), snapshot1->getNum()) << endl;
 
-       if (tmp != snapshots.end() && scd2.description == default_description2)
-           scd2.description += sformat(" of #%d", tmp->getNum());
+               if (!global_options.quiet())
+                   cout << sformat(_("Creating read-write snapshot of snapshot %d."), tmp->getNum()) << flush;
 
-       scd2.read_only = false;
-       snapshot2 = snapper->createSingleSnapshot(tmp, scd2);
+               if (tmp != snapshots.end() && scd2.description == default_description2)
+                   scd2.description += sformat(" of #%d", tmp->getNum());
 
-       if (!global_options->quiet())
-           cout << " " << sformat(_("(Snapshot %d.)"), snapshot2->getNum()) << endl;
-    }
+               scd2.read_only = false;
+               snapshot2 = snapper->createSingleSnapshot(tmp, scd2);
 
-    if (previous_default != snapshots.end() && previous_default->getCleanup().empty())
-    {
-       SMD smd = previous_default->getSmd();
-       smd.cleanup = "number";
-       snapper->modifySnapshot(previous_default, smd);
-    }
+               if (!global_options.quiet())
+                   cout << " " << sformat(_("(Snapshot %d.)"), snapshot2->getNum()) << endl;
+           }
+
+           if (previous_default != snapshots.end() && previous_default->getCleanup().empty())
+           {
+               SMD smd = previous_default->getSmd();
+               smd.cleanup = "number";
+               snapper->modifySnapshot(previous_default, smd);
+           }
 
-    if (!global_options->quiet())
-       cout << sformat(_("Setting default subvolume to snapshot %d."), snapshot2->getNum()) << endl;
+           if (!global_options.quiet())
+               cout << sformat(_("Setting default subvolume to snapshot %d."), snapshot2->getNum()) << endl;
 
-    filesystem->setDefault(snapshot2->getNum());
+           filesystem->setDefault(snapshot2->getNum());
 
-    Hooks::rollback(filesystem->snapshotDir(snapshot1->getNum()),
-                   filesystem->snapshotDir(snapshot2->getNum()));
+           Hooks::rollback(filesystem->snapshotDir(snapshot1->getNum()),
+                           filesystem->snapshotDir(snapshot2->getNum()));
 
-    if (print_number)
-       cout << snapshot2->getNum() << endl;
+           if (print_number)
+               cout << snapshot2->getNum() << endl;
+       }
+       break;
+
+       case cli::GlobalOptions::Ambit::TRANSACTIONAL:
+       {
+           // see bsc #1172273
+
+           ProxySnapshots::iterator snapshot = snapshots.end();
+
+           if (getopts.numArgs() == 0)
+           {
+               snapshot = snapshots.getActive();
+           }
+           else
+           {
+               snapshot = snapshots.findNum(getopts.popArg());
+           }
+
+           if (previous_default == snapshot)
+           {
+               cerr << _("Active snapshot is already default snapshot.") << endl;
+               exit(EXIT_FAILURE);
+           }
+
+           SMD smd = snapshot->getSmd();
+           smd.cleanup = "";
+           snapper->modifySnapshot(snapshot, smd);
+
+           if (!global_options.quiet())
+               cout << sformat(_("Setting default subvolume to snapshot %d."), snapshot->getNum()) << endl;
+
+           filesystem->setDefault(snapshot->getNum());
+
+           Hooks::rollback(filesystem->snapshotDir(previous_default->getNum()),
+                           filesystem->snapshotDir(snapshot->getNum()));
+       }
+       break;
+
+       case cli::GlobalOptions::Ambit::AUTO:
+       {
+           cerr << "internal error: ambit is auto" << endl;
+           exit(EXIT_FAILURE);
+       }
+       break;
+    }
 }
 
 #endif
@@ -1152,7 +1212,7 @@ help_setup_quota()
 
 
 void
-command_setup_quota(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_setup_quota(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     GetOpts::parsed_opts opts = getopts.parse("setup-quota", GetOpts::no_options);
     if (getopts.numArgs() != 0)
@@ -1175,7 +1235,7 @@ help_cleanup()
 
 
 void
-command_cleanup(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_cleanup(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     GetOpts::parsed_opts opts = getopts.parse("cleanup", GetOpts::no_options);
     if (getopts.numArgs() != 1)
@@ -1188,15 +1248,15 @@ command_cleanup(cli::GlobalOptions* global_options, ProxySnappers* snappers, Pro
 
     if (cleanup == "number")
     {
-       do_cleanup_number(snapper, global_options->verbose());
+       do_cleanup_number(snapper, global_options.verbose());
     }
     else if (cleanup == "timeline")
     {
-       do_cleanup_timeline(snapper, global_options->verbose());
+       do_cleanup_timeline(snapper, global_options.verbose());
     }
     else if (cleanup == "empty-pre-post")
     {
-       do_cleanup_empty_pre_post(snapper, global_options->verbose());
+       do_cleanup_empty_pre_post(snapper, global_options.verbose());
     }
     else
     {
@@ -1213,7 +1273,7 @@ help_debug()
 
 
 void
-command_debug(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper*)
+command_debug(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper*)
 {
     getopts.parse("debug", GetOpts::no_options);
     if (getopts.hasArgs())
@@ -1257,7 +1317,7 @@ print_xa_diff(const string loc_pre, const string loc_post)
 }
 
 void
-command_xa_diff(cli::GlobalOptions* global_options, ProxySnappers* snappers, ProxySnapper* snapper)
+command_xa_diff(cli::GlobalOptions& global_options, ProxySnappers* snappers, ProxySnapper* snapper)
 {
     GetOpts::parsed_opts opts = getopts.parse("xadiff", GetOpts::no_options);
     if (getopts.numArgs() < 1)
@@ -1390,161 +1450,169 @@ main(int argc, char** argv)
        Cmd("debug", command_debug, help_debug, false)
     };
 
-    getopts.init(argc, argv);
-
-    cli::GlobalOptions global_options(getopts);
-
-    if (global_options.has_errors())
+    try
     {
-       cerr << global_options.errors().front() << endl;
+       getopts.init(argc, argv);
 
-       exit(EXIT_FAILURE);
-    }
+       cli::GlobalOptions global_options(getopts);
 
-    if (global_options.version())
-    {
-       cout << "snapper " << Snapper::compileVersion() << endl;
-       cout << "flags " << Snapper::compileFlags() << endl;
-       exit(EXIT_SUCCESS);
-    }
+       if (global_options.version())
+       {
+           cout << "snapper " << Snapper::compileVersion() << endl;
+           cout << "flags " << Snapper::compileFlags() << endl;
+           exit(EXIT_SUCCESS);
+       }
 
-    if (global_options.help())
-    {
-       help(cmds);
-    }
+       if (global_options.help())
+       {
+           help(cmds);
+       }
 
-    if (!getopts.hasArgs())
-    {
-       cerr << _("No command provided.") << endl
-            << _("Try 'snapper --help' for more information.") << endl;
-       exit(EXIT_FAILURE);
-    }
+       if (!getopts.hasArgs())
+       {
+           cerr << _("No command provided.") << endl
+                << _("Try 'snapper --help' for more information.") << endl;
+           exit(EXIT_FAILURE);
+       }
 
-    const char* command = getopts.popArg();
+       const char* command = getopts.popArg();
 
-    list<Cmd>::const_iterator cmd = cmds.begin();
-    while (cmd != cmds.end() && (cmd->name != command && !contains(cmd->aliases, command)))
-       ++cmd;
+       list<Cmd>::const_iterator cmd = cmds.begin();
+       while (cmd != cmds.end() && (cmd->name != command && !contains(cmd->aliases, command)))
+           ++cmd;
 
-    if (cmd == cmds.end())
-    {
-       cerr << sformat(_("Unknown command '%s'."), command) << endl
-            << _("Try 'snapper --help' for more information.") << endl;
-       exit(EXIT_FAILURE);
-    }
+       if (cmd == cmds.end())
+       {
+           cerr << sformat(_("Unknown command '%s'."), command) << endl
+                << _("Try 'snapper --help' for more information.") << endl;
+           exit(EXIT_FAILURE);
+       }
 
-    try
-    {
-       ProxySnappers snappers(global_options.no_dbus() ? ProxySnappers::createLib(global_options.root()) :
-                              ProxySnappers::createDbus());
+       try
+       {
+           ProxySnappers snappers(global_options.no_dbus() ? ProxySnappers::createLib(global_options.root()) :
+                                  ProxySnappers::createDbus());
 
-       if (cmd->needs_snapper)
-           (*cmd->cmd_func)(&global_options, &snappers, snappers.getSnapper(global_options.config()));
-       else
-           (*cmd->cmd_func)(&global_options, &snappers, nullptr);
-    }
-    catch (const DBus::ErrorException& e)
-    {
-       SN_CAUGHT(e);
+           if (cmd->needs_snapper)
+               (*cmd->cmd_func)(global_options, &snappers, snappers.getSnapper(global_options.config()));
+           else
+               (*cmd->cmd_func)(global_options, &snappers, nullptr);
+       }
+       catch (const DBus::ErrorException& e)
+       {
+           SN_CAUGHT(e);
+
+           if (strcmp(e.name(), "error.unknown_config") == 0 && global_options.config() == "root")
+           {
+               cerr << _("The config 'root' does not exist. Likely snapper is not configured.") << endl
+                    << _("See 'man snapper' for further instructions.") << endl;
+               exit(EXIT_FAILURE);
+           }
 
-       if (strcmp(e.name(), "error.unknown_config") == 0 && global_options.config() == "root")
+           cerr << error_description(e) << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const DBus::FatalException& e)
        {
-           cerr << _("The config 'root' does not exist. Likely snapper is not configured.") << endl
-                << _("See 'man snapper' for further instructions.") << endl;
+           SN_CAUGHT(e);
+           cerr << _("Failure") << " (" << e.what() << ")." << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const IllegalSnapshotException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << _("Illegal snapshot.") << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const ConfigNotFoundException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << sformat(_("Config '%s' not found."), global_options.config().c_str()) << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const InvalidConfigException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << sformat(_("Config '%s' is invalid."), global_options.config().c_str()) << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const ListConfigsFailedException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << sformat(_("Listing configs failed (%s)."), e.what()) << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const CreateConfigFailedException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << sformat(_("Creating config failed (%s)."), e.what()) << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const DeleteConfigFailedException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << sformat(_("Deleting config failed (%s)."), e.what()) << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const InvalidConfigdataException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << _("Invalid configdata.") << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const AclException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << _("ACL error.") << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const IOErrorException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << sformat(_("IO error (%s)."), e.what()) << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const InvalidUserException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << _("Invalid user.") << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const InvalidGroupException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << _("Invalid group.") << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const QuotaException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << sformat(_("Quota error (%s)."), e.what()) << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const FreeSpaceException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << sformat(_("Free space error (%s)."), e.what()) << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const OptionsException& e)
+       {
+           SN_CAUGHT(e);
+           cerr << e.what() << endl;
+           exit(EXIT_FAILURE);
+       }
+       catch (const Exception& e)
+       {
+           SN_CAUGHT(e);
+           cerr << sformat(_("Error (%s)."), e.what()) << endl;
            exit(EXIT_FAILURE);
        }
-
-       cerr << error_description(e) << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const DBus::FatalException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << _("Failure") << " (" << e.what() << ")." << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const IllegalSnapshotException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << _("Illegal snapshot.") << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const ConfigNotFoundException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << sformat(_("Config '%s' not found."), global_options.config().c_str()) << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const InvalidConfigException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << sformat(_("Config '%s' is invalid."), global_options.config().c_str()) << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const ListConfigsFailedException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << sformat(_("Listing configs failed (%s)."), e.what()) << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const CreateConfigFailedException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << sformat(_("Creating config failed (%s)."), e.what()) << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const DeleteConfigFailedException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << sformat(_("Deleting config failed (%s)."), e.what()) << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const InvalidConfigdataException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << _("Invalid configdata.") << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const AclException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << _("ACL error.") << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const IOErrorException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << sformat(_("IO error (%s)."), e.what()) << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const InvalidUserException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << _("Invalid user.") << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const InvalidGroupException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << _("Invalid group.") << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const QuotaException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << sformat(_("Quota error (%s)."), e.what()) << endl;
-       exit(EXIT_FAILURE);
-    }
-    catch (const FreeSpaceException& e)
-    {
-       SN_CAUGHT(e);
-       cerr << sformat(_("Free space error (%s)."), e.what()) << endl;
-       exit(EXIT_FAILURE);
     }
-    catch (const Exception& e)
+    catch (const OptionsException& e)
     {
        SN_CAUGHT(e);
-       cerr << sformat(_("Error (%s)."), e.what()) << endl;
+       cerr << e.what() << endl;
        exit(EXIT_FAILURE);
     }
 
index 3e42ac08477d89260091b4b6c5070e2e31a1216a..bb7922c90c13322b89fde6e0123146e27a3b7ded 100644 (file)
@@ -2,13 +2,13 @@
 <refentry id='snapper8' xmlns:xlink="http://www.w3.org/1999/xlink">
 
   <refentryinfo>
-    <date>2019-10-14</date>
+    <date>2020-06-15</date>
   </refentryinfo>
 
   <refmeta>
     <refentrytitle>snapper</refentrytitle>
     <manvolnum>8</manvolnum>
-    <refmiscinfo class='date'>2019-10-14</refmiscinfo>
+    <refmiscinfo class='date'>2020-06-15</refmiscinfo>
     <refmiscinfo class='version'>@VERSION@</refmiscinfo>
     <refmiscinfo class='manual'>Filesystem Snapshot Management</refmiscinfo>
   </refmeta>
          <para>Operate on target root. Only works together with no-dbus and only for some commands.</para>
        </listitem>
       </varlistentry>
+      <varlistentry>
+       <term><option>-a, --ambit <replaceable>ambit</replaceable></option></term>
+       <listitem>
+         <para>Operate in the specified ambit. Can be used to override the ambit detection.
+         Allowed ambits are auto, classic and transactional.</para>
+       </listitem>
+      </varlistentry>
       <varlistentry>
        <term><option>--version</option></term>
        <listitem>
          <para>The rollback command also sets the description, the cleanup
          algorithm and some userdata unless the values are specified on the command
          line. This will automate cleanup of snapshots created by rollbacks.</para>
+         <para>In other ambits than classic the rollback command does what is required
+         to do a rollback. Anyway it is recommended to use specific programs in that
+         case.</para>
        </listitem>
       </varlistentry>
 
index 8b39b00c433e1c10bad4e7e5e734c278e279abc3..7b989949094f0299111cc502c6738db43ff9f3dc 100644 (file)
@@ -1,3 +1,9 @@
+-------------------------------------------------------------------
+Tue Jun 16 18:31:47 CEST 2020 - aschnell@suse.com
+
+- special rollback for transactional server (bsc#1172273)
+- version 0.8.10
+
 -------------------------------------------------------------------
 Mon Apr 06 16:22:29 CEST 2020 - aschnell@suse.com
 
index 7928b4058e20c1cf13a2b2a455610f57cb2d9302..519f4a42ebd082ef1a42d6df6f59660333d8a466 100644 (file)
@@ -63,7 +63,7 @@ namespace snapper
        if ((size_t)(value) >= names.size())
            throw OutOfRangeException();
 
-       return names[value];
+       return names[(size_t)(value)];
     }