Replace Boost.Log with spdlog

This removes a bunch of Boost dependencies, and doesn't cause LOOT
to crash on launch, so fixes loot/loot#835 too.
This commit is contained in:
Oliver Hamlet
2017-11-02 19:04:10 +00:00
parent af05aafe67
commit 8ef3fea3d3
24 changed files with 556 additions and 236 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ install:
- export CXX="g++-6" CC="gcc-6"
# Build Boost.
- wget https://raw.githubusercontent.com/WrinklyNinja/ci-scripts/1.5.0/install_boost.py
- python install_boost.py --directory ~ --boost-version 1.64.0 -a 64 -t gcc-6 atomic chrono date_time filesystem iostreams locale log regex system thread
- python install_boost.py --directory ~ --boost-version 1.64.0 -a 64 -t gcc-6 filesystem locale system
# Install packages for generating documentation
- pip install --user -r docs/requirements.txt
# Add sphinx-build to PATH
+14 -3
View File
@@ -61,7 +61,7 @@ ELSE ()
set(RUST_TARGET x86_64-unknown-linux-gnu)
ENDIF ()
find_package(Boost REQUIRED COMPONENTS atomic log log_setup regex locale thread date_time chrono filesystem system iostreams)
find_package(Boost REQUIRED COMPONENTS locale filesystem system)
ExternalProject_Add(GTest
PREFIX "external"
@@ -137,6 +137,15 @@ ExternalProject_Add(testing-plugins
BUILD_COMMAND ""
INSTALL_COMMAND "")
ExternalProject_Add(spdlog
PREFIX "external"
URL "https://github.com/gabime/spdlog/archive/v0.14.0.tar.gz"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "")
ExternalProject_Get_Property(spdlog SOURCE_DIR)
set(SPDLOG_INCLUDE_DIRS "${SOURCE_DIR}/include")
ExternalProject_Add(yaml-cpp
PREFIX "external"
URL "https://github.com/WrinklyNinja/yaml-cpp/archive/patched-for-loot.tar.gz"
@@ -223,6 +232,7 @@ set (LOOT_API_HEADERS "${CMAKE_SOURCE_DIR}/include/loot/api.h"
"${CMAKE_SOURCE_DIR}/src/api/plugin/plugin_sorter.h"
"${CMAKE_SOURCE_DIR}/src/api/helpers/git_helper.h"
"${CMAKE_SOURCE_DIR}/src/api/helpers/crc.h"
"${CMAKE_SOURCE_DIR}/src/api/helpers/logging.h"
"${CMAKE_SOURCE_DIR}/src/api/helpers/version.h"
"${CMAKE_SOURCE_DIR}/src/api/helpers/windows_encoding_converters.h")
@@ -277,6 +287,7 @@ include_directories ("${CMAKE_SOURCE_DIR}/src"
${LIBGIT2_INCLUDE_DIRS}
${ESPLUGIN_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${SPDLOG_INCLUDE_DIRS}
${YAML_CPP_INCLUDE_DIRS}
${GTEST_INCLUDE_DIRS}
${PSEUDOSEM_INCLUDE_DIRS})
@@ -339,12 +350,12 @@ ENDIF ()
# Build tests.
add_executable (loot_api_internals_tests ${LOOT_API_SRC} ${LOOT_API_HEADERS} ${LOOT_TESTS_SRC} ${LOOT_TESTS_HEADERS})
add_dependencies (loot_api_internals_tests esplugin libgit2 libloadorder pseudosem yaml-cpp GTest testing-metadata testing-plugins)
add_dependencies (loot_api_internals_tests esplugin libgit2 libloadorder pseudosem spdlog yaml-cpp GTest testing-metadata testing-plugins)
target_link_libraries(loot_api_internals_tests ${Boost_LIBRARIES} ${LIBGIT2_LIBRARIES} ${ESPLUGIN_LIBRARIES} ${LIBLOADORDER_LIBRARIES} ${LOOT_LIBS} ${YAML_CPP_LIBRARIES} ${GTEST_LIBRARIES})
# Build API.
add_library (loot_api ${LOOT_API_SRC} ${LOOT_API_HEADERS})
add_dependencies (loot_api esplugin libgit2 libloadorder pseudosem yaml-cpp)
add_dependencies (loot_api esplugin libgit2 libloadorder pseudosem spdlog yaml-cpp)
target_link_libraries(loot_api ${Boost_LIBRARIES} ${LIBGIT2_LIBRARIES} ${ESPLUGIN_LIBRARIES} ${LIBLOADORDER_LIBRARIES} ${LOOT_LIBS} ${YAML_CPP_LIBRARIES})
# Build API tests.
+1 -1
View File
@@ -32,7 +32,7 @@ install:
- ps: (New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/WrinklyNinja/ci-scripts/1.1.0/install_boost.py', "$env:APPVEYOR_BUILD_FOLDER\install_boost.py")
- ps: (New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/WrinklyNinja/ci-scripts/1.2.0/delete_old_bintray_versions.py', "$env:APPVEYOR_BUILD_FOLDER\delete_old_bintray_versions.py")
- ps: if ($env:PLATFORM -eq "Win32") { $env:ADDRESS_MODEL = '32' } else { $env:ADDRESS_MODEL = '64' }
- ps: python $env:APPVEYOR_BUILD_FOLDER\install_boost.py -d C:\projects -b 1.61.0 -a $env:ADDRESS_MODEL atomic chrono date_time filesystem iostreams locale log regex system thread
- ps: python $env:APPVEYOR_BUILD_FOLDER\install_boost.py -d C:\projects -b 1.61.0 -a $env:ADDRESS_MODEL filesystem locale system
before_build:
- cd %APPVEYOR_BUILD_FOLDER%
+6 -52
View File
@@ -25,14 +25,9 @@
#include "loot/api.h"
#include <boost/filesystem.hpp>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/file.hpp>
#include "api/game/game.h"
#include "api/helpers/logging.h"
namespace fs = boost::filesystem;
@@ -46,54 +41,13 @@ std::string ResolvePath(const std::string& path) {
return fs::read_symlink(path).string();
}
LogLevel mapFromBoostLog(boost::log::trivial::severity_level severity) {
using boost::log::trivial::severity_level;
switch (severity) {
case severity_level::trace:
return LogLevel::trace;
case severity_level::debug:
return LogLevel::debug;
case severity_level::info:
return LogLevel::info;
case severity_level::warning:
return LogLevel::warning;
case severity_level::error:
return LogLevel::error;
case severity_level::fatal:
return LogLevel::fatal;
default:
return LogLevel::trace;
}
}
class LoggingSink : public boost::log::sinks::basic_formatted_sink_backend<char, boost::log::sinks::concurrent_feeding> {
public:
LoggingSink(std::function<void(LogLevel, const char*)> callback) {
this->callback = callback;
}
void consume(const boost::log::record_view& rec, const std::string& str) {
using boost::log::trivial::severity_level;
auto severity = rec.attribute_values()[boost::log::aux::default_attribute_names::severity()].extract<severity_level>();
if (!severity) {
return;
}
callback(mapFromBoostLog(*severity), str.c_str());
}
private:
std::function<void(LogLevel, const char*)> callback;
};
LOOT_API void SetLoggingCallback(std::function<void(LogLevel, const char*)> callback) {
typedef boost::log::sinks::synchronous_sink<LoggingSink> sink_t;
auto sink = std::make_shared<SpdLoggingSink>(callback);
auto logger = std::make_shared<spdlog::logger>(LOGGER_NAME, sink);
logger->set_level(spdlog::level::level_enum::trace);
auto sink_backend = boost::make_shared<LoggingSink>(callback);
boost::shared_ptr<sink_t> sink(new sink_t(sink_backend));
boost::log::core::get()->remove_all_sinks();
boost::log::core::get()->add_sink(sink);
spdlog::drop(LOGGER_NAME);
spdlog::register_logger(logger);
}
LOOT_API bool IsCompatible(const unsigned int versionMajor, const unsigned int versionMinor, const unsigned int versionPatch) {
+25 -10
View File
@@ -29,11 +29,9 @@
#include <cmath>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>
#include <boost/locale.hpp>
#include <boost/log/trivial.hpp>
#include "api/api_database.h"
#include "api/helpers/logging.h"
#include "api/plugin/plugin_sorter.h"
#include "loot/exception/file_access_error.h"
@@ -66,7 +64,10 @@ Game::Game(const GameType gameType,
localDataPath_(localDataPath),
cache_(std::make_shared<GameCache>()),
loadOrderHandler_(std::make_shared<LoadOrderHandler>()) {
BOOST_LOG_TRIVIAL(info) << "Initialising load order data for game of type " << (int)type_ << " at: " << gamePath_;
auto logger = getLogger();
if (logger) {
logger->info("Initialising load order data for game of type {} at: {}", (int) type_, gamePath_.string());
}
loadOrderHandler_->Init(type_, gamePath_, localDataPath_);
@@ -98,6 +99,7 @@ bool Game::IsValidPlugin(const std::string& plugin) const {
}
void Game::LoadPlugins(const std::vector<std::string>& plugins, bool loadHeadersOnly) {
auto logger = getLogger();
uintmax_t meanFileSize = 0;
std::multimap<uintmax_t, string> sizeMap;
@@ -125,15 +127,22 @@ void Game::LoadPlugins(const std::vector<std::string>& plugins, bool loadHeaders
// Divide the plugins up by thread.
unsigned int pluginsPerThread = ceil((double)sizeMap.size() / threadsToUse);
vector<vector<string>> pluginGroups(threadsToUse);
BOOST_LOG_TRIVIAL(info) << "Loading " << sizeMap.size() << " plugins using " << threadsToUse << " threads, with up to " << pluginsPerThread << " plugins per thread.";
if (logger) {
logger->info("Loading {} plugins using {} threads, with up to {} plugins per thread.", sizeMap.size(), threadsToUse, pluginsPerThread);
}
// The plugins should be split between the threads so that the data
// load is as evenly spread as possible.
size_t currentGroup = 0;
for (const auto& plugin : sizeMap) {
if (currentGroup == threadsToUse)
if (currentGroup == threadsToUse) {
currentGroup = 0;
BOOST_LOG_TRIVIAL(trace) << "Adding plugin " << plugin.second << " to loading group " << currentGroup;
}
if (logger) {
logger->trace("Adding plugin {} to loading group {}", plugin.second, currentGroup);
}
pluginGroups[currentGroup].push_back(plugin.second);
++currentGroup;
}
@@ -143,18 +152,24 @@ void Game::LoadPlugins(const std::vector<std::string>& plugins, bool loadHeaders
loadOrderHandler_->LoadCurrentState();
// Load the plugins.
BOOST_LOG_TRIVIAL(trace) << "Starting plugin loading.";
if (logger) {
logger->trace("Starting plugin loading.");
}
vector<thread> threads;
while (threads.size() < threadsToUse) {
vector<string>& pluginGroup = pluginGroups[threads.size()];
threads.push_back(thread([&]() {
for (auto pluginName : pluginGroup) {
BOOST_LOG_TRIVIAL(trace) << "Loading " << pluginName;
if (logger) {
logger->trace("Loading {}", pluginName);
}
const bool loadHeader = boost::iequals(pluginName, masterFile_) || loadHeadersOnly;
try {
cache_->AddPlugin(Plugin(Type(), DataPath(), loadOrderHandler_, pluginName, loadHeader));
} catch(std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Caught exception while trying to add " << pluginName << " to the cache: " << e.what();
if (logger) {
logger->trace("Caught exception while trying to add {} to the cache: {}", pluginName, e.what());
}
}
}
}));
-1
View File
@@ -28,7 +28,6 @@
#include <boost/algorithm/string.hpp>
#include <boost/locale.hpp>
#include <boost/log/trivial.hpp>
using boost::locale::to_lower;
using std::lock_guard;
+30 -8
View File
@@ -26,9 +26,9 @@
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include "loot/exception/error_categories.h"
#include "api/helpers/logging.h"
using boost::format;
using std::string;
@@ -78,7 +78,10 @@ void LoadOrderHandler::Init(const GameType& gameType,
}
void LoadOrderHandler::LoadCurrentState() {
BOOST_LOG_TRIVIAL(debug) << "Loading the current load order state.";
auto logger = getLogger();
if (logger) {
logger->debug("Loading the current load order state.");
}
unsigned int ret = lo_load_current_state(gh_);
@@ -86,7 +89,10 @@ void LoadOrderHandler::LoadCurrentState() {
}
bool LoadOrderHandler::IsPluginActive(const std::string& pluginName) const {
BOOST_LOG_TRIVIAL(debug) << "Checking if plugin \"" << pluginName << "\" is active.";
auto logger = getLogger();
if (logger) {
logger->debug("Checking if plugin \"{}\" is active.", pluginName);
}
bool result = false;
unsigned int ret = lo_get_plugin_active(gh_, pluginName.c_str(), &result);
@@ -97,7 +103,10 @@ bool LoadOrderHandler::IsPluginActive(const std::string& pluginName) const {
}
std::vector<std::string> LoadOrderHandler::GetLoadOrder() const {
BOOST_LOG_TRIVIAL(debug) << "Getting load order.";
auto logger = getLogger();
if (logger) {
logger->debug("Getting load order.");
}
char ** pluginArr;
size_t pluginArrSize;
@@ -113,12 +122,19 @@ std::vector<std::string> LoadOrderHandler::GetLoadOrder() const {
}
void LoadOrderHandler::SetLoadOrder(const std::vector<std::string>& loadOrder) const {
BOOST_LOG_TRIVIAL(info) << "Setting load order.";
auto logger = getLogger();
if (logger) {
logger->info("Setting load order.");
}
size_t pluginArrSize = loadOrder.size();
char ** pluginArr = new char*[pluginArrSize];
int i = 0;
for (const auto &plugin : loadOrder) {
BOOST_LOG_TRIVIAL(info) << '\t' << '\t' << plugin;
if (logger) {
logger->info("\t\t{}", plugin);
}
pluginArr[i] = new char[plugin.length() + 1];
strcpy(pluginArr[i], plugin.c_str());
++i;
@@ -132,7 +148,9 @@ void LoadOrderHandler::SetLoadOrder(const std::vector<std::string>& loadOrder) c
HandleError("set the load order", ret);
BOOST_LOG_TRIVIAL(info) << "Load order set successfully.";
if (logger) {
logger->info("Load order set successfully.");
}
}
void LoadOrderHandler::HandleError(const std::string& operation, unsigned int returnCode) const {
@@ -150,7 +168,11 @@ void LoadOrderHandler::HandleError(const std::string& operation, unsigned int re
err = (format("libloadorder failed to " + operation + ". Details: %1%") % e).str();
}
BOOST_LOG_TRIVIAL(error) << err;
auto logger = getLogger();
if (logger) {
logger->error(err);
}
throw std::system_error(returnCode, libloadorder_category(), err);
}
}
+8 -3
View File
@@ -27,7 +27,7 @@
#include <boost/crc.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include "api/helpers/logging.h"
#include "loot/exception/file_access_error.h"
@@ -48,7 +48,10 @@ size_t GetStreamSize(std::istream& stream) {
//Calculate the CRC of the given file for comparison purposes.
uint32_t GetCrc32(const boost::filesystem::path& filename) {
try {
BOOST_LOG_TRIVIAL(trace) << "Calculating CRC for: " << filename.string();
auto logger = getLogger();
if (logger) {
logger->trace("Calculating CRC for: {}", filename.string());
}
boost::filesystem::ifstream ifile(filename, std::ios::binary);
ifile.exceptions(std::ios_base::badbit | std::ios_base::failbit);
@@ -68,7 +71,9 @@ uint32_t GetCrc32(const boost::filesystem::path& filename) {
}
uint32_t checksum = result.checksum();
BOOST_LOG_TRIVIAL(debug) << "CRC32(\"" << filename.string() << "\"): " << std::hex << checksum << std::dec;
if (logger) {
logger->debug("CRC32(\"{}\"): {:x}", filename.string(), checksum);
}
return checksum;
} catch (std::exception& e) {
+86 -31
View File
@@ -25,16 +25,30 @@
#include "api/helpers/git_helper.h"
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include "loot/exception/error_categories.h"
#include "loot/exception/git_state_error.h"
#include "api/helpers/logging.h"
using std::string;
namespace fs = boost::filesystem;
namespace loot {
GitHelper::GitHelper() : logger_(getLogger()) {}
GitHelper::~GitHelper() {
if (data_.repo != nullptr) {
std::string path = git_repository_path(data_.repo);
if (!path.empty()) {
try {
FixRepoPermissions(path);
} catch (std::exception&) {}
}
}
}
GitHelper::GitData::GitData() :
repo(nullptr),
remote(nullptr),
@@ -78,12 +92,6 @@ GitHelper::GitData::~GitData() {
delete[] checkout_options.paths.strings[i];
}
if (!path.empty()) {
try {
FixRepoPermissions(path);
} catch (std::exception&) {}
}
git_libgit2_shutdown();
}
@@ -110,20 +118,30 @@ bool GitHelper::IsRepository(const boost::filesystem::path& path) {
// Removes the read-only flag from some files in git repositories created by libgit2.
void GitHelper::FixRepoPermissions(const boost::filesystem::path& path) {
BOOST_LOG_TRIVIAL(trace) << "Recursively setting write permission on directory: " << path;
if (logger_) {
logger_->trace("Recursively setting write permission on directory: {}", path.string());
}
for (fs::recursive_directory_iterator it(path); it != fs::recursive_directory_iterator(); ++it) {
if ((it->status().permissions() & (fs::owner_write | fs::group_write | fs::others_write)) == 0) {
BOOST_LOG_TRIVIAL(trace) << "Setting write permission for: " << it->path();
if (logger_) {
logger_->trace("Setting write permission for: {}", it->path().string());
}
fs::permissions(it->path(), fs::add_perms | fs::owner_write);
}
}
}
int GitHelper::DiffFileCallback(const git_diff_delta *delta, float progress, void * payload) {
BOOST_LOG_TRIVIAL(trace) << "Checking diff for: " << delta->old_file.path;
auto logger = getLogger();
if (logger) {
logger->trace("Checking diff for: {}", delta->old_file.path);
}
DiffPayload * gdp = (DiffPayload*)payload;
if (strcmp(delta->old_file.path, gdp->fileToFind) == 0) {
BOOST_LOG_TRIVIAL(warning) << "Edited masterlist found.";
if (logger) {
logger->warn("Edited masterlist found.");
}
gdp->fileFound = true;
}
@@ -136,7 +154,9 @@ void GitHelper::Clone(const boost::filesystem::path& path, const std::string& ur
throw GitStateError("Cannot clone repository that has already been opened.");
// Clone the remote repository.
BOOST_LOG_TRIVIAL(info) << "Repository doesn't exist, cloning the remote repository.";
if (logger_) {
logger_->info("Repository doesn't exist, cloning the remote repository.");
}
fs::path tempPath = path.parent_path() / fs::unique_path();
@@ -147,7 +167,9 @@ void GitHelper::Clone(const boost::filesystem::path& path, const std::string& ur
// Directory is non-empty. Delete the masterlist file and
// .git folder, then move any remaining files to a temporary
// folder while the repo is cloned, before moving them back.
BOOST_LOG_TRIVIAL(trace) << "Repo path not empty, renaming folder.";
if (logger_) {
logger_->trace("Repo path not empty, renaming folder.");
}
// Clear any read-only flags first.
FixRepoPermissions(path);
@@ -166,7 +188,9 @@ void GitHelper::Clone(const boost::filesystem::path& path, const std::string& ur
if (fs::exists(tempPath)) {
//Move contents back in.
BOOST_LOG_TRIVIAL(trace) << "Repo path wasn't empty, moving previous files back in.";
if (logger_) {
logger_->trace("Repo path wasn't empty, moving previous files back in.");
}
for (fs::directory_iterator it(tempPath); it != fs::directory_iterator(); ++it) {
if (!fs::exists(path / it->path().filename())) {
//No conflict, OK to move back in.
@@ -182,7 +206,9 @@ void GitHelper::Fetch(const std::string& remote) {
if (data_.repo == nullptr)
throw GitStateError("Cannot fetch updates for repository that has not been opened.");
BOOST_LOG_TRIVIAL(trace) << "Fetching updates from remote.";
if (logger_) {
logger_->trace("Fetching updates from remote.");
}
// Get the origin remote.
Call(git_remote_lookup(&data_.remote, data_.repo, remote.c_str()));
@@ -193,7 +219,10 @@ void GitHelper::Fetch(const std::string& remote) {
// Log some stats on what was fetched either during update or clone.
const git_transfer_progress * stats = git_remote_stats(data_.remote);
BOOST_LOG_TRIVIAL(info) << "Received " << stats->indexed_objects << " of " << stats->total_objects << " objects in " << stats->received_bytes << " bytes.";
if (logger_) {
logger_->trace("Received {} of {} objects in {} bytes.",
stats->indexed_objects, stats->total_objects, stats->received_bytes);
}
git_remote_free(data_.remote);
data_.remote = nullptr;
@@ -209,26 +238,34 @@ void GitHelper::CheckoutNewBranch(const std::string& remote, const std::string&
else if (data_.reference != nullptr)
throw GitStateError("Cannot fetch repository updates, reference memory already allocated.");
BOOST_LOG_TRIVIAL(trace) << "Looking up commit referred to by the remote branch \"" << branch << "\".";
if (logger_) {
logger_->trace("Looking up commit referred to by the remote branch \"{}\".", branch);
}
Call(git_revparse_single(&data_.object, data_.repo, (remote + "/" + branch).c_str()));
const git_oid * commit_id = git_object_id(data_.object);
// Create a branch.
BOOST_LOG_TRIVIAL(trace) << "Creating the new branch.";
if (logger_) {
logger_->trace("Creating the new branch.");
}
Call(git_commit_lookup(&data_.commit, data_.repo, commit_id));
Call(git_branch_create(&data_.reference, data_.repo, branch.c_str(), data_.commit, 1));
// Set upstream.
BOOST_LOG_TRIVIAL(trace) << "Setting the upstream for the new branch.";
if (logger_) {
logger_->trace("Setting the upstream for the new branch.");
}
Call(git_branch_set_upstream(data_.reference, (remote + "/" + branch).c_str()));
// Check if HEAD points to the desired branch and set it to if not.
if (!git_branch_is_head(data_.reference)) {
BOOST_LOG_TRIVIAL(trace) << "Setting HEAD to follow branch: " << branch;
if (logger_) {
logger_->trace("Setting HEAD to follow branch: {}", branch);
}
Call(git_repository_set_head(data_.repo, (string("refs/heads/") + branch).c_str()));
}
BOOST_LOG_TRIVIAL(trace) << "Performing a Git checkout of HEAD.";
if (logger_) {
logger_->trace("Performing a Git checkout of HEAD.");
}
Call(git_checkout_head(data_.repo, &data_.checkout_options));
// Free tree and commit pointers. Reference pointer is still used below.
@@ -254,7 +291,9 @@ void GitHelper::CheckoutRevision(const std::string& revision) {
Call(git_repository_set_head_detached(data_.repo, oid));
// Checkout the new HEAD.
BOOST_LOG_TRIVIAL(trace) << "Performing a Git checkout of HEAD.";
if (logger_) {
logger_->trace("Performing a Git checkout of HEAD.");
}
Call(git_checkout_head(data_.repo, &data_.checkout_options));
git_object_free(data_.object);
@@ -271,11 +310,15 @@ std::string GitHelper::GetHeadShortId() {
else if (data_.buffer.ptr != nullptr)
throw GitStateError("Cannot fetch repository updates, buffer memory already allocated.");
BOOST_LOG_TRIVIAL(trace) << "Getting the Git object for HEAD.";
if (logger_) {
logger_->trace("Getting the Git object for HEAD.");
}
Call(git_repository_head(&data_.reference, data_.repo));
Call(git_reference_peel(&data_.object, data_.reference, GIT_OBJ_COMMIT));
BOOST_LOG_TRIVIAL(trace) << "Generating hex string for Git object ID.";
if (logger_) {
logger_->trace("Generating hex string for Git object ID.");
}
Call(git_object_short_id(&data_.buffer, data_.object));
string revision = data_.buffer.ptr;
@@ -294,24 +337,36 @@ GitHelper::GitData& GitHelper::GetData() {
}
bool GitHelper::IsFileDifferent(const boost::filesystem::path& repoRoot, const std::string& filename) {
auto logger = getLogger();
if (!IsRepository(repoRoot)) {
BOOST_LOG_TRIVIAL(info) << "Unknown masterlist revision: Git repository missing.";
if (logger) {
logger->info("Unknown masterlist revision: Git repository missing.");
}
throw GitStateError("Cannot check if the \"" + filename + "\" working copy is edited, Git repository missing.");
}
BOOST_LOG_TRIVIAL(debug) << "Existing repository found, attempting to open it.";
if (logger) {
logger->trace("Existing repository found, attempting to open it.");
}
GitHelper git;
git.Call(git_repository_open(&git.data_.repo, repoRoot.string().c_str()));
// Perform a git diff, then iterate the deltas to see if one exists for the masterlist.
BOOST_LOG_TRIVIAL(trace) << "Getting the tree for the HEAD revision.";
if (logger) {
logger->trace("Getting the tree for the HEAD revision.");
}
git.Call(git_revparse_single(&git.data_.object, git.data_.repo, "HEAD^{tree}"));
git.Call(git_tree_lookup(&git.data_.tree, git.data_.repo, git_object_id(git.data_.object)));
BOOST_LOG_TRIVIAL(trace) << "Performing git diff.";
if (logger) {
logger->trace("Performing git diff.");
}
git.Call(git_diff_tree_to_workdir_with_index(&git.data_.diff, git.data_.repo, git.data_.tree, NULL));
BOOST_LOG_TRIVIAL(trace) << "Iterating over git diff deltas.";
if (logger) {
logger->trace("Iterating over git diff deltas.");
}
GitHelper::DiffPayload payload;
payload.fileFound = false;
payload.fileToFind = filename.c_str();
+6 -1
View File
@@ -29,6 +29,7 @@
#include <boost/filesystem.hpp>
#include <git2.h>
#include <spdlog/spdlog.h>
namespace loot {
class GitHelper {
@@ -59,6 +60,9 @@ public:
git_clone_options clone_options;
};
GitHelper();
~GitHelper();
void Call(int error_code);
static bool IsRepository(const boost::filesystem::path& path);
@@ -77,9 +81,10 @@ public:
private:
// Removes the read-only flag from some files in git repositories
// created by libgit2.
static void FixRepoPermissions(const boost::filesystem::path& path);
void FixRepoPermissions(const boost::filesystem::path& path);
GitData data_;
std::shared_ptr<spdlog::logger> logger_;
};
}
#endif
+76
View File
@@ -0,0 +1,76 @@
/* LOOT
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
Fallout: New Vegas.
Copyright (C) 2012-2016 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
<https://www.gnu.org/licenses/>.
*/
#ifndef LOOT_API_HELPERS_LOGGING
#define LOOT_API_HELPERS_LOGGING
#include <spdlog/spdlog.h>
#include "loot/enum/log_level.h"
namespace loot {
static const char * LOGGER_NAME = "loot_api_logger";
inline std::shared_ptr<spdlog::logger> getLogger() {
return spdlog::get(LOGGER_NAME);
}
class SpdLoggingSink : public spdlog::sinks::base_sink<std::mutex> {
public:
SpdLoggingSink(std::function<void(LogLevel, const char*)> callback) {
this->callback = callback;
}
protected:
void _sink_it(const spdlog::details::log_msg& msg) override {
callback(mapFromSpdlog(msg.level), msg.raw.str().c_str());
}
void _flush() override {}
private:
std::function<void(LogLevel, const char*)> callback;
static LogLevel mapFromSpdlog(spdlog::level::level_enum severity) {
using spdlog::level::level_enum;
switch (severity) {
case level_enum::trace:
return LogLevel::trace;
case level_enum::debug:
return LogLevel::debug;
case level_enum::info:
return LogLevel::info;
case level_enum::warn:
return LogLevel::warning;
case level_enum::err:
return LogLevel::error;
case level_enum::critical:
return LogLevel::fatal;
default:
return LogLevel::trace;
}
}
};
}
#endif
+83 -30
View File
@@ -28,12 +28,12 @@
#include <sstream>
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include "loot/exception/file_access_error.h"
#include "loot/exception/git_state_error.h"
#include "api/game/game.h"
#include "api/helpers/git_helper.h"
#include "api/helpers/logging.h"
using boost::format;
using std::string;
@@ -46,22 +46,34 @@ MasterlistInfo Masterlist::GetInfo(const boost::filesystem::path& path, bool sho
GitHelper git;
MasterlistInfo info;
auto logger = getLogger();
if (!fs::exists(path)) {
BOOST_LOG_TRIVIAL(info) << "Unknown masterlist revision: No masterlist present.";
if (logger) {
logger->info("Unknown masterlist revision: No masterlist present.");
}
throw FileAccessError(string("N/A: No masterlist present at ") + path.string());
} else if (!git.IsRepository(path.parent_path())) {
BOOST_LOG_TRIVIAL(info) << "Unknown masterlist revision: Git repository missing.";
if (logger) {
logger->info("Unknown masterlist revision: Git repository missing.");
}
throw GitStateError(string("Unknown: \"") + path.parent_path().string() + "\" is not a Git repository.");
}
BOOST_LOG_TRIVIAL(debug) << "Existing repository found, attempting to open it.";
if (logger) {
logger->debug("Existing repository found, attempting to open it.");
}
git.Call(git_repository_open(&git.GetData().repo, path.parent_path().string().c_str()));
//Need to get the HEAD object, because the individual file has a different SHA.
BOOST_LOG_TRIVIAL(info) << "Getting the Git object for the tree at HEAD.";
if (logger) {
logger->info("Getting the Git object for the tree at HEAD.");
}
git.Call(git_revparse_single(&git.GetData().object, git.GetData().repo, "HEAD"));
BOOST_LOG_TRIVIAL(trace) << "Generating hex string for Git object ID.";
if (logger) {
logger->trace("Generating hex string for Git object ID.");
}
if (shortID) {
git.Call(git_object_short_id(&git.GetData().buffer, git.GetData().object));
info.revision_id = git.GetData().buffer.ptr;
@@ -70,7 +82,9 @@ MasterlistInfo Masterlist::GetInfo(const boost::filesystem::path& path, bool sho
info.revision_id = git_oid_tostr(c_rev, GIT_OID_HEXSZ + 1, git_object_id(git.GetData().object));
}
BOOST_LOG_TRIVIAL(trace) << "Getting date for Git object.";
if (logger) {
logger->trace("Getting date for Git object.");
}
const git_oid * oid = git_object_id(git.GetData().object);
git.Call(git_commit_lookup(&git.GetData().commit, git.GetData().repo, oid));
git_time_t time = git_commit_time(git.GetData().commit);
@@ -79,7 +93,9 @@ MasterlistInfo Masterlist::GetInfo(const boost::filesystem::path& path, bool sho
out << std::put_time(std::gmtime(&time), "%Y-%m-%d");
info.revision_date = out.str();
BOOST_LOG_TRIVIAL(trace) << "Diffing masterlist HEAD and working copy.";
if (logger) {
logger->trace("Diffing masterlist HEAD and working copy.");
}
info.is_modified = GitHelper::IsFileDifferent(path.parent_path(), path.filename().string());
return info;
@@ -91,13 +107,18 @@ bool Masterlist::IsLatest(const boost::filesystem::path& path,
throw std::invalid_argument("Repository branch must not be empty.");
GitHelper git;
auto logger = getLogger();
if (!git.IsRepository(path.parent_path())) {
BOOST_LOG_TRIVIAL(info) << "Cannot get latest masterlist revision: Git repository missing.";
if (logger) {
logger->info("Cannot get latest masterlist revision: Git repository missing.");
}
throw GitStateError(string("Unknown: \"") + path.parent_path().string() + "\" is not a Git repository.");
}
BOOST_LOG_TRIVIAL(info) << "Attempting to open repository.";
if (logger) {
logger->info("Attempting to open repository.");
}
git.Call(git_repository_open(&git.GetData().repo, path.parent_path().string().c_str()));
git.Fetch("origin");
@@ -115,6 +136,7 @@ bool Masterlist::IsLatest(const boost::filesystem::path& path,
bool Masterlist::Update(const boost::filesystem::path& path, const std::string& repoUrl, const std::string& repoBranch) {
GitHelper git;
auto logger = getLogger();
fs::path repoPath = path.parent_path();
string filename = path.filename().string();
@@ -122,7 +144,9 @@ bool Masterlist::Update(const boost::filesystem::path& path, const std::string&
throw std::invalid_argument("Repository URL and branch must not be empty.");
// Initialise checkout options.
BOOST_LOG_TRIVIAL(debug) << "Setting up checkout options.";
if (logger) {
logger->debug("Setting up checkout options.");
}
char * paths = new char[filename.length() + 1];
strcpy(paths, filename.c_str());
git.GetData().checkout_options.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_DONT_REMOVE_EXISTING;
@@ -135,18 +159,24 @@ bool Masterlist::Update(const boost::filesystem::path& path, const std::string&
git.GetData().clone_options.checkout_branch = repoBranch.c_str();
// Now try to access the repository if it exists, or clone one if it doesn't.
BOOST_LOG_TRIVIAL(trace) << "Attempting to open the Git repository at: " << repoPath;
if (logger) {
logger->trace("Attempting to open the Git repository at: {}", repoPath.string());
}
if (!git.IsRepository(repoPath))
git.Clone(repoPath, repoUrl);
else {
// Repository exists: check settings are correct, then pull updates.
// Open the repository.
BOOST_LOG_TRIVIAL(info) << "Existing repository found, attempting to open it.";
if (logger) {
logger->info("Existing repository found, attempting to open it.");
}
git.Call(git_repository_open(&git.GetData().repo, repoPath.string().c_str()));
// Set the remote URL.
BOOST_LOG_TRIVIAL(info) << "Using remote URL: " << repoUrl;
if (logger) {
logger->info("Using remote URL: {}", repoUrl);
}
git.Call(git_remote_set_url(git.GetData().repo, "origin", repoUrl.c_str()));
// Now fetch updates from the remote.
@@ -164,14 +194,18 @@ bool Masterlist::Update(const boost::filesystem::path& path, const std::string&
// Check if HEAD points to the desired branch and set it to if not.
if (!git_branch_is_head(git.GetData().reference)) {
BOOST_LOG_TRIVIAL(trace) << "Setting HEAD to follow branch: " << repoBranch;
if (logger) {
logger->trace("Setting HEAD to follow branch: {}", repoBranch);
}
git.Call(git_repository_set_head(git.GetData().repo, (string("refs/heads/") + repoBranch).c_str()));
}
// Get remote branch reference.
git.Call(git_branch_upstream(&git.GetData().reference2, git.GetData().reference));
BOOST_LOG_TRIVIAL(trace) << "Checking HEAD and remote branch's mergeability.";
if (logger) {
logger->trace("Checking HEAD and remote branch's mergeability.");
}
git_merge_analysis_t analysis;
git_merge_preference_t pref;
git.Call(git_annotated_commit_from_ref(&git.GetData().annotated_commit, git.GetData().repo, git.GetData().reference2));
@@ -179,9 +213,13 @@ bool Masterlist::Update(const boost::filesystem::path& path, const std::string&
if ((analysis & GIT_MERGE_ANALYSIS_FASTFORWARD) == 0 && (analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) == 0) {
// The local branch can't be easily merged. Best just to delete and recreate it.
BOOST_LOG_TRIVIAL(trace) << "Local branch cannot be easily merged with remote branch.";
if (logger) {
logger->trace("Local branch cannot be easily merged with remote branch.");
}
BOOST_LOG_TRIVIAL(trace) << "Detaching HEAD so that the branch can be recreated.";
if (logger) {
logger->trace("Detaching HEAD so that the branch can be recreated.");
}
git.Call(git_repository_detach_head(git.GetData().repo));
// Need to free ref before calling git.CheckoutNewBranch()
@@ -206,8 +244,9 @@ bool Masterlist::Update(const boost::filesystem::path& path, const std::string&
// No merge is required, but HEAD might be ahead of the remote branch. Check
// to see if that's the case, and move HEAD back to match the remote branch
// if so.
BOOST_LOG_TRIVIAL(trace) << "Local branch is up-to-date with remote branch.";
BOOST_LOG_TRIVIAL(trace) << "Checking to see if local and remote branch heads are equal.";
if (logger) {
logger->trace("Local branch is up-to-date with remote branch. Checking to see if local and remote branch heads are equal.");
}
// Get local branch commit ID.
git.Call(git_reference_peel(&git.GetData().object, git.GetData().reference, GIT_OBJ_COMMIT));
@@ -223,21 +262,29 @@ bool Masterlist::Update(const boost::filesystem::path& path, const std::string&
// action needs to be taken. Otherwise, a checkout
// must be performed and the checked-out file parsed.
if (!updateBranchHead) {
BOOST_LOG_TRIVIAL(trace) << "Local and remote branch heads are equal.";
if (logger) {
logger->trace("Local and remote branch heads are equal.");
}
if (!GitHelper::IsFileDifferent(repoPath, filename)) {
BOOST_LOG_TRIVIAL(info) << "Local branch and masterlist file are already up to date.";
if (logger) {
logger->info("Local branch and masterlist file are already up to date.");
}
return false;
}
} else
BOOST_LOG_TRIVIAL(trace) << "Local branch heads is ahead of remote branch head.";
} else
BOOST_LOG_TRIVIAL(trace) << "Local branch can be fast-forwarded to remote branch.";
} else if (logger) {
logger->trace("Local branch heads is ahead of remote branch head.");
}
} else if (logger) {
logger->trace("Local branch can be fast-forwarded to remote branch.");
}
if (updateBranchHead) {
// The remote branch reference points to a particular
// commit. Update the local branch reference to point
// to the same commit.
BOOST_LOG_TRIVIAL(trace) << "Syncing local branch head with remote branch head.";
if (logger) {
logger->trace("Syncing local branch head with remote branch head.");
}
git.Call(git_reference_set_target(&git.GetData().reference2, git.GetData().reference, remote_commit_id, "Setting branch reference."));
git_reference_free(git.GetData().reference2);
@@ -247,7 +294,9 @@ bool Masterlist::Update(const boost::filesystem::path& path, const std::string&
git_reference_free(git.GetData().reference);
git.GetData().reference = nullptr;
BOOST_LOG_TRIVIAL(trace) << "Performing a Git checkout of HEAD.";
if (logger) {
logger->trace("Performing a Git checkout of HEAD.");
}
git.Call(git_checkout_head(git.GetData().repo, &git.GetData().checkout_options));
}
}
@@ -263,7 +312,9 @@ bool Masterlist::Update(const boost::filesystem::path& path, const std::string&
string revision = git.GetHeadShortId();
//Now try parsing the masterlist.
BOOST_LOG_TRIVIAL(debug) << "Testing masterlist parsing.";
if (logger) {
logger->debug("Testing masterlist parsing.");
}
try {
this->Load(path);
@@ -272,7 +323,9 @@ bool Masterlist::Update(const boost::filesystem::path& path, const std::string&
parsingFailed = true;
//There was an error, roll back one revision.
BOOST_LOG_TRIVIAL(error) << "Masterlist parsing failed. Masterlist revision " + string(revision) + ": " + e.what();
if (logger) {
logger->error("Masterlist parsing failed. Masterlist revision {}: {}", revision, e.what());
}
git.CheckoutRevision("HEAD^");
}
} while (parsingFailed);
+17 -5
View File
@@ -26,9 +26,9 @@
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include "api/helpers/crc.h"
#include "api/helpers/logging.h"
#include "api/metadata/condition_grammar.h"
#include "loot/exception/condition_syntax_error.h"
@@ -55,7 +55,10 @@ bool ConditionEvaluator::evaluate(const std::string& condition) const {
if (condition.empty())
return true;
BOOST_LOG_TRIVIAL(trace) << "Evaluating condition: " << condition;
auto logger = getLogger();
if (logger) {
logger->trace("Evaluating condition: {}", condition);
}
auto cachedValue = gameCache_->GetCachedCondition(condition);
if (cachedValue.second)
@@ -272,7 +275,10 @@ bool ConditionEvaluator::compareVersions(const std::string & filePath, const std
Version givenVersion = Version(testVersion);
Version trueVersion = getVersion(filePath);
BOOST_LOG_TRIVIAL(trace) << "Version extracted: " << trueVersion.AsString();
auto logger = getLogger();
if (logger) {
logger->trace("Version extracted: {}", trueVersion.AsString());
}
return ((comparator == "==" && trueVersion == givenVersion)
|| (comparator == "!=" && trueVersion != givenVersion)
@@ -283,7 +289,10 @@ bool ConditionEvaluator::compareVersions(const std::string & filePath, const std
}
void ConditionEvaluator::validatePath(const boost::filesystem::path& path) {
BOOST_LOG_TRIVIAL(trace) << "Checking to see if the path \"" << path << "\" is safe.";
auto logger = getLogger();
if (logger) {
logger->trace("Checking to see if the path \"{}\" is safe.", path.string());
}
boost::filesystem::path temp;
for (const auto& component : path) {
@@ -357,7 +366,10 @@ bool ConditionEvaluator::isRegexMatchInDataDirectory(const std::pair<boost::file
// Now we have a valid parent path and a regex filename. Check that the
// parent path exists and is a directory.
if (!isGameSubdirectory(pathRegex.first)) {
BOOST_LOG_TRIVIAL(trace) << "The path \"" << pathRegex.first << "\" is not a game subdirectory.";
auto logger = getLogger();
if (logger) {
logger->trace("The path \"{}\" is not a game subdirectory.", pathRegex.first.string());
}
return false;
}
+28 -10
View File
@@ -36,10 +36,8 @@
#include <cstdint>
#include <regex>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/regex.hpp>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
@@ -47,6 +45,7 @@
#include "loot/exception/condition_syntax_error.h"
#include "api/game/game.h"
#include "api/helpers/logging.h"
#include "api/helpers/version.h"
#include "api/metadata/condition_evaluator.h"
#include "api/plugin/plugin.h"
@@ -127,6 +126,8 @@ public:
qi::on_error<qi::fail>(filePath_, phoenix::bind(&ConditionGrammar::SyntaxError, this, qi::labels::_1, qi::labels::_2, qi::labels::_3, qi::labels::_4));
qi::on_error<qi::fail>(comparator_, phoenix::bind(&ConditionGrammar::SyntaxError, this, qi::labels::_1, qi::labels::_2, qi::labels::_3, qi::labels::_4));
qi::on_error<qi::fail>(invalidPathChars_, phoenix::bind(&ConditionGrammar::SyntaxError, this, qi::labels::_1, qi::labels::_2, qi::labels::_3, qi::labels::_4));
logger_ = getLogger();
}
private:
@@ -139,7 +140,9 @@ private:
//Eval's exact paths. Check for files and ghosted plugins.
void CheckFile(bool& result, const std::string& file) const {
BOOST_LOG_TRIVIAL(trace) << "Checking to see if the file \"" << file << "\" exists.";
if (logger_) {
logger_->trace("Checking to see if the file \"{}\" exists.", file);
}
result = false;
if (IsRegex(file))
@@ -147,30 +150,40 @@ private:
else
result = evaluator_.fileExists(file);
BOOST_LOG_TRIVIAL(trace) << "File check result: " << result;
if (logger_) {
logger_->trace("File check result: {}", result);
}
}
void CheckMany(bool& result, const std::string& regexStr) const {
BOOST_LOG_TRIVIAL(trace) << "Checking to see if more than one file matching the regex \"" << regexStr << "\" exist.";
if (logger_) {
logger_->trace("Checking to see if more than one file matching the regex \"{}\" exists.", regexStr);
}
result = false;
result = evaluator_.regexMatchesExist(regexStr);
}
void CheckSum(bool& result, const std::string& file, const uint32_t checksum) {
BOOST_LOG_TRIVIAL(trace) << "Checking the CRC of the file \"" << file << "\".";
if (logger_) {
logger_->trace("Checking the CRC of the file \"{}\".", file);
}
result = false;
result = evaluator_.checksumMatches(file, checksum);
}
void CheckVersion(bool& result, const std::string& file, const std::string& version, const std::string& comparator) const {
BOOST_LOG_TRIVIAL(trace) << "Checking version of file \"" << file << "\".";
if (logger_) {
logger_->trace("Checking the version of the file \"{}\".", file);
}
result = false;
result = evaluator_.compareVersions(file, version, comparator);
BOOST_LOG_TRIVIAL(trace) << "Version check result: " << result;
if (logger_) {
logger_->trace("Version check result: {}", result);
}
}
void CheckActive(bool& result, const std::string& file) const {
@@ -180,11 +193,15 @@ private:
else
result = evaluator_.isPluginActive(file);
BOOST_LOG_TRIVIAL(trace) << "Active check result: " << result;
if (logger_) {
logger_->trace("Active check result: {}", result);
}
}
void CheckManyActive(bool& result, const std::string& regexStr) const {
BOOST_LOG_TRIVIAL(trace) << "Checking to see if more than one file matching the regex \"" << regexStr << "\" exist.";
if (logger_) {
logger_->trace("Checking to see if more than one file matching the regex \"{}\" is active.", regexStr);
}
result = false;
result = evaluator_.arePluginsActive(regexStr);
@@ -203,6 +220,7 @@ private:
boost::spirit::qi::rule<Iterator, char()> invalidPathChars_;
const ConditionEvaluator& evaluator_;
std::shared_ptr<spdlog::logger> logger_;
};
}
#endif
+8 -5
View File
@@ -24,10 +24,8 @@
#include "loot/metadata/conditional_metadata.h"
#include <boost/locale.hpp>
#include <boost/log/trivial.hpp>
#include "api/game/game.h"
#include "api/helpers/logging.h"
#include "api/metadata/condition_evaluator.h"
using std::string;
@@ -46,7 +44,12 @@ std::string ConditionalMetadata::GetCondition() const {
}
void ConditionalMetadata::ParseCondition() const {
BOOST_LOG_TRIVIAL(trace) << "Testing condition syntax: " << condition_;
ConditionEvaluator().evaluate(condition_);
if (!condition_.empty()) {
auto logger = getLogger();
if (logger) {
logger->trace("Testing condition syntax: {}", condition_);
}
ConditionEvaluator().evaluate(condition_);
}
}
}
-1
View File
@@ -25,7 +25,6 @@
#include "loot/metadata/message.h"
#include <boost/algorithm/string.hpp>
#include <boost/log/trivial.hpp>
#include "api/game/game.h"
+5 -2
View File
@@ -26,10 +26,10 @@
#include <boost/format.hpp>
#include <boost/locale.hpp>
#include <boost/log/trivial.hpp>
#include "api/game/game.h"
#include "api/helpers/crc.h"
#include "api/helpers/logging.h"
namespace loot {
PluginCleaningData::PluginCleaningData() : crc_(0), itm_(0), ref_(0), nav_(0) {}
@@ -78,7 +78,10 @@ std::vector<MessageContent> PluginCleaningData::GetInfo() const {
}
MessageContent PluginCleaningData::ChooseInfo(const std::string& language) const {
BOOST_LOG_TRIVIAL(trace) << "Choosing dirty info content.";
auto logger = getLogger();
if (logger) {
logger->trace("Choosing dirty info content.");
}
return MessageContent::Choose(info_, language);
}
}
+11 -3
View File
@@ -30,9 +30,9 @@
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/locale.hpp>
#include <boost/log/trivial.hpp>
#include "api/game/game.h"
#include "api/helpers/logging.h"
using std::inserter;
using std::regex;
@@ -50,7 +50,11 @@ PluginMetadata::PluginMetadata(const std::string& n) : name_(n), enabled_(true)
}
void PluginMetadata::MergeMetadata(const PluginMetadata& plugin) {
BOOST_LOG_TRIVIAL(trace) << "Merging metadata for: " << name_;
auto logger = getLogger();
if (logger) {
logger->trace("Merging metadata for: {}", name_);
}
if (plugin.HasNameOnly())
return;
@@ -92,7 +96,11 @@ void PluginMetadata::MergeMetadata(const PluginMetadata& plugin) {
PluginMetadata PluginMetadata::NewMetadata(const PluginMetadata& plugin) const {
using std::set_difference;
BOOST_LOG_TRIVIAL(trace) << "Comparing new metadata for: " << name_;
auto logger = getLogger();
if (logger) {
logger->trace("Comparing new metadata for: {}", name_);
}
PluginMetadata p(*this);
//Compare this plugin against the given plugin.
+13 -5
View File
@@ -26,18 +26,21 @@
#include <boost/algorithm/string.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/log/trivial.hpp>
#include "loot/exception/file_access_error.h"
#include "api/metadata/yaml/plugin_metadata.h"
#include "api/game/game.h"
#include "api/helpers/logging.h"
#include "api/metadata/condition_evaluator.h"
#include "api/metadata/yaml/plugin_metadata.h"
namespace loot {
void MetadataList::Load(const boost::filesystem::path& filepath) {
Clear();
BOOST_LOG_TRIVIAL(debug) << "Loading file: " << filepath;
auto logger = getLogger();
if (logger) {
logger->debug("Loading file: {}", filepath.string());
}
boost::filesystem::ifstream in(filepath);
if (!in.good())
@@ -64,11 +67,16 @@ void MetadataList::Load(const boost::filesystem::path& filepath) {
if (metadataList["bash_tags"])
bashTags_ = metadataList["bash_tags"].as<std::set<std::string>>();
BOOST_LOG_TRIVIAL(debug) << "File loaded successfully.";
if (logger) {
logger->debug("File loaded successfully.");
}
}
void MetadataList::Save(const boost::filesystem::path& filepath) const {
BOOST_LOG_TRIVIAL(trace) << "Saving metadata list to: " << filepath;
auto logger = getLogger();
if (logger) {
logger->trace("Saving metadata list to: {}", filepath.string());
}
YAML::Emitter emitter;
emitter.SetIndent(2);
emitter << YAML::BeginMap;
+35 -11
View File
@@ -28,12 +28,12 @@
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/log/trivial.hpp>
#include <boost/format.hpp>
#include <boost/locale.hpp>
#include "api/game/game.h"
#include "api/helpers/crc.h"
#include "api/helpers/logging.h"
#include "api/helpers/version.h"
#include "loot/exception/file_access_error.h"
@@ -53,6 +53,8 @@ Plugin::Plugin(const GameType gameType,
loadsArchive_(false),
crc_(0),
numOverrideRecords_(0) {
auto logger = getLogger();
try {
boost::filesystem::path filepath = dataPath / name_;
@@ -68,10 +70,14 @@ Plugin::Plugin(const GameType gameType,
}
if (!headerOnly) {
BOOST_LOG_TRIVIAL(trace) << name_ << ": Caching CRC value.";
if (logger) {
logger->trace("{}: Caching CRC value.", name_);
}
crc_ = GetCrc32(filepath);
BOOST_LOG_TRIVIAL(trace) << name_ << ": Counting override FormIDs.";
if (logger) {
logger->trace("{}: Counting override FormIDs.", name_);
}
ret = esp_plugin_count_override_records(esPlugin.get(), &numOverrideRecords_);
if (ret != ESP_OK) {
throw FileAccessError(name + " : Libespm error code: " + std::to_string(ret));
@@ -79,8 +85,11 @@ Plugin::Plugin(const GameType gameType,
}
//Also read Bash Tags applied and version string in description.
if (logger) {
logger->trace("{}: Attempting to extract Bash Tags from the description.", name_);
}
string text = GetDescription();
BOOST_LOG_TRIVIAL(trace) << name_ << ": " << "Attempting to extract Bash Tags from the description.";
size_t pos1 = text.find("{{BASH:");
if (pos1 != string::npos && pos1 + 7 != text.length()) {
pos1 += 7;
@@ -94,8 +103,11 @@ Plugin::Plugin(const GameType gameType,
for (auto &tag : bashTags) {
boost::trim(tag);
BOOST_LOG_TRIVIAL(trace) << name_ << ": " << "Extracted Bash Tag: " << tag;
tags_.insert(Tag(tag));
if (logger) {
logger->trace("{}: Extracted Bash Tag: {}", name_, tag);
}
}
}
}
@@ -104,11 +116,15 @@ Plugin::Plugin(const GameType gameType,
loadsArchive_ = LoadsArchive(name_, gameType, dataPath);
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Cannot read plugin file \"" << name << "\". Details: " << e.what();
if (logger) {
logger->error("Cannot read plugin file \"{}\". Details: {}", name_, e.what());
}
throw FileAccessError((boost::format("Cannot read \"%1%\". Details: %2%") % name % e.what()).str());
}
BOOST_LOG_TRIVIAL(trace) << name_ << ": " << "Plugin loading complete.";
if (logger) {
logger->trace("{}: Plugin loading complete.", name_);
}
}
std::string Plugin::GetName() const {
@@ -185,7 +201,10 @@ bool Plugin::DoFormIDsOverlap(const PluginInterface& plugin) const {
return doPluginsOverlap;
} catch (std::bad_cast&) {
BOOST_LOG_TRIVIAL(error) << "Tried to check if FormIDs overlapped with a non-Plugin implementation of PluginInterface.";
auto logger = getLogger();
if (logger) {
logger->error("Tried to check if FormIDs overlapped with a non-Plugin implementation of PluginInterface.");
}
}
return false;
@@ -196,7 +215,10 @@ size_t Plugin::NumOverrideFormIDs() const {
}
bool Plugin::IsValid(const std::string& filename, const GameType gameType, const boost::filesystem::path& dataPath) {
BOOST_LOG_TRIVIAL(trace) << "Checking to see if \"" << filename << "\" is a valid plugin.";
auto logger = getLogger();
if (logger) {
logger->trace("Checking to see if \"{}\" is a valid plugin.", filename);
}
//If the filename passed ends in '.ghost', that should be trimmed.
std::string name;
@@ -214,7 +236,9 @@ bool Plugin::IsValid(const std::string& filename, const GameType gameType, const
int ret = esp_plugin_is_valid(GetEspluginGameId(gameType), path.string().c_str(), true, &isValid);
if (ret != ESP_OK || !isValid) {
BOOST_LOG_TRIVIAL(warning) << "The .es(p|m) file \"" << filename << "\" is not a valid plugin.";
if (logger) {
logger->warn("The file \"{}\" is not a valid plugin.", filename);
}
}
return (ret == ESP_OK && isValid)
@@ -314,7 +338,7 @@ unsigned int Plugin::GetEspluginGameId(GameType gameType) {
bool hasPluginFileExtension(const std::string& filename, GameType gameType) {
bool espOrEsm = boost::iends_with(filename, ".esp") || boost::iends_with(filename, ".esm");
bool lightMaster = (gameType == GameType::fo4 || gameType == GameType::tes5se)
bool lightMaster = (gameType == GameType::fo4 || gameType == GameType::tes5se)
&& boost::iends_with(filename, ".esl");
return espOrEsm || lightMaster;

Some files were not shown because too many files have changed in this diff Show More