Initial commit
This commit is contained in:
		
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| *.toml | ||||
| CMakeCache.txt | ||||
| CMakeFiles/ | ||||
| /.cache/ | ||||
| /build/ | ||||
							
								
								
									
										21
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| 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() | ||||
							
								
								
									
										373
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,373 @@ | ||||
| Mozilla Public License Version 2.0 | ||||
| ================================== | ||||
|  | ||||
| 1. Definitions | ||||
| -------------- | ||||
|  | ||||
| 1.1. "Contributor" | ||||
|     means each individual or legal entity that creates, contributes to | ||||
|     the creation of, or owns Covered Software. | ||||
|  | ||||
| 1.2. "Contributor Version" | ||||
|     means the combination of the Contributions of others (if any) used | ||||
|     by a Contributor and that particular Contributor's Contribution. | ||||
|  | ||||
| 1.3. "Contribution" | ||||
|     means Covered Software of a particular Contributor. | ||||
|  | ||||
| 1.4. "Covered Software" | ||||
|     means Source Code Form to which the initial Contributor has attached | ||||
|     the notice in Exhibit A, the Executable Form of such Source Code | ||||
|     Form, and Modifications of such Source Code Form, in each case | ||||
|     including portions thereof. | ||||
|  | ||||
| 1.5. "Incompatible With Secondary Licenses" | ||||
|     means | ||||
|  | ||||
|     (a) that the initial Contributor has attached the notice described | ||||
|         in Exhibit B to the Covered Software; or | ||||
|  | ||||
|     (b) that the Covered Software was made available under the terms of | ||||
|         version 1.1 or earlier of the License, but not also under the | ||||
|         terms of a Secondary License. | ||||
|  | ||||
| 1.6. "Executable Form" | ||||
|     means any form of the work other than Source Code Form. | ||||
|  | ||||
| 1.7. "Larger Work" | ||||
|     means a work that combines Covered Software with other material, in | ||||
|     a separate file or files, that is not Covered Software. | ||||
|  | ||||
| 1.8. "License" | ||||
|     means this document. | ||||
|  | ||||
| 1.9. "Licensable" | ||||
|     means having the right to grant, to the maximum extent possible, | ||||
|     whether at the time of the initial grant or subsequently, any and | ||||
|     all of the rights conveyed by this License. | ||||
|  | ||||
| 1.10. "Modifications" | ||||
|     means any of the following: | ||||
|  | ||||
|     (a) any file in Source Code Form that results from an addition to, | ||||
|         deletion from, or modification of the contents of Covered | ||||
|         Software; or | ||||
|  | ||||
|     (b) any new file in Source Code Form that contains any Covered | ||||
|         Software. | ||||
|  | ||||
| 1.11. "Patent Claims" of a Contributor | ||||
|     means any patent claim(s), including without limitation, method, | ||||
|     process, and apparatus claims, in any patent Licensable by such | ||||
|     Contributor that would be infringed, but for the grant of the | ||||
|     License, by the making, using, selling, offering for sale, having | ||||
|     made, import, or transfer of either its Contributions or its | ||||
|     Contributor Version. | ||||
|  | ||||
| 1.12. "Secondary License" | ||||
|     means either the GNU General Public License, Version 2.0, the GNU | ||||
|     Lesser General Public License, Version 2.1, the GNU Affero General | ||||
|     Public License, Version 3.0, or any later versions of those | ||||
|     licenses. | ||||
|  | ||||
| 1.13. "Source Code Form" | ||||
|     means the form of the work preferred for making modifications. | ||||
|  | ||||
| 1.14. "You" (or "Your") | ||||
|     means an individual or a legal entity exercising rights under this | ||||
|     License. For legal entities, "You" includes any entity that | ||||
|     controls, is controlled by, or is under common control with You. For | ||||
|     purposes of this definition, "control" means (a) the power, direct | ||||
|     or indirect, to cause the direction or management of such entity, | ||||
|     whether by contract or otherwise, or (b) ownership of more than | ||||
|     fifty percent (50%) of the outstanding shares or beneficial | ||||
|     ownership of such entity. | ||||
|  | ||||
| 2. License Grants and Conditions | ||||
| -------------------------------- | ||||
|  | ||||
| 2.1. Grants | ||||
|  | ||||
| Each Contributor hereby grants You a world-wide, royalty-free, | ||||
| non-exclusive license: | ||||
|  | ||||
| (a) under intellectual property rights (other than patent or trademark) | ||||
|     Licensable by such Contributor to use, reproduce, make available, | ||||
|     modify, display, perform, distribute, and otherwise exploit its | ||||
|     Contributions, either on an unmodified basis, with Modifications, or | ||||
|     as part of a Larger Work; and | ||||
|  | ||||
| (b) under Patent Claims of such Contributor to make, use, sell, offer | ||||
|     for sale, have made, import, and otherwise transfer either its | ||||
|     Contributions or its Contributor Version. | ||||
|  | ||||
| 2.2. Effective Date | ||||
|  | ||||
| The licenses granted in Section 2.1 with respect to any Contribution | ||||
| become effective for each Contribution on the date the Contributor first | ||||
| distributes such Contribution. | ||||
|  | ||||
| 2.3. Limitations on Grant Scope | ||||
|  | ||||
| The licenses granted in this Section 2 are the only rights granted under | ||||
| this License. No additional rights or licenses will be implied from the | ||||
| distribution or licensing of Covered Software under this License. | ||||
| Notwithstanding Section 2.1(b) above, no patent license is granted by a | ||||
| Contributor: | ||||
|  | ||||
| (a) for any code that a Contributor has removed from Covered Software; | ||||
|     or | ||||
|  | ||||
| (b) for infringements caused by: (i) Your and any other third party's | ||||
|     modifications of Covered Software, or (ii) the combination of its | ||||
|     Contributions with other software (except as part of its Contributor | ||||
|     Version); or | ||||
|  | ||||
| (c) under Patent Claims infringed by Covered Software in the absence of | ||||
|     its Contributions. | ||||
|  | ||||
| This License does not grant any rights in the trademarks, service marks, | ||||
| or logos of any Contributor (except as may be necessary to comply with | ||||
| the notice requirements in Section 3.4). | ||||
|  | ||||
| 2.4. Subsequent Licenses | ||||
|  | ||||
| No Contributor makes additional grants as a result of Your choice to | ||||
| distribute the Covered Software under a subsequent version of this | ||||
| License (see Section 10.2) or under the terms of a Secondary License (if | ||||
| permitted under the terms of Section 3.3). | ||||
|  | ||||
| 2.5. Representation | ||||
|  | ||||
| Each Contributor represents that the Contributor believes its | ||||
| Contributions are its original creation(s) or it has sufficient rights | ||||
| to grant the rights to its Contributions conveyed by this License. | ||||
|  | ||||
| 2.6. Fair Use | ||||
|  | ||||
| This License is not intended to limit any rights You have under | ||||
| applicable copyright doctrines of fair use, fair dealing, or other | ||||
| equivalents. | ||||
|  | ||||
| 2.7. Conditions | ||||
|  | ||||
| Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted | ||||
| in Section 2.1. | ||||
|  | ||||
| 3. Responsibilities | ||||
| ------------------- | ||||
|  | ||||
| 3.1. Distribution of Source Form | ||||
|  | ||||
| All distribution of Covered Software in Source Code Form, including any | ||||
| Modifications that You create or to which You contribute, must be under | ||||
| the terms of this License. You must inform recipients that the Source | ||||
| Code Form of the Covered Software is governed by the terms of this | ||||
| License, and how they can obtain a copy of this License. You may not | ||||
| attempt to alter or restrict the recipients' rights in the Source Code | ||||
| Form. | ||||
|  | ||||
| 3.2. Distribution of Executable Form | ||||
|  | ||||
| If You distribute Covered Software in Executable Form then: | ||||
|  | ||||
| (a) such Covered Software must also be made available in Source Code | ||||
|     Form, as described in Section 3.1, and You must inform recipients of | ||||
|     the Executable Form how they can obtain a copy of such Source Code | ||||
|     Form by reasonable means in a timely manner, at a charge no more | ||||
|     than the cost of distribution to the recipient; and | ||||
|  | ||||
| (b) You may distribute such Executable Form under the terms of this | ||||
|     License, or sublicense it under different terms, provided that the | ||||
|     license for the Executable Form does not attempt to limit or alter | ||||
|     the recipients' rights in the Source Code Form under this License. | ||||
|  | ||||
| 3.3. Distribution of a Larger Work | ||||
|  | ||||
| You may create and distribute a Larger Work under terms of Your choice, | ||||
| provided that You also comply with the requirements of this License for | ||||
| the Covered Software. If the Larger Work is a combination of Covered | ||||
| Software with a work governed by one or more Secondary Licenses, and the | ||||
| Covered Software is not Incompatible With Secondary Licenses, this | ||||
| License permits You to additionally distribute such Covered Software | ||||
| under the terms of such Secondary License(s), so that the recipient of | ||||
| the Larger Work may, at their option, further distribute the Covered | ||||
| Software under the terms of either this License or such Secondary | ||||
| License(s). | ||||
|  | ||||
| 3.4. Notices | ||||
|  | ||||
| You may not remove or alter the substance of any license notices | ||||
| (including copyright notices, patent notices, disclaimers of warranty, | ||||
| or limitations of liability) contained within the Source Code Form of | ||||
| the Covered Software, except that You may alter any license notices to | ||||
| the extent required to remedy known factual inaccuracies. | ||||
|  | ||||
| 3.5. Application of Additional Terms | ||||
|  | ||||
| You may choose to offer, and to charge a fee for, warranty, support, | ||||
| indemnity or liability obligations to one or more recipients of Covered | ||||
| Software. However, You may do so only on Your own behalf, and not on | ||||
| behalf of any Contributor. You must make it absolutely clear that any | ||||
| such warranty, support, indemnity, or liability obligation is offered by | ||||
| You alone, and You hereby agree to indemnify every Contributor for any | ||||
| liability incurred by such Contributor as a result of warranty, support, | ||||
| indemnity or liability terms You offer. You may include additional | ||||
| disclaimers of warranty and limitations of liability specific to any | ||||
| jurisdiction. | ||||
|  | ||||
| 4. Inability to Comply Due to Statute or Regulation | ||||
| --------------------------------------------------- | ||||
|  | ||||
| If it is impossible for You to comply with any of the terms of this | ||||
| License with respect to some or all of the Covered Software due to | ||||
| statute, judicial order, or regulation then You must: (a) comply with | ||||
| the terms of this License to the maximum extent possible; and (b) | ||||
| describe the limitations and the code they affect. Such description must | ||||
| be placed in a text file included with all distributions of the Covered | ||||
| Software under this License. Except to the extent prohibited by statute | ||||
| or regulation, such description must be sufficiently detailed for a | ||||
| recipient of ordinary skill to be able to understand it. | ||||
|  | ||||
| 5. Termination | ||||
| -------------- | ||||
|  | ||||
| 5.1. The rights granted under this License will terminate automatically | ||||
| if You fail to comply with any of its terms. However, if You become | ||||
| compliant, then the rights granted under this License from a particular | ||||
| Contributor are reinstated (a) provisionally, unless and until such | ||||
| Contributor explicitly and finally terminates Your grants, and (b) on an | ||||
| ongoing basis, if such Contributor fails to notify You of the | ||||
| non-compliance by some reasonable means prior to 60 days after You have | ||||
| come back into compliance. Moreover, Your grants from a particular | ||||
| Contributor are reinstated on an ongoing basis if such Contributor | ||||
| notifies You of the non-compliance by some reasonable means, this is the | ||||
| first time You have received notice of non-compliance with this License | ||||
| from such Contributor, and You become compliant prior to 30 days after | ||||
| Your receipt of the notice. | ||||
|  | ||||
| 5.2. If You initiate litigation against any entity by asserting a patent | ||||
| infringement claim (excluding declaratory judgment actions, | ||||
| counter-claims, and cross-claims) alleging that a Contributor Version | ||||
| directly or indirectly infringes any patent, then the rights granted to | ||||
| You by any and all Contributors for the Covered Software under Section | ||||
| 2.1 of this License shall terminate. | ||||
|  | ||||
| 5.3. In the event of termination under Sections 5.1 or 5.2 above, all | ||||
| end user license agreements (excluding distributors and resellers) which | ||||
| have been validly granted by You or Your distributors under this License | ||||
| prior to termination shall survive termination. | ||||
|  | ||||
| ************************************************************************ | ||||
| *                                                                      * | ||||
| *  6. Disclaimer of Warranty                                           * | ||||
| *  -------------------------                                           * | ||||
| *                                                                      * | ||||
| *  Covered Software is provided under this License on an "as is"       * | ||||
| *  basis, without warranty of any kind, either expressed, implied, or  * | ||||
| *  statutory, including, without limitation, warranties that the       * | ||||
| *  Covered Software is free of defects, merchantable, fit for a        * | ||||
| *  particular purpose or non-infringing. The entire risk as to the     * | ||||
| *  quality and performance of the Covered Software is with You.        * | ||||
| *  Should any Covered Software prove defective in any respect, You     * | ||||
| *  (not any Contributor) assume the cost of any necessary servicing,   * | ||||
| *  repair, or correction. This disclaimer of warranty constitutes an   * | ||||
| *  essential part of this License. No use of any Covered Software is   * | ||||
| *  authorized under this License except under this disclaimer.         * | ||||
| *                                                                      * | ||||
| ************************************************************************ | ||||
|  | ||||
| ************************************************************************ | ||||
| *                                                                      * | ||||
| *  7. Limitation of Liability                                          * | ||||
| *  --------------------------                                          * | ||||
| *                                                                      * | ||||
| *  Under no circumstances and under no legal theory, whether tort      * | ||||
| *  (including negligence), contract, or otherwise, shall any           * | ||||
| *  Contributor, or anyone who distributes Covered Software as          * | ||||
| *  permitted above, be liable to You for any direct, indirect,         * | ||||
| *  special, incidental, or consequential damages of any character      * | ||||
| *  including, without limitation, damages for lost profits, loss of    * | ||||
| *  goodwill, work stoppage, computer failure or malfunction, or any    * | ||||
| *  and all other commercial damages or losses, even if such party      * | ||||
| *  shall have been informed of the possibility of such damages. This   * | ||||
| *  limitation of liability shall not apply to liability for death or   * | ||||
| *  personal injury resulting from such party's negligence to the       * | ||||
| *  extent applicable law prohibits such limitation. Some               * | ||||
| *  jurisdictions do not allow the exclusion or limitation of           * | ||||
| *  incidental or consequential damages, so this exclusion and          * | ||||
| *  limitation may not apply to You.                                    * | ||||
| *                                                                      * | ||||
| ************************************************************************ | ||||
|  | ||||
| 8. Litigation | ||||
| ------------- | ||||
|  | ||||
| Any litigation relating to this License may be brought only in the | ||||
| courts of a jurisdiction where the defendant maintains its principal | ||||
| place of business and such litigation shall be governed by laws of that | ||||
| jurisdiction, without reference to its conflict-of-law provisions. | ||||
| Nothing in this Section shall prevent a party's ability to bring | ||||
| cross-claims or counter-claims. | ||||
|  | ||||
| 9. Miscellaneous | ||||
| ---------------- | ||||
|  | ||||
| This License represents the complete agreement concerning the subject | ||||
| matter hereof. If any provision of this License is held to be | ||||
| unenforceable, such provision shall be reformed only to the extent | ||||
| necessary to make it enforceable. Any law or regulation which provides | ||||
| that the language of a contract shall be construed against the drafter | ||||
| shall not be used to construe this License against a Contributor. | ||||
|  | ||||
| 10. Versions of the License | ||||
| --------------------------- | ||||
|  | ||||
| 10.1. New Versions | ||||
|  | ||||
| Mozilla Foundation is the license steward. Except as provided in Section | ||||
| 10.3, no one other than the license steward has the right to modify or | ||||
| publish new versions of this License. Each version will be given a | ||||
| distinguishing version number. | ||||
|  | ||||
| 10.2. Effect of New Versions | ||||
|  | ||||
| You may distribute the Covered Software under the terms of the version | ||||
| of the License under which You originally received the Covered Software, | ||||
| or under the terms of any subsequent version published by the license | ||||
| steward. | ||||
|  | ||||
| 10.3. Modified Versions | ||||
|  | ||||
| If you create software not governed by this License, and you want to | ||||
| create a new license for such software, you may create and use a | ||||
| modified version of this License if you rename the license and remove | ||||
| any references to the name of the license steward (except to note that | ||||
| such modified license differs from this License). | ||||
|  | ||||
| 10.4. Distributing Source Code Form that is Incompatible With Secondary | ||||
| Licenses | ||||
|  | ||||
| If You choose to distribute Source Code Form that is Incompatible With | ||||
| Secondary Licenses under the terms of this version of the License, the | ||||
| notice described in Exhibit B of this License must be attached. | ||||
|  | ||||
| Exhibit A - Source Code Form License Notice | ||||
| ------------------------------------------- | ||||
|  | ||||
|   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 http://mozilla.org/MPL/2.0/. | ||||
|  | ||||
| If it is not possible or desirable to put the notice in a particular | ||||
| file, then You may include the notice in a location (such as a LICENSE | ||||
| file in a relevant directory) where a recipient would be likely to look | ||||
| for such a notice. | ||||
|  | ||||
| You may add additional accurate notices of copyright ownership. | ||||
|  | ||||
| Exhibit B - "Incompatible With Secondary Licenses" Notice | ||||
| --------------------------------------------------------- | ||||
|  | ||||
|   This Source Code Form is "Incompatible With Secondary Licenses", as | ||||
|   defined by the Mozilla Public License, v. 2.0. | ||||
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| ## Build instructions | ||||
|  | ||||
| ```sh | ||||
| cmake -B build | ||||
| make -C build | ||||
| ``` | ||||
|  | ||||
| Pass `-DCMAKE_BUILD_TYPE=Debug` or `-DCMAKE_BUILD_TYPE=Release` to | ||||
| `cmake` to select the according build configuration. | ||||
|  | ||||
| This builds a CLI that can be then found in `./build/bin/katja`. | ||||
							
								
								
									
										26
									
								
								cli/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								cli/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| 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) | ||||
							
								
								
									
										152
									
								
								cli/component.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								cli/component.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| #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; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										76
									
								
								cli/component.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								cli/component.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| #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
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								cli/main.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| #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("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; | ||||
| } | ||||
							
								
								
									
										39
									
								
								include/katja/database.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/katja/database.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| /* | ||||
|  * 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(); | ||||
| } | ||||
							
								
								
									
										32
									
								
								include/katja/repository.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								include/katja/repository.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     }; | ||||
| } | ||||
							
								
								
									
										44
									
								
								include/katja/sbo.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								include/katja/sbo.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| /* | ||||
|  * 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); | ||||
| } | ||||
							
								
								
									
										2
									
								
								katja.conf.dist
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								katja.conf.dist
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| [sbo] | ||||
| path = "/home/path/to/local/repository" | ||||
							
								
								
									
										96
									
								
								katja/database.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								katja/database.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /* | ||||
|  * 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; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										27
									
								
								katja/repository.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								katja/repository.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| /* | ||||
|  * 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
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								katja/sbo.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | ||||
| /* | ||||
|  * 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); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										15
									
								
								tests/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								tests/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| 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() | ||||
							
								
								
									
										14
									
								
								tests/database.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tests/database.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #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"); | ||||
| } | ||||
							
								
								
									
										13
									
								
								tests/repository.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								tests/repository.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| #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