mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-11 04:31:46 +08:00
Copying from other config folders:
Find if there is more recent config in other folders (alpha / beta / release). If yes, ask user, make snapshot, copy files. if there is no current config, ask user and copy recent one.
This commit is contained in:
parent
4c8e13947c
commit
ca8f7fbf80
@ -248,11 +248,11 @@ std::string AppConfig::load()
|
||||
bool recovered = false;
|
||||
|
||||
try {
|
||||
ifs.open(AppConfig::config_path());
|
||||
ifs.open(AppConfig::loading_path());
|
||||
#ifdef WIN32
|
||||
// Verify the checksum of the config file without taking just for debugging purpose.
|
||||
if (!verify_config_file_checksum(ifs))
|
||||
BOOST_LOG_TRIVIAL(info) << "The configuration file " << AppConfig::config_path() <<
|
||||
BOOST_LOG_TRIVIAL(info) << "The configuration file " << AppConfig::loading_path() <<
|
||||
" has a wrong MD5 checksum or the checksum is missing. This may indicate a file corruption or a harmless user edit.";
|
||||
|
||||
ifs.seekg(0, boost::nowide::ifstream::beg);
|
||||
@ -262,32 +262,32 @@ std::string AppConfig::load()
|
||||
#ifdef WIN32
|
||||
// The configuration file is corrupted, try replacing it with the backup configuration.
|
||||
ifs.close();
|
||||
std::string backup_path = (boost::format("%1%.bak") % AppConfig::config_path()).str();
|
||||
std::string backup_path = (boost::format("%1%.bak") % AppConfig::loading_path()).str();
|
||||
if (boost::filesystem::exists(backup_path)) {
|
||||
// Compute checksum of the configuration backup file and try to load configuration from it when the checksum is correct.
|
||||
boost::nowide::ifstream backup_ifs(backup_path);
|
||||
if (!verify_config_file_checksum(backup_ifs)) {
|
||||
BOOST_LOG_TRIVIAL(error) << format("Both \"%1%\" and \"%2%\" are corrupted. It isn't possible to restore configuration from the backup.", AppConfig::config_path(), backup_path);
|
||||
BOOST_LOG_TRIVIAL(error) << format("Both \"%1%\" and \"%2%\" are corrupted. It isn't possible to restore configuration from the backup.", AppConfig::loading_path(), backup_path);
|
||||
backup_ifs.close();
|
||||
boost::filesystem::remove(backup_path);
|
||||
} else if (std::string error_message; copy_file(backup_path, AppConfig::config_path(), error_message, false) != SUCCESS) {
|
||||
BOOST_LOG_TRIVIAL(error) << format("Configuration file \"%1%\" is corrupted. Failed to restore from backup \"%2%\": %3%", AppConfig::config_path(), backup_path, error_message);
|
||||
} else if (std::string error_message; copy_file(backup_path, AppConfig::loading_path(), error_message, false) != SUCCESS) {
|
||||
BOOST_LOG_TRIVIAL(error) << format("Configuration file \"%1%\" is corrupted. Failed to restore from backup \"%2%\": %3%", AppConfig::loading_path(), backup_path, error_message);
|
||||
backup_ifs.close();
|
||||
boost::filesystem::remove(backup_path);
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << format("Configuration file \"%1%\" was corrupted. It has been succesfully restored from the backup \"%2%\".", AppConfig::config_path(), backup_path);
|
||||
BOOST_LOG_TRIVIAL(info) << format("Configuration file \"%1%\" was corrupted. It has been succesfully restored from the backup \"%2%\".", AppConfig::loading_path(), backup_path);
|
||||
// Try parse configuration file after restore from backup.
|
||||
try {
|
||||
ifs.open(AppConfig::config_path());
|
||||
ifs.open(AppConfig::loading_path());
|
||||
pt::read_ini(ifs, tree);
|
||||
recovered = true;
|
||||
} catch (pt::ptree_error& ex) {
|
||||
BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\" after it has been restored from backup: %2%", AppConfig::config_path(), ex.what());
|
||||
BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\" after it has been restored from backup: %2%", AppConfig::loading_path(), ex.what());
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif // WIN32
|
||||
BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\": %2%", AppConfig::config_path(), ex.what());
|
||||
BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\": %2%", AppConfig::loading_path(), ex.what());
|
||||
if (! recovered) {
|
||||
// Report the initial error of parsing PrusaSlicer.ini.
|
||||
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
|
||||
|
@ -148,6 +148,9 @@ public:
|
||||
// Does the config file exist?
|
||||
bool exists();
|
||||
|
||||
void set_loading_path(const std::string& path) { m_loading_path = path; }
|
||||
std::string loading_path() { return (m_loading_path.empty() ? config_path() : m_loading_path); }
|
||||
|
||||
std::vector<std::string> get_recent_projects() const;
|
||||
void set_recent_projects(const std::vector<std::string>& recent_projects);
|
||||
|
||||
@ -196,6 +199,8 @@ private:
|
||||
Semver m_orig_version;
|
||||
// Whether the existing version is before system profiles & configuration updating
|
||||
bool m_legacy_datadir;
|
||||
|
||||
std::string m_loading_path;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -188,6 +188,61 @@ void PresetBundle::setup_directories()
|
||||
}
|
||||
}
|
||||
|
||||
// recursively copy all files and dirs in from_dir to to_dir
|
||||
static void copy_dir(const boost::filesystem::path& from_dir, const boost::filesystem::path& to_dir)
|
||||
{
|
||||
if(!boost::filesystem::is_directory(from_dir))
|
||||
return;
|
||||
// i assume to_dir.parent surely exists
|
||||
if (!boost::filesystem::is_directory(to_dir))
|
||||
boost::filesystem::create_directory(to_dir);
|
||||
for (auto& dir_entry : boost::filesystem::directory_iterator(from_dir)) {
|
||||
if (!boost::filesystem::is_directory(dir_entry.path())) {
|
||||
std::string em;
|
||||
CopyFileResult cfr = copy_file(dir_entry.path().string(), (to_dir / dir_entry.path().filename()).string(), em, false);
|
||||
if (cfr != SUCCESS) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error when copying files from " << from_dir << " to " << to_dir << ": " << em;
|
||||
}
|
||||
} else {
|
||||
copy_dir(dir_entry.path(), to_dir / dir_entry.path().filename());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PresetBundle::copy_files(const std::string& from)
|
||||
{
|
||||
boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
|
||||
// list of searched paths based on current directory system in setup_directories()
|
||||
// do not copy cache and snapshots
|
||||
boost::filesystem::path from_data_dir = boost::filesystem::path(from);
|
||||
std::initializer_list<boost::filesystem::path> from_dirs= {
|
||||
from_data_dir / "vendor",
|
||||
from_data_dir / "shapes",
|
||||
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
|
||||
// Store the print/filament/printer presets into a "presets" directory.
|
||||
data_dir / "presets",
|
||||
data_dir / "presets" / "print",
|
||||
data_dir / "presets" / "filament",
|
||||
data_dir / "presets" / "sla_print",
|
||||
data_dir / "presets" / "sla_material",
|
||||
data_dir / "presets" / "printer",
|
||||
data_dir / "presets" / "physical_printer"
|
||||
#else
|
||||
// Store the print/filament/printer presets at the same location as the upstream Slic3r.
|
||||
from_data_dir / "print",
|
||||
from_data_dir / "filament",
|
||||
from_data_dir / "sla_print",
|
||||
from_data_dir / "sla_material",
|
||||
from_data_dir / "printer",
|
||||
from_data_dir / "physical_printer"
|
||||
#endif
|
||||
};
|
||||
// copy recursively all files
|
||||
for (const boost::filesystem::path& from_dir : from_dirs) {
|
||||
copy_dir(from_dir, data_dir / from_dir.filename());
|
||||
}
|
||||
}
|
||||
|
||||
PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule substitution_rule,
|
||||
const PresetPreferences& preferred_selection/* = PresetPreferences()*/)
|
||||
{
|
||||
|
@ -24,6 +24,7 @@ public:
|
||||
void reset(bool delete_files);
|
||||
|
||||
void setup_directories();
|
||||
void copy_files(const std::string& from);
|
||||
|
||||
struct PresetPreferences {
|
||||
std::string printer_model_id;// name of a preferred printer model
|
||||
|
@ -743,6 +743,25 @@ bool GUI_App::init_opengl()
|
||||
#endif
|
||||
}
|
||||
|
||||
// gets path to PrusaSlicer.ini, returns semver from first line comment
|
||||
static boost::optional<Semver> parse_semver_from_ini(std::string path)
|
||||
{
|
||||
std::ifstream stream(path);
|
||||
std::stringstream buffer;
|
||||
buffer << stream.rdbuf();
|
||||
std::string body = buffer.str();
|
||||
size_t end_line = body.find_first_of("\n\r");
|
||||
body.resize(end_line);
|
||||
size_t start = body.find("PrusaSlicer ");
|
||||
if (start == std::string::npos)
|
||||
return boost::none;
|
||||
body = body.substr(start + 12);
|
||||
size_t end = body.find_first_of(" \n\r");
|
||||
if (end < body.size())
|
||||
body.resize(end);
|
||||
return Semver::parse(body);
|
||||
}
|
||||
|
||||
void GUI_App::init_app_config()
|
||||
{
|
||||
// Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release.
|
||||
@ -791,9 +810,110 @@ void GUI_App::init_app_config()
|
||||
"\n\n" + app_config->config_path() + "\n\n" + error);
|
||||
}
|
||||
}
|
||||
// Save orig_version here, so its empty if no app_config existed before this run.
|
||||
m_last_config_version = app_config->orig_version();//parse_semver_from_ini(app_config->config_path());
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if found newer version and user agreed to use it
|
||||
bool GUI_App::check_older_app_config(Semver current_version, bool backup)
|
||||
{
|
||||
// find other version app config (alpha / beta / release)
|
||||
std::string config_path = app_config->config_path();
|
||||
boost::filesystem::path parent_file_path(config_path);
|
||||
std::string filename = parent_file_path.filename().string();
|
||||
parent_file_path.remove_filename().remove_filename();
|
||||
|
||||
std::vector<boost::filesystem::path> candidates;
|
||||
|
||||
if (SLIC3R_APP_KEY "-alpha" != GetAppName()) candidates.emplace_back(parent_file_path / SLIC3R_APP_KEY "-alpha" / filename);
|
||||
if (SLIC3R_APP_KEY "-beta" != GetAppName()) candidates.emplace_back(parent_file_path / SLIC3R_APP_KEY "-beta" / filename);
|
||||
if (SLIC3R_APP_KEY != GetAppName()) candidates.emplace_back(parent_file_path / SLIC3R_APP_KEY / filename);
|
||||
|
||||
Semver last_semver = current_version;
|
||||
for (const auto& candidate : candidates) {
|
||||
if (boost::filesystem::exists(candidate)) {
|
||||
// parse
|
||||
boost::optional<Semver>other_semver = parse_semver_from_ini(candidate.string());
|
||||
if (other_semver && *other_semver > last_semver) {
|
||||
last_semver = *other_semver;
|
||||
m_older_data_dir_path = candidate.parent_path().string();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_older_data_dir_path.empty())
|
||||
return false;
|
||||
BOOST_LOG_TRIVIAL(info) << "last app config file used: " << m_older_data_dir_path;
|
||||
// ask about using older data folder
|
||||
wxRichMessageDialog msg(nullptr, backup ?
|
||||
wxString::Format(_L("PrusaSlicer detected another configuration folder at %s."
|
||||
"\nIts version is %s."
|
||||
"\nLast version you used in current configuration folder is %s."
|
||||
"\nPlease note that PrusaSlicer uses different folders to save configuration of alpha, beta and full release versions."
|
||||
"\nWould you like to copy found configuration to your current configuration folder?"
|
||||
|
||||
"\n\nIf you select yes, PrusaSlicer will copy all profiles and other files from found folder to the current one. Overwriting any existing file with matching name."
|
||||
"\nIf you select no, you will continue with current configuration.")
|
||||
, m_older_data_dir_path, last_semver.to_string(), current_version.to_string())
|
||||
: wxString::Format(_L("PrusaSlicer detected another configuration folder at %s."
|
||||
"\nIts version is %s."
|
||||
"\nThere is no configuration file in current configuration folder."
|
||||
"\nPlease note that PrusaSlicer uses different folders to save configuration of alpha, beta and full release versions."
|
||||
"\nWould you like to copy found configuration to your current configuration folder?"
|
||||
|
||||
"\n\nIf you select yes, PrusaSlicer will copy all profiles and other files from found folder to the current one."
|
||||
"\nIf you select no, you will start with clean installation with configuration wizard.")
|
||||
, m_older_data_dir_path, last_semver.to_string())
|
||||
, _L("PrusaSlicer"), wxICON_QUESTION | wxYES_NO);
|
||||
if (msg.ShowModal() == wxID_YES) {
|
||||
std::string snapshot_id;
|
||||
if (backup) {
|
||||
// configuration snapshot
|
||||
std::string comment;
|
||||
if (const Config::Snapshot* snapshot = Config::take_config_snapshot_report_error(
|
||||
*app_config,
|
||||
Config::Snapshot::SNAPSHOT_USER,
|
||||
comment);
|
||||
snapshot != nullptr)
|
||||
// Is thos correct? Save snapshot id for later, when new app config is loaded.
|
||||
snapshot_id = snapshot->id;
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to take congiguration snapshot: ";
|
||||
}
|
||||
|
||||
// This will tell later (when config folder structure is sure to exists) to copy files from m_older_data_dir_path
|
||||
m_init_app_config_from_older = true;
|
||||
// load app config from older file
|
||||
app_config->set_loading_path((boost::filesystem::path(m_older_data_dir_path) / filename).string());
|
||||
std::string error = app_config->load();
|
||||
if (!error.empty()) {
|
||||
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
|
||||
if (is_editor()) {
|
||||
throw Slic3r::RuntimeError(
|
||||
_u8L("Error parsing PrusaSlicer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error. Your user profiles will not be affected.") +
|
||||
"\n\n" + app_config->config_path() + "\n\n" + error);
|
||||
}
|
||||
else {
|
||||
throw Slic3r::RuntimeError(
|
||||
_u8L("Error parsing PrusaGCodeViewer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error.") +
|
||||
"\n\n" + app_config->config_path() + "\n\n" + error);
|
||||
}
|
||||
}
|
||||
if (!snapshot_id.empty())
|
||||
app_config->set("on_snapshot", snapshot_id);
|
||||
m_app_conf_exists = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GUI_App::copy_older_config()
|
||||
{
|
||||
preset_bundle->copy_files(m_older_data_dir_path);
|
||||
}
|
||||
|
||||
void GUI_App::init_single_instance_checker(const std::string &name, const std::string &path)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << "init wx instance checker " << name << " "<< path;
|
||||
@ -884,6 +1004,13 @@ bool GUI_App::on_init_inner()
|
||||
}
|
||||
}
|
||||
|
||||
if (m_last_config_version) {
|
||||
if (*m_last_config_version < *Semver::parse(SLIC3R_VERSION))
|
||||
check_older_app_config(*m_last_config_version, true);
|
||||
} else {
|
||||
check_older_app_config(Semver(), false);
|
||||
}
|
||||
|
||||
app_config->set("version", SLIC3R_VERSION);
|
||||
app_config->save();
|
||||
|
||||
@ -922,12 +1049,18 @@ bool GUI_App::on_init_inner()
|
||||
scrn->SetText(_L("Loading configuration")+ dots);
|
||||
}
|
||||
|
||||
|
||||
|
||||
preset_bundle = new PresetBundle();
|
||||
|
||||
// just checking for existence of Slic3r::data_dir is not enough : it may be an empty directory
|
||||
// supplied as argument to --datadir; in that case we should still run the wizard
|
||||
preset_bundle->setup_directories();
|
||||
|
||||
|
||||
if (m_init_app_config_from_older)
|
||||
copy_older_config();
|
||||
|
||||
if (is_editor()) {
|
||||
#ifdef __WXMSW__
|
||||
if (app_config->get("associate_3mf") == "1")
|
||||
|
@ -337,6 +337,8 @@ public:
|
||||
private:
|
||||
bool on_init_inner();
|
||||
void init_app_config();
|
||||
bool check_older_app_config(Semver current_version, bool backup);
|
||||
void copy_older_config();
|
||||
void window_pos_save(wxTopLevelWindow* window, const std::string &name);
|
||||
void window_pos_restore(wxTopLevelWindow* window, const std::string &name, bool default_maximized = false);
|
||||
void window_pos_sanitize(wxTopLevelWindow* window);
|
||||
@ -344,6 +346,10 @@ private:
|
||||
|
||||
bool config_wizard_startup();
|
||||
void check_updates(const bool verbose);
|
||||
|
||||
bool m_init_app_config_from_older { false };
|
||||
std::string m_older_data_dir_path;
|
||||
boost::optional<Semver> m_last_config_version;
|
||||
};
|
||||
|
||||
DECLARE_APP(GUI_App)
|
||||
|
Loading…
x
Reference in New Issue
Block a user