hyprpm: move to system directories for storing plugins (#10211)
Some checks are pending
Build Hyprland / Build Hyprland (Arch) (push) Waiting to run
Build Hyprland / Build Hyprland with Meson (Arch) (push) Waiting to run
Build Hyprland / Build Hyprland without precompiled headers (Arch) (push) Waiting to run
Build Hyprland / Build Hyprland in pure Wayland (Arch) (push) Waiting to run
Build Hyprland / Code Style (Arch) (push) Waiting to run
Nix (CI) / update-inputs (push) Waiting to run
Nix (CI) / build (push) Waiting to run
Security Checks / Flawfinder Checks (push) Waiting to run

This commit is contained in:
Vaxry 2025-05-01 18:00:26 +02:00 committed by GitHub
parent b5ef049ea1
commit 858c0e26d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 278 additions and 74 deletions

View file

@ -109,7 +109,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.8.0) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.8.0)
pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2)
pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7)
pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.6.0) pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.7.0)
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1)
string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION}) string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION})

View file

@ -9,7 +9,7 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
set(CMAKE_CXX_STANDARD 23) 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) find_package(glaze QUIET)
if (NOT glaze_FOUND) if (NOT glaze_FOUND)

View file

@ -1,22 +1,15 @@
#include "DataState.hpp" #include "DataState.hpp"
#include <sys/stat.h>
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
#include <print> #include <print>
#include <fstream> #include <fstream>
#include "PluginManager.hpp" #include "PluginManager.hpp"
#include "../helpers/Die.hpp"
#include "../helpers/Sys.hpp"
#include "../helpers/StringUtils.hpp"
std::filesystem::path DataState::getDataStatePath() { std::filesystem::path DataState::getDataStatePath() {
const auto HOME = getenv("HOME"); return std::filesystem::path("/var/cache/hyprpm/" + g_pPluginManager->m_szUsername);
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";
} }
std::string DataState::getHeadersPath() { std::string DataState::getHeadersPath() {
@ -41,21 +34,25 @@ std::vector<std::filesystem::path> DataState::getPluginStates() {
} }
void DataState::ensureStateStoreExists() { void DataState::ensureStateStoreExists() {
const auto PATH = getDataStatePath(); std::error_code ec;
if (!std::filesystem::exists(getHeadersPath(), ec) || ec) {
if (!std::filesystem::exists(PATH)) std::println("{}", infoString("The hyprpm state store doesn't exist. Creating now..."));
std::filesystem::create_directories(PATH); if (!std::filesystem::exists("/var/cache/hyprpm/", ec) || ec)
NSys::runAsSuperuser("mkdir -p -m 755 '/var/cache/hyprpm/'");
if (!std::filesystem::exists(getHeadersPath())) if (!std::filesystem::exists(getDataStatePath(), ec) || ec)
std::filesystem::create_directories(getHeadersPath()); NSys::runAsSuperuser("mkdir -p -m 755 '" + getDataStatePath().string() + "'");
NSys::runAsSuperuser("mkdir -p -m 755 '" + getHeadersPath() + "'");
}
} }
void DataState::addNewPluginRepo(const SPluginRepository& repo) { void DataState::addNewPluginRepo(const SPluginRepository& repo) {
ensureStateStoreExists(); 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 // clang-format off
auto DATA = toml::table{ auto DATA = toml::table{
{"repository", toml::table{ {"repository", toml::table{
@ -68,9 +65,9 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
for (auto const& p : repo.plugins) { for (auto const& p : repo.plugins) {
const auto filename = p.name + ".so"; 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)) 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{ DATA.emplace(p.name, toml::table{
{"filename", filename}, {"filename", filename},
@ -80,16 +77,16 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
} }
// clang-format on // clang-format on
std::ofstream ofs(PATH / "state.toml", std::ios::trunc); std::stringstream ss;
ofs << DATA; ss << DATA;
ofs.close();
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) { bool DataState::pluginRepoExists(const std::string& urlOrName) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath();
for (const auto& stateFile : getPluginStates()) { for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); const auto STATE = toml::parse_file(stateFile.c_str());
const auto NAME = STATE["repository"]["name"].value_or(""); 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) { void DataState::removePluginRepo(const std::string& urlOrName) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath();
for (const auto& stateFile : getPluginStates()) { for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); const auto STATE = toml::parse_file(stateFile.c_str());
const auto NAME = STATE["repository"]["name"].value_or(""); 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); 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; return;
} }
} }
@ -131,9 +132,11 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
void DataState::updateGlobalState(const SGlobalState& state) { void DataState::updateGlobalState(const SGlobalState& state) {
ensureStateStoreExists(); 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 // clang-format off
auto DATA = toml::table{ auto DATA = toml::table{
{"state", toml::table{ {"state", toml::table{
@ -143,17 +146,20 @@ void DataState::updateGlobalState(const SGlobalState& state) {
}; };
// clang-format on // clang-format on
std::ofstream ofs(PATH / "state.toml", std::ios::trunc); std::stringstream ss;
ofs << DATA; ss << DATA;
ofs.close();
NSys::runAsSuperuser("cat << EOF > " + (PATH / "state.toml").string() + "\n" + ss.str() + "\nEOF");
NSys::runAsSuperuser("chmod 644 '" + (PATH / "state.toml").string() + "'");
} }
SGlobalState DataState::getGlobalState() { SGlobalState DataState::getGlobalState() {
ensureStateStoreExists(); 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{}; return SGlobalState{};
auto DATA = toml::parse_file(stateFile.c_str()); auto DATA = toml::parse_file(stateFile.c_str());
@ -168,8 +174,6 @@ SGlobalState DataState::getGlobalState() {
std::vector<SPluginRepository> DataState::getAllRepositories() { std::vector<SPluginRepository> DataState::getAllRepositories() {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath();
std::vector<SPluginRepository> repos; std::vector<SPluginRepository> repos;
for (const auto& stateFile : getPluginStates()) { for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); 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) { bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath();
for (const auto& stateFile : getPluginStates()) { for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); const auto STATE = toml::parse_file(stateFile.c_str());
for (const auto& [key, val] : STATE) { for (const auto& [key, val] : STATE) {
@ -224,9 +226,11 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
auto modifiedState = STATE; auto modifiedState = STATE;
(*modifiedState[key].as_table()).insert_or_assign("enabled", enabled); (*modifiedState[key].as_table()).insert_or_assign("enabled", enabled);
std::ofstream state(stateFile, std::ios::trunc); std::stringstream ss;
state << modifiedState; ss << modifiedState;
state.close();
NSys::runAsSuperuser("cat << EOF > " + stateFile.string() + "\n" + ss.str() + "\nEOF");
NSys::runAsSuperuser("chmod 644 '" + stateFile.string() + "'");
return true; return true;
} }
@ -234,3 +238,17 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
return false; 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 + "'");
}

View file

@ -18,6 +18,7 @@ namespace DataState {
void removePluginRepo(const std::string& urlOrName); void removePluginRepo(const std::string& urlOrName);
bool pluginRepoExists(const std::string& urlOrName); bool pluginRepoExists(const std::string& urlOrName);
void updateGlobalState(const SGlobalState& state); void updateGlobalState(const SGlobalState& state);
void purgeAllCache();
SGlobalState getGlobalState(); SGlobalState getGlobalState();
bool setPluginEnabled(const std::string& name, bool enabled); bool setPluginEnabled(const std::string& name, bool enabled);
std::vector<SPluginRepository> getAllRepositories(); std::vector<SPluginRepository> getAllRepositories();

View file

@ -5,6 +5,8 @@
#include "Manifest.hpp" #include "Manifest.hpp"
#include "DataState.hpp" #include "DataState.hpp"
#include "HyprlandSocket.hpp" #include "HyprlandSocket.hpp"
#include "../helpers/Sys.hpp"
#include "../helpers/Die.hpp"
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
@ -50,6 +52,13 @@ static std::string getTempRoot() {
return STR; 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) { SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
static bool onceRunning = false; static bool onceRunning = false;
static bool onceInstalled = false; static bool onceInstalled = false;
@ -275,6 +284,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
if (HEADERSSTATUS != HEADERS_OK) { if (HEADERSSTATUS != HEADERS_OK) {
std::println("\n{}", headerError(HEADERSSTATUS)); std::println("\n{}", headerError(HEADERSSTATUS));
std::println("\n{}", infoString("if the problem persists, try running hyprpm purge-cache."));
return false; return false;
} }
@ -550,13 +560,20 @@ bool CPluginManager::updateHeaders(bool force) {
progress.m_szCurrentMessage = "Installing sources"; progress.m_szCurrentMessage = "Installing sources";
progress.print(); progress.print();
const std::string& cmd = std::string cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile", DataState::getHeadersPath(), WORKINGDIR);
std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR);
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("installation will run: {}", cmd)); progress.printMessageAbove(verboseString("prepare install will run: {}", cmd));
ret = execAndGet(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) if (m_bVerbose)
std::println("{}", verboseString("installer returned: {}", ret)); std::println("{}", verboseString("installer returned: {}", ret));
@ -570,9 +587,14 @@ bool CPluginManager::updateHeaders(bool force) {
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
auto GLOBALSTATE = DataState::getGlobalState();
GLOBALSTATE.headersHashCompiled = HLVER.hash;
DataState::updateGlobalState(GLOBALSTATE);
std::print("\n"); std::print("\n");
} else { } else {
progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID))); 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_iSteps = 5;
progress.m_szCurrentMessage = "Failed"; progress.m_szCurrentMessage = "Failed";
progress.print(); progress.print();
@ -884,7 +906,8 @@ bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) {
auto HLVER = getHyprlandVersion(true); auto HLVER = getHyprlandVersion(true);
if (state.headersHashCompiled != HLVER.hash) { 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; return false;
} }

View file

@ -40,6 +40,8 @@ struct SHyprlandVersion {
class CPluginManager { class CPluginManager {
public: public:
CPluginManager();
bool addNewPluginRepo(const std::string& url, const std::string& rev); bool addNewPluginRepo(const std::string& url, const std::string& rev);
bool removePluginRepo(const std::string& urlOrName); bool removePluginRepo(const std::string& urlOrName);
@ -62,7 +64,7 @@ class CPluginManager {
bool m_bVerbose = false; bool m_bVerbose = false;
bool m_bNoShallow = false; bool m_bNoShallow = false;
std::string m_szCustomHlUrl; std::string m_szCustomHlUrl, m_szUsername;
// will delete recursively if exists!! // will delete recursively if exists!!
bool createSafeDirectory(const std::string& path); bool createSafeDirectory(const std::string& path);

View file

@ -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);
}
};

110
hyprpm/src/helpers/Sys.cpp Normal file
View file

@ -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;
}
}

View file

@ -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();
};

View file

@ -2,34 +2,37 @@
#include "helpers/StringUtils.hpp" #include "helpers/StringUtils.hpp"
#include "core/PluginManager.hpp" #include "core/PluginManager.hpp"
#include "core/DataState.hpp" #include "core/DataState.hpp"
#include "helpers/Sys.hpp"
#include <cstdio> #include <cstdio>
#include <vector> #include <vector>
#include <string> #include <string>
#include <print> #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 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. is optional, when set, commit locks are ignored.
remove [url/name] Remove an installed plugin repository remove [url/name] Remove an installed plugin repository.
enable [name] Enable a plugin enable [name] Enable a plugin.
disable [name] Disable a plugin disable [name] Disable a plugin.
update Check and update all plugins if needed update Check and update all plugins if needed.
reload Reload hyprpm state. Ensure all enabled plugins are loaded. 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: Flags:
--notify | -n Send a hyprland notification for important events (including both successes and fail events) --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 --notify-fail | -nn Send a hyprland notification for fail events only.
--help | -h Show this menu --help | -h Show this menu.
--verbose | -v Enable too much logging --verbose | -v Enable too much logging.
--force | -f Force an operation ignoring checks (e.g. update -f) --force | -f Force an operation ignoring checks (e.g. update -f).
--no-shallow | -s Disable shallow cloning of Hyprland sources --no-shallow | -s Disable shallow cloning of Hyprland sources.
--hl-url | Pass a custom hyprland source url --hl-url | Pass a custom hyprland source url.
)#"; )#";
@ -96,9 +99,11 @@ int main(int argc, char** argv, char** envp) {
} }
std::string rev = ""; std::string rev = "";
if (command.size() >= 3) { if (command.size() >= 3)
rev = command[2]; rev = command[2];
}
NSys::cacheSudo();
CScopeGuard x([] { NSys::dropSudo(); });
return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1; return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1;
} else if (command[0] == "remove") { } else if (command[0] == "remove") {
@ -107,10 +112,17 @@ int main(int argc, char** argv, char** envp) {
return 1; return 1;
} }
NSys::cacheSudo();
CScopeGuard x([] { NSys::dropSudo(); });
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1; return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
} else if (command[0] == "update") { } else if (command[0] == "update") {
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK; NSys::cacheSudo();
bool headers = g_pPluginManager->updateHeaders(force); CScopeGuard x([] { NSys::dropSudo(); });
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
bool headers = g_pPluginManager->updateHeaders(force);
if (headers) { if (headers) {
const auto HLVER = g_pPluginManager->getHyprlandVersion(false); const auto HLVER = g_pPluginManager->getHyprlandVersion(false);
auto GLOBALSTATE = DataState::getGlobalState(); auto GLOBALSTATE = DataState::getGlobalState();
@ -141,7 +153,10 @@ int main(int argc, char** argv, char** envp) {
return 1; return 1;
} }
auto ret = g_pPluginManager->ensurePluginsLoadState(); NSys::cacheSudo();
CScopeGuard x([] { NSys::dropSudo(); });
auto ret = g_pPluginManager->ensurePluginsLoadState();
if (ret == LOADSTATE_HYPRLAND_UPDATED) if (ret == LOADSTATE_HYPRLAND_UPDATED)
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Enabled plugin, but Hyprland was updated. Please restart Hyprland."); 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; return 1;
} }
auto ret = g_pPluginManager->ensurePluginsLoadState(); NSys::cacheSudo();
CScopeGuard x([] { NSys::dropSudo(); });
auto ret = g_pPluginManager->ensurePluginsLoadState();
if (ret != LOADSTATE_OK) if (ret != LOADSTATE_OK)
return 1; return 1;
} else if (command[0] == "reload") { } else if (command[0] == "reload") {
@ -181,6 +200,10 @@ int main(int argc, char** argv, char** envp) {
} else if (notify && !notifyFail) { } else if (notify && !notifyFail) {
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins"); 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") { } else if (command[0] == "list") {
g_pPluginManager->listAllPlugins(); g_pPluginManager->listAllPlugins();
} else { } else {

View file

@ -35,7 +35,7 @@ aquamarine = dependency('aquamarine', version: '>=0.8.0')
hyprcursor = dependency('hyprcursor', version: '>=0.1.7') hyprcursor = dependency('hyprcursor', version: '>=0.1.7')
hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1') hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1')
hyprlang = dependency('hyprlang', version: '>= 0.3.2') hyprlang = dependency('hyprlang', version: '>= 0.3.2')
hyprutils = dependency('hyprutils', version: '>= 0.6.0') hyprutils = dependency('hyprutils', version: '>= 0.7.0')
aquamarine_version_list = aquamarine.version().split('.') aquamarine_version_list = aquamarine.version().split('.')
add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp')
add_project_arguments(['-DAQUAMARINE_VERSION_MAJOR=@0@'.format(aquamarine_version_list.get(0))], language: 'cpp') add_project_arguments(['-DAQUAMARINE_VERSION_MAJOR=@0@'.format(aquamarine_version_list.get(0))], language: 'cpp')