The Battle for Wesnoth  1.19.0-dev
migrate_version_selection.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2024
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
18 
19 #include "addon/manager_ui.hpp"
20 #include "filesystem.hpp"
21 #include "game_version.hpp"
22 #include "gettext.hpp"
24 #include "gui/widgets/listbox.hpp"
25 #include "gui/widgets/window.hpp"
27 #include "preferences/game.hpp"
28 #include "serialization/parser.hpp"
29 
30 #include <boost/algorithm/string.hpp>
31 
32 static lg::log_domain log_version_migration{"gui/dialogs/migrate_version_selection"};
33 #define ERR_LOG_VERSION_MIGRATION LOG_STREAM(err, log_version_migration)
34 #define WRN_LOG_VERSION_MIGRATION LOG_STREAM(warn, log_version_migration)
35 #define LOG_LOG_VERSION_MIGRATION LOG_STREAM(info, log_version_migration)
36 #define DBG_LOG_VERSION_MIGRATION LOG_STREAM(debug, log_version_migration)
37 
38 namespace gui2::dialogs
39 {
40 REGISTER_DIALOG(migrate_version_selection)
41 
43 {
45  if(mig.versions_.size() > 0) {
46  mig.show();
47  }
48 }
49 
51  : modal_dialog(window_id())
52 {
54  std::string current_version_str = filesystem::get_version_path_suffix();
55 
56  for(unsigned int i = 1; i < current_version.minor_version(); i++) {
57  std::string previous_version_str = std::to_string(current_version.major_version()) + "."
58  + std::to_string(current_version.minor_version() - i);
59  std::string previous_addons_dir
60  = boost::replace_all_copy(filesystem::get_addons_dir(), current_version_str, previous_version_str);
61 
62  if(previous_addons_dir != filesystem::get_addons_dir() && filesystem::file_exists(previous_addons_dir)) {
63  versions_.push_back(previous_version_str);
64  }
65  }
66 }
67 
69 {
70  listbox& version_list = find_widget<listbox>(&window, "versions_listbox", false);
71 
72  for(const auto& version : versions_) {
74  widget_item item_label;
75 
76  item_label["label"] = version;
77  data["version_label"] = item_label;
78 
79  version_list.add_row(data);
80  }
81 }
82 
84 {
85  if(get_retval() == gui2::OK) {
86  std::string current_version_str = filesystem::get_version_path_suffix();
87  listbox& version_list = find_widget<listbox>(&window, "versions_listbox", false);
88  int selected_row = version_list.get_selected_row();
89  std::string selected = versions_.at(selected_row);
90 
91  std::string migrate_addons_dir
92  = boost::replace_all_copy(filesystem::get_addons_dir(), current_version_str, selected);
93  std::string migrate_prefs_file
94  = boost::replace_all_copy(filesystem::get_prefs_file(), current_version_str, selected);
95  std::string migrate_credentials_file
96  = boost::replace_all_copy(filesystem::get_credentials_file(), current_version_str, selected);
97 
98  // given self-compilation and linux distros being able to do whatever they want plus command line options to
99  // alter locations make sure the directories/files are actually different before doing anything with them
100  if(migrate_addons_dir != filesystem::get_addons_dir()) {
101  std::vector<std::string> old_addons;
102  std::vector<std::string> current_addons;
103  std::vector<std::string> migrate_addons;
104 
105  filesystem::get_files_in_dir(migrate_addons_dir, nullptr, &old_addons);
106  filesystem::get_files_in_dir(filesystem::get_addons_dir(), nullptr, &current_addons);
107 
108  std::set_difference(old_addons.begin(), old_addons.end(), current_addons.begin(), current_addons.end(), std::back_inserter(migrate_addons));
109 
110  if(migrate_addons.size() > 0) {
111  ad_hoc_addon_fetch_session(migrate_addons);
112  }
113  }
114 
115  if(migrate_prefs_file != filesystem::get_prefs_file() && filesystem::file_exists(migrate_prefs_file)) {
116  // if the file doesn't exist, just copy the file over
117  // else need to merge the preferences file
119  filesystem::copy_file(migrate_prefs_file, filesystem::get_prefs_file());
120  } else {
121  config current_cfg;
123  read(current_cfg, *current_stream);
124  config old_cfg;
125  filesystem::scoped_istream old_stream = filesystem::istream_file(migrate_prefs_file, false);
126  read(old_cfg, *old_stream);
127 
128  // when both files have the same attribute, use the one from whichever was most recently modified
129  bool current_prefs_are_older = filesystem::file_modified_time(filesystem::get_prefs_file()) < filesystem::file_modified_time(migrate_prefs_file);
130  for(const config::attribute& val : old_cfg.attribute_range()) {
131  if(current_prefs_are_older || !current_cfg.has_attribute(val.first)) {
132  preferences::set(val.first, val.second);
133  }
134  }
135 
136  // don't touch child tags
137 
139  }
140  }
141 
142  // don't touch the credentials file on migrator re-run if it already exists
143  if(migrate_credentials_file != filesystem::get_credentials_file() && filesystem::file_exists(migrate_credentials_file) && !filesystem::file_exists(filesystem::get_credentials_file())) {
144  filesystem::copy_file(migrate_credentials_file, filesystem::get_credentials_file());
145  }
146 
147  // reload preferences and credentials
148  // otherwise the copied files won't be used and also will get overwritten/deleted when Wesnoth closes
152  }
153 }
154 } // namespace gui2::dialogs
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
const_attr_itors attribute_range() const
Definition: config.cpp:763
bool has_attribute(config_key_type key) const
Definition: config.cpp:155
attribute_map::value_type attribute
Definition: config.hpp:299
This shows the dialog to select a previous version of Wesnoth to migrate preferences from and redownl...
virtual void post_show(window &window) override
Actions to be taken after the window has been shown.
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
Abstract base class for all modal dialogs.
bool show(const unsigned auto_close_time=0)
Shows the window.
int get_retval() const
Returns the cached window exit code.
The listbox class.
Definition: listbox.hpp:43
grid & add_row(const widget_item &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition: listbox.cpp:59
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:268
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:63
Represents version numbers.
unsigned int minor_version() const
Retrieves the minor version number (x2 in "x1.x2.x3").
unsigned int major_version() const
Retrieves the major version number (x1 in "x1.x2.x3").
Declarations for File-IO.
std::size_t i
Definition: function.cpp:968
Interfaces for manipulating version numbers of engine, add-ons, etc.
This file contains the window object, this object is a top level container which has the event manage...
bool ad_hoc_addon_fetch_session(const std::vector< std::string > &addon_ids)
Conducts an ad-hoc add-ons server connection to download an add-on with a particular id and all it's ...
Definition: manager_ui.cpp:255
static lg::log_domain log_version_migration
std::time_t file_modified_time(const std::string &fname)
Get the modification time of a file.
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, name_mode mode, filter_mode filter, reorder_mode reorder, file_tree_checksum *checksum)
Get a list of all files and/or directories in a given directory.
Definition: filesystem.cpp:405
void copy_file(const std::string &src, const std::string &dest)
Read a file and then writes it back out.
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:319
std::string get_prefs_file()
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:50
std::string get_credentials_file()
std::string get_addons_dir()
const std::string get_version_path_suffix(const version_info &version)
Definition: filesystem.cpp:569
std::string selected
const version_info wesnoth_version(VERSION)
REGISTER_DIALOG(editor_edit_unit)
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:34
std::map< std::string, t_string > widget_item
Definition: widget.hpp:31
@ OK
Dialog was closed with the OK button.
Definition: retval.hpp:35
void set(const std::string &key, bool value)
Definition: general.cpp:165
void load_base_prefs()
Definition: general.cpp:240
void write_preferences()
Definition: general.cpp:141
void load_credentials()
void load_game_prefs()
Definition: game.cpp:117
std::string_view data
Definition: picture.cpp:194
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:627