hyprpm: convert std::cout and std::cerr to std::println()

This commit is contained in:
Toni500git 2024-10-13 14:23:33 +02:00 committed by Vaxry
parent 1822707c7e
commit e79d3cd2ef
7 changed files with 202 additions and 159 deletions

View file

@ -1,6 +1,6 @@
#include "DataState.hpp"
#include <toml++/toml.hpp>
#include <iostream>
#include <print>
#include <filesystem>
#include <fstream>
#include "PluginManager.hpp"
@ -8,7 +8,7 @@
std::string DataState::getDataStatePath() {
const auto HOME = getenv("HOME");
if (!HOME) {
std::cerr << "DataState: no $HOME\n";
std::println(stderr, "DataState: no $HOME");
throw std::runtime_error("no $HOME");
return "";
}
@ -242,4 +242,4 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
}
return false;
}
}

View file

@ -1,12 +1,15 @@
#include "PluginManager.hpp"
#include "../helpers/Colors.hpp"
#include "../helpers/StringUtils.hpp"
#include "../progress/CProgressBar.hpp"
#include "Manifest.hpp"
#include "DataState.hpp"
#include <cstdio>
#include <iostream>
#include <array>
#include <filesystem>
#include <print>
#include <thread>
#include <fstream>
#include <algorithm>
@ -31,6 +34,7 @@ static std::string execAndGet(std::string cmd) {
if (!pipe)
return "";
result.reserve(buffer.size());
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
@ -47,10 +51,10 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() {
once = true;
const auto HLVERCALL = execAndGet("hyprctl version");
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "version returned: " << HLVERCALL << "\n";
std::println("{}", verboseString("version returned: {}", HLVERCALL));
if (!HLVERCALL.contains("Tag:")) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " You don't seem to be running Hyprland.";
std::println(stderr, "\n{}", failureString("You don't seem to be running Hyprland."));
return SHyprlandVersion{};
}
@ -76,7 +80,7 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() {
} catch (...) { ; }
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "parsed commit " << hlcommit << " at branch " << hlbranch << " on " << hldate << ", commits " << commits << "\n";
std::println("{}", verboseString("parsed commit {} at branch {} on {}, commits {}", hlcommit, hlbranch, hldate, commits));
ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits};
return ver;
@ -102,20 +106,21 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
const auto HLVER = getHyprlandVersion();
if (!hasDeps()) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n";
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio"));
return false;
}
if (DataState::pluginRepoExists(url)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n";
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Repository already installed."));
return false;
}
auto GLOBALSTATE = DataState::getGlobalState();
if (!GLOBALSTATE.dontWarnInstall) {
std::cout << Colors::YELLOW << "!" << Colors::RED << " Disclaimer:\n " << Colors::RESET
<< "plugins, especially not official, have no guarantee of stability, availablity or security.\n Run them at your own risk.\n "
<< "This message will not appear again.\n";
std::println("{}!{} Disclaimer: {}", Colors::YELLOW, Colors::RED, Colors::RESET);
std::println("plugins, especially not official, have no guarantee of stability, availablity or security.\n"
"Run them at your own risk.\n"
"This message will not appear again.");
GLOBALSTATE.dontWarnInstall = true;
DataState::updateGlobalState(GLOBALSTATE);
}
@ -129,7 +134,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::getline(std::cin, input);
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
std::cout << "Aborting.\n";
std::println(stderr, "Aborting.");
return false;
}
@ -144,7 +149,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::filesystem::create_directory("/tmp/hyprpm");
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
} else if (!std::filesystem::is_directory("/tmp/hyprpm")) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not prepare working dir for hyprpm\n";
std::println(stderr, "\n{}", failureString("Could not prepare working dir for hyprpm"));
return false;
}
@ -153,59 +158,59 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME;
if (!createSafeDirectory(m_szWorkingPluginDirectory)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not prepare working dir for repo\n";
std::println(stderr, "\n{}", failureString("Could not prepare working dir for repo"));
return false;
}
progress.printMessageAbove(std::string{Colors::RESET} + " → Cloning " + url);
progress.printMessageAbove(infoString("Cloning {}", url));
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + url + " " + USERNAME);
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. shell returned:\n" << ret << "\n";
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. shell returned:\n{}", ret));
return false;
}
if (!rev.empty()) {
std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + rev);
if (ret.compare(0, 6, "fatal:") == 0) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n";
std::println(stderr, "\n{}", failureString("Could not check out revision {}. shell returned:\n{}", rev, ret));
return false;
}
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n";
std::println("{}", verboseString("git submodule update --init returned: {}", ret));
}
progress.m_iSteps = 1;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " cloned");
progress.printMessageAbove(successString("cloned"));
progress.m_szCurrentMessage = "Reading the manifest";
progress.print();
std::unique_ptr<CManifest> pManifest;
if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) {
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprpm manifest");
progress.printMessageAbove(successString("found hyprpm manifest"));
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml");
} else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) {
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprload manifest");
progress.printMessageAbove(successString("found hyprload manifest"));
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml");
}
if (!pManifest) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n";
std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest"));
return false;
}
if (!pManifest->m_bGood) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n";
std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest"));
return false;
}
progress.m_iSteps = 2;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:");
progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:"));
for (auto const& pl : pManifest->m_vPlugins) {
std::string message = std::string{Colors::RESET} + " " + pl.name + " by ";
std::string message = "" + pl.name + " by ";
for (auto const& a : pl.authors) {
message += a + ", ";
}
@ -220,19 +225,19 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
if (!pManifest->m_sRepository.commitPins.empty()) {
// check commit pins
progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size()));
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash)
continue;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin));
execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin);
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n";
std::println("{}", verboseString("git submodule update --init returned: {}", ret));
break;
}
@ -244,12 +249,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
const auto HEADERSSTATUS = headersValid();
if (HEADERSSTATUS != HEADERS_OK) {
std::cerr << "\n" << headerError(HEADERSSTATUS);
std::println("\n{}", headerError(HEADERSSTATUS));
return false;
}
progress.m_iSteps = 3;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " Hyprland headers OK");
progress.printMessageAbove(successString("Hyprland headers OK"));
progress.m_szCurrentMessage = "Building plugin(s)";
progress.print();
@ -257,35 +262,36 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::string out;
if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n");
progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name));
p.failed = true;
continue;
}
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
progress.printMessageAbove(infoString("Building {}", p.name));
for (auto const& bs : p.buildSteps) {
std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
}
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
std::println("{}", verboseString("shell returned: " + out));
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Plugin " + p.name + " failed to build.\n" +
" This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update "
"first.\n Try re-running with -v to see "
"more verbose output.\n");
progress.printMessageAbove(failureString("Plugin {} failed to build.\n"
" This likely means that the plugin is either outdated, not yet available for your version, or broken.\n"
" If you are on -git, update first\n"
" Try re-running with -v to see more verbose output.\n",
p.name));
p.failed = true;
continue;
}
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " built " + p.name + " into " + p.output);
progress.printMessageAbove(successString("built {} into {}", p.name, p.output));
}
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " all plugins built");
progress.printMessageAbove(successString("all plugins built"));
progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing repository";
progress.print();
@ -304,13 +310,13 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
}
DataState::addNewPluginRepo(repo);
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " installed repository");
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " you can now enable the plugin(s) with hyprpm enable");
progress.printMessageAbove(successString("installed repository"));
progress.printMessageAbove(successString("you can now enable the plugin(s) with hyprpm enable"));
progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Done!";
progress.print();
std::cout << "\n";
std::print("\n");
// remove build files
std::filesystem::remove_all(m_szWorkingPluginDirectory);
@ -320,7 +326,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
if (!DataState::pluginRepoExists(urlOrName)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not remove the repository. Repository is not installed.\n";
std::println(stderr, "\n{}", failureString("Could not remove the repository. Repository is not installed."));
return false;
}
@ -331,7 +337,7 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
std::getline(std::cin, input);
if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') {
std::cout << "Aborting.\n";
std::println("Aborting.");
return false;
}
@ -347,15 +353,15 @@ eHeadersErrors CPluginManager::headersValid() {
return HEADERS_MISSING;
// find headers commit
std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
auto headers = execAndGet(cmd.c_str());
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());
if (!headers.contains("-I/"))
return HEADERS_MISSING;
headers.pop_back(); // pop newline
std::string verHeader = "";
std::string verHeader;
while (!headers.empty()) {
const auto PATH = headers.substr(0, headers.find(" -I/", 3));
@ -406,7 +412,7 @@ bool CPluginManager::updateHeaders(bool force) {
const auto HLVER = getHyprlandVersion();
if (!hasDeps()) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n";
std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio"));
return false;
}
@ -416,7 +422,7 @@ bool CPluginManager::updateHeaders(bool force) {
}
if (!force && headersValid() == HEADERS_OK) {
std::cout << "\n" << std::string{Colors::GREEN} + "" + Colors::RESET + " Headers up to date.\n";
std::println("\n{}", successString("Headers up to date."));
return true;
}
@ -430,11 +436,11 @@ bool CPluginManager::updateHeaders(bool force) {
const auto WORKINGDIR = "/tmp/hyprpm/hyprland-" + USERNAME;
if (!createSafeDirectory(WORKINGDIR)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not prepare working dir for hl\n";
std::println("\n{}", failureString("Could not prepare working dir for hl"));
return false;
}
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment.");
progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning https://github.com/hyprwm/Hyprland, this might take a moment."));
const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow;
@ -443,60 +449,60 @@ bool CPluginManager::updateHeaders(bool force) {
const std::string SHALLOW_DATE = trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+%a %b %d %H:%M:%S %Y'");
if (m_bVerbose && bShallow)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE);
progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE));
std::string ret =
execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : ""));
execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : ""));
if (!std::filesystem::exists(WORKINGDIR)) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Clone failed. Retrying without shallow.");
progress.printMessageAbove(failureString("Clone failed. Retrying without shallow."));
ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME);
}
if (!std::filesystem::exists(WORKINGDIR + "/.git")) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the hyprland repository. shell returned:\n" << ret << "\n";
std::println(stderr, "\n{}", failureString("Could not clone the Hyprland repository. shell returned:\n{}", ret));
return false;
}
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " cloned");
progress.printMessageAbove(successString("Hyprland cloned"));
progress.m_iSteps = 2;
progress.m_szCurrentMessage = "Checking out sources";
progress.print();
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will run: " + "cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
progress.printMessageAbove(verboseString("will run: cd {} && git checkout {} 2>&1", WORKINGDIR, HLVER.hash));
ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
if (ret.contains("fatal: unable to read tree")) {
std::cerr << "\n"
<< Colors::RED << "" << Colors::RESET
<< " Could not checkout the running Hyprland commit. If you are on -git, try updating.\nYou can also try re-running hyprpm update with --no-shallow.\n";
std::println(stderr, "\n{}",
failureString("Could not checkout the running Hyprland commit. If you are on -git, try updating.\n"
"You can also try re-running hyprpm update with --no-shallow."));
return false;
}
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret);
progress.printMessageAbove(verboseString("git returned (co): {}", ret));
ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash);
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (rs): " + ret);
progress.printMessageAbove(verboseString("git returned (rs): {}", ret));
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " checked out to running ver");
progress.printMessageAbove(successString("checked out to running ver"));
progress.m_iSteps = 3;
progress.m_szCurrentMessage = "Building Hyprland";
progress.print();
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " configuring Hyprland");
progress.printMessageAbove(statusString("!", Colors::YELLOW, "configuring Hyprland"));
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "setting PREFIX for cmake to " + DataState::getHeadersPath());
progress.printMessageAbove(verboseString("setting PREFIX for cmake to {}", DataState::getHeadersPath()));
ret = execAndGet(std::format("cd {} && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja", WORKINGDIR,
DataState::getHeadersPath()));
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
progress.printMessageAbove(verboseString("cmake returned: {}", ret));
if (ret.contains("CMake Error at")) {
// missing deps, let the user know.
@ -505,48 +511,46 @@ bool CPluginManager::updateHeaders(bool force) {
missing = missing.substr(0, missing.find("-- Configuring incomplete"));
missing = missing.substr(0, missing.find_last_of('\n'));
std::cerr << "\n"
<< Colors::RED << "" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n"
<< missing << "\n\nThis likely means that you are missing the above dependencies or they are out of date.\n";
std::println(stderr, "\n{}",
failureString("Could not configure the hyprland source, cmake complained:\n{}\n\n"
"This likely means that you are missing the above dependencies or they are out of date.",
missing));
return false;
}
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " configured Hyprland");
progress.printMessageAbove(successString("configured Hyprland"));
progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing sources";
progress.print();
std::string cmd =
const std::string& cmd =
std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR);
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "installation will run: " + cmd);
progress.printMessageAbove(verboseString("installation will run: {}", cmd));
ret = execAndGet(cmd);
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "installer returned: " << ret << "\n";
std::println("{}", verboseString("installer returned: {}", ret));
// remove build files
std::filesystem::remove_all(WORKINGDIR);
auto HEADERSVALID = headersValid();
if (HEADERSVALID == HEADERS_OK) {
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " installed headers");
progress.printMessageAbove(successString("installed headers"));
progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Done!";
progress.print();
std::cout << "\n";
std::print("\n");
} else {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID) + " (" +
headerErrorShort(HEADERSVALID) + ")");
progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID)));
progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Failed";
progress.print();
std::cout << "\n";
std::cerr << "\n" << headerError(HEADERSVALID);
std::print(stderr, "\n\n{}", headerError(HEADERSVALID));
return false;
}
@ -556,14 +560,14 @@ bool CPluginManager::updateHeaders(bool force) {
bool CPluginManager::updatePlugins(bool forceUpdateAll) {
if (headersValid() != HEADERS_OK) {
std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n";
std::println("{}", failureString("headers are not up-to-date, please run hyprpm update."));
return false;
}
const auto REPOS = DataState::getAllRepositories();
if (REPOS.size() < 1) {
std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " No repos to update.\n";
std::println("{}", failureString("No repos to update."));
return true;
}
@ -585,25 +589,26 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.m_szCurrentMessage = "Updating " + repo.name;
progress.print();
progress.printMessageAbove(std::string{Colors::RESET} + " → checking for updates for " + repo.name);
progress.printMessageAbove(infoString("checking for updates for {}", repo.name));
createSafeDirectory(m_szWorkingPluginDirectory);
progress.printMessageAbove(std::string{Colors::RESET} + " → Cloning " + repo.url);
progress.printMessageAbove(infoString("Cloning {}", repo.url));
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + repo.url + " " + USERNAME);
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) {
std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " could not clone repo: shell returned:\n" + ret;
std::println("{}", failureString("could not clone repo: shell returned: {}", ret));
return false;
}
if (!repo.rev.empty()) {
progress.printMessageAbove(std::string{Colors::RESET} + " → Plugin has revision set, resetting: " + repo.rev);
progress.printMessageAbove(infoString("Plugin has revision set, resetting: {}", repo.rev));
std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + repo.rev);
if (ret.compare(0, 6, "fatal:") == 0) {
std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " could not check out revision " + repo.rev + ": shell returned:\n" + ret;
std::println(stderr, "\n{}", failureString("could not check out revision {}: shell returned:\n{}", repo.rev, ret));
return false;
}
}
@ -619,7 +624,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
if (!update) {
std::filesystem::remove_all(m_szWorkingPluginDirectory);
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " repository " + repo.name + " is up-to-date.");
progress.printMessageAbove(successString("repository {} is up-to-date.", repo.name));
progress.m_iSteps++;
progress.print();
continue;
@ -627,41 +632,41 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
// we need to update
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " repository " + repo.name + " has updates.");
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + repo.name);
progress.printMessageAbove(successString("repository {} has updates.", repo.name));
progress.printMessageAbove(infoString("Building {}", repo.name));
progress.m_iSteps++;
progress.print();
std::unique_ptr<CManifest> pManifest;
if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) {
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprpm manifest");
progress.printMessageAbove(successString("found hyprpm manifest"));
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml");
} else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) {
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " found hyprload manifest");
progress.printMessageAbove(successString("found hyprload manifest"));
pManifest = std::make_unique<CManifest>(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml");
}
if (!pManifest) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n";
std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest"));
continue;
}
if (!pManifest->m_bGood) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n";
std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest"));
continue;
}
if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) {
// check commit pins unless a revision is specified
progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size()));
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash)
continue;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin));
execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin);
}
@ -671,32 +676,33 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
std::string out;
if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n");
progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name));
p.failed = true;
continue;
}
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
progress.printMessageAbove(infoString("Building {}", p.name));
for (auto const& bs : p.buildSteps) {
std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
}
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
std::println("{}", verboseString("shell returned: {}", out));
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) {
std::cerr << "\n"
<< Colors::RED << "" << Colors::RESET << " Plugin " << p.name << " failed to build.\n"
<< " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update first.\n Try "
"re-running with -v to see more verbose "
"output.\n";
std::println(stderr,
"\n{}\n"
" This likely means that the plugin is either outdated, not yet available for your version, or broken.\n"
"If you are on -git, update first.\n"
"Try re-running with -v to see more verbose output.",
failureString("Plugin {} failed to build."));
p.failed = true;
continue;
}
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " built " + p.name + " into " + p.output);
progress.printMessageAbove(successString("built {} into {}", p.name, p.output));
}
// add repo toml to DataState
@ -717,7 +723,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
std::filesystem::remove_all(m_szWorkingPluginDirectory);
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " updated " + repo.name);
progress.printMessageAbove(successString("updated {}", repo.name));
}
progress.m_iSteps++;
@ -732,7 +738,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.m_szCurrentMessage = "Done!";
progress.print();
std::cout << "\n";
std::print("\n");
return true;
}
@ -740,27 +746,27 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
bool CPluginManager::enablePlugin(const std::string& name) {
bool ret = DataState::setPluginEnabled(name, true);
if (ret)
std::cout << Colors::GREEN << "" << Colors::RESET << " Enabled " << name << "\n";
std::println("{}", successString("Enabled {}", name));
return ret;
}
bool CPluginManager::disablePlugin(const std::string& name) {
bool ret = DataState::setPluginEnabled(name, false);
if (ret)
std::cout << Colors::GREEN << "" << Colors::RESET << " Disabled " << name << "\n";
std::println("{}", successString("Disabled {}", name));
return ret;
}
ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
if (headersValid() != HEADERS_OK) {
std::cerr << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n";
std::println(stderr, "\n{}", failureString("headers are not up-to-date, please run hyprpm update."));
return LOADSTATE_HEADERS_OUTDATED;
}
const auto HOME = getenv("HOME");
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!HOME || !HIS) {
std::cerr << "PluginManager: no $HOME or HIS\n";
std::println(stderr, "PluginManager: no $HOME or HIS");
return LOADSTATE_FAIL;
}
const auto HYPRPMPATH = DataState::getDataStatePath() + "/";
@ -769,14 +775,14 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
std::vector<std::string> loadedPlugins;
std::cout << Colors::GREEN << "" << Colors::RESET << " Ensuring plugin load state\n";
std::println("{}", successString("Ensuring plugin load state"));
// iterate line by line
while (!pluginLines.empty()) {
auto plLine = pluginLines.substr(0, pluginLines.find("\n"));
auto plLine = pluginLines.substr(0, pluginLines.find('\n'));
if (pluginLines.find("\n") != std::string::npos)
pluginLines = pluginLines.substr(pluginLines.find("\n") + 1);
if (pluginLines.find('\n') != std::string::npos)
pluginLines = pluginLines.substr(pluginLines.find('\n') + 1);
else
pluginLines = "";
@ -819,7 +825,7 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
if (!enabled(p)) {
// unload
loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false);
std::cout << Colors::GREEN << "" << Colors::RESET << " Unloaded " << p << "\n";
std::println("{}", successString("Unloaded {}", p));
}
}
@ -833,11 +839,11 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
continue;
loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true);
std::cout << Colors::GREEN << "" << Colors::RESET << " Loaded " << p.name << "\n";
std::println("{}", successString("Loaded {}"), p.name);
}
}
std::cout << Colors::GREEN << "" << Colors::RESET << " Plugin load state ensured\n";
std::println("{}", successString("Plugin load state ensured"));
return LOADSTATE_OK;
}
@ -855,16 +861,17 @@ void CPluginManager::listAllPlugins() {
const auto REPOS = DataState::getAllRepositories();
for (auto const& r : REPOS) {
std::cout << std::string{Colors::RESET} + " → Repository " + r.name + ":\n";
std::println("{}", infoString("Repository {}:", r.name));
for (auto const& p : r.plugins) {
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name;
std::println(" │ Plugin {}", p.name);
if (!p.failed)
std::cout << "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false") << Colors::RESET << "\n";
std::println(" └─ enabled: {}", (p.enabled ? std::string{Colors::GREEN} + "true" : std::string{Colors::RED} + "false"));
else
std::cout << "\n └─ enabled: " << Colors::RED << "Plugin failed to build" << Colors::RESET << "\n";
std::println(" └─ enabled: {}Plugin failed to build", Colors::RED);
std::println("{}", Colors::RESET);
}
}
}
@ -875,19 +882,19 @@ void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int duratio
std::string CPluginManager::headerError(const eHeadersErrors err) {
switch (err) {
case HEADERS_CORRUPTED: return std::string{Colors::RED} + "" + Colors::RESET + " Headers corrupted. Please run hyprpm update to fix those.\n";
case HEADERS_MISMATCHED: return std::string{Colors::RED} + "" + Colors::RESET + " Headers version mismatch. Please run hyprpm update to fix those.\n";
case HEADERS_NOT_HYPRLAND: return std::string{Colors::RED} + "" + Colors::RESET + " It doesn't seem you are running on hyprland.\n";
case HEADERS_MISSING: return std::string{Colors::RED} + "" + Colors::RESET + " Headers missing. Please run hyprpm update to fix those.\n";
case HEADERS_CORRUPTED: return failureString("Headers corrupted. Please run hyprpm update to fix those.\n");
case HEADERS_MISMATCHED: return failureString("Headers version mismatch. Please run hyprpm update to fix those.\n");
case HEADERS_NOT_HYPRLAND: return failureString("It doesn't seem you are running on hyprland.\n");
case HEADERS_MISSING: return failureString("Headers missing. Please run hyprpm update to fix those.\n");
case HEADERS_DUPLICATED: {
return std::string{Colors::RED} + "" + Colors::RESET + " Headers duplicated!!! This is a very bad sign.\n" +
" This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" +
" If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n";
return failureString("Headers duplicated!!! This is a very bad sign.\n"
"This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n"
"If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n");
}
default: break;
}
return std::string{Colors::RED} + "" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n";
return failureString("Unknown header error. Please run hyprpm update to fix those.\n");
}
std::string CPluginManager::headerErrorShort(const eHeadersErrors err) {

View file

@ -2,6 +2,7 @@
#include <memory>
#include <string>
#include <utility>
enum eHeadersErrors {
HEADERS_OK = 0,
@ -68,7 +69,7 @@ class CPluginManager {
std::string headerError(const eHeadersErrors err);
std::string headerErrorShort(const eHeadersErrors err);
std::string m_szWorkingPluginDirectory = "";
std::string m_szWorkingPluginDirectory;
};
inline std::unique_ptr<CPluginManager> g_pPluginManager;

View file

@ -0,0 +1,32 @@
#pragma once
#include <format>
#include <string>
#include "Colors.hpp"
template <typename... Args>
std::string statusString(const std::string_view emoji, const std::string_view color, const std::string_view fmt, Args&&... args) {
std::string ret = std::format("{}{}{} ", color, emoji, Colors::RESET);
ret += std::vformat(fmt, std::make_format_args(args...));
return ret;
}
template <typename... Args>
std::string successString(const std::string_view fmt, Args&&... args) {
return statusString("", Colors::GREEN, fmt, args...);
}
template <typename... Args>
std::string failureString(const std::string_view fmt, Args&&... args) {
return statusString("", Colors::RED, fmt, args...);
}
template <typename... Args>
std::string verboseString(const std::string_view fmt, Args&&... args) {
return statusString("[v]", Colors::BLUE, fmt, args...);
}
template <typename... Args>
std::string infoString(const std::string_view fmt, Args&&... args) {
return statusString("", Colors::RESET, fmt, args...);
}

View file

@ -1,15 +1,16 @@
#include "progress/CProgressBar.hpp"
#include "helpers/Colors.hpp"
#include "helpers/StringUtils.hpp"
#include "core/PluginManager.hpp"
#include "core/DataState.hpp"
#include <iostream>
#include <cstdio>
#include <vector>
#include <string>
#include <print>
#include <chrono>
#include <thread>
const std::string 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
is optional, when set, commit locks are ignored.
@ -30,14 +31,14 @@ const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
)#";
int main(int argc, char** argv, char** envp) {
int main(int argc, char** argv, char** envp) {
std::vector<std::string> ARGS{argc};
for (int i = 0; i < argc; ++i) {
ARGS[i] = std::string{argv[i]};
}
if (ARGS.size() < 2) {
std::cout << HELP;
std::println(stderr, "{}", HELP);
return 1;
}
@ -47,7 +48,7 @@ int main(int argc, char** argv, char** envp) {
for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) {
if (ARGS[i] == "--help" || ARGS[i] == "-h") {
std::cout << HELP;
std::println("{}", HELP);
return 0;
} else if (ARGS[i] == "--notify" || ARGS[i] == "-n") {
notify = true;
@ -57,9 +58,9 @@ int main(int argc, char** argv, char** envp) {
noShallow = true;
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
force = true;
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
std::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing."));
} else {
std::cerr << "Unrecognized option " << ARGS[i] << "\n";
std::println(stderr, "Unrecognized option {}", ARGS[i]);
return 1;
}
} else {
@ -68,7 +69,7 @@ int main(int argc, char** argv, char** envp) {
}
if (command.empty()) {
std::cout << HELP;
std::println(stderr, "{}", HELP);
return 0;
}
@ -78,7 +79,7 @@ int main(int argc, char** argv, char** envp) {
if (command[0] == "add") {
if (command.size() < 2) {
std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for add.\n";
std::println(stderr, "{}", failureString("Not enough args for add."));
return 1;
}
@ -90,7 +91,7 @@ int main(int argc, char** argv, char** envp) {
return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1;
} else if (command[0] == "remove") {
if (ARGS.size() < 2) {
std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for remove.\n";
std::println(stderr, "{}", failureString("Not enough args for remove."));
return 1;
}
@ -116,12 +117,12 @@ int main(int argc, char** argv, char** envp) {
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers");
} else if (command[0] == "enable") {
if (ARGS.size() < 2) {
std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for enable.\n";
std::println(stderr, "{}", failureString("Not enough args for enable."));
return 1;
}
if (!g_pPluginManager->enablePlugin(command[1])) {
std::cerr << Colors::RED << "" << Colors::RESET << " Couldn't enable plugin (missing?)\n";
std::println(stderr, "{}", failureString("Couldn't enable plugin (missing?)"));
return 1;
}
@ -130,12 +131,12 @@ int main(int argc, char** argv, char** envp) {
return 1;
} else if (command[0] == "disable") {
if (command.size() < 2) {
std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for disable.\n";
std::println(stderr, "{}", failureString("Not enough args for disable."));
return 1;
}
if (!g_pPluginManager->disablePlugin(command[1])) {
std::cerr << Colors::RED << "" << Colors::RESET << " Couldn't disable plugin (missing?)\n";
std::println(stderr, "{}", failureString("Couldn't disable plugin (missing?)"));
return 1;
}
@ -160,9 +161,9 @@ int main(int argc, char** argv, char** envp) {
} else if (command[0] == "list") {
g_pPluginManager->listAllPlugins();
} else {
std::cout << HELP;
std::println(stderr, "{}", HELP);
return 1;
}
return 0;
}
}

View file

@ -1,11 +1,11 @@
#include "CProgressBar.hpp"
#include <iostream>
#include <sys/ioctl.h>
#include <algorithm>
#include <cmath>
#include <format>
#include <sys/ioctl.h>
#include <print>
#include <stdio.h>
#include <unistd.h>
@ -16,11 +16,12 @@ void CProgressBar::printMessageAbove(const std::string& msg) {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
std::string spaces;
spaces.reserve(w.ws_col);
for (size_t i = 0; i < w.ws_col; ++i) {
spaces += ' ';
}
std::cout << "\r" << spaces << "\r" << msg << "\n";
std::println("\r{}\r{}", spaces, msg);
print();
}
@ -29,15 +30,16 @@ void CProgressBar::print() {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (m_bFirstPrint)
std::cout << "\n";
std::print("\n");
m_bFirstPrint = false;
std::string spaces;
spaces.reserve(w.ws_col);
for (size_t i = 0; i < w.ws_col; ++i) {
spaces += ' ';
}
std::cout << "\r" << spaces << "\r";
std::print("\r{}\r", spaces);
std::string message = "";
@ -74,7 +76,7 @@ void CProgressBar::print() {
message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " ";
// draw message
std::cout << message + " " + m_szCurrentMessage;
std::print("{} {}", message, m_szCurrentMessage);
std::fflush(stdout);
}
}

View file

@ -14,4 +14,4 @@ class CProgressBar {
private:
bool m_bFirstPrint = true;
};
};