From 4cb6576929136d511f1e7395ac1ffd03f8a1b7d5 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Sun, 22 May 2016 21:41:47 +0100 Subject: [PATCH] Refactor globals into static class members To allow more control over runtime value initialisation of paths. Versions were refactored just to keep things tidy. Also refactor GetLocalAppDataPath into the new LootPaths class, and initialise paths before first usage. --- CMakeLists.txt | 15 ++- src/api/api.cpp | 19 ++- src/backend/app/loot_paths.cpp | 118 ++++++++++++++++++ src/backend/app/loot_paths.h | 54 ++++++++ src/backend/app/loot_settings.cpp | 4 +- src/backend/app/loot_state.cpp | 23 ++-- .../{globals.h => app/loot_version.cpp.in} | 25 +--- src/backend/app/loot_version.h | 40 ++++++ src/backend/game/game.cpp | 6 +- src/backend/game/game_cache.cpp | 1 - src/backend/game/game_settings.cpp | 6 +- src/backend/globals.cpp.in | 44 ------- src/backend/helpers/helpers.cpp | 36 ------ src/backend/helpers/helpers.h | 3 - src/backend/metadata_list.cpp | 1 - src/gui/handler.cpp | 13 +- src/gui/loot_app.cpp | 10 +- src/gui/loot_handler.cpp | 8 +- src/gui/main.cpp | 7 +- src/gui/scheme.cpp | 4 +- src/tests/backend/app/loot_paths_test.h | 86 +++++++++++++ src/tests/backend/app/loot_settings_test.h | 6 +- src/tests/backend/game/game_settings_test.h | 10 +- src/tests/backend/game/game_test.h | 14 +-- src/tests/backend/helpers/version_test.h | 9 +- src/tests/backend/masterlist_test.h | 7 +- src/tests/main.cpp | 1 + src/validator/main.cpp | 8 +- 28 files changed, 391 insertions(+), 187 deletions(-) create mode 100644 src/backend/app/loot_paths.cpp create mode 100644 src/backend/app/loot_paths.h rename src/backend/{globals.h => app/loot_version.cpp.in} (55%) create mode 100644 src/backend/app/loot_version.h delete mode 100644 src/backend/globals.cpp.in create mode 100644 src/tests/backend/app/loot_paths_test.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 36393470..bbdfeb5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ ENDIF () message(STATUS "Git revision: ${GIT_COMMIT_STRING}") # Write to file. -configure_file("${CMAKE_SOURCE_DIR}/src/backend/globals.cpp.in" "${CMAKE_BINARY_DIR}/generated/globals.cpp" @ONLY) +configure_file("${CMAKE_SOURCE_DIR}/src/backend/app/loot_version.cpp.in" "${CMAKE_BINARY_DIR}/generated/loot_version.cpp" @ONLY) ############################## # External Projects @@ -120,8 +120,10 @@ IF (NOT DEFINED CEF_ROOT) set (CEF_ROOT "../../cef") ENDIF () -set (LOOT_SRC "${CMAKE_SOURCE_DIR}/src/backend/app/loot_settings.cpp" +set (LOOT_SRC "${CMAKE_SOURCE_DIR}/src/backend/app/loot_paths.cpp" + "${CMAKE_SOURCE_DIR}/src/backend/app/loot_settings.cpp" "${CMAKE_SOURCE_DIR}/src/backend/app/loot_state.cpp" + "${CMAKE_BINARY_DIR}/generated/loot_version.cpp" "${CMAKE_SOURCE_DIR}/src/backend/metadata/conditional_metadata.cpp" "${CMAKE_SOURCE_DIR}/src/backend/metadata/file.cpp" "${CMAKE_SOURCE_DIR}/src/backend/metadata/location.cpp" @@ -141,11 +143,12 @@ set (LOOT_SRC "${CMAKE_SOURCE_DIR}/src/backend/app/loot_settings.cpp" "${CMAKE_SOURCE_DIR}/src/backend/helpers/git_helper.cpp" "${CMAKE_SOURCE_DIR}/src/backend/helpers/helpers.cpp" "${CMAKE_SOURCE_DIR}/src/backend/helpers/language.cpp" - "${CMAKE_SOURCE_DIR}/src/backend/helpers/version.cpp" - "${CMAKE_BINARY_DIR}/generated/globals.cpp") + "${CMAKE_SOURCE_DIR}/src/backend/helpers/version.cpp") -set (LOOT_HEADERS "${CMAKE_SOURCE_DIR}/src/backend/app/loot_settings.h" +set (LOOT_HEADERS "${CMAKE_SOURCE_DIR}/src/backend/app/loot_paths.h" + "${CMAKE_SOURCE_DIR}/src/backend/app/loot_settings.h" "${CMAKE_SOURCE_DIR}/src/backend/app/loot_state.h" + "${CMAKE_SOURCE_DIR}/src/backend/app/loot_version.h" "${CMAKE_SOURCE_DIR}/src/backend/metadata/condition_grammar.h" "${CMAKE_SOURCE_DIR}/src/backend/metadata/conditional_metadata.h" "${CMAKE_SOURCE_DIR}/src/backend/metadata/file.h" @@ -169,7 +172,6 @@ set (LOOT_HEADERS "${CMAKE_SOURCE_DIR}/src/backend/app/loot_settings.h" "${CMAKE_SOURCE_DIR}/src/backend/helpers/language.h" "${CMAKE_SOURCE_DIR}/src/backend/helpers/version.h" "${CMAKE_SOURCE_DIR}/src/backend/helpers/yaml_set_helpers.h" - "${CMAKE_SOURCE_DIR}/src/backend/globals.h" "${CMAKE_SOURCE_DIR}/src/backend/error.h") set (LOOT_GUI_SRC ${LOOT_SRC} @@ -223,6 +225,7 @@ set (LOOT_TESTS_HEADERS "${CMAKE_SOURCE_DIR}/src/tests/base_game_test.h" "${CMAKE_SOURCE_DIR}/src/tests/api/loot_write_minimal_list_test.h" "${CMAKE_SOURCE_DIR}/src/tests/api/test_api.h" + "${CMAKE_SOURCE_DIR}/src/tests/backend/app/loot_paths_test.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/app/loot_settings_test.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/app/loot_state_test.h" "${CMAKE_SOURCE_DIR}/src/tests/backend/game/game_test.h" diff --git a/src/api/api.cpp b/src/api/api.cpp index cf108c5f..54462bb3 100644 --- a/src/api/api.cpp +++ b/src/api/api.cpp @@ -25,7 +25,8 @@ #include "loot/api.h" #include "loot_db.h" #include "../backend/error.h" -#include "../backend/globals.h" +#include "../backend/app/loot_paths.h" +#include "../backend/app/loot_version.h" #include "../backend/plugin/plugin_sorter.h" #include @@ -121,9 +122,9 @@ LOOT_API unsigned int loot_get_error_message(const char ** const message) { // LOOT version. Abstracts LOOT API stability policy away from clients. LOOT_API bool loot_is_compatible(const unsigned int versionMajor, const unsigned int versionMinor, const unsigned int versionPatch) { if (versionMajor > 0) - return versionMajor == loot::g_version_major; + return versionMajor == loot::LootVersion::major; else - return versionMinor == loot::g_version_minor; + return versionMinor == loot::LootVersion::minor; } // Returns the version string for this version of LOOT. @@ -133,9 +134,9 @@ LOOT_API unsigned int loot_get_version(unsigned int * const versionMajor, unsign if (versionMajor == nullptr || versionMinor == nullptr || versionPatch == nullptr) return c_error(loot_error_invalid_args, "Null pointer passed."); - *versionMajor = loot::g_version_major; - *versionMinor = loot::g_version_minor; - *versionPatch = loot::g_version_patch; + *versionMajor = loot::LootVersion::major; + *versionMinor = loot::LootVersion::minor; + *versionPatch = loot::LootVersion::patch; return loot_ok; } @@ -144,7 +145,7 @@ LOOT_API unsigned int loot_get_build_id(const char ** const revision) { if (revision == nullptr) return c_error(loot_error_invalid_args, "Null message pointer passed."); - *revision = loot::g_build_revision; + *revision = loot::LootVersion::revision.c_str(); return loot_ok; } @@ -172,9 +173,7 @@ LOOT_API unsigned int loot_create_db(loot_db ** const db, && clientGame != loot_game_fo4)) return c_error(loot_error_invalid_args, "Null pointer passed."); - //Set the locale to get encoding conversions working correctly. - std::locale::global(boost::locale::generator().generate("")); - boost::filesystem::path::imbue(std::locale()); + loot::LootPaths::initialise(); //Disable logging or else stdout will get overrun. boost::log::core::get()->set_logging_enabled(false); diff --git a/src/backend/app/loot_paths.cpp b/src/backend/app/loot_paths.cpp new file mode 100644 index 00000000..8c1ba8fa --- /dev/null +++ b/src/backend/app/loot_paths.cpp @@ -0,0 +1,118 @@ +/* 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 + . +*/ + +#include "loot_paths.h" +#include "../helpers/helpers.h" +#include "../error.h" + +#include + +#include + +#ifdef _WIN32 +# ifndef UNICODE +# define UNICODE +# endif +# ifndef _UNICODE +# define _UNICODE +# endif +# include "windows.h" +# include "shlobj.h" +#endif + +namespace loot { + boost::filesystem::path LootPaths::getReadmePath() { + return lootAppPath / "docs" / "LOOT Readme.html"; + } + + boost::filesystem::path LootPaths::getUIIndexPath() { + return lootAppPath / "resources" / "ui" / "index.html"; + } + + boost::filesystem::path LootPaths::getL10nPath() { + return lootAppPath / "resources" / "l10n"; + } + + boost::filesystem::path LootPaths::getLootDataPath() { + return lootDataPath; + } + + boost::filesystem::path LootPaths::getSettingsPath() { + return lootDataPath / "settings.yaml"; + } + + boost::filesystem::path LootPaths::getLogPath() { + return lootDataPath / "LOOTDebugLog.txt"; + } + + void LootPaths::initialise() { + // Set the locale to get UTF-8 conversions working correctly. + std::locale::global(boost::locale::generator().generate("")); + boost::filesystem::path::imbue(std::locale()); + + lootAppPath = boost::filesystem::current_path(); + lootDataPath = getLocalAppDataPath() / "LOOT"; + } + + void LootPaths::setLootAppPath(const boost::filesystem::path& path) { + lootAppPath = path; + } + + void LootPaths::setLootDataPath(const boost::filesystem::path& path) { + lootDataPath = path; + } + + boost::filesystem::path LootPaths::getLocalAppDataPath() { +#ifdef _WIN32 + HWND owner = 0; + PWSTR path; + + if (SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path) != S_OK) + throw error(error::windows_error, boost::locale::translate("Failed to get %LOCALAPPDATA% path.")); + + boost::filesystem::path localAppDataPath(FromWinWide(path)); + CoTaskMemFree(path); + + return localAppDataPath; +#else + // Use XDG_CONFIG_HOME environmental variable if it's available. + const char * xdgConfigHome = getenv("XDG_CONFIG_HOME"); + + if (xdgConfigHome != nullptr) + return boost::filesystem::path(xdgConfigHome); + + // Otherwise, use the HOME env. var. if it's available. + xdgConfigHome = getenv("HOME"); + + if (xdgConfigHome != nullptr) + return boost::filesystem::path(xdgConfigHome) / ".config"; + + // If somehow both are missing, use the current path. + return boost::filesystem::current_path(); +#endif + } + + boost::filesystem::path LootPaths::lootAppPath = boost::filesystem::path(); + boost::filesystem::path LootPaths::lootDataPath = boost::filesystem::path(); +} diff --git a/src/backend/app/loot_paths.h b/src/backend/app/loot_paths.h new file mode 100644 index 00000000..b5ecb4f1 --- /dev/null +++ b/src/backend/app/loot_paths.h @@ -0,0 +1,54 @@ +/* LOOT + +A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and +Fallout: New Vegas. + +Copyright (C) 2014-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 +. +*/ + +#ifndef LOOT_BACKEND_LOOT_PATHS +#define LOOT_BACKEND_LOOT_PATHS + +#include + +namespace loot { + class LootPaths { + public: + static boost::filesystem::path getReadmePath(); + static boost::filesystem::path getUIIndexPath(); + static boost::filesystem::path getL10nPath(); + static boost::filesystem::path getLootDataPath(); + static boost::filesystem::path getSettingsPath(); + static boost::filesystem::path getLogPath(); + + // Sets the app path to the current path, and the data path to the user + // local app data path / "LOOT". + static void initialise(); + static void setLootAppPath(const boost::filesystem::path& path); + static void setLootDataPath(const boost::filesystem::path& path); + private: + static boost::filesystem::path lootAppPath; + static boost::filesystem::path lootDataPath; + + //Get the local application data path. + static boost::filesystem::path getLocalAppDataPath(); + }; +} + +#endif diff --git a/src/backend/app/loot_settings.cpp b/src/backend/app/loot_settings.cpp index 434a71a9..1cf6d161 100644 --- a/src/backend/app/loot_settings.cpp +++ b/src/backend/app/loot_settings.cpp @@ -23,7 +23,7 @@ */ #include "loot_settings.h" -#include "backend/globals.h" +#include "backend/app/loot_version.h" #include @@ -195,7 +195,7 @@ namespace loot { void LootSettings::updateLastVersion() { std::lock_guard guard(mutex); - lastVersion = std::to_string(g_version_major) + "." + std::to_string(g_version_minor) + "." + std::to_string(g_version_patch); + lastVersion = std::to_string(LootVersion::major) + "." + std::to_string(LootVersion::minor) + "." + std::to_string(LootVersion::patch); } YAML::Node LootSettings::toYaml() const { diff --git a/src/backend/app/loot_state.cpp b/src/backend/app/loot_state.cpp index 4285a911..7aa20298 100644 --- a/src/backend/app/loot_state.cpp +++ b/src/backend/app/loot_state.cpp @@ -23,9 +23,10 @@ */ #include "loot_state.h" +#include "loot_paths.h" #include "backend/error.h" -#include "backend/globals.h" +#include "backend/app/loot_version.h" #include "backend/helpers/helpers.h" #include "backend/helpers/language.h" @@ -104,7 +105,7 @@ namespace loot { // Do some preliminary locale / UTF-8 support setup here, in case the settings file reading requires it. //Boost.Locale initialisation: Specify location of language dictionaries. boost::locale::generator gen; - gen.add_messages_path(g_path_l10n.string()); + gen.add_messages_path(LootPaths::getL10nPath().string()); gen.add_messages_domain("loot"); //Boost.Locale initialisation: Generate and imbue locales. @@ -112,18 +113,18 @@ namespace loot { boost::filesystem::path::imbue(locale()); // Check if the LOOT local app data folder exists, and create it if not. - if (!fs::exists(g_path_local)) { + if (!fs::exists(LootPaths::getLootDataPath())) { BOOST_LOG_TRIVIAL(info) << "Local app data LOOT folder doesn't exist, creating it."; try { - fs::create_directory(g_path_local); + fs::create_directory(LootPaths::getLootDataPath()); } catch (exception& e) { _initErrors.push_back((format(translate("Error: Could not create LOOT settings file. %1%")) % e.what()).str()); } } - if (fs::exists(g_path_settings)) { + if (fs::exists(LootPaths::getSettingsPath())) { try { - LootSettings::load(g_path_settings); + LootSettings::load(LootPaths::getSettingsPath()); } catch (exception& e) { _initErrors.push_back((format(translate("Error: Settings parsing failed. %1%")) % e.what()).str()); @@ -132,7 +133,7 @@ namespace loot { //Set up logging. boost::log::add_file_log( - boost::log::keywords::file_name = g_path_log.string().c_str(), + boost::log::keywords::file_name = LootPaths::getLogPath().string().c_str(), boost::log::keywords::auto_flush = true, boost::log::keywords::format = ( boost::log::expressions::stream @@ -140,13 +141,13 @@ namespace loot { << " [" << boost::log::trivial::severity << "]: " << boost::log::expressions::smessage ) - ); + ); boost::log::add_common_attributes(); boost::log::core::get()->set_logging_enabled(isDebugLoggingEnabled()); // Log some useful info. - BOOST_LOG_TRIVIAL(info) << "LOOT Version: " << g_version_major << "." << g_version_minor << "." << g_version_patch; - BOOST_LOG_TRIVIAL(info) << "LOOT Build Revision: " << g_build_revision; + BOOST_LOG_TRIVIAL(info) << "LOOT Version: " << LootVersion::major << "." << LootVersion::minor << "." << LootVersion::patch; + BOOST_LOG_TRIVIAL(info) << "LOOT Build Revision: " << LootVersion::revision; #ifdef _WIN32 // Check if LOOT is being run through Mod Organiser. bool runFromMO = GetModuleHandle(ToWinWide("hook.dll").c_str()) != NULL; @@ -157,7 +158,7 @@ namespace loot { // The CEF debug log is appended to, not overwritten, so it gets really long. // Delete the current CEF debug log. - fs::remove(g_path_local / "CEFDebugLog.txt"); + fs::remove(LootPaths::getLootDataPath() / "CEFDebugLog.txt"); // Now that settings have been loaded, set the locale again to handle translations. if (getLanguage().Code() != Language::english) { diff --git a/src/backend/globals.h b/src/backend/app/loot_version.cpp.in similarity index 55% rename from src/backend/globals.h rename to src/backend/app/loot_version.cpp.in index 58f2ac9e..8609e161 100644 --- a/src/backend/globals.h +++ b/src/backend/app/loot_version.cpp.in @@ -21,27 +21,12 @@ along with LOOT. If not, see . */ -#ifndef __LOOT_GLOBALS__ -#define __LOOT_GLOBALS__ -#include +#include "backend/app/loot_version.h" namespace loot { - //Version numbers. - extern const unsigned int g_version_major; - extern const unsigned int g_version_minor; - extern const unsigned int g_version_patch; - - // Build revision - extern const char * g_build_revision; - - //Common paths. - extern const boost::filesystem::path g_path_readme; - extern const boost::filesystem::path g_path_report; - extern const boost::filesystem::path g_path_l10n; - extern const boost::filesystem::path g_path_local; - extern const boost::filesystem::path g_path_settings; - extern const boost::filesystem::path g_path_log; + const unsigned int LootVersion::major = 0; + const unsigned int LootVersion::minor = 9; + const unsigned int LootVersion::patch = 0; + const std::string LootVersion::revision = "@GIT_COMMIT_STRING@"; } - -#endif diff --git a/src/backend/app/loot_version.h b/src/backend/app/loot_version.h new file mode 100644 index 00000000..d3d68d3f --- /dev/null +++ b/src/backend/app/loot_version.h @@ -0,0 +1,40 @@ +/* LOOT + +A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and +Fallout: New Vegas. + +Copyright (C) 2014-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 +. +*/ + +#ifndef LOOT_BACKEND_LOOT_VERSION +#define LOOT_BACKEND_LOOT_VERSION + +#include + +namespace loot { + class LootVersion { + public: + static const unsigned int major; + static const unsigned int minor; + static const unsigned int patch; + static const std::string revision; + }; +} + +#endif diff --git a/src/backend/game/game.cpp b/src/backend/game/game.cpp index 6d55ace0..d317723e 100644 --- a/src/backend/game/game.cpp +++ b/src/backend/game/game.cpp @@ -23,7 +23,7 @@ */ #include "game.h" -#include "../globals.h" +#include "../app/loot_paths.h" #include "../helpers/helpers.h" #include "../error.h" @@ -67,8 +67,8 @@ namespace loot { if (createFolder) { //Make sure that the LOOT game path exists. try { - if (!fs::exists(g_path_local / FolderName())) - fs::create_directories(g_path_local / FolderName()); + if (!fs::exists(LootPaths::getLootDataPath() / FolderName())) + fs::create_directories(LootPaths::getLootDataPath() / FolderName()); } catch (fs::filesystem_error& e) { BOOST_LOG_TRIVIAL(error) << "Could not create LOOT folder for game. Details: " << e.what(); diff --git a/src/backend/game/game_cache.cpp b/src/backend/game/game_cache.cpp index 9dd71763..813726bb 100644 --- a/src/backend/game/game_cache.cpp +++ b/src/backend/game/game_cache.cpp @@ -23,7 +23,6 @@ */ #include "game_cache.h" -#include "../globals.h" #include "../helpers/helpers.h" #include "../error.h" diff --git a/src/backend/game/game_settings.cpp b/src/backend/game/game_settings.cpp index 604e8832..12001ede 100644 --- a/src/backend/game/game_settings.cpp +++ b/src/backend/game/game_settings.cpp @@ -23,7 +23,7 @@ */ #include "game_settings.h" -#include "../globals.h" +#include "../app/loot_paths.h" #include "../helpers/helpers.h" #include "../error.h" @@ -181,14 +181,14 @@ namespace loot { if (_lootFolderName.empty()) return ""; else - return g_path_local / _lootFolderName / "masterlist.yaml"; + return LootPaths::getLootDataPath() / _lootFolderName / "masterlist.yaml"; } fs::path GameSettings::UserlistPath() const { if (_lootFolderName.empty()) return ""; else - return g_path_local / _lootFolderName / "userlist.yaml"; + return LootPaths::getLootDataPath() / _lootFolderName / "userlist.yaml"; } GameSettings& GameSettings::SetName(const std::string& name) { diff --git a/src/backend/globals.cpp.in b/src/backend/globals.cpp.in deleted file mode 100644 index 5e3d579e..00000000 --- a/src/backend/globals.cpp.in +++ /dev/null @@ -1,44 +0,0 @@ -/* 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 - . - */ - -#include "backend/globals.h" -#include "backend/helpers/helpers.h" - -namespace loot { - //Version numbers. - const unsigned int g_version_major = 0; - const unsigned int g_version_minor = 9; - const unsigned int g_version_patch = 0; - - // Build revision - const char * g_build_revision = "@GIT_COMMIT_STRING@"; - - //Common paths. - const boost::filesystem::path g_path_readme = boost::filesystem::current_path() / "docs" / "LOOT Readme.html"; - const boost::filesystem::path g_path_report = boost::filesystem::current_path() / "resources" / "ui" / "index.html"; - const boost::filesystem::path g_path_l10n = boost::filesystem::current_path() / "resources" / "l10n"; - const boost::filesystem::path g_path_local = GetLocalAppDataPath() / "LOOT"; - const boost::filesystem::path g_path_settings = g_path_local / "settings.yaml"; - const boost::filesystem::path g_path_log = g_path_local / "LOOTDebugLog.txt"; -} diff --git a/src/backend/helpers/helpers.cpp b/src/backend/helpers/helpers.cpp index 2dc54f6c..0f7732e4 100644 --- a/src/backend/helpers/helpers.cpp +++ b/src/backend/helpers/helpers.cpp @@ -131,42 +131,6 @@ namespace loot { #endif } - boost::filesystem::path GetLocalAppDataPath() { -#ifdef _WIN32 - HWND owner = 0; - PWSTR path; - - if (SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path) != S_OK) - throw error(error::windows_error, lc::translate("Failed to get %LOCALAPPDATA% path.")); - - // This code runs to set the value for a global constant, so before the - // main initialisation code, which means it needs to imbue a UTF-8 - // codecvt for paths itself. - std::locale::global(std::locale(std::locale(), new std::codecvt_utf8_utf16)); - boost::filesystem::path::imbue(std::locale()); - - fs::path localAppDataPath(FromWinWide(path)); - CoTaskMemFree(path); - - return localAppDataPath; -#else - // Use XDG_CONFIG_HOME environmental variable if it's available. - const char * xdgConfigHome = getenv("XDG_CONFIG_HOME"); - - if (xdgConfigHome != nullptr) - return fs::path(xdgConfigHome); - - // Otherwise, use the HOME env. var. if it's available. - xdgConfigHome = getenv("HOME"); - - if (xdgConfigHome != nullptr) - return fs::path(xdgConfigHome) / ".config"; - - // If somehow both are missing, use the current path. - return fs::current_path(); -#endif - } - #ifdef _WIN32 //Get registry subkey value string. string RegKeyStringValue(const std::string& keyStr, const std::string& subkey, const std::string& value) { diff --git a/src/backend/helpers/helpers.h b/src/backend/helpers/helpers.h index f4ed208f..338df43a 100644 --- a/src/backend/helpers/helpers.h +++ b/src/backend/helpers/helpers.h @@ -42,9 +42,6 @@ namespace loot { //Opens the file in its registered default application. void OpenInDefaultApplication(const boost::filesystem::path& file); - //Get the local application data path, within which LOOT's data folder should be stored. - boost::filesystem::path GetLocalAppDataPath(); - #ifdef _WIN32 //Get registry subkey value string. std::string RegKeyStringValue(const std::string& keyStr, const std::string& subkey, const std::string& value); diff --git a/src/backend/metadata_list.cpp b/src/backend/metadata_list.cpp index 719a330a..48c6c341 100644 --- a/src/backend/metadata_list.cpp +++ b/src/backend/metadata_list.cpp @@ -23,7 +23,6 @@ */ #include "metadata_list.h" -#include "globals.h" #include "error.h" #include diff --git a/src/gui/handler.cpp b/src/gui/handler.cpp index 9f7d6a56..ad98fbaf 100644 --- a/src/gui/handler.cpp +++ b/src/gui/handler.cpp @@ -28,7 +28,8 @@ #include "loot_handler.h" #include "../backend/error.h" -#include "../backend/globals.h" +#include "../backend/app/loot_paths.h" +#include "../backend/app/loot_version.h" #include "../backend/plugin/plugin_sorter.h" #include "../backend/helpers/helpers.h" #include "../backend/helpers/json.h" @@ -558,18 +559,18 @@ namespace loot { void Handler::OpenReadme() { BOOST_LOG_TRIVIAL(info) << "Opening LOOT readme."; // Open readme in default application. - OpenInDefaultApplication(g_path_readme); + OpenInDefaultApplication(LootPaths::getReadmePath()); } void Handler::OpenLogLocation() { BOOST_LOG_TRIVIAL(info) << "Opening LOOT local appdata folder."; //Open debug log folder. - OpenInDefaultApplication(g_path_log.parent_path()); + OpenInDefaultApplication(LootPaths::getLogPath().parent_path()); } std::string Handler::GetVersion() { BOOST_LOG_TRIVIAL(info) << "Getting LOOT version."; - YAML::Node version(to_string(g_version_major) + "." + to_string(g_version_minor) + "." + to_string(g_version_patch) + "." + g_build_revision); + YAML::Node version(to_string(LootVersion::major) + "." + to_string(LootVersion::minor) + "." + to_string(LootVersion::patch) + "." + LootVersion::revision); return JSON::stringify(version); } @@ -653,7 +654,7 @@ namespace loot { "This probably happened because an update to LOOT changed " "its metadata syntax support. Try updating your masterlist " "to resolve the error." - )) % e.what()).str())); + )) % e.what()).str())); } } @@ -676,7 +677,7 @@ namespace loot { "[syntax documentation](http://loot.github.io/docs/%2%.%3%.%4%/LOOT%%20Metadata%%20Syntax.html).\n\n" "You can also seek support on LOOT's forum thread, which is " "linked to on [LOOT's website](http://loot.github.io/)." - )) % e.what() % g_version_major % g_version_minor % g_version_patch).str())); + )) % e.what() % LootVersion::major % LootVersion::minor % LootVersion::patch).str())); } } } diff --git a/src/gui/loot_app.cpp b/src/gui/loot_app.cpp index 36aedb7a..07ac9c52 100644 --- a/src/gui/loot_app.cpp +++ b/src/gui/loot_app.cpp @@ -26,7 +26,7 @@ #include "loot_handler.h" #include "scheme.h" -#include "../backend/globals.h" +#include "../backend/app/loot_paths.h" #include "../backend/helpers/helpers.h" #include "../backend/helpers/language.h" @@ -47,7 +47,9 @@ using boost::format; namespace fs = boost::filesystem; namespace loot { - LootApp::LootApp() {} + LootApp::LootApp() { + LootPaths::initialise(); + } void LootApp::OnBeforeCommandLineProcessing(const CefString& process_type, CefRefPtr command_line) { @@ -98,7 +100,7 @@ namespace loot { BOOST_LOG_TRIVIAL(debug) << "Initialising language settings in UI thread."; if (lootState.getLanguage().Code() != Language::english) { boost::locale::generator gen; - gen.add_messages_path(g_path_l10n.string()); + gen.add_messages_path(LootPaths::getL10nPath().string()); gen.add_messages_domain("loot"); BOOST_LOG_TRIVIAL(debug) << "Selected language: " << lootState.getLanguage().Name(); @@ -107,7 +109,7 @@ namespace loot { } // Set URL to load. Ignore any command line values. - std::string url = ToFileURL(g_path_report); + std::string url = ToFileURL(LootPaths::getUIIndexPath()); // Create the first browser window. CefBrowserHost::CreateBrowser(window_info, handler.get(), url, browser_settings, NULL); diff --git a/src/gui/loot_handler.cpp b/src/gui/loot_handler.cpp index dd4fbb77..c738964b 100644 --- a/src/gui/loot_handler.cpp +++ b/src/gui/loot_handler.cpp @@ -28,7 +28,7 @@ #include "loot_app.h" #include "../backend/error.h" -#include "../backend/globals.h" +#include "../backend/app/loot_paths.h" #include "../backend/helpers/helpers.h" #include "../backend/helpers/json.h" @@ -186,7 +186,7 @@ namespace loot { #endif try { - _lootState.save(g_path_settings); + _lootState.save(LootPaths::getSettingsPath()); } catch (std::exception &e) { BOOST_LOG_TRIVIAL(error) << "Failed to save LOOT's settings. Error: " << e.what(); @@ -241,9 +241,9 @@ namespace loot { CefRefPtr< CefRequest > request, bool is_redirect) { BOOST_LOG_TRIVIAL(trace) << "Attempting to open link: " << request->GetURL().ToString(); - BOOST_LOG_TRIVIAL(trace) << "Comparing with URL: " << ToFileURL(g_path_report); + BOOST_LOG_TRIVIAL(trace) << "Comparing with URL: " << ToFileURL(LootPaths::getUIIndexPath()); - if (boost::iequals(request->GetURL().ToString(), ToFileURL(g_path_report))) { + if (boost::iequals(request->GetURL().ToString(), ToFileURL(LootPaths::getUIIndexPath()))) { BOOST_LOG_TRIVIAL(trace) << "Link is to LOOT page, allowing CEF's default handling."; return false; } diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 2b7149c2..a10d541b 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -23,8 +23,7 @@ */ #include "loot_app.h" -#include "backend/app/loot_state.h" -#include "backend/globals.h" +#include "backend/app/loot_paths.h" #ifdef _WIN32 #include @@ -57,10 +56,10 @@ CefSettings GetCefSettings() { cef_settings.command_line_args_disabled = false; // Set CEF logging. - CefString(&cef_settings.log_file).FromString((g_path_local / "CEFDebugLog.txt").string()); + CefString(&cef_settings.log_file).FromString((LootPaths::getLootDataPath() / "CEFDebugLog.txt").string()); // Load locale pack files from LOOT's l10n path. - CefString(&cef_settings.locales_dir_path).FromString(g_path_l10n.string()); + CefString(&cef_settings.locales_dir_path).FromString(LootPaths::getL10nPath().string()); return cef_settings; } diff --git a/src/gui/scheme.cpp b/src/gui/scheme.cpp index f006ddb1..38b3118e 100644 --- a/src/gui/scheme.cpp +++ b/src/gui/scheme.cpp @@ -24,7 +24,7 @@ along with LOOT. If not, see #include "scheme.h" -#include "../backend/globals.h" +#include "backend/app/loot_paths.h" #include @@ -47,7 +47,7 @@ namespace loot { // Get the path from the custom URL, which is of the form // loot://l10n/ - string file = (g_path_l10n / request->GetURL().ToString().substr(12)).string(); + string file = (LootPaths::getL10nPath() / request->GetURL().ToString().substr(12)).string(); CefResponse::HeaderMap headers; headers.emplace("Access-Control-Allow-Origin", "*"); diff --git a/src/tests/backend/app/loot_paths_test.h b/src/tests/backend/app/loot_paths_test.h new file mode 100644 index 00000000..a2d55f11 --- /dev/null +++ b/src/tests/backend/app/loot_paths_test.h @@ -0,0 +1,86 @@ +/* LOOT + +A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and +Fallout: New Vegas. + +Copyright (C) 2014-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 +. +*/ + +#ifndef LOOT_TEST_BACKEND_LOOT_PATHS +#define LOOT_TEST_BACKEND_LOOT_PATHS + +#include "backend/app/loot_paths.h" + +namespace loot { + namespace test { + TEST(LootPaths, getReadmePathShouldUseLootAppPath) { + LootPaths::setLootAppPath("readme"); + + EXPECT_EQ(boost::filesystem::path("readme") / "docs" / "LOOT Readme.html", LootPaths::getReadmePath()); + } + + TEST(LootPaths, getUIIndexPathShouldUseLootAppPath) { + LootPaths::setLootAppPath("ui"); + + EXPECT_EQ(boost::filesystem::path("ui") / "resources" / "ui" / "index.html", LootPaths::getUIIndexPath()); + } + + TEST(LootPaths, getL10nPathShouldUseLootAppPath) { + LootPaths::setLootAppPath("l10n"); + + EXPECT_EQ(boost::filesystem::path("l10n") / "resources" / "l10n", LootPaths::getL10nPath()); + } + + TEST(LootPaths, getLootDataPathShouldReturnTheSetPath) { + LootPaths::setLootDataPath("data"); + + EXPECT_EQ("data", LootPaths::getLootDataPath()); + } + + TEST(LootPaths, getSettingsPathShouldUseLootDataPath) { + LootPaths::setLootDataPath("settings"); + + EXPECT_EQ(boost::filesystem::path("settings") / "settings.yaml", LootPaths::getSettingsPath()); + } + + TEST(LootPaths, getLogPathShouldUseLootDataPath) { + LootPaths::setLootDataPath("log"); + + EXPECT_EQ(boost::filesystem::path("log") / "LOOTDebugLog.txt", LootPaths::getLogPath()); + } + + TEST(LootPaths, initialiseShouldSetTheAppPathToTheCurrentPath) { + LootPaths::initialise(); + + EXPECT_EQ(boost::filesystem::current_path(), LootPaths::getReadmePath().parent_path().parent_path()); + } + + TEST(LootPaths, initialiseShouldSetTheAppPathToTheLocalAppDataPathSlashLoot) { + LootPaths::initialise(); + + // Can't actually know what the path should be, but we can check + // its properties. + EXPECT_EQ("LOOT", LootPaths::getLootDataPath().filename()); + EXPECT_FALSE(LootPaths::getLootDataPath().parent_path().empty()); + EXPECT_TRUE(boost::filesystem::exists(LootPaths::getLootDataPath().parent_path())); + } + } +} + +#endif diff --git a/src/tests/backend/app/loot_settings_test.h b/src/tests/backend/app/loot_settings_test.h index 8941db8a..a12949f2 100644 --- a/src/tests/backend/app/loot_settings_test.h +++ b/src/tests/backend/app/loot_settings_test.h @@ -26,7 +26,7 @@ along with LOOT. If not, see #define LOOT_TEST_GUI_LOOT_SETTINGS #include "backend/app/loot_settings.h" -#include "backend/globals.h" +#include "backend/app/loot_version.h" namespace loot { namespace test { @@ -43,7 +43,7 @@ namespace loot { }; TEST_F(LootSettingsTest, defaultConstructorShouldSetDefaultValues) { - const std::string currentVersion = std::to_string(g_version_major) + "." + std::to_string(g_version_minor) + "." + std::to_string(g_version_patch); + const std::string currentVersion = std::to_string(LootVersion::major) + "." + std::to_string(LootVersion::minor) + "." + std::to_string(LootVersion::patch); const std::vector expectedGameSettings({ GameSettings(GameSettings::tes4), GameSettings(GameSettings::tes5), @@ -408,7 +408,7 @@ namespace loot { } TEST_F(LootSettingsTest, updateLastVersionShouldSetValueToCurrentLootVersion) { - const std::string currentVersion = std::to_string(g_version_major) + "." + std::to_string(g_version_minor) + "." + std::to_string(g_version_patch); + const std::string currentVersion = std::to_string(LootVersion::major) + "." + std::to_string(LootVersion::minor) + "." + std::to_string(LootVersion::patch); YAML::Node inputYaml; inputYaml["lastVersion"] = "v0.7.1"; diff --git a/src/tests/backend/game/game_settings_test.h b/src/tests/backend/game/game_settings_test.h index c56adcf9..69c7a780 100644 --- a/src/tests/backend/game/game_settings_test.h +++ b/src/tests/backend/game/game_settings_test.h @@ -25,7 +25,7 @@ along with LOOT. If not, see #ifndef LOOT_TEST_BACKEND_GAME_SETTINGS #define LOOT_TEST_BACKEND_GAME_SETTINGS -#include "backend/globals.h" +#include "backend/app/loot_paths.h" #include "backend/game/game_settings.h" #include "tests/base_game_test.h" @@ -75,16 +75,16 @@ namespace loot { EXPECT_EQ("", game.GamePath()); EXPECT_EQ("", game.DataPath()); - EXPECT_EQ(g_path_local / "Skyrim" / "masterlist.yaml", game.MasterlistPath()); - EXPECT_EQ(g_path_local / "Skyrim" / "userlist.yaml", game.UserlistPath()); + EXPECT_EQ(LootPaths::getLootDataPath() / "Skyrim" / "masterlist.yaml", game.MasterlistPath()); + EXPECT_EQ(LootPaths::getLootDataPath() / "Skyrim" / "userlist.yaml", game.UserlistPath()); } TEST_P(GameSettingsTest, idConstructorShouldSetGameFolderIfGiven) { game = GameSettings(GameSettings::tes5, "folder"); EXPECT_EQ("folder", game.FolderName()); - EXPECT_EQ(g_path_local / "folder" / "masterlist.yaml", game.MasterlistPath()); - EXPECT_EQ(g_path_local / "folder" / "userlist.yaml", game.UserlistPath()); + EXPECT_EQ(LootPaths::getLootDataPath() / "folder" / "masterlist.yaml", game.MasterlistPath()); + EXPECT_EQ(LootPaths::getLootDataPath() / "folder" / "userlist.yaml", game.UserlistPath()); } TEST_P(GameSettingsTest, isInstalledShouldBeFalseIfGamePathIsNotSet) { diff --git a/src/tests/backend/game/game_test.h b/src/tests/backend/game/game_test.h index 52150702..a5f02c59 100644 --- a/src/tests/backend/game/game_test.h +++ b/src/tests/backend/game/game_test.h @@ -26,7 +26,7 @@ along with LOOT. If not, see #define LOOT_TEST_BACKEND_GAME #include "backend/error.h" -#include "backend/globals.h" +#include "backend/app/loot_paths.h" #include "backend/game/game.h" #include "load_order_handler_test.h" @@ -39,7 +39,7 @@ namespace loot { void TearDown() { BaseGameTest::TearDown(); - ASSERT_NO_THROW(boost::filesystem::remove_all(g_path_local)); + ASSERT_NO_THROW(boost::filesystem::remove_all(LootPaths::getLootDataPath())); } #endif }; @@ -121,7 +121,7 @@ namespace loot { TEST_P(GameTest, initShouldThrowOnLinuxIfLocalPathIsNotGiven) { Game game = Game(GetParam()).SetGamePath(dataPath.parent_path()); - ASSERT_FALSE(boost::filesystem::exists(g_path_local / game.FolderName())); + ASSERT_FALSE(boost::filesystem::exists(LootPaths::getLootDataPath() / game.FolderName())); EXPECT_THROW(game.Init(false), error); } @@ -130,19 +130,19 @@ namespace loot { TEST_P(GameTest, initShouldNotCreateAGameFolderIfTheCreateFolderArgumentIsFalse) { Game game = Game(GetParam()).SetGamePath(dataPath.parent_path()); - ASSERT_FALSE(boost::filesystem::exists(g_path_local / game.FolderName())); + ASSERT_FALSE(boost::filesystem::exists(LootPaths::getLootDataPath() / game.FolderName())); EXPECT_NO_THROW(game.Init(false, localPath)); - EXPECT_FALSE(boost::filesystem::exists(g_path_local / game.FolderName())); + EXPECT_FALSE(boost::filesystem::exists(LootPaths::getLootDataPath() / game.FolderName())); } TEST_P(GameTest, initShouldCreateAGameFolderIfTheCreateFolderArgumentIsTrue) { Game game = Game(GetParam()).SetGamePath(dataPath.parent_path()); - ASSERT_FALSE(boost::filesystem::exists(g_path_local / game.FolderName())); + ASSERT_FALSE(boost::filesystem::exists(LootPaths::getLootDataPath() / game.FolderName())); EXPECT_NO_THROW(game.Init(true, localPath)); - EXPECT_TRUE(boost::filesystem::exists(g_path_local / game.FolderName())); + EXPECT_TRUE(boost::filesystem::exists(LootPaths::getLootDataPath() / game.FolderName())); } #else TEST_P(GameTest, initShouldNotThrowOnWindowsIfLocalPathIsNotGiven) { diff --git a/src/tests/backend/helpers/version_test.h b/src/tests/backend/helpers/version_test.h index 6f540899..5ce5a158 100644 --- a/src/tests/backend/helpers/version_test.h +++ b/src/tests/backend/helpers/version_test.h @@ -25,7 +25,6 @@ along with LOOT. If not, see #ifndef LOOT_TEST_BACKEND_HELPERS_VERSION #define LOOT_TEST_BACKEND_HELPERS_VERSION -#include "backend/globals.h" #include "backend/helpers/version.h" #include @@ -37,10 +36,10 @@ namespace loot { // Use the API DLL built. Version version(boost::filesystem::path("loot_api.dll")); std::string expected( - std::to_string(g_version_major) + "." + - std::to_string(g_version_minor) + "." + - std::to_string(g_version_patch) + ".0" - ); + std::to_string(LootVersion::major) + "." + + std::to_string(LootVersion::minor) + "." + + std::to_string(LootVersion::patch) + ".0" + ); EXPECT_EQ(expected, version.AsString()); } #endif diff --git a/src/tests/backend/masterlist_test.h b/src/tests/backend/masterlist_test.h index a663ac51..54519c0c 100644 --- a/src/tests/backend/masterlist_test.h +++ b/src/tests/backend/masterlist_test.h @@ -26,6 +26,7 @@ along with LOOT. If not, see #define LOOT_TEST_BACKEND_MASTERLIST #include "backend/masterlist.h" +#include "backend/app/loot_paths.h" #include "tests/base_game_test.h" namespace loot { @@ -43,7 +44,7 @@ namespace loot { ASSERT_FALSE(boost::filesystem::exists(masterlistPath)); ASSERT_FALSE(boost::filesystem::exists(localPath / ".git")); - ASSERT_NO_THROW(boost::filesystem::create_directories(g_path_local / Game(GetParam()).FolderName())); + ASSERT_NO_THROW(boost::filesystem::create_directories(LootPaths::getLootDataPath() / Game(GetParam()).FolderName())); } void TearDown() { @@ -52,8 +53,8 @@ namespace loot { ASSERT_NO_THROW(boost::filesystem::remove(masterlistPath)); ASSERT_NO_THROW(boost::filesystem::remove_all(localPath / ".git")); - ASSERT_NO_THROW(boost::filesystem::remove(g_path_local / Game(GetParam()).FolderName() / "masterlist.yaml")); - ASSERT_NO_THROW(boost::filesystem::remove_all(g_path_local / Game(GetParam()).FolderName() / ".git")); + ASSERT_NO_THROW(boost::filesystem::remove(LootPaths::getLootDataPath() / Game(GetParam()).FolderName() / "masterlist.yaml")); + ASSERT_NO_THROW(boost::filesystem::remove_all(LootPaths::getLootDataPath() / Game(GetParam()).FolderName() / ".git")); } const std::string repoUrl; diff --git a/src/tests/main.cpp b/src/tests/main.cpp index 2ba489de..9de3a2c4 100644 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -41,6 +41,7 @@ #include "api/loot_update_masterlist_test.h" #include "api/loot_write_minimal_list_test.h" #include "api/test_api.h" +#include "backend/app/loot_paths_test.h" #include "backend/app/loot_settings_test.h" #include "backend/app/loot_state_test.h" #include "backend/game/game_test.h" diff --git a/src/validator/main.cpp b/src/validator/main.cpp index f3337598..b1df79d4 100644 --- a/src/validator/main.cpp +++ b/src/validator/main.cpp @@ -27,7 +27,7 @@ #define BOOST_NO_CXX11_SCOPED_ENUMS #endif -#include "backend/globals.h" +#include "backend/app/loot_version.h" #include "backend/metadata_list.h" #include @@ -54,9 +54,9 @@ int main(int argc, char **argv) { // Print version info if -v or --version are given. if ((strcmp(argv[1], "-v") == 0) || (strcmp(argv[1], "--version") == 0)) { std::cout << std::endl << "LOOT Metadata Validator" << std::endl - << "v" << loot::g_version_major << "." << loot::g_version_minor - << "." << loot::g_version_patch << std::endl - << "build revision " << loot::g_build_revision << std::endl << std::endl; + << "v" << loot::LootVersion::major << "." << loot::LootVersion::minor + << "." << loot::LootVersion::patch << std::endl + << "build revision " << loot::LootVersion::revision << std::endl << std::endl; return 0; }