diff --git a/hyprpm/CMakeLists.txt b/hyprpm/CMakeLists.txt index f2e0b223630..5dea92bbd45 100644 --- a/hyprpm/CMakeLists.txt +++ b/hyprpm/CMakeLists.txt @@ -13,7 +13,7 @@ pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0 find_package(glaze QUIET) if (NOT glaze_FOUND) - set(GLAZE_VERSION v5.1.1) + set(GLAZE_VERSION v6.1.0) message(STATUS "glaze dependency not found, retrieving ${GLAZE_VERSION} with FetchContent") include(FetchContent) FetchContent_Declare( diff --git a/hyprpm/src/core/DataState.cpp b/hyprpm/src/core/DataState.cpp index 131146a169d..42f1d428922 100644 --- a/hyprpm/src/core/DataState.cpp +++ b/hyprpm/src/core/DataState.cpp @@ -181,7 +181,7 @@ void DataState::updateGlobalState(const SGlobalState& state) { // clang-format off auto DATA = toml::table{ {"state", toml::table{ - {"hash", state.headersHashCompiled}, + {"hash", state.headersAbiCompiled}, {"dont_warn_install", state.dontWarnInstall} }} }; @@ -206,8 +206,8 @@ SGlobalState DataState::getGlobalState() { auto DATA = toml::parse_file(stateFile.c_str()); SGlobalState state; - state.headersHashCompiled = DATA["state"]["hash"].value_or(""); - state.dontWarnInstall = DATA["state"]["dont_warn_install"].value_or(false); + state.headersAbiCompiled = DATA["state"]["hash"].value_or(""); + state.dontWarnInstall = DATA["state"]["dont_warn_install"].value_or(false); return state; } diff --git a/hyprpm/src/core/DataState.hpp b/hyprpm/src/core/DataState.hpp index c35ded06474..dfab535a7f3 100644 --- a/hyprpm/src/core/DataState.hpp +++ b/hyprpm/src/core/DataState.hpp @@ -5,8 +5,8 @@ #include "Plugin.hpp" struct SGlobalState { - std::string headersHashCompiled = ""; - bool dontWarnInstall = false; + std::string headersAbiCompiled = ""; + bool dontWarnInstall = false; }; namespace DataState { diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 9dea8bf40bb..aa630943cce 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -78,40 +78,30 @@ SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) { else onceInstalled = true; - const auto HLVERCALL = running ? NHyprlandSocket::send("/version") : execAndGet("Hyprland --version"); - if (m_bVerbose) - std::println("{}", verboseString("{} version returned: {}", running ? "running" : "installed", HLVERCALL)); + const auto HLVERCALL = running ? NHyprlandSocket::send("j/version") : execAndGet("Hyprland --version-json"); + + auto jsonQuery = glz::read_json(HLVERCALL); - if (!HLVERCALL.contains("Tag:")) { - std::println(stderr, "\n{}", failureString("You don't seem to be running Hyprland.")); + if (!jsonQuery) { + std::println("{}", failureString("failed to get the current hyprland version. Are you running hyprland?")); return SHyprlandVersion{}; } - std::string hlcommit = HLVERCALL.substr(HLVERCALL.find("at commit") + 10); - hlcommit = hlcommit.substr(0, hlcommit.find_first_of(' ')); - - std::string hlbranch = HLVERCALL.substr(HLVERCALL.find("from branch") + 12); - hlbranch = hlbranch.substr(0, hlbranch.find(" at commit ")); - - std::string hldate = HLVERCALL.substr(HLVERCALL.find("Date: ") + 6); - hldate = hldate.substr(0, hldate.find('\n')); - - std::string hlcommits; + auto hlbranch = (*jsonQuery)["branch"].get_string(); + auto hlcommit = (*jsonQuery)["commit"].get_string(); + auto abiHash = (*jsonQuery)["abiHash"].get_string(); + auto hldate = (*jsonQuery)["commit_date"].get_string(); + auto hlcommits = (*jsonQuery)["commits"].get_string(); - if (HLVERCALL.contains("commits:")) { - hlcommits = HLVERCALL.substr(HLVERCALL.find("commits:") + 9); - hlcommits = hlcommits.substr(0, hlcommits.find(' ')); - } - - int commits = 0; + size_t commits = 0; try { - commits = std::stoi(hlcommits); + commits = std::stoull(hlcommits); } catch (...) { ; } if (m_bVerbose) std::println("{}", verboseString("parsed commit {} at branch {} on {}, commits {}", hlcommit, hlbranch, hldate, commits)); - auto ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits}; + auto ver = SHyprlandVersion{hlbranch, hlcommit, hldate, abiHash, commits}; if (running) verRunning = ver; @@ -161,7 +151,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& DataState::updateGlobalState(GLOBALSTATE); } - if (GLOBALSTATE.headersHashCompiled.empty()) { + if (GLOBALSTATE.headersAbiCompiled.empty()) { std::println("\n{}", failureString("Cannot find headers in the global state. Try running hyprpm update first.")); return false; } @@ -444,6 +434,12 @@ eHeadersErrors CPluginManager::headersValid() { if (hash != HLVER.hash) return HEADERS_MISMATCHED; + // check ABI hash too + const auto GLOBALSTATE = DataState::getGlobalState(); + + if (GLOBALSTATE.headersAbiCompiled != HLVER.abiHash) + return HEADERS_ABI_MISMATCH; + return HEADERS_OK; } @@ -595,8 +591,8 @@ bool CPluginManager::updateHeaders(bool force) { progress.m_szCurrentMessage = "Done!"; progress.print(); - auto GLOBALSTATE = DataState::getGlobalState(); - GLOBALSTATE.headersHashCompiled = HLVER.hash; + auto GLOBALSTATE = DataState::getGlobalState(); + GLOBALSTATE.headersAbiCompiled = HLVER.abiHash; DataState::updateGlobalState(GLOBALSTATE); std::print("\n"); @@ -787,8 +783,8 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { progress.m_szCurrentMessage = "Updating global state..."; progress.print(); - auto GLOBALSTATE = DataState::getGlobalState(); - GLOBALSTATE.headersHashCompiled = HLVER.hash; + auto GLOBALSTATE = DataState::getGlobalState(); + GLOBALSTATE.headersAbiCompiled = HLVER.abiHash; DataState::updateGlobalState(GLOBALSTATE); progress.m_iSteps++; @@ -828,7 +824,7 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload) } const auto HYPRPMPATH = DataState::getDataStatePath(); - const auto json = glz::read_json(NHyprlandSocket::send("j/plugins list")); + const auto json = glz::read_json(NHyprlandSocket::send("j/plugins list")); if (!json) { std::println(stderr, "PluginManager: couldn't parse plugin list output"); return LOADSTATE_FAIL; @@ -913,9 +909,9 @@ bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) { auto state = DataState::getGlobalState(); auto HLVER = getHyprlandVersion(true); - if (state.headersHashCompiled != HLVER.hash) { + if (state.headersAbiCompiled != HLVER.hash) { if (load) - std::println("{}", infoString("Running Hyprland version ({}) differs from plugin state ({}), please restart Hyprland.", HLVER.hash, state.headersHashCompiled)); + std::println("{}", infoString("Running Hyprland version ({}) differs from plugin state ({}), please restart Hyprland.", HLVER.hash, state.headersAbiCompiled)); return false; } @@ -956,6 +952,7 @@ std::string CPluginManager::headerError(const eHeadersErrors err) { case HEADERS_MISMATCHED: return failureString("Headers version mismatch. Please run hyprpm update to fix those.\n"); case HEADERS_NOT_HYPRLAND: return failureString("It doesn't seem you are running on hyprland.\n"); case HEADERS_MISSING: return failureString("Headers missing. Please run hyprpm update to fix those.\n"); + case HEADERS_ABI_MISMATCH: return failureString("ABI is mismatched. Please run hyprpm update to fix that.\n"); case HEADERS_DUPLICATED: { return failureString("Headers duplicated!!! This is a very bad sign.\n" "This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" diff --git a/hyprpm/src/core/PluginManager.hpp b/hyprpm/src/core/PluginManager.hpp index e0ed1203cf5..2425f5ec92e 100644 --- a/hyprpm/src/core/PluginManager.hpp +++ b/hyprpm/src/core/PluginManager.hpp @@ -11,6 +11,7 @@ enum eHeadersErrors { HEADERS_MISSING, HEADERS_CORRUPTED, HEADERS_MISMATCHED, + HEADERS_ABI_MISMATCH, HEADERS_DUPLICATED }; @@ -36,6 +37,7 @@ struct SHyprlandVersion { std::string branch; std::string hash; std::string date; + std::string abiHash; int commits = 0; }; diff --git a/hyprpm/src/main.cpp b/hyprpm/src/main.cpp index 777d1d46ec0..817049ff5b1 100644 --- a/hyprpm/src/main.cpp +++ b/hyprpm/src/main.cpp @@ -106,7 +106,7 @@ int main(int argc, char** argv, char** envp) { const auto HLVER = g_pPluginManager->getHyprlandVersion(); auto GLOBALSTATE = DataState::getGlobalState(); - if (GLOBALSTATE.headersHashCompiled != HLVER.hash) { + if (GLOBALSTATE.headersAbiCompiled != HLVER.abiHash) { std::println(stderr, "{}", failureString("Headers outdated, please run hyprpm update.")); return 1; } @@ -137,7 +137,7 @@ int main(int argc, char** argv, char** envp) { if (headers) { const auto HLVER = g_pPluginManager->getHyprlandVersion(false); auto GLOBALSTATE = DataState::getGlobalState(); - const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled; + const auto COMPILEDOUTDATED = HLVER.abiHash != GLOBALSTATE.headersAbiCompiled; bool ret1 = g_pPluginManager->updatePlugins(!headersValid || force || COMPILEDOUTDATED); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index dc5be6ce957..7370c60e7c8 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1063,6 +1063,9 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { result += "\n"; result += getBuiltSystemLibraryNames(); result += "\n"; + result += "Version ABI string: "; + result += __hyprland_api_get_hash(); + result += "\n"; #if (!ISDEBUG && !defined(NO_XWAYLAND)) result += "no flags were set\n"; @@ -1097,10 +1100,12 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { "systemHyprutils": "{}", "systemHyprcursor": "{}", "systemHyprgraphics": "{}", + "abiHash": "{}", "flags": [)#", GIT_BRANCH, GIT_COMMIT_HASH, HYPRLAND_VERSION, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION, HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION, getSystemLibraryVersion("aquamarine"), - getSystemLibraryVersion("hyprlang"), getSystemLibraryVersion("hyprutils"), getSystemLibraryVersion("hyprcursor"), getSystemLibraryVersion("hyprgraphics")); + getSystemLibraryVersion("hyprlang"), getSystemLibraryVersion("hyprutils"), getSystemLibraryVersion("hyprcursor"), getSystemLibraryVersion("hyprgraphics"), + __hyprland_api_get_hash()); #if ISDEBUG result += "\"debug\","; diff --git a/src/main.cpp b/src/main.cpp index 2574d82228b..3e21c965138 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,7 +25,7 @@ using namespace Hyprutils::Memory; static void help() { std::println("usage: Hyprland [arg [...]].\n"); - std::println(R"(Arguments: + std::println(R"#(Arguments: --help -h - Show this message again --config FILE -c FILE - Specify config file to use --socket NAME - Sets the Wayland socket name (for Wayland socket handover) @@ -33,7 +33,8 @@ static void help() { --systeminfo - Prints system infos --i-am-really-stupid - Omits root user privileges check (why would you do that?) --verify-config - Do not run Hyprland, only print if the config has any errors - --version -v - Print this binary's version)"); + --version -v - Print this binary's version + --version-json - Print this binary's version as json)#"); } static void reapZombieChildrenAutomatically() { @@ -142,6 +143,9 @@ int main(int argc, char** argv) { } else if (value == "-v" || value == "--version") { std::println("{}", versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "")); return 0; + } else if (value == "--version-json") { + std::println("{}", versionRequest(eHyprCtlOutputFormat::FORMAT_JSON, "")); + return 0; } else if (value == "--systeminfo") { std::println("{}", systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "")); return 0;