diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..459d31e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,11 @@ +name: github-ci + +on: [push] + + +jobs: + build: + + + steps: + - uses: actions/checkout@v1 \ No newline at end of file diff --git a/.gitignore b/.gitignore index b64ba40..5cbeffb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ build/** +builds/** bin/gdpm +bin/gdpm-tests +cache/** tests */tmp/** vgcore.* diff --git a/.gitlab-ci-local/.gitignore b/.gitlab-ci-local/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/.gitlab-ci-local/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..f7599d0 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,45 @@ +variables: + PROJECT_ROOT_PATH: /home/$USER/gdpm + + +stages: + - build + - test + - package + + +cache: + paths: + - .cache + + +before-script: + - echo "Setting up dependencies..." + - git clone $ + + +build-job: + stage: build + script: + - echo -e "Building executable and libraries...\n$PWD" + - bin/compile.sh + + +test-job: + stage: test + script: + - echo "Running unit tests..." + - bin/gdpm-tests + + +package-job: + stage: package + script: + - echo "Packaging binaries..." + + +deploy-job: + stage: deploy + script: + - echo "Deploying application..." + environment: production \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..d2520c7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,17 @@ +os: linux +language: cpp +compiler: clang + +env: + - ARCH_TRAVIS_VERBOSE=1 + +archlinux: + repos: + packages: + - base-devel + - git + - yay + + script: + - "bin/compile.sh" + diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index d85baee..9a42b42 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -1,6 +1,6 @@ version: 0.1 cli: - version: 0.15.1-beta + version: 1.2.1 lint: enabled: - git-diff-check@SYSTEM diff --git a/CMakeLists.txt b/CMakeLists.txt index f5ada29..5fd8a97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ endif() # Get source files except for main.cpp file(GLOB SRC CONFIG_DEPENDS "src/[!main]*.cpp") +file(GLOB TESTS CONFIG_DEPENDS "tests/*.cpp") # Find all the packages required to build find_package(Threads REQUIRED) @@ -22,24 +23,24 @@ find_package(Catch2 CONFIG REQUIRED) find_package(cxxopts CONFIG REQUIRED) find_package(Poco CONFIG REQUIRED COMPONENTS Net JSON Util) find_package(libzip CONFIG REQUIRED) -find_package(unofficial-sqlite3 CONFIG REQUIRED) # ...used with vcpkg unsuccessfully... +find_package(SQLiteCpp CONFIG REQUIRED) set(CMAKE_CXX_COMPILER "clang++") set(CMAKE_BUILD_RPATH "build/cmake") set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -std=c++20 -Ofast -fPIC -fPIE -fpermissive -Wall -Wno-switch -Wno-unused-variable -Wno-sign-conversion -pedantic-errors" + "${CMAKE_CXX_FLAGS} -std=c++20 -Ofast -fPIC -fPIE -fpermissive -Wall -Wno-switch -Wno-unused-variable -Wno-unused-function -Wno-sign-conversion -pedantic-errors" ) set(INCLUDE_DIRS "include" + "/usr/include/doctest" ${RAPIDJSON_INCLUDE_DIRS} - ${SQLite3_INCLUDE_DIRS} ) set(LINK_LIBS fmt::fmt Threads::Threads Catch2::Catch2 cxxopts::cxxopts - unofficial::sqlite3::sqlite3 + SQLiteCpp -lcurlpp -lzip ) @@ -48,16 +49,19 @@ set(LINK_LIBS add_library(${PROJECT_NAME}-shared SHARED "${SRC}") add_library(${PROJECT_NAME}-static STATIC "${SRC}") add_executable(${PROJECT_NAME} "src/main.cpp") +add_executable(${PROJECT_NAME}-tests "${TESTS}") # Set include directories for targets target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIRS}) target_include_directories(${PROJECT_NAME}-shared PRIVATE ${INCLUDE_DIRS}) target_include_directories(${PROJECT_NAME}-static PRIVATE ${INCLUDE_DIRS}) +target_include_directories(${PROJECT_NAME}-tests PRIVATE ${INCLUDE_DIRS}) # Set link libraries for targets target_link_libraries(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}-shared ${LINK_LIBS}) target_link_libraries(${PROJECT_NAME}-shared PRIVATE ${LINK_LIBS}) target_link_libraries(${PROJECT_NAME}-static PRIVATE ${LINK_LIBS}) +target_link_libraries(${PROJECT_NAME}-tests PRIVATE ${LINK_LIBS}) # Add project unit tests # add_custom_target("${PROJECT_NAME}-tests" SOURCE ${TESTS}) diff --git a/bin/compile.sh b/bin/compile.sh new file mode 100755 index 0000000..8499ed0 --- /dev/null +++ b/bin/compile.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +# Run this script at project root +#meson configure build +#CXX=clang++ meson compile -C build -j$(proc) + + + +# CMake/ninja build system +mkdir -p build +cmake -B build -S . -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -G Ninja +ninja -C build + +# Create symlinks to executables in build folder if necessary +ln -s ../build/gdpm bin/gdpm +ln -s ../build/gdpm-tests bin/gdpm-tests \ No newline at end of file diff --git a/bin/gdpm-compile.sh b/bin/gdpm-compile.sh deleted file mode 100755 index 6c1d02f..0000000 --- a/bin/gdpm-compile.sh +++ /dev/null @@ -1,3 +0,0 @@ -# Run this script at project root -meson configure build -CXX=clang++ meson compile -C build -j$(proc) \ No newline at end of file diff --git a/bin/gdpm-lines.sh b/bin/lines.sh similarity index 100% rename from bin/gdpm-lines.sh rename to bin/lines.sh diff --git a/bin/gdpm-test.sh b/bin/test.sh similarity index 100% rename from bin/gdpm-test.sh rename to bin/test.sh diff --git a/include/cache.hpp b/include/cache.hpp index 74855ae..5bcb2d6 100644 --- a/include/cache.hpp +++ b/include/cache.hpp @@ -1,4 +1,6 @@ +#pragma once + #include "constants.hpp" #include #include diff --git a/include/config.hpp b/include/config.hpp index d36b312..479865c 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -1,6 +1,7 @@ #pragma once #include "constants.hpp" +#include "error.hpp" #include #include @@ -9,7 +10,7 @@ namespace gdpm::config{ - struct config_context{ + struct context{ std::string username; std::string password; std::string path; @@ -24,10 +25,11 @@ namespace gdpm::config{ bool enable_file_logging; int verbose; }; - std::string to_json(const config_context& params); - config_context load(std::filesystem::path path, int verbose = 0); - int save(const config_context& config, int verbose = 0); - config_context make_context(const std::string& username = GDPM_CONFIG_USERNAME, const std::string& password = GDPM_CONFIG_PASSWORD, const std::string& path = GDPM_CONFIG_PATH, const std::string& token = GDPM_CONFIG_TOKEN, const std::string& godot_version = GDPM_CONFIG_GODOT_VERSION, const std::string& packages_dir = GDPM_CONFIG_LOCAL_PACKAGES_DIR, const std::string& tmp_dir = GDPM_CONFIG_LOCAL_TMP_DIR, const std::set& remote_sources = {GDPM_CONFIG_REMOTE_SOURCES}, size_t threads = GDPM_CONFIG_THREADS, size_t timeout = 0, bool enable_sync = GDPM_CONFIG_ENABLE_SYNC, bool enable_file_logging = GDPM_CONFIG_ENABLE_FILE_LOGGING, int verbose = GDPM_CONFIG_VERBOSE); + std::string to_json(const context& params); + context load(std::filesystem::path path, int verbose = 0); + gdpm::error load(std::filesystem:: path, context& config, int verbose = 0); + gdpm::error save(std::filesystem::path path, const context& config, int verbose = 0); + context make_context(const std::string& username = GDPM_CONFIG_USERNAME, const std::string& password = GDPM_CONFIG_PASSWORD, const std::string& path = GDPM_CONFIG_PATH, const std::string& token = GDPM_CONFIG_TOKEN, const std::string& godot_version = GDPM_CONFIG_GODOT_VERSION, const std::string& packages_dir = GDPM_CONFIG_LOCAL_PACKAGES_DIR, const std::string& tmp_dir = GDPM_CONFIG_LOCAL_TMP_DIR, const std::set& remote_sources = {GDPM_CONFIG_REMOTE_SOURCES}, size_t threads = GDPM_CONFIG_THREADS, size_t timeout = 0, bool enable_sync = GDPM_CONFIG_ENABLE_SYNC, bool enable_file_logging = GDPM_CONFIG_ENABLE_FILE_LOGGING, int verbose = GDPM_CONFIG_VERBOSE); - extern config_context config; + extern context config; } \ No newline at end of file diff --git a/include/constants.hpp b/include/constants.hpp index c6499b1..014f7b4 100644 --- a/include/constants.hpp +++ b/include/constants.hpp @@ -6,6 +6,7 @@ namespace gdpm::constants{ const std::string HomePath(std::string(std::getenv("HOME")) + "/"); + const std::string TestPath(HomePath + ".config/gdpm/tests") const std::string ConfigPath(HomePath + ".config/gdpm/config.json"); const std::string LockfilePath(HomePath + ".config/gdpm/gdpm.lck"); const std::string LocalPackagesDir(HomePath + ".config/gdpm/packages"); diff --git a/include/error.hpp b/include/error.hpp new file mode 100644 index 0000000..de017f3 --- /dev/null +++ b/include/error.hpp @@ -0,0 +1,16 @@ + +#include + + +namespace gdpm{ + class error{ + public: + error(int code, const std::string& message): + m_code(code), m_message(message) + {} + + private: + int m_code; + std::string m_message; + } +} \ No newline at end of file diff --git a/include/log.hpp b/include/log.hpp index 7ee38b8..1de8c94 100644 --- a/include/log.hpp +++ b/include/log.hpp @@ -29,7 +29,8 @@ namespace gdpm::log #if GDPM_LOG_LEVEL > 0 vlog( fmt::format(GDPM_COLOR_LOG_INFO "[INFO {}] {}\n" GDPM_COLOR_LOG_RESET, utils::timestamp(), format), - fmt::make_args_checked(format, args...) + // fmt::make_format_args(args...) + fmt::make_format_args(args...) ); #endif } @@ -38,7 +39,8 @@ namespace gdpm::log static constexpr void info_n(const S& format, Args&&...args){ vlog( fmt::format(GDPM_COLOR_LOG_INFO "[INFO {}] {}" GDPM_COLOR_LOG_RESET, utils::timestamp(), format), - fmt::make_args_checked(format, args...) + // fmt::make_format_args(args...) + fmt::make_format_args(args...) ); } @@ -47,7 +49,8 @@ namespace gdpm::log #if GDPM_LOG_LEVEL > 1 vlog( fmt::format(GDPM_COLOR_LOG_ERROR "[ERROR {}] {}\n" GDPM_COLOR_LOG_RESET, utils::timestamp(), format), - fmt::make_args_checked(format, args...) + // fmt::make_format_args(args...) + fmt::make_format_args(args...) ); #endif } @@ -57,7 +60,8 @@ namespace gdpm::log #if GDPM_LOG_LEVEL > 1 vlog( fmt::format(GDPM_COLOR_LOG_DEBUG "[DEBUG {}] {}\n" GDPM_COLOR_LOG_RESET, utils::timestamp(), format), - fmt::make_args_checked(format, args...) + // fmt::make_format_args(args...) + fmt::make_format_args(args...) ); #endif } @@ -66,7 +70,8 @@ namespace gdpm::log static constexpr void print(const S& format, Args&&...args){ vlog( fmt::format("{}", format), - fmt::make_args_checked(format, args...) + // fmt::make_format_args(args...) + fmt::make_format_args(args...) ); } @@ -74,7 +79,8 @@ namespace gdpm::log static constexpr void println(const S& format, Args&&...args){ vlog( fmt::format("{}\n", format), - fmt::make_args_checked(format, args...) + // fmt::make_format_args(args...) + fmt::make_format_args(args...) ); } diff --git a/include/package_manager.hpp b/include/package_manager.hpp index e7451fd..66275c3 100644 --- a/include/package_manager.hpp +++ b/include/package_manager.hpp @@ -14,7 +14,7 @@ namespace gdpm::package_manager{ extern std::vector repo_sources; extern CURL *curl; extern CURLcode res; - extern config::config_context config; + extern config::context config; struct package_info{ size_t asset_id; diff --git a/meson.build b/meson.build index 1c2cea1..1baf497 100644 --- a/meson.build +++ b/meson.build @@ -9,6 +9,7 @@ deps = [ dependency('RapidJSON'), dependency('fmt'), dependency('Catch2'), + dependency('doctest'), dependency('cxxopts'), # dependency('curl'), dependency('curlpp'), diff --git a/src/config.cpp b/src/config.cpp index 6a64af3..fb49926 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -26,8 +26,8 @@ namespace gdpm::config{ - config_context config; - std::string to_json(const config_context& params){ + context config; + std::string to_json(const context& params){ auto _build_json_array = [](std::set a){ std::string o{"["}; for(const std::string& src : a) @@ -57,7 +57,8 @@ namespace gdpm::config{ return json; } - config_context load(std::filesystem::path path, int verbose){ + + context load(std::filesystem::path path, int verbose){ std::fstream file; file.open(path, std::ios::in); if(!file){ @@ -75,7 +76,7 @@ namespace gdpm::config{ */ using namespace rapidjson; - /* Read JSON fro config, parse, and check document. Must make sure that program does not crash here and use default config instead! */ + /* Read JSON from config, parse, and check document. Must make sure that program does not crash here and use default config instead! */ std::string contents, line; while(std::getline(file, line)) contents += line + "\n"; @@ -99,7 +100,7 @@ namespace gdpm::config{ // if(!status){ // log::error("config::load: Could not parse contents of file (Error: {}/{}).", GetParseError_En(status), doc.GetErrorOffset()); - // return config_context(); + // return context(); // } /* Must check if keys exists first, then populate _config_params. */ @@ -141,7 +142,8 @@ namespace gdpm::config{ return config; } - int save(const config_context& config, int verbose){ + + int save(std::filesystem::path path, const context& config, int verbose){ using namespace rapidjson; /* Build a JSON string to pass to document */ @@ -152,7 +154,7 @@ namespace gdpm::config{ /* Dump JSON config to file */ Document doc; doc.Parse(json.c_str()); - std::ofstream ofs(config.path); + std::ofstream ofs(path); OStreamWrapper osw(ofs); PrettyWriter writer(osw); @@ -161,8 +163,9 @@ namespace gdpm::config{ return 0; } - config_context make_context(const std::string& username, const std::string& password, const std::string& path, const std::string& token, const std::string& godot_version, const std::string& packages_dir, const std::string& tmp_dir, const std::set& remote_sources, size_t threads, size_t timeout, bool enable_sync, bool enable_file_logging, int verbose){ - config_context config { + + context make_context(const std::string& username, const std::string& password, const std::string& path, const std::string& token, const std::string& godot_version, const std::string& packages_dir, const std::string& tmp_dir, const std::set& remote_sources, size_t threads, size_t timeout, bool enable_sync, bool enable_file_logging, int verbose){ + context config { .username = username, .password = password, .path = path, diff --git a/src/http.cpp b/src/http.cpp index b4d7fb1..3ffa9a3 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -27,7 +27,7 @@ namespace gdpm::http{ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&buf); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, utils::curl_write_to_buffer); - curl_easy_setopt(curl, CURLOPT_USERAGENT, constants::UserAgent); + curl_easy_setopt(curl, CURLOPT_USERAGENT, constants::UserAgent.c_str()); curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout); res = curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &r.code); @@ -61,7 +61,7 @@ namespace gdpm::http{ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_fields); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&buf); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, utils::curl_write_to_buffer); - curl_easy_setopt(curl, CURLOPT_USERAGENT, constants::UserAgent); + curl_easy_setopt(curl, CURLOPT_USERAGENT, constants::UserAgent.c_str()); curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout); res = curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &r.code); @@ -109,7 +109,7 @@ namespace gdpm::http{ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, utils::curl_write_to_stream); - curl_easy_setopt(curl, CURLOPT_USERAGENT, constants::UserAgent); + curl_easy_setopt(curl, CURLOPT_USERAGENT, constants::UserAgent.c_str()); curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout); res = curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &r.code); diff --git a/src/main.cpp b/src/main.cpp index aff763e..9174348 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,11 @@ // Godot Package Manager (GPM) - #include "constants.hpp" #include "log.hpp" #include "config.hpp" #include "package_manager.hpp" + int main(int argc, char **argv){ gdpm::package_manager::initialize(argc, argv); gdpm::package_manager::execute(); diff --git a/src/package_manager.cpp b/src/package_manager.cpp index 0644198..770c38a 100644 --- a/src/package_manager.cpp +++ b/src/package_manager.cpp @@ -33,7 +33,7 @@ namespace gdpm::package_manager{ std::vector repo_sources; CURL *curl; CURLcode res; - config::config_context config; + config::context config; rest_api::rest_api_context params; command_e command; std::vector packages; @@ -67,6 +67,7 @@ namespace gdpm::package_manager{ return 0; } + int execute(){ run_command(command, packages, opts); if(clean_tmp_dir) @@ -118,8 +119,10 @@ namespace gdpm::package_manager{ } log::println("Packages to install: "); - for(const auto& p : p_found) + for(const auto& p : p_found){ + std::string output((p.is_installed) ? p.title + " (reinstall)" : p.title); log::print(" {} ", (p.is_installed) ? p.title + " (reinstall)" : p.title); + } log::println(""); if(!skip_prompt){ @@ -566,7 +569,7 @@ namespace gdpm::package_manager{ /* Parse command-line arguments using cxxopts */ cxxopts::Options options( argv[0], - "Experimental package manager made for managing assets for the Godot game engine.\n" + "Experimental package manager made for managing assets for the Godot game engine through the command-line.\n" ); options.allow_unrecognised_options(); options.custom_help("[COMMAND] [OPTIONS...]"); @@ -879,4 +882,6 @@ namespace gdpm::package_manager{ return cache::get_package_info_by_title(package_titles); } -} // namespace gdpm::package_manager \ No newline at end of file +} // namespace gdpm::package_manager + +