From dfa5a732bab2bf4c50c6b193cb49cd3a67aef720 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 10 Mar 2025 12:16:31 +0100 Subject: [PATCH] Display packages installed from a repository --- .gitignore | 3 +- CMakeLists.txt | 20 +++++ cli/main.cpp | 166 +++-------------------------------- include/katja/database.hpp | 11 ++- include/katja/repository.hpp | 10 +++ include/katja/sbo.hpp | 29 ++++++ katja/database.cpp | 29 ++++++ katja/repository.cpp | 8 ++ katja/sbo.cpp | 139 +++++++++++++++++++++++++++++ 9 files changed, 259 insertions(+), 156 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 include/katja/repository.hpp create mode 100644 include/katja/sbo.hpp create mode 100644 katja/repository.cpp create mode 100644 katja/sbo.cpp diff --git a/.gitignore b/.gitignore index a8d7602..1c6e0ce 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /config/tea-cleaner.toml /log/ /tmp/ -CMakeLists.txt +CMakeCache.txt +CMakeFiles/ /.cache/ /build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6b3667c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.21) +project(Katja) + +set(CMAKE_EXPORT_COMPILE_COMMANDS 1) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set(CMAKE_CXX_STANDARD 17) + +find_package(Boost CONFIG COMPONENTS process program_options REQUIRED) + +add_library(backend + katja/database.cpp include/katja/database.hpp + katja/sbo.cpp include/katja/sbo.hpp + katja/repository.cpp include/katja/repository.hpp +) +target_include_directories(backend PRIVATE include ${Boost_INCLUDE_DIR}) + +add_executable(katja cli/main.cpp) +target_link_libraries(katja PRIVATE backend) +target_include_directories(katja PRIVATE include ${Boost_INCLUDE_DIR}) +target_link_libraries(katja LINK_PUBLIC ${Boost_LIBRARIES}) diff --git a/cli/main.cpp b/cli/main.cpp index 614a274..c417b83 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -1,171 +1,29 @@ #include #include -#include -#include -#include -#include + +#include "katja/sbo.hpp" #include "katja/database.hpp" -bool trim_info_line(std::string& info_value) -{ - if (boost::algorithm::ends_with(info_value, "\"")) - { - info_value.pop_back(); - return false; - } - else if (boost::algorithm::ends_with(info_value, "\\")) - { - info_value.pop_back(); - return true; - } - return false; -} - -struct info_file -{ - const std::string program_name; - const std::string version; - const std::string homepage; - const std::string email; - const std::string maintainer; - - info_file(const std::string& program_name, const std::string& version, - const std::string homepage, const std::string& email, const std::string& maintainer) - : program_name(program_name), version(version), homepage(homepage), email(email), maintainer(maintainer) - { - } -}; - -std::optional read_slackbuild_info(const std::filesystem::path& info_filepath) -{ - std::ifstream info_stream{ info_filepath }; - std::string info_line, info_variable, info_value; - std::string program_name, version, homepage, email, maintainer; - std::vector download, md5sum, download_x86_64, md5sum_x86_64, requires; - bool continuation{ false }; - - while (std::getline(info_stream, info_line)) - { - if (info_line.empty()) - { - continue; - } - else if (!continuation) - { - auto equals_position = std::find(info_line.cbegin(), info_line.cend(), '='); - info_variable = std::string(info_line.cbegin(), equals_position); - - if (equals_position == info_line.cend() - || ++equals_position == info_line.cend() || *equals_position != '"') - { - return std::nullopt; - } - info_value = std::string(std::next(equals_position), info_line.cend()); - } - else - { - info_value += info_line; - } - continuation = trim_info_line(info_value); - - if (!continuation) - { - if (info_variable == "PRGNAM") - { - std::swap(program_name, info_value); - } - else if (info_variable == "VERSION") - { - std::swap(version, info_value); - } - else if (info_variable == "HOMEPAGE") - { - std::swap(homepage, info_value); - } - else if (info_variable == "EMAIL") - { - std::swap(email, info_value); - } - else if (info_variable == "MAINTAINER") - { - std::swap(maintainer, info_value); - } - else if (info_variable == "DOWNLOAD") - { - boost::split(download, info_value, boost::is_any_of(" "), boost::token_compress_on); - } - else if (info_variable == "MD5SUM") - { - boost::split(md5sum, info_value, boost::is_any_of(" "), boost::token_compress_on); - } - else if (info_variable == "DOWNLOAD_x86_64") - { - boost::split(download_x86_64, info_value, boost::is_any_of(" "), boost::token_compress_on); - } - else if (info_variable == "MD5SUM_x86_64") - { - boost::split(md5sum_x86_64, info_value, boost::is_any_of(" "), boost::token_compress_on); - } - else if (info_variable == "REQUIRES") - { - boost::split(requires, info_value, boost::is_any_of(" "), boost::token_compress_on); - } - } - } - return std::make_optional(program_name, version, homepage, email, maintainer); -} - -void search_for_slackbuilds(std::vector& info_files, const std::filesystem::path& directory) -{ - for (const auto& entry : std::filesystem::directory_iterator(directory)) - { - std::filesystem::path entry_path = entry; - std::filesystem::path info_filename = entry_path; - info_filename.replace_extension(".info"); - - std::filesystem::path info_filepath = entry_path / info_filename; - - if (std::filesystem::exists(info_filepath)) - { - auto slackbuild_info = read_slackbuild_info(info_filepath); - - if (slackbuild_info.has_value()) - { - info_files.emplace_back(std::move(slackbuild_info.value())); - } - else - { - std::cout << info_filepath << std::endl; - } - } - else if (std::filesystem::is_directory(entry_path)) - { - search_for_slackbuilds(info_files, entry_path); - } - } -} - int main(int argc, const char **argv) { - std::vector info_files; + std::vector info_files; + std::multimap installed_database = katja::read_installed_database(); if (argc > 1) { std::filesystem::path slackbuild_repository{ argv[1] }; - search_for_slackbuilds(info_files, slackbuild_repository); + katja::search_for_slackbuilds(info_files, slackbuild_repository); for (const auto& slackbuild_info : info_files) { - std::cout << slackbuild_info.program_name << " " << slackbuild_info.version << " " << std::endl; - } - } - else - { - for (const auto& entry : std::filesystem::directory_iterator(katja::database)) - { - katja::database_package database_entry{ entry.path().filename() }; + std::multimap::const_iterator installed_package = + installed_database.find(slackbuild_info.program_name); - std::cout << database_entry.to_string() << std::endl; + if (installed_package != installed_database.cend()) + { + std::cout << slackbuild_info.program_name << " " << slackbuild_info.version + << " (installed " << installed_package->second.version << ")" << std::endl; + } } } return 0; diff --git a/include/katja/database.hpp b/include/katja/database.hpp index d4d99e6..ee4816e 100644 --- a/include/katja/database.hpp +++ b/include/katja/database.hpp @@ -1,6 +1,12 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ #pragma once #include +#include namespace katja { @@ -21,8 +27,11 @@ namespace katja database_package(const std::string& fullname); + bool operator<(const database_package& that) const; + bool operator>(const database_package& that) const; + std::string to_string() const; }; - + std::multimap read_installed_database(); } diff --git a/include/katja/repository.hpp b/include/katja/repository.hpp new file mode 100644 index 0000000..ca20277 --- /dev/null +++ b/include/katja/repository.hpp @@ -0,0 +1,10 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#pragma once + +namespace katja +{ +} diff --git a/include/katja/sbo.hpp b/include/katja/sbo.hpp new file mode 100644 index 0000000..ff16dd7 --- /dev/null +++ b/include/katja/sbo.hpp @@ -0,0 +1,29 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include +#include +#include +#include + +namespace katja +{ + struct info_file + { + const std::string program_name; + const std::string version; + const std::string homepage; + const std::string email; + const std::string maintainer; + + info_file(const std::string& program_name, const std::string& version, + const std::string homepage, const std::string& email, const std::string& maintainer); + }; + + std::optional read_slackbuild_info(const std::filesystem::path& info_filepath); + void search_for_slackbuilds(std::vector& info_files, const std::filesystem::path& directory); +} diff --git a/katja/database.cpp b/katja/database.cpp index 555e679..11e3730 100644 --- a/katja/database.cpp +++ b/katja/database.cpp @@ -1,5 +1,12 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ #include "katja/database.hpp" +#include + namespace katja { database_package database_package::create_database_package(const std::string& fullname) @@ -47,6 +54,16 @@ namespace katja { } + bool database_package::operator<(const database_package& that) const + { + return this->name < that.name; + } + + bool database_package::operator>(const database_package& that) const + { + return this->name > that.name; + } + std::string database_package::to_string() const { std::string package_string; @@ -64,4 +81,16 @@ namespace katja return package_string; } + + std::multimap read_installed_database() + { + std::multimap result; + + for (const auto& entry : std::filesystem::directory_iterator(katja::database)) + { + database_package database_entry{ entry.path().filename() }; + result.emplace(database_entry.name, database_entry); + } + return result; + } } diff --git a/katja/repository.cpp b/katja/repository.cpp new file mode 100644 index 0000000..e9a345c --- /dev/null +++ b/katja/repository.cpp @@ -0,0 +1,8 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +namespace katja +{ +} diff --git a/katja/sbo.cpp b/katja/sbo.cpp new file mode 100644 index 0000000..161e834 --- /dev/null +++ b/katja/sbo.cpp @@ -0,0 +1,139 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#include + +#include + +#include "katja/sbo.hpp" + +namespace katja +{ + info_file::info_file(const std::string& program_name, const std::string& version, + const std::string homepage, const std::string& email, const std::string& maintainer) + : program_name(program_name), version(version), homepage(homepage), email(email), maintainer(maintainer) + { + } + + bool trim_info_line(std::string& info_value) + { + if (boost::algorithm::ends_with(info_value, "\"")) + { + info_value.pop_back(); + return false; + } + else if (boost::algorithm::ends_with(info_value, "\\")) + { + info_value.pop_back(); + return true; + } + return false; + } + + std::optional read_slackbuild_info(const std::filesystem::path& info_filepath) + { + std::ifstream info_stream{ info_filepath }; + std::string info_line, info_variable, info_value; + std::string program_name, version, homepage, email, maintainer; + std::vector download, md5sum, download_x86_64, md5sum_x86_64, requires; + bool continuation{ false }; + + while (std::getline(info_stream, info_line)) + { + if (info_line.empty()) + { + continue; + } + else if (!continuation) + { + auto equals_position = std::find(info_line.cbegin(), info_line.cend(), '='); + info_variable = std::string(info_line.cbegin(), equals_position); + + if (equals_position == info_line.cend() + || ++equals_position == info_line.cend() || *equals_position != '"') + { + return std::nullopt; + } + info_value = std::string(std::next(equals_position), info_line.cend()); + } + else + { + info_value += info_line; + } + continuation = trim_info_line(info_value); + + if (!continuation) + { + if (info_variable == "PRGNAM") + { + std::swap(program_name, info_value); + } + else if (info_variable == "VERSION") + { + std::swap(version, info_value); + } + else if (info_variable == "HOMEPAGE") + { + std::swap(homepage, info_value); + } + else if (info_variable == "EMAIL") + { + std::swap(email, info_value); + } + else if (info_variable == "MAINTAINER") + { + std::swap(maintainer, info_value); + } + else if (info_variable == "DOWNLOAD") + { + boost::split(download, info_value, boost::is_any_of(" "), boost::token_compress_on); + } + else if (info_variable == "MD5SUM") + { + boost::split(md5sum, info_value, boost::is_any_of(" "), boost::token_compress_on); + } + else if (info_variable == "DOWNLOAD_x86_64") + { + boost::split(download_x86_64, info_value, boost::is_any_of(" "), boost::token_compress_on); + } + else if (info_variable == "MD5SUM_x86_64") + { + boost::split(md5sum_x86_64, info_value, boost::is_any_of(" "), boost::token_compress_on); + } + else if (info_variable == "REQUIRES") + { + boost::split(requires, info_value, boost::is_any_of(" "), boost::token_compress_on); + } + } + } + return std::make_optional(program_name, version, homepage, email, maintainer); + } + + void search_for_slackbuilds(std::vector& info_files, const std::filesystem::path& directory) + { + for (const auto& entry : std::filesystem::directory_iterator(directory)) + { + std::filesystem::path entry_path = entry; + std::filesystem::path info_filename = entry_path.filename(); + info_filename.replace_extension(".info"); + + std::filesystem::path info_filepath = entry_path / info_filename; + + if (std::filesystem::exists(info_filepath)) + { + auto slackbuild_info = read_slackbuild_info(info_filepath); + + if (slackbuild_info.has_value()) + { + info_files.emplace_back(std::move(slackbuild_info.value())); + } + } + else if (std::filesystem::is_directory(entry_path)) + { + search_for_slackbuilds(info_files, entry_path); + } + } + } +}