mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-05-12 23:00:36 +01:00
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
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:
parent
b5ef049ea1
commit
858c0e26d1
11 changed files with 278 additions and 74 deletions
|
@ -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(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2)
|
||||
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)
|
||||
|
||||
string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION})
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 + "'");
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
15
hyprpm/src/helpers/Die.hpp
Normal file
15
hyprpm/src/helpers/Die.hpp
Normal 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
110
hyprpm/src/helpers/Sys.cpp
Normal 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;
|
||||
}
|
||||
}
|
12
hyprpm/src/helpers/Sys.hpp
Normal file
12
hyprpm/src/helpers/Sys.hpp
Normal 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();
|
||||
};
|
|
@ -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 {
|
||||
|
|
|
@ -35,7 +35,7 @@ aquamarine = dependency('aquamarine', version: '>=0.8.0')
|
|||
hyprcursor = dependency('hyprcursor', version: '>=0.1.7')
|
||||
hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1')
|
||||
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('.')
|
||||
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')
|
||||
|
|
Loading…
Reference in a new issue