1
0
mirror of synced 2025-01-11 05:42:15 +01:00

feat: Added system to handle version migrations

This commit is contained in:
WerWolv 2024-12-26 14:00:50 +01:00
parent 9ce64ec6e1
commit 43c88a2fab
18 changed files with 178 additions and 31 deletions

View File

@ -38,6 +38,7 @@ set(LIBIMHEX_SOURCES
source/helpers/debugging.cpp source/helpers/debugging.cpp
source/helpers/default_paths.cpp source/helpers/default_paths.cpp
source/helpers/imgui_hooks.cpp source/helpers/imgui_hooks.cpp
source/helpers/semantic_version.cpp
source/test/tests.cpp source/test/tests.cpp

View File

@ -217,6 +217,7 @@ namespace hex {
EVENT_DEF(EventOSThemeChanged); EVENT_DEF(EventOSThemeChanged);
EVENT_DEF(EventDPIChanged, float, float); EVENT_DEF(EventDPIChanged, float, float);
EVENT_DEF(EventWindowFocused, bool); EVENT_DEF(EventWindowFocused, bool);
EVENT_DEF(EventImHexUpdated, SemanticVersion, SemanticVersion);
/** /**
* @brief Called when the provider is created. * @brief Called when the provider is created.

View File

@ -2,6 +2,7 @@
#include <hex.hpp> #include <hex.hpp>
#include <hex/api/localization_manager.hpp> #include <hex/api/localization_manager.hpp>
#include <hex/helpers/semantic_version.hpp>
#include <functional> #include <functional>
#include <optional> #include <optional>
@ -618,7 +619,7 @@ namespace hex {
* @brief Gets the current ImHex version * @brief Gets the current ImHex version
* @return ImHex version * @return ImHex version
*/ */
std::string getImHexVersion(bool withBuildType = true); SemanticVersion getImHexVersion();
/** /**
* @brief Gets the current git commit hash * @brief Gets the current git commit hash
@ -695,6 +696,13 @@ namespace hex {
*/ */
void* getLibImHexModuleHandle(); void* getLibImHexModuleHandle();
/**
* Adds a new migration routine that will be executed when upgrading from a lower version than specified in migrationVersion
* @param migrationVersion Upgrade point version
* @param function Function to run
*/
void addMigrationRoutine(SemanticVersion migrationVersion, std::function<void()> function);
} }
/** /**

View File

@ -0,0 +1,36 @@
#pragma once
#include <hex.hpp>
#include <compare>
#include <string>
#include <vector>
namespace hex {
class SemanticVersion {
public:
SemanticVersion() = default;
SemanticVersion(std::string version);
SemanticVersion(std::string_view version);
SemanticVersion(const char *version);
std::strong_ordering operator<=>(const SemanticVersion &) const;
bool operator==(const SemanticVersion &other) const;
u32 major() const;
u32 minor() const;
u32 patch() const;
bool nightly() const;
const std::string& buildType() const;
bool isValid() const;
std::string get(bool withBuildType = true) const;
private:
std::vector<std::string> m_parts;
std::string m_buildType;
};
}

View File

@ -630,7 +630,7 @@ namespace hex {
} }
runtime.addDefine("__IMHEX__"); runtime.addDefine("__IMHEX__");
runtime.addDefine("__IMHEX_VERSION__", ImHexApi::System::getImHexVersion()); runtime.addDefine("__IMHEX_VERSION__", ImHexApi::System::getImHexVersion().get());
} }
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) { void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {

View File

@ -645,6 +645,14 @@ namespace hex {
return hex::getContainingModule(reinterpret_cast<void*>(&getLibImHexModuleHandle)); return hex::getContainingModule(reinterpret_cast<void*>(&getLibImHexModuleHandle));
} }
void addMigrationRoutine(SemanticVersion migrationVersion, std::function<void()> function) {
EventImHexUpdated::subscribe([migrationVersion, function](const SemanticVersion &oldVersion, const SemanticVersion &newVersion) {
if (oldVersion < migrationVersion && newVersion >= migrationVersion) {
function();
}
});
}
const std::map<std::string, std::string>& getInitArguments() { const std::map<std::string, std::string>& getInitArguments() {
return *impl::s_initArguments; return *impl::s_initArguments;
@ -794,16 +802,11 @@ namespace hex {
return { { name, version } }; return { { name, version } };
} }
std::string getImHexVersion(bool withBuildType) { SemanticVersion getImHexVersion() {
#if defined IMHEX_VERSION #if defined IMHEX_VERSION
if (withBuildType) { return SemanticVersion(IMHEX_VERSION);
return IMHEX_VERSION;
} else {
auto version = std::string(IMHEX_VERSION);
return version.substr(0, version.find('-'));
}
#else #else
return "Unknown"; return {};
#endif #endif
} }
@ -837,7 +840,7 @@ namespace hex {
} }
bool isNightlyBuild() { bool isNightlyBuild() {
return getImHexVersion(false).ends_with("WIP"); return getImHexVersion().nightly();
} }
bool updateImHex(UpdateType updateType) { bool updateImHex(UpdateType updateType) {

View File

@ -129,7 +129,7 @@ namespace hex {
const auto requestedVersion = getCompatibleVersion(); const auto requestedVersion = getCompatibleVersion();
const auto imhexVersion = ImHexApi::System::getImHexVersion(); const auto imhexVersion = ImHexApi::System::getImHexVersion().get();
if (!imhexVersion.starts_with(requestedVersion)) { if (!imhexVersion.starts_with(requestedVersion)) {
if (requestedVersion.empty()) { if (requestedVersion.empty()) {
log::warn("Plugin '{}' did not specify a compatible version, assuming it is compatible with the current version of ImHex.", wolv::util::toUTF8String(m_path.filename())); log::warn("Plugin '{}' did not specify a compatible version, assuming it is compatible with the current version of ImHex.", wolv::util::toUTF8String(m_path.filename()));

View File

@ -0,0 +1,96 @@
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/semantic_version.hpp>
#include <wolv/utils/string.hpp>
namespace hex {
SemanticVersion::SemanticVersion(const char *version) : SemanticVersion(std::string(version)) {
}
SemanticVersion::SemanticVersion(std::string_view version) : SemanticVersion(std::string(version.begin(), version.end())) {
}
SemanticVersion::SemanticVersion(std::string version) {
if (version.empty())
return;
if (version.starts_with("v"))
version = version.substr(1);
m_parts = wolv::util::splitString(version, ".");
if (m_parts.size() != 3 && m_parts.size() != 4) {
m_parts.clear();
return;
}
if (m_parts.back().contains("-")) {
auto buildTypeParts = wolv::util::splitString(m_parts.back(), "-");
if (buildTypeParts.size() != 2) {
m_parts.clear();
return;
}
m_parts.back() = buildTypeParts[0];
m_buildType = buildTypeParts[1];
}
}
u32 SemanticVersion::major() const {
return std::stoul(m_parts[0]);
}
u32 SemanticVersion::minor() const {
return std::stoul(m_parts[1]);
}
u32 SemanticVersion::patch() const {
return std::stoul(m_parts[2]);
}
bool SemanticVersion::nightly() const {
return m_parts.size() == 4 && m_parts[3] == "WIP";
}
const std::string& SemanticVersion::buildType() const {
return m_buildType;
}
bool SemanticVersion::isValid() const {
return !m_parts.empty();
}
bool SemanticVersion::operator==(const SemanticVersion& other) const {
return this->m_parts == other.m_parts;
}
std::strong_ordering SemanticVersion::operator<=>(const SemanticVersion &other) const {
if (*this == other)
return std::strong_ordering::equivalent;
if (this->major() > other.major())
return std::strong_ordering::greater;
if (this->minor() > other.minor())
return std::strong_ordering::greater;
if (this->patch() > other.patch())
return std::strong_ordering::greater;
if (!this->nightly() && other.nightly())
return std::strong_ordering::greater;
return std::strong_ordering::less;
}
std::string SemanticVersion::get(bool withBuildType) const {
auto result = wolv::util::combineStrings(m_parts, ".");
if (withBuildType && !m_buildType.empty())
result += hex::format("-{}", m_buildType);
return result;
}
}

View File

@ -331,9 +331,9 @@ namespace hex::init {
// Draw version information // Draw version information
// In debug builds, also display the current commit hash and branch // In debug builds, also display the current commit hash and branch
#if defined(DEBUG) #if defined(DEBUG)
const static auto VersionInfo = hex::format("{0} : {1}@{2}", ImHexApi::System::getImHexVersion(), ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash()); const static auto VersionInfo = hex::format("{0} : {1}@{2}", ImHexApi::System::getImHexVersion().get(), ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash());
#else #else
const static auto VersionInfo = hex::format("{0}", ImHexApi::System::getImHexVersion()); const static auto VersionInfo = hex::format("{0}", ImHexApi::System::getImHexVersion().get());
#endif #endif
drawList->AddText(ImVec2((this->m_splashBackgroundTexture.getSize().x - ImGui::CalcTextSize(VersionInfo.c_str()).x) / 2, 105), ImColor(0xFF, 0xFF, 0xFF, 0xFF), VersionInfo.c_str()); drawList->AddText(ImVec2((this->m_splashBackgroundTexture.getSize().x - ImGui::CalcTextSize(VersionInfo.c_str()).x) / 2, 105), ImColor(0xFF, 0xFF, 0xFF, 0xFF), VersionInfo.c_str());

View File

@ -40,7 +40,7 @@ int main(int argc, char **argv) {
} }
// Log some system information to aid debugging when users share their logs // Log some system information to aid debugging when users share their logs
log::info("Welcome to ImHex {}!", ImHexApi::System::getImHexVersion()); log::info("Welcome to ImHex {}!", ImHexApi::System::getImHexVersion().get());
log::info("Compiled using commit {}@{}", ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash()); log::info("Compiled using commit {}@{}", ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash());
log::info("Running on {} {} ({})", ImHexApi::System::getOSName(), ImHexApi::System::getOSVersion(), ImHexApi::System::getArchitecture()); log::info("Running on {} {} ({})", ImHexApi::System::getOSName(), ImHexApi::System::getOSVersion(), ImHexApi::System::getArchitecture());
#if defined(OS_LINUX) #if defined(OS_LINUX)

View File

@ -31,7 +31,7 @@ namespace hex::plugin::builtin {
std::ignore = args; std::ignore = args;
hex::log::print(std::string(romfs::get("logo.ans").string()), hex::log::print(std::string(romfs::get("logo.ans").string()),
ImHexApi::System::getImHexVersion(), ImHexApi::System::getImHexVersion().get(),
ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash(), ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash(),
__DATE__, __TIME__, __DATE__, __TIME__,
ImHexApi::System::isPortableVersion() ? "Portable" : "Installed"); ImHexApi::System::isPortableVersion() ? "Portable" : "Installed");

View File

@ -18,7 +18,7 @@ namespace hex::plugin::builtin {
nlohmann::json result; nlohmann::json result;
result["build"] = { result["build"] = {
{ "version", ImHexApi::System::getImHexVersion() }, { "version", ImHexApi::System::getImHexVersion().get() },
{ "commit", ImHexApi::System::getCommitHash(true) }, { "commit", ImHexApi::System::getCommitHash(true) },
{ "branch", ImHexApi::System::getCommitBranch() } { "branch", ImHexApi::System::getCommitBranch() }
}; };

View File

@ -226,11 +226,15 @@ namespace hex::plugin::builtin {
}); });
EventWindowInitialized::subscribe([] { EventWindowInitialized::subscribe([] {
if (ContentRegistry::Settings::read<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", "") == "") { const auto currVersion = ImHexApi::System::getImHexVersion();
const auto prevLaunchVersion = ContentRegistry::Settings::read<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", "");
if (prevLaunchVersion == "") {
EventFirstLaunch::post(); EventFirstLaunch::post();
} }
ContentRegistry::Settings::write<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", ImHexApi::System::getImHexVersion()); EventImHexUpdated::post(SemanticVersion(prevLaunchVersion), currVersion);
ContentRegistry::Settings::write<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", currVersion.get(false));
}); });
EventWindowDeinitializing::subscribe([](GLFWwindow *window) { EventWindowDeinitializing::subscribe([](GLFWwindow *window) {

View File

@ -39,9 +39,7 @@ namespace hex::plugin::builtin {
return false; return false;
// Convert the current version string to a format that can be compared to the latest release // Convert the current version string to a format that can be compared to the latest release
auto versionString = ImHexApi::System::getImHexVersion(); auto currVersion = "v" + ImHexApi::System::getImHexVersion().get(false);
size_t versionLength = std::min(versionString.find_first_of('-'), versionString.length());
auto currVersion = "v" + versionString.substr(0, versionLength);
// Get the latest release version string // Get the latest release version string
auto latestVersion = releases["tag_name"].get<std::string_view>(); auto latestVersion = releases["tag_name"].get<std::string_view>();
@ -59,7 +57,7 @@ namespace hex::plugin::builtin {
ContentRegistry::Settings::write<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", uuid); ContentRegistry::Settings::write<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", uuid);
} }
TaskManager::createBackgroundTask("hex.builtin.task.sending_statistics"_lang, [uuid, versionString](auto&) { TaskManager::createBackgroundTask("hex.builtin.task.sending_statistics"_lang, [uuid](auto&) {
// To avoid potentially flooding our database with lots of dead users // To avoid potentially flooding our database with lots of dead users
// from people just visiting the website, don't send telemetry data from // from people just visiting the website, don't send telemetry data from
// the web version // the web version
@ -71,7 +69,7 @@ namespace hex::plugin::builtin {
nlohmann::json telemetry = { nlohmann::json telemetry = {
{ "uuid", uuid }, { "uuid", uuid },
{ "format_version", "1" }, { "format_version", "1" },
{ "imhex_version", versionString }, { "imhex_version", ImHexApi::System::getImHexVersion().get(false) },
{ "imhex_commit", fmt::format("{}@{}", ImHexApi::System::getCommitHash(true), ImHexApi::System::getCommitBranch()) }, { "imhex_commit", fmt::format("{}@{}", ImHexApi::System::getCommitHash(true), ImHexApi::System::getCommitBranch()) },
{ "install_type", ImHexApi::System::isPortableVersion() ? "Portable" : "Installed" }, { "install_type", ImHexApi::System::isPortableVersion() ? "Portable" : "Installed" },
{ "os", ImHexApi::System::getOSName() }, { "os", ImHexApi::System::getOSName() },

View File

@ -298,7 +298,7 @@ namespace hex::plugin::builtin {
ImGui::TextUnformatted("hex.builtin.oobe.server_contact.data_collected.version"_lang); ImGui::TextUnformatted("hex.builtin.oobe.server_contact.data_collected.version"_lang);
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGuiExt::TextFormattedWrapped("{}\n{}@{}\n{}", ImGuiExt::TextFormattedWrapped("{}\n{}@{}\n{}",
ImHexApi::System::getImHexVersion(), ImHexApi::System::getImHexVersion().get(),
ImHexApi::System::getCommitHash(true), ImHexApi::System::getCommitHash(true),
ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitBranch(),
ImHexApi::System::isPortableVersion() ? "Portable" : "Installed" ImHexApi::System::isPortableVersion() ? "Portable" : "Installed"

View File

@ -158,7 +158,7 @@ namespace hex::plugin::builtin {
} }
{ {
const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, ImHexApi::System::getImHexVersion()); const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, ImHexApi::System::getImHexVersion().get(false));
tar.writeString(MetadataPath, metadataContent); tar.writeString(MetadataPath, metadataContent);
} }

View File

@ -193,7 +193,7 @@ namespace hex::plugin::builtin {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
{ {
// Draw basic information about ImHex and its version // Draw basic information about ImHex and its version
ImGuiExt::TextFormatted("ImHex Hex Editor v{} by WerWolv", ImHexApi::System::getImHexVersion()); ImGuiExt::TextFormatted("ImHex Hex Editor v{} by WerWolv", ImHexApi::System::getImHexVersion().get());
ImGui::Indent(25_scaled); ImGui::Indent(25_scaled);
ImGuiExt::TextFormatted("Powered by Dear ImGui v{}", ImGui::GetVersion()); ImGuiExt::TextFormatted("Powered by Dear ImGui v{}", ImGui::GetVersion());
ImGui::Unindent(25_scaled); ImGui::Unindent(25_scaled);
@ -582,9 +582,9 @@ namespace hex::plugin::builtin {
static ReleaseNotes notes; static ReleaseNotes notes;
// Set up the request to get the release notes the first time the page is opened // Set up the request to get the release notes the first time the page is opened
const static auto ImHexVersionString = ImHexApi::System::getImHexVersion(false); const static auto ImHexVersion = ImHexApi::System::getImHexVersion();
AT_FIRST_TIME { AT_FIRST_TIME {
static HttpRequest request("GET", GitHubApiURL + std::string("/releases/") + (ImHexVersionString.ends_with(".WIP") ? "latest" : ( "tags/v" + ImHexVersionString))); static HttpRequest request("GET", GitHubApiURL + std::string("/releases/") + (ImHexVersion.nightly() ? "latest" : ( "tags/v" + ImHexVersion.get(false))));
m_releaseNoteRequest = request.execute(); m_releaseNoteRequest = request.execute();
}; };

View File

@ -57,7 +57,7 @@ namespace hex::plugin::builtin {
// Force update all installed items after an update so that there's no old and incompatible versions around anymore // Force update all installed items after an update so that there's no old and incompatible versions around anymore
{ {
const auto prevUpdateVersion = ContentRegistry::Settings::read<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", ""); const auto prevUpdateVersion = ContentRegistry::Settings::read<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", "");
if (prevUpdateVersion != ImHexApi::System::getImHexVersion()) { if (SemanticVersion(prevUpdateVersion) != ImHexApi::System::getImHexVersion()) {
updateAll(); updateAll();
} }
} }
@ -359,7 +359,7 @@ namespace hex::plugin::builtin {
} }
TaskManager::doLater([] { TaskManager::doLater([] {
ContentRegistry::Settings::write<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", ImHexApi::System::getImHexVersion()); ContentRegistry::Settings::write<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", ImHexApi::System::getImHexVersion().get(false));
}); });
}); });
} }