ENH: updater: refine the config update logic

add more logic to process error
jira: no-jira

Change-Id: I7a23a25648f6965cd7ebe2d32212675ff11aa60e
This commit is contained in:
lane.wei 2025-03-27 10:26:17 +08:00 committed by Lane.Wei
parent be08d1d793
commit cd4fcb292a
6 changed files with 176 additions and 74 deletions

View File

@ -237,7 +237,7 @@ void PresetBundle::copy_files(const std::string& from)
} }
} }
PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule substitution_rule, std::pair<PresetsConfigSubstitutions, std::string> PresetBundle::load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule substitution_rule,
const PresetPreferences& preferred_selection/* = PresetPreferences()*/) const PresetPreferences& preferred_selection/* = PresetPreferences()*/)
{ {
// First load the vendor specific system presets. // First load the vendor specific system presets.
@ -267,7 +267,8 @@ PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, Forward
//BBS: add config related logs //BBS: add config related logs
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" finished, returned substitutions %1%")%substitutions.size(); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" finished, returned substitutions %1%")%substitutions.size();
return substitutions;
return std::make_pair(std::move(substitutions), errors_cummulative);
} }
//BBS: add function to generate differed preset for save //BBS: add function to generate differed preset for save

View File

@ -86,7 +86,7 @@ public:
// Load ini files of all types (print, filament, printer) from Slic3r::data_dir() / presets. // Load ini files of all types (print, filament, printer) from Slic3r::data_dir() / presets.
// Load selections (current print, current filaments, current printer) from config.ini // Load selections (current print, current filaments, current printer) from config.ini
// select preferred presets, if any exist // select preferred presets, if any exist
PresetsConfigSubstitutions load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule rule, std::pair<PresetsConfigSubstitutions, std::string> load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule rule,
const PresetPreferences& preferred_selection = PresetPreferences()); const PresetPreferences& preferred_selection = PresetPreferences());
// Load selections (current print, current filaments, current printer) from config.ini // Load selections (current print, current filaments, current printer) from config.ini

View File

