From be552db0fbdcf5d81c13ee0ccfe9cc1aeb8c980e Mon Sep 17 00:00:00 2001 From: Riyyi Date: Sat, 25 Sep 2021 16:56:16 +0200 Subject: [PATCH] Manager: Start working on package tracking --- src/package.cpp | 153 ++++++++++++++++++++++++++++++++++++++++++++++++ src/package.h | 36 ++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 src/package.cpp create mode 100644 src/package.h diff --git a/src/package.cpp b/src/package.cpp new file mode 100644 index 0000000..fe0217c --- /dev/null +++ b/src/package.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2021 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#include +#include // fprintf, printf, stderr +#include // istringstream +#include // getline +#include + +#include "package.h" +#include "util/file.h" +#include "util/system.h" + +Package::Package() +{ +} + +Package::~Package() +{ +} + +// ----------------------------------------- + +void Package::aurInstall(const std::vector& targets) +{ +} + +void Package::install(const std::vector& targets) +{ +} + +void Package::list(const std::vector& targets) +{ + distroDetect(); + distroDependencies(); + + std::string packages; + + Util::System $; + if (m_distro == Distro::Arch) { + auto basePackages = $("pactree -u base") | $("tail -n +2"); + auto develPackages = $("pacman -Qqg base-devel"); + auto filterList = basePackages + develPackages | $("sort -u"); + auto packageList = $("pacman -Qqe") | $("grep -vx " + filterList.output()) | $("sort"); + packages = packageList.output(); + } + else if (m_distro == Distro::Debian) { + auto installedList = $("dpkg-query --show --showformat=${Package}\\t${Priority}\\n"); + auto filterList = installedList | $("grep -E required|important|standard") | $("cut -f 1"); + installedList = installedList | $("cut -f 1"); + auto installedManuallyList = $("awk '/Commandline:.* install / && !/APT::/ { print $NF }' /var/log/apt/history.log"); + installedManuallyList = (installedManuallyList + $("apt-mark showmanual")) | $("sort -u"); + auto packageList = installedManuallyList | $("grep -x " + installedList.output()) | $("grep -vx " + filterList.output()); + } + + if (targets.empty()) { + printf("%s", packages.c_str()); + return; + } + + auto stream = std::istringstream(packages); + packages.clear(); + + // FIXME: Decide on the type of match, currently 'or, any part of the string'. + std::string line; + while (std::getline(stream, line)) { + for (const auto& target : targets) { + if (line.find(target) != std::string::npos) { + packages.append(line + '\n'); + break; + } + } + } + + printf("%s", packages.c_str()); +} + +void Package::store(const std::vector& targets) +{ +} + +// ----------------------------------------- + +bool Package::distroDetect() +{ + std::string id; + std::string idLike; + + auto osRelease = Util::File("/etc/os-release"); + auto stream = std::istringstream(osRelease.data()); + std::string line; + while (std::getline(stream, line)) { + if (line.find("ID=") == 0) { + id = line.substr(3); + } + if (line.find("ID_LIKE=") == 0) { + idLike = line.substr(8); + } + } + + if (id == "arch") { + m_distro = Distro::Arch; + } + else if (id == "debian") { + m_distro = Distro::Debian; + } + else if (id == "ubuntu") { + m_distro = Distro::Debian; + } + else if (idLike.find("arch") != std::string::npos) { + m_distro = Distro::Arch; + } + else if (idLike.find("debian") != std::string::npos) { + m_distro = Distro::Debian; + } + else if (idLike.find("ubuntu") != std::string::npos) { + m_distro = Distro::Debian; + } + else { + fprintf(stderr, "\033[31;1mPackage:\033[0m unsupported distribution\n"); + return false; + } + + return true; +} + +bool Package::distroDependencies() +{ + std::vector> dependencies; + if (m_distro == Distro::Arch) { + dependencies.push_back({ "pacman", "pacman" }); + dependencies.push_back({ "pactree", "pacman-contrib" }); + } + else if (m_distro == Distro::Debian) { + dependencies.push_back({ "apt-cache", "apt" }); + dependencies.push_back({ "apt-mark", "apt" }); + dependencies.push_back({ "dpkg-query", "dpkg" }); + } + + // FIXME: Conglomerate which calls to save multiple external process creation. + Util::System $; + for (const auto& dependency : dependencies) { + if ($("which " + dependency.at(0))().status() > 0) { + fprintf(stderr, "\033[31;1mPackage:\033[0m required dependency '%s' is missing\n", dependency.at(1).c_str()); + return false; + } + } + + return true; +} diff --git a/src/package.h b/src/package.h new file mode 100644 index 0000000..fc749a0 --- /dev/null +++ b/src/package.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#ifndef PACKAGE_H +#define PACKAGE_H + +#include +#include + +class Package { +public: + Package(); + virtual ~Package(); + + enum class Distro { + Unsupported, + Arch, + Debian, + }; + + void aurInstall(const std::vector& targets = {}); + void install(const std::vector& targets = {}); + void list(const std::vector& targets = {}); + void store(const std::vector& targets = {}); + +private: + bool distroDetect(); + bool distroDependencies(); + + Distro m_distro { Distro::Unsupported }; +}; + +#endif // PACKAGE_H