Revert "Refactored masterlist updating code."

This reverts commit a5b8a1c89a.
This commit is contained in:
Oliver Hamlet
2014-12-20 19:56:24 +00:00
parent 0e9977a006
commit 759c4fe1f9
7 changed files with 224 additions and 178 deletions
-58
View File
@@ -28,7 +28,6 @@
#include "error.h"
#include "metadata.h"
#include "parsers.h"
#include "streams.h"
#include <boost/algorithm/string.hpp>
@@ -60,63 +59,6 @@ namespace loot {
return games;
}
// MetadataList member functions
//------------------------------
void MetadataList::Load(boost::filesystem::path& filepath) {
plugins.clear();
messages.clear();
BOOST_LOG_TRIVIAL(debug) << "Loading file: " << filepath;
loot::ifstream in(filepath);
YAML::Node metadataList = YAML::Load(in);
in.close();
if (metadataList["plugins"])
plugins = metadataList["plugins"].as< list<Plugin> >();
if (metadataList["globals"])
messages = metadataList["globals"].as< list<Message> >();
BOOST_LOG_TRIVIAL(debug) << "File loaded successfully.";
}
// Masterlist member functions
//----------------------------
void Masterlist::Load(Game& game, const unsigned int language) {
try {
Update(game, language);
}
catch (error& e) {
if (e.code() != error::ok) {
// Error wasn't a parsing error. Need to try parsing masterlist if it exists.
try {
MetadataList::Load(game.MasterlistPath());
}
catch (...) {}
}
throw e;
}
}
std::string Masterlist::GetRevision(boost::filesystem::path& path) {
if (revision.empty())
GetGitInfo(path);
return revision;
}
std::string Masterlist::GetDate(boost::filesystem::path& path) {
if (date.empty())
GetGitInfo(path);
return date;
}
// Game member functions
//----------------------
Game::Game() : id(Game::autodetect) {}
Game::Game(const unsigned int gameCode, const std::string& folder) : id(gameCode) {
+4 -83
View File
@@ -40,8 +40,6 @@
#include <yaml-cpp/yaml.h>
namespace loot {
class Game;
/* Each Game object should store the config details specific to that game.
It should also store the plugin and masterlist data for that game.
@@ -53,82 +51,6 @@ namespace loot {
data. Plugin data should be loaded as header-only and as full data.
*/
class MetadataList {
public:
void Load(boost::filesystem::path& filepath);
std::list<Plugin> plugins;
std::list<Message> messages;
std::unordered_map<std::string, bool> conditionCache; //Holds lowercased strings.
std::unordered_map<std::string, uint32_t> crcCache; //Holds lowercased strings.
};
class Masterlist : public MetadataList {
public:
void Load(Game& game, const unsigned int language); //Handles update with load fallback.
void Update(Game& game, const unsigned int language);
std::string GetRevision(boost::filesystem::path& path);
std::string GetDate(boost::filesystem::path& path);
private:
void GetGitInfo(boost::filesystem::path& path);
std::string revision;
std::string date;
};
/*
class PluginCache {
bool IsActive(const std::string& plugin) const;
void GetLoadOrder(std::list<std::string>& loadOrder) const;
void SetLoadOrder(const std::list<Plugin>& loadOrder) const; //Modifies game load order, even though const.
void RefreshActivePluginsList();
void RedatePlugins(); //Change timestamps to match load order (Skyrim only).
void LoadPlugins(bool headersOnly); //Loads all installed plugins.
std::unordered_map<std::string, Plugin> plugins; //Map so that plugin data can be edited.
std::unordered_set<std::string> activePlugins; //Holds lowercased strings.
};
*/
// A couple of plugin loader classes for handling plugin loading in separate threads.
class PluginLoader {
public:
PluginLoader(Plugin& plugin, Game& game) : _plugin(plugin), _game(game) {
}
void operator () () {
_plugin = Plugin(_game, _plugin.Name(), false);
}
Plugin& _plugin;
Game& _game;
std::string _filename;
bool _b;
};
class PluginsLoader {
public:
PluginsLoader(std::list<Plugin>& plugins, Game& game) : _plugins(plugins), _game(game) {}
void operator () () {
for (auto &plugin : _plugins) {
if (skipPlugins.find(plugin.Name()) == skipPlugins.end()) {
plugin = Plugin(_game, plugin.Name(), false);
}
}
}
std::list<Plugin>& _plugins;
Game& _game;
std::set<std::string> skipPlugins;
};
class Game {
public:
//Game functions.
@@ -160,8 +82,8 @@ namespace loot {
boost::filesystem::path UserlistPath() const;
boost::filesystem::path ReportDataPath() const;
//TO BE REMOVED
//Game plugin functions.
bool IsActive(const std::string& plugin) const;
void GetLoadOrder(std::list<std::string>& loadOrder) const;
@@ -174,12 +96,11 @@ namespace loot {
//Caches for condition results, active plugins and CRCs.
std::unordered_map<std::string, bool> conditionCache; //Holds lowercased strings.
std::unordered_map<std::string, uint32_t> crcCache; //Holds lowercased strings.
//END TO BE REMOVED
//Plugin data and metadata lists.
Masterlist masterlist;
MetadataList masterlist;
MetadataList userlist;
std::unordered_map<std::string, Plugin> plugins; //Map so that plugin data can be edited. TO BE REMOVED
std::unordered_map<std::string, Plugin> plugins; //Map so that plugin data can be edited.
espm::Settings espm_settings;
@@ -201,7 +122,7 @@ namespace loot {
boost::filesystem::path gamePath; //Path to the game's folder.
std::unordered_set<std::string> activePlugins; //Holds lowercased strings. TO BE REMOVED
std::unordered_set<std::string> activePlugins; //Holds lowercased strings.
//Creates directory in LOOT folder for LOOT's game-specific files.
void CreateLOOTGameFolder();
+18
View File
@@ -763,6 +763,24 @@ namespace loot {
return boost::filesystem::exists(game.DataPath() / (name.substr(0, name.length() - 3) + "bsa"));
}
void MetadataList::Load(boost::filesystem::path& filepath) {
plugins.clear();
messages.clear();
BOOST_LOG_TRIVIAL(debug) << "Loading file: " << filepath;
loot::ifstream in(filepath);
YAML::Node metadataList = YAML::Load(in);
in.close();
if (metadataList["plugins"])
plugins = metadataList["plugins"].as< list<Plugin> >();
if (metadataList["globals"])
messages = metadataList["globals"].as< list<Message> >();
BOOST_LOG_TRIVIAL(debug) << "File loaded successfully.";
}
size_t plugin_hash::operator () (const Plugin& p) const {
size_t seed = 0;
boost::hash_combine(seed, p.Name());
+8
View File
@@ -243,6 +243,14 @@ namespace loot {
size_t numOverrideRecords;
};
class MetadataList {
public:
void Load(boost::filesystem::path& filepath);
std::list<Plugin> plugins;
std::list<Message> messages;
};
struct plugin_hash : std::unary_function<Plugin, size_t> {
size_t operator () (const Plugin& p) const;
};
+29 -25
View File
@@ -22,11 +22,11 @@
<http://www.gnu.org/licenses/>.
*/
#include "network.h"
#include "error.h"
#include "parsers.h"
#include "streams.h"
#include "helpers.h"
#include "game.h"
#include <boost/log/trivial.hpp>
#include <boost/locale.hpp>
@@ -92,6 +92,11 @@ namespace loot {
std::string ui_message;
};
int progress_cb(const char *str, int len, void *data) {
BOOST_LOG_TRIVIAL(info) << string(str, len);
return 0;
}
bool are_files_equal(const void * buf1, size_t buf1_size, const void * buf2, size_t buf2_size) {
if (buf1_size != buf2_size)
return false;
@@ -109,17 +114,12 @@ namespace loot {
return git_repository_open_ext(NULL, path.string().c_str(), GIT_REPOSITORY_OPEN_NO_SEARCH, NULL) == 0;
}
void Masterlist::GetGitInfo(boost::filesystem::path& path) {
if (!fs::exists(path.parent_path() / ".git")) {
revision = "Unknown: Git repository missing";
date = "Unknown: Git repository missing";
return;
}
else if (!fs::exists(path)) {
revision = "N/A: No masterlist present";
date = "N/A: No masterlist present";
return;
std::pair<string, string> GetMasterlistRevision(const Game& game) {
if (!fs::exists(game.MasterlistPath().parent_path() / ".git")) {
return pair<string, string>("Unknown: Git repository missing", "Unknown: Git repository missing");
}
else if (!fs::exists(game.MasterlistPath()))
return pair<string, string>("N/A: No masterlist present", "N/A: No masterlist present");
else {
/* Compares HEAD to the working dir.
1. Get an object for the masterlist in HEAD.
@@ -128,9 +128,9 @@ namespace loot {
4. Compare the file and blob buffers.
*/
git_handler git;
git.ui_message = "An error occurred while trying to read the local masterlist's version. If this error happens again, try deleting the \".git\" folder in " + path.parent_path().string() + ".";
git.ui_message = "An error occurred while trying to read the local masterlist's version. If this error happens again, try deleting the \".git\" folder in \"%LOCALAPPDATA%\\LOOT\\" + game.FolderName() + "\".";
BOOST_LOG_TRIVIAL(debug) << "Existing repository found, attempting to open it.";
git.call(git_repository_open(&git.repo, path.parent_path().string().c_str()));
git.call(git_repository_open(&git.repo, game.MasterlistPath().parent_path().string().c_str()));
BOOST_LOG_TRIVIAL(trace) << "Getting HEAD masterlist object.";
git.call(git_revparse_single(&git.obj, git.repo, "HEAD:masterlist.yaml"));
@@ -140,7 +140,7 @@ namespace loot {
BOOST_LOG_TRIVIAL(debug) << "Opening masterlist in working directory.";
std::string mlist;
loot::ifstream ifile(path, ios::binary);
loot::ifstream ifile(game.MasterlistPath().string().c_str(), ios::binary);
if (ifile.fail())
throw error(error::path_read_fail, "Couldn't open masterlist.");
ifile.unsetf(ios::skipws); // No white space skipping!
@@ -153,6 +153,7 @@ namespace loot {
BOOST_LOG_TRIVIAL(debug) << "Comparing files.";
if (are_files_equal(git_blob_rawcontent(git.blob), git_blob_rawsize(git.blob), mlist.data(), mlist.length())) {
string revision, date;
//Need to get the HEAD object, because the individual file has a different SHA.
git_object_free(git.obj);
git.obj = nullptr; //Just to be safe.
@@ -175,17 +176,15 @@ namespace loot {
out << boost::locale::as::ftime("%Y-%m-%d") << dateTime;
date = out.str();
return;
return pair<string, string>(revision, date);
}
else {
revision = "Unknown: Masterlist edited";
date = "Unknown: Masterlist edited";
return;
return pair<string, string>("Unknown: Masterlist edited", "Unknown: Masterlist edited");
}
}
}
void Masterlist::Update(Game& game, const unsigned int language) {
std::pair<std::string, std::string> UpdateMasterlist(Game& game, std::list<Message>& parsingErrors, std::list<Plugin>& plugins, std::list<Message>& messages, const unsigned int language) {
git_handler git;
fs::path repo_path = game.MasterlistPath().parent_path();
string repo_branch = game.RepoBranch();
@@ -388,7 +387,7 @@ namespace loot {
// and try again.
bool parsingFailed = false;
std::string parsingError;
string revision, date;
git.ui_message = "An error occurred while trying to read information on the updated masterlist. If this error happens again, try deleting the \".git\" folder in \"%LOCALAPPDATA%\\LOOT\\" + game.FolderName() + "\".";
do {
// Get some descriptive info about what was checked out.
@@ -429,7 +428,14 @@ namespace loot {
//Now try parsing the masterlist.
BOOST_LOG_TRIVIAL(debug) << "Testing masterlist parsing.";
try {
this->MetadataList::Load(game.MasterlistPath());
loot::ifstream in(game.MasterlistPath());
YAML::Node mlist = YAML::Load(in);
in.close();
if (mlist["globals"])
messages = mlist["globals"].as< list<loot::Message> >();
if (mlist["plugins"])
plugins = mlist["plugins"].as< list<loot::Plugin> >();
for (auto &plugin: plugins) {
plugin.EvalAllConditions(game, language);
@@ -460,12 +466,10 @@ namespace loot {
BOOST_LOG_TRIVIAL(trace) << "Performing a Git checkout of HEAD.";
git.call(git_checkout_head(git.repo, &checkout_opts));
if (parsingError.empty())
parsingError = boost::locale::translate("Masterlist revision").str() + " " + string(revision) + ": " + e.what() + " " + boost::locale::translate("Rolled back to the previous revision.").str();
parsingErrors.push_back(loot::Message(loot::Message::error, boost::locale::translate("Masterlist revision").str() + " " + string(revision) + ": " + e.what() + " " + boost::locale::translate("Rolled back to the previous revision.").str()));
}
} while (parsingFailed);
if (!parsingError.empty())
throw error(error::ok, parsingError); //Throw an OK because the process still completed in a successful state.
return pair<string, string>(revision, date);
}
}
+40
View File
@@ -0,0 +1,40 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2014 WrinklyNinja
This file is part of LOOT.
LOOT is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
LOOT is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LOOT. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __LOOT_NETWORK__
#define __LOOT_NETWORK__
#include <vector>
#include <string>
#include "game.h"
#include "metadata.h"
namespace loot {
std::pair<std::string, std::string> UpdateMasterlist(Game& game, std::list<Message>& parsingErrors, std::list<Plugin>& plugins, std::list<Message>& messages, const unsigned int language);
std::pair<std::string, std::string> GetMasterlistRevision(const Game& game);
}
#endif
+125 -12
View File
@@ -33,6 +33,7 @@
#include "../backend/error.h"
#include "../backend/helpers.h"
#include "../backend/generators.h"
#include "../backend/network.h"
#include "../backend/streams.h"
#include "../backend/graph.h"
@@ -70,6 +71,123 @@ using boost::format;
namespace fs = boost::filesystem;
namespace loc = boost::locale;
struct plugin_loader {
plugin_loader(loot::Plugin& plugin, loot::Game& game) : _plugin(plugin), _game(game) {
}
void operator () () {
_plugin = loot::Plugin(_game, _plugin.Name(), false);
}
loot::Plugin& _plugin;
loot::Game& _game;
string _filename;
bool _b;
};
struct plugin_list_loader {
plugin_list_loader(list<loot::Plugin>& plugins, loot::Game& game) : _plugins(plugins), _game(game) {}
void operator () () {
for (auto &plugin : _plugins) {
if (skipPlugins.find(plugin.Name()) == skipPlugins.end()) {
plugin = loot::Plugin(_game, plugin.Name(), false);
}
}
}
list<loot::Plugin>& _plugins;
loot::Game& _game;
set<string> skipPlugins;
};
struct masterlist_updater_parser {
masterlist_updater_parser(bool doUpdate, loot::Game& game, list<loot::Message>& errors, list<loot::Plugin>& plugins, list<loot::Message>& messages, string& revision, string& date, const unsigned int language) : _doUpdate(doUpdate), _game(game), _errors(errors), _plugins(plugins), _messages(messages), _revision(revision), _date(date), _language(language) {}
void operator () () {
if (_doUpdate) {
BOOST_LOG_TRIVIAL(debug) << "Updating masterlist";
try {
pair<string, string> ret = UpdateMasterlist(_game, _errors, _plugins, _messages, _language);
_revision = ret.first;
_date = ret.second;
} catch (std::exception& e) {
_plugins.clear();
_messages.clear();
BOOST_LOG_TRIVIAL(error) << "Masterlist update failed. Details: " << e.what();
_errors.push_back(loot::Message(loot::Message::error, (format(loc::translate("Masterlist update failed. Details: %1%")) % e.what()).str()));
//Try getting masterlist revision anyway.
try {
pair<string, string> ret = GetMasterlistRevision(_game);
_revision = ret.first;
_date = ret.second;
}
catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Masterlist revision check failed. Details: " << e.what();
_errors.push_back(loot::Message(loot::Message::error, (format(loc::translate("Masterlist revision check failed. Details: %1%")) % e.what()).str()));
}
}
}
else {
BOOST_LOG_TRIVIAL(debug) << "Getting masterlist revision";
try {
pair<string, string> ret = GetMasterlistRevision(_game);
_revision = ret.first;
_date = ret.second;
}
catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Masterlist revision check failed. Details: " << e.what();
_errors.push_back(loot::Message(loot::Message::error, (format(loc::translate("Masterlist revision check failed. Details: %1%")) % e.what()).str()));
}
}
if (_plugins.empty() && _messages.empty() && fs::exists(_game.MasterlistPath())) {
BOOST_LOG_TRIVIAL(debug) << "Parsing masterlist...";
try {
loot::ifstream in(_game.MasterlistPath());
YAML::Node mlist = YAML::Load(in);
in.close();
if (mlist["globals"])
_messages = mlist["globals"].as< list<loot::Message> >();
if (mlist["plugins"])
_plugins = mlist["plugins"].as< list<loot::Plugin> >();
} catch (YAML::Exception& e) {
BOOST_LOG_TRIVIAL(error) << "Masterlist parsing failed. Details: " << e.what();
_errors.push_back(loot::Message(loot::Message::error, (format(loc::translate("Masterlist parsing failed. Details: %1%")) % e.what()).str()));
}
BOOST_LOG_TRIVIAL(debug) << "Finished parsing masterlist.";
}
if (_revision.empty()) {
if (fs::exists(_game.MasterlistPath()))
_revision = loc::translate("Unknown");
else
_revision = loc::translate("No masterlist");
}
if (_date.empty()) {
if (fs::exists(_game.MasterlistPath()))
_date = loc::translate("Unknown");
else
_date = loc::translate("No masterlist");
}
}
bool _doUpdate;
loot::Game& _game;
list<loot::Message>& _errors;
list<loot::Plugin>& _plugins;
list<loot::Message>& _messages;
string& _revision;
string& _date;
unsigned int _language;
};
bool LOOT::OnInit() {
//Check if GUI is already running.
@@ -628,6 +746,7 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
list<loot::Plugin> mlist_plugins, ulist_plugins;
list<loot::Plugin> plugins;
boost::thread_group group;
string revision, date;
wxProgressDialog *progDia = new wxProgressDialog(translate("LOOT: Working..."),translate("LOOT working..."), 1000, this, wxPD_APP_MODAL|wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME);
@@ -645,14 +764,8 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
BOOST_LOG_TRIVIAL(info) << "Using message language: " << Language(lang).Name();
bool doUpdate = _settings["Update Masterlist"] && _settings["Update Masterlist"].as<bool>();
group.create_thread([this, lang, &messages]() {
try {
this->_game->masterlist.Load(*this->_game, lang);
}
catch (exception &e) {
messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("Masterlist parsing failed. Details: %1%")) % e.what()).str()));
}
});
masterlist_updater_parser mup(doUpdate, *_game, messages, mlist_plugins, mlist_messages, revision, date, lang);
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;
@@ -669,7 +782,7 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
meanFileSize /= tempMap.size();
//Now load plugins.
PluginsLoader pll(plugins, *_game);
plugin_list_loader pll(plugins, *_game);
for (const auto &pluginPair: tempMap) {
BOOST_LOG_TRIVIAL(info) << "Found plugin: " << pluginPair.first;
@@ -678,7 +791,7 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
if (pluginPair.second > meanFileSize) {
pll.skipPlugins.insert(pluginPair.first);
PluginLoader pl(plugins.back(), *_game);
plugin_loader pl(plugins.back(), *_game);
group.create_thread(pl);
}
@@ -962,8 +1075,8 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
GenerateReportData(*_game,
messages,
plugins,
_game->masterlist.GetRevision(_game->MasterlistPath()),
_game->masterlist.GetDate(_game->MasterlistPath()),
revision,
date,
doUpdate);
} catch (std::exception& e) {
wxMessageBox(