summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Barkess <57995669+Brumus14@users.noreply.github.com>2025-12-14 17:16:58 +0000
committerGitHub <noreply@github.com>2025-12-14 17:16:58 +0000
commit05ccbb2f2dc3121a48e9c1925357039b27d22a92 (patch)
treea5bb42acf7343c32b54ae93956b521c60739c9d3
parent09e195d1f293a876ce21a077af3d7c5047881b79 (diff)
hyprpm: added plugin author (#12594)
-rw-r--r--hyprpm/src/core/DataState.cpp57
-rw-r--r--hyprpm/src/core/DataState.hpp8
-rw-r--r--hyprpm/src/core/Plugin.cpp48
-rw-r--r--hyprpm/src/core/Plugin.hpp23
-rw-r--r--hyprpm/src/core/PluginManager.cpp45
-rw-r--r--hyprpm/src/core/PluginManager.hpp8
-rw-r--r--hyprpm/src/main.cpp38
7 files changed, 160 insertions, 67 deletions
diff --git a/hyprpm/src/core/DataState.cpp b/hyprpm/src/core/DataState.cpp
index 42f1d428..64f3cfa0 100644
--- a/hyprpm/src/core/DataState.cpp
+++ b/hyprpm/src/core/DataState.cpp
@@ -93,6 +93,7 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
auto DATA = toml::table{
{"repository", toml::table{
{"name", repo.name},
+ {"author", repo.author},
{"hash", repo.hash},
{"url", repo.url},
{"rev", repo.rev}
@@ -122,31 +123,32 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
Debug::die("{}", failureString("Failed to write plugin state"));
}
-bool DataState::pluginRepoExists(const std::string& urlOrName) {
+bool DataState::pluginRepoExists(const SPluginRepoIdentifier identifier) {
ensureStateStoreExists();
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("");
+ const auto STATE = toml::parse_file(stateFile.c_str());
+ const auto NAME = STATE["repository"]["name"].value_or("");
+ const auto AUTHOR = STATE["repository"]["author"].value_or("");
+ const auto URL = STATE["repository"]["url"].value_or("");
- if (URL == urlOrName || NAME == urlOrName)
+ if (identifier.matches(URL, NAME, AUTHOR))
return true;
}
return false;
}
-void DataState::removePluginRepo(const std::string& urlOrName) {
+void DataState::removePluginRepo(const SPluginRepoIdentifier identifier) {
ensureStateStoreExists();
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) {
+ const auto STATE = toml::parse_file(stateFile.c_str());
+ const auto NAME = STATE["repository"]["name"].value_or("");
+ const auto AUTHOR = STATE["repository"]["author"].value_or("");
+ const auto URL = STATE["repository"]["url"].value_or("");
+ if (identifier.matches(URL, NAME, AUTHOR)) {
// unload the plugins!!
for (const auto& file : std::filesystem::directory_iterator(stateFile.parent_path())) {
if (!file.path().string().ends_with(".so"))
@@ -219,16 +221,18 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
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("");
- const auto REV = STATE["repository"]["rev"].value_or("");
- const auto HASH = STATE["repository"]["hash"].value_or("");
+ const auto NAME = STATE["repository"]["name"].value_or("");
+ const auto AUTHOR = STATE["repository"]["author"].value_or("");
+ const auto URL = STATE["repository"]["url"].value_or("");
+ const auto REV = STATE["repository"]["rev"].value_or("");
+ const auto HASH = STATE["repository"]["hash"].value_or("");
SPluginRepository repo;
- repo.hash = HASH;
- repo.name = NAME;
- repo.url = URL;
- repo.rev = REV;
+ repo.hash = HASH;
+ repo.name = NAME;
+ repo.author = AUTHOR;
+ repo.url = URL;
+ repo.rev = REV;
for (const auto& [key, val] : STATE) {
if (key == "repository")
@@ -247,7 +251,7 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
return repos;
}
-bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
+bool DataState::setPluginEnabled(const SPluginRepoIdentifier identifier, bool enabled) {
ensureStateStoreExists();
for (const auto& stateFile : getPluginStates()) {
@@ -256,8 +260,17 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
if (key == "repository")
continue;
- if (key.str() != name)
- continue;
+ switch (identifier.type) {
+ case IDENTIFIER_NAME:
+ if (key.str() != identifier.name)
+ continue;
+ break;
+ case IDENTIFIER_AUTHOR_NAME:
+ if (STATE["repository"]["author"] != identifier.author || key.str() != identifier.name)
+ continue;
+ break;
+ default: return false;
+ }
const auto FAILED = STATE[key]["failed"].value_or(false);
diff --git a/hyprpm/src/core/DataState.hpp b/hyprpm/src/core/DataState.hpp
index dfab535a..d9872b90 100644
--- a/hyprpm/src/core/DataState.hpp
+++ b/hyprpm/src/core/DataState.hpp
@@ -15,11 +15,11 @@ namespace DataState {
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 removePluginRepo(const SPluginRepoIdentifier identifier);
+ bool pluginRepoExists(const SPluginRepoIdentifier identifier);
void updateGlobalState(const SGlobalState& state);
void purgeAllCache();
SGlobalState getGlobalState();
- bool setPluginEnabled(const std::string& name, bool enabled);
+ bool setPluginEnabled(const SPluginRepoIdentifier identifier, bool enabled);
std::vector<SPluginRepository> getAllRepositories();
-}; \ No newline at end of file
+};
diff --git a/hyprpm/src/core/Plugin.cpp b/hyprpm/src/core/Plugin.cpp
new file mode 100644
index 00000000..3aaa8592
--- /dev/null
+++ b/hyprpm/src/core/Plugin.cpp
@@ -0,0 +1,48 @@
+#include "Plugin.hpp"
+
+SPluginRepoIdentifier SPluginRepoIdentifier::fromUrl(const std::string& url) {
+ return SPluginRepoIdentifier{.type = IDENTIFIER_URL, .url = url};
+}
+
+SPluginRepoIdentifier SPluginRepoIdentifier::fromName(const std::string& name) {
+ return SPluginRepoIdentifier{.type = IDENTIFIER_NAME, .name = name};
+}
+
+SPluginRepoIdentifier SPluginRepoIdentifier::fromAuthorName(const std::string& author, const std::string& name) {
+ return SPluginRepoIdentifier{.type = IDENTIFIER_AUTHOR_NAME, .name = name, .author = author};
+}
+
+SPluginRepoIdentifier SPluginRepoIdentifier::fromString(const std::string& string) {
+ if (string.find(':') != std::string::npos) {
+ return SPluginRepoIdentifier{.type = IDENTIFIER_URL, .url = string};
+ } else {
+ auto slashPos = string.find('/');
+ if (slashPos != std::string::npos) {
+ std::string author = string.substr(0, slashPos);
+ std::string name = string.substr(slashPos + 1, string.size() - slashPos - 1);
+ return SPluginRepoIdentifier{.type = IDENTIFIER_AUTHOR_NAME, .name = name, .author = author};
+ } else {
+ return SPluginRepoIdentifier{.type = IDENTIFIER_NAME, .name = string};
+ }
+ }
+}
+
+std::string SPluginRepoIdentifier::toString() const {
+ switch (type) {
+ case IDENTIFIER_NAME: return name;
+ case IDENTIFIER_AUTHOR_NAME: return author + '/' + name;
+ case IDENTIFIER_URL: return url;
+ }
+
+ return "";
+}
+
+bool SPluginRepoIdentifier::matches(const std::string& url, const std::string& name, const std::string& author) const {
+ switch (type) {
+ case IDENTIFIER_URL: return this->url == url;
+ case IDENTIFIER_NAME: return this->name == name;
+ case IDENTIFIER_AUTHOR_NAME: return this->author == author && this->name == name;
+ }
+
+ return false;
+}
diff --git a/hyprpm/src/core/Plugin.hpp b/hyprpm/src/core/Plugin.hpp
index e66031c9..a8c74084 100644
--- a/hyprpm/src/core/Plugin.hpp
+++ b/hyprpm/src/core/Plugin.hpp
@@ -14,6 +14,27 @@ struct SPluginRepository {
std::string url;
std::string rev;
std::string name;
+ std::string author;
std::vector<SPlugin> plugins;
std::string hash;
-}; \ No newline at end of file
+};
+
+enum ePluginRepoIdentifierType {
+ IDENTIFIER_URL,
+ IDENTIFIER_NAME,
+ IDENTIFIER_AUTHOR_NAME
+};
+
+struct SPluginRepoIdentifier {
+ ePluginRepoIdentifierType type;
+ std::string url = "";
+ std::string name = "";
+ std::string author = "";
+
+ static SPluginRepoIdentifier fromString(const std::string& string);
+ static SPluginRepoIdentifier fromUrl(const std::string& Url);
+ static SPluginRepoIdentifier fromName(const std::string& name);
+ static SPluginRepoIdentifier fromAuthorName(const std::string& author, const std::string& name);
+ std::string toString() const;
+ bool matches(const std::string& url, const std::string& name, const std::string& author) const;
+};
diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp
index ed952eec..0d35b4ae 100644
--- a/hyprpm/src/core/PluginManager.cpp
+++ b/hyprpm/src/core/PluginManager.cpp
@@ -11,6 +11,7 @@
#include <cstdio>
#include <iostream>
#include <filesystem>
+#include <string>
#include <print>
#include <fstream>
#include <algorithm>
@@ -136,7 +137,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
return false;
}
- if (DataState::pluginRepoExists(url)) {
+ if (DataState::pluginRepoExists(SPluginRepoIdentifier::fromUrl(url))) {
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Repository already installed."));
return false;
}
@@ -333,10 +334,13 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::string repohash = execAndGet("cd " + m_szWorkingPluginDirectory + " && git rev-parse HEAD");
if (repohash.length() > 0)
repohash.pop_back();
- repo.name = pManifest->m_repository.name.empty() ? url.substr(url.find_last_of('/') + 1) : pManifest->m_repository.name;
- repo.url = url;
- repo.rev = rev;
- repo.hash = repohash;
+ auto lastSlash = url.find_last_of('/');
+ auto secondLastSlash = url.find_last_of('/', lastSlash - 1);
+ repo.name = pManifest->m_repository.name.empty() ? url.substr(lastSlash + 1) : pManifest->m_repository.name;
+ repo.author = url.substr(secondLastSlash + 1, lastSlash - secondLastSlash - 1);
+ repo.url = url;
+ repo.rev = rev;
+ repo.hash = repohash;
for (auto const& p : pManifest->m_plugins) {
repo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, false, p.failed});
}
@@ -356,13 +360,13 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
return true;
}
-bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
- if (!DataState::pluginRepoExists(urlOrName)) {
+bool CPluginManager::removePluginRepo(const SPluginRepoIdentifier identifier) {
+ if (!DataState::pluginRepoExists(identifier)) {
std::println(stderr, "\n{}", failureString("Could not remove the repository. Repository is not installed."));
return false;
}
- std::cout << Colors::YELLOW << "!" << Colors::RESET << Colors::RED << " removing a plugin repository: " << Colors::RESET << urlOrName << "\n "
+ std::cout << Colors::YELLOW << "!" << Colors::RESET << Colors::RED << " removing a plugin repository: " << Colors::RESET << identifier.toString() << "\n "
<< "Are you sure? [Y/n] ";
std::fflush(stdout);
std::string input;
@@ -373,7 +377,7 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
return false;
}
- DataState::removePluginRepo(urlOrName);
+ DataState::removePluginRepo(identifier);
return true;
}
@@ -444,7 +448,6 @@ eHeadersErrors CPluginManager::headersValid() {
}
bool CPluginManager::updateHeaders(bool force) {
-
DataState::ensureStateStoreExists();
const auto HLVER = getHyprlandVersion(false);
@@ -772,7 +775,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
const auto OLDPLUGINIT = std::find_if(repo.plugins.begin(), repo.plugins.end(), [&](const auto& other) { return other.name == p.name; });
newrepo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, OLDPLUGINIT != repo.plugins.end() ? OLDPLUGINIT->enabled : false});
}
- DataState::removePluginRepo(newrepo.name);
+ DataState::removePluginRepo(SPluginRepoIdentifier::fromName(newrepo.name));
DataState::addNewPluginRepo(newrepo);
std::filesystem::remove_all(m_szWorkingPluginDirectory);
@@ -797,17 +800,23 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
return true;
}
-bool CPluginManager::enablePlugin(const std::string& name) {
- bool ret = DataState::setPluginEnabled(name, true);
+bool CPluginManager::enablePlugin(const SPluginRepoIdentifier identifier) {
+ bool ret = false;
+
+ switch (identifier.type) {
+ case IDENTIFIER_NAME:
+ case IDENTIFIER_AUTHOR_NAME: ret = DataState::setPluginEnabled(identifier, true); break;
+ default: return false;
+ }
if (ret)
- std::println("{}", successString("Enabled {}", name));
+ std::println("{}", successString("Enabled {}", identifier.name));
return ret;
}
-bool CPluginManager::disablePlugin(const std::string& name) {
- bool ret = DataState::setPluginEnabled(name, false);
+bool CPluginManager::disablePlugin(const SPluginRepoIdentifier identifier) {
+ bool ret = DataState::setPluginEnabled(identifier, false);
if (ret)
- std::println("{}", successString("Disabled {}", name));
+ std::println("{}", successString("Disabled {}", identifier.name));
return ret;
}
@@ -928,7 +937,7 @@ void CPluginManager::listAllPlugins() {
const auto REPOS = DataState::getAllRepositories();
for (auto const& r : REPOS) {
- std::println("{}", infoString("Repository {}:", r.name));
+ std::println("{}", infoString("Repository {} (by {}):", r.name, r.author));
for (auto const& p : r.plugins) {
std::println(" │ Plugin {}", p.name);
diff --git a/hyprpm/src/core/PluginManager.hpp b/hyprpm/src/core/PluginManager.hpp
index 2425f5ec..10a71469 100644
--- a/hyprpm/src/core/PluginManager.hpp
+++ b/hyprpm/src/core/PluginManager.hpp
@@ -2,8 +2,10 @@
#include <cstdint>
#include <memory>
+#include <optional>
#include <string>
#include <utility>
+#include "Plugin.hpp"
enum eHeadersErrors {
HEADERS_OK = 0,
@@ -46,7 +48,7 @@ class CPluginManager {
CPluginManager();
bool addNewPluginRepo(const std::string& url, const std::string& rev);
- bool removePluginRepo(const std::string& urlOrName);
+ bool removePluginRepo(const SPluginRepoIdentifier identifier);
eHeadersErrors headersValid();
bool updateHeaders(bool force = false);
@@ -54,8 +56,8 @@ class CPluginManager {
void listAllPlugins();
- bool enablePlugin(const std::string& name);
- bool disablePlugin(const std::string& name);
+ bool enablePlugin(const SPluginRepoIdentifier identifier);
+ bool disablePlugin(const SPluginRepoIdentifier identifier);
ePluginLoadStateReturn ensurePluginsLoadState(bool forceReload = false);
bool loadUnloadPlugin(const std::string& path, bool load);
diff --git a/hyprpm/src/main.cpp b/hyprpm/src/main.cpp
index 817049ff..dced58e7 100644
--- a/hyprpm/src/main.cpp
+++ b/hyprpm/src/main.cpp
@@ -13,25 +13,25 @@ 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
-┃ 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.
-┣ reload → Reload hyprpm state. Ensure all enabled plugins are loaded.
-┣ list → List all installed plugins.
-┣ purge-cache → Remove the entire hyprpm cache, built plugins, hyprpm settings and headers.
+┣ add <url> [git rev] → Install a new plugin repository from git. Git revision
+┃ is optional, when set, commit locks are ignored.
+┣ remove <url|name|author/name> → Remove an installed plugin repository.
+┣ enable <name|author/name> → Enable a plugin.
+┣ disable <name|author/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.
+┣ purge-cache → Remove the entire hyprpm cache, built plugins, hyprpm settings and headers.
┃
┣ Flags:
┃
-┣ --notify | -n → Send a hyprland notification confirming successful plugin load.
-┃ Warnings/Errors trigger notifications regardless of this flag.
-┣ --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 confirming successful plugin load.
+┃ Warnings/Errors trigger notifications regardless of this flag.
+┣ --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.
┗
)#";
@@ -126,7 +126,7 @@ int main(int argc, char** argv, char** envp) {
NSys::root::cacheSudo();
CScopeGuard x([] { NSys::root::dropSudo(); });
- return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
+ return g_pPluginManager->removePluginRepo(SPluginRepoIdentifier::fromString(command[1])) ? 0 : 1;
} else if (command[0] == "update") {
NSys::root::cacheSudo();
CScopeGuard x([] { NSys::root::dropSudo(); });
@@ -160,7 +160,7 @@ int main(int argc, char** argv, char** envp) {
return 1;
}
- if (!g_pPluginManager->enablePlugin(command[1])) {
+ if (!g_pPluginManager->enablePlugin(SPluginRepoIdentifier::fromString(command[1]))) {
std::println(stderr, "{}", failureString("Couldn't enable plugin (missing?)"));
return 1;
}
@@ -181,7 +181,7 @@ int main(int argc, char** argv, char** envp) {
return 1;
}
- if (!g_pPluginManager->disablePlugin(command[1])) {
+ if (!g_pPluginManager->disablePlugin(SPluginRepoIdentifier::fromString(command[1]))) {
std::println(stderr, "{}", failureString("Couldn't disable plugin (missing?)"));
return 1;
}