mirror of
https://github.com/davidallendj/gdpm.git
synced 2025-12-20 03:27:02 -07:00
More refactoring and bug fixes
- Added `libhttp` and `librest_api` targets to CMakeLists.txt - Added examples for `libhttp` and `librest_api` in examples directory - Added `cache` and `add` commands - Added documentation for `libhttp` and `librest_api` - Added all available HTTP response codes to REST API - Changed how `bin/compile.sh` works (must supply args to build)
This commit is contained in:
parent
5a73651ad1
commit
8b1f1374d8
23 changed files with 575 additions and 164 deletions
|
|
@ -14,6 +14,8 @@ endif()
|
|||
# Get source files except for main.cpp
|
||||
file(GLOB SRC CONFIG_DEPENDS "src/[!main]*.cpp")
|
||||
file(GLOB TESTS CONFIG_DEPENDS "tests/*.cpp")
|
||||
set(SRC_HTTP "src/http.cpp")
|
||||
set(SRC_RESTAPI "src/rest_api.cpp")
|
||||
|
||||
# Find all the packages required to build
|
||||
find_package(Threads REQUIRED)
|
||||
|
|
@ -50,6 +52,8 @@ set(LINK_LIBS
|
|||
# Set library and executable targets
|
||||
add_library(${PROJECT_NAME}-shared SHARED "${SRC}")
|
||||
add_library(${PROJECT_NAME}-static STATIC "${SRC}")
|
||||
add_library(${PROJECT_NAME}-http SHARED "${SRC_HTTP}")
|
||||
add_library(${PROJECT_NAME}-restapi SHARED "${SRC_RESTAPI}")
|
||||
add_executable(${PROJECT_NAME} "src/main.cpp")
|
||||
add_executable(${PROJECT_NAME}.static "src/main.cpp")
|
||||
add_executable(${PROJECT_NAME}.tests "${TESTS}")
|
||||
|
|
@ -60,6 +64,8 @@ target_include_directories(${PROJECT_NAME}.static PRIVATE ${INCLUDE_DIRS})
|
|||
target_include_directories(${PROJECT_NAME}.tests 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}-http PRIVATE ${INCLUDE_DIRS})
|
||||
target_include_directories(${PROJECT_NAME}-restapi PRIVATE ${INCLUDE_DIRS})
|
||||
|
||||
# Set link libraries for targets
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}-shared ${LINK_LIBS})
|
||||
|
|
@ -67,6 +73,8 @@ target_link_libraries(${PROJECT_NAME}.static PRIVATE ${PROJECT_NAME}-static ${LI
|
|||
target_link_libraries(${PROJECT_NAME}.tests 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}-http PRIVATE ${LINK_LIBS})
|
||||
target_link_libraries(${PROJECT_NAME}-restapi PRIVATE ${LINK_LIBS})
|
||||
|
||||
# Add project unit tests
|
||||
# add_custom_target("${PROJECT_NAME}-tests" SOURCE ${TESTS})
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ exe=gdpm
|
|||
static=gdpm.static
|
||||
tests=gdpm.tests
|
||||
|
||||
function test_link(){
|
||||
function link_exe(){
|
||||
path=$1
|
||||
link=$2
|
||||
if test -f "$path"
|
||||
|
|
@ -19,7 +19,7 @@ function test_link(){
|
|||
fi
|
||||
}
|
||||
|
||||
function test_strip(){
|
||||
function strip(){
|
||||
path=$1
|
||||
if test -f "$path"
|
||||
then
|
||||
|
|
@ -28,29 +28,65 @@ function test_strip(){
|
|||
fi
|
||||
}
|
||||
|
||||
function generate_docs(){
|
||||
# Generate documentation using `doxygen`
|
||||
cd ${script_dir}/..
|
||||
doxygen
|
||||
}
|
||||
|
||||
function strip_all(){
|
||||
# Strip debug symbols
|
||||
strip ${script_dir}/../build/gdpm
|
||||
strip ${script_dir}/../build/gdpm.static
|
||||
strip ${script_dir}/../build/gdpm.tests
|
||||
}
|
||||
|
||||
function link_all(){
|
||||
# Create symlinks to executables in build folder if necessary
|
||||
link_exe $script_dir/../build/gdpm $script_dir/../bin/$exe
|
||||
link_exe $script_dir/../build/gdpm.static $script_dir/../bin/$static
|
||||
link_exe $script_dir/../build/gdpm.tests $script_dir/../bin/$tests
|
||||
}
|
||||
|
||||
function clean(){
|
||||
rm ${script_dir}/../bin/$exe
|
||||
rm ${script_dir}/../bin/$static
|
||||
rm ${script_dir}/../bin/$tests
|
||||
}
|
||||
|
||||
# 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 . -D CMAKE_EXPORT_COMPILE_COMMANDS=1 -D CMAKE_BUILD_TYPE=Debug -G Ninja
|
||||
ninja -C build -j $(nproc)
|
||||
function build_binaries(){
|
||||
mkdir -p build
|
||||
cmake -B build -S . -D CMAKE_EXPORT_COMPILE_COMMANDS=1 -D CMAKE_BUILD_TYPE=Debug -G Ninja
|
||||
ninja -C build -j $(nproc)
|
||||
}
|
||||
|
||||
|
||||
# Create symlinks to executables in build folder if necessary
|
||||
test_link $script_dir/../build/gdpm $script_dir/../bin/$exe
|
||||
test_link $script_dir/../build/gdpm.static $script_dir/../bin/$static
|
||||
test_link $script_dir/../build/gdpm.tests $script_dir/../bin/$tests
|
||||
# Stop if no args
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Handle arguemnts passed in
|
||||
i=$(($#-1))
|
||||
while [ $i -ge 0 ];
|
||||
do
|
||||
case "$1" in
|
||||
-a|--all) build_binaries shift;;
|
||||
-c|--clean) clean shift;;
|
||||
-d|--docs) generate_docs shift;;
|
||||
-s|--strip) strip_all shift;;
|
||||
-l|--link) link_all shift;;
|
||||
--*) echo "Bad option: $1"
|
||||
esac
|
||||
i=$((i-1))
|
||||
done
|
||||
exit 0
|
||||
|
||||
|
||||
# Strip debug symbols
|
||||
test_strip ${script_dir}/../build/gdpm
|
||||
test_strip ${script_dir}/../build/gdpm.static
|
||||
test_strip ${script_dir}/../build/gdpm.tests
|
||||
|
||||
|
||||
# Generate documentation using `doxygen`
|
||||
cd ${script_dir}/..
|
||||
doxygen
|
||||
|
|
|
|||
15
examples/http/README.md
Normal file
15
examples/http/README.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# GDPM HTTP Example
|
||||
|
||||
This is an example showing how to use the GDPM HTTP library to download files. The library uses RapidJSON to get results.
|
||||
|
||||
|
||||
Here is a quick snippet to get started:
|
||||
```c++
|
||||
// Get a full list of assets
|
||||
rest_api::context context = rest_api::make_context();
|
||||
rapidjson::Document doc = http::get_asset_list(
|
||||
"https://godotengine.org/asset-library/api",
|
||||
context
|
||||
)
|
||||
// ... parse the rapidjson::Document
|
||||
```
|
||||
9
examples/http/main.cpp
Normal file
9
examples/http/main.cpp
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/*! Example using the `libgdpm-http` library
|
||||
*/
|
||||
|
||||
#include "http.hpp"
|
||||
|
||||
|
||||
int main(int argc, char **argv){
|
||||
return 0;
|
||||
}
|
||||
26
examples/rest_api/README.md
Normal file
26
examples/rest_api/README.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# GDPM Rest API Example
|
||||
|
||||
This is an example showing how to use the REST API designed to query the Godot Asset library in C++. It is built using the `libcurl` library.
|
||||
|
||||
Here is a snippet making a HTTP get and post request.
|
||||
|
||||
```c++
|
||||
using string = std::string;
|
||||
using headers_t = std::unordered_map<string, string>;
|
||||
|
||||
std::string url = "www.example.com";
|
||||
http::response r_get = http::request_get(url)
|
||||
if(r_get.response_code == http::response_code::OK){
|
||||
// ...do something...
|
||||
}
|
||||
|
||||
http::request_params params;
|
||||
params.headers = {
|
||||
{"user-agent", "firefox"},
|
||||
{"content-type", "application/json"}
|
||||
}
|
||||
http::response r_post = http::request_post(url, params);
|
||||
if(r_post.response_code == http::response_code::OK){
|
||||
// ...do something...
|
||||
}
|
||||
```
|
||||
8
examples/rest_api/main.cpp
Normal file
8
examples/rest_api/main.cpp
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/*! Example using the `libgdpm-restapi` library */
|
||||
|
||||
#include "rest_api.hpp"
|
||||
|
||||
|
||||
int main(int argc, char **argv){
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
namespace gdpm::cache {
|
||||
struct params {
|
||||
std::string cache_path = GDPM_PACKAGE_CACHE_PATH;
|
||||
std::string table_name = GDPM_PACKAGE_CACHE_TABLENAME;
|
||||
string cache_path = GDPM_PACKAGE_CACHE_PATH;
|
||||
string table_name = GDPM_PACKAGE_CACHE_TABLENAME;
|
||||
};
|
||||
|
||||
error create_package_database(bool overwrite = false, const params& = params());
|
||||
|
|
@ -22,11 +22,11 @@ namespace gdpm::cache {
|
|||
result_t<package::info_list> get_package_info_by_title(const package::title_list& package_titles, const params& params = cache::params());
|
||||
result_t<package::info_list> get_installed_packages(const params& = params());
|
||||
error update_package_info(const package::info_list& packages, const params& = params());
|
||||
error update_sync_info(const std::vector<std::string>& download_urls, const params& = params());
|
||||
error update_sync_info(const args_t& download_urls, const params& = params());
|
||||
error delete_packages(const package::title_list& package_titles, const params& = params());
|
||||
error delete_packages(const package::id_list& package_ids, const params& = params());
|
||||
error drop_package_database(const params& = params());
|
||||
|
||||
result_t<std::string> to_values(const package::info& package);
|
||||
result_t<std::string> to_values(const package::info_list& packages);
|
||||
result_t<string> to_values(const package::info& package);
|
||||
result_t<string> to_values(const package::info_list& packages);
|
||||
}
|
||||
6
include/concepts.hpp
Normal file
6
include/concepts.hpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace gdpm::concepts{
|
||||
template <typename...Args> concept RequireMinArgs = requires (std::size_t min){ sizeof...(Args) > min; };
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ namespace gdpm::config{
|
|||
string to_json(const context& params);
|
||||
error load(std::filesystem::path path, context& config, int verbose = 0);
|
||||
error save(std::filesystem::path path, const context& config, int verbose = 0);
|
||||
context make_context(const std::string& username = GDPM_CONFIG_USERNAME, const string& password = GDPM_CONFIG_PASSWORD, const string& path = GDPM_CONFIG_PATH, const string& token = GDPM_CONFIG_TOKEN, const string& godot_version = GDPM_CONFIG_GODOT_VERSION, const string& packages_dir = GDPM_CONFIG_LOCAL_PACKAGES_DIR, const string& tmp_dir = GDPM_CONFIG_LOCAL_TMP_DIR, const string_map& 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);
|
||||
context make_context(const string& username = GDPM_CONFIG_USERNAME, const string& password = GDPM_CONFIG_PASSWORD, const string& path = GDPM_CONFIG_PATH, const string& token = GDPM_CONFIG_TOKEN, const string& godot_version = GDPM_CONFIG_GODOT_VERSION, const string& packages_dir = GDPM_CONFIG_LOCAL_PACKAGES_DIR, const string& tmp_dir = GDPM_CONFIG_LOCAL_TMP_DIR, const string_map& 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);
|
||||
error validate(const rapidjson::Document& doc);
|
||||
|
||||
extern context config;
|
||||
|
|
|
|||
|
|
@ -78,9 +78,7 @@ namespace gdpm{
|
|||
string get_message() const { return m_message; }
|
||||
bool has_occurred() const { return m_code != 0; }
|
||||
|
||||
bool operator()(){
|
||||
return has_occurred();
|
||||
}
|
||||
bool operator()(){ return has_occurred(); }
|
||||
|
||||
private:
|
||||
int m_code;
|
||||
|
|
@ -89,14 +87,20 @@ namespace gdpm{
|
|||
|
||||
// Add logging function that can handle error objects
|
||||
namespace log {
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void error(const gdpm::error& e){
|
||||
#if GDPM_LOG_LEVEL > 1
|
||||
#if GDPM_LOG_LEVEL > ERROR
|
||||
vlog(
|
||||
fmt::format(GDPM_COLOR_LOG_ERROR "[ERROR {}" GDPM_COLOR_LOG_RESET, e.get_message()),
|
||||
fmt::format(GDPM_COLOR_LOG_ERROR "[ERROR {}] {}\n" GDPM_COLOR_LOG_RESET, utils::timestamp(), e.get_message()),
|
||||
fmt::make_format_args("" /*e.get_message()*/)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void error(const S& prefix, const gdpm::error& e){
|
||||
vlog(
|
||||
fmt::format(GDPM_COLOR_LOG_ERROR + prefix + GDPM_COLOR_LOG_RESET, e.get_message())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,73 @@
|
|||
|
||||
namespace gdpm::http{
|
||||
using headers_t = std::unordered_map<string, string>;
|
||||
|
||||
// REF: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
|
||||
enum response_code{
|
||||
OK = 200,
|
||||
NOT_FOUND = 400
|
||||
CONTINUE = 100,
|
||||
SWITCHING_PROTOCOLS = 101,
|
||||
PROCESSING = 102,
|
||||
EARLY_HINTS = 103,
|
||||
OK = 200,
|
||||
CREATED = 201,
|
||||
ACCEPTED = 202,
|
||||
NON_AUTHORITATIVE_INFORMATION = 203,
|
||||
NO_CONTENT = 204,
|
||||
RESET_CONTENT = 205,
|
||||
PARTIAL_CONTENT = 206,
|
||||
MULTI_STATUS = 207,
|
||||
ALREADY_REPORTED = 208,
|
||||
IM_USED = 226,
|
||||
MULTIPLE_CHOICES = 300,
|
||||
MOVED_PERMANENTLY = 301,
|
||||
FOUND = 302,
|
||||
SEE_OTHER = 303,
|
||||
NOT_MODIFIED = 304,
|
||||
USE_PROXY = 305,
|
||||
UNUSED = 306,
|
||||
TEMPORARY_REDIRECT = 307,
|
||||
PERMANENT_REDIRECT = 308,
|
||||
BAD_REQUEST = 400,
|
||||
UNAUTHORIZED = 401,
|
||||
PAYMENT_REQUIRED = 402,
|
||||
FORBIDDEN = 403,
|
||||
NOT_FOUND = 404,
|
||||
METHOD_NOT_ALLOWED = 405,
|
||||
NOT_ACCEPTABLE = 406,
|
||||
PROXY_AUTHENTICATION_REQUIRED = 407,
|
||||
REQUEST_TIMEOUT = 408,
|
||||
CONFLICT = 409,
|
||||
GONE = 410,
|
||||
LENGTH_REQUIRED = 411,
|
||||
PRECONDITION_FAILED = 412,
|
||||
PAYLOAD_TOO_LARGE = 413,
|
||||
URI_TOO_LONG = 414,
|
||||
UNSUPPORTED_MEDIA_TYPE = 415,
|
||||
RANGE_NOT_SATISFIABLE = 416,
|
||||
EXPECTATION_FAILED = 417,
|
||||
IM_A_TEAPOT = 418,
|
||||
MISDIRECTED_REQUEST = 421,
|
||||
UNPROCESSABLE_CONTENT = 422,
|
||||
LOCKED = 423,
|
||||
FAILED_DEPENDENCY = 424,
|
||||
TOO_EARLY = 425,
|
||||
UPGRADE_REQUIRED = 426,
|
||||
PRECONDITION_REQUIRED = 428,
|
||||
TOO_MANY_REQUESTS = 429,
|
||||
REQUEST_HEADER_FILEDS_TOO_LARGE = 431,
|
||||
UNAVAILABLE_FOR_LEGAL_REASONS = 451,
|
||||
INTERNAL_SERVER_ERROR = 500,
|
||||
NOT_IMPLEMENTED = 501,
|
||||
BAD_GATEWAY = 502,
|
||||
SERVICE_UNAVAILABLE = 503,
|
||||
GATEWAY_TIMEOUT = 504,
|
||||
HTTP_VERSION_NOT_SUPPORTED = 505,
|
||||
VARIANT_ALSO_NEGOTIATES = 506,
|
||||
INSUFFICIENT_STORAGE = 507,
|
||||
LOOP_DETECTED = 508,
|
||||
NOT_EXTENDED = 510,
|
||||
NETWORK_AUTHENTICATION_REQUIRED = 511
|
||||
|
||||
};
|
||||
struct response{
|
||||
long code = 0;
|
||||
|
|
@ -18,14 +82,15 @@ namespace gdpm::http{
|
|||
};
|
||||
|
||||
|
||||
struct params {
|
||||
struct request_params {
|
||||
headers_t headers = {};
|
||||
size_t timeout = GDPM_CONFIG_TIMEOUT_MS;
|
||||
int verbose = 0;
|
||||
};
|
||||
|
||||
string url_escape(const string& url);
|
||||
response request_get(const string& url, const http::params& params = http::params());
|
||||
response request_post(const string& url, const char *post_fields="", const http::params& params = http::params());
|
||||
response download_file(const string& url, const string& storage_path, const http::params& params = http::params());
|
||||
response request_get(const string& url, const http::request_params& params = http::request_params());
|
||||
response request_post(const string& url, const http::request_params& params = http::request_params());
|
||||
response download_file(const string& url, const string& storage_path, const http::request_params& params = http::request_params());
|
||||
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "utils.hpp"
|
||||
#include "colors.hpp"
|
||||
#include "types.hpp"
|
||||
#include <format>
|
||||
// #include <fmt/core.h>
|
||||
|
||||
#if __cplusplus > 201703L
|
||||
|
|
@ -18,22 +20,21 @@ TODO: Write log information to file
|
|||
*/
|
||||
namespace gdpm::log
|
||||
{
|
||||
template <typename...Args> concept RequireMinArgs = requires (std::size_t min){ sizeof...(Args) > min; };
|
||||
|
||||
enum level{
|
||||
NONE,
|
||||
NONE = 0,
|
||||
INFO,
|
||||
WARNING,
|
||||
DEBUG,
|
||||
ERROR
|
||||
};
|
||||
|
||||
struct config {
|
||||
static int level;
|
||||
static std::string prefix;
|
||||
static std::string path;
|
||||
static bool print_to_stdout;
|
||||
static bool print_to_stderr;
|
||||
struct context {
|
||||
int level;
|
||||
string prefix;
|
||||
string path;
|
||||
bool print_to_stdout;
|
||||
bool print_to_stderr;
|
||||
};
|
||||
|
||||
static void vlog(fmt::string_view format, fmt::format_args args){
|
||||
|
|
@ -46,7 +47,7 @@ namespace gdpm::log
|
|||
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void info(const S& format, Args&&...args){
|
||||
#if GDPM_LOG_LEVEL > 0
|
||||
#if GDPM_LOG_LEVEL > NONE
|
||||
vlog(
|
||||
fmt::format(GDPM_COLOR_LOG_INFO "[INFO {}] {}\n" GDPM_COLOR_LOG_RESET, utils::timestamp(), format),
|
||||
// fmt::make_format_args<Args...>(args...)
|
||||
|
|
@ -55,18 +56,40 @@ namespace gdpm::log
|
|||
#endif
|
||||
}
|
||||
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void info(const S& prefix, const S& format, Args&&...args){
|
||||
#if GDPM_LOG_LEVEL > INFO
|
||||
vlog(
|
||||
fmt::format(GDPM_COLOR_LOG_INFO + prefix + GDPM_COLOR_LOG_RESET, format),
|
||||
fmt::make_format_args(args...)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void info(const context& context, const S& format, Args&&...args){
|
||||
#if GDPM_LOG_LEVEL > INFO
|
||||
vlog(
|
||||
fmt::format(GDPM_COLOR_LOG_INFO + context.prefix + GDPM_COLOR_LOG_RESET, format),
|
||||
fmt::make_format_args(args...)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void info_n(const S& format, Args&&...args){
|
||||
#if GDPM_LOG_LEVEL > INFO
|
||||
vlog(
|
||||
fmt::format(GDPM_COLOR_LOG_INFO "[INFO {}] {}" GDPM_COLOR_LOG_RESET, utils::timestamp(), format),
|
||||
// fmt::make_format_args<Args...>(args...)
|
||||
fmt::make_format_args(args...)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void error(const S& format, Args&&...args){
|
||||
#if GDPM_LOG_LEVEL > 1
|
||||
#if GDPM_LOG_LEVEL > ERROR
|
||||
vlog(
|
||||
fmt::format(GDPM_COLOR_LOG_ERROR "[ERROR {}] {}\n" GDPM_COLOR_LOG_RESET, utils::timestamp(), format),
|
||||
// fmt::make_format_args<Args...>(args...)
|
||||
|
|
@ -75,9 +98,29 @@ namespace gdpm::log
|
|||
#endif
|
||||
}
|
||||
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void error(const S& prefix, const S& format, Args&&...args){
|
||||
#if GDPM_LOG_LEVEL > ERROR
|
||||
vlog(
|
||||
fmt::format(GDPM_COLOR_LOG_ERROR + prefix + GDPM_COLOR_LOG_RESET, format),
|
||||
fmt::make_format_args(args...)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void error(const context& context, const S& format, Args&&...args){
|
||||
#if GDPM_LOG_LEVEL > ERROR
|
||||
vlog(
|
||||
fmt::format(GDPM_COLOR_LOG_ERROR + context.prefix + GDPM_COLOR_LOG_RESET, format),
|
||||
fmt::make_format_args(args...)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void debug(const S& format, Args&&...args){
|
||||
#if GDPM_LOG_LEVEL > 1
|
||||
#if GDPM_LOG_LEVEL > DEBUG
|
||||
vlog(
|
||||
fmt::format(GDPM_COLOR_LOG_DEBUG "[DEBUG {}] {}\n" GDPM_COLOR_LOG_RESET, utils::timestamp(), format),
|
||||
// fmt::make_format_args<Args...>(args...)
|
||||
|
|
@ -86,6 +129,26 @@ namespace gdpm::log
|
|||
#endif
|
||||
}
|
||||
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void debug(const S& prefix, const S& format, Args&&...args){
|
||||
#if GDPM_LOG_LEVEL > DEBUG
|
||||
vlog(
|
||||
fmt::format(GDPM_COLOR_LOG_DEBUG + prefix + GDPM_COLOR_LOG_RESET, format),
|
||||
fmt::make_format_args(args...)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void debug(const context& context, const S& format, Args&&...args){
|
||||
#if GDPM_LOG_LEVEL > DEBUG
|
||||
vlog(
|
||||
fmt::format(GDPM_COLOR_LOG_DEBUG + context.prefix + GDPM_COLOR_LOG_RESET, format),
|
||||
fmt::make_format_args(args...)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename S, typename...Args>
|
||||
static constexpr void print(const S& format, Args&&...args){
|
||||
vlog(
|
||||
|
|
@ -95,7 +158,7 @@ namespace gdpm::log
|
|||
);
|
||||
}
|
||||
|
||||
template <typename S = std::string, typename...Args>
|
||||
template <typename S = string, typename...Args>
|
||||
static constexpr void println(const S& format, Args&&...args){
|
||||
vlog(
|
||||
fmt::format("{}\n", format),
|
||||
|
|
@ -105,7 +168,7 @@ namespace gdpm::log
|
|||
}
|
||||
|
||||
template <typename>
|
||||
static constexpr void println(const std::string& format = ""){
|
||||
static constexpr void println(const string& format = ""){
|
||||
println(format);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,18 +36,18 @@ namespace gdpm::package {
|
|||
std::vector<info> dependencies;
|
||||
};
|
||||
|
||||
enum install_method_e : int{
|
||||
GLOBAL_LINK_LOCAL = 0,
|
||||
GLOBAL_CLONE_LOCAL = 1,
|
||||
GLOBAL_ONLY = 2,
|
||||
LOCAL_ONLY = 3
|
||||
};
|
||||
struct params {
|
||||
enum install_method_e{
|
||||
GLOBAL_LINK_LOCAL,
|
||||
GLOBAL_CLONE_LOCAL,
|
||||
GLOBAL_ONLY,
|
||||
LOCAL_ONLY
|
||||
};
|
||||
bool parallel_jobs = 1;
|
||||
bool use_cache = true;
|
||||
bool use_remote = true;
|
||||
bool skip_prompt = false;
|
||||
std::string remote_source = "";
|
||||
int parallel_jobs = 1;
|
||||
bool enable_cache = true;
|
||||
bool enable_sync = true;
|
||||
bool skip_prompt = false;
|
||||
string remote_source = "";
|
||||
install_method_e install_method = GLOBAL_LINK_LOCAL;
|
||||
};
|
||||
|
||||
|
|
@ -87,7 +87,13 @@ namespace gdpm::package {
|
|||
|
||||
*/
|
||||
GDPM_DLL_EXPORT error install(const config::context& config, const title_list& package_titles, const params& params = package::params());
|
||||
|
||||
/*!
|
||||
@brief Adds package to project locally only.
|
||||
@param config
|
||||
@param package_titles
|
||||
@param params
|
||||
*/
|
||||
GDPM_DLL_EXPORT error add(const config::context& config, const title_list& package_titles, const params& params = package::params());
|
||||
/*!
|
||||
@brief Remove's package and contents from local database.
|
||||
*/
|
||||
|
|
@ -106,6 +112,7 @@ namespace gdpm::package {
|
|||
GDPM_DLL_EXPORT result_t<info_list> get_package_info(const opts_t& opts);
|
||||
GDPM_DLL_EXPORT result_t<title_list> get_package_titles(const info_list& packages);
|
||||
GDPM_DLL_EXPORT void clean_temporary(const config::context& config, const title_list& package_titles);
|
||||
GDPM_DLL_EXPORT params make_params(const var_args& args, const var_opts& opts);
|
||||
|
||||
/* Dependency Management API */
|
||||
GDPM_DLL_EXPORT result_t<info_list> synchronize_database(const config::context& config, const title_list& package_titles);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
#include <curl/curl.h>
|
||||
|
||||
namespace gdpm::package_manager {
|
||||
extern remote::repository_map repo_sources;
|
||||
extern remote::repository_map remote_sources;
|
||||
extern CURL *curl;
|
||||
extern CURLcode res;
|
||||
extern config::context config;
|
||||
|
|
@ -27,12 +27,13 @@ namespace gdpm::package_manager {
|
|||
};
|
||||
|
||||
struct exec_args{
|
||||
args_t args;
|
||||
opts_t opts;
|
||||
var_args args;
|
||||
var_opts opts;
|
||||
};
|
||||
|
||||
enum class action_e{
|
||||
install,
|
||||
add,
|
||||
remove,
|
||||
update,
|
||||
search,
|
||||
|
|
@ -47,12 +48,12 @@ namespace gdpm::package_manager {
|
|||
none
|
||||
};
|
||||
|
||||
GDPM_DLL_EXPORT result_t<exec_args> initialize(int argc, char **argv);
|
||||
GDPM_DLL_EXPORT int execute(const args_t& args, const opts_t& opts);
|
||||
GDPM_DLL_EXPORT result_t<exec_args> initialize(int argc, char **argv);
|
||||
GDPM_DLL_EXPORT int execute(const exec_args& in);
|
||||
GDPM_DLL_EXPORT void finalize();
|
||||
|
||||
/* Auxiliary Functions */
|
||||
GDPM_DLL_EXPORT cxxargs _parse_arguments(int argc, char **argv);
|
||||
GDPM_DLL_EXPORT result_t<exec_args> _handle_arguments(const cxxargs& args);
|
||||
GDPM_DLL_EXPORT void run_command(action_e command, const package::title_list& package_titles, const opts_t& opts);
|
||||
GDPM_DLL_EXPORT void run_command(action_e command, const var_args& args, const var_opts& opts);
|
||||
}
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
|
||||
|
||||
#pragma once
|
||||
#include "types.hpp"
|
||||
#include <string>
|
||||
|
||||
namespace gdpm::plugin{
|
||||
struct info{
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string version;
|
||||
string name;
|
||||
string description;
|
||||
string version;
|
||||
};
|
||||
extern int init(int argc, char **argv);
|
||||
extern int set_name(const char *name);
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ namespace gdpm::rest_api{
|
|||
constexpr const char *POST_AssetEditId = "/asset/edit/{id}";
|
||||
}
|
||||
|
||||
bool register_account(const std::string& username, const std::string& password, const std::string& email);
|
||||
bool login(const std::string& username, const std::string& password);
|
||||
bool register_account(const string& username, const string& password, const string& email);
|
||||
bool login(const string& username, const string& password);
|
||||
bool logout();
|
||||
// bool change_password()
|
||||
|
||||
|
|
@ -38,9 +38,9 @@ namespace gdpm::rest_api{
|
|||
type_e type;
|
||||
int category;
|
||||
support_e support;
|
||||
std::string filter;
|
||||
std::string user;
|
||||
std::string godot_version;
|
||||
string filter;
|
||||
string user;
|
||||
string godot_version;
|
||||
int max_results;
|
||||
int page;
|
||||
sort_e sort;
|
||||
|
|
@ -51,21 +51,21 @@ namespace gdpm::rest_api{
|
|||
context make_from_config(const config::context& config);
|
||||
context make_context(type_e type = GDPM_DEFAULT_ASSET_TYPE, int category = GDPM_DEFAULT_ASSET_CATEGORY, support_e support = GDPM_DEFAULT_ASSET_SUPPORT, const std::string& filter = GDPM_DEFAULT_ASSET_FILTER, const std::string& user = GDPM_DEFAULT_ASSET_USER, const std::string& godot_version = GDPM_DEFAULT_ASSET_GODOT_VERSION, int max_results = GDPM_DEFAULT_ASSET_MAX_RESULTS, int page = GDPM_DEFAULT_ASSET_PAGE, sort_e sort = GDPM_DEFAULT_ASSET_SORT, bool reverse = GDPM_DEFAULT_ASSET_REVERSE, int verbose = GDPM_DEFAULT_ASSET_VERBOSE);
|
||||
|
||||
std::string to_string(type_e type);
|
||||
std::string to_string(support_e support);
|
||||
std::string to_string(sort_e sort);
|
||||
string to_string(type_e type);
|
||||
string to_string(support_e support);
|
||||
string to_string(sort_e sort);
|
||||
void _print_params(const context& params);
|
||||
rapidjson::Document _parse_json(const std::string& r, int verbose = 0);
|
||||
std::string _prepare_request(const std::string& url, const context& context);
|
||||
rapidjson::Document _parse_json(const string& r, int verbose = 0);
|
||||
string _prepare_request(const string& url, const context& context);
|
||||
|
||||
bool register_account(const std::string& username, const std::string& password, const std::string& email);
|
||||
bool login(const std::string& username, const std::string& password);
|
||||
bool register_account(const string& username, const string& password, const string& email);
|
||||
bool login(const string& username, const string& password);
|
||||
bool logout();
|
||||
|
||||
rapidjson::Document configure(const std::string& url = constants::HostUrl, type_e type = any, int verbose = 0);
|
||||
rapidjson::Document get_assets_list(const std::string& url = constants::HostUrl, type_e type = GDPM_DEFAULT_ASSET_TYPE, int category = GDPM_DEFAULT_ASSET_CATEGORY, support_e support = GDPM_DEFAULT_ASSET_SUPPORT, const std::string& filter = GDPM_DEFAULT_ASSET_FILTER, const std::string& user = GDPM_DEFAULT_ASSET_USER, const std::string& godot_version = GDPM_DEFAULT_ASSET_GODOT_VERSION, int max_results = GDPM_DEFAULT_ASSET_MAX_RESULTS, int page = GDPM_DEFAULT_ASSET_PAGE, sort_e sort = GDPM_DEFAULT_ASSET_SORT, bool reverse = GDPM_DEFAULT_ASSET_REVERSE, int verbose = GDPM_DEFAULT_ASSET_VERBOSE);
|
||||
rapidjson::Document get_assets_list(const std::string& url, const context& params = {});
|
||||
rapidjson::Document get_asset(const std::string& url, int asset_id, const context& params = {});
|
||||
rapidjson::Document configure(const string& url = constants::HostUrl, type_e type = any, int verbose = 0);
|
||||
rapidjson::Document get_assets_list(const string& url = constants::HostUrl, type_e type = GDPM_DEFAULT_ASSET_TYPE, int category = GDPM_DEFAULT_ASSET_CATEGORY, support_e support = GDPM_DEFAULT_ASSET_SUPPORT, const string& filter = GDPM_DEFAULT_ASSET_FILTER, const std::string& user = GDPM_DEFAULT_ASSET_USER, const std::string& godot_version = GDPM_DEFAULT_ASSET_GODOT_VERSION, int max_results = GDPM_DEFAULT_ASSET_MAX_RESULTS, int page = GDPM_DEFAULT_ASSET_PAGE, sort_e sort = GDPM_DEFAULT_ASSET_SORT, bool reverse = GDPM_DEFAULT_ASSET_REVERSE, int verbose = GDPM_DEFAULT_ASSET_VERBOSE);
|
||||
rapidjson::Document get_assets_list(const string& url, const context& params = {});
|
||||
rapidjson::Document get_asset(const string& url, int asset_id, const context& params = {});
|
||||
bool delete_asset(int asset_id); // ...for moderators
|
||||
bool undelete_asset(int asset_id); // ...for moderators
|
||||
bool set_support_level(int asset_id); // ...for moderators
|
||||
|
|
@ -81,11 +81,11 @@ namespace gdpm::rest_api{
|
|||
void get_asset_edit(int asset_id);
|
||||
|
||||
/* POST /asset/edit/{id}/review */
|
||||
std::string review_asset_edit(int asset_id);
|
||||
string review_asset_edit(int asset_id);
|
||||
|
||||
/* POST /asset/edit/{id}/accept */
|
||||
std::string accept_asset_edit(int asset_id); // ...for moderators
|
||||
string accept_asset_edit(int asset_id); // ...for moderators
|
||||
|
||||
/* POST /asset/edit/{id}/reject */
|
||||
std::string reject_asset_edit(int asset_id);
|
||||
string reject_asset_edit(int asset_id);
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
#include <type_traits>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <future>
|
||||
|
||||
namespace gdpm{
|
||||
class error;
|
||||
|
|
@ -29,6 +30,16 @@ namespace gdpm{
|
|||
non_movable(non_movable&&) = delete;
|
||||
};
|
||||
|
||||
enum variant_type_index : int{
|
||||
INT = 0,
|
||||
FLOAT = 1,
|
||||
BOOL = 2,
|
||||
STRING = 3,
|
||||
STRING_LIST = 4,
|
||||
STRING_MAP = 5,
|
||||
SIZE_T = 6,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept error_t = requires{ std::is_same<error, T>::value; };
|
||||
|
||||
|
|
@ -36,12 +47,58 @@ namespace gdpm{
|
|||
using string_list = std::vector<string>;
|
||||
using string_map = std::unordered_map<string, string>;
|
||||
using string_pair = std::pair<string, string>;
|
||||
using var = std::variant<int, bool, float, std::string>;
|
||||
using var = std::variant<int, float, bool, string, string_list, string_map, size_t>;
|
||||
template <typename T = var>
|
||||
using _args_t = std::vector<T>;
|
||||
using args_t = _args_t<string>;
|
||||
template <typename Key = std::string, class Value = _args_t<var>>
|
||||
using var_args = _args_t<var>;
|
||||
using var_list = std::vector<var>;
|
||||
using var_map = std::unordered_map<string, var>;
|
||||
template <typename Key = string, class Value = _args_t<var>>
|
||||
using _opts_t = std::unordered_map<Key, Value>;
|
||||
using opts_t = _opts_t<string, string_list>;
|
||||
using opt = std::pair<string, string_list>;
|
||||
using var_opt = std::pair<string, var>;
|
||||
using var_opts = _opts_t<string, var>;
|
||||
template <typename T = error>
|
||||
using _task_list = std::vector<std::future<T>>;
|
||||
using task_list = _task_list<error>;
|
||||
|
||||
inline string_list unwrap(const var_args& args){
|
||||
string_list sl;
|
||||
std::for_each(args.begin(), args.end(), [&sl](const var& v){
|
||||
if(v.index() == STRING){
|
||||
sl.emplace_back(std::get<string>(v));
|
||||
}
|
||||
});
|
||||
return sl;
|
||||
}
|
||||
|
||||
inline opts_t unwrap(const var_opts& opts){
|
||||
opts_t o;
|
||||
std::for_each(opts.begin(), opts.end(), [&o](const var_opt& opt){
|
||||
if(opt.second.index() == STRING){
|
||||
string_list sl;
|
||||
string arg(std::get<string>(opt.second)); // must make copy for const&
|
||||
sl.emplace_back(arg);
|
||||
o.insert(std::pair(opt.first, sl));
|
||||
}
|
||||
});
|
||||
return o;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr void get(const var& v, T& target){
|
||||
switch(v.index()){
|
||||
case INT: /*return*/ target = std::get<int>(v);
|
||||
case FLOAT: /*return*/ target = std::get<float>(v);
|
||||
case BOOL: /*return*/ target = std::get<bool>(v);
|
||||
case STRING: /*return*/ target = std::get<string>(v);
|
||||
case STRING_LIST: /*return*/ target = std::get<string_list>(v);
|
||||
case STRING_MAP: /*return*/ target = std::get<string_map>(v);
|
||||
case SIZE_T: /*return*/ target = std::get<size_t>(v);
|
||||
default: /*return*/ target = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,12 +130,12 @@ namespace gdpm::config{
|
|||
|
||||
/* Must check if keys exists first, then populate `_config_params`. */
|
||||
if(doc.HasMember("remote_sources")){
|
||||
if(doc["remote_sources"].IsArray()){
|
||||
if(doc["remote_sources"].IsObject()){
|
||||
const Value& srcs = doc["remote_sources"];
|
||||
for(auto& src : srcs.GetObject()){
|
||||
// config.remote_sources.push_back(src.GetString());
|
||||
config.remote_sources.insert(
|
||||
std::pair(src.name.GetString(), src.value.GetString())
|
||||
string_pair(src.name.GetString(), src.value.GetString())
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
21
src/http.cpp
21
src/http.cpp
|
|
@ -20,7 +20,7 @@ namespace gdpm::http{
|
|||
|
||||
response request_get(
|
||||
const string& url,
|
||||
const http::params& params
|
||||
const http::request_params& params
|
||||
){
|
||||
CURL *curl = nullptr;
|
||||
CURLcode res;
|
||||
|
|
@ -58,8 +58,7 @@ namespace gdpm::http{
|
|||
|
||||
response request_post(
|
||||
const string& url,
|
||||
const char *post_fields,
|
||||
const http::params& params
|
||||
const http::request_params& params
|
||||
){
|
||||
CURL *curl = nullptr;
|
||||
CURLcode res;
|
||||
|
|
@ -70,13 +69,25 @@ namespace gdpm::http{
|
|||
using namespace std::chrono_literals;
|
||||
utils::delay();
|
||||
#endif
|
||||
string h;
|
||||
std::for_each(
|
||||
params.headers.begin(),
|
||||
params.headers.end(),
|
||||
[&h](const string_pair& kv){
|
||||
h += kv.first + "=" + kv.second + "&";
|
||||
}
|
||||
);
|
||||
h.pop_back();
|
||||
h = url_escape(h);
|
||||
|
||||
// const char *post_fields = "";
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
curl = curl_easy_init();
|
||||
if(curl){
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
// curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=daniel&project=curl");
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_fields);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, h.size());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, h.c_str());
|
||||
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.c_str());
|
||||
|
|
@ -98,7 +109,7 @@ namespace gdpm::http{
|
|||
response download_file(
|
||||
const string& url,
|
||||
const string& storage_path,
|
||||
const http::params& params
|
||||
const http::request_params& params
|
||||
){
|
||||
CURL *curl = nullptr;
|
||||
CURLcode res;
|
||||
|
|
|
|||
10
src/main.cpp
10
src/main.cpp
|
|
@ -9,9 +9,11 @@
|
|||
|
||||
int main(int argc, char **argv){
|
||||
using namespace gdpm;
|
||||
result_t <package_manager::exec_args> r_input = package_manager::initialize(argc, argv);
|
||||
package_manager::exec_args input = r_input.unwrap_unsafe();
|
||||
package_manager::execute(input.args, input.opts);
|
||||
package_manager::finalize();
|
||||
using namespace gdpm::package_manager;
|
||||
|
||||
result_t <exec_args> r_input = initialize(argc, argv);
|
||||
exec_args input = r_input.unwrap_unsafe();
|
||||
execute(input);
|
||||
finalize();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
|
||||
#include "package.hpp"
|
||||
#include "error.hpp"
|
||||
#include "log.hpp"
|
||||
#include "rest_api.hpp"
|
||||
#include "config.hpp"
|
||||
#include "cache.hpp"
|
||||
#include "http.hpp"
|
||||
#include "remote.hpp"
|
||||
#include "types.hpp"
|
||||
#include <future>
|
||||
#include <rapidjson/ostreamwrapper.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
|
|
@ -21,9 +23,16 @@ namespace gdpm::package{
|
|||
|
||||
/* TODO: Need a way to use remote sources from config until none left */
|
||||
|
||||
/* Check if the package data is already stored in cache. If it is, there
|
||||
is no need to do a lookup to synchronize the local database since we
|
||||
have all the information we need to fetch the asset data. */
|
||||
/*
|
||||
Implementation steps:
|
||||
|
||||
1. Synchronize the cache information by making a request using remote API.
|
||||
(can skip with `--no-sync` options)
|
||||
2. Check if the package is installed. If it is, make sure it is latest version.
|
||||
If not, download and update to the latest version.
|
||||
3. Extract package contents and copy/move to the correct install location.
|
||||
*/
|
||||
|
||||
result_t result = cache::get_package_info_by_title(package_titles);
|
||||
package::info_list p_found = {};
|
||||
package::info_list p_cache = result.unwrap_unsafe();
|
||||
|
|
@ -37,6 +46,8 @@ namespace gdpm::package{
|
|||
}
|
||||
}
|
||||
|
||||
/* Match queried package titles with those found in cache. */
|
||||
log::debug("Searching for packages in cache...");
|
||||
for(const auto& p_title : package_titles){
|
||||
auto found = std::find_if(
|
||||
p_cache.begin(),
|
||||
|
|
@ -50,16 +61,26 @@ namespace gdpm::package{
|
|||
}
|
||||
}
|
||||
|
||||
/* If size of package_titles == p_found, then all packages can be installed
|
||||
from cache and there's no need to query remote API. However, this will
|
||||
only installed the latest *local* version and will not sync with remote. */
|
||||
if(p_found.size() == package_titles.size()){
|
||||
log::info("Found all packages stored in local cache.");
|
||||
}
|
||||
|
||||
/* Found nothing to install so there's nothing to do at this point. */
|
||||
if(p_found.empty()){
|
||||
constexpr const char *message = "No packages found to install.";
|
||||
log::error(message);
|
||||
return error(constants::error::NOT_FOUND, message);
|
||||
error error(
|
||||
constants::error::NOT_FOUND,
|
||||
"No packages found to install."
|
||||
);
|
||||
log::error(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
log::println("Packages to install: ");
|
||||
for(const auto& p : p_found){
|
||||
std::string output((p.is_installed) ? p.title + " (reinstall)" : p.title);
|
||||
string output((p.is_installed) ? p.title + " (reinstall)" : p.title);
|
||||
log::print(" {} ", (p.is_installed) ? p.title + " (reinstall)" : p.title);
|
||||
}
|
||||
log::println("");
|
||||
|
|
@ -70,9 +91,8 @@ namespace gdpm::package{
|
|||
}
|
||||
|
||||
/* Try and obtain all requested packages. */
|
||||
using ss_pair = std::pair<std::string, std::string>;
|
||||
std::vector<ss_pair> dir_pairs;
|
||||
std::vector<std::future<error>> tasks;
|
||||
std::vector<string_pair> dir_pairs;
|
||||
task_list tasks;
|
||||
rest_api::context rest_api_params = rest_api::make_from_config(config);
|
||||
for(auto& p : p_found){ // TODO: Execute each in parallel using coroutines??
|
||||
|
||||
|
|
@ -80,8 +100,8 @@ namespace gdpm::package{
|
|||
in global storage location only. */
|
||||
|
||||
log::info("Fetching asset data for \"{}\"...", p.title);
|
||||
std::string url{config.remote_sources.at(params.remote_source) + rest_api::endpoints::GET_AssetId};
|
||||
std::string package_dir, tmp_dir, tmp_zip;
|
||||
string url{config.remote_sources.at(params.remote_source) + rest_api::endpoints::GET_AssetId};
|
||||
string package_dir, tmp_dir, tmp_zip;
|
||||
|
||||
/* Retrieve necessary asset data if it was found already in cache */
|
||||
Document doc;
|
||||
|
|
@ -161,7 +181,7 @@ namespace gdpm::package{
|
|||
}
|
||||
}
|
||||
|
||||
dir_pairs.emplace_back(ss_pair(tmp_zip, package_dir + "/"));
|
||||
dir_pairs.emplace_back(string_pair(tmp_zip, package_dir + "/"));
|
||||
|
||||
p.is_installed = true;
|
||||
p.install_path = package_dir;
|
||||
|
|
@ -182,6 +202,16 @@ namespace gdpm::package{
|
|||
}
|
||||
|
||||
|
||||
error add(
|
||||
const config::context& config,
|
||||
const title_list& package_titles,
|
||||
const params& params
|
||||
){
|
||||
|
||||
return error();
|
||||
}
|
||||
|
||||
|
||||
error remove(
|
||||
const config::context& config,
|
||||
const string_list& package_titles,
|
||||
|
|
@ -346,11 +376,11 @@ namespace gdpm::package{
|
|||
|
||||
error search(
|
||||
const config::context& config,
|
||||
const package::title_list &package_titles,
|
||||
const package::title_list &package_titles,
|
||||
const package::params& params
|
||||
){
|
||||
result_t r_cache = cache::get_package_info_by_title(package_titles);
|
||||
std::vector<package::info> p_cache = r_cache.unwrap_unsafe();
|
||||
info_list p_cache = r_cache.unwrap_unsafe();
|
||||
|
||||
if(!p_cache.empty() && !config.enable_sync){
|
||||
print_list(p_cache);
|
||||
|
|
@ -393,22 +423,24 @@ namespace gdpm::package{
|
|||
using namespace rapidjson;
|
||||
using namespace std::filesystem;
|
||||
|
||||
if(opts.empty() || opts.contains("packages")){
|
||||
string show((!args.empty()) ? args[0] : "");
|
||||
if(show.empty() || show == "packages"){
|
||||
result_t r_installed = cache::get_installed_packages();
|
||||
info_list p_installed = r_installed.unwrap_unsafe();
|
||||
if(!p_installed.empty()){
|
||||
log::println("Installed packages: ");
|
||||
print_list(p_installed);
|
||||
}
|
||||
else{
|
||||
log::println("empty");
|
||||
}
|
||||
}
|
||||
else if(opts.contains("remote")){
|
||||
else if(show == "remote"){
|
||||
remote::print_repositories(config);
|
||||
}
|
||||
else{
|
||||
error error(
|
||||
constants::error::UNKNOWN_COMMAND,
|
||||
"Unrecognized subcommand. Try either 'packages' or 'remote' instead."
|
||||
|
||||
);
|
||||
log::error(error);
|
||||
}
|
||||
|
|
@ -654,6 +686,28 @@ namespace gdpm::package{
|
|||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
auto set_if_key_exists(
|
||||
const var_opts& o,
|
||||
const string& k,
|
||||
T& p
|
||||
){
|
||||
if(o.count(k)){ p = std::get<T>(o.at(k)); }
|
||||
}
|
||||
|
||||
params make_params(const var_args& args, const var_opts& opts){
|
||||
params p;
|
||||
set_if_key_exists<int>(opts, "jobs", p.parallel_jobs);
|
||||
set_if_key_exists(opts, "cache", p.enable_cache);
|
||||
set_if_key_exists(opts, "sync", p.enable_sync);
|
||||
set_if_key_exists(opts, "skip-prompt", p.skip_prompt);
|
||||
set_if_key_exists(opts, "remote-source", p.remote_source);
|
||||
// set_if_key_exists(opts, "install-method", p.install_method);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
result_t<info_list> synchronize_database(
|
||||
const config::context& config,
|
||||
const title_list& package_titles
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
*/
|
||||
|
||||
namespace gdpm::package_manager{
|
||||
remote::repository_map repo_sources;
|
||||
remote::repository_map remote_sources;
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
config::context config;
|
||||
|
|
@ -76,8 +76,8 @@ namespace gdpm::package_manager{
|
|||
}
|
||||
|
||||
|
||||
int execute(const args_t& args, const opts_t& opts){
|
||||
run_command(action, packages, opts);
|
||||
int execute(const exec_args& in){
|
||||
run_command(action, in.args, in.opts);
|
||||
if(clean_tmp_dir)
|
||||
package::clean_temporary(config, packages);
|
||||
return 0;
|
||||
|
|
@ -102,7 +102,8 @@ namespace gdpm::package_manager{
|
|||
options.allow_unrecognised_options();
|
||||
options.custom_help("[COMMAND] [OPTIONS...]");
|
||||
options.add_options("Command")
|
||||
("command", "Specify the input parameters", cxxopts::value<string_list>())
|
||||
("command", "Specify the input parameters", cxxopts::value<string>())
|
||||
("positional", "", cxxopts::value<string_list>())
|
||||
("install", "Install package or packages.", cxxopts::value<string_list>()->implicit_value(""), "<packages...>")
|
||||
("remove", "Remove a package or packages.", cxxopts::value<string_list>()->implicit_value(""), "<packages...>")
|
||||
("update", "Update a package or packages. This will update all packages if no argument is provided.", cxxopts::value<string_list>()->implicit_value(""), "<packages...>")
|
||||
|
|
@ -111,13 +112,14 @@ namespace gdpm::package_manager{
|
|||
("list", "Show list of installed packages.")
|
||||
("link", "Create a symlink (or shortcut) to target directory. Must be used with the `--path` argument.", cxxopts::value<string_list>(), "<packages...>")
|
||||
("clone", "Clone packages into target directory. Must be used with the `--path` argument.", cxxopts::value<string_list>(), "<packages...>")
|
||||
("cache", "Caching operations", cxxopts::value<string_list>())
|
||||
("clean", "Clean temporary downloaded files.")
|
||||
("fetch", "Fetch asset data from remote sources.")
|
||||
("remote", "Set a source repository.", cxxopts::value<string>()->default_value(constants::AssetRepo), "<url>")
|
||||
("h,help", "Print this message and exit.")
|
||||
("version", "Show the current version and exit.")
|
||||
;
|
||||
options.parse_positional({"command"});
|
||||
options.parse_positional({"command", "positional"});
|
||||
options.positional_help("");
|
||||
options.add_options("Other")
|
||||
("c,config", "Set the config file path.", cxxopts::value<string>())
|
||||
|
|
@ -128,9 +130,8 @@ namespace gdpm::package_manager{
|
|||
("support", "Set the support level for API (all|official|community|testing).")
|
||||
("max-results", "Set the max results to return from search.", cxxopts::value<int>()->default_value("500"), "<int>")
|
||||
("godot-version", "Set the Godot version to include in request.", cxxopts::value<string>())
|
||||
("set-priority", "Set the priority for remote source. Lower values are used first (0...100).", cxxopts::value<int>())
|
||||
("set-packages-directory", "Set the local package storage location.", cxxopts::value<string>())
|
||||
("set-temporary-directory", "Set the local temporary storage location.", cxxopts::value<string>())
|
||||
("package-dir", "Set the local package storage location.", cxxopts::value<string>())
|
||||
("tmp-dir", "Set the local temporary storage location.", cxxopts::value<string>())
|
||||
("timeout", "Set the amount of time to wait for a response.", cxxopts::value<size_t>())
|
||||
("no-sync", "Disable synchronizing with remote.", cxxopts::value<bool>()->implicit_value("true")->default_value("false"))
|
||||
("y,no-prompt", "Bypass yes/no prompt for installing or removing packages.")
|
||||
|
|
@ -142,17 +143,38 @@ namespace gdpm::package_manager{
|
|||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void insert(
|
||||
var_opts& opts,
|
||||
const cxxopts::ParseResult& result,
|
||||
const string& key
|
||||
){
|
||||
opts.insert(var_opt(key, result[key].as<T>()));
|
||||
};
|
||||
|
||||
|
||||
result_t<exec_args> _handle_arguments(const cxxargs& args){
|
||||
const auto& result = args.result;
|
||||
const auto& options = args.options;
|
||||
exec_args in;
|
||||
|
||||
// auto get_opt = [](const string& key){
|
||||
// result[key].as<T>();
|
||||
// }
|
||||
// auto get_opt = [&result]<typename V>(const string& key){
|
||||
// return opt(key, result[key].as<V>());
|
||||
// };
|
||||
|
||||
/* Set option variables first to be used in functions below. */
|
||||
if(result.count("search")){
|
||||
in.args = result["search"].as<var_args>();
|
||||
}
|
||||
if(result.count("help")){
|
||||
log::println("{}", options.help());
|
||||
}
|
||||
if(result.count("config")){
|
||||
config.path = result["config"].as<string>();
|
||||
insert<string>(in.opts, result, "config");
|
||||
config::load(config.path, config);
|
||||
log::info("Config: {}", config.path);
|
||||
}
|
||||
|
|
@ -163,9 +185,8 @@ namespace gdpm::package_manager{
|
|||
string argv = result.arguments_string();
|
||||
log::println("argv: {}", argv);
|
||||
remote::add_repositories(config, {});
|
||||
|
||||
}
|
||||
else if(sub_command == "delete"){
|
||||
else if(sub_command == "remove"){
|
||||
remote::remove_respositories(config, {});
|
||||
log::println("argv: {}");
|
||||
}
|
||||
|
|
@ -174,9 +195,10 @@ namespace gdpm::package_manager{
|
|||
string path = result["file"].as<string>();
|
||||
string contents = utils::readfile(path);
|
||||
packages = utils::parse_lines(contents);
|
||||
insert<string>(in.opts, result, "file");
|
||||
}
|
||||
if(result.count("path")){
|
||||
in.opts.insert({"path", result["path"].as<string_list>()});
|
||||
insert<string_list>(in.opts, result, "path");
|
||||
}
|
||||
if(result.count("sort")){
|
||||
string r = result["sort"].as<string>();
|
||||
|
|
@ -187,14 +209,16 @@ namespace gdpm::package_manager{
|
|||
else if(r == "name") sort = rest_api::sort_e::name;
|
||||
else if(r == "updated") sort = rest_api::sort_e::updated;
|
||||
api_params.sort = sort;
|
||||
in.opts.insert(var_opt("sort", r));
|
||||
}
|
||||
if(result.count("type")){
|
||||
string r = result["type"].as<std::string>();
|
||||
string r = result["type"].as<string>();
|
||||
rest_api::type_e type = rest_api::type_e::any;
|
||||
if(r == "any") type = rest_api::type_e::any;
|
||||
else if(r == "addon") type = rest_api::type_e::addon;
|
||||
else if(r == "project") type = rest_api::type_e::project;
|
||||
api_params.type = type;
|
||||
in.opts.insert(var_opt("type", r));
|
||||
}
|
||||
if(result.count("support")){
|
||||
string r = result["support"].as<string>();
|
||||
|
|
@ -204,42 +228,52 @@ namespace gdpm::package_manager{
|
|||
else if(r == "community") support = rest_api::support_e::community;
|
||||
else if(r == "testing") support = rest_api::support_e::testing;
|
||||
api_params.support = support;
|
||||
in.opts.insert(var_opt("support", r));
|
||||
}
|
||||
if(result.count("max-results")){
|
||||
api_params.max_results = result["max-results"].as<int>();
|
||||
insert<int>(in.opts, result, "max-results");
|
||||
}
|
||||
if(result.count("godot-version")){
|
||||
config.godot_version = result["godot-version"].as<string>();
|
||||
insert<string>(in.opts, result, "godot-version");
|
||||
}
|
||||
if(result.count("timeout")){
|
||||
config.timeout = result["timeout"].as<size_t>();
|
||||
insert<size_t>(in.opts, result, "timeout");
|
||||
}
|
||||
if(result.count("no-sync")){
|
||||
config.enable_sync = false;
|
||||
in.opts.insert(var_opt("sync", "disabled"));
|
||||
}
|
||||
if(result.count("set-priority")){
|
||||
priority = result["set-priority"].as<int>();
|
||||
if(result.count("package-dir")){
|
||||
config.packages_dir = result["package-dir"].as<string>();
|
||||
insert<string>(in.opts, result, "package-dir");
|
||||
}
|
||||
if(result.count("set-packages-directory")){
|
||||
config.packages_dir = result["set-packages-directory"].as<string>();
|
||||
}
|
||||
if(result.count("set-temporary-directory")){
|
||||
config.tmp_dir = result["set-temporary-directory"].as<string>();
|
||||
if(result.count("tmp-dir")){
|
||||
config.tmp_dir = result["tmp-dir"].as<string>();
|
||||
insert<string>(in.opts, result, "tmp-dir");
|
||||
}
|
||||
if(result.count("yes")){
|
||||
skip_prompt = true;
|
||||
in.opts.insert(opt("skip-prompt", true));
|
||||
}
|
||||
if(result.count("link")){
|
||||
packages = result["link"].as<string_list>();
|
||||
insert<string_list>(in.opts, result, "link");
|
||||
}
|
||||
if(result.count("clone")){
|
||||
packages = result["clone"].as<string_list>();
|
||||
insert<string_list>(in.opts, result, "clone");
|
||||
}
|
||||
if(result.count("clean")){
|
||||
in.opts.insert(opt("clean", true));
|
||||
clean_tmp_dir = true;
|
||||
}
|
||||
config.verbose = 0;
|
||||
config.verbose += result["verbose"].as<int>();
|
||||
insert<int>(in.opts, result, "verbose");
|
||||
|
||||
string json = to_json(config);
|
||||
if(config.verbose > 0){
|
||||
log::println("Verbose set to level {}", config.verbose);
|
||||
|
|
@ -251,17 +285,20 @@ namespace gdpm::package_manager{
|
|||
return result_t(in, error());
|
||||
}
|
||||
|
||||
args_t _argv = result["command"].as<args_t>();
|
||||
string sub_command = _argv[0];
|
||||
args_t argv{_argv.begin()+1, _argv.end()};
|
||||
if(packages.empty() && in.opts.size() > 0){
|
||||
for(const auto& arg : argv){
|
||||
packages.emplace_back(arg);
|
||||
string sub_command = result["command"].as<string>();
|
||||
if(result.count("positional")){
|
||||
string_list _argv = result["positional"].as<string_list>();
|
||||
args_t argv{_argv.begin(), _argv.end()};
|
||||
if(!argv.empty()){
|
||||
for(const auto& arg : argv){
|
||||
in.args.emplace_back(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Catch arguments passed with dashes */
|
||||
if(sub_command == "install") action = action_e::install;
|
||||
else if(sub_command == "add") action = action_e::add;
|
||||
else if(sub_command == "remove") action = action_e::remove;
|
||||
else if(sub_command == "update") action = action_e::update;
|
||||
else if(sub_command == "search") action = action_e::search;
|
||||
|
|
@ -272,7 +309,7 @@ namespace gdpm::package_manager{
|
|||
else if(sub_command == "clean") action = action_e::clean;
|
||||
else if(sub_command == "sync") action = action_e::sync;
|
||||
else if(sub_command == "remote") action = action_e::remote;
|
||||
else if(sub_command == "help" || argv[0] == "-h" || argv[0] == "--help" || argv[0].empty()){
|
||||
else if(sub_command == "help"){ action = action_e::help;
|
||||
log::println("{}", options.help());
|
||||
}
|
||||
else{
|
||||
|
|
@ -283,22 +320,24 @@ namespace gdpm::package_manager{
|
|||
|
||||
|
||||
/* Used to run the command AFTER parsing and setting all command line args. */
|
||||
void run_command(action_e c, const args_t& args, const opts_t& opts){
|
||||
package::params params;
|
||||
void run_command(action_e c, const var_args& args, const var_opts& opts){
|
||||
package::params params = package::make_params(args, opts);
|
||||
string_list args_list = unwrap(args);
|
||||
opts_t opts_list = unwrap(opts);
|
||||
params.skip_prompt = skip_prompt;
|
||||
switch(c){
|
||||
case action_e::install: package::install(config, args, params); break;
|
||||
case action_e::remove: package::remove(config, args, params); break;
|
||||
case action_e::update: package::update(config, args, params); break;
|
||||
case action_e::search: package::search(config, args, params); break;
|
||||
case action_e::p_export: package::export_to(args); break;
|
||||
case action_e::list: package::list(config, args, opts); break;
|
||||
/* ...opts are the paths here */
|
||||
case action_e::link: package::link(config, args, opts); break;
|
||||
case action_e::clone: package::clone(config, args, opts); break;
|
||||
case action_e::clean: package::clean_temporary(config, args); break;
|
||||
case action_e::sync: package::synchronize_database(config, args); break;
|
||||
case action_e::remote: remote::_handle_remote(config, args, opts); break;
|
||||
case action_e::install: package::install(config, args_list, params); break;
|
||||
case action_e::remove: package::remove(config, args_list, params); break;
|
||||
case action_e::update: package::update(config, args_list, params); break;
|
||||
case action_e::search: package::search(config, args_list, params); break;
|
||||
case action_e::p_export: package::export_to(args_list); break;
|
||||
case action_e::list: package::list(config, args_list, opts_list); break;
|
||||
/* ...opts are the paths here */
|
||||
case action_e::link: package::link(config, args_list, opts_list); break;
|
||||
case action_e::clone: package::clone(config, args_list, opts_list); break;
|
||||
case action_e::clean: package::clean_temporary(config, args_list); break;
|
||||
case action_e::sync: package::synchronize_database(config, args_list); break;
|
||||
case action_e::remote: remote::_handle_remote(config, args_list, opts_list); break;
|
||||
case action_e::help: /* ...runs in handle_arguments() */ break;
|
||||
case action_e::none: /* ...here to run with no command */ break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ namespace gdpm::rest_api{
|
|||
}
|
||||
|
||||
string to_string(type_e type){
|
||||
std::string _s{"type="};
|
||||
string _s{"type="};
|
||||
switch(type){
|
||||
case any: _s += "any"; break;
|
||||
case addon: _s += "addon"; break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue