--- /dev/null
+*.lo
+*.la
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#include <algorithm>
+
+#include <boost/algorithm/string.hpp>
+
+#include "client/Command/ColumnsOption.h"
+#include "client/utils/text.h"
+
+using namespace std;
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ 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())
+ {
+ if (wrong_column(column))
+ wrong.push_back(column);
+ }
+
+ return wrong;
+ }
+
+
+ bool Command::ColumnsOption::wrong_column(const std::string& column) const
+ {
+ return find(_all_columns.begin(), _all_columns.end(), column) == _all_columns.end();
+ }
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#ifndef SNAPPER_CLI_COMMAND_COLUMNS_OPTION_H
+#define SNAPPER_CLI_COMMAND_COLUMNS_OPTION_H
+
+#include <string>
+#include <vector>
+
+#include "client/Command.h"
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ class Command::ColumnsOption
+ {
+
+ public:
+
+ ColumnsOption(const std::vector<std::string>& all_columns) :
+ _all_columns(all_columns), _raw_columns()
+ {}
+
+ void set_raw_columns(const string& raw_columns)
+ {
+ _raw_columns = raw_columns;
+ }
+
+ 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;
+
+ };
+
+ }
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#include <iostream>
+
+#include "client/utils/text.h"
+#include "client/Command/ListSnapshots.h"
+#include "client/Command/ListSnapshots/Options.h"
+#include "client/Command/ListSnapshots/SnappersData/Table.h"
+#include "client/Command/ListSnapshots/SnappersData/Csv.h"
+#include "client/Command/ListSnapshots/SnappersData/Json.h"
+
+using namespace std;
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ string Command::ListSnapshots::help()
+ {
+ return
+ string(
+ _(" List snapshots:\n"
+ "\tsnapper list\n"
+ "\n")
+ ) + Options::help_text();
+ }
+
+
+ Command::ListSnapshots::ListSnapshots(const GlobalOptions& global_options,
+ GetOpts& options_parser, ProxySnappers& snappers) :
+ Command(global_options, options_parser, snappers), _options(new Options(options_parser))
+ {}
+
+
+ Command::ListSnapshots::ListSnapshots::~ListSnapshots()
+ {}
+
+
+ const Command::ListSnapshots::Options& Command::ListSnapshots::options() const
+ {
+ return *_options.get();
+ }
+
+
+ vector<string> Command::ListSnapshots::errors() const
+ {
+ return options().errors();
+ }
+
+
+ void Command::ListSnapshots::run()
+ {
+ if (_options_parser.hasArgs())
+ {
+ cerr << _("Command 'list' does not take arguments.") << endl;
+ exit(EXIT_FAILURE);
+ }
+
+ if (options().has_errors())
+ {
+ cerr << options().errors().front() << endl;
+ exit(EXIT_FAILURE);
+ }
+
+ string output;
+
+ switch (global_options().output_format())
+ {
+ case GlobalOptions::OutputFormat::TABLE:
+ {
+ SnappersData::Table table(*this, global_options().table_style());
+ output = table.output();
+ }
+ break;
+
+ case GlobalOptions::OutputFormat::CSV:
+ {
+ SnappersData::Csv csv(*this, global_options().separator());
+ output = csv.output();
+ }
+ break;
+
+ case GlobalOptions::OutputFormat::JSON:
+ {
+ SnappersData::Json json(*this);
+ output = json.output() + "\n";
+ }
+ break;
+ }
+
+ cout << output;
+ }
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#ifndef SNAPPER_CLI_COMMAND_LIST_SNAPSHOTS_H
+#define SNAPPER_CLI_COMMAND_LIST_SNAPSHOTS_H
+
+#include <memory>
+
+#include "client/Command.h"
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ class Command::ListSnapshots : public Command
+ {
+
+ public:
+
+ class Options;
+
+ class ColumnsOption;
+
+ class SnappersData;
+
+ static std::string help();
+
+ ListSnapshots(const GlobalOptions& global_options, GetOpts& options_parser,
+ ProxySnappers& snappers);
+
+ const Options& options() const;
+
+ virtual std::vector<std::string> errors() const override;
+
+ virtual void run() override;
+
+ virtual ~ListSnapshots();
+
+ private:
+
+ std::unique_ptr<Options> _options;
+ };
+
+ }
+}
+
+#endif
--- /dev/null
+#
+# Makefile.am for snapper/client/Command/ListSnapshots
+#
+
+SUBDIRS = SnappersData
+
+AM_CPPFLAGS = -I$(top_srcdir) $(DBUS_CFLAGS)
+
+noinst_LTLIBRARIES = libcommandlistsnapshots.la
+
+libcommandlistsnapshots_la_SOURCES = \
+ Options.cc Options.h \
+ SnappersData.cc SnappersData.h
+
+libcommandlistsnapshots_la_LIBADD = \
+ ../../../snapper/libsnapper.la \
+ ../../utils/libutils.la \
+ ../../../dbus/libdbus.la \
+ SnappersData/libcommandlistsnapshotssnappersdata.la
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#include <stdexcept>
+
+#include <boost/algorithm/string.hpp>
+
+#include "client/Command/ListSnapshots/Options.h"
+#include "client/utils/text.h"
+
+using namespace std;
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ namespace
+ {
+ const option OPTIONS[] = {
+ { "type", required_argument, 0, 't' },
+ { "disable-used-space", no_argument, 0, 0 },
+ { "all-configs", no_argument, 0, 'a' },
+ { "columns", required_argument, 0, 0},
+ { 0, 0, 0, 0 }
+ };
+ }
+
+
+ string Command::ListSnapshots::Options::help_text()
+ {
+ return _(" Options for 'list' command:\n"
+ "\t--type, -t <type>\t\tType of snapshots to list.\n"
+ "\t--disable-used-space\t\tDisable showing used space.\n"
+ "\t--all-configs, -a\t\tList snapshots from all accessible configs.\n"
+ "\t--columns <columns>\t\tColumns to show separated by comma.\n"
+ "\t\t\t\t\tPossible columns: config, subvolume, number, default, active,\n"
+ "\t\t\t\t\ttype, date, user, used-space, cleanup, description, userdata,\n"
+ "\t\t\t\t\tpre-number, post-number, post-date.\n");
+ }
+
+
+ const string Command::ListSnapshots::Options::Columns::CONFIG = "config";
+ const string Command::ListSnapshots::Options::Columns::SUBVOLUME = "subvolume";
+ const string Command::ListSnapshots::Options::Columns::NUMBER = "number";
+ const string Command::ListSnapshots::Options::Columns::DEFAULT = "default";
+ const string Command::ListSnapshots::Options::Columns::ACTIVE = "active";
+ const string Command::ListSnapshots::Options::Columns::TYPE = "type";
+ const string Command::ListSnapshots::Options::Columns::DATE = "date";
+ const string Command::ListSnapshots::Options::Columns::USER = "user";
+ const string Command::ListSnapshots::Options::Columns::USED_SPACE = "used-space";
+ const string Command::ListSnapshots::Options::Columns::CLEANUP = "cleanup";
+ const string Command::ListSnapshots::Options::Columns::DESCRIPTION = "description";
+ const string Command::ListSnapshots::Options::Columns::USERDATA = "userdata";
+ const string Command::ListSnapshots::Options::Columns::PRE_NUMBER = "pre-number";
+ const string Command::ListSnapshots::Options::Columns::POST_NUMBER = "post-number";
+ const string Command::ListSnapshots::Options::Columns::POST_DATE = "post-date";
+
+
+ const vector<string> Command::ListSnapshots::Options::ALL_COLUMNS = {
+ Columns::CONFIG,
+ Columns::SUBVOLUME,
+ Columns::NUMBER,
+ Columns::DEFAULT,
+ Columns::ACTIVE,
+ Columns::TYPE,
+ Columns::DATE,
+ Columns::USER,
+ Columns::USED_SPACE,
+ Columns::CLEANUP,
+ Columns::DESCRIPTION,
+ Columns::USERDATA,
+ Columns::PRE_NUMBER,
+ Columns::POST_NUMBER,
+ Columns::POST_DATE
+ };
+
+
+ Command::ListSnapshots::Options::Options(GetOpts& parser) :
+ cli::Options(parser), _columns_option(ALL_COLUMNS)
+ {
+ parse_options();
+
+ _disable_used_space = has_option("disable-used-space");
+ _all_configs = has_option("all-configs");
+ _list_mode = list_mode_value();
+
+ _columns_option.set_raw_columns(columns_raw());
+ }
+
+
+ void Command::ListSnapshots::Options::parse_options()
+ {
+ _options = _parser.parse("list", OPTIONS);
+ }
+
+
+ vector<string>
+ Command::ListSnapshots::Options::columns(GlobalOptions::OutputFormat format) const
+ {
+ if (has_option("columns"))
+ return _columns_option.selected_columns();
+
+ return list_mode_columns(format);
+ }
+
+
+ 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 (type == "all")
+ return LM_ALL;
+
+ if (type == "single")
+ return LM_SINGLE;
+
+ if (type == "pre-post")
+ return LM_PRE_POST;
+
+ return LM_ALL;
+ }
+
+
+ string Command::ListSnapshots::Options::columns_raw() const
+ {
+ return has_option("columns") ? get_option("columns")->second : "";
+ }
+
+
+ vector<string>
+ Command::ListSnapshots::Options::list_mode_columns(GlobalOptions::OutputFormat format) const
+ {
+ vector<string> columns;
+
+ switch (list_mode())
+ {
+ case LM_ALL:
+ columns = all_mode_columns(format);
+ break;
+
+ case LM_SINGLE:
+ columns = single_mode_columns(format);
+ break;
+
+ case LM_PRE_POST:
+ columns = pre_post_mode_columns(format);
+ break;
+ }
+
+ if (disable_used_space())
+ {
+ columns.erase(
+ remove(columns.begin(), columns.end(), Columns::USED_SPACE), columns.end());
+ }
+
+ return columns;
+ }
+
+
+ vector<string>
+ Command::ListSnapshots::Options::all_mode_columns(GlobalOptions::OutputFormat format) const
+ {
+ if (format == GlobalOptions::OutputFormat::TABLE)
+ return {
+ Columns::NUMBER,
+ Columns::TYPE,
+ Columns::PRE_NUMBER,
+ Columns::DATE,
+ Columns::USER,
+ Columns::USED_SPACE,
+ Columns::CLEANUP,
+ Columns::DESCRIPTION,
+ Columns::USERDATA
+ };
+
+ if (format == GlobalOptions::OutputFormat::CSV)
+ return {
+ Columns::CONFIG,
+ Columns::SUBVOLUME,
+ Columns::NUMBER,
+ Columns::DEFAULT,
+ Columns::ACTIVE,
+ Columns::TYPE,
+ Columns::PRE_NUMBER,
+ Columns::DATE,
+ Columns::USER,
+ Columns::USED_SPACE,
+ Columns::CLEANUP,
+ Columns::DESCRIPTION,
+ Columns::USERDATA
+ };
+
+ if (format == GlobalOptions::OutputFormat::JSON)
+ return {
+ Columns::SUBVOLUME,
+ Columns::NUMBER,
+ Columns::DEFAULT,
+ Columns::ACTIVE,
+ Columns::TYPE,
+ Columns::PRE_NUMBER,
+ Columns::DATE,
+ Columns::USER,
+ Columns::USED_SPACE,
+ Columns::CLEANUP,
+ Columns::DESCRIPTION,
+ Columns::USERDATA
+ };
+
+ throw logic_error("unknown output format");
+ }
+
+
+ vector<string>
+ Command::ListSnapshots::Options::single_mode_columns(GlobalOptions::OutputFormat format) const
+ {
+ if (format == GlobalOptions::OutputFormat::TABLE)
+ return {
+ Columns::NUMBER,
+ Columns::DATE,
+ Columns::USER,
+ Columns::USED_SPACE,
+ Columns::DESCRIPTION,
+ Columns::USERDATA
+ };
+
+ if (format == GlobalOptions::OutputFormat::CSV)
+ return {
+ Columns::CONFIG,
+ Columns::SUBVOLUME,
+ Columns::NUMBER,
+ Columns::DEFAULT,
+ Columns::ACTIVE,
+ Columns::DATE,
+ Columns::USER,
+ Columns::USED_SPACE,
+ Columns::DESCRIPTION,
+ Columns::USERDATA
+ };
+
+ if (format == GlobalOptions::OutputFormat::JSON)
+ return {
+ Columns::SUBVOLUME,
+ Columns::NUMBER,
+ Columns::DEFAULT,
+ Columns::ACTIVE,
+ Columns::DATE,
+ Columns::USER,
+ Columns::USED_SPACE,
+ Columns::DESCRIPTION,
+ Columns::USERDATA
+ };
+
+ throw logic_error("unknown output format");
+ }
+
+
+ vector<string>
+ Command::ListSnapshots::Options::pre_post_mode_columns(GlobalOptions::OutputFormat format) const
+ {
+ if (format == GlobalOptions::OutputFormat::TABLE)
+ return {
+ Columns::NUMBER,
+ Columns::POST_NUMBER,
+ Columns::DATE,
+ Columns::POST_DATE,
+ Columns::DESCRIPTION,
+ Columns::USERDATA
+ };
+
+ if (format == GlobalOptions::OutputFormat::CSV)
+ return {
+ Columns::CONFIG,
+ Columns::SUBVOLUME,
+ Columns::NUMBER,
+ Columns::DEFAULT,
+ Columns::ACTIVE,
+ Columns::POST_NUMBER,
+ Columns::DATE,
+ Columns::POST_DATE,
+ Columns::DESCRIPTION,
+ Columns::USERDATA
+ };
+
+ if (format == GlobalOptions::OutputFormat::JSON)
+ return {
+ Columns::SUBVOLUME,
+ Columns::NUMBER,
+ Columns::DEFAULT,
+ Columns::ACTIVE,
+ Columns::POST_NUMBER,
+ Columns::DATE,
+ Columns::POST_DATE,
+ Columns::DESCRIPTION,
+ Columns::USERDATA
+ };
+
+ 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.");
+ }
+
+
+ string Command::ListSnapshots::Options::columns_error() const
+ {
+ return _columns_option.error();
+ }
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#ifndef SNAPPER_CLI_COMMAND_LIST_SNAPSHOTS_OPTIONS_H
+#define SNAPPER_CLI_COMMAND_LIST_SNAPSHOTS_OPTIONS_H
+
+#include "client/Options.h"
+#include "client/GlobalOptions.h"
+#include "client/Command/ColumnsOption.h"
+#include "client/Command/ListSnapshots.h"
+#include "client/Command/ListSnapshots/SnappersData.h"
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ class Command::ListSnapshots::Options : public cli::Options
+ {
+
+ public:
+
+ struct Columns
+ {
+ static const std::string CONFIG;
+ static const std::string SUBVOLUME;
+ static const std::string NUMBER;
+ static const std::string DEFAULT;
+ static const std::string ACTIVE;
+ static const std::string TYPE;
+ static const std::string DATE;
+ static const std::string USER;
+ static const std::string USED_SPACE;
+ static const std::string CLEANUP;
+ static const std::string DESCRIPTION;
+ static const std::string USERDATA;
+ static const std::string PRE_NUMBER;
+ static const std::string POST_NUMBER;
+ static const std::string POST_DATE;
+ };
+
+ static const std::vector<std::string> ALL_COLUMNS;
+
+ enum ListMode { LM_ALL, LM_SINGLE, LM_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;
+ }
+
+ std::vector<std::string> columns(GlobalOptions::OutputFormat format) const;
+
+ virtual std::vector<std::string> errors() const override;
+
+ private:
+
+ void parse_options();
+
+ ListMode list_mode_value() const;
+
+ string columns_raw() const;
+
+ std::vector<std::string> list_mode_columns(GlobalOptions::OutputFormat format) const;
+
+ std::vector<std::string> all_mode_columns(GlobalOptions::OutputFormat format) const;
+
+ std::vector<std::string> single_mode_columns(GlobalOptions::OutputFormat format) const;
+
+ 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;
+
+ bool _all_configs;
+
+ Command::ColumnsOption _columns_option;
+
+ };
+
+ }
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#include <algorithm>
+#include <string.h>
+#include <time.h>
+#include <dbus/DBusMessage.h>
+
+#include <snapper/Snapper.h>
+#include <snapper/Exception.h>
+#include <snapper/SnapperTmpl.h>
+#include <snapper/Snapshot.h>
+#include <snapper/Enum.h>
+
+#include "client/Command/ListSnapshots/SnappersData.h"
+#include "client/Command/ListSnapshots/Options.h"
+#include "client/utils/HumanString.h"
+#include "client/misc.h"
+
+using namespace std;
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ Command::ListSnapshots::SnappersData::SnappersData(const Command::ListSnapshots& command) :
+ _command(command)
+ {
+ calculate_used_space();
+ }
+
+
+ Command::ListSnapshots::SnappersData::~SnappersData()
+ {}
+
+
+ vector<ProxySnapper*> Command::ListSnapshots::SnappersData::snappers() const
+ {
+ vector<ProxySnapper*> snappers;
+
+ for (auto config_name : configs())
+ {
+ ProxySnapper* snapper = command().snappers().getSnapper(config_name);
+
+ snappers.push_back(snapper);
+ }
+
+ return snappers;
+ }
+
+
+ vector<const ProxySnapshot*>
+ Command::ListSnapshots::SnappersData::selected_snapshots(const ProxySnapper* snapper) const
+ {
+ const ProxySnapshots& snapshots = this->snapshots(snapper);
+
+ vector<const ProxySnapshot*> selected;
+
+ for (const ProxySnapshot& snapshot : snapshots)
+ {
+ switch (command().options().list_mode())
+ {
+ case Options::ListMode::LM_ALL:
+ {
+ selected.push_back(&snapshot);
+ }
+ break;
+
+ case Options::ListMode::LM_SINGLE:
+ {
+ if (snapshot.getType() == SINGLE)
+ selected.push_back(&snapshot);
+ }
+ break;
+
+ case Options::ListMode::LM_PRE_POST:
+ {
+ ProxySnapshots::const_iterator post_it = find_post(snapshot, snapshots);
+
+ if (post_it != snapshots.end())
+ selected.push_back(&snapshot);
+ }
+ break;
+ }
+ }
+
+ return selected;
+ }
+
+
+ vector<string>
+ Command::ListSnapshots::SnappersData::selected_columns() const
+ {
+ return command().options().columns(command().global_options().output_format());
+ }
+
+
+ string Command::ListSnapshots::SnappersData::value_for(const string& column,
+ const ProxySnapshot& snapshot,
+ const ProxySnapshots& snapshots,
+ const ProxySnapper* snapper) const
+ {
+ if (column == Options::Columns::CONFIG)
+ return config_value(snapper);
+
+ if (column == Options::Columns::SUBVOLUME)
+ return subvolume_value(snapper);
+
+ if (column == Options::Columns::NUMBER)
+ return number_value(snapshot, snapshots);
+
+ if (column == Options::Columns::DEFAULT)
+ return default_value(snapshot, snapshots);
+
+ if (column == Options::Columns::ACTIVE)
+ return active_value(snapshot, snapshots);
+
+ if (column == Options::Columns::TYPE)
+ return type_value(snapshot);
+
+ if (column == Options::Columns::DATE)
+ return date_value(snapshot);
+
+ if (column == Options::Columns::USER)
+ return user_value(snapshot);
+
+ if (column == Options::Columns::USED_SPACE)
+ return used_space_value(snapshot, snapper);
+
+ if (column == Options::Columns::CLEANUP)
+ return cleanup_value(snapshot);
+
+ if (column == Options::Columns::DESCRIPTION)
+ return description_value(snapshot);
+
+ if (column == Options::Columns::USERDATA)
+ return userdata_value(snapshot);
+
+ if (column == Options::Columns::PRE_NUMBER)
+ return pre_number_value(snapshot);
+
+ if (column == Options::Columns::POST_NUMBER)
+ return post_number_value(snapshot, snapshots);
+
+ if (column == Options::Columns::POST_DATE)
+ return post_date_value(snapshot, snapshots);
+
+ return "";
+ }
+
+
+ vector<string> Command::ListSnapshots::SnappersData::configs() const
+ {
+ vector<string> names;
+
+ if (!command().options().all_configs())
+ {
+ names.push_back(command().global_options().config());
+ }
+ else
+ {
+ map<string, ProxyConfig> configs = command().snappers().getConfigs();
+
+ for (map<string, ProxyConfig>::value_type it : configs)
+ names.push_back(it.first);
+ }
+
+ return names;
+ }
+
+
+ const ProxySnapshots&
+ Command::ListSnapshots::SnappersData::snapshots(const ProxySnapper* snapper) const
+ {
+ return snapper->getSnapshots();
+ }
+
+
+ bool
+ Command::ListSnapshots::SnappersData::calculated_used_space(const ProxySnapper* snapper) const
+ {
+ map<const ProxySnapper*, bool>::const_iterator it = _calculated_used_space.find(snapper);
+
+ if (it == _calculated_used_space.end())
+ return false;
+
+ return it->second;
+ }
+
+
+ void Command::ListSnapshots::SnappersData::calculate_used_space()
+ {
+ for (ProxySnapper* snapper : snappers())
+ calculate_used_space(snapper);
+ }
+
+
+ void
+ Command::ListSnapshots::SnappersData::calculate_used_space(ProxySnapper* snapper)
+ {
+ bool calculated;
+
+ if (!need_used_space())
+ {
+ calculated = false;
+ }
+ else
+ {
+ try
+ {
+ snapper->calculateUsedSpace();
+
+ calculated = true;
+ }
+ catch (const QuotaException& e)
+ {
+ SN_CAUGHT(e);
+
+ calculated = false;
+ }
+ }
+
+ _calculated_used_space[snapper] = calculated;
+ }
+
+
+ bool Command::ListSnapshots::SnappersData::need_used_space() const
+ {
+ vector<string> columns = selected_columns();
+
+ vector<string>::iterator it =
+ find(columns.begin(), columns.end(), Options::Columns::USED_SPACE);
+
+ return it != columns.end();
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::config_value(const ProxySnapper* snapper) const
+ {
+ return snapper->configName();
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::subvolume_value(const ProxySnapper* snapper) const
+ {
+ return snapper->getConfig().getSubvolume();
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::number_value(const ProxySnapshot& snapshot,
+ const ProxySnapshots& snapshots) const
+ {
+ return decString(snapshot.getNum());
+ }
+
+
+ string Command::ListSnapshots::SnappersData::default_value(const ProxySnapshot& snapshot,
+ const ProxySnapshots& snapshots) const
+ {
+ return boolean_text(is_default_snapshot(snapshot, snapshots));
+ }
+
+
+ string Command::ListSnapshots::SnappersData::active_value(const ProxySnapshot& snapshot,
+ const ProxySnapshots& snapshots) const
+ {
+ return boolean_text(is_active_snapshot(snapshot, snapshots));
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::date_value(const ProxySnapshot& snapshot) const
+ {
+ if (command().options().list_mode() == Options::ListMode::LM_PRE_POST)
+ return snapshot_date(snapshot);
+
+ return snapshot.isCurrent() ? "" : snapshot_date(snapshot);
+ }
+
+ string
+ Command::ListSnapshots::SnappersData::type_value(const ProxySnapshot& snapshot) const
+ {
+ return toString(snapshot.getType());
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::user_value(const ProxySnapshot& snapshot) const
+ {
+ return username(snapshot.getUid());
+ }
+
+
+ string Command::ListSnapshots::SnappersData::used_space_value(
+ const ProxySnapshot& snapshot, const ProxySnapper* snapper) const
+ {
+ if (!calculated_used_space(snapper))
+ return "";
+
+ return snapshot.isCurrent() ? "" : snapshot_used_value(snapshot);
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::cleanup_value(const ProxySnapshot& snapshot) const
+ {
+ return snapshot.getCleanup();
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::description_value(const ProxySnapshot& snapshot) const
+ {
+ return snapshot.getDescription();
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::userdata_value(const ProxySnapshot& snapshot) const
+ {
+ return show_userdata(snapshot.getUserdata());
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::pre_number_value(const ProxySnapshot& snapshot) const
+ {
+ return snapshot.getType() == POST ? decString(snapshot.getPreNum()) : "";
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::post_number_value(const ProxySnapshot& snapshot,
+ const ProxySnapshots& snapshots) const
+ {
+ ProxySnapshots::const_iterator post_it = find_post(snapshot, snapshots);
+
+ if (post_it == snapshots.end())
+ return "";
+
+ return number_value(*post_it, snapshots);
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::post_date_value(const ProxySnapshot& snapshot,
+ const ProxySnapshots& snapshots) const
+ {
+ ProxySnapshots::const_iterator post_it = find_post(snapshot, snapshots);
+
+ if (post_it == snapshots.end())
+ return "";
+
+ return snapshot_date(*post_it);
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::snapshot_date(const ProxySnapshot& snapshot) const
+ {
+ bool iso = command().global_options().iso();
+
+ if (command().global_options().output_format() != GlobalOptions::OutputFormat::TABLE)
+ iso = true;
+
+ return datetime(snapshot.getDate(), command().global_options().utc(), iso);
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::snapshot_used_value(const ProxySnapshot& snapshot) const
+ {
+ uint64_t used_space = snapshot.getUsedSpace();
+
+ if (command().global_options().output_format() == GlobalOptions::OutputFormat::TABLE)
+ return byte_to_humanstring(used_space, 2);
+ else
+ return to_string(used_space);
+ }
+
+
+ bool
+ Command::ListSnapshots::SnappersData::is_default_snapshot(const ProxySnapshot& snapshot,
+ const ProxySnapshots& snapshots) const
+ {
+ auto default_snapshot = this->default_snapshot(snapshots);
+
+ return default_snapshot != snapshots.end() &&
+ default_snapshot->getNum() == snapshot.getNum();
+ }
+
+
+ bool
+ Command::ListSnapshots::SnappersData::is_active_snapshot(const ProxySnapshot& snapshot,
+ const ProxySnapshots& snapshots) const
+ {
+ auto active_snapshot = this->active_snapshot(snapshots);
+
+ return active_snapshot != snapshots.end() &&
+ active_snapshot->getNum() == snapshot.getNum();
+ }
+
+
+ ProxySnapshots::const_iterator
+ Command::ListSnapshots::SnappersData::default_snapshot(const ProxySnapshots& snapshots) const
+ {
+ try
+ {
+ return snapshots.getDefault();
+ }
+ catch (const DBus::ErrorException& e)
+ {
+ SN_CAUGHT(e);
+
+ // If snapper was just updated and the old snapperd is still
+ // running it might not know the GetDefaultSnapshot method.
+
+ if (strcmp(e.name(), "error.unknown_method") != 0)
+ SN_RETHROW(e);
+
+ return snapshots.end();
+ }
+ }
+
+
+ ProxySnapshots::const_iterator
+ Command::ListSnapshots::SnappersData::active_snapshot(const ProxySnapshots& snapshots) const
+ {
+ try
+ {
+ return snapshots.getActive();
+ }
+ catch (const DBus::ErrorException& e)
+ {
+ SN_CAUGHT(e);
+
+ // If snapper was just updated and the old snapperd is still
+ // running it might not know the GetActiveSnapshot method.
+
+ if (strcmp(e.name(), "error.unknown_method") != 0)
+ SN_RETHROW(e);
+
+ return snapshots.end();
+ }
+ }
+
+
+ ProxySnapshots::const_iterator Command::ListSnapshots::SnappersData::find_post(
+ const ProxySnapshot& snapshot, const ProxySnapshots& snapshots) const
+ {
+ if (snapshot.getType() != SnapshotType::PRE)
+ return snapshots.end();
+
+ ProxySnapshots::const_iterator it = snapshots.find(snapshot.getNum());
+ ProxySnapshots::const_iterator post_it = snapshots.findPost(it);
+
+ if (post_it == snapshots.end())
+ return snapshots.end();
+
+ return post_it;
+ }
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#ifndef SNAPPER_CLI_COMMAND_LIST_SNAPSHOTS_SNAPPERS_DATA_H
+#define SNAPPER_CLI_COMMAND_LIST_SNAPSHOTS_SNAPPERS_DATA_H
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "client/Command/ListSnapshots.h"
+#include "client/proxy.h"
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ class Command::ListSnapshots::SnappersData
+ {
+
+ public:
+
+ class Table;
+
+ class Csv;
+
+ class Json;
+
+ SnappersData(const Command::ListSnapshots& command);
+
+ virtual ~SnappersData();
+
+ virtual std::string output() const = 0;
+
+ protected:
+
+ const ListSnapshots& command() const
+ {
+ return _command;
+ }
+
+ std::vector<ProxySnapper*> snappers() const;
+
+ vector<const ProxySnapshot*> selected_snapshots(const ProxySnapper* snapper) const;
+
+ std::vector<std::string> selected_columns() const;
+
+ std::string value_for(const string& column,
+ const ProxySnapshot& snapshot, const ProxySnapshots& snapshots,
+ const ProxySnapper* snapper) const;
+
+ private:
+
+ std::vector<std::string> configs() const;
+
+ const ProxySnapshots& snapshots(const ProxySnapper* snapper) const;
+
+ bool calculated_used_space(const ProxySnapper* snapper) const;
+
+ void calculate_used_space();
+
+ void calculate_used_space(ProxySnapper* snapper);
+
+ bool need_used_space() const;
+
+ std::string config_value(const ProxySnapper* snapper) const;
+
+ std::string subvolume_value(const ProxySnapper* snapper) const;
+
+ virtual std::string
+ number_value(const ProxySnapshot& snapshot, const ProxySnapshots& snapshots) const;
+
+ std::string
+ default_value(const ProxySnapshot& snapshot, const ProxySnapshots& snapshots) const;
+
+ std::string
+ active_value(const ProxySnapshot& snapshot, const ProxySnapshots& snapshots) const;
+
+ std::string type_value(const ProxySnapshot& snapshot) const;
+
+ std::string date_value(const ProxySnapshot& snapshot) const;
+
+ std::string user_value(const ProxySnapshot& snapshot) const;
+
+ std::string
+ used_space_value(const ProxySnapshot& snapshot, const ProxySnapper* snapper) const;
+
+ std::string cleanup_value(const ProxySnapshot& snapshot) const;
+
+ std::string description_value(const ProxySnapshot& snapshot) const;
+
+ std::string userdata_value(const ProxySnapshot& snapshot) const;
+
+ std::string pre_number_value(const ProxySnapshot& snapshot) const;
+
+ std::string post_number_value(const ProxySnapshot& snapshot,
+ const ProxySnapshots& snapshots) const;
+
+ std::string
+ post_date_value(const ProxySnapshot& snapshot, const ProxySnapshots& snapshots) const;
+
+ std::string snapshot_date(const ProxySnapshot& snapshot) const;
+
+ std::string snapshot_used_value(const ProxySnapshot& snapshot) const;
+
+ bool
+ is_default_snapshot(const ProxySnapshot& snapshot, const ProxySnapshots& snapshots) const;
+
+ bool
+ is_active_snapshot(const ProxySnapshot& snapshot, const ProxySnapshots& snapshots) const;
+
+ ProxySnapshots::const_iterator default_snapshot(const ProxySnapshots& snapshots) const;
+
+ ProxySnapshots::const_iterator active_snapshot(const ProxySnapshots& snapshots) const;
+
+ ProxySnapshots::const_iterator
+ find_post(const ProxySnapshot& snapshot, const ProxySnapshots& snapshots) const;
+
+ virtual string boolean_text(bool value) const = 0;
+
+ const ListSnapshots& _command;
+
+ std::map<const ProxySnapper*, bool> _calculated_used_space;
+
+ };
+
+ }
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#include <snapper/AppUtil.h>
+
+#include "client/Command/ListSnapshots/SnappersData/Csv.h"
+#include "client/utils/CsvFormatter.h"
+
+using namespace std;
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ Command::ListSnapshots::SnappersData::Csv::Csv(
+ const Command::ListSnapshots& command, const string separator) :
+ SnappersData(command), _separator(separator)
+ {}
+
+
+ std::string Command::ListSnapshots::SnappersData::Csv::output() const
+ {
+ vector<string> columns;
+
+ vector<vector<string>> rows;
+
+ for (const string& column : selected_columns())
+ columns.push_back(column);
+
+ for (ProxySnapper* snapper : snappers())
+ {
+ vector<vector<string>> snapper_rows = this->snapper_rows(snapper);
+
+ rows.insert(rows.end(), snapper_rows.begin(), snapper_rows.end());
+ }
+
+ CsvFormatter formatter(columns, rows, _separator);
+
+ return formatter.output();
+ }
+
+
+ vector<vector<string>>
+ Command::ListSnapshots::SnappersData::Csv::snapper_rows(const ProxySnapper* snapper) const
+ {
+ vector<vector<string>> rows;
+
+ const ProxySnapshots& snapshots = this->snapshots(snapper);
+
+ for (const ProxySnapshot* snapshot : selected_snapshots(snapper))
+ {
+ vector<string> row;
+
+ for (const string& column : selected_columns())
+ {
+ row.push_back(value_for(column, *snapshot, snapshots, snapper));
+ }
+
+ rows.push_back(row);
+ }
+
+ return rows;
+ }
+
+
+ string Command::ListSnapshots::SnappersData::Csv::boolean_text(bool value) const
+ {
+ return value ? "yes" : "no";
+ }
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#ifndef SNAPPER_CLI_COMMAND_LIST_SNAPSHOTS_SNAPPERS_DATA_CSV_H
+#define SNAPPER_CLI_COMMAND_LIST_SNAPSHOTS_SNAPPERS_DATA_CSV_H
+
+#include <vector>
+#include <string>
+
+#include "client/Command/ListSnapshots/SnappersData.h"
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ class Command::ListSnapshots::SnappersData::Csv : public Command::ListSnapshots::SnappersData
+ {
+
+ public:
+
+ Csv(const ListSnapshots& command, const std::string separator);
+
+ virtual std::string output() const override;
+
+ private:
+
+ std::vector<std::vector<std::string>> snapper_rows(const ProxySnapper* snapper) const;
+
+ virtual string boolean_text(bool value) const override;
+
+ const std::string _separator;
+ };
+
+ }
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#include <utility>
+
+#include "client/Command/ListSnapshots/SnappersData/Json.h"
+#include "client/Command/ListSnapshots/Options.h"
+#include "client/utils/JsonFormatter.h"
+
+using namespace std;
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ namespace
+ {
+
+ string userdata_json(const map<string, string>& userdata)
+ {
+ if (userdata.empty())
+ return "";
+
+ JsonFormatter::Data data;
+
+ for (auto udata : userdata)
+ data.emplace_back(udata.first, udata.second);
+
+ JsonFormatter formatter(data);
+
+ formatter.set_inline(true);
+
+ return formatter.output(3);
+ }
+
+ }
+
+
+ std::string Command::ListSnapshots::SnappersData::Json::output() const
+ {
+ JsonFormatter::Data data;
+
+ vector<string> keys;
+
+ for (ProxySnapper* snapper : snappers())
+ {
+ data.emplace_back(snapper_key(snapper), snapper_value(snapper));
+
+ keys.push_back(snapper_key(snapper));
+ }
+
+ JsonFormatter formatter(data);
+
+ formatter.skip_format_values(keys);
+
+ return formatter.output();
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::Json::snapper_key(const ProxySnapper* snapper) const
+ {
+ return snapper->configName();
+ }
+
+
+ string
+ Command::ListSnapshots::SnappersData::Json::snapper_value(const ProxySnapper* snapper) const
+ {
+ vector<string> data;
+
+ const ProxySnapshots& snapshots = this->snapshots(snapper);
+
+ for (const ProxySnapshot* snapshot : selected_snapshots(snapper))
+ {
+ JsonFormatter::Data snapshot_data;
+
+ vector<string> skip_format;
+
+ for (const string& column : selected_columns())
+ {
+ string value = value_for(column, *snapshot, snapshots, snapper);
+
+ if (column == Options::Columns::USERDATA)
+ value = userdata_json(snapshot->getUserdata());
+
+ if (value.empty())
+ {
+ value = "null";
+ skip_format.push_back(column);
+ }
+
+ if (skip_format_value(column))
+ skip_format.push_back(column);
+
+ snapshot_data.emplace_back(column, value);
+ }
+
+ JsonFormatter formatter(snapshot_data);
+
+ formatter.skip_format_values(skip_format);
+
+ data.push_back(formatter.output(2));
+ }
+
+ JsonFormatter::List json_list(data);
+
+ return json_list.output(1);
+ }
+
+
+ bool Command::ListSnapshots::SnappersData::Json::skip_format_value(const string& column) const
+ {
+ if (column == Options::Columns::NUMBER ||
+ column == Options::Columns::DEFAULT ||
+ column == Options::Columns::ACTIVE ||
+ column == Options::Columns::USED_SPACE ||
+ column == Options::Columns::USERDATA ||
+ column == Options::Columns::PRE_NUMBER ||
+ column == Options::Columns::POST_NUMBER)
+ return true;
+ else
+ return false;
+ }
+
+
+ string Command::ListSnapshots::SnappersData::Json::boolean_text(bool value) const
+ {
+ return value ? "true" : "false";
+ }
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#ifndef SNAPPER_CLI_COMMAND_LIST_SNAPSHOTS_SNAPPERS_DATA_JSON_H
+#define SNAPPER_CLI_COMMAND_LIST_SNAPSHOTS_SNAPPERS_DATA_JSON_H
+
+#include <vector>
+#include <string>
+
+#include "client/Command/ListSnapshots/SnappersData.h"
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ class Command::ListSnapshots::SnappersData::Json : public Command::ListSnapshots::SnappersData
+ {
+
+ public:
+
+ using Command::ListSnapshots::SnappersData::SnappersData;
+
+ virtual std::string output() const override;
+
+ private:
+
+ std::string snapper_key(const ProxySnapper* snapper) const;
+
+ std::string snapper_value(const ProxySnapper* snapper) const;
+
+ std::string snapshot_json(const ProxySnapshot* snapshot) const;
+
+ bool skip_format_value(const string& column) const;
+
+ virtual string boolean_text(bool value) const override;
+
+ };
+
+ }
+}
+
+#endif
--- /dev/null
+#
+# Makefile.am for snapper/client/Command/ListSnapshots/SnappersData
+#
+
+AM_CPPFLAGS = -I$(top_srcdir) $(DBUS_CFLAGS)
+
+noinst_LTLIBRARIES = libcommandlistsnapshotssnappersdata.la
+
+libcommandlistsnapshotssnappersdata_la_SOURCES = \
+ Table.cc Table.h \
+ Csv.cc Csv.h \
+ Json.cc Json.h
+
+libcommandlistsnapshotssnappersdata_la_LIBADD = \
+ ../../../../snapper/libsnapper.la \
+ ../../../utils/libutils.la \
+ ../../../../dbus/libdbus.la
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#include <utility>
+
+#include <snapper/AppUtil.h>
+
+#include "client/Command/ListSnapshots/SnappersData/Table.h"
+#include "client/Command/ListSnapshots/Options.h"
+#include "client/utils/TableFormatter.h"
+#include "client/utils/text.h"
+
+using namespace std;
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ Command::ListSnapshots::SnappersData::Table::Table(
+ const Command::ListSnapshots& command, TableLineStyle style) :
+ SnappersData(command), _style(style)
+ {}
+
+
+ string Command::ListSnapshots::SnappersData::Table::output() const
+ {
+ string output;
+
+ vector<ProxySnapper*> snappers = this->snappers();
+
+ for (ProxySnapper* snapper : snappers)
+ {
+ if (snappers.size() > 1)
+ {
+ if (snapper != *snappers.begin())
+ output += "\n";
+
+ output += snapper_description(snapper) + "\n";
+ }
+
+ output += snapper_table(snapper);
+ }
+
+ return output;
+ }
+
+
+ string Command::ListSnapshots::SnappersData::Table::label_for(const string& column) const
+ {
+ Options::ListMode list_mode = command().options().list_mode();
+
+ if (column == Options::Columns::CONFIG)
+ return _("Config");
+
+ if (column == Options::Columns::SUBVOLUME)
+ return _("Subvolume");
+
+ if (column == Options::Columns::NUMBER)
+ return list_mode == Options::LM_PRE_POST ? _("Pre #") : _("#");
+
+ if (column == Options::Columns::DEFAULT)
+ return _("Default");
+
+ if (column == Options::Columns::ACTIVE)
+ return _("Active");
+
+ if (column == Options::Columns::TYPE)
+ return _("Type");
+
+ if (column == Options::Columns::DATE)
+ return list_mode == Options::LM_PRE_POST ? _("Pre Date") : _("Date");
+
+ if (column == Options::Columns::USER)
+ return _("User");
+
+ if (column == Options::Columns::USED_SPACE)
+ return _("Used Space");
+
+ if (column == Options::Columns::CLEANUP)
+ return _("Cleanup");
+
+ if (column == Options::Columns::DESCRIPTION)
+ return _("Description");
+
+ if (column == Options::Columns::USERDATA)
+ return _("Userdata");
+
+ if (column == Options::Columns::PRE_NUMBER)
+ return _("Pre #");
+
+ if (column == Options::Columns::POST_NUMBER)
+ return _("Post #");
+
+ if (column == Options::Columns::POST_DATE)
+ return _("Post Date");
+
+ return "";
+ }
+
+
+ string Command::ListSnapshots::SnappersData::Table::number_value(const ProxySnapshot& snapshot,
+ const ProxySnapshots& snapshots) const
+ {
+ bool is_default = is_default_snapshot(snapshot, snapshots);
+ bool is_active = is_active_snapshot(snapshot, snapshots);
+
+ static const char sign[2][2] = { { ' ', '-' }, { '+', '*' } };
+
+ return Command::ListSnapshots::SnappersData::number_value(snapshot, snapshots) +
+ sign[is_default][is_active];
+ }
+
+
+ string Command::ListSnapshots::SnappersData::Table::boolean_text(bool value) const
+ {
+ return value ? _("yes") : _("no");
+ }
+
+
+ string Command::ListSnapshots::SnappersData::Table::snapper_description(
+ const ProxySnapper* snapper) const
+ {
+ return sformat(_("Config: %s, subvolume: %s"), config_value(snapper).c_str(),
+ subvolume_value(snapper).c_str());
+ }
+
+
+ string Command::ListSnapshots::SnappersData::Table::snapper_table(
+ const ProxySnapper* snapper) const
+ {
+ const ProxySnapshots& snapshots = this->snapshots(snapper);
+
+ vector<pair<string, TableAlign>> columns;
+
+ vector<vector<string>> rows;
+
+ for (const string& column : selected_columns())
+ {
+ if (skip_column(column, snapper))
+ continue;
+
+ columns.emplace_back(label_for(column), column_alignment(column));
+ }
+
+ for (const ProxySnapshot* snapshot : selected_snapshots(snapper))
+ {
+ vector<string> row;
+
+ for (const string& column : selected_columns())
+ {
+ if (skip_column(column, snapper))
+ continue;
+
+ row.push_back(value_for(column, *snapshot, snapshots, snapper));
+ }
+
+ rows.push_back(row);
+ }
+
+ TableFormatter formatter(columns, rows, _style);
+
+ return formatter.output();
+ }
+
+
+ bool Command::ListSnapshots::SnappersData::Table::skip_column(const string& column,
+ const ProxySnapper* snapper) const
+ {
+ return column == Options::Columns::USED_SPACE && !calculated_used_space(snapper);
+ }
+
+
+ TableAlign
+ Command::ListSnapshots::SnappersData::Table::column_alignment(const string& column) const
+ {
+ if (column == Options::Columns::NUMBER ||
+ column == Options::Columns::PRE_NUMBER ||
+ column == Options::Columns::POST_NUMBER ||
+ column == Options::Columns::USED_SPACE)
+ return TableAlign::RIGHT;
+ else
+ return TableAlign::LEFT;
+ }
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) [2019] SUSE LLC
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+#ifndef SNAPPER_CLI_COMMAND_LIST_SNAPSHOTS_SNAPPERS_DATA_TABLE_H
+#define SNAPPER_CLI_COMMAND_LIST_SNAPSHOTS_SNAPPERS_DATA_TABLE_H
+
+#include <string>
+
+#include "client/Command/ListSnapshots/SnappersData.h"
+#include "client/utils/Table.h"
+
+namespace snapper
+{
+ namespace cli
+ {
+
+ class Command::ListSnapshots::SnappersData::Table : public Command::ListSnapshots::SnappersData
+ {
+
+ public:
+
+ Table(const ListSnapshots& command, TableLineStyle style);
+
+ virtual std::string output() const override;
+
+ private:
+
+ std::string label_for(const string& column) const;
+
+ virtual std::string
+ number_value(const ProxySnapshot& snapshot, const ProxySnapshots& snapshots) const override;
+
+ virtual string boolean_text(bool value) const override;
+
+ std::string snapper_description(const ProxySnapper* snapper) const;
+
+ std::string snapper_table(const ProxySnapper* snapper) const;
+
+ bool skip_column(const string& column, const ProxySnapper* snapper) const;
+
+ TableAlign column_alignment(const string& column) const;
+
+ TableLineStyle _style;
+
+ };
+
+ }
+}
+
+#endif