summaryrefslogtreecommitdiff
path: root/hyprpm
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2025-05-01 18:00:26 +0200
committerGitHub <noreply@github.com>2025-05-01 18:00:26 +0200
commit858c0e26d19391d56c1e7a6ac8574da956068d38 (patch)
tree4fde23b1d3017dd8f7d14ac4f4001ed79eba3e40 /hyprpm
parentb5ef049ea153e476057987ef11ccbdbbfb655c15 (diff)
hyprpm: move to system directories for storing plugins (#10211)
Diffstat (limited to 'hyprpm')
-rw-r--r--hyprpm/CMakeLists.txt2
-rw-r--r--hyprpm/src/core/DataState.cpp108
-rw-r--r--hyprpm/src/core/DataState.hpp1
-rw-r--r--hyprpm/src/core/PluginManager.cpp31
-rw-r--r--hyprpm/src/core/PluginManager.hpp4
-rw-r--r--hyprpm/src/helpers/Die.hpp15
-rw-r--r--hyprpm/src/helpers/Sys.cpp110
-rw-r--r--hyprpm/src/helpers/Sys.hpp12
-rw-r--r--hyprpm/src/main.cpp65
9 files changed, 276 insertions, 72 deletions
diff --git a/hyprpm/CMakeLists.txt b/hyprpm/CMakeLists.txt
index b3028d0a..f2e0b223 100644
--- a/hyprpm/CMakeLists.txt
+++ b/hyprpm/CMakeLists.txt
@@ -9,7 +9,7 @@ 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)
+pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.7.0)
find_package(glaze QUIET)
if (NOT glaze_FOUND)
diff --git a/hyprpm/src/core/DataState.cpp b/hyprpm/src/core/DataState.cpp
index 55f148a4..d8a9477e 100644
--- a/hyprpm/src/core/DataState.cpp
+++ b/hyprpm/src/core/DataState.cpp
@@ -1,22 +1,15 @@
#include "DataState.hpp"
+#include <sys/stat.h>
#include <toml++/toml.hpp>
#include <print>
#include <fstream>
#include "PluginManager.hpp"
+#include "../helpers/Die.hpp"
+#include "../helpers/Sys.hpp"
+#include "../helpers/StringUtils.hpp"
std::filesystem::path DataState::getDataStatePath() {
- const auto HOME = getenv("HOME");
- if (!HOME) {
- std::println(stderr, "DataState: no $HOME");
- throw std::runtime_error("no $HOME");
- return "";
- }
-
- const auto XDG_DATA_HOME = getenv("XDG_DATA_HOME");
-
- if (XDG_DATA_HOME)
- return std::filesystem::path{XDG_DATA_HOME} / "hyprpm";
- return std::filesystem::path{HOME} / ".local/share/hyprpm";
+ return std::filesystem::path("/var/cache/hyprpm/" + g_pPluginManager->m_szUsername);
}
std::string DataState::getHeadersPath() {
@@ -41,21 +34,25 @@ std::vector<std::filesystem::path> DataState::getPluginStates() {
}
void DataState::ensureStateStoreExists() {
- const auto PATH = getDataStatePath();
-
- if (!std::filesystem::exists(PATH))
- std::filesystem::create_directories(PATH);
-
- if (!std::filesystem::exists(getHeadersPath()))
- std::filesystem::create_directories(getHeadersPath());
+ std::error_code ec;
+ if (!std::filesystem::exists(getHeadersPath(), ec) || ec) {
+ std::println("{}", infoString("The hyprpm state store doesn't exist. Creating now..."));
+ if (!std::filesystem::exists("/var/cache/hyprpm/", ec) || ec)
+ NSys::runAsSuperuser("mkdir -p -m 755 '/var/cache/hyprpm/'");
+ if (!std::filesystem::exists(getDataStatePath(), ec) || ec)
+ NSys::runAsSuperuser("mkdir -p -m 755 '" + getDataStatePath().string() + "'");
+ NSys::runAsSuperuser("mkdir -p -m 755 '" + getHeadersPath() + "'");
+ }
}
void DataState::addNewPluginRepo(const SPluginRepository& repo) {
ensureStateStoreExists();
- const auto PATH = getDataStatePath() / repo.name;
+ const auto PATH = getDataStatePath() / repo.name;
- std::filesystem::create_directories(PATH);
+ std::error_code ec;
+ if (!std::filesystem::exists(PATH, ec) || ec)
+ NSys::runAsSuperuser("mkdir -p -m 755 '" + PATH.string() + "'");
// clang-format off
auto DATA = toml::table{
{"repository", toml::table{
@@ -68,9 +65,9 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
for (auto const& p : repo.plugins) {
const auto filename = p.name + ".so";
- // copy .so to the good place
+ // copy .so to the good place and chmod 755
if (std::filesystem::exists(p.filename))
- std::filesystem::copy_file(p.filename, PATH / filename);
+ NSys::runAsSuperuser("cp '" + p.filename + "' '" + (PATH / filename).string() + "' && chmod 755 '" + (PATH / filename).string() + "'");
DATA.emplace(p.name, toml::table{
{"filename", filename},
@@ -80,16 +77,16 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
}
// clang-format on
- std::ofstream ofs(PATH / "state.toml", std::ios::trunc);
- ofs << DATA;
- ofs.close();
+ std::stringstream ss;
+ ss << DATA;
+
+ NSys::runAsSuperuser("cat << EOF > " + (PATH / "state.toml").string() + "\n" + ss.str() + "\nEOF");
+ NSys::runAsSuperuser("chmod 644 '" + (PATH / "state.toml").string() + "'");
}
bool DataState::pluginRepoExists(const std::string& urlOrName) {
ensureStateStoreExists();
- const auto PATH = getDataStatePath();
-
for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str());
const auto NAME = STATE["repository"]["name"].value_or("");
@@ -105,8 +102,6 @@ bool DataState::pluginRepoExists(const std::string& urlOrName) {
void DataState::removePluginRepo(const std::string& urlOrName) {
ensureStateStoreExists();
- const auto PATH = getDataStatePath();
-
for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str());
const auto NAME = STATE["repository"]["name"].value_or("");
@@ -122,7 +117,13 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false);
}
- std::filesystem::remove_all(stateFile.parent_path());
+ const auto PATH = stateFile.parent_path().string();
+
+ if (!PATH.starts_with("/var/cache/hyprpm") || PATH.contains('\''))
+ return; // WTF?
+
+ // scary!
+ NSys::runAsSuperuser("rm -r '" + PATH + "'");
return;
}
}
@@ -131,9 +132,11 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
void DataState::updateGlobalState(const SGlobalState& state) {
ensureStateStoreExists();
- const auto PATH = getDataStatePath();
+ const auto PATH = getDataStatePath();
- std::filesystem::create_directories(PATH);
+ std::error_code ec;
+ if (!std::filesystem::exists(PATH, ec) || ec)
+ NSys::runAsSuperuser("mkdir -p -m 755 '" + PATH.string() + "'");
// clang-format off
auto DATA = toml::table{
{"state", toml::table{
@@ -143,17 +146,20 @@ void DataState::updateGlobalState(const SGlobalState& state) {
};
// clang-format on
- std::ofstream ofs(PATH / "state.toml", std::ios::trunc);
- ofs << DATA;
- ofs.close();
+ std::stringstream ss;
+ ss << DATA;
+
+ NSys::runAsSuperuser("cat << EOF > " + (PATH / "state.toml").string() + "\n" + ss.str() + "\nEOF");
+ NSys::runAsSuperuser("chmod 644 '" + (PATH / "state.toml").string() + "'");
}
SGlobalState DataState::getGlobalState() {
ensureStateStoreExists();
- const auto stateFile = getDataStatePath() / "state.toml";
+ const auto stateFile = getDataStatePath() / "state.toml";
- if (!std::filesystem::exists(stateFile))
+ std::error_code ec;
+ if (!std::filesystem::exists(stateFile, ec) || ec)
return SGlobalState{};
auto DATA = toml::parse_file(stateFile.c_str());
@@ -168,8 +174,6 @@ SGlobalState DataState::getGlobalState() {
std::vector<SPluginRepository> DataState::getAllRepositories() {
ensureStateStoreExists();
- const auto PATH = getDataStatePath();
-
std::vector<SPluginRepository> repos;
for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str());
@@ -205,8 +209,6 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
ensureStateStoreExists();
- const auto PATH = getDataStatePath();
-
for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str());
for (const auto& [key, val] : STATE) {
@@ -224,9 +226,11 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
auto modifiedState = STATE;
(*modifiedState[key].as_table()).insert_or_assign("enabled", enabled);
- std::ofstream state(stateFile, std::ios::trunc);
- state << modifiedState;
- state.close();
+ std::stringstream ss;
+ ss << modifiedState;
+
+ NSys::runAsSuperuser("cat << EOF > " + stateFile.string() + "\n" + ss.str() + "\nEOF");
+ NSys::runAsSuperuser("chmod 644 '" + stateFile.string() + "'");
return true;
}
@@ -234,3 +238,17 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
return false;
}
+
+void DataState::purgeAllCache() {
+ std::error_code ec;
+ if (!std::filesystem::exists(getDataStatePath()) && !ec) {
+ std::println("{}", infoString("Nothing to do"));
+ return;
+ }
+
+ const auto PATH = getDataStatePath().string();
+ if (PATH.contains('\''))
+ return;
+ // scary!
+ NSys::runAsSuperuser("rm -r '" + PATH + "'");
+}
diff --git a/hyprpm/src/core/DataState.hpp b/hyprpm/src/core/DataState.hpp
index ebb550ba..c35ded06 100644
--- a/hyprpm/src/core/DataState.hpp
+++ b/hyprpm/src/core/DataState.hpp
@@ -18,6 +18,7 @@ namespace DataState {
void removePluginRepo(const std::string& urlOrName);
bool pluginRepoExists(const std::string& urlOrName);
void updateGlobalState(const SGlobalState& state);
+ void purgeAllCache();
SGlobalState getGlobalState();
bool setPluginEnabled(const std::string& name, bool enabled);
std::vector<SPluginRepository> getAllRepositories();
diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp
index ee7d8e8f..33e565d3 100644
--- a/hyprpm/src/core/PluginManager.cpp
+++ b/hyprpm/src/core/PluginManager.cpp
@@ -5,6 +5,8 @@
#include "Manifest.hpp"
#include "DataState.hpp"
#include "HyprlandSocket.hpp"
+#include "../helpers/Sys.hpp"
+#include "../helpers/Die.hpp"
#include <cstdio>
#include <iostream>
@@ -50,6 +52,13 @@ static std::string getTempRoot() {
return STR;
}
+CPluginManager::CPluginManager() {
+ if (NSys::isSuperuser())
+ Debug::die("Don't run hyprpm as a superuser.");
+
+ m_szUsername = getpwuid(NSys::getUID())->pw_name;
+}
+
SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
static bool onceRunning = false;
static bool onceInstalled = false;
@@ -275,6 +284,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
if (HEADERSSTATUS != HEADERS_OK) {
std::println("\n{}", headerError(HEADERSSTATUS));
+ std::println("\n{}", infoString("if the problem persists, try running hyprpm purge-cache."));
return false;
}
@@ -550,13 +560,20 @@ bool CPluginManager::updateHeaders(bool force) {
progress.m_szCurrentMessage = "Installing sources";
progress.print();
- const std::string& cmd =
- std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR);
+ std::string cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile", DataState::getHeadersPath(), WORKINGDIR);
if (m_bVerbose)
- progress.printMessageAbove(verboseString("installation will run: {}", cmd));
+ progress.printMessageAbove(verboseString("prepare install will run: {}", cmd));
ret = execAndGet(cmd);
+ cmd = std::format("cd {} && make installheaders && chmod -R 644 {} && find {} -type d -exec chmod o+x {{}} \\;", WORKINGDIR, DataState::getHeadersPath(),
+ DataState::getHeadersPath());
+
+ if (m_bVerbose)
+ progress.printMessageAbove(verboseString("install will run as sudo: {}", cmd));
+
+ ret = NSys::runAsSuperuser(cmd);
+
if (m_bVerbose)
std::println("{}", verboseString("installer returned: {}", ret));
@@ -570,9 +587,14 @@ bool CPluginManager::updateHeaders(bool force) {
progress.m_szCurrentMessage = "Done!";
progress.print();
+ auto GLOBALSTATE = DataState::getGlobalState();
+ GLOBALSTATE.headersHashCompiled = HLVER.hash;
+ DataState::updateGlobalState(GLOBALSTATE);
+
std::print("\n");
} else {
progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID)));
+ progress.printMessageAbove(infoString("if the problem persists, try running hyprpm purge-cache."));
progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Failed";
progress.print();
@@ -884,7 +906,8 @@ bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) {
auto HLVER = getHyprlandVersion(true);
if (state.headersHashCompiled != HLVER.hash) {
- std::println("{}", infoString("Running Hyprland version differs from plugin state, please restart Hyprland."));
+ if (load)
+ std::println("{}", infoString("Running Hyprland version ({}) differs from plugin state ({}), please restart Hyprland.", HLVER.hash, state.headersHashCompiled));
return false;
}
diff --git a/hyprpm/src/core/PluginManager.hpp b/hyprpm/src/core/PluginManager.hpp
index b159b921..7640d7c8 100644
--- a/hyprpm/src/core/PluginManager.hpp
+++ b/hyprpm/src/core/PluginManager.hpp
@@ -40,6 +40,8 @@ struct SHyprlandVersion {
class CPluginManager {
public:
+ CPluginManager();
+
bool addNewPluginRepo(const std::string& url, const std::string& rev);
bool removePluginRepo(const std::string& urlOrName);
@@ -62,7 +64,7 @@ class CPluginManager {
bool m_bVerbose = false;
bool m_bNoShallow = false;
- std::string m_szCustomHlUrl;
+ std::string m_szCustomHlUrl, m_szUsername;
// will delete recursively if exists!!
bool createSafeDirectory(const std::string& path);
diff --git a/hyprpm/src/helpers/Die.hpp b/hyprpm/src/helpers/Die.hpp
new file mode 100644
index 00000000..0c00bcf3
--- /dev/null
+++ b/hyprpm/src/helpers/Die.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <format>
+#include <iostream>
+
+// NOLINTNEXTLINE
+namespace Debug {
+ template <typename... Args>
+ void die(std::format_string<Args...> fmt, Args&&... args) {
+ const std::string logMsg = std::vformat(fmt.get(), std::make_format_args(args...));
+
+ std::cout << "\n[ERR] " << logMsg << "\n";
+ exit(1);
+ }
+}; \ No newline at end of file
diff --git a/hyprpm/src/helpers/Sys.cpp b/hyprpm/src/helpers/Sys.cpp
new file mode 100644
index 00000000..3c6501ee
--- /dev/null
+++ b/hyprpm/src/helpers/Sys.cpp
@@ -0,0 +1,110 @@
+#include "Sys.hpp"
+#include "Die.hpp"
+#include "StringUtils.hpp"
+#include <pwd.h>
+#include <unistd.h>
+#include <print>
+#include <filesystem>
+
+#include <hyprutils/os/Process.hpp>
+#include <hyprutils/string/VarList.hpp>
+using namespace Hyprutils::OS;
+using namespace Hyprutils::String;
+
+static const std::vector<const char*> SUPERUSER_BINARIES = {
+ "sudo",
+ "doas",
+ "run0",
+};
+
+static bool executableExistsInPath(const std::string& exe) {
+ if (!getenv("PATH"))
+ return false;
+
+ static CVarList paths(getenv("PATH"), 0, ':', true);
+
+ for (auto& p : paths) {
+ std::string path = p + std::string{"/"} + exe;
+ std::error_code ec;
+ if (!std::filesystem::exists(path, ec) || ec)
+ continue;
+
+ if (!std::filesystem::is_regular_file(path, ec) || ec)
+ continue;
+
+ auto stat = std::filesystem::status(path, ec);
+ if (ec)
+ continue;
+
+ auto perms = stat.permissions();
+
+ return std::filesystem::perms::none != (perms & std::filesystem::perms::others_exec);
+ }
+
+ return false;
+}
+
+static std::pair<std::string, int> execAndGet(std::string cmd, bool noRedirect = false) {
+ if (!noRedirect)
+ cmd += " 2>&1";
+
+ CProcess proc("/bin/sh", {"-c", cmd});
+
+ if (!proc.runSync())
+ return {"error", 1};
+
+ return {proc.stdOut(), proc.exitCode()};
+}
+
+int NSys::getUID() {
+ const auto UID = getuid();
+ const auto PWUID = getpwuid(UID);
+ return PWUID ? PWUID->pw_uid : UID;
+}
+
+int NSys::getEUID() {
+ const auto UID = geteuid();
+ const auto PWUID = getpwuid(UID);
+ return PWUID ? PWUID->pw_uid : UID;
+}
+
+bool NSys::isSuperuser() {
+ return getuid() != geteuid() || !geteuid();
+}
+
+std::string NSys::runAsSuperuser(const std::string& cmd) {
+ for (const auto& SB : SUPERUSER_BINARIES) {
+ if (!executableExistsInPath(SB))
+ continue;
+
+ const auto RESULT = execAndGet(std::string{SB} + " /bin/sh -c \"" + cmd + "\"", true);
+
+ if (RESULT.second != 0)
+ Debug::die("Failed to run a command as sudo. This could be due to an invalid password, or a hyprpm bug.");
+
+ return RESULT.first;
+ }
+
+ Debug::die("Failed to find a superuser binary. Supported: sudo, doas, run0.");
+ return "";
+}
+
+void NSys::cacheSudo() {
+ // "caches" the sudo so that the prompt later doesn't pop up in a weird spot
+ // sudo will not ask us again for a moment
+ runAsSuperuser("echo e > /dev/null");
+}
+
+void NSys::dropSudo() {
+ for (const auto& SB : SUPERUSER_BINARIES) {
+ if (!executableExistsInPath(SB))
+ continue;
+
+ if (SB == std::string_view{"sudo"})
+ execAndGet("sudo -k");
+ else
+ std::println("{}", infoString("Don't know how to drop timestamp for {}, ignoring.", SB));
+
+ return;
+ }
+}
diff --git a/hyprpm/src/helpers/Sys.hpp b/hyprpm/src/helpers/Sys.hpp
new file mode 100644
index 00000000..2d643d40
--- /dev/null
+++ b/hyprpm/src/helpers/Sys.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <string>
+
+namespace NSys {
+ bool isSuperuser();
+ int getUID();
+ int getEUID();
+ std::string runAsSuperuser(const std::string& cmd);
+ void cacheSudo();
+ void dropSudo();
+}; \ No newline at end of file
diff --git a/hyprpm/src/main.cpp b/hyprpm/src/main.cpp
index 0d5efd1d..6d0cda40 100644
--- a/hyprpm/src/main.cpp
+++ b/hyprpm/src/main.cpp
@@ -2,34 +2,37 @@
#include "helpers/StringUtils.hpp"
#include "core/PluginManager.hpp"
#include "core/DataState.hpp"
+#include "helpers/Sys.hpp"
#include <cstdio>
#include <vector>
#include <string>
#include <print>
-#include <chrono>
-#include <thread>
+
+#include <hyprutils/utils/ScopeGuard.hpp>
+using namespace Hyprutils::Utils;
constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
┃
-┣ add [url] [git rev] → Install a new plugin repository from git. Git revision
+┣ add [url] [git rev] → Install a new plugin repository from git. Git revision.
┃ is optional, when set, commit locks are ignored.
-┣ remove [url/name] → Remove an installed plugin repository
-┣ enable [name] → Enable a plugin
-┣ disable [name] → Disable a plugin
-┣ update → Check and update all plugins if needed
+┣ remove [url/name] → Remove an installed plugin repository.
+┣ enable [name] → Enable a plugin.
+┣ disable [name] → Disable a plugin.
+┣ update → Check and update all plugins if needed.
┣ reload → Reload hyprpm state. Ensure all enabled plugins are loaded.
-┣ list → List all installed plugins
+┣ list → List all installed plugins.
+┣ purge-cache → Remove the entire hyprpm cache, built plugins, hyprpm settings and headers.
┃
┣ Flags:
┃
-┣ --notify | -n → Send a hyprland notification for important events (including both successes and fail events)
-┣ --notify-fail | -nn → Send a hyprland notification for fail events only
-┣ --help | -h → Show this menu
-┣ --verbose | -v → Enable too much logging
-┣ --force | -f → Force an operation ignoring checks (e.g. update -f)
-┣ --no-shallow | -s → Disable shallow cloning of Hyprland sources
-┣ --hl-url | → Pass a custom hyprland source url
+┣ --notify | -n → Send a hyprland notification for important events (including both successes and fail events).
+┣ --notify-fail | -nn → Send a hyprland notification for fail events only.
+┣ --help | -h → Show this menu.
+┣ --verbose | -v → Enable too much logging.
+┣ --force | -f → Force an operation ignoring checks (e.g. update -f).
+┣ --no-shallow | -s → Disable shallow cloning of Hyprland sources.
+┣ --hl-url | → Pass a custom hyprland source url.
┗
)#";
@@ -96,9 +99,11 @@ int main(int argc, char** argv, char** envp) {
}
std::string rev = "";
- if (command.size() >= 3) {
+ if (command.size() >= 3)
rev = command[2];
- }
+
+ NSys::cacheSudo();
+ CScopeGuard x([] { NSys::dropSudo(); });
return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1;
} else if (command[0] == "remove") {
@@ -107,10 +112,17 @@ int main(int argc, char** argv, char** envp) {
return 1;
}
+ NSys::cacheSudo();
+ CScopeGuard x([] { NSys::dropSudo(); });
+
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
} else if (command[0] == "update") {
- bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
- bool headers = g_pPluginManager->updateHeaders(force);
+ NSys::cacheSudo();
+ CScopeGuard x([] { NSys::dropSudo(); });
+
+ bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
+ bool headers = g_pPluginManager->updateHeaders(force);
+
if (headers) {
const auto HLVER = g_pPluginManager->getHyprlandVersion(false);
auto GLOBALSTATE = DataState::getGlobalState();
@@ -141,7 +153,10 @@ int main(int argc, char** argv, char** envp) {
return 1;
}
- auto ret = g_pPluginManager->ensurePluginsLoadState();
+ NSys::cacheSudo();
+ CScopeGuard x([] { NSys::dropSudo(); });
+
+ auto ret = g_pPluginManager->ensurePluginsLoadState();
if (ret == LOADSTATE_HYPRLAND_UPDATED)
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Enabled plugin, but Hyprland was updated. Please restart Hyprland.");
@@ -159,7 +174,11 @@ int main(int argc, char** argv, char** envp) {
return 1;
}
- auto ret = g_pPluginManager->ensurePluginsLoadState();
+ NSys::cacheSudo();
+ CScopeGuard x([] { NSys::dropSudo(); });
+
+ auto ret = g_pPluginManager->ensurePluginsLoadState();
+
if (ret != LOADSTATE_OK)
return 1;
} else if (command[0] == "reload") {
@@ -181,6 +200,10 @@ int main(int argc, char** argv, char** envp) {
} else if (notify && !notifyFail) {
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
}
+ } else if (command[0] == "purge-cache") {
+ NSys::cacheSudo();
+ CScopeGuard x([] { NSys::dropSudo(); });
+ DataState::purgeAllCache();
} else if (command[0] == "list") {
g_pPluginManager->listAllPlugins();
} else {