diff --git a/CMakeLists.txt b/CMakeLists.txt index d85463a..7b3ad1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,9 +102,6 @@ add_executable(${PROJECT_NAME} src/definitions.hpp src/config.cpp src/config.hpp src/utils.cpp src/utils.hpp - src/cpu.cpp src/cpu.hpp - src/pacmanconf_repo.cpp src/pacmanconf_repo.hpp - src/initcpio.cpp src/initcpio.hpp src/chwd_profiles.cpp src/chwd_profiles.hpp src/disk.cpp src/disk.hpp src/drivers.cpp src/drivers.hpp @@ -135,13 +132,15 @@ target_link_libraries(screen PRIVATE range-v3::range-v3) target_link_libraries(dom PRIVATE range-v3::range-v3) target_link_libraries(component PRIVATE range-v3::range-v3) -include_directories(${CMAKE_SOURCE_DIR}/src ${RAPIDJSON_INCLUDE_DIR}) +include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/gucc/src ${RAPIDJSON_INCLUDE_DIR}) + +add_subdirectory(gucc) if(COS_INSTALLER_BUILD_TESTS) add_subdirectory(tests) endif() -target_link_libraries(${PROJECT_NAME} PRIVATE project_warnings project_options spdlog::spdlog fmt::fmt ftxui::screen ftxui::dom ftxui::component range-v3::range-v3 ctre::ctre tomlplusplus::tomlplusplus) +target_link_libraries(${PROJECT_NAME} PRIVATE project_warnings project_options spdlog::spdlog fmt::fmt ftxui::screen ftxui::dom ftxui::component range-v3::range-v3 ctre::ctre tomlplusplus::tomlplusplus gucc::gucc) if(NOT ENABLE_DEVENV) target_link_libraries(${PROJECT_NAME} PRIVATE cpr::cpr) endif() diff --git a/cmake/StandardProjectSettings.cmake b/cmake/StandardProjectSettings.cmake index 2ba39d1..af4648e 100644 --- a/cmake/StandardProjectSettings.cmake +++ b/cmake/StandardProjectSettings.cmake @@ -18,7 +18,6 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "" FORCE) set(FTXUI_BUILD_DOCS OFF CACHE INTERNAL "" FORCE) set(FTXUI_BUILD_EXAMPLES OFF CACHE INTERNAL "" FORCE) set(FTXUI_ENABLE_INSTALL OFF CACHE INTERNAL "" FORCE) @@ -30,6 +29,9 @@ set(CPR_USE_SYSTEM_CURL ON CACHE INTERNAL "" FORCE) # Generate compile_commands.json to make it easier to work with clang based tools set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +# Build with PIC +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + if(CMAKE_C_COMPILER_ID MATCHES ".*Clang") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -flto=thin -fwhole-program-vtables") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -flto=thin -fwhole-program-vtables") @@ -42,7 +44,6 @@ if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto -fwhole-program -fuse-linker-plugin") endif() -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")# -static") if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") #add_compile_options(-nostdlib++ -stdlib=libc++ -nodefaultlibs -fexperimental-library) @@ -80,6 +81,13 @@ else() message(STATUS "No colored compiler diagnostic set for '${CMAKE_CXX_COMPILER_ID}' compiler.") endif() +# Builds as statically linked +option(COS_BUILD_STATIC "Build all static" OFF) +if(COS_BUILD_STATIC) + set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "" FORCE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")# -static") +endif() + # Enables STL container checker if not building a release. if(CMAKE_BUILD_TYPE STREQUAL "Debug") add_definitions(-D_GLIBCXX_ASSERTIONS) diff --git a/gucc/CMakeLists.txt b/gucc/CMakeLists.txt new file mode 100644 index 0000000..9803d2c --- /dev/null +++ b/gucc/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.6) + +## +## PROJECT +## name and version +## +project(gucc + VERSION 0.0.1 + LANGUAGES CXX) + +add_library(${PROJECT_NAME} SHARED + #src/utils.cpp src/utils.hpp + src/string_utils.cpp src/string_utils.hpp + src/file_utils.cpp src/file_utils.hpp + src/cpu.cpp src/cpu.hpp + src/pacmanconf_repo.cpp src/pacmanconf_repo.hpp + src/initcpio.cpp src/initcpio.hpp + #src/chwd_profiles.cpp src/chwd_profiles.hpp + #src/disk.cpp src/disk.hpp + ) + +add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_DIR}/src) +target_link_libraries(${PROJECT_NAME} PUBLIC project_warnings project_options spdlog::spdlog fmt::fmt range-v3::range-v3) + +if(COS_INSTALLER_BUILD_TESTS) + add_subdirectory(tests) +endif() diff --git a/gucc/README.md b/gucc/README.md new file mode 100644 index 0000000..5dde11e --- /dev/null +++ b/gucc/README.md @@ -0,0 +1 @@ +# what diff --git a/src/cpu.cpp b/gucc/src/cpu.cpp similarity index 98% rename from src/cpu.cpp rename to gucc/src/cpu.cpp index 0eed6a7..d54edf7 100644 --- a/src/cpu.cpp +++ b/gucc/src/cpu.cpp @@ -6,7 +6,7 @@ #include -namespace utils { +namespace gucc::cpu { /* clang-format off */ namespace { @@ -145,4 +145,4 @@ auto get_isa_levels() noexcept -> std::vector { return supported_isa_levels; } -} // namespace utils +} // namespace gucc::cpu diff --git a/src/cpu.hpp b/gucc/src/cpu.hpp similarity index 79% rename from src/cpu.hpp rename to gucc/src/cpu.hpp index c4d6b93..445e40d 100644 --- a/src/cpu.hpp +++ b/gucc/src/cpu.hpp @@ -4,10 +4,10 @@ #include // for string #include // for vector -namespace utils { +namespace gucc::cpu { auto get_isa_levels() noexcept -> std::vector; -} // namespace utils +} // namespace gucc::cpu #endif // CPU_HPP diff --git a/gucc/src/file_utils.cpp b/gucc/src/file_utils.cpp new file mode 100644 index 0000000..8c89478 --- /dev/null +++ b/gucc/src/file_utils.cpp @@ -0,0 +1,48 @@ +#include "file_utils.hpp" + +#include // for errno, strerror +#include // for feof, fgets, pclose, perror, popen +#include // for exit, WIFEXITED, WIFSIGNALED + +#include // for ofstream + +#include + +namespace gucc::file_utils { + +auto read_whole_file(const std::string_view& filepath) noexcept -> std::string { + // Use std::fopen because it's faster than std::ifstream + auto* file = std::fopen(filepath.data(), "rb"); + if (file == nullptr) { + spdlog::error("[READWHOLEFILE] '{}' read failed: {}", filepath, std::strerror(errno)); + return {}; + } + + std::fseek(file, 0u, SEEK_END); + const auto size = static_cast(std::ftell(file)); + std::fseek(file, 0u, SEEK_SET); + + std::string buf; + buf.resize(size); + + const std::size_t read = std::fread(buf.data(), sizeof(char), size, file); + if (read != size) { + spdlog::error("[READWHOLEFILE] '{}' read failed: {}", filepath, std::strerror(errno)); + return {}; + } + std::fclose(file); + + return buf; +} + +bool write_to_file(const std::string_view& data, const std::string_view& filepath) noexcept { + std::ofstream file{filepath.data()}; + if (!file.is_open()) { + spdlog::error("[WRITE_TO_FILE] '{}' open failed: {}", filepath, std::strerror(errno)); + return false; + } + file << data; + return true; +} + +} // namespace gucc::file_utils diff --git a/gucc/src/file_utils.hpp b/gucc/src/file_utils.hpp new file mode 100644 index 0000000..f31a014 --- /dev/null +++ b/gucc/src/file_utils.hpp @@ -0,0 +1,14 @@ +#ifndef FILE_UTILS_HPP +#define FILE_UTILS_HPP + +#include // for string +#include // for string_view + +namespace gucc::file_utils { + +auto read_whole_file(const std::string_view& filepath) noexcept -> std::string; +bool write_to_file(const std::string_view& data, const std::string_view& filepath) noexcept; + +} // namespace gucc::file_utils + +#endif // FILE_UTILS_HPP diff --git a/src/initcpio.cpp b/gucc/src/initcpio.cpp similarity index 93% rename from src/initcpio.cpp rename to gucc/src/initcpio.cpp index 9b7015b..744ad1a 100644 --- a/src/initcpio.cpp +++ b/gucc/src/initcpio.cpp @@ -1,8 +1,10 @@ #include "initcpio.hpp" -#include "utils.hpp" +#include "file_utils.hpp" +#include "string_utils.hpp" #include // for ofstream +#include #include #include @@ -27,10 +29,10 @@ #pragma GCC diagnostic pop #endif -namespace detail { +namespace gucc::detail { bool Initcpio::write() const noexcept { - auto&& file_content = utils::read_whole_file(m_file_path); + auto&& file_content = file_utils::read_whole_file(m_file_path); if (file_content.empty()) { spdlog::error("[INITCPIO] '{}' error occurred!", m_file_path); return false; @@ -69,7 +71,7 @@ bool Initcpio::write() const noexcept { } bool Initcpio::parse_file() noexcept { - auto&& file_content = utils::read_whole_file(m_file_path); + auto&& file_content = file_utils::read_whole_file(m_file_path); if (file_content.empty()) { spdlog::error("[INITCPIO] '{}' error occurred!", m_file_path); return false; @@ -101,4 +103,4 @@ bool Initcpio::parse_file() noexcept { return true; } -} // namespace detail +} // namespace gucc::detail diff --git a/src/initcpio.hpp b/gucc/src/initcpio.hpp similarity index 98% rename from src/initcpio.hpp rename to gucc/src/initcpio.hpp index dd6a02f..7cb8a5d 100644 --- a/src/initcpio.hpp +++ b/gucc/src/initcpio.hpp @@ -26,9 +26,9 @@ #pragma GCC diagnostic pop #endif -namespace detail { +namespace gucc::detail { -class Initcpio { +class Initcpio final { public: explicit Initcpio(const std::string_view& file_path) noexcept : m_file_path(file_path) { } @@ -127,6 +127,6 @@ class Initcpio { std::string_view m_file_path{}; }; -} // namespace detail +} // namespace gucc::detail #endif // INITCPIO_HPP diff --git a/src/pacmanconf_repo.cpp b/gucc/src/pacmanconf_repo.cpp similarity index 92% rename from src/pacmanconf_repo.cpp rename to gucc/src/pacmanconf_repo.cpp index 704b672..3ebdf93 100644 --- a/src/pacmanconf_repo.cpp +++ b/gucc/src/pacmanconf_repo.cpp @@ -1,5 +1,5 @@ #include "pacmanconf_repo.hpp" -#include "utils.hpp" +#include "file_utils.hpp" #include // for ofstream #include // for string @@ -28,11 +28,11 @@ #pragma GCC diagnostic pop #endif -namespace detail::pacmanconf { +namespace gucc::detail::pacmanconf { bool push_repos_front(std::string_view file_path, std::string_view value) noexcept { using StringVec = std::vector; - auto&& file_content = utils::read_whole_file(file_path); + auto&& file_content = file_utils::read_whole_file(file_path); if (file_content.empty()) { spdlog::error("[PACMANCONFREPO] '{}' error occurred!", file_path); return false; @@ -62,7 +62,7 @@ bool push_repos_front(std::string_view file_path, std::string_view value) noexce } auto get_repo_list(std::string_view file_path) noexcept -> std::vector { - auto&& file_content = utils::read_whole_file(file_path); + auto&& file_content = file_utils::read_whole_file(file_path); if (file_content.empty()) { spdlog::error("[PACMANCONFREPO] '{}' error occurred!", file_path); return {}; @@ -75,4 +75,4 @@ auto get_repo_list(std::string_view file_path) noexcept -> std::vector>(); } -} // namespace detail::pacmanconf +} // namespace gucc::detail::pacmanconf diff --git a/src/pacmanconf_repo.hpp b/gucc/src/pacmanconf_repo.hpp similarity index 82% rename from src/pacmanconf_repo.hpp rename to gucc/src/pacmanconf_repo.hpp index 3cefb73..209654e 100644 --- a/src/pacmanconf_repo.hpp +++ b/gucc/src/pacmanconf_repo.hpp @@ -5,9 +5,9 @@ #include // for string_view #include // for vector -namespace detail::pacmanconf { +namespace gucc::detail::pacmanconf { bool push_repos_front(std::string_view file_path, std::string_view value) noexcept; auto get_repo_list(std::string_view file_path) noexcept -> std::vector; -} // namespace detail::pacmanconf +} // namespace gucc::detail::pacmanconf #endif // PACMANCONF_REPO_HPP diff --git a/gucc/src/string_utils.cpp b/gucc/src/string_utils.cpp new file mode 100644 index 0000000..3d9770d --- /dev/null +++ b/gucc/src/string_utils.cpp @@ -0,0 +1,61 @@ +#include "string_utils.hpp" + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuseless-cast" +#pragma GCC diagnostic ignored "-Wold-style-cast" +#endif + +#include +#include +#include +#include + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +namespace gucc::utils { + +auto make_multiline(std::string_view str, bool reverse, char delim) noexcept -> std::vector { + std::vector lines{}; + ranges::for_each(utils::make_split_view(str, delim), [&](auto&& rng) { lines.emplace_back(rng); }); + if (reverse) { + ranges::reverse(lines); + } + return lines; +} + +auto make_multiline_view(std::string_view str, bool reverse, char delim) noexcept -> std::vector { + std::vector lines{}; + ranges::for_each(utils::make_split_view(str, delim), [&](auto&& rng) { lines.emplace_back(rng); }); + if (reverse) { + ranges::reverse(lines); + } + return lines; +} + +auto make_multiline(const std::vector& multiline, bool reverse, std::string_view delim) noexcept -> std::string { + std::string res{}; + for (const auto& line : multiline) { + res += line; + res += delim.data(); + } + + if (reverse) { + ranges::reverse(res); + } + + return res; +} + +auto join(const std::vector& lines, std::string_view delim) noexcept -> std::string { + return lines | ranges::views::join(delim) | ranges::to(); +} + +} // namespace gucc::utils diff --git a/gucc/src/string_utils.hpp b/gucc/src/string_utils.hpp new file mode 100644 index 0000000..23eff52 --- /dev/null +++ b/gucc/src/string_utils.hpp @@ -0,0 +1,79 @@ +#ifndef STRING_UTILS_HPP +#define STRING_UTILS_HPP + +#include // for transform +#include // for string +#include // for string_view +#include // for vector + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wsign-conversion" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnull-dereference" +#pragma GCC diagnostic ignored "-Wuseless-cast" +#pragma GCC diagnostic ignored "-Wold-style-cast" +#endif + +#include +#include +#include +#include +#include + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +namespace gucc::utils { + +/// @brief Split a string into multiple lines based on a delimiter. +/// @param str The string to split. +/// @param reverse Flag indicating whether to reverse the order of the resulting lines. +/// @param delim The delimiter to split the string. +/// @return A vector of strings representing the split lines. +auto make_multiline(std::string_view str, bool reverse = false, char delim = '\n') noexcept -> std::vector; + +/// @brief Split a string into views of multiple lines based on a delimiter. +/// @param str The string to split. +/// @param reverse Flag indicating whether to reverse the order of the resulting lines. +/// @param delim The delimiter to split the string. +/// @return A vector of string views representing the split lines. +auto make_multiline_view(std::string_view str, bool reverse = false, char delim = '\n') noexcept -> std::vector; + +/// @brief Combine multiple lines into a single string using a delimiter. +/// @param multiline The lines to combine. +/// @param reverse Flag indicating whether to reverse the order of the lines before combining. +/// @param delim The delimiter to join the lines. +/// @return The combined lines as a single string. +auto make_multiline(const std::vector& multiline, bool reverse = false, std::string_view delim = "\n") noexcept -> std::string; + +/// @brief Join a vector of strings into a single string using a delimiter. +/// @param lines The lines to join. +/// @param delim The delimiter to join the lines. +/// @return The joined lines as a single string. +auto join(const std::vector& lines, std::string_view delim = "\n") noexcept -> std::string; + +/// @brief Make a split view from a string into multiple lines based on a delimiter. +/// @param str The string to split. +/// @param delim The delimiter to split the string. +/// @return A range view representing the split lines. +constexpr auto make_split_view(std::string_view str, char delim = '\n') noexcept { + constexpr auto functor = [](auto&& rng) { + return std::string_view(&*rng.begin(), static_cast(ranges::distance(rng))); + }; + constexpr auto second = [](auto&& rng) { return rng != ""; }; + + return str + | ranges::views::split(delim) + | ranges::views::transform(functor) + | ranges::views::filter(second); +} + +} // namespace gucc::utils + +#endif // STRING_UTILS_HPP diff --git a/gucc/tests/CMakeLists.txt b/gucc/tests/CMakeLists.txt new file mode 100644 index 0000000..fd93df1 --- /dev/null +++ b/gucc/tests/CMakeLists.txt @@ -0,0 +1,17 @@ +############################################################################# +# one executable for each unit test file +############################################################################# + +file(GLOB files unit-*.cpp) + +foreach(file ${files}) + get_filename_component(file_basename ${file} NAME_WE) + string(REGEX REPLACE "unit-([^$]+)" "test-\\1" testcase ${file_basename}) + + add_executable(${testcase} ${file}) + target_compile_options(${testcase} PRIVATE + $<$>:-Wno-deprecated;-Wno-float-equal> + $<$:-Wno-deprecated-declarations> + ) + target_link_libraries(${testcase} PRIVATE project_warnings project_options gucc::gucc) +endforeach() diff --git a/gucc/tests/meson.build b/gucc/tests/meson.build new file mode 100644 index 0000000..9ee9e9a --- /dev/null +++ b/gucc/tests/meson.build @@ -0,0 +1,28 @@ +source_path = '../src/' + +test_libreq = shared_library('test_libreq', + sources : [ + source_path + 'file_utils.cpp', + source_path + 'cpu.cpp', + source_path + 'pacmanconf_repo.cpp', + source_path + 'initcpio.cpp', + ], + include_directories : [include_directories(source_path)], + dependencies: deps +) + +executable( + 'test-initcpio', + files('unit-initcpio.cpp'), + dependencies: deps, + link_with: [test_libreq], + include_directories: [include_directories(source_path)], + install: false) + +executable( + 'test-pacmanconf', + files('unit-pacmanconf.cpp'), + dependencies: deps, + link_with: [test_libreq], + include_directories: [include_directories(source_path)], + install: false) diff --git a/tests/unit-initcpio.cpp b/gucc/tests/unit-initcpio.cpp similarity index 93% rename from tests/unit-initcpio.cpp rename to gucc/tests/unit-initcpio.cpp index fa508a5..f3ab988 100644 --- a/tests/unit-initcpio.cpp +++ b/gucc/tests/unit-initcpio.cpp @@ -1,4 +1,4 @@ -#include "utils.hpp" +#include "file_utils.hpp" #include "initcpio.hpp" #include @@ -38,8 +38,9 @@ FILES=() HOOKS=(base udev autodetect modconf block filesystems keyboard fsck btrfs usr lvm2 zfs) )"; - int main() { + using namespace gucc; // NOLINT + static constexpr std::string_view filename{"/tmp/mkinitcpio.conf"}; // Open mkinitcpio file for writing. @@ -72,7 +73,7 @@ int main() { // Check if file is equal to test data. // "\n# MODULES\nMODULES=(crc32c-intel)\n\n# BINARIES\nBINARIES=()\n\n# FILES\nFILES=()\n\n# HOOKS\nHOOKS=(base usr lvm2 zfs)"\n - const auto& file_content = utils::read_whole_file(filename); + const auto& file_content = file_utils::read_whole_file(filename); assert(file_content == MKINITCPIO_TEST); // Cleanup. diff --git a/tests/unit-pacmanconf.cpp b/gucc/tests/unit-pacmanconf.cpp similarity index 96% rename from tests/unit-pacmanconf.cpp rename to gucc/tests/unit-pacmanconf.cpp index 2d65ee5..a600e1a 100644 --- a/tests/unit-pacmanconf.cpp +++ b/gucc/tests/unit-pacmanconf.cpp @@ -1,12 +1,12 @@ -#include "utils.hpp" +#include "file_utils.hpp" #include "pacmanconf_repo.hpp" #include +#include #include #include #include #include -#include namespace fs = std::filesystem; @@ -117,8 +117,9 @@ Include = /etc/pacman.d/mirrorlist [multilib] Include = /etc/pacman.d/mirrorlist)"; - int main() { + using namespace gucc; + static constexpr std::string_view filename{"/tmp/pacman.conf"}; // Open pacmanconf file for writing. @@ -136,14 +137,14 @@ int main() { // Push repo. assert(detail::pacmanconf::push_repos_front(filename, "[cachyos]\nInclude = /etc/pacman.d/cachyos-mirrorlist")); - + // Check repo list after pushing repo. repo_list = detail::pacmanconf::get_repo_list(filename); assert(!repo_list.empty()); assert((repo_list == std::vector{"[cachyos]", "[core]", "[extra]", "[community]", "[multilib]"})); // Check if file is equal to test data. - const auto& file_content = utils::read_whole_file(filename); + const auto& file_content = file_utils::read_whole_file(filename); assert(file_content == PACMANCONF_TEST); // Cleanup. diff --git a/src/chwd_profiles.cpp b/src/chwd_profiles.cpp index c94e1cc..8258153 100644 --- a/src/chwd_profiles.cpp +++ b/src/chwd_profiles.cpp @@ -1,6 +1,9 @@ #include "chwd_profiles.hpp" #include "utils.hpp" +// import gucc +#include "string_utils.hpp" + #include // for any_of, sort, for_each #include @@ -61,7 +64,7 @@ auto get_available_profile_names(std::string_view profile_type) noexcept -> std: if (!all_profile_names.has_value()) { return {}; } /* clang-format on */ - const auto& available_profile_names = utils::make_multiline(utils::exec("chwd --list -d | grep Name | awk '{print $4}'")); + const auto& available_profile_names = gucc::utils::make_multiline(utils::exec("chwd --list -d | grep Name | awk '{print $4}'")); std::vector filtered_profile_names{}; const auto& functor = [available_profile_names](auto&& profile_name) { return ranges::any_of(available_profile_names, [profile_name](auto&& available_profile) { return available_profile == profile_name; }); }; diff --git a/src/crypto.cpp b/src/crypto.cpp index 2850921..c77bcf7 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -3,6 +3,12 @@ #include "utils.hpp" #include "widgets.hpp" +// import gucc +#include "string_utils.hpp" + +#include +#include + /* clang-format off */ #include // for Component, ScreenI... #include // for operator|, size @@ -30,7 +36,7 @@ bool select_crypt_partition(const std::string_view& text) noexcept { bool success{}; auto ok_callback = [&] { const auto& src = partitions[static_cast(selected)]; - const auto& lines = utils::make_multiline(src, false, ' '); + const auto& lines = gucc::utils::make_multiline(src, false, ' '); config_data["PARTITION"] = lines[0]; success = true; screen.ExitLoopClosure()(); @@ -75,7 +81,7 @@ bool luks_open() noexcept { // Filter out partitions that don't contain crypt device /*const auto& ignore_part = utils::list_non_crypt(); - const auto& parts = utils::make_multiline(ignore_part); + const auto& parts = gucc::utils::make_multiline(ignore_part); for (const auto& part : parts) { utils::delete_partition_in_list(part); }*/ diff --git a/src/disk.cpp b/src/disk.cpp index d1d52b2..0573fdd 100644 --- a/src/disk.cpp +++ b/src/disk.cpp @@ -3,6 +3,9 @@ #include "utils.hpp" #include "widgets.hpp" +// import gucc +#include "string_utils.hpp" + #include // for exists, is_directory #include // for Renderer, Button #include // for ButtonOption @@ -37,7 +40,7 @@ void btrfs_create_subvols([[maybe_unused]] const disk_part& disk, const std::str } const auto& saved_path = fs::current_path(); fs::current_path("/mnt"); - auto subvol_list = utils::make_multiline(subvols, false, ' '); + auto subvol_list = gucc::utils::make_multiline(subvols, false, ' '); for (const auto& subvol : subvol_list) { utils::exec(fmt::format(FMT_COMPILE("btrfs subvolume create {} 2>>/tmp/cachyos-install.log"), subvol), true); } @@ -107,7 +110,7 @@ void mount_existing_subvols(const disk_part& disk) noexcept { umount("/mnt"); // Mount subvolumes one by one - for (const auto& subvol : utils::make_multiline(utils::exec("cat /tmp/.subvols"sv))) { + for (const auto& subvol : gucc::utils::make_multiline(utils::exec("cat /tmp/.subvols"sv))) { // Ask for mountpoint const auto& content = fmt::format(FMT_COMPILE("\nInput mountpoint of\nthe subvolume {}\nas it would appear\nin installed system\n(without prepending /mnt).\n"), subvol); std::string mountpoint{"/"}; @@ -125,7 +128,7 @@ void mount_existing_subvols(const disk_part& disk) noexcept { } std::vector lvm_show_vg() noexcept { - const auto& vg_list = utils::make_multiline(utils::exec("lvs --noheadings | awk '{print $2}' | uniq"sv)); + const auto& vg_list = gucc::utils::make_multiline(utils::exec("lvs --noheadings | awk '{print $2}' | uniq"sv)); std::vector res{}; res.reserve(vg_list.size()); @@ -243,7 +246,7 @@ std::string zfs_list_pools() noexcept { std::string zfs_list_devs() noexcept { std::string list_of_devices{}; // get a list of devices with zpools on them - const auto& devices = utils::make_multiline(utils::exec("zpool status -PL 2>/dev/null | awk '{print $1}' | grep \"^/\""sv)); + const auto& devices = gucc::utils::make_multiline(utils::exec("zpool status -PL 2>/dev/null | awk '{print $1}' | grep \"^/\""sv)); for (const auto& device : devices) { // add the device list_of_devices += fmt::format(FMT_COMPILE("{}\n"), device); diff --git a/src/follow_process_log.cpp b/src/follow_process_log.cpp index 86f0e79..11f2f86 100644 --- a/src/follow_process_log.cpp +++ b/src/follow_process_log.cpp @@ -1,8 +1,11 @@ #include "follow_process_log.hpp" #include "subprocess.h" -#include "utils.hpp" // for make_multiline +#include "utils.hpp" // for exec_follow #include "widgets.hpp" +// import gucc +#include "string_utils.hpp" + #include // for operator""s, chrono_literals #include // for string, operator<<, to_string #include @@ -70,7 +73,7 @@ void follow_process_log_widget(const std::vector& vec, Decorator bo auto container = Container::Horizontal({button_back}); auto renderer = Renderer(container, [&] { - return tui::detail::centered_widget(container, "New CLI Installer", tui::detail::multiline_text(utils::make_multiline(process_log, true)) | box_size | vscroll_indicator | yframe | flex); + return tui::detail::centered_widget(container, "New CLI Installer", tui::detail::multiline_text(gucc::utils::make_multiline(process_log, true)) | box_size | vscroll_indicator | yframe | flex); }); screen.Loop(renderer); diff --git a/src/simple_tui.cpp b/src/simple_tui.cpp index c5207d5..12d3f01 100644 --- a/src/simple_tui.cpp +++ b/src/simple_tui.cpp @@ -5,6 +5,9 @@ #include "utils.hpp" #include "widgets.hpp" +// import gucc +#include "string_utils.hpp" + /* clang-format off */ #include // for setenv #include // for mount @@ -18,6 +21,7 @@ #include // for operator|, size /* clang-format on */ +#include #include using namespace ftxui; @@ -151,7 +155,7 @@ auto make_partitions_prepared(std::string_view bootloader, std::string_view root std::string root_part{}; for (auto&& ready_part : ready_parts) { - auto part_info = utils::make_multiline(ready_part, false, '\t'); + auto part_info = gucc::utils::make_multiline(ready_part, false, '\t'); auto part_name = part_info[0]; auto part_mountpoint = part_info[1]; @@ -230,7 +234,7 @@ auto get_root_part(std::string_view device_info) noexcept -> std::string { /* clang-format off */ if (!partition.starts_with(device_info)) { continue; } /* clang-format on */ - const auto& partition_stat = utils::make_multiline(partition, false, ' '); + const auto& partition_stat = gucc::utils::make_multiline(partition, false, ' '); const auto& part_name = partition_stat[0]; const auto& part_size = partition_stat[1]; @@ -268,26 +272,26 @@ auto auto_make_partitions(std::string_view device_info, std::string_view root_fs } const auto& partitions = std::get>(config_data["PARTITIONS"]); for (const auto& partition : partitions) {*/ - /* clang-format off */ + /* clang-format off */ //if (!partition.starts_with(device_info)) { continue; } - /* clang-format on */ - /*const auto& partition_stat = utils::make_multiline(partition, false, ' '); - const auto& part_name = partition_stat[0]; - const auto& part_size = partition_stat[1]; - - auto part_type{"additional"}; - if (part_size == "512M"sv || part_size == "1G"sv || part_size == "2G"sv) { - //make_esp(part_name, bootloader); - spdlog::info("boot partition: name={}", part_name); - continue; - } - - auto&& part_data = fmt::format(FMT_COMPILE("{}\t{}\t{}\t{}\t{}"), part_name, - partition_map["mountpoint"].GetString(), partition_map["size"].GetString(), part_fs_name, part_type); - ready_parts.emplace_back(std::move(part_data)); + /* clang-format on */ + /*const auto& partition_stat = gucc::utils::make_multiline(partition, false, ' '); + const auto& part_name = partition_stat[0]; + const auto& part_size = partition_stat[1]; + + auto part_type{"additional"}; + if (part_size == "512M"sv || part_size == "1G"sv || part_size == "2G"sv) { + //make_esp(part_name, bootloader); + spdlog::info("boot partition: name={}", part_name); + continue; } - auto root_part = std::max_element(parts.begin(), parts.end(), [](auto&& lhs, auto&& rhs) { return lhs.second < rhs.second; })->first; - ready_parts.push_back();*/ + + auto&& part_data = fmt::format(FMT_COMPILE("{}\t{}\t{}\t{}\t{}"), part_name, + partition_map["mountpoint"].GetString(), partition_map["size"].GetString(), part_fs_name, part_type); + ready_parts.emplace_back(std::move(part_data)); +} +auto root_part = std::max_element(parts.begin(), parts.end(), [](auto&& lhs, auto&& rhs) { return lhs.second < rhs.second; })->first; +ready_parts.push_back();*/ return ready_parts; } @@ -366,16 +370,16 @@ void menu_simple() noexcept { // something similar to default partioning table created by calamares is fine. if (ready_parts.empty()) { spdlog::info("TODO: auto make layout(ready parts)!"); - //ready_parts = auto_make_partitions(device_info, fs_name, mount_opts_info); + // ready_parts = auto_make_partitions(device_info, fs_name, mount_opts_info); return; } const auto root_ready_part = *std::find_if(ready_parts.begin(), ready_parts.end(), [](const std::string_view& ready_part) { - const auto part_type = utils::make_multiline(ready_part, false, '\t')[4]; + const auto part_type = gucc::utils::make_multiline(ready_part, false, '\t')[4]; return part_type == "root"sv; }); - auto root_part = utils::make_multiline(root_ready_part, false, '\t')[0]; - if(!make_partitions_prepared(bootloader, fs_name, mount_opts_info, ready_parts)) { + auto root_part = gucc::utils::make_multiline(root_ready_part, false, '\t')[0]; + if (!make_partitions_prepared(bootloader, fs_name, mount_opts_info, ready_parts)) { utils::umount_partitions(); return; } diff --git a/src/tui.cpp b/src/tui.cpp index 666b8b0..d888b6a 100644 --- a/src/tui.cpp +++ b/src/tui.cpp @@ -9,6 +9,12 @@ #include "utils.hpp" #include "widgets.hpp" +// import gucc +#include "string_utils.hpp" + +#include +#include + /* clang-format off */ #include // for setenv #include // for mount @@ -169,7 +175,7 @@ void set_hostname() noexcept { // Set system language void set_locale() noexcept { - const auto& locales = utils::make_multiline(utils::exec("cat /etc/locale.gen | grep -v \"# \" | sed 's/#//g' | awk '/UTF-8/ {print $1}'")); + const auto& locales = gucc::utils::make_multiline(utils::exec("cat /etc/locale.gen | grep -v \"# \" | sed 's/#//g' | awk '/UTF-8/ {print $1}'")); // System language std::string locale{}; @@ -195,7 +201,7 @@ void set_locale() noexcept { // Set keymap for X11 void set_xkbmap() noexcept { static constexpr auto keymaps_xkb = "af al am at az ba bd be bg br bt bw by ca cd ch cm cn cz de dk ee es et eu fi fo fr gb ge gh gn gr hr hu ie il in iq ir is it jp ke kg kh kr kz la lk lt lv ma md me mk ml mm mn mt mv ng nl no np pc ph pk pl pt ro rs ru se si sk sn sy tg th tj tm tr tw tz ua us uz vn za"sv; - const auto& xkbmap_list = utils::make_multiline(keymaps_xkb, false, ' '); + const auto& xkbmap_list = gucc::utils::make_multiline(keymaps_xkb, false, ' '); auto screen = ScreenInteractive::Fullscreen(); std::int32_t selected{86}; @@ -232,7 +238,7 @@ void select_keymap() noexcept { if (!keep_default) { return; } /* clang-format on */ - const auto& keymaps = utils::make_multiline(utils::exec(R"(ls -R /usr/share/kbd/keymaps | grep "map.gz" | sed 's/\.map\.gz//g' | sort)")); + const auto& keymaps = gucc::utils::make_multiline(utils::exec(R"(ls -R /usr/share/kbd/keymaps | grep "map.gz" | sed 's/\.map\.gz//g' | sort)")); auto screen = ScreenInteractive::Fullscreen(); std::int32_t selected{226}; @@ -252,7 +258,7 @@ bool set_timezone() noexcept { { auto screen = ScreenInteractive::Fullscreen(); const auto& cmd = utils::exec(R"(cat /usr/share/zoneinfo/zone.tab | awk '{print $3}' | grep "/" | sed "s/\/.*//g" | sort -ud)"); - const auto& zone_list = utils::make_multiline(cmd); + const auto& zone_list = gucc::utils::make_multiline(cmd); std::int32_t selected{}; auto ok_callback = [&] { @@ -272,7 +278,7 @@ bool set_timezone() noexcept { { auto screen = ScreenInteractive::Fullscreen(); const auto& cmd = utils::exec(fmt::format(FMT_COMPILE("cat /usr/share/zoneinfo/zone.tab | {1} | grep \"{0}/\" | sed \"s/{0}\\///g\" | sort -ud"), zone, "awk '{print $3}'")); - const auto& city_list = utils::make_multiline(cmd); + const auto& city_list = gucc::utils::make_multiline(cmd); std::int32_t selected{}; auto ok_callback = [&] { @@ -878,14 +884,14 @@ bool select_device() noexcept { auto* config_instance = Config::instance(); auto& config_data = config_instance->data(); auto devices = utils::exec(R"(lsblk -lno NAME,SIZE,TYPE | grep 'disk' | awk '{print "/dev/" $1 " " $2}' | sort -u)"); - const auto& devices_list = utils::make_multiline(devices); + const auto& devices_list = gucc::utils::make_multiline(devices); auto screen = ScreenInteractive::Fullscreen(); std::int32_t selected{}; bool success{}; auto ok_callback = [&] { const auto& src = devices_list[static_cast(selected)]; - const auto& lines = utils::make_multiline(src, false, ' '); + const auto& lines = gucc::utils::make_multiline(src, false, ' '); config_data["DEVICE"] = lines[0]; success = true; screen.ExitLoopClosure()(); @@ -916,7 +922,7 @@ bool select_filesystem() noexcept { bool success{}; auto ok_callback = [&] { const auto& src = menu_entries[static_cast(selected)]; - const auto& lines = utils::make_multiline(src, false, ' '); + const auto& lines = gucc::utils::make_multiline(src, false, ' '); const auto& file_sys = lines[0]; utils::select_filesystem(file_sys); success = true; @@ -1077,7 +1083,7 @@ bool mount_current_partition(bool force) noexcept { }; // Check if LUKS on LVM (parent = lvm /dev/mapper/...) - auto cryptparts = utils::make_multiline(utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep "lvm" | grep -i "crypto_luks" | uniq | awk '{print "/dev/mapper/"$1}')")); + auto cryptparts = gucc::utils::make_multiline(utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep "lvm" | grep -i "crypto_luks" | uniq | awk '{print "/dev/mapper/"$1}')")); auto check_functor = [&](const auto cryptpart) { config_data["LUKS_DEV"] = fmt::format(FMT_COMPILE("{} cryptdevice={}:{}"), luks_dev, cryptpart, luks_name); config_data["LVM"] = 1; @@ -1087,13 +1093,13 @@ bool mount_current_partition(bool force) noexcept { } // Check if LVM on LUKS - cryptparts = utils::make_multiline(utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep " crypt$" | grep -i "LVM2_member" | uniq | awk '{print "/dev/mapper/"$1}')")); + cryptparts = gucc::utils::make_multiline(utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep " crypt$" | grep -i "LVM2_member" | uniq | awk '{print "/dev/mapper/"$1}')")); if (check_cryptparts(cryptparts, check_functor)) { return true; } // Check if LUKS alone (parent = part /dev/...) - cryptparts = utils::make_multiline(utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep "part" | grep -i "crypto_luks" | uniq | awk '{print "/dev/"$1}')")); + cryptparts = gucc::utils::make_multiline(utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep "part" | grep -i "crypto_luks" | uniq | awk '{print "/dev/"$1}')")); const auto& check_func_dev = [&](const auto cryptpart) { auto& luks_uuid = std::get(config_data["LUKS_UUID"]); luks_uuid = utils::exec(fmt::format(FMT_COMPILE("lsblk -lno UUID,TYPE,FSTYPE {} | grep \"part\" | grep -i \"crypto_luks\" | {}"), cryptpart, "awk '{print $1}'")); @@ -1162,7 +1168,7 @@ void make_swap() noexcept { bool success{}; auto ok_callback = [&] { const auto& src = temp[static_cast(selected)]; - const auto& lines = utils::make_multiline(src, false, ' '); + const auto& lines = gucc::utils::make_multiline(src, false, ' '); answer = lines[0]; success = true; screen.ExitLoopClosure()(); @@ -1322,7 +1328,7 @@ bool zfs_create_zpool(bool do_create_zpool = true) noexcept { ignore_part += utils::zfs_list_devs(); ignore_part += utils::list_containing_crypt(); - /* const auto& parts = utils::make_multiline(ignore_part); + /* const auto& parts = gucc::utils::make_multiline(ignore_part); for (const auto& part : parts) { utils::delete_partition_in_list(part); }*/ @@ -1336,7 +1342,7 @@ bool zfs_create_zpool(bool do_create_zpool = true) noexcept { bool success{}; auto ok_callback = [&] { const auto& src = partitions[static_cast(selected)]; - const auto& lines = utils::make_multiline(src, false, ' '); + const auto& lines = gucc::utils::make_multiline(src, false, ' '); config_data["PARTITION"] = lines[0]; success = true; screen.ExitLoopClosure()(); @@ -1391,7 +1397,7 @@ bool zfs_create_zpool(bool do_create_zpool = true) noexcept { } bool zfs_import_pool() noexcept { - const auto& zlist = utils::make_multiline(utils::exec("zpool import 2>/dev/null | grep \"^[[:space:]]*pool\" | awk -F : '{print $2}' | awk '{$1=$1};1'")); + const auto& zlist = gucc::utils::make_multiline(utils::exec("zpool import 2>/dev/null | grep \"^[[:space:]]*pool\" | awk -F : '{print $2}' | awk '{$1=$1};1'")); if (zlist.empty()) { // no available datasets detail::infobox_widget("\nNo pools available\"\n"sv); @@ -1431,7 +1437,7 @@ bool zfs_import_pool() noexcept { } bool zfs_new_ds(const std::string_view& zmount = "") noexcept { - const auto& zlist = utils::make_multiline(utils::zfs_list_pools()); + const auto& zlist = gucc::utils::make_multiline(utils::zfs_list_pools()); if (zlist.empty()) { // no available datasets detail::infobox_widget("\nNo pools available\"\n"sv); @@ -1518,7 +1524,7 @@ bool zfs_new_ds(const std::string_view& zmount = "") noexcept { } void zfs_set_property() noexcept { - const auto& zlist = utils::make_multiline(utils::zfs_list_datasets()); + const auto& zlist = gucc::utils::make_multiline(utils::zfs_list_datasets()); if (zlist.empty()) { // no available datasets detail::infobox_widget("\nNo datasets available\"\n"sv); @@ -1573,7 +1579,7 @@ void zfs_set_property() noexcept { } void zfs_destroy_dataset() noexcept { - const auto& zlist = utils::make_multiline(utils::zfs_list_datasets()); + const auto& zlist = gucc::utils::make_multiline(utils::zfs_list_datasets()); if (zlist.empty()) { // no available datasets detail::infobox_widget("\nNo datasets available\"\n"sv); @@ -1737,7 +1743,7 @@ void make_esp() noexcept { bool success{}; auto ok_callback = [&] { const auto& src = partitions[static_cast(selected)]; - const auto& lines = utils::make_multiline(src, false, ' '); + const auto& lines = gucc::utils::make_multiline(src, false, ' '); answer = lines[0]; success = true; screen.ExitLoopClosure()(); @@ -1836,7 +1842,7 @@ void mount_partitions() noexcept { ignore_part += utils::zfs_list_devs(); ignore_part += utils::list_containing_crypt(); - /* const auto& parts = utils::make_multiline(ignore_part); + /* const auto& parts = gucc::utils::make_multiline(ignore_part); for (const auto& part : parts) { utils::delete_partition_in_list(part); }*/ @@ -1856,7 +1862,7 @@ void mount_partitions() noexcept { auto ok_callback = [&] { const auto& src = partitions[static_cast(selected)]; - const auto& lines = utils::make_multiline(src, false, ' '); + const auto& lines = gucc::utils::make_multiline(src, false, ' '); config_data["PARTITION"] = lines[0]; config_data["ROOT_PART"] = lines[0]; success = true; @@ -1927,7 +1933,7 @@ void mount_partitions() noexcept { NUMBER_PARTITIONS=$(( NUMBER_PARTITIONS + 1 )) done*/ - /*const auto& parts_tmp = utils::make_multiline(utils::list_mounted()); + /*const auto& parts_tmp = gucc::utils::make_multiline(utils::list_mounted()); for (const auto& part : parts_tmp) { utils::delete_partition_in_list(part); }*/ @@ -1948,7 +1954,7 @@ void mount_partitions() noexcept { bool success{}; auto ok_callback = [&] { const auto& src = temp[static_cast(selected)]; - const auto& lines = utils::make_multiline(src, false, ' '); + const auto& lines = gucc::utils::make_multiline(src, false, ' '); config_data["PARTITION"] = lines[0]; success = true; screen.ExitLoopClosure()(); diff --git a/src/utils.cpp b/src/utils.cpp index 41eceb3..cb347fb 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -8,6 +8,10 @@ #include "tui.hpp" #include "widgets.hpp" +// import gucc +#include "file_utils.hpp" +#include "string_utils.hpp" + #include // for transform #include // for array #include // for bit_cast @@ -27,6 +31,7 @@ #include // for execvp, fork #include // for unordered_map +#include #include #if defined(__clang__) @@ -263,41 +268,6 @@ std::string exec(const std::string_view& command, const bool& interactive) noexc return result; } -auto read_whole_file(const std::string_view& filepath) noexcept -> std::string { - // Use std::fopen because it's faster than std::ifstream - auto* file = std::fopen(filepath.data(), "rb"); - if (file == nullptr) { - spdlog::error("[READWHOLEFILE] '{}' read failed: {}", filepath, std::strerror(errno)); - return {}; - } - - std::fseek(file, 0u, SEEK_END); - const auto size = static_cast(std::ftell(file)); - std::fseek(file, 0u, SEEK_SET); - - std::string buf; - buf.resize(size); - - const std::size_t read = std::fread(buf.data(), sizeof(char), size, file); - if (read != size) { - spdlog::error("[READWHOLEFILE] '{}' read failed: {}", filepath, std::strerror(errno)); - return {}; - } - std::fclose(file); - - return buf; -} - -bool write_to_file(const std::string_view& data, const std::string_view& filepath) noexcept { - std::ofstream file{filepath.data()}; - if (!file.is_open()) { - spdlog::error("[WRITE_TO_FILE] '{}' open failed: {}", filepath, std::strerror(errno)); - return false; - } - file << data; - return true; -} - void dump_to_log(const std::string& data) noexcept { spdlog::info("[DUMP_TO_LOG] :=\n{}", data); } @@ -329,42 +299,6 @@ bool prompt_char(const char* prompt, const char* color, char* read) noexcept { return true; } -auto make_multiline(std::string_view str, bool reverse, char delim) noexcept -> std::vector { - std::vector lines{}; - ranges::for_each(utils::make_split_view(str, delim), [&](auto&& rng) { lines.emplace_back(rng); }); - if (reverse) { - ranges::reverse(lines); - } - return lines; -} - -auto make_multiline_view(std::string_view str, bool reverse, char delim) noexcept -> std::vector { - std::vector lines{}; - ranges::for_each(utils::make_split_view(str, delim), [&](auto&& rng) { lines.emplace_back(rng); }); - if (reverse) { - ranges::reverse(lines); - } - return lines; -} - -auto make_multiline(const std::vector& multiline, bool reverse, std::string_view delim) noexcept -> std::string { - std::string res{}; - for (const auto& line : multiline) { - res += line; - res += delim.data(); - } - - if (reverse) { - ranges::reverse(res); - } - - return res; -} - -auto join(const std::vector& lines, std::string_view delim) noexcept -> std::string { - return lines | ranges::views::join(delim) | ranges::to(); -} - // install a pkg in the live session if not installed void inst_needed(const std::string_view& pkg) noexcept { if (utils::exec(fmt::format(FMT_COMPILE("pacman -Qq {} &>/dev/null"), pkg), true) != "0") { @@ -400,7 +334,7 @@ void umount_partitions() noexcept { utils::exec("swapoff -a"); #endif - const auto& lines = utils::make_multiline(mount_info); + const auto& lines = gucc::utils::make_multiline(mount_info); for (const auto& line : lines) { #ifdef NDEVENV umount(line.c_str()); @@ -421,7 +355,7 @@ void auto_partition() noexcept { #ifdef NDEVENV // Find existing partitions (if any) to remove const auto& parts = utils::exec(fmt::format(FMT_COMPILE("parted -s {} print | {}"), device_info, "awk '/^ / {print $1}'")); - const auto& del_parts = utils::make_multiline(parts); + const auto& del_parts = gucc::utils::make_multiline(parts); for (const auto& del_part : del_parts) { utils::exec(fmt::format(FMT_COMPILE("parted -s {} rm {} 2>>/tmp/cachyos-install.log &>/dev/null"), device_info, del_part)); } @@ -485,7 +419,7 @@ void generate_fstab(const std::string_view& fstab_cmd) noexcept { utils::exec(fmt::format(FMT_COMPILE("{0} {1} > {1}/etc/fstab"), fstab_cmd, mountpoint)); spdlog::info("Created fstab file:"); - const auto& fstab_content = utils::read_whole_file(fmt::format(FMT_COMPILE("{}/etc/fstab"), mountpoint)); + const auto& fstab_content = gucc::file_utils::read_whole_file(fmt::format(FMT_COMPILE("{}/etc/fstab"), mountpoint)); utils::dump_to_log(fstab_content); const auto& swap_file = fmt::format(FMT_COMPILE("{}/swapfile"), mountpoint); @@ -498,7 +432,7 @@ void generate_fstab(const std::string_view& fstab_cmd) noexcept { utils::exec(fmt::format(FMT_COMPILE("sed -i \"s/subvolid=.*,subvol=\\/.*,//g\" {}/etc/fstab"), mountpoint)); // remove any zfs datasets that are mounted by zfs - const auto& msource_list = utils::make_multiline(utils::exec(fmt::format(FMT_COMPILE("cat {}/etc/fstab | grep \"^[a-z,A-Z]\" | {}"), mountpoint, "awk '{print $1}'"))); + const auto& msource_list = gucc::utils::make_multiline(utils::exec(fmt::format(FMT_COMPILE("cat {}/etc/fstab | grep \"^[a-z,A-Z]\" | {}"), mountpoint, "awk '{print $1}'"))); for (const auto& msource : msource_list) { if (utils::exec(fmt::format(FMT_COMPILE("zfs list -H -o mountpoint,name | grep \"^/\" | {} | grep \"^{}$\""), "awk '{print $2}'", msource), true) == "0") utils::exec(fmt::format(FMT_COMPILE("sed -e \"\\|^{}[[:space:]]| s/^#*/#/\" -i {}/etc/fstab"), msource, mountpoint)); @@ -681,7 +615,7 @@ void find_partitions() noexcept { // partition_list="${partition_list} /dev/md/${i}" // done - const auto& partition_list = utils::make_multiline(partitions_tmp, true); + const auto& partition_list = gucc::utils::make_multiline(partitions_tmp, true); config_data["PARTITIONS"] = partition_list; number_partitions = static_cast(partition_list.size()); @@ -742,7 +676,7 @@ auto get_pkglist_base(const std::string_view& packages) noexcept -> std::vector< const auto& is_root_on_btrfs = (root_filesystem == "btrfs"); const auto& is_root_on_bcachefs = (root_filesystem == "bcachefs"); - auto pkg_list = utils::make_multiline(packages, false, ' '); + auto pkg_list = gucc::utils::make_multiline(packages, false, ' '); const auto pkg_count = pkg_list.size(); for (std::size_t i = 0; i < pkg_count; ++i) { @@ -987,7 +921,7 @@ void install_from_pkglist(const std::string_view& packages) noexcept { void install_base(const std::string_view& packages) noexcept { const auto& pkg_list = utils::get_pkglist_base(packages); - const auto& base_pkgs = utils::make_multiline(pkg_list, false, " "); + const auto& base_pkgs = gucc::utils::make_multiline(pkg_list, false, " "); spdlog::info(fmt::format(FMT_COMPILE("Preparing for pkgs to install: \"{}\""), base_pkgs)); @@ -1082,7 +1016,7 @@ void install_base(const std::string_view& packages) noexcept { void install_desktop(const std::string_view& desktop) noexcept { // Create the base list of packages const auto& pkg_list = utils::get_pkglist_desktop(desktop); - const std::string& packages = utils::make_multiline(pkg_list, false, " "); + const std::string& packages = gucc::utils::make_multiline(pkg_list, false, " "); spdlog::info(fmt::format(FMT_COMPILE("Preparing for desktop envs to install: \"{}\""), packages)); utils::install_from_pkglist(packages); @@ -1308,7 +1242,7 @@ void install_refind() noexcept { } spdlog::info("Created rEFInd config:"); - const auto& refind_conf_content = utils::read_whole_file(fmt::format(FMT_COMPILE("{}/boot/refind_linux.conf"), mountpoint)); + const auto& refind_conf_content = gucc::file_utils::read_whole_file(fmt::format(FMT_COMPILE("{}/boot/refind_linux.conf"), mountpoint)); utils::dump_to_log(refind_conf_content); utils::install_from_pkglist("refind-theme-nord"); @@ -1561,7 +1495,7 @@ void get_cryptroot() noexcept { // Check if LUKS on LVM (parent = lvm /dev/mapper/...) auto temp_out = utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE,MOUNTPOINT | grep "lvm" | grep "/mnt$" | grep -i "crypto_luks" | uniq | awk '{print "/dev/mapper/"$1}')"); if (!temp_out.empty()) { - const auto& cryptparts = utils::make_multiline(temp_out); + const auto& cryptparts = gucc::utils::make_multiline(temp_out); const auto& check_functor = [&](const auto& cryptpart) { config_data["LUKS_DEV"] = fmt::format(FMT_COMPILE("cryptdevice={}:{}"), cryptpart, luks_name); config_data["LVM"] = 1; @@ -1573,7 +1507,7 @@ void get_cryptroot() noexcept { // Check if LVM on LUKS temp_out = utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE | grep " crypt$" | grep -i "LVM2_member" | uniq | awk '{print "/dev/mapper/"$1}')"); if (!temp_out.empty()) { - const auto& cryptparts = utils::make_multiline(temp_out); + const auto& cryptparts = gucc::utils::make_multiline(temp_out); const auto& check_functor = [&]([[maybe_unused]] const auto& cryptpart) { auto& luks_uuid = std::get(config_data["LUKS_UUID"]); luks_uuid = utils::exec(R"(lsblk -ino NAME,FSTYPE,TYPE,MOUNTPOINT,UUID | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e "/\/mnt /,/part/p" | awk '/crypto_LUKS/ {print $4}')"); @@ -1587,7 +1521,7 @@ void get_cryptroot() noexcept { // Check if LUKS alone (parent = part /dev/...) temp_out = utils::exec(R"(lsblk -lno NAME,FSTYPE,TYPE,MOUNTPOINT | grep "/mnt$" | grep "part" | grep -i "crypto_luks" | uniq | awk '{print "/dev/"$1}')"); if (!temp_out.empty()) { - const auto& cryptparts = utils::make_multiline(temp_out); + const auto& cryptparts = gucc::utils::make_multiline(temp_out); const auto& check_functor = [&](const auto& cryptpart) { auto& luks_uuid = std::get(config_data["LUKS_UUID"]); luks_uuid = utils::exec(fmt::format(FMT_COMPILE("lsblk -lno UUID,TYPE,FSTYPE {} | grep \"part\" | grep -i \"crypto_luks\" | {}"), cryptpart, "awk '{print $1}'")); @@ -1765,7 +1699,7 @@ void install_cachyos_repo() noexcept { } spdlog::info("{} is supported", isa_level); - const auto& repo_list = detail::pacmanconf::get_repo_list("/etc/pacman.conf"); + const auto& repo_list = gucc::detail::pacmanconf::get_repo_list("/etc/pacman.conf"); if (ranges::contains(repo_list, fmt::format(FMT_COMPILE("[{}]"), repo_name))) { spdlog::info("'{}' is already added!", repo_name); return; @@ -1793,7 +1727,7 @@ void install_cachyos_repo() noexcept { }; // Check if it's already been applied - const auto& repo_list = detail::pacmanconf::get_repo_list("/etc/pacman.conf"); + const auto& repo_list = gucc::detail::pacmanconf::get_repo_list("/etc/pacman.conf"); spdlog::info("install_cachyos_repo: repo_list := '{}'", repo_list); #ifdef NDEVENV @@ -1801,7 +1735,7 @@ void install_cachyos_repo() noexcept { utils::exec("pacman-key --lsign-key F3B607488DB35A47", true); #endif - const auto& isa_levels = utils::get_isa_levels(); + const auto& isa_levels = gucc::cpu::get_isa_levels(); static constexpr auto CACHYOS_V1_REPO_STR = R"( [cachyos] diff --git a/src/utils.hpp b/src/utils.hpp index af33ef8..2bd7a0a 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -11,31 +11,6 @@ #include // for string_view #include // for vector -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wold-style-cast" -#pragma clang diagnostic ignored "-Wsign-conversion" -#elif defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnull-dereference" -#pragma GCC diagnostic ignored "-Wuseless-cast" -#pragma GCC diagnostic ignored "-Wold-style-cast" -#endif - -#include -#include -#include -#include -#include - -#if defined(__clang__) -#pragma clang diagnostic pop -#elif defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - -#include - namespace utils { [[nodiscard]] bool is_connected() noexcept; @@ -105,49 +80,6 @@ void grub_mkconfig() noexcept; void enable_services() noexcept; void final_check() noexcept; -/// @brief Split a string into multiple lines based on a delimiter. -/// @param str The string to split. -/// @param reverse Flag indicating whether to reverse the order of the resulting lines. -/// @param delim The delimiter to split the string. -/// @return A vector of strings representing the split lines. -auto make_multiline(std::string_view str, bool reverse = false, char delim = '\n') noexcept -> std::vector; - -/// @brief Split a string into views of multiple lines based on a delimiter. -/// @param str The string to split. -/// @param reverse Flag indicating whether to reverse the order of the resulting lines. -/// @param delim The delimiter to split the string. -/// @return A vector of string views representing the split lines. -auto make_multiline_view(std::string_view str, bool reverse = false, char delim = '\n') noexcept -> std::vector; - -/// @brief Combine multiple lines into a single string using a delimiter. -/// @param multiline The lines to combine. -/// @param reverse Flag indicating whether to reverse the order of the lines before combining. -/// @param delim The delimiter to join the lines. -/// @return The combined lines as a single string. -auto make_multiline(const std::vector& multiline, bool reverse = false, std::string_view delim = "\n") noexcept -> std::string; - -/// @brief Join a vector of strings into a single string using a delimiter. -/// @param lines The lines to join. -/// @param delim The delimiter to join the lines. -/// @return The joined lines as a single string. -auto join(const std::vector& lines, std::string_view delim = "\n") noexcept -> std::string; - -/// @brief Make a split view from a string into multiple lines based on a delimiter. -/// @param str The string to split. -/// @param delim The delimiter to split the string. -/// @return A range view representing the split lines. -constexpr auto make_split_view(std::string_view str, char delim = '\n') noexcept { - constexpr auto functor = [](auto&& rng) { - return std::string_view(&*rng.begin(), static_cast(ranges::distance(rng))); - }; - constexpr auto second = [](auto&& rng) { return rng != ""; }; - - return str - | ranges::views::split(delim) - | ranges::views::transform(functor) - | ranges::views::filter(second); -} - template ::is_integer>> inline T to_int(const std::string_view& str) { diff --git a/src/widgets.cpp b/src/widgets.cpp index 4e2792e..072c26a 100644 --- a/src/widgets.cpp +++ b/src/widgets.cpp @@ -1,5 +1,5 @@ #include "widgets.hpp" -#include "utils.hpp" // for make_multiline +#include "string_utils.hpp" // for make_multiline #include // for transform #include // for size_t @@ -138,7 +138,7 @@ void msgbox_widget(const std::string_view& content, Decorator boxsize) noexcept auto container = Container::Horizontal({button_back}); auto renderer = Renderer(container, [&] { - return detail::centered_widget(container, "New CLI Installer", detail::multiline_text(utils::make_multiline(content)) | boxsize); + return detail::centered_widget(container, "New CLI Installer", detail::multiline_text(gucc::utils::make_multiline(content)) | boxsize); }); /* clang-format on */ @@ -155,7 +155,7 @@ bool inputbox_widget(std::string& value, const std::string_view& content, Decora const InputOption input_option{.on_enter = ok_callback, .password = password}; auto input_value = Input(&value, "", input_option); auto content_container = Renderer([&] { - return multiline_text(utils::make_multiline(content)) | hcenter | boxsize; + return multiline_text(gucc::utils::make_multiline(content)) | hcenter | boxsize; }); auto controls_container = detail::controls_widget({"OK", "Cancel"}, {ok_callback, screen.ExitLoopClosure()}); @@ -186,7 +186,7 @@ void infobox_widget(const std::string_view& content, Decorator boxsize) noexcept Dimension::Full() // Height ); - auto element = detail::centered_widget_nocontrols("New CLI Installer", detail::multiline_text(utils::make_multiline(content)) | vcenter | boxsize); + auto element = detail::centered_widget_nocontrols("New CLI Installer", detail::multiline_text(gucc::utils::make_multiline(content)) | vcenter | boxsize); Render(screen, element); screen.Print(); } @@ -210,7 +210,7 @@ bool yesno_widget(const std::string_view& content, Decorator boxsize) noexcept { }); auto renderer = Renderer(container, [&] { - return detail::centered_widget(container, "New CLI Installer", detail::multiline_text(utils::make_multiline(content)) | hcenter | boxsize); + return detail::centered_widget(container, "New CLI Installer", detail::multiline_text(gucc::utils::make_multiline(content)) | hcenter | boxsize); }); screen.Loop(renderer); @@ -265,7 +265,7 @@ void menu_widget(const std::vector& entries, const std::function& entries, const std::functi Components children{}; if (!widget_res.text.empty()) { children = { - Renderer([&] { return detail::multiline_text(utils::make_multiline(widget_res.text)) | widget_sizes.text_size; }), + Renderer([&] { return detail::multiline_text(gucc::utils::make_multiline(widget_res.text)) | widget_sizes.text_size; }), Renderer([] { return separator(); }), content, Renderer([] { return separator(); }), @@ -338,7 +338,7 @@ void checklist_widget(const std::vector& opts, const std::function< Components children{}; if (!text.empty()) { children = { - Renderer([&] { return std::move(detail::multiline_text(utils::make_multiline(text))) | widget_sizes.text_size; }), + Renderer([&] { return std::move(detail::multiline_text(gucc::utils::make_multiline(text))) | widget_sizes.text_size; }), Renderer([] { return separator(); }), content, Renderer([] { return separator(); }), diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f300966..88c7e42 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,9 +1,6 @@ list(APPEND test_SOURCES ${CMAKE_SOURCE_DIR}/src/config.cpp ${CMAKE_SOURCE_DIR}/src/utils.cpp - ${CMAKE_SOURCE_DIR}/src/cpu.cpp - ${CMAKE_SOURCE_DIR}/src/pacmanconf_repo.cpp - ${CMAKE_SOURCE_DIR}/src/initcpio.cpp ${CMAKE_SOURCE_DIR}/src/chwd_profiles.cpp ${CMAKE_SOURCE_DIR}/src/disk.cpp ${CMAKE_SOURCE_DIR}/src/drivers.cpp @@ -38,7 +35,7 @@ foreach(file ${files}) $<$:-Wno-deprecated-declarations> ) target_include_directories(${testcase} PRIVATE ${CMAKE_BINARY_DIR}/include ${CMAKE_SOURCE_DIR}/include ${CMAKE_CURRENT_DIR}) - target_link_libraries(${testcase} PRIVATE project_warnings project_options test_libreq spdlog::spdlog fmt::fmt ftxui::component range-v3::range-v3 ctre::ctre tomlplusplus::tomlplusplus) + target_link_libraries(${testcase} PRIVATE project_warnings project_options test_libreq spdlog::spdlog fmt::fmt ftxui::component range-v3::range-v3 ctre::ctre tomlplusplus::tomlplusplus gucc::gucc) if(NOT ENABLE_DEVENV) target_link_libraries(${testcase} PRIVATE cpr::cpr) endif() diff --git a/tests/meson.build b/tests/meson.build index 14a5312..c0b2930 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -4,9 +4,6 @@ test_libreq = shared_library('test_libreq', sources : [ source_path + 'config.cpp', source_path + 'utils.cpp', - source_path + 'cpu.cpp', - source_path + 'pacmanconf_repo.cpp', - source_path + 'initcpio.cpp', source_path + 'chwd_profiles.cpp', source_path + 'disk.cpp', source_path + 'drivers.cpp', @@ -36,19 +33,3 @@ executable( link_with: [test_libreq], include_directories: [include_directories(source_path)], install: false) - -executable( - 'test-initcpio', - files('unit-initcpio.cpp'), - dependencies: deps, - link_with: [test_libreq], - include_directories: [include_directories(source_path)], - install: false) - -executable( - 'test-pacmanconf', - files('unit-pacmanconf.cpp'), - dependencies: deps, - link_with: [test_libreq], - include_directories: [include_directories(source_path)], - install: false)