From df55813d591399dade930b17323d86785aca7455 Mon Sep 17 00:00:00 2001 From: Martchus Date: Thu, 9 Nov 2023 15:18:50 +0100 Subject: [PATCH] Add `pacparse` utility to parse package files --- CMakeLists.txt | 2 +- pacparse/CMakeLists.txt | 39 ++++++++++++++++++ pacparse/main.cpp | 82 ++++++++++++++++++++++++++++++++++++++ pacparse/tests/check.cpp | 39 ++++++++++++++++++ pacparse/tests/cppunit.cpp | 1 + 5 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 pacparse/CMakeLists.txt create mode 100644 pacparse/main.cpp create mode 100644 pacparse/tests/check.cpp create mode 100644 pacparse/tests/cppunit.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d75a16..09f3608 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,4 +42,4 @@ link_directories(${LIBREPOMGR_BINARY_DIR}) add_subdirectory(srv) add_subdirectory(cli) add_subdirectory(pacfind) - +add_subdirectory(pacparse) diff --git a/pacparse/CMakeLists.txt b/pacparse/CMakeLists.txt new file mode 100644 index 0000000..3933266 --- /dev/null +++ b/pacparse/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.17.0 FATAL_ERROR) + +# add project files +set(HEADER_FILES) +set(SRC_FILES main.cpp) +set(TEST_HEADER_FILES) +set(TEST_SRC_FILES tests/cppunit.cpp tests/check.cpp) + +# meta data +set(META_PROJECT_NAME pacparse) +set(META_PROJECT_TYPE application) +set(META_PROJECT_VARNAME REPO_CLEAN) +set(META_APP_NAME "Package parser") +set(META_APP_AUTHOR "Martchus") +set(META_APP_DESCRIPTION "Tool to parse an Arch Linux package printing the results as JSON") +set(META_VERSION_MAJOR 0) +set(META_VERSION_MINOR 0) +set(META_VERSION_PATCH 1) + +# find c++utilities +set(CONFIGURATION_PACKAGE_SUFFIX + "" + CACHE STRING "sets the suffix for find_package() calls to packages configured via c++utilities") +find_package(c++utilities${CONFIGURATION_PACKAGE_SUFFIX} 5.0.0 REQUIRED) +use_cpp_utilities() + +# find backend libraries +find_package(libpkg ${META_APP_VERSION} REQUIRED) +use_libpkg() + +list(APPEND PRIVATE_LIBRARIES pthread) + +# include modules to apply configuration +include(BasicConfig) +include(WindowsResources) +include(AppTarget) +include(TestTarget) +include(ShellCompletion) +include(ConfigHeader) diff --git a/pacparse/main.cpp b/pacparse/main.cpp new file mode 100644 index 0000000..a991f92 --- /dev/null +++ b/pacparse/main.cpp @@ -0,0 +1,82 @@ +#include "../libpkg/parser/binary.h" +#include "../libpkg/parser/package.h" + +#include "resources/config.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace CppUtilities; + +int main(int argc, const char *argv[]) +{ + SET_APPLICATION_INFO; + + // read cli args + auto parser = ArgumentParser(); + auto packagesArg = Argument("packages", 'p', "specifies the paths of the package files to parse"); + packagesArg.setRequiredValueCount(Argument::varValueCount); + packagesArg.setValueNames({ "path" }); + packagesArg.setImplicit(true); + parser.setMainArguments({ &packagesArg, &parser.helpArg() }); + parser.setDefaultArgument(&parser.helpArg()); + parser.parseArgs(argc, argv); + + auto packages = std::vector>(); + auto packageMutex = std::mutex(); + + auto pi = std::vector::const_iterator(); + auto pend = std::vector::const_iterator(); + auto piMutex = std::mutex(); + if (packagesArg.isPresent()) { + const auto &packagePaths = packagesArg.values(); + pi = packagePaths.begin(); + pend = packagePaths.end(); + packages.reserve(packagePaths.size()); + } + + const auto processPackage = [&] { + for (;;) { + // get next package path + auto piLock = std::unique_lock(piMutex); + if (pi == pend) { + return; + } + auto packagePath = *(pi++); + piLock.unlock(); + + // parse package + try { + auto package = LibPkg::Package::fromPkgFile(packagePath); + auto packageLock = std::unique_lock(packageMutex); + packages.emplace_back(std::move(package)); + } catch (const std::runtime_error &e) { + std::cerr << "Unable to parse \"" << packagePath << "\": " << e.what() << '\n'; + } + } + }; + + auto threads + = std::vector(std::max(std::min(std::thread::hardware_concurrency(), packages.capacity()), 1u) - 1); + for (auto &t : threads) { + t = std::thread(processPackage); + } + processPackage(); + for (auto &t : threads) { + t.join(); + } + + const auto json = ReflectiveRapidJSON::JsonReflector::toJson(packages); + std::cout << std::string_view(json.GetString(), json.GetSize()); + return 0; +} diff --git a/pacparse/tests/check.cpp b/pacparse/tests/check.cpp new file mode 100644 index 0000000..7d8882b --- /dev/null +++ b/pacparse/tests/check.cpp @@ -0,0 +1,39 @@ +#include + +#include +#include + +using namespace std; +using namespace CPPUNIT_NS; +using namespace CppUtilities; + +class PacParseTests : public TestFixture { + CPPUNIT_TEST_SUITE(PacParseTests); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); + +public: + PacParseTests(); + void setUp() override; + void tearDown() override; + + void test(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(PacParseTests); + +PacParseTests::PacParseTests() +{ +} + +void PacParseTests::setUp() +{ +} + +void PacParseTests::tearDown() +{ +} + +void PacParseTests::test() +{ +} diff --git a/pacparse/tests/cppunit.cpp b/pacparse/tests/cppunit.cpp new file mode 100644 index 0000000..67aaee6 --- /dev/null +++ b/pacparse/tests/cppunit.cpp @@ -0,0 +1 @@ +#include