From eccf38b98751a24204e833e88a98930525913bd6 Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Thu, 1 Aug 2013 12:30:30 +0100 Subject: [PATCH 1/6] Added possibility of early exit to masterlist updating. The parsing test also has its output recorded so that if there aren't any issues, it doesn't need to be repeated later. --- src/backend/network.cpp | 22 +++++++++++++++++----- src/backend/network.h | 3 ++- src/gui/main.cpp | 24 ++++++++++++++++++++++-- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/backend/network.cpp b/src/backend/network.cpp index cb9e8e3a..a0480ad3 100644 --- a/src/backend/network.cpp +++ b/src/backend/network.cpp @@ -193,7 +193,7 @@ namespace boss { throw boss::error(boss::error::git_error, error_message); } - std::string UpdateMasterlist(Game& game, std::vector& parsingErrors) { + std::string UpdateMasterlist(Game& game, std::vector& parsingErrors, std::list& plugins, std::list& messages) { //First need to decide how the masterlist is updated: using Git or Subversion? //Look at the update URL to decide. @@ -268,16 +268,19 @@ namespace boss { } BOOST_LOG_TRIVIAL(trace) << "Reading the masterlist version from the svn info output."; - revision = GetRevision(output); + std::string newRevision = GetRevision(output); + + //Check if revision has changed. If it hasn't, exit early. + if (newRevision == revision) + return revision; + else + revision = newRevision; try { //Now test masterlist to see if it parses OK. BOOST_LOG_TRIVIAL(trace) << "Testing the new masterlist to see if it parses OK."; YAML::Node mlist = YAML::LoadFile(game.MasterlistPath().string()); - list messages; - list plugins; - if (mlist["globals"]) messages = mlist["globals"].as< list >(); if (mlist["plugins"]) @@ -446,6 +449,10 @@ namespace boss { BOOST_LOG_TRIVIAL(info) << "Received " << stats->indexed_objects << " of " << stats->total_objects << " objects in " << stats->received_bytes << " bytes."; + bool exitEarly = false; + if (stats->received_bytes == 0) //No update received. + exitEarly = true; + // Disconnect from the remote repository. BOOST_LOG_TRIVIAL(trace) << "Disconnecting from remote."; @@ -508,6 +515,11 @@ namespace boss { git_object_free(ptrs.obj); + if (exitEarly) { + ptrs.free(); + return string(revision); + } + BOOST_LOG_TRIVIAL(trace) << "Testing masterlist parsing."; //Now try parsing the masterlist. diff --git a/src/backend/network.h b/src/backend/network.h index 34d71fbc..ae1d46d2 100644 --- a/src/backend/network.h +++ b/src/backend/network.h @@ -28,6 +28,7 @@ #include #include "game.h" +#include "metadata.h" namespace boss { @@ -62,6 +63,6 @@ namespace boss { So when using Git, the Game::URL() function would return the path to the repository, and BOSS would expect that the masterlist be in the root directory of the repository, which is not unreasonable. */ - std::string UpdateMasterlist(Game& game, std::vector& parsingErrors); + std::string UpdateMasterlist(Game& game, std::vector& parsingErrors, std::list& plugins, std::list& messages); } #endif diff --git a/src/gui/main.cpp b/src/gui/main.cpp index a65e7940..a704bec1 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -408,13 +408,33 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { wxProgressDialog *progDia = new wxProgressDialog(translate("BOSS: Working..."),translate("BOSS working..."), 1000, this, wxPD_APP_MODAL|wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME); + /* MULTITHREADING + + The following things are quite slow: + + * Masterlist updating (need to fetch over network, parse masterlist possibly several times) + * Masterlist parsing (at least when it's big). + * Large plugin loading. + + As such, the following items will each have a separate thread: + + * Each plugin which has a size greater than the mean plugin size. + * All the plugins with sizes less than or equal to the mean plugin size. + * Masterlist updating. + + Userlist parsing could also get its own thread, but userlists are generally quite small so it probably isn't worth it. + + */ + BOOST_LOG_TRIVIAL(trace) << "Updating masterlist"; vector parsingErrors; string revision; try { - revision = UpdateMasterlist(_game, parsingErrors); + revision = UpdateMasterlist(_game, parsingErrors, mlist_plugins, mlist_messages); } catch (boss::error& e) { + mlist_plugins.clear(); + mlist_messages.clear(); BOOST_LOG_TRIVIAL(error) << "Masterlist update failed. Details: " << e.what(); messages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("Masterlist update failed. Details: %1%")) % e.what()).str())); } @@ -445,7 +465,7 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { group.create_thread(pll); group.join_all(); - if (fs::exists(_game.MasterlistPath())) { + if (mlist_plugins.empty() && mlist_messages.empty() && fs::exists(_game.MasterlistPath())) { BOOST_LOG_TRIVIAL(trace) << "Parsing masterlist..."; try { From 547b112da93ddd863cc953671b23712abb611104 Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Thu, 1 Aug 2013 15:48:56 +0100 Subject: [PATCH 2/6] Issue #9: Plugin loading multithreading now checks file sizes. --- src/gui/main.cpp | 53 +++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/gui/main.cpp b/src/gui/main.cpp index a704bec1..f52a26d4 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -73,16 +74,17 @@ namespace loc = boost::locale; struct plugin_loader { - plugin_loader(boss::Plugin& plugin, boss::Game& game, const string& filename, bool b) : _plugin(plugin), _game(game), _filename(filename), _b(b) {} + plugin_loader(boss::Plugin& plugin, boss::Game& game) : _plugin(plugin), _game(game) { + BOOST_LOG_TRIVIAL(info) << "Creating loader for: " << plugin.Name(); + } void operator () () { - _plugin = boss::Plugin(_game, _filename, _b); + BOOST_LOG_TRIVIAL(info) << "Loading: " << _plugin.Name(); + _plugin = boss::Plugin(_game, _plugin.Name(), false); } boss::Plugin& _plugin; boss::Game& _game; - string _filename; - bool _b; }; struct plugin_list_loader { @@ -90,13 +92,14 @@ struct plugin_list_loader { void operator () () { for (list::iterator it=_plugins.begin(), endit=_plugins.end(); it != endit; ++it) { - if (!boost::iequals(it->Name(), _game.Master())) + if (skipPlugins.find(it->Name()) == skipPlugins.end()) *it = boss::Plugin(_game, it->Name(), false); } } list& _plugins; boss::Game& _game; + set skipPlugins; }; bool BossGUI::OnInit() { @@ -442,29 +445,41 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { messages.push_back(boss::Message(boss::g_message_error, *it)); } - // Get a list of the plugins. - list plugins; - boost::thread_group group; + //First calculate the mean plugin size. Store it temporarily in a map to reduce filesystem lookups and file size recalculation. + size_t meanFileSize = 0; + boost::unordered_map tempMap; for (fs::directory_iterator it(_game.DataPath()); it != fs::directory_iterator(); ++it) { if (fs::is_regular_file(it->status()) && IsPlugin(it->path().string())) { + size_t fileSize = fs::file_size(it->path()); + meanFileSize += fileSize; - string filename = it->path().filename().string(); - BOOST_LOG_TRIVIAL(trace) << "Reading plugin: " << filename; - - plugins.push_back(boss::Plugin(filename)); - - if (filename == _game.Master()) { - plugin_loader pl(plugins.back(), _game, filename, false); - group.create_thread(pl); - } - - progDia->Pulse(); + tempMap.emplace(fileSize, boss::Plugin(it->path().filename().string())); } } + meanFileSize /= tempMap.size(); + + //Now load plugins. + list plugins; + boost::thread_group group; plugin_list_loader pll(plugins, _game); + for (boost::unordered_map::const_iterator it=tempMap.begin(), endit=tempMap.end(); it != endit; ++it) { + + BOOST_LOG_TRIVIAL(trace) << "Found plugin: " << it->second.Name(); + + plugins.push_back(it->second); + + if (it->first > meanFileSize) { + plugin_loader pl(plugins.back(), _game); + pll.skipPlugins.insert(it->second.Name()); + group.create_thread(pl); + } + + progDia->Pulse(); + } group.create_thread(pll); group.join_all(); + //Now load masterlist if it hasn't already been parsed. if (mlist_plugins.empty() && mlist_messages.empty() && fs::exists(_game.MasterlistPath())) { BOOST_LOG_TRIVIAL(trace) << "Parsing masterlist..."; From 47ffc74ce482ec3a5ee00ae6ea2d6b101510cff1 Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Thu, 1 Aug 2013 21:52:32 +0100 Subject: [PATCH 3/6] Fixes to masterlist parser and generator. --- src/backend/generators.h | 17 ++++++++--------- src/backend/parsers.h | 10 +++++----- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/backend/generators.h b/src/backend/generators.h index 2d3737ff..e3a6555b 100644 --- a/src/backend/generators.h +++ b/src/backend/generators.h @@ -565,17 +565,13 @@ namespace YAML { } inline Emitter& operator << (Emitter& out, const boss::MessageContent& rhs) { - if (rhs.Language() == boss::g_lang_any) - out << rhs.Str(); - else { - out << BeginMap; + out << BeginMap; - out << Key << "lang" << Value << boss::GetLangString(rhs.Language()); + out << Key << "lang" << Value << boss::GetLangString(rhs.Language()); - out << Key << "str" << Value << rhs.Str(); + out << Key << "str" << Value << rhs.Str(); - out << EndMap; - } + out << EndMap; } inline Emitter& operator << (Emitter& out, const boss::Message& rhs) { @@ -588,7 +584,10 @@ namespace YAML { else out << Key << "type" << Value << "error"; - out << Key << "content" << Value << rhs.Content(); + if (rhs.Content().size() == 1 && rhs.Content().front().Language() == boss::g_lang_any) + out << Key << "content" << Value << rhs.Content().front().Str(); + else + out << Key << "content" << Value << rhs.Content(); if (!rhs.Condition().empty()) out << Key << "condition" << Value << rhs.Condition(); diff --git a/src/backend/parsers.h b/src/backend/parsers.h index 96933534..cc27ab6c 100644 --- a/src/backend/parsers.h +++ b/src/backend/parsers.h @@ -167,8 +167,9 @@ namespace YAML { std::vector content; if (node["content"].IsSequence()) content = node["content"].as< std::vector >(); - else - content.push_back(node["content"].as()); + else { + content.push_back(boss::MessageContent(node["content"].as())); + } //Check now that at least one item in content is English if there are multiple items. if (content.size() > 1) { @@ -177,9 +178,8 @@ namespace YAML { if (it->Language() == boss::g_lang_english) found = true; } - //Commented out because the auto-converted masterlist has localisations as separate messages and so will always fail. - // if (!found) - // return false; + if (!found) + return false; } std::string condition; From 975cb5144bc0a624d5d53422ac7a0154f9996752 Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Thu, 1 Aug 2013 21:53:18 +0100 Subject: [PATCH 4/6] Simplified handling of parsing errors during masterlist update. --- src/backend/network.cpp | 6 +++--- src/backend/network.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/network.cpp b/src/backend/network.cpp index a0480ad3..ed25716d 100644 --- a/src/backend/network.cpp +++ b/src/backend/network.cpp @@ -193,7 +193,7 @@ namespace boss { throw boss::error(boss::error::git_error, error_message); } - std::string UpdateMasterlist(Game& game, std::vector& parsingErrors, std::list& plugins, std::list& messages) { + std::string UpdateMasterlist(Game& game, std::list& parsingErrors, std::list& plugins, std::list& messages) { //First need to decide how the masterlist is updated: using Git or Subversion? //Look at the update URL to decide. @@ -301,7 +301,7 @@ namespace boss { //Roll back one revision if there's an error. BOOST_LOG_TRIVIAL(error) << "Masterlist parsing failed. Masterlist revision " + revision + ": " + e.what(); - parsingErrors.push_back("Masterlist revision " + revision + ": " + e.what()); + parsingErrors.push_back(boss::Message(boss::g_message_error, "Masterlist revision " + revision + ": " + e.what())); command = g_path_svn.string() + " update --revision PREV \"" + game.MasterlistPath().string() + "\""; @@ -548,7 +548,7 @@ namespace boss { //Roll back one revision if there's an error. BOOST_LOG_TRIVIAL(error) << "Masterlist parsing failed. Masterlist revision " + string(revision) + ": " + e.what(); - parsingErrors.push_back("Masterlist revision " + string(revision) + ": " + e.what()); + parsingErrors.push_back(boss::Message(boss::g_message_error, "Masterlist revision " + string(revision) + ": " + e.what())); } } while (parsingFailed); diff --git a/src/backend/network.h b/src/backend/network.h index ae1d46d2..dfd53c58 100644 --- a/src/backend/network.h +++ b/src/backend/network.h @@ -63,6 +63,6 @@ namespace boss { So when using Git, the Game::URL() function would return the path to the repository, and BOSS would expect that the masterlist be in the root directory of the repository, which is not unreasonable. */ - std::string UpdateMasterlist(Game& game, std::vector& parsingErrors, std::list& plugins, std::list& messages); + std::string UpdateMasterlist(Game& game, std::list& parsingErrors, std::list& plugins, std::list& messages); } #endif From c4707df27958b5c2cae644e052e6ac544cb1f126 Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Thu, 1 Aug 2013 22:39:14 +0100 Subject: [PATCH 5/6] Multithreaded masterlist updating & parsing. --- src/gui/main.cpp | 125 ++++++++++++++++++++++++----------------------- 1 file changed, 63 insertions(+), 62 deletions(-) diff --git a/src/gui/main.cpp b/src/gui/main.cpp index f52a26d4..2ab3c628 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -92,8 +92,10 @@ struct plugin_list_loader { void operator () () { for (list::iterator it=_plugins.begin(), endit=_plugins.end(); it != endit; ++it) { - if (skipPlugins.find(it->Name()) == skipPlugins.end()) + if (skipPlugins.find(it->Name()) == skipPlugins.end()) { + BOOST_LOG_TRIVIAL(info) << "Loading: " << it->Name(); *it = boss::Plugin(_game, it->Name(), false); + } } } @@ -102,6 +104,46 @@ struct plugin_list_loader { set skipPlugins; }; +struct masterlist_updater_parser { + masterlist_updater_parser(boss::Game& game, list& errors, list& plugins, list& messages, string& revision) : _game(game), _errors(errors), _plugins(plugins), _messages(messages), _revision(revision) {} + + void operator () () { + + BOOST_LOG_TRIVIAL(trace) << "Updating masterlist"; + try { + _revision = UpdateMasterlist(_game, _errors, _plugins, _messages); + } catch (boss::error& e) { + _plugins.clear(); + _messages.clear(); + BOOST_LOG_TRIVIAL(error) << "Masterlist update failed. Details: " << e.what(); + _errors.push_back(boss::Message(boss::g_message_error, (format(loc::translate("Masterlist update failed. Details: %1%")) % e.what()).str())); + } + + if (_plugins.empty() && _messages.empty() && fs::exists(_game.MasterlistPath())) { + + BOOST_LOG_TRIVIAL(trace) << "Parsing masterlist..."; + try { + YAML::Node mlist = YAML::LoadFile(_game.MasterlistPath().string()); + + if (mlist["globals"]) + _messages = mlist["globals"].as< list >(); + if (mlist["plugins"]) + _plugins = mlist["plugins"].as< list >(); + } catch (YAML::Exception& e) { + BOOST_LOG_TRIVIAL(error) << "Masterlist parsing failed. Details: " << e.what(); + _errors.push_back(boss::Message(boss::g_message_error, (format(loc::translate("Masterlist parsing failed. Details: %1%")) % e.what()).str())); + } + BOOST_LOG_TRIVIAL(trace) << "Finished parsing masterlist."; + } + } + + boss::Game& _game; + list& _errors; + list& _plugins; + list& _messages; + string& _revision; +}; + bool BossGUI::OnInit() { //Check if GUI is already running. @@ -405,45 +447,16 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { BOOST_LOG_TRIVIAL(debug) << "Beginning sorting process."; - YAML::Node mlist, ulist; list messages, mlist_messages, ulist_messages; list mlist_plugins, ulist_plugins; + boost::thread_group group; + list plugins; + string revision; wxProgressDialog *progDia = new wxProgressDialog(translate("BOSS: Working..."),translate("BOSS working..."), 1000, this, wxPD_APP_MODAL|wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME); - /* MULTITHREADING - - The following things are quite slow: - - * Masterlist updating (need to fetch over network, parse masterlist possibly several times) - * Masterlist parsing (at least when it's big). - * Large plugin loading. - - As such, the following items will each have a separate thread: - - * Each plugin which has a size greater than the mean plugin size. - * All the plugins with sizes less than or equal to the mean plugin size. - * Masterlist updating. - - Userlist parsing could also get its own thread, but userlists are generally quite small so it probably isn't worth it. - - */ - - BOOST_LOG_TRIVIAL(trace) << "Updating masterlist"; - - vector parsingErrors; - string revision; - try { - revision = UpdateMasterlist(_game, parsingErrors, mlist_plugins, mlist_messages); - } catch (boss::error& e) { - mlist_plugins.clear(); - mlist_messages.clear(); - BOOST_LOG_TRIVIAL(error) << "Masterlist update failed. Details: " << e.what(); - messages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("Masterlist update failed. Details: %1%")) % e.what()).str())); - } - for (vector::const_iterator it=parsingErrors.begin(), endit=parsingErrors.end(); it != endit; ++it) { - messages.push_back(boss::Message(boss::g_message_error, *it)); - } + masterlist_updater_parser mup(_game, messages, mlist_plugins, mlist_messages, revision); + group.create_thread(mup); //First calculate the mean plugin size. Store it temporarily in a map to reduce filesystem lookups and file size recalculation. size_t meanFileSize = 0; @@ -459,8 +472,6 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { meanFileSize /= tempMap.size(); //Now load plugins. - list plugins; - boost::thread_group group; plugin_list_loader pll(plugins, _game); for (boost::unordered_map::const_iterator it=tempMap.begin(), endit=tempMap.end(); it != endit; ++it) { @@ -479,50 +490,40 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { group.create_thread(pll); group.join_all(); - //Now load masterlist if it hasn't already been parsed. - if (mlist_plugins.empty() && mlist_messages.empty() && fs::exists(_game.MasterlistPath())) { - BOOST_LOG_TRIVIAL(trace) << "Parsing masterlist..."; - - try { - mlist = YAML::LoadFile(_game.MasterlistPath().string()); - } catch (YAML::ParserException& e) { - BOOST_LOG_TRIVIAL(error) << "Masterlist parsing failed. Details: " << e.what(); - messages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("Masterlist parsing failed. Details: %1%")) % e.what()).str())); - } - if (mlist["globals"]) - mlist_messages = mlist["globals"].as< list >(); - if (mlist["plugins"]) - mlist_plugins = mlist["plugins"].as< list >(); - } - + //Now load userlist. if (fs::exists(_game.UserlistPath())) { BOOST_LOG_TRIVIAL(trace) << "Parsing userlist..."; try { - ulist = YAML::LoadFile(_game.UserlistPath().string()); + YAML::Node ulist = YAML::LoadFile(_game.UserlistPath().string()); + + if (ulist["plugins"]) + ulist_plugins = ulist["plugins"].as< list >(); } catch (YAML::ParserException& e) { BOOST_LOG_TRIVIAL(error) << "Userlist parsing failed. Details: " << e.what(); messages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("Userlist parsing failed. Details: %1%")) % e.what()).str())); } - if (ulist["plugins"]) - ulist_plugins = ulist["plugins"].as< list >(); } progDia->Pulse(); bool cyclicDependenciesExist = false; if (fs::exists(_game.MasterlistPath()) || fs::exists(_game.UserlistPath())) { - BOOST_LOG_TRIVIAL(trace) << "Merging plugin lists, evaluating conditions and and checking for install validity..."; + BOOST_LOG_TRIVIAL(trace) << "Merging plugin lists, evaluating conditions and checking for install validity..."; + + //Set language. + unsigned int lang = GetLangNum(_settings["Language"].as()); + //Merge all global message lists. BOOST_LOG_TRIVIAL(trace) << "Merging all global message lists."; - messages = mlist_messages; - messages.insert(messages.end(), ulist_messages.begin(), ulist_messages.end()); - - //Set language. - unsigned int lang = GetLangNum(_settings["Language"].as()); + if (!mlist_messages.empty()) + messages.insert(messages.end(), mlist_messages.begin(), mlist_messages.end()); + if (!ulist_messages.empty()) + messages.insert(messages.end(), ulist_messages.begin(), ulist_messages.end()); //Evaluate any conditions in the global messages. + BOOST_LOG_TRIVIAL(trace) << "Evaluating global message conditions..."; list::iterator it=messages.begin(); while (it != messages.end()) { if (!it->EvalCondition(_game, lang)) From d8bd7506ac9cb335ad58c3ec606b52849e990644 Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Fri, 2 Aug 2013 08:28:17 +0100 Subject: [PATCH 6/6] Exceptions thrown during global message condition eval are now caught. Also fixed global message conditions in v2 masterlists not being converted. --- src/backend/legacy-parser.h | 7 ++----- src/backend/metadata.cpp | 7 +++++++ src/backend/parsers.h | 3 +++ src/gui/main.cpp | 20 +++++++++++++------- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/backend/legacy-parser.h b/src/backend/legacy-parser.h index 469266d7..419872b0 100644 --- a/src/backend/legacy-parser.h +++ b/src/backend/legacy-parser.h @@ -501,11 +501,6 @@ namespace boss { std::list::iterator it = messages.begin(); while (it != messages.end()) { - std::string condition = it->Condition(); - ConvertCondition(condition); - - *it = Message(it->Type(), it->Content(), condition); - if (it->Type() == g_message_tag) { std::string message = it->ChooseContent(g_lang_any).Str(); @@ -684,6 +679,8 @@ namespace boss { std::vector mc_vec; mc_vec.push_back(MessageContent(content, langInt)); + ConvertCondition(condition); + message = Message(type, mc_vec, condition); } diff --git a/src/backend/metadata.cpp b/src/backend/metadata.cpp index 1c7af0cf..9e0adcd5 100644 --- a/src/backend/metadata.cpp +++ b/src/backend/metadata.cpp @@ -30,6 +30,7 @@ #include #include #include +#include using namespace std; @@ -83,6 +84,8 @@ namespace boss { } bool ConditionStruct::EvalCondition(boss::Game& game) const { + BOOST_LOG_TRIVIAL(trace) << "Evaluating condition: " << _condition; + if (_condition.empty()) return true; @@ -153,6 +156,10 @@ namespace boss { } bool Message::EvalCondition(boss::Game& game, const unsigned int language) { + + BOOST_LOG_TRIVIAL(trace) << "Choosing message language."; + + if (_content.size() > 1) { if (language == g_lang_any) //Can use a message of any language, so use the first string. _content.resize(1); diff --git a/src/backend/parsers.h b/src/backend/parsers.h index cc27ab6c..8f23d3a8 100644 --- a/src/backend/parsers.h +++ b/src/backend/parsers.h @@ -570,6 +570,9 @@ namespace boss { //Checks that the path (not regex) doesn't go outside any game folders. bool IsSafePath(const std::string& path) { + + BOOST_LOG_TRIVIAL(trace) << "Checking to see if the path \"" << path << "\" is safe."; + std::vector components; boost::split(components, path, boost::is_any_of("/\\")); components.pop_back(); diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 2ab3c628..9790efb9 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -75,12 +75,12 @@ namespace loc = boost::locale; struct plugin_loader { plugin_loader(boss::Plugin& plugin, boss::Game& game) : _plugin(plugin), _game(game) { - BOOST_LOG_TRIVIAL(info) << "Creating loader for: " << plugin.Name(); } void operator () () { BOOST_LOG_TRIVIAL(info) << "Loading: " << _plugin.Name(); _plugin = boss::Plugin(_game, _plugin.Name(), false); + BOOST_LOG_TRIVIAL(info) << "Finished loading: " << _plugin.Name(); } boss::Plugin& _plugin; @@ -95,6 +95,7 @@ struct plugin_list_loader { if (skipPlugins.find(it->Name()) == skipPlugins.end()) { BOOST_LOG_TRIVIAL(info) << "Loading: " << it->Name(); *it = boss::Plugin(_game, it->Name(), false); + BOOST_LOG_TRIVIAL(info) << "Finished loading: " << it->Name(); } } } @@ -524,12 +525,17 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { //Evaluate any conditions in the global messages. BOOST_LOG_TRIVIAL(trace) << "Evaluating global message conditions..."; - list::iterator it=messages.begin(); - while (it != messages.end()) { - if (!it->EvalCondition(_game, lang)) - it = messages.erase(it); - else - ++it; + try { + list::iterator it=messages.begin(); + while (it != messages.end()) { + if (!it->EvalCondition(_game, lang)) + it = messages.erase(it); + else + ++it; + } + } catch (boss::error& e) { + BOOST_LOG_TRIVIAL(error) << "A global message contains a condition that could not be evaluated. Details: " << e.what(); + messages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("A global message contains a condition that could not be evaluated. Details: %1%")) % e.what()).str())); } //Merge plugin list, masterlist and userlist plugin data.