@ -2609,6 +2609,10 @@ bool GUI_App::on_init_inner()
wxLog::SetLogLevel(wxLOG_Message); wxLog::SetLogLevel(wxLOG_Message);
#endif #endif
//set preset text
auto preset_path = fs::path(Slic3r::data_dir()) / PRESET_SYSTEM_DIR;
m_install_preset_fail_text = wxString::Format(_L("Failed to install preset files to %s.\nPlease make sure Bambu Studio has permission to delete and write in this directory,\nand it is not being occupied by the system or other applications."), preset_path.string());
// Set initialization of image handlers before any UI actions - See GH issue #7469 // Set initialization of image handlers before any UI actions - See GH issue #7469
wxInitAllImageHandlers(); wxInitAllImageHandlers();
#ifdef NDEBUG #ifdef NDEBUG
@ -2942,7 +2946,10 @@ bool GUI_App::on_init_inner()
// Enable all substitutions (in both user and system profiles), but log the substitutions in user profiles only. // Enable all substitutions (in both user and system profiles), but log the substitutions in user profiles only.
// If there are substitutions in system profiles, then a "reconfigure" event shall be triggered, which will force // If there are substitutions in system profiles, then a "reconfigure" event shall be triggered, which will force
// installation of a compatible system preset, thus nullifying the system preset substitutions. // installation of a compatible system preset, thus nullifying the system preset substitutions.
init_params->preset_substitutions = preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent); std::string errors_cummulative;
std::tie(init_params->preset_substitutions, errors_cummulative) = preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent);
if (!errors_cummulative.empty())
show_error(nullptr, errors_cummulative);
} }
catch (const std::exception& ex) { catch (const std::exception& ex) {
show_error(nullptr, ex.what()); show_error(nullptr, ex.what());
@ -7043,6 +7050,10 @@ bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage
mainframe->refresh_plugin_tips(); mainframe->refresh_plugin_tips();
// BBS: remove SLA related message // BBS: remove SLA related message
} }
else {
MessageDialog msg_dlg(mainframe, m_install_preset_fail_text, _L("Install presets failed"), wxAPPLY | wxOK);
msg_dlg.ShowModal();
}
return res; return res;
} }
@ -7257,7 +7268,8 @@ void GUI_App::check_updates(const bool verbose)
//updater_result = preset_updater->config_update(app_config->orig_version(), verbose ? PresetUpdater::UpdateParams::SHOW_TEXT_BOX : PresetUpdater::UpdateParams::SHOW_NOTIFICATION); //updater_result = preset_updater->config_update(app_config->orig_version(), verbose ? PresetUpdater::UpdateParams::SHOW_TEXT_BOX : PresetUpdater::UpdateParams::SHOW_NOTIFICATION);
updater_result = preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::SHOW_TEXT_BOX); updater_result = preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::SHOW_TEXT_BOX);
if (updater_result == PresetUpdater::R_INCOMPAT_EXIT) { if (updater_result == PresetUpdater::R_INCOMPAT_EXIT) {
mainframe->Close(); MessageDialog msg_dlg(mainframe, m_install_preset_fail_text, _L("Install presets failed"), wxAPPLY | wxOK);
msg_dlg.ShowModal();
} }
else if (updater_result == PresetUpdater::R_INCOMPAT_CONFIGURED) { else if (updater_result == PresetUpdater::R_INCOMPAT_CONFIGURED) {
m_app_conf_exists = true; m_app_conf_exists = true;

View File

@ -308,6 +308,7 @@ private:
bool m_side_popup_status{false}; bool m_side_popup_status{false};
bool m_show_error_msgdlg{false}; bool m_show_error_msgdlg{false};
wxString m_info_dialog_content; wxString m_info_dialog_content;
wxString m_install_preset_fail_text;
HttpServer m_http_server; HttpServer m_http_server;
boost::thread m_check_cert_thread; boost::thread m_check_cert_thread;

View File

@ -928,9 +928,14 @@ bool GuideFrame::apply_config(AppConfig *app_config, PresetBundle *preset_bundle
app_config->set_section(AppConfig::SECTION_FILAMENTS, enabled_filaments); app_config->set_section(AppConfig::SECTION_FILAMENTS, enabled_filaments);
app_config->set_vendors(m_appconfig_new); app_config->set_vendors(m_appconfig_new);
if (check_unsaved_preset_changes) if (check_unsaved_preset_changes) {
preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem, std::string errors_cummulative;
PresetsConfigSubstitutions preset_substitutions;
std::tie(preset_substitutions, errors_cummulative) = preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem,
{ preferred_model, preferred_variant, first_added_filament, std::string() }); { preferred_model, preferred_variant, first_added_filament, std::string() });
if (!errors_cummulative.empty())
show_error(nullptr, errors_cummulative);
}
// Update the selections from the compatibilty. // Update the selections from the compatibilty.
preset_bundle->export_selections(*app_config); preset_bundle->export_selections(*app_config);
@ -1101,10 +1106,40 @@ int GuideFrame::LoadProfileData()
// BBS: add json logic for vendor bundle // BBS: add json logic for vendor bundle
auto bbl_bundle_path = vendor_dir; auto bbl_bundle_path = vendor_dir;
bbl_bundle_rsrc = false; bbl_bundle_rsrc = false;
if (!boost::filesystem::exists((vendor_dir / PresetBundle::BBL_BUNDLE).replace_extension(".json"))) { boost::filesystem::path vendor_bbl_dir = (vendor_dir / PresetBundle::BBL_BUNDLE);
bbl_bundle_path = rsrc_vendor_dir; if (!boost::filesystem::exists(vendor_bbl_dir)) {
bbl_bundle_rsrc = true; bbl_bundle_rsrc = true;
} }
else {
boost::filesystem::path vendor_bbl_printer_dir = (vendor_bbl_dir / PRESET_PRINTER_NAME);
boost::filesystem::path vendor_bbl_filament_dir = (vendor_bbl_dir / PRESET_FILAMENT_NAME);
boost::filesystem::path vendor_bbl_print_dir = (vendor_bbl_dir / PRESET_PRINT_NAME);
boost::filesystem::path vendor_bbl_json = vendor_bbl_dir.replace_extension(".json");
if (!boost::filesystem::exists(vendor_bbl_printer_dir) || !boost::filesystem::is_directory(vendor_bbl_printer_dir)
|| !boost::filesystem::exists(vendor_bbl_filament_dir) || !boost::filesystem::is_directory(vendor_bbl_filament_dir)
|| !boost::filesystem::exists(vendor_bbl_print_dir) || !boost::filesystem::is_directory(vendor_bbl_print_dir)
|| !boost::filesystem::exists(vendor_bbl_json))
{
bbl_bundle_rsrc = true;
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__<< boost::format(", can not find subdirectory in data bbl, will use resource dir");
}
else {
auto is_file = [](const boost::filesystem::directory_entry& entry) {
return boost::filesystem::is_regular_file(entry.path());
};
auto begin = boost::filesystem::directory_iterator(vendor_bbl_printer_dir);
auto end = boost::filesystem::directory_iterator();
int file_count = std::count_if(begin, end, is_file);
if (file_count < 10) {
bbl_bundle_rsrc = true;
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__<< boost::format(", can not find enough files under printer directory of data, will use resource dir");
}
}
}
if (bbl_bundle_rsrc)
bbl_bundle_path = rsrc_vendor_dir;
// load BBL bundle from user data path // load BBL bundle from user data path
string targetPath = bbl_bundle_path.make_preferred().string(); string targetPath = bbl_bundle_path.make_preferred().string();

View File

@ -54,55 +54,68 @@ static const char *TMP_EXTENSION = ".data";
static const char *PRESET_SUBPATH = "presets"; static const char *PRESET_SUBPATH = "presets";
static const char *PLUGINS_SUBPATH = "plugins"; static const char *PLUGINS_SUBPATH = "plugins";
void copy_file_fix(const fs::path &source, const fs::path &target) int copy_file_fix(const fs::path &source, const fs::path &target, std::string& error_message)
{ {
BOOST_LOG_TRIVIAL(debug) << format("PresetUpdater: Copying %1% -> %2%", source, target); BOOST_LOG_TRIVIAL(debug) << format("PresetUpdater: Copying %1% -> %2%", source, target);
std::string error_message;
//CopyFileResult cfr = Slic3r::GUI::copy_file_gui(source.string(), target.string(), error_message, false); //CopyFileResult cfr = Slic3r::GUI::copy_file_gui(source.string(), target.string(), error_message, false);
CopyFileResult cfr = copy_file(source.string(), target.string(), error_message, false); CopyFileResult cfr = copy_file(source.string(), target.string(), error_message, false);
if (cfr != CopyFileResult::SUCCESS) { if (cfr != CopyFileResult::SUCCESS) {
BOOST_LOG_TRIVIAL(error) << "Copying failed(" << cfr << "): " << error_message; BOOST_LOG_TRIVIAL(error) << "Copying failed(" << cfr << "): " << error_message;
throw Slic3r::CriticalException(GUI::format( return -1;
_L("Copying of file %1% to %2% failed: %3%"),
source, target, error_message));
} }
// Permissions should be copied from the source file by copy_file(). We are not sure about the source // Permissions should be copied from the source file by copy_file(). We are not sure about the source
// permissions, let's rewrite them with 644. // permissions, let's rewrite them with 644.
static constexpr const auto perms = fs::owner_read | fs::owner_write | fs::group_read | fs::others_read; static constexpr const auto perms = fs::owner_read | fs::owner_write | fs::group_read | fs::others_read;
fs::permissions(target, perms); fs::permissions(target, perms);
return 0;
} }
//BBS: add directory copy //BBS: add directory copy
void copy_directory_fix(const fs::path &source, const fs::path &target) int copy_directory_fix(const fs::path &source, const fs::path &target, std::string& error_message)
{ {
int ret = 0;
BOOST_LOG_TRIVIAL(debug) << format("PresetUpdater: Copying %1% -> %2%", source, target); BOOST_LOG_TRIVIAL(debug) << format("PresetUpdater: Copying %1% -> %2%", source, target);
std::string error_message;
if (fs::exists(target)) if (fs::exists(target)) {
fs::remove_all(target); boost::system::error_code ec;
fs::create_directories(target); fs::remove_all(target, ec);
if (ec) {
error_message = ec.message();
BOOST_LOG_TRIVIAL(error) << "copy_directory_fix: Failed to remove existing target directory: " + error_message;
return -1;
}
}
boost::system::error_code ec;
fs::create_directories(target, ec);
if (ec) {
error_message = ec.message();
BOOST_LOG_TRIVIAL(error) << "copy_directory_fix: Failed to create target directory: " + error_message;
return -2;
}
for (auto &dir_entry : fs::directory_iterator(source)) for (auto &dir_entry : fs::directory_iterator(source))
{ {
std::string source_file = dir_entry.path().string(); fs::path source_file = dir_entry.path();
fs::path target_file = target / dir_entry.path().filename();
std::string name = dir_entry.path().filename().string(); std::string name = dir_entry.path().filename().string();
std::string target_file = target.string() + "/" + name;
if (fs::is_directory(dir_entry)) { if (fs::is_directory(dir_entry)) {
const auto target_path = target / name; ret = copy_directory_fix(source_file, target_file, error_message);
copy_directory_fix(dir_entry, target_path); if (ret)
return ret;
} }
else { else {
//CopyFileResult cfr = Slic3r::GUI::copy_file_gui(source_file, target_file, error_message, false); //CopyFileResult cfr = Slic3r::GUI::copy_file_gui(source_file, target_file, error_message, false);
CopyFileResult cfr = copy_file(source_file, target_file, error_message, false); CopyFileResult cfr = copy_file(source_file.string(), target_file.string(), error_message, false);
if (cfr != CopyFileResult::SUCCESS) { if (cfr != CopyFileResult::SUCCESS) {
BOOST_LOG_TRIVIAL(error) << "Copying failed(" << cfr << "): " << error_message; BOOST_LOG_TRIVIAL(error) << "Copying failed(" << cfr << "): " << error_message;
throw Slic3r::CriticalException(GUI::format( return -3;
_L("Copying directory %1% to %2% failed: %3%"),
source, target, error_message));
} }
} }
} }
return; return 0;
} }
struct Update struct Update
@ -135,14 +148,25 @@ struct Update
{} {}
//BBS: add directory support //BBS: add directory support
void install() const int install() const
{ {
int ret = 0;
std::string error_message;
if (is_directory) { if (is_directory) {
copy_directory_fix(source, target); ret = copy_directory_fix(source, target, error_message);
} }
else { else {
copy_file_fix(source, target); ret = copy_file_fix(source, target, error_message);
} }
/*if (ret) {
throw Slic3r::CriticalException(GUI::format(
_L("Copying of file %1% to %2% failed: %3%"),
source, target, error_message));
}*/
return ret;
} }
friend std::ostream& operator<<(std::ostream& os, const Update &self) friend std::ostream& operator<<(std::ostream& os, const Update &self)
@ -1251,18 +1275,40 @@ bool PresetUpdater::priv::install_bundles_rsrc(std::vector<std::string> bundles,
BOOST_LOG_TRIVIAL(info) << format("Installing %1% bundles from resources ...", bundles.size()); BOOST_LOG_TRIVIAL(info) << format("Installing %1% bundles from resources ...", bundles.size());
for (const auto &bundle : bundles) { for (const auto &bundle : bundles) {
auto path_in_rsrc = (this->rsrc_path / bundle).replace_extension(".json");
auto path_in_vendors = (this->vendor_path / bundle).replace_extension(".json");
updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version(), bundle, "", "");
//BBS: add directory support //BBS: add directory support
auto print_in_rsrc = this->rsrc_path / bundle; auto print_in_rsrc = this->rsrc_path / bundle;
auto print_in_vendors = this->vendor_path / bundle; auto print_in_vendors = this->vendor_path / bundle;
fs::path print_folder(print_in_vendors); fs::path print_folder(print_in_vendors);
if (fs::exists(print_folder))
fs::remove_all(print_folder); auto path_in_rsrc = (this->rsrc_path / bundle).replace_extension(".json");
fs::create_directories(print_folder); auto path_in_vendors = (this->vendor_path / bundle).replace_extension(".json");
//delete the json at first
boost::system::error_code ec;
if (fs::exists(path_in_vendors)) {
fs::remove(path_in_vendors, ec);
if (ec) {
BOOST_LOG_TRIVIAL(error) << boost::format("install_bundles_rsrc: Failed to remove file %1%, error %2% ") % path_in_vendors.string() % ec.message();
return false;
}
}
if (fs::exists(print_folder)) {
fs::remove_all(print_folder, ec);
if (ec) {
BOOST_LOG_TRIVIAL(error) << boost::format("install_bundles_rsrc: Failed to remove directory %1%, error %2% ") % print_folder.string() % ec.message();
return false;
}
}
fs::create_directories(print_folder, ec);
if (ec) {
BOOST_LOG_TRIVIAL(error) << boost::format("install_bundles_rsrc: Failed to create directory %1%, error %2% ")% print_folder.string() %ec.message();
return false;
}
updates.updates.emplace_back(std::move(print_in_rsrc), std::move(print_in_vendors), Version(), bundle, "", "", false, true); updates.updates.emplace_back(std::move(print_in_rsrc), std::move(print_in_vendors), Version(), bundle, "", "", false, true);
//copy json at the last
updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version(), bundle, "", "");
} }
return perform_updates(std::move(updates), snapshot); return perform_updates(std::move(updates), snapshot);
@ -1290,7 +1336,7 @@ void PresetUpdater::priv::check_installed_vendor_profiles() const
vendor_name.erase(vendor_name.size() - 5); vendor_name.erase(vendor_name.size() - 5);
if (enabled_config_update) { if (enabled_config_update) {
if ( fs::exists(path_in_vendor)) { if ( fs::exists(path_in_vendor)) {
if (enabled_vendors.find(vendor_name) != enabled_vendors.end()) { if ((vendor_name == PresetBundle::BBL_BUNDLE) || (enabled_vendors.find(vendor_name) != enabled_vendors.end())) {
Semver resource_ver = get_version_from_json(file_path); Semver resource_ver = get_version_from_json(file_path);
Semver vendor_ver = get_version_from_json(path_in_vendor.string()); Semver vendor_ver = get_version_from_json(path_in_vendor.string());
@ -1426,10 +1472,10 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version
version.config_version = cached_semver; version.config_version = cached_semver;
//version.comment = description; //version.comment = description;
updates.updates.emplace_back(std::move(file_path), std::move(path_in_vendor.string()), std::move(version), vendor_name, description, "", force_update, false);
//BBS: add directory support //BBS: add directory support
updates.updates.emplace_back(cache_folder / vendor_name, vendor_path / vendor_name, Version(), vendor_name, "", "", force_update, true); updates.updates.emplace_back(cache_folder / vendor_name, vendor_path / vendor_name, Version(), vendor_name, "", "", force_update, true);
updates.updates.emplace_back(std::move(file_path), std::move(path_in_vendor.string()), std::move(version), vendor_name, description, "", force_update, false);
} }
} }
} }
@ -1443,6 +1489,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version
//BBS: switch to new BBL.json configs //BBS: switch to new BBL.json configs
bool PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) const bool PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) const
{ {
int ret = 0;
//std::string vendor_path; //std::string vendor_path;
//std::string vendor_name; //std::string vendor_name;
if (updates.incompats.size() > 0) { if (updates.incompats.size() > 0) {
@ -1471,7 +1518,11 @@ bool PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons
for (const auto &update : updates.updates) { for (const auto &update : updates.updates) {
BOOST_LOG_TRIVIAL(info) << '\t' << update; BOOST_LOG_TRIVIAL(info) << '\t' << update;
update.install(); ret = update.install();
if (ret) {
BOOST_LOG_TRIVIAL(error) << boost::format("[BBL Updater]:perform_updates to %1% failed, ret=%2%")% update.target.string() % ret;
break;
}
//if (!update.is_directory) { //if (!update.is_directory) {
// vendor_path = update.source.parent_path().string(); // vendor_path = update.source.parent_path().string();
// vendor_name = update.vendor; // vendor_name = update.vendor;
@ -1496,7 +1547,7 @@ bool PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons
//} //}
} }
return true; return (ret == 0);
} }
void PresetUpdater::priv::set_waiting_updates(Updates u) void PresetUpdater::priv::set_waiting_updates(Updates u)
@ -1656,7 +1707,7 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3
ret = reload_configs_update_gui(); ret = reload_configs_update_gui();
if (!ret) { if (!ret) {
BOOST_LOG_TRIVIAL(warning) << format("[BBL Updater]:reload_configs_update_gui failed"); BOOST_LOG_TRIVIAL(warning) << format("[BBL Updater]:reload_configs_update_gui failed");
return R_INCOMPAT_EXIT; return R_ALL_CANCELED;
} }
Semver cur_ver = GUI::wxGetApp().preset_bundle->get_vendor_profile_version(PresetBundle::BBL_BUNDLE); Semver cur_ver = GUI::wxGetApp().preset_bundle->get_vendor_profile_version(PresetBundle::BBL_BUNDLE);
@ -1687,8 +1738,10 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3
const auto res = dlg.ShowModal(); const auto res = dlg.ShowModal();
if (res == wxID_OK) { if (res == wxID_OK) {
BOOST_LOG_TRIVIAL(debug) << "[BBL Updater]:selected yes to update"; BOOST_LOG_TRIVIAL(debug) << "[BBL Updater]:selected yes to update";
if (! p->perform_updates(std::move(updates)) || if (!p->perform_updates(std::move(updates)))
! reload_configs_update_gui()) return R_INCOMPAT_EXIT;
if (!reload_configs_update_gui())
return R_ALL_CANCELED; return R_ALL_CANCELED;
return R_UPDATE_INSTALLED; return R_UPDATE_INSTALLED;
} }