The Battle for Wesnoth  1.19.5+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"
23 #include "gui/dialogs/message.hpp"
24 #include "gui/widgets/listbox.hpp"
25 #include "gui/widgets/window.hpp"
27 #include "serialization/parser.hpp"
28 
29 #include <boost/algorithm/string.hpp>
30 
31 static lg::log_domain log_version_migration{"gui/dialogs/migrate_version_selection"};
32 #define ERR_LOG_VERSION_MIGRATION LOG_STREAM(err, log_version_migration)
33 #define WRN_LOG_VERSION_MIGRATION LOG_STREAM(warn, log_version_migration)
34 #define LOG_LOG_VERSION_MIGRATION LOG_STREAM(info, log_version_migration)
35 #define DBG_LOG_VERSION_MIGRATION LOG_STREAM(debug, log_version_migration)
36 
37 namespace gui2::dialogs
38 {
39 REGISTER_DIALOG(migrate_version_selection)
40 
42 {
44  if(mig.versions_.size() > 0) {
45  mig.show();
46  } else {
47  gui2::show_message(_("No Other Version Found"), _("This would import settings from a previous version of Wesnoth, but no other version was found on this device"), gui2::dialogs::message::button_style::auto_close);
48  }
49 }
50 
52  : modal_dialog(window_id())
53 {
55  std::string current_version_str = filesystem::get_version_path_suffix();
56 
57  for(unsigned int i = 1; i < current_version.minor_version(); i++) {
58  std::string previous_version_str = std::to_string(current_version.major_version()) + "."
59  + std::to_string(current_version.minor_version() - i);
60  std::string previous_addons_dir
61  = boost::replace_all_copy(filesystem::get_addons_dir(), current_version_str, previous_version_str);
62 
63  if(previous_addons_dir != filesystem::get_addons_dir() && filesystem::file_exists(previous_addons_dir)) {
64  versions_.push_back(previous_version_str);
65  }
66  }
67 }
68 
70 {
71  listbox& version_list = find_widget<listbox>("versions_listbox");
72 
73  for(const auto& version : versions_) {
75  widget_item item_label;
76 
77  item_label["label"] = version;
78  data["version_label"] = item_label;
79 
80  version_list.add_row(data);
81  }
82 }
83 
85 {
86  if(get_retval() == gui2::OK) {
87  std::string current_version_str = filesystem::get_version_path_suffix();
88  listbox& version_list = find_widget<listbox>("versions_listbox");
89  int selected_row = version_list.get_selected_row();
90  std::string selected = versions_.at(selected_row);
91 
92  std::string migrate_addons_dir
93  = boost::replace_all_copy(filesystem::get_addons_dir(), current_version_str, selected);
94  std::string migrate_synced_prefs_file
95  = boost::replace_all_copy(filesystem::get_synced_prefs_file(), current_version_str, selected);
96  std::string migrate_unsynced_prefs_file
97  = boost::replace_all_copy(filesystem::get_unsynced_prefs_file(), current_version_str, selected);
98  std::string migrate_credentials_file
99  = boost::replace_all_copy(filesystem::get_credentials_file(), current_version_str, selected);
100 
101  // given self-compilation and linux distros being able to do whatever they want plus command line options to
102  // alter locations make sure the directories/files are actually different before doing anything with them
103  if(migrate_addons_dir != filesystem::get_addons_dir()) {
104  std::vector<std::string> old_addons;
105  std::vector<std::string> current_addons;
106  std::vector<std::string> migrate_addons;
107 
108  filesystem::get_files_in_dir(migrate_addons_dir, nullptr, &old_addons);
109  filesystem::get_files_in_dir(filesystem::get_addons_dir(), nullptr, &current_addons);
110 
111  std::set_difference(old_addons.begin(), old_addons.end(), current_addons.begin(), current_addons.end(), std::back_inserter(migrate_addons));
112 
113  if(migrate_addons.size() > 0) {
114  ad_hoc_addon_fetch_session(migrate_addons);
115  }
116  }
117 
118 #if !defined(_WIN32) && !defined(__APPLE__)
119  bool already_migrated = false;
120  std::string linux_old_config_dir = old_config_dir();
121  std::string old_migrate_prefs_file = linux_old_config_dir + "/preferences";
122  std::string old_migrate_credentials_file = linux_old_config_dir + "/credentials-aes";
123 
124  if(filesystem::file_exists(old_migrate_prefs_file)) {
125  already_migrated = true;
126  prefs::get().migrate_preferences(old_migrate_prefs_file);
127  }
128  if(filesystem::file_exists(old_migrate_credentials_file)) {
129  already_migrated = true;
130  migrate_credentials(old_migrate_credentials_file);
131  }
132 
133  if(!already_migrated)
134 #endif
135  {
136  prefs::get().migrate_preferences(migrate_unsynced_prefs_file);
137  prefs::get().migrate_preferences(migrate_synced_prefs_file);
138  migrate_credentials(migrate_credentials_file);
139  }
140 
141  // reload preferences and credentials
142  // otherwise the copied files won't be used and also will get overwritten/deleted when Wesnoth closes
143 
145  }
146 }
147 
148 /**
149  * Prior to 1.19 linux installs would usually store the credentials and preferences file under XDG_CONFIG_HOME with no version separation.
150  * That special handling has been removed, but still needs to be accounted for when migrating
151  */
153 {
154  char const* xdg_config = getenv("XDG_CONFIG_HOME");
155  std::string old_config_dir;
156 
157  if(!xdg_config || xdg_config[0] == '\0') {
158  xdg_config = getenv("HOME");
159  if(!xdg_config) {
161  return old_config_dir;
162  }
163 
164  old_config_dir = xdg_config;
165  old_config_dir += "/.config";
166  } else {
167  old_config_dir = xdg_config;
168  }
169 
170  old_config_dir += "/wesnoth";
171  return old_config_dir;
172 }
173 
174 void migrate_version_selection::migrate_credentials(const std::string& migrate_credentials_file)
175 {
176  // don't touch the credentials file on migrator re-run if it already exists
177  if(migrate_credentials_file != filesystem::get_credentials_file() && filesystem::file_exists(migrate_credentials_file) && !filesystem::file_exists(filesystem::get_credentials_file())) {
178  filesystem::copy_file(migrate_credentials_file, filesystem::get_credentials_file());
179  }
180 }
181 
182 } // namespace gui2::dialogs
This shows the dialog to select a previous version of Wesnoth to migrate preferences from and redownl...
virtual void post_show() override
Actions to be taken after the window has been shown.
std::string old_config_dir()
Prior to 1.19 linux installs would usually store the credentials and preferences file under XDG_CONFI...
void migrate_credentials(const std::string &credentials_dir)
virtual void pre_show() 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:58
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:267
static prefs & get()
void migrate_preferences(const std::string &prefs_dir)
void reload_preferences()
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:1028
Interfaces for manipulating version numbers of engine, add-ons, etc.
static std::string _(const char *str)
Definition: gettext.hpp:93
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
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:444
std::string get_user_data_dir()
Definition: filesystem.cpp:827
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:325
std::string get_synced_prefs_file()
location of preferences file containing preferences that are synced between computers note that wesno...
std::string get_unsynced_prefs_file()
location of preferences file containing preferences that aren't synced between computers
std::string get_credentials_file()
std::string get_addons_dir()
const std::string get_version_path_suffix(const version_info &version)
Definition: filesystem.cpp:613
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:36
std::map< std::string, t_string > widget_item
Definition: widget.hpp:33
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
Definition: message.cpp:148
@ OK
Dialog was closed with the OK button.
Definition: retval.hpp:35
std::string_view data
Definition: picture.cpp:178