summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTuur Vanhoutte <4633209+zjeffer@users.noreply.github.com>2024-12-27 15:40:46 +0100
committerGitHub <noreply@github.com>2024-12-27 14:40:46 +0000
commit43ca66779b7d267cc6c52bdea75d3ff8eb60132f (patch)
tree0c4590d7def526cc88d5602f96781755db7e6c45
parente75e2cdac79417ffdbbbe903f72668953483a4e7 (diff)
hyprpm: use glaze to parse hyprctl plugin list (#8812)
* Use std::filesystem::path in hyprpm DataState to avoid concatenating strings with (folder + "/" + file) * Added getPluginStates helper method in DataState * Small clang-tidy improvements
-rw-r--r--.github/actions/setup_base/action.yml9
-rw-r--r--hyprpm/CMakeLists.txt3
-rw-r--r--hyprpm/src/core/DataState.cpp107
-rw-r--r--hyprpm/src/core/DataState.hpp22
-rw-r--r--hyprpm/src/core/PluginManager.cpp48
-rw-r--r--hyprpm/src/meson.build1
-rw-r--r--nix/default.nix4
7 files changed, 97 insertions, 97 deletions
diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml
index c510bb74..6df442b3 100644
--- a/.github/actions/setup_base/action.yml
+++ b/.github/actions/setup_base/action.yml
@@ -63,6 +63,15 @@ runs:
librsvg \
re2
+ - name: Get glaze
+ shell: bash
+ run: |
+ git clone https://github.com/stephenberry/glaze.git
+ cd glaze
+ cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -S . -B ./build
+ cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
+ cmake --install build
+
- name: Get hyprwayland-scanner-git
shell: bash
run: |
diff --git a/hyprpm/CMakeLists.txt b/hyprpm/CMakeLists.txt
index 22cb8caa..8eb325fd 100644
--- a/hyprpm/CMakeLists.txt
+++ b/hyprpm/CMakeLists.txt
@@ -10,10 +10,11 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
set(CMAKE_CXX_STANDARD 23)
pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.2.4)
+find_package(glaze REQUIRED)
add_executable(hyprpm ${SRCFILES})
-target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps)
+target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps glaze::glaze)
# binary
install(TARGETS hyprpm)
diff --git a/hyprpm/src/core/DataState.cpp b/hyprpm/src/core/DataState.cpp
index fb8679d6..55f148a4 100644
--- a/hyprpm/src/core/DataState.cpp
+++ b/hyprpm/src/core/DataState.cpp
@@ -1,11 +1,10 @@
#include "DataState.hpp"
#include <toml++/toml.hpp>
#include <print>
-#include <filesystem>
#include <fstream>
#include "PluginManager.hpp"
-std::string DataState::getDataStatePath() {
+std::filesystem::path DataState::getDataStatePath() {
const auto HOME = getenv("HOME");
if (!HOME) {
std::println(stderr, "DataState: no $HOME");
@@ -16,12 +15,29 @@ std::string DataState::getDataStatePath() {
const auto XDG_DATA_HOME = getenv("XDG_DATA_HOME");
if (XDG_DATA_HOME)
- return std::string{XDG_DATA_HOME} + "/hyprpm";
- return std::string{HOME} + "/.local/share/hyprpm";
+ return std::filesystem::path{XDG_DATA_HOME} / "hyprpm";
+ return std::filesystem::path{HOME} / ".local/share/hyprpm";
}
std::string DataState::getHeadersPath() {
- return getDataStatePath() + "/headersRoot";
+ return getDataStatePath() / "headersRoot";
+}
+
+std::vector<std::filesystem::path> DataState::getPluginStates() {
+ ensureStateStoreExists();
+
+ std::vector<std::filesystem::path> states;
+ for (const auto& entry : std::filesystem::directory_iterator(getDataStatePath())) {
+ if (!entry.is_directory() || entry.path().stem() == "headersRoot")
+ continue;
+
+ const auto stateFile = entry.path() / "state.toml";
+ if (!std::filesystem::exists(stateFile))
+ continue;
+
+ states.emplace_back(stateFile);
+ }
+ return states;
}
void DataState::ensureStateStoreExists() {
@@ -37,7 +53,7 @@ void DataState::ensureStateStoreExists() {
void DataState::addNewPluginRepo(const SPluginRepository& repo) {
ensureStateStoreExists();
- const auto PATH = getDataStatePath() + "/" + repo.name;
+ const auto PATH = getDataStatePath() / repo.name;
std::filesystem::create_directories(PATH);
// clang-format off
@@ -50,19 +66,21 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
}}
};
for (auto const& p : repo.plugins) {
+ const auto filename = p.name + ".so";
+
// copy .so to the good place
if (std::filesystem::exists(p.filename))
- std::filesystem::copy_file(p.filename, PATH + "/" + p.name + ".so");
+ std::filesystem::copy_file(p.filename, PATH / filename);
DATA.emplace(p.name, toml::table{
- {"filename", p.name + ".so"},
+ {"filename", filename},
{"enabled", p.enabled},
{"failed", p.failed}
});
}
// clang-format on
- std::ofstream ofs(PATH + "/state.toml", std::ios::trunc);
+ std::ofstream ofs(PATH / "state.toml", std::ios::trunc);
ofs << DATA;
ofs.close();
}
@@ -72,17 +90,10 @@ bool DataState::pluginRepoExists(const std::string& urlOrName) {
const auto PATH = getDataStatePath();
- for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
- if (!entry.is_directory() || entry.path().stem() == "headersRoot")
- continue;
-
- if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
- continue;
-
- auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
-
- const auto NAME = STATE["repository"]["name"].value_or("");
- const auto URL = STATE["repository"]["url"].value_or("");
+ for (const auto& stateFile : getPluginStates()) {
+ const auto STATE = toml::parse_file(stateFile.c_str());
+ const auto NAME = STATE["repository"]["name"].value_or("");
+ const auto URL = STATE["repository"]["url"].value_or("");
if (URL == urlOrName || NAME == urlOrName)
return true;
@@ -96,29 +107,22 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
const auto PATH = getDataStatePath();
- for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
- if (!entry.is_directory() || entry.path().stem() == "headersRoot")
- continue;
-
- if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
- continue;
-
- auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
-
- const auto NAME = STATE["repository"]["name"].value_or("");
- const auto URL = STATE["repository"]["url"].value_or("");
+ for (const auto& stateFile : getPluginStates()) {
+ const auto STATE = toml::parse_file(stateFile.c_str());
+ const auto NAME = STATE["repository"]["name"].value_or("");
+ const auto URL = STATE["repository"]["url"].value_or("");
if (URL == urlOrName || NAME == urlOrName) {
// unload the plugins!!
- for (const auto& file : std::filesystem::directory_iterator(entry.path())) {
+ for (const auto& file : std::filesystem::directory_iterator(stateFile.parent_path())) {
if (!file.path().string().ends_with(".so"))
continue;
g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false);
}
- std::filesystem::remove_all(entry.path());
+ std::filesystem::remove_all(stateFile.parent_path());
return;
}
}
@@ -139,7 +143,7 @@ void DataState::updateGlobalState(const SGlobalState& state) {
};
// clang-format on
- std::ofstream ofs(PATH + "/state.toml", std::ios::trunc);
+ std::ofstream ofs(PATH / "state.toml", std::ios::trunc);
ofs << DATA;
ofs.close();
}
@@ -147,12 +151,12 @@ void DataState::updateGlobalState(const SGlobalState& state) {
SGlobalState DataState::getGlobalState() {
ensureStateStoreExists();
- const auto PATH = getDataStatePath();
+ const auto stateFile = getDataStatePath() / "state.toml";
- if (!std::filesystem::exists(PATH + "/state.toml"))
+ if (!std::filesystem::exists(stateFile))
return SGlobalState{};
- auto DATA = toml::parse_file(PATH + "/state.toml");
+ auto DATA = toml::parse_file(stateFile.c_str());
SGlobalState state;
state.headersHashCompiled = DATA["state"]["hash"].value_or("");
@@ -167,15 +171,8 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
const auto PATH = getDataStatePath();
std::vector<SPluginRepository> repos;
-
- for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
- if (!entry.is_directory() || entry.path().stem() == "headersRoot")
- continue;
-
- if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
- continue;
-
- auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
+ for (const auto& stateFile : getPluginStates()) {
+ const auto STATE = toml::parse_file(stateFile.c_str());
const auto NAME = STATE["repository"]["name"].value_or("");
const auto URL = STATE["repository"]["url"].value_or("");
@@ -210,15 +207,8 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
const auto PATH = getDataStatePath();
- for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
- if (!entry.is_directory() || entry.path().stem() == "headersRoot")
- continue;
-
- if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
- continue;
-
- auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
-
+ for (const auto& stateFile : getPluginStates()) {
+ const auto STATE = toml::parse_file(stateFile.c_str());
for (const auto& [key, val] : STATE) {
if (key == "repository")
continue;
@@ -231,10 +221,11 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
if (FAILED)
return false;
- (*STATE[key].as_table()).insert_or_assign("enabled", enabled);
+ auto modifiedState = STATE;
+ (*modifiedState[key].as_table()).insert_or_assign("enabled", enabled);
- std::ofstream state(entry.path().string() + "/state.toml", std::ios::trunc);
- state << STATE;
+ std::ofstream state(stateFile, std::ios::trunc);
+ state << modifiedState;
state.close();
return true;
diff --git a/hyprpm/src/core/DataState.hpp b/hyprpm/src/core/DataState.hpp
index 70788f72..ebb550ba 100644
--- a/hyprpm/src/core/DataState.hpp
+++ b/hyprpm/src/core/DataState.hpp
@@ -1,4 +1,5 @@
#pragma once
+#include <filesystem>
#include <string>
#include <vector>
#include "Plugin.hpp"
@@ -9,14 +10,15 @@ struct SGlobalState {
};
namespace DataState {
- std::string getDataStatePath();
- std::string getHeadersPath();
- void ensureStateStoreExists();
- void addNewPluginRepo(const SPluginRepository& repo);
- void removePluginRepo(const std::string& urlOrName);
- bool pluginRepoExists(const std::string& urlOrName);
- void updateGlobalState(const SGlobalState& state);
- SGlobalState getGlobalState();
- bool setPluginEnabled(const std::string& name, bool enabled);
- std::vector<SPluginRepository> getAllRepositories();
+ std::filesystem::path getDataStatePath();
+ std::string getHeadersPath();
+ std::vector<std::filesystem::path> getPluginStates();
+ void ensureStateStoreExists();
+ void addNewPluginRepo(const SPluginRepository& repo);
+ void removePluginRepo(const std::string& urlOrName);
+ bool pluginRepoExists(const std::string& urlOrName);
+ void updateGlobalState(const SGlobalState& state);
+ SGlobalState getGlobalState();
+ bool setPluginEnabled(const std::string& name, bool enabled);
+ std::vector<SPluginRepository> getAllRepositories();
}; \ No newline at end of file
diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp
index 48b108c8..a3bd5a09 100644
--- a/hyprpm/src/core/PluginManager.cpp
+++ b/hyprpm/src/core/PluginManager.cpp
@@ -7,10 +7,8 @@
#include <cstdio>
#include <iostream>
-#include <array>
#include <filesystem>
#include <print>
-#include <thread>
#include <fstream>
#include <algorithm>
#include <format>
@@ -21,6 +19,7 @@
#include <unistd.h>
#include <toml++/toml.hpp>
+#include <glaze/glaze.hpp>
#include <hyprutils/string/String.hpp>
#include <hyprutils/os/Process.hpp>
@@ -83,13 +82,13 @@ SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
hlbranch = hlbranch.substr(0, hlbranch.find(" at commit "));
std::string hldate = HLVERCALL.substr(HLVERCALL.find("Date: ") + 6);
- hldate = hldate.substr(0, hldate.find("\n"));
+ hldate = hldate.substr(0, hldate.find('\n'));
std::string hlcommits;
if (HLVERCALL.contains("commits:")) {
hlcommits = HLVERCALL.substr(HLVERCALL.find("commits:") + 9);
- hlcommits = hlcommits.substr(0, hlcommits.find(" "));
+ hlcommits = hlcommits.substr(0, hlcommits.find(' '));
}
int commits = 0;
@@ -378,7 +377,7 @@ eHeadersErrors CPluginManager::headersValid() {
// find headers commit
const std::string& cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
- auto headers = execAndGet(cmd.c_str());
+ auto headers = execAndGet(cmd);
if (!headers.contains("-I/"))
return HEADERS_MISSING;
@@ -790,35 +789,28 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
const auto HOME = getenv("HOME");
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!HOME || !HIS) {
- std::println(stderr, "PluginManager: no $HOME or HIS");
+ std::println(stderr, "PluginManager: no $HOME or $HYPRLAND_INSTANCE_SIGNATURE");
return LOADSTATE_FAIL;
}
- const auto HYPRPMPATH = DataState::getDataStatePath() + "/";
+ const auto HYPRPMPATH = DataState::getDataStatePath();
- auto pluginLines = execAndGet("hyprctl plugins list | grep Plugin");
+ const auto json = glz::read_json<glz::json_t::array_t>(execAndGet("hyprctl plugins list -j"));
+ if (!json) {
+ std::println(stderr, "PluginManager: couldn't parse hyprctl output");
+ return LOADSTATE_FAIL;
+ }
std::vector<std::string> loadedPlugins;
+ for (const auto& plugin : json.value()) {
+ if (!plugin.is_object() || !plugin.contains("name")) {
+ std::println(stderr, "PluginManager: couldn't parse plugin object");
+ return LOADSTATE_FAIL;
+ }
+ loadedPlugins.emplace_back(plugin["name"].get<std::string>());
+ }
std::println("{}", successString("Ensuring plugin load state"));
- // iterate line by line
- while (!pluginLines.empty()) {
- auto plLine = pluginLines.substr(0, pluginLines.find('\n'));
-
- if (pluginLines.find('\n') != std::string::npos)
- pluginLines = pluginLines.substr(pluginLines.find('\n') + 1);
- else
- pluginLines = "";
-
- if (plLine.back() != ':')
- continue;
-
- plLine = plLine.substr(7);
- plLine = plLine.substr(0, plLine.find(" by "));
-
- loadedPlugins.push_back(plLine);
- }
-
// get state
const auto REPOS = DataState::getAllRepositories();
@@ -853,7 +845,7 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
for (auto const& p : loadedPlugins) {
if (!enabled(p)) {
// unload
- if (!loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false)) {
+ if (!loadUnloadPlugin(HYPRPMPATH / repoForName(p) / (p + ".so"), false)) {
std::println("{}", infoString("{} will be unloaded after restarting Hyprland", p));
hyprlandVersionMismatch = true;
} else
@@ -870,7 +862,7 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
if (std::find_if(loadedPlugins.begin(), loadedPlugins.end(), [&](const auto& other) { return other == p.name; }) != loadedPlugins.end())
continue;
- if (!loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true)) {
+ if (!loadUnloadPlugin(HYPRPMPATH / repoForName(p.name) / p.filename, true)) {
std::println("{}", infoString("{} will be loaded after restarting Hyprland", p.name));
hyprlandVersionMismatch = true;
} else
diff --git a/hyprpm/src/meson.build b/hyprpm/src/meson.build
index 2ef6c323..fd914f9d 100644
--- a/hyprpm/src/meson.build
+++ b/hyprpm/src/meson.build
@@ -8,6 +8,7 @@ executable(
dependency('hyprutils', version: '>= 0.1.1'),
dependency('threads'),
dependency('tomlplusplus'),
+ dependency('glaze', method: 'cmake'),
],
install: true,
)
diff --git a/nix/default.nix b/nix/default.nix
index 9293a35c..8e3af31d 100644
--- a/nix/default.nix
+++ b/nix/default.nix
@@ -5,12 +5,14 @@
pkg-config,
pkgconf,
makeWrapper,
+ cmake,
meson,
ninja,
aquamarine,
binutils,
cairo,
git,
+ glaze,
hyprcursor,
hyprgraphics,
hyprland-protocols,
@@ -102,6 +104,7 @@ in
makeWrapper
meson
ninja
+ cmake # needed for glaze
pkg-config
];
@@ -116,6 +119,7 @@ in
aquamarine
cairo
git
+ glaze
hyprcursor
hyprgraphics
hyprland-protocols