SaveTool: separate update checking mechanism.
THIS IS BROKEN, ONLY BUILD THIS COMMIT FOR DEBUGGING PURPOSES!
This commit is contained in:
parent
07cbaefeac
commit
389dabfc77
8 changed files with 309 additions and 153 deletions
|
@ -97,7 +97,10 @@ add_executable(MassBuilderSaveTool WIN32
|
|||
Maps/WeaponTypes.hpp
|
||||
ToastQueue/ToastQueue.h
|
||||
ToastQueue/ToastQueue.cpp
|
||||
UpdateChecker/UpdateChecker.h
|
||||
UpdateChecker/UpdateChecker.cpp
|
||||
Utilities/Crc32.h
|
||||
Version/Version.h
|
||||
FontAwesome/IconsFontAwesome5.h
|
||||
FontAwesome/IconsFontAwesome5Brands.h
|
||||
${SAVETOOL_RC_FILE}
|
||||
|
|
|
@ -29,8 +29,7 @@
|
|||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include <wtypesbase.h>
|
||||
#include <shellapi.h>
|
||||
#include <wtsapi32.h>
|
||||
|
||||
|
@ -131,8 +130,6 @@ SaveTool::SaveTool(const Arguments& arguments):
|
|||
|
||||
initialiseConfiguration();
|
||||
|
||||
LOG_INFO("Initialising update checker.");
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
if(conf().checkUpdatesOnStartup()) {
|
||||
_queue.addToast(Toast::Type::Default, "Checking for updates..."_s);
|
||||
_updateThread = std::thread{[this]{ checkForUpdates(); }};
|
||||
|
@ -155,9 +152,6 @@ SaveTool::SaveTool(const Arguments& arguments):
|
|||
SaveTool::~SaveTool() {
|
||||
LOG_INFO("Cleaning up.");
|
||||
|
||||
LOG_INFO("Shutting libcurl down.");
|
||||
curl_global_cleanup();
|
||||
|
||||
SDL_RemoveTimer(_gameCheckTimerId);
|
||||
|
||||
LOG_INFO("Saving the configuration.");
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
|
@ -40,6 +41,7 @@
|
|||
#include "../ProfileManager/ProfileManager.h"
|
||||
#include "../MassManager/MassManager.h"
|
||||
#include "../ToastQueue/ToastQueue.h"
|
||||
#include "../UpdateChecker/UpdateChecker.h"
|
||||
|
||||
#ifdef SAVETOOL_DEBUG_BUILD
|
||||
#define tw CORRADE_TWEAKABLE
|
||||
|
@ -83,11 +85,6 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
};
|
||||
void initEvent(SDL_Event& event);
|
||||
|
||||
enum UpdateCheckStatus : std::int32_t {
|
||||
CurlInitFailed = 0,
|
||||
CurlError = 1,
|
||||
CurlTimeout = 2,
|
||||
};
|
||||
void updateCheckEvent(SDL_Event& event);
|
||||
|
||||
enum FileEventType: std::int32_t {
|
||||
|
@ -260,10 +257,8 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
};
|
||||
Containers::StaticArray<2, efsw::WatchID> _watchIDs;
|
||||
|
||||
bool _updateAvailable{false};
|
||||
Containers::String _latestVersion;
|
||||
Containers::String _releaseLink;
|
||||
Containers::String _downloadLink;
|
||||
Containers::Optional<UpdateChecker> _checker{Containers::NullOpt};
|
||||
std::mutex _checkerMutex;
|
||||
|
||||
bool _modifiedBySaveTool{false};
|
||||
bool _jointsDirty{false};
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
#include <SDL_events.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "../Logger/Logger.h"
|
||||
|
||||
#include "SaveTool.h"
|
||||
|
@ -28,108 +26,51 @@ void
|
|||
SaveTool::updateCheckEvent(SDL_Event& event) {
|
||||
_updateThread.join();
|
||||
|
||||
if(event.user.code == CurlInitFailed) {
|
||||
_queue.addToast(Toast::Type::Error, "Couldn't initialise libcurl. Update check aborted."_s);
|
||||
LOG_ERROR("Couldn't initialise libcurl. Update check aborted.");
|
||||
return;
|
||||
}
|
||||
else if(event.user.code == CurlError) {
|
||||
Containers::String error{static_cast<char*>(event.user.data2), CURL_ERROR_SIZE, nullptr};
|
||||
_queue.addToast(Toast::Type::Error, error, std::chrono::milliseconds{5000});
|
||||
_queue.addToast(Toast::Type::Error, static_cast<char*>(event.user.data1),
|
||||
std::chrono::milliseconds{5000});
|
||||
LOG_ERROR_FORMAT("{}: {}", static_cast<char*>(event.user.data1), static_cast<char*>(event.user.data2));
|
||||
return;
|
||||
}
|
||||
else if(event.user.code == CurlTimeout) {
|
||||
_queue.addToast(Toast::Type::Error, "The request timed out."_s);
|
||||
LOG_ERROR("The request timed out.");
|
||||
return;
|
||||
}
|
||||
else if(event.user.code != 200) {
|
||||
_queue.addToast(Toast::Type::Error,
|
||||
Utility::format("The request failed with error code {}.", event.user.code));
|
||||
LOG_ERROR_FORMAT("The request failed with error code {}.", event.user.code);
|
||||
return;
|
||||
}
|
||||
LOG_INFO("in updateCheckEvent().");
|
||||
|
||||
struct Version {
|
||||
explicit Version(Containers::StringView str) {
|
||||
std::size_t start_point = 0;
|
||||
|
||||
if(str[0] == 'v') {
|
||||
start_point++;
|
||||
}
|
||||
|
||||
auto components = Containers::StringView{str.data() + start_point}.split('.');
|
||||
|
||||
major = std::strtol(components[0].data(), nullptr, 10);
|
||||
minor = std::strtol(components[1].data(), nullptr, 10);
|
||||
patch = std::strtol(components[2].data(), nullptr, 10);
|
||||
|
||||
fullVersion = major * 10000 + minor * 100 + patch;
|
||||
|
||||
if(str.hasSuffix("-pre")) {
|
||||
prerelease = true;
|
||||
}
|
||||
}
|
||||
std::int32_t fullVersion;
|
||||
std::int32_t major = 0;
|
||||
std::int32_t minor = 0;
|
||||
std::int32_t patch = 0;
|
||||
bool prerelease = false;
|
||||
|
||||
bool operator==(const Version& other) const {
|
||||
return fullVersion == other.fullVersion && prerelease == other.prerelease;
|
||||
}
|
||||
bool operator>(const Version& other) const {
|
||||
if((fullVersion > other.fullVersion) ||
|
||||
(fullVersion == other.fullVersion && !prerelease && other.prerelease))
|
||||
{
|
||||
return true;
|
||||
switch(static_cast<UpdateChecker::Result>(event.user.code)) {
|
||||
case UpdateChecker::Success:
|
||||
_checkerMutex.lock();
|
||||
if(_checker->updateAvailable()) {
|
||||
using namespace std::chrono_literals;
|
||||
_queue.addToast(Toast::Type::Warning,
|
||||
"Your version is out of date and thus unsupported.\nCheck the settings for more information."_s, 5s);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
explicit operator Containers::String() const {
|
||||
return Utility::format("{}.{}.{}{}", major, minor, patch, prerelease ? "-pre" : "");
|
||||
}
|
||||
};
|
||||
|
||||
static const Version current_ver{SAVETOOL_VERSION};
|
||||
|
||||
auto str = static_cast<char*>(event.user.data1);
|
||||
Containers::String response{str, strlen(str), nullptr};
|
||||
auto components = response.splitOnAnyWithoutEmptyParts("\r\n");
|
||||
|
||||
Version latest_ver{components.front()};
|
||||
|
||||
if(latest_ver > current_ver) {
|
||||
_queue.addToast(Toast::Type::Warning,
|
||||
"Your version is out of date.\nCheck the settings for more information."_s,
|
||||
std::chrono::milliseconds{5000});
|
||||
_updateAvailable = true;
|
||||
_latestVersion = Containers::String{latest_ver};
|
||||
_releaseLink = Utility::format("https://williamjcm.ovh/git/williamjcm/MassBuilderSaveTool/releases/tag/v{}",
|
||||
components.front());
|
||||
_downloadLink = components.back();
|
||||
}
|
||||
else if(latest_ver == current_ver || (current_ver > latest_ver && current_ver.prerelease)) {
|
||||
if(_checker->version() == current_version || (current_version > _checker->version() && current_version.prerelease)) {
|
||||
_queue.addToast(Toast::Type::Success, "The application is already up to date."_s);
|
||||
}
|
||||
else if(current_ver > latest_ver && !current_ver.prerelease) {
|
||||
else if(_checker->version() > current_version && !current_version.prerelease) {
|
||||
_queue.addToast(Toast::Type::Warning,
|
||||
"Your version is more recent than the latest one in the repo. How???"_s);
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
std::size_t
|
||||
writeData(char* ptr, std::size_t size, std::size_t nmemb, Containers::String* buf) {
|
||||
if(!ptr || !buf) return 0;
|
||||
(*buf) = Utility::format("{}{}", *buf, Containers::StringView{ptr, size * nmemb});
|
||||
return size * nmemb;
|
||||
_checkerMutex.unlock();
|
||||
break;
|
||||
case UpdateChecker::HttpError:
|
||||
_checkerMutex.lock();
|
||||
_queue.addToast(Toast::Type::Error, _checker->error());
|
||||
LOG_ERROR(_checker->error());
|
||||
_checkerMutex.unlock();
|
||||
break;
|
||||
case UpdateChecker::CurlInitFailed:
|
||||
_queue.addToast(Toast::Type::Error, "Couldn't initialise libcurl. Update check aborted."_s);
|
||||
LOG_ERROR("Couldn't initialise libcurl. Update check aborted.");
|
||||
break;
|
||||
case UpdateChecker::CurlError:
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
_checkerMutex.lock();
|
||||
_queue.addToast(Toast::Type::Error, _checker->error(), 10s);
|
||||
LOG_ERROR(_checker->error());
|
||||
_checkerMutex.unlock();
|
||||
}
|
||||
break;
|
||||
case UpdateChecker::CurlTimeout:
|
||||
_queue.addToast(Toast::Type::Error, "The request timed out."_s);
|
||||
LOG_ERROR("The request timed out.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -138,43 +79,15 @@ SaveTool::checkForUpdates() {
|
|||
SDL_zero(event);
|
||||
event.type = _updateEventId;
|
||||
|
||||
auto curl = curl_easy_init();
|
||||
if(!curl) {
|
||||
event.user.code = CurlInitFailed;
|
||||
_checkerMutex.lock();
|
||||
|
||||
if(!_checker) {
|
||||
_checker.emplace();
|
||||
}
|
||||
|
||||
if(curl) {
|
||||
Containers::String response_body{Containers::AllocatedInit, ""};
|
||||
Containers::String error_buffer{ValueInit, CURL_ERROR_SIZE * 2};
|
||||
event.user.code = _checker->check();
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "https://williamjcm.ovh/mbst/version");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer.data());
|
||||
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 10000L);
|
||||
|
||||
auto code = curl_easy_perform(curl);
|
||||
|
||||
if(code == CURLE_OK) {
|
||||
long status = 0;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
|
||||
event.user.code = std::int32_t(status);
|
||||
event.user.data1 = response_body.release();
|
||||
}
|
||||
else if(code == CURLE_OPERATION_TIMEDOUT) {
|
||||
event.user.code = CurlTimeout;
|
||||
}
|
||||
else {
|
||||
event.user.code = CurlError;
|
||||
event.user.data1 = const_cast<char*>(curl_easy_strerror(code));
|
||||
event.user.data2 = Containers::String{error_buffer}.release();
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
_checkerMutex.unlock();
|
||||
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
|
|
@ -132,15 +132,16 @@ SaveTool::drawMainMenu() {
|
|||
_updateThread = std::thread{[this]{ checkForUpdates(); }};
|
||||
}
|
||||
|
||||
if(_updateAvailable) {
|
||||
drawAlignedText("Version %s is available.", _latestVersion.data());
|
||||
if(_checker && (_checkerMutex.try_lock() && _checker->updateAvailable())) {
|
||||
drawAlignedText("Version %s is available.", Containers::String{_checker->version()}.data());
|
||||
if(ImGui::Button(ICON_FA_FILE_SIGNATURE " Release notes")) {
|
||||
openUri(_releaseLink);
|
||||
openUri("https://williamjcm.ovh/mbst");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button(ICON_FA_DOWNLOAD " Download now")) {
|
||||
openUri(_downloadLink);
|
||||
openUri(_checker->downloadLink());
|
||||
}
|
||||
_checkerMutex.unlock();
|
||||
}
|
||||
|
||||
if(drawCheckbox("Skip disclaimer", conf().skipDisclaimer())) {
|
||||
|
|
112
src/UpdateChecker/UpdateChecker.cpp
Normal file
112
src/UpdateChecker/UpdateChecker.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021-2023 Guillaume Jacquemin
|
||||
//
|
||||
// This program 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.
|
||||
//
|
||||
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <Corrade/Containers/ScopeGuard.h>
|
||||
#include <Corrade/Containers/String.h>
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
#include <Corrade/Utility/Format.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "../Logger/Logger.h"
|
||||
|
||||
#include "UpdateChecker.h"
|
||||
|
||||
using namespace Corrade;
|
||||
|
||||
UpdateChecker::UpdateChecker() {
|
||||
LOG_INFO("Initialising update checker.");
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
}
|
||||
|
||||
UpdateChecker::~UpdateChecker() {
|
||||
LOG_INFO("Shutting libcurl down.");
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
UpdateChecker::Result
|
||||
UpdateChecker::check() {
|
||||
auto curl = curl_easy_init();
|
||||
if(!curl) {
|
||||
return Result::CurlInitFailed;
|
||||
}
|
||||
|
||||
Containers::ScopeGuard guard(curl, curl_easy_cleanup);
|
||||
|
||||
Containers::String response_body{Containers::AllocatedInit, ""};
|
||||
Containers::String error_buffer{ValueInit, CURL_ERROR_SIZE};
|
||||
static auto write_data = [](char* ptr, std::size_t size, std::size_t nmemb, Containers::String* buf){
|
||||
if(!ptr || !buf) return std::size_t{};
|
||||
(*buf) = Utility::format("{}{}", *buf, Containers::StringView{ptr, size * nmemb});
|
||||
return size * nmemb;
|
||||
};
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "https://williamjcm.ovh/mbst/version");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer.data());
|
||||
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
|
||||
|
||||
auto code = curl_easy_perform(curl);
|
||||
|
||||
if(code == CURLE_OK) {
|
||||
long status = 0;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
|
||||
|
||||
if(status != 200) {
|
||||
_error = Utility::format("The request failed with error code {}.", status);
|
||||
return Result::HttpError;
|
||||
}
|
||||
|
||||
auto parts = response_body.splitOnAnyWithoutEmptyParts("\r\n");
|
||||
|
||||
_foundVersion = Version{parts.front()};
|
||||
_downloadLink = parts.back();
|
||||
LOG_INFO_FORMAT("Found version: {}", Containers::String{_foundVersion});
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
else if(code == CURLE_OPERATION_TIMEDOUT) {
|
||||
return Result::CurlTimeout;
|
||||
}
|
||||
else {
|
||||
_error = Utility::format("{}: {}", curl_easy_strerror(code), error_buffer);
|
||||
return Result::CurlError;
|
||||
}
|
||||
}
|
||||
|
||||
Containers::StringView
|
||||
UpdateChecker::error() const {
|
||||
return _error;
|
||||
}
|
||||
|
||||
bool
|
||||
UpdateChecker::updateAvailable() const {
|
||||
return _foundVersion > current_version;
|
||||
}
|
||||
|
||||
const Version&
|
||||
UpdateChecker::version() const {
|
||||
return _foundVersion;
|
||||
}
|
||||
|
||||
Containers::StringView
|
||||
UpdateChecker::downloadLink() const {
|
||||
return _downloadLink;
|
||||
}
|
49
src/UpdateChecker/UpdateChecker.h
Normal file
49
src/UpdateChecker/UpdateChecker.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021-2023 Guillaume Jacquemin
|
||||
//
|
||||
// This program 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.
|
||||
//
|
||||
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Version/Version.h"
|
||||
|
||||
class UpdateChecker {
|
||||
public:
|
||||
explicit UpdateChecker();
|
||||
~UpdateChecker();
|
||||
|
||||
enum Result: std::int32_t {
|
||||
Success,
|
||||
HttpError,
|
||||
CurlInitFailed,
|
||||
CurlError,
|
||||
CurlTimeout
|
||||
};
|
||||
|
||||
auto check() -> Result;
|
||||
|
||||
auto error() const -> Containers::StringView;
|
||||
|
||||
bool updateAvailable() const;
|
||||
|
||||
auto version() const -> const Version&;
|
||||
|
||||
auto downloadLink() const -> Containers::StringView;
|
||||
|
||||
private:
|
||||
Containers::String _error;
|
||||
|
||||
Version _foundVersion{};
|
||||
Containers::String _downloadLink;
|
||||
};
|
89
src/Version/Version.h
Normal file
89
src/Version/Version.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021-2023 Guillaume Jacquemin
|
||||
//
|
||||
// This program 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.
|
||||
//
|
||||
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <Corrade/Containers/Array.h>
|
||||
#include <Corrade/Containers/String.h>
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
#include <Corrade/Utility/Format.h>
|
||||
|
||||
using namespace Corrade;
|
||||
|
||||
struct Version {
|
||||
explicit Version() = default;
|
||||
|
||||
explicit Version(Containers::StringView str) {
|
||||
std::size_t start_point = 0;
|
||||
|
||||
if(str[0] == 'v') {
|
||||
start_point++;
|
||||
}
|
||||
|
||||
auto components = Containers::StringView{str.data() + start_point}.split('.');
|
||||
|
||||
major = std::strtol(components[0].data(), nullptr, 10);
|
||||
minor = std::strtol(components[1].data(), nullptr, 10);
|
||||
patch = std::strtol(components[2].data(), nullptr, 10);
|
||||
|
||||
fullVersion = major * 10000 + minor * 100 + patch;
|
||||
|
||||
if(str.hasSuffix("-pre")) {
|
||||
prerelease = true;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr explicit Version(long major_, long minor_, long patch_, bool prerelease_):
|
||||
major{major_}, minor{minor_}, patch{patch_}, prerelease{prerelease_},
|
||||
fullVersion{major_ * 10000 + minor_ * 100 + patch_}
|
||||
{
|
||||
//ctor
|
||||
}
|
||||
|
||||
long major = 0;
|
||||
long minor = 0;
|
||||
long patch = 0;
|
||||
bool prerelease = false;
|
||||
long fullVersion = 0;
|
||||
|
||||
bool operator==(const Version& other) const {
|
||||
return fullVersion == other.fullVersion && prerelease == other.prerelease;
|
||||
}
|
||||
|
||||
bool operator>(const Version& other) const {
|
||||
if((fullVersion > other.fullVersion) ||
|
||||
(fullVersion == other.fullVersion && !prerelease && other.prerelease))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
explicit operator Containers::String() const {
|
||||
return Utility::format("{}.{}.{}{}", major, minor, patch, prerelease ? "-pre" : "");
|
||||
}
|
||||
};
|
||||
|
||||
constexpr Version current_version{
|
||||
SAVETOOL_VERSION_MAJOR,
|
||||
SAVETOOL_VERSION_MINOR,
|
||||
SAVETOOL_VERSION_PATCH,
|
||||
SAVETOOL_VERSION_PRERELEASE
|
||||
};
|
Loading…
Reference in a new issue