Move katja into a separate repository
This commit is contained in:
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -2,8 +2,4 @@ | |||||||
| /config/*.toml | /config/*.toml | ||||||
| /log/ | /log/ | ||||||
| /tmp/ | /tmp/ | ||||||
| CMakeCache.txt |  | ||||||
| CMakeFiles/ |  | ||||||
| /.cache/ |  | ||||||
| /build/ |  | ||||||
| /vendor/ | /vendor/ | ||||||
|   | |||||||
| @@ -1,21 +0,0 @@ | |||||||
| cmake_minimum_required(VERSION 3.21) |  | ||||||
| project(Katja) |  | ||||||
|  |  | ||||||
| include(CTest) |  | ||||||
| include(FetchContent) |  | ||||||
|  |  | ||||||
| set(CMAKE_EXPORT_COMPILE_COMMANDS 1) |  | ||||||
| set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) |  | ||||||
| set(CMAKE_CXX_STANDARD 17) |  | ||||||
|  |  | ||||||
| add_library(katja |  | ||||||
|        katja/database.cpp include/katja/database.hpp |  | ||||||
|        katja/sbo.cpp include/katja/sbo.hpp |  | ||||||
|        katja/repository.cpp include/katja/repository.hpp |  | ||||||
| ) |  | ||||||
| include_directories(include ${Boost_INCLUDE_DIR}) |  | ||||||
|  |  | ||||||
| add_subdirectory(cli) |  | ||||||
| if(BUILD_TESTING) |  | ||||||
| 	add_subdirectory(tests) |  | ||||||
| endif() |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| FetchContent_Declare(ftxui |  | ||||||
| 	GIT_REPOSITORY https://github.com/ArthurSonzogni/ftxui |  | ||||||
| 	GIT_TAG v6.0.2 |  | ||||||
| 	GIT_PROGRESS TRUE |  | ||||||
| 	GIT_SHALLOW TRUE |  | ||||||
| 	EXCLUDE_FROM_ALL |  | ||||||
| ) |  | ||||||
| FetchContent_MakeAvailable(ftxui) |  | ||||||
|  |  | ||||||
| FetchContent_Declare(toml11 |  | ||||||
| 	GIT_REPOSITORY https://github.com/ToruNiina/toml11.git |  | ||||||
| 	GIT_TAG v4.4.0 |  | ||||||
| 	GIT_PROGRESS TRUE |  | ||||||
| ) |  | ||||||
| FetchContent_MakeAvailable(toml11) |  | ||||||
|  |  | ||||||
| add_executable(katja-cli main.cpp component.hpp component.cpp) |  | ||||||
| target_include_directories(katja-cli PRIVATE ${Boost_INCLUDE_DIR}) |  | ||||||
| target_link_libraries(katja-cli |  | ||||||
| 	LINK_PUBLIC katja |  | ||||||
| 	LINK_PRIVATE ftxui::screen |  | ||||||
| 	LINK_PRIVATE ftxui::dom |  | ||||||
| 	LINK_PRIVATE ftxui::component |  | ||||||
| 	LINK_PRIVATE toml11::toml11 |  | ||||||
| ) |  | ||||||
| set_target_properties(katja-cli PROPERTIES RUNTIME_OUTPUT_NAME katja) |  | ||||||
| @@ -1,152 +0,0 @@ | |||||||
| #include "component.hpp" |  | ||||||
|  |  | ||||||
| #include <algorithm> |  | ||||||
|  |  | ||||||
| namespace katja |  | ||||||
| { |  | ||||||
|     ScreenContainer::ScreenContainer(std::vector<std::pair<std::string, Page>> pages, std::function<void()> on_enter) |  | ||||||
|         : on_enter(on_enter) |  | ||||||
|     { |  | ||||||
|         ftxui::Components menu_pages; |  | ||||||
|  |  | ||||||
|         std::transform(std::cbegin(pages), std::cend(pages), std::back_inserter(menu_entries), |  | ||||||
|                 [](const std::pair<std::string, Page>& pair) { return pair.first; }); |  | ||||||
|         std::transform(std::cbegin(pages), std::cend(pages), std::back_inserter(this->menu_pages), |  | ||||||
|                 [](const std::pair<std::string, Page>& pair) { return pair.second; }); |  | ||||||
|         std::copy(std::cbegin(this->menu_pages), std::cend(this->menu_pages), std::back_inserter(menu_pages)); |  | ||||||
|  |  | ||||||
|         ftxui::MenuOption menu_option = ftxui::MenuOption::Horizontal(); |  | ||||||
|         this->menu = ftxui::Toggle(&this->menu_entries, &this->menu_selected); |  | ||||||
|  |  | ||||||
|         this->content = ftxui::Container::Tab(std::move(menu_pages), &this->menu_selected); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ftxui::Element ScreenContainer::OnRender() |  | ||||||
|     { |  | ||||||
|         return ftxui::vbox({ |  | ||||||
|             this->menu->Render(), |  | ||||||
|             ftxui::separator(), |  | ||||||
|             this->content->Render() |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool ScreenContainer::OnEvent(ftxui::Event event) |  | ||||||
|     { |  | ||||||
|         if (event == ftxui::Event::CtrlQ && this->on_enter) |  | ||||||
|         { |  | ||||||
|             on_enter(); |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|         int previously = this->menu_selected; |  | ||||||
|         bool result{ false }; |  | ||||||
|  |  | ||||||
|         if (event == ftxui::Event::CtrlP) |  | ||||||
|         { |  | ||||||
|             result = menu->OnEvent(ftxui::Event::ArrowLeft); |  | ||||||
|         } |  | ||||||
|         else if (event == ftxui::Event::CtrlN) |  | ||||||
|         { |  | ||||||
|             result = menu->OnEvent(ftxui::Event::ArrowRight); |  | ||||||
|         } |  | ||||||
|         if (previously != this->menu_selected) |  | ||||||
|         { |  | ||||||
|             this->menu_pages.at(this->menu_selected)->Load(); |  | ||||||
|         } |  | ||||||
|         if (!result) |  | ||||||
|         { |  | ||||||
|             result = this->menu_pages.at(this->menu_selected)->OnEvent(event); |  | ||||||
|         } |  | ||||||
|         return result; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ftxui::Component Screen(std::vector<std::pair<std::string, Page>> pages, std::function<void()> on_enter) |  | ||||||
|     { |  | ||||||
|         return std::make_shared<ScreenContainer>(std::move(pages), on_enter); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ftxui::Element WelcomePage::OnRender() |  | ||||||
|     { |  | ||||||
|         return ftxui::paragraph("Select an action in the menu."); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void WelcomePage::Load() |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     UpdatesPage::UpdatesPage(std::shared_ptr<struct repository> repository, package_database database) |  | ||||||
|         : repository(repository), database(database) |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void UpdatesPage::Load() |  | ||||||
|     { |  | ||||||
|         this->updatable = repository->get_updates(this->database); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ftxui::Element UpdatesPage::OnRender() |  | ||||||
|     { |  | ||||||
|         std::vector<ftxui::Element> lines; |  | ||||||
|  |  | ||||||
|         for (const auto& package_identifier : this->updatable) |  | ||||||
|         { |  | ||||||
|             auto line = ftxui::text(package_identifier.to_string()) | color(ftxui::Color::SkyBlue2); |  | ||||||
|             lines.push_back(line); |  | ||||||
|         } |  | ||||||
|         ftxui::Element summary = ftxui::text(" Updates (" + std::to_string(lines.size()) + ")"); |  | ||||||
|  |  | ||||||
|         return ftxui::window(summary, ftxui::vbox(lines)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     SearchPage::SearchPage(std::shared_ptr<struct repository> repository, const std::string& architecture) |  | ||||||
|         : repository(repository), architecture(architecture) |  | ||||||
|     { |  | ||||||
|         ftxui::InputOption search_input_option = { .multiline = false }; |  | ||||||
|         this->search_input = ftxui::Input(&this->needle, "Search", search_input_option); |  | ||||||
|         this->type_input = ftxui::Radiobox(std::vector<std::string>{ "Names", "Description" }, &this->search_type); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void SearchPage::Load() |  | ||||||
|     { |  | ||||||
|         this->needle.erase(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ftxui::Element SearchPage::OnRender() |  | ||||||
|     { |  | ||||||
|         std::vector<ftxui::Element> lines; |  | ||||||
|  |  | ||||||
|         for (const auto& package_identifier : this->search_results) |  | ||||||
|         { |  | ||||||
|             auto line = ftxui::text(package_identifier.to_string()) | color(ftxui::Color::SkyBlue2); |  | ||||||
|             lines.push_back(line); |  | ||||||
|         } |  | ||||||
|         ftxui::FlexboxConfig config; |  | ||||||
|         config.justify_content = ftxui::FlexboxConfig::JustifyContent::FlexStart; |  | ||||||
|         config.align_items = ftxui::FlexboxConfig::AlignItems::FlexStart; |  | ||||||
|         config.direction = ftxui::FlexboxConfig::Direction::Row; |  | ||||||
|  |  | ||||||
|         return ftxui::vbox({ |  | ||||||
|             ftxui::flexbox({ |  | ||||||
|                 this->search_input->Render(), |  | ||||||
|                 ftxui::window(ftxui::text("Search in"), type_input->Render()) |  | ||||||
|             }, config), |  | ||||||
|             ftxui::vbox(lines) |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool SearchPage::OnEvent(ftxui::Event event) |  | ||||||
|     { |  | ||||||
|         if (event == ftxui::Event::Return) |  | ||||||
|         { |  | ||||||
|             if (!this->needle.empty()) |  | ||||||
|             { |  | ||||||
|                 this->search_results = this->repository->search_names(this->architecture, this->needle); |  | ||||||
|             } |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             return this->search_input->OnEvent(event); |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,76 +0,0 @@ | |||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include <ftxui/component/event.hpp> |  | ||||||
| #include <ftxui/component/component_base.hpp> |  | ||||||
| #include <ftxui/component/component.hpp> |  | ||||||
|  |  | ||||||
| #include "katja/repository.hpp" |  | ||||||
| #include "katja/database.hpp" |  | ||||||
|  |  | ||||||
| namespace katja |  | ||||||
| { |  | ||||||
|     class PageBase : public ftxui::ComponentBase |  | ||||||
|     { |  | ||||||
|     public: |  | ||||||
|         virtual void Load() = 0; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     using Page = std::shared_ptr<PageBase>; |  | ||||||
|     using Pages = std::vector<Page>; |  | ||||||
|  |  | ||||||
|     class ScreenContainer final : public ftxui::ComponentBase |  | ||||||
|     { |  | ||||||
|         int menu_selected{ 0 }; |  | ||||||
|         ftxui::Component menu; |  | ||||||
|         ftxui::Component content; |  | ||||||
|         std::vector<std::string> menu_entries; |  | ||||||
|         Pages menu_pages; |  | ||||||
|         std::function<void()> on_enter; |  | ||||||
|  |  | ||||||
|     public: |  | ||||||
|         ScreenContainer(std::vector<std::pair<std::string, Page>> pages, std::function<void()> on_enter); |  | ||||||
|  |  | ||||||
|         ftxui::Element OnRender() override; |  | ||||||
|         bool OnEvent(ftxui::Event event) override; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     ftxui::Component Screen(std::vector<std::pair<std::string, Page>> pages, std::function<void()> on_enter); |  | ||||||
|  |  | ||||||
|     class WelcomePage final : public PageBase |  | ||||||
|     { |  | ||||||
|     public: |  | ||||||
|         void Load() override; |  | ||||||
|         ftxui::Element OnRender() override; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     class UpdatesPage final : public PageBase |  | ||||||
|     { |  | ||||||
|         std::vector<package_identifier> updatable; |  | ||||||
|         std::shared_ptr<struct repository> repository; |  | ||||||
|         package_database database; |  | ||||||
|  |  | ||||||
|     public: |  | ||||||
|         UpdatesPage(std::shared_ptr<struct repository> repository, package_database database); |  | ||||||
|  |  | ||||||
|         void Load() override; |  | ||||||
|         ftxui::Element OnRender() override; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     class SearchPage final : public PageBase |  | ||||||
|     { |  | ||||||
|         std::string needle; |  | ||||||
|         ftxui::Component search_input; |  | ||||||
|         ftxui::Component type_input; |  | ||||||
|         std::shared_ptr<struct repository> repository; |  | ||||||
|         std::string architecture; |  | ||||||
|         std::vector<package_identifier> search_results; |  | ||||||
|         int search_type{ 0 }; |  | ||||||
|  |  | ||||||
|     public: |  | ||||||
|         SearchPage(std::shared_ptr<struct repository> repository, const std::string& architecture); |  | ||||||
|  |  | ||||||
|         void Load() override; |  | ||||||
|         ftxui::Element OnRender() override; |  | ||||||
|         bool OnEvent(ftxui::Event event) override; |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
							
								
								
									
										32
									
								
								cli/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								cli/main.cpp
									
									
									
									
									
								
							| @@ -1,32 +0,0 @@ | |||||||
| #include <filesystem> |  | ||||||
|  |  | ||||||
| #include <ftxui/component/screen_interactive.hpp> |  | ||||||
| #include <ftxui/dom/elements.hpp> |  | ||||||
| #include <toml.hpp> |  | ||||||
|  |  | ||||||
| #include "katja/sbo.hpp" |  | ||||||
| #include "katja/database.hpp" |  | ||||||
| #include "component.hpp" |  | ||||||
|  |  | ||||||
| int main(int argc, const char **argv) |  | ||||||
| { |  | ||||||
|     auto configuration = toml::parse("config/katja.toml"); |  | ||||||
|     katja::package_database installed_database = katja::read_installed_database(); |  | ||||||
|  |  | ||||||
|     for (const auto& [repository_name, repository_value] : configuration.as_table()) |  | ||||||
|     { |  | ||||||
|         std::filesystem::path slackbuild_repository{ repository_value.at("path").as_string() }; |  | ||||||
|         auto repository = std::make_shared<katja::sbo_repository>(slackbuild_repository); |  | ||||||
|  |  | ||||||
|         auto screen = ftxui::ScreenInteractive::Fullscreen(); |  | ||||||
|  |  | ||||||
|         auto container = Screen(std::vector<std::pair<std::string, katja::Page>>{ |  | ||||||
|             { "Home", ftxui::Make<katja::WelcomePage>() }, |  | ||||||
|             { "Updates", ftxui::Make<katja::UpdatesPage>(repository, std::move(installed_database)) }, |  | ||||||
|             { "Search", ftxui::Make<katja::SearchPage>(repository, "x86-64") } |  | ||||||
|         }, screen.ExitLoopClosure()); |  | ||||||
|  |  | ||||||
|         screen.Loop(container); |  | ||||||
|     } |  | ||||||
|     return EXIT_SUCCESS; |  | ||||||
| } |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| [sbo] |  | ||||||
| path = "/home/path/to/local/repository" |  | ||||||
| @@ -1,39 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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 <string> |  | ||||||
| #include <map> |  | ||||||
|  |  | ||||||
| namespace katja |  | ||||||
| { |  | ||||||
|     constexpr const char *database = "/var/lib/pkgtools/packages"; |  | ||||||
|  |  | ||||||
|     class database_package |  | ||||||
|     { |  | ||||||
|         database_package(std::string&& name, std::string&& version, |  | ||||||
|                 std::string&& architecture, std::string&& build_tag); |  | ||||||
|  |  | ||||||
|         static database_package create_database_package(const std::string& fullname); |  | ||||||
|  |  | ||||||
|     public: |  | ||||||
|         const std::string name; |  | ||||||
|         const std::string version; |  | ||||||
|         const std::string architecture; |  | ||||||
|         const std::string build_tag; |  | ||||||
|  |  | ||||||
|         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; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     using package_database = std::multimap<std::string, database_package>; |  | ||||||
|  |  | ||||||
|     package_database read_installed_database(); |  | ||||||
| } |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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 <string> |  | ||||||
| #include <vector> |  | ||||||
|  |  | ||||||
| #include "katja/database.hpp" |  | ||||||
|  |  | ||||||
| namespace katja |  | ||||||
| { |  | ||||||
|     struct package_identifier |  | ||||||
|     { |  | ||||||
|         const std::string name; |  | ||||||
|         const std::string version; |  | ||||||
|         const std::string architecture; |  | ||||||
|         const std::string data; |  | ||||||
|  |  | ||||||
|         std::string to_string() const; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     class repository |  | ||||||
|     { |  | ||||||
|     public: |  | ||||||
|         virtual std::vector<package_identifier> get_updates(const package_database& database) = 0; |  | ||||||
|         virtual std::vector<package_identifier> search_names(const std::string& architecture, |  | ||||||
|                 const std::string& needle) = 0; |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| @@ -1,44 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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 <string> |  | ||||||
| #include <vector> |  | ||||||
| #include <filesystem> |  | ||||||
| #include <optional> |  | ||||||
|  |  | ||||||
| #include "katja/repository.hpp" |  | ||||||
|  |  | ||||||
| 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); |  | ||||||
|  |  | ||||||
|         package_identifier identifier_for(const std::string& architecture); |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     class sbo_repository final : public repository |  | ||||||
|     { |  | ||||||
|         std::map<std::string, std::filesystem::path> info_paths; |  | ||||||
|  |  | ||||||
|     public: |  | ||||||
|         sbo_repository(const std::filesystem::path& repository_path); |  | ||||||
|  |  | ||||||
|         std::vector<package_identifier> get_updates(const package_database& database) override; |  | ||||||
|         std::vector<package_identifier> search_names(const std::string& architecture, |  | ||||||
|                 const std::string& needle) override; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     std::optional<info_file> read_slackbuild_info(const std::filesystem::path& info_filepath); |  | ||||||
| } |  | ||||||
| @@ -1,96 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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 <filesystem> |  | ||||||
|  |  | ||||||
| namespace katja |  | ||||||
| { |  | ||||||
|     database_package database_package::create_database_package(const std::string& fullname) |  | ||||||
|     { |  | ||||||
|         std::string::const_reverse_iterator begin_iterator = std::crbegin(fullname); |  | ||||||
|         std::string::const_reverse_iterator end_iterator = begin_iterator; |  | ||||||
|         int minus_counter = 0; |  | ||||||
|  |  | ||||||
|         std::string build_tag; |  | ||||||
|         std::string architecture; |  | ||||||
|         std::string version; |  | ||||||
|  |  | ||||||
|         for (; begin_iterator != std::crend(fullname) && minus_counter < 3; ++begin_iterator) |  | ||||||
|         { |  | ||||||
|             if (*begin_iterator == '-') |  | ||||||
|             { |  | ||||||
|                 if (minus_counter == 0) |  | ||||||
|                 { |  | ||||||
|                     build_tag = std::string(begin_iterator.base(), end_iterator.base()); |  | ||||||
|                 } |  | ||||||
|                 else if (minus_counter == 1) |  | ||||||
|                 { |  | ||||||
|                     architecture = std::string(begin_iterator.base(), end_iterator.base()); |  | ||||||
|                 } |  | ||||||
|                 else if (minus_counter == 2) |  | ||||||
|                 { |  | ||||||
|                     version = std::string(begin_iterator.base(), end_iterator.base()); |  | ||||||
|                 } |  | ||||||
|                 end_iterator = begin_iterator + 1; |  | ||||||
|                 ++minus_counter; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return database_package(std::string(fullname.cbegin(), end_iterator.base()), |  | ||||||
|                 std::move(version), std::move(architecture), std::move(build_tag)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     database_package::database_package(std::string&& name, std::string&& version, |  | ||||||
|                 std::string&& architecture, std::string&& build_tag) |  | ||||||
|         : name(name), version(version), architecture(architecture), build_tag(build_tag) |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     database_package::database_package(const std::string& fullname) |  | ||||||
|         : database_package(create_database_package(fullname)) |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     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; |  | ||||||
|         const std::size_t total_size = this->name.size() + this->version.size() |  | ||||||
|             + this->architecture.size() + this->build_tag.size() + 3; |  | ||||||
|  |  | ||||||
|         package_string.reserve(total_size); |  | ||||||
|         package_string.append(this->name); |  | ||||||
|         package_string.push_back('-'); |  | ||||||
|         package_string.append(this->version); |  | ||||||
|         package_string.push_back('-'); |  | ||||||
|         package_string.append(this->architecture); |  | ||||||
|         package_string.push_back('-'); |  | ||||||
|         package_string.append(this->build_tag); |  | ||||||
|  |  | ||||||
|         return package_string; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     package_database read_installed_database() |  | ||||||
|     { |  | ||||||
|         package_database 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; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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/repository.hpp" |  | ||||||
|  |  | ||||||
| namespace katja |  | ||||||
| { |  | ||||||
|     std::string package_identifier::to_string() const |  | ||||||
|     { |  | ||||||
|         std::string identifier; |  | ||||||
|         const std::size_t total_size = this->name.size() + this->version.size() |  | ||||||
|             + this->architecture.size() + this->data.size() + 3; |  | ||||||
|  |  | ||||||
|         identifier.reserve(total_size); |  | ||||||
|         identifier.append(this->name); |  | ||||||
|         identifier.push_back(';'); |  | ||||||
|         identifier.append(this->version); |  | ||||||
|         identifier.push_back(';'); |  | ||||||
|         identifier.append(this->architecture); |  | ||||||
|         identifier.push_back(';'); |  | ||||||
|         identifier.append(this->data); |  | ||||||
|  |  | ||||||
|         return identifier; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										202
									
								
								katja/sbo.cpp
									
									
									
									
									
								
							
							
						
						
									
										202
									
								
								katja/sbo.cpp
									
									
									
									
									
								
							| @@ -1,202 +0,0 @@ | |||||||
| /* |  | ||||||
|  * 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 <fstream> |  | ||||||
|  |  | ||||||
| #include <boost/algorithm/string.hpp> |  | ||||||
|  |  | ||||||
| #include "katja/sbo.hpp" |  | ||||||
|  |  | ||||||
| namespace katja |  | ||||||
| { |  | ||||||
|     static |  | ||||||
|     void search_for_slackbuilds(std::map<std::string, std::filesystem::path>& 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)) |  | ||||||
|             { |  | ||||||
|                 info_files.emplace(entry_path.filename(), info_filepath); |  | ||||||
|             } |  | ||||||
|             else if (std::filesystem::is_directory(entry_path)) |  | ||||||
|             { |  | ||||||
|                 search_for_slackbuilds(info_files, entry_path); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static |  | ||||||
|     void search_for_slackbuilds(std::vector<info_file>& info_files, const std::filesystem::path& directory) |  | ||||||
|     { |  | ||||||
|         std::map<std::string, std::filesystem::path> info_paths; |  | ||||||
|  |  | ||||||
|         search_for_slackbuilds(info_paths, directory); |  | ||||||
|         for (const auto& [_, info_filepath] : info_paths) |  | ||||||
|         { |  | ||||||
|             auto slackbuild_info = read_slackbuild_info(info_filepath); |  | ||||||
|  |  | ||||||
|             if (slackbuild_info.has_value()) |  | ||||||
|             { |  | ||||||
|                 info_files.emplace_back(std::move(slackbuild_info.value())); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     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) |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     package_identifier info_file::identifier_for(const std::string& architecture) |  | ||||||
|     { |  | ||||||
|         return package_identifier{ this->program_name, this->version, architecture, "SBo" }; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     sbo_repository::sbo_repository(const std::filesystem::path& repository_path) |  | ||||||
|     { |  | ||||||
|         search_for_slackbuilds(this->info_paths, repository_path); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     std::vector<package_identifier> sbo_repository::get_updates(const package_database& database) |  | ||||||
|     { |  | ||||||
|         std::vector<package_identifier> identifiers; |  | ||||||
|  |  | ||||||
|         for (const auto& [package_name, package] : database) |  | ||||||
|         { |  | ||||||
|             auto looked_up_info_path = this->info_paths.find(package_name); |  | ||||||
|  |  | ||||||
|             if (looked_up_info_path != this->info_paths.cend()) |  | ||||||
|             { |  | ||||||
|                 auto slackbuild_info = read_slackbuild_info(looked_up_info_path->second); |  | ||||||
|  |  | ||||||
|                 if (slackbuild_info.has_value() && slackbuild_info.value().version != package.version) |  | ||||||
|                 { |  | ||||||
|                     identifiers.push_back(slackbuild_info->identifier_for(package.architecture)); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return identifiers; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     std::vector<package_identifier> sbo_repository::search_names(const std::string& architecture, |  | ||||||
|             const std::string& needle) |  | ||||||
|     { |  | ||||||
|         std::vector<package_identifier> identifiers; |  | ||||||
|  |  | ||||||
|         for (const auto& [package_name, info_path] : this->info_paths) |  | ||||||
|         { |  | ||||||
|             if (package_name.find(needle) != std::string::npos) |  | ||||||
|             { |  | ||||||
|                 auto slackbuild_info = read_slackbuild_info(info_path); |  | ||||||
|  |  | ||||||
|                 identifiers.push_back(slackbuild_info->identifier_for(architecture)); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return identifiers; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static |  | ||||||
|     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<info_file> 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<std::string> 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<info_file>(program_name, version, homepage, email, maintainer); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| find_package(Boost CONFIG COMPONENTS unit_test_framework REQUIRED) |  | ||||||
|  |  | ||||||
| file(GLOB KATJA_TEST_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) |  | ||||||
|  |  | ||||||
| foreach(test_source ${KATJA_TEST_SOURCES}) |  | ||||||
| 	get_filename_component(test_name ${test_source} NAME_WE) |  | ||||||
| 	set(tester ${test_name}-tester) |  | ||||||
|  |  | ||||||
| 	add_executable(${tester} ${test_source}) |  | ||||||
|  |  | ||||||
| 	target_compile_definitions(${tester} PRIVATE "BOOST_TEST_DYN_LINK=1") |  | ||||||
| 	target_link_libraries(${tester} LINK_PRIVATE katja Boost::unit_test_framework) |  | ||||||
|  |  | ||||||
| 	add_test(NAME ${test_name} COMMAND ${tester}) |  | ||||||
| endforeach() |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| #define BOOST_TEST_MODULE database tests |  | ||||||
|  |  | ||||||
| #include <boost/test/unit_test.hpp> |  | ||||||
| #include "katja/database.hpp" |  | ||||||
|  |  | ||||||
| BOOST_AUTO_TEST_CASE(generate_package_identifier) |  | ||||||
| { |  | ||||||
|     katja::database_package actual("libarchive-3.7.8-i586-1_slack15.0"); |  | ||||||
|  |  | ||||||
|     BOOST_TEST(actual.name == "libarchive"); |  | ||||||
|     BOOST_TEST(actual.version == "3.7.8"); |  | ||||||
|     BOOST_TEST(actual.architecture == "i586"); |  | ||||||
|     BOOST_TEST(actual.build_tag == "1_slack15.0"); |  | ||||||
| } |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| #define BOOST_TEST_MODULE repository tests |  | ||||||
|  |  | ||||||
| #include <boost/test/unit_test.hpp> |  | ||||||
| #include "katja/repository.hpp" |  | ||||||
|  |  | ||||||
| BOOST_AUTO_TEST_CASE(construct_valid_database_package) |  | ||||||
| { |  | ||||||
|     katja::package_identifier given{ "libarchive", "3.7.8", "i586", "slackware" }; |  | ||||||
|     std::string actual = given.to_string(); |  | ||||||
|     std::string expected = "libarchive;3.7.8;i586;slackware"; |  | ||||||
|  |  | ||||||
|     BOOST_TEST(actual == expected); |  | ||||||
| } |  | ||||||
		Reference in New Issue
	
	Block a user