mirror of
https://github.com/davidallendj/gdpm.git
synced 2025-12-19 19:17:01 -07:00
Change command-line parsing (again...)
- Added formatted table with `--style` option - Added `warning` log level - Fixed bugs and cleaned up API - Removed some extra debugging output
This commit is contained in:
parent
0238dfd510
commit
b36d55ceee
15 changed files with 685 additions and 255 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -13,3 +13,6 @@
|
||||||
[submodule "modules/csv2"]
|
[submodule "modules/csv2"]
|
||||||
path = modules/csv2
|
path = modules/csv2
|
||||||
url = https://github.com/p-ranav/csv2
|
url = https://github.com/p-ranav/csv2
|
||||||
|
[submodule "modules/argparse"]
|
||||||
|
path = modules/argparse
|
||||||
|
url = https://github.com/p-ranav/argparse
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ find_package(SQLiteCpp CONFIG REQUIRED)
|
||||||
set(CMAKE_CXX_COMPILER "clang++")
|
set(CMAKE_CXX_COMPILER "clang++")
|
||||||
set(CMAKE_BUILD_RPATH "build/cmake")
|
set(CMAKE_BUILD_RPATH "build/cmake")
|
||||||
set(CMAKE_CXX_FLAGS
|
set(CMAKE_CXX_FLAGS
|
||||||
"${CMAKE_CXX_FLAGS} -std=c++20 -Ofast -fPIC -fPIE -fpermissive -Wall -Wno-switch -Wno-unused-variable -Wno-unused-function -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 -Wno-deprecated-declarations -pedantic-errors"
|
||||||
)
|
)
|
||||||
set(INCLUDE_DIRS
|
set(INCLUDE_DIRS
|
||||||
"include"
|
"include"
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,11 @@ namespace gdpm::package{
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace gdpm::config{
|
namespace gdpm::config{
|
||||||
|
enum class print_style{
|
||||||
|
list = 0,
|
||||||
|
table = 1,
|
||||||
|
};
|
||||||
|
|
||||||
struct context{
|
struct context{
|
||||||
string username;
|
string username;
|
||||||
string password;
|
string password;
|
||||||
|
|
@ -25,24 +30,28 @@ namespace gdpm::config{
|
||||||
string packages_dir;
|
string packages_dir;
|
||||||
string tmp_dir;
|
string tmp_dir;
|
||||||
string_map remote_sources;
|
string_map remote_sources;
|
||||||
size_t jobs = 1;
|
int jobs = 1;
|
||||||
size_t timeout = 3000;
|
int timeout = 3000;
|
||||||
size_t max_results = 200;
|
|
||||||
bool enable_sync = true;
|
bool enable_sync = true;
|
||||||
bool enable_cache = true;
|
bool enable_cache = true;
|
||||||
bool skip_prompt = false;
|
bool skip_prompt = false;
|
||||||
bool enable_file_logging;
|
bool enable_file_logging;
|
||||||
bool clean_temporary;
|
bool clean_temporary;
|
||||||
int verbose;
|
|
||||||
|
int verbose = log::INFO;
|
||||||
|
print_style style = print_style::list;
|
||||||
package::info info;
|
package::info info;
|
||||||
rest_api::request_params api_params;
|
rest_api::request_params rest_api_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
string to_json(const context& config, bool pretty_print = false);
|
string to_json(const context& config, bool pretty_print = false);
|
||||||
error load(std::filesystem::path path, context& config);
|
error load(std::filesystem::path path, context& config);
|
||||||
error save(std::filesystem::path path, const context& config);
|
error save(std::filesystem::path path, const context& config);
|
||||||
error handle_config(config::context& config, const args_t& args, const var_opts& opts);
|
error handle_config(config::context& config, const args_t& args, const var_opts& opts);
|
||||||
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 set_property(config::context& config, const string& property, const any& value);
|
||||||
|
template <typename T = any>
|
||||||
|
T& get_property(const config::context& config, const string& property);
|
||||||
|
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}, int jobs = GDPM_CONFIG_THREADS, int 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);
|
error validate(const rapidjson::Document& doc);
|
||||||
void print_json(const context& config);
|
void print_json(const context& config);
|
||||||
void print_properties(const context& config, const string_list& properties);
|
void print_properties(const context& config, const string_list& properties);
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ namespace gdpm::constants::error{
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
UNKNOWN_COMMAND,
|
UNKNOWN_COMMAND,
|
||||||
|
UNKNOWN_ARGUMENT,
|
||||||
|
ARGPARSE_ERROR,
|
||||||
NOT_FOUND,
|
NOT_FOUND,
|
||||||
NOT_DEFINED,
|
NOT_DEFINED,
|
||||||
NOT_IMPLEMENTED,
|
NOT_IMPLEMENTED,
|
||||||
|
|
@ -102,6 +104,11 @@ namespace gdpm{
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr gdpm::error error_rc(const gdpm::error& e){
|
||||||
|
error(e);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
static void error(const char *p, const gdpm::error& e){
|
static void error(const char *p, const gdpm::error& e){
|
||||||
println("{}{}{}", p, prefix.contents, e.get_message());
|
println("{}{}{}", p, prefix.contents, e.get_message());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ namespace gdpm::log
|
||||||
inline constexpr const char* get_info_prefix() { return "[INFO {}] "; }
|
inline constexpr const char* get_info_prefix() { return "[INFO {}] "; }
|
||||||
inline constexpr const char* get_error_prefix() { return "[ERROR {}] "; }
|
inline constexpr const char* get_error_prefix() { return "[ERROR {}] "; }
|
||||||
inline constexpr const char* get_debug_prefix() { return "[DEBUG {}] "; }
|
inline constexpr const char* get_debug_prefix() { return "[DEBUG {}] "; }
|
||||||
|
inline constexpr const char* get_warning_prefix() { return "[WARN {}] "; }
|
||||||
|
|
||||||
static void vlog(fmt::string_view format, fmt::format_args args){
|
static void vlog(fmt::string_view format, fmt::format_args args){
|
||||||
fmt::vprint(format, args);
|
fmt::vprint(format, args);
|
||||||
|
|
@ -142,6 +143,21 @@ namespace gdpm::log
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename S, typename...Args>
|
||||||
|
static constexpr void warn(const S& format, Args&&...args){
|
||||||
|
if(log::level < to_int(log::WARNING))
|
||||||
|
return;
|
||||||
|
#if GDPM_LOG_LEVEL > WARN
|
||||||
|
set_prefix_if(std::format(get_warning_prefix(), utils::timestamp()), true);
|
||||||
|
set_suffix_if("\n");
|
||||||
|
vlog(
|
||||||
|
fmt::format(GDPM_COLOR_LOG_WARNING "{}{}{}" GDPM_COLOR_LOG_RESET, prefix.contents, format, suffix),
|
||||||
|
fmt::make_format_args(args...)
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename S, typename...Args>
|
template <typename S, typename...Args>
|
||||||
static constexpr void print(const S& format, Args&&...args){
|
static constexpr void print(const S& format, Args&&...args){
|
||||||
vlog(
|
vlog(
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@ namespace gdpm::package {
|
||||||
|
|
||||||
GDPM_DLL_EXPORT void print_list(const rapidjson::Document& json);
|
GDPM_DLL_EXPORT void print_list(const rapidjson::Document& json);
|
||||||
GDPM_DLL_EXPORT void print_list(const info_list& packages);
|
GDPM_DLL_EXPORT void print_list(const info_list& packages);
|
||||||
|
GDPM_DLL_EXPORT void print_table(const info_list& packages);
|
||||||
GDPM_DLL_EXPORT result_t<info_list> get_package_info(const opts_t& opts);
|
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 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 void clean_temporary(const config::context& config, const title_list& package_titles);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "clipp.h"
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
#include <any>
|
||||||
|
|
||||||
namespace gdpm{
|
namespace gdpm{
|
||||||
class error;
|
class error;
|
||||||
|
|
@ -47,6 +49,7 @@ namespace gdpm{
|
||||||
using string_list = std::vector<string>;
|
using string_list = std::vector<string>;
|
||||||
using string_map = std::unordered_map<string, string>;
|
using string_map = std::unordered_map<string, string>;
|
||||||
using string_pair = std::pair<string, string>;
|
using string_pair = std::pair<string, string>;
|
||||||
|
using any = std::any;
|
||||||
using var = std::variant<int, float, bool, string, string_list, string_map, size_t>;
|
using var = std::variant<int, float, bool, string, string_list, string_map, size_t>;
|
||||||
template <typename T = var>
|
template <typename T = var>
|
||||||
using _args_t = std::vector<T>;
|
using _args_t = std::vector<T>;
|
||||||
|
|
|
||||||
1
modules/argparse
Submodule
1
modules/argparse
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 557948f1236db9e27089959de837cc23de6c6bbd
|
||||||
167
src/config.cpp
167
src/config.cpp
|
|
@ -7,6 +7,7 @@
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
|
|
||||||
// RapidJSON
|
// RapidJSON
|
||||||
|
#include <any>
|
||||||
#include <rapidjson/ostreamwrapper.h>
|
#include <rapidjson/ostreamwrapper.h>
|
||||||
#include <rapidjson/rapidjson.h>
|
#include <rapidjson/rapidjson.h>
|
||||||
#include <rapidjson/writer.h>
|
#include <rapidjson/writer.h>
|
||||||
|
|
@ -14,6 +15,7 @@
|
||||||
#include <rapidjson/prettywriter.h>
|
#include <rapidjson/prettywriter.h>
|
||||||
#include <rapidjson/document.h>
|
#include <rapidjson/document.h>
|
||||||
#include <rapidjson/error/en.h>
|
#include <rapidjson/error/en.h>
|
||||||
|
#include <tabulate/table.hpp>
|
||||||
|
|
||||||
|
|
||||||
// fmt
|
// fmt
|
||||||
|
|
@ -67,7 +69,7 @@ namespace gdpm::config{
|
||||||
file.open(path, std::ios::in);
|
file.open(path, std::ios::in);
|
||||||
if(!file){
|
if(!file){
|
||||||
if(config.verbose)
|
if(config.verbose)
|
||||||
log::info("No configuration file found. Creating a new one.");
|
log::warn("No configuration file found. Creating a new one.");
|
||||||
config = make_context();
|
config = make_context();
|
||||||
save(config.path, config);
|
save(config.path, config);
|
||||||
return error();
|
return error();
|
||||||
|
|
@ -230,6 +232,46 @@ namespace gdpm::config{
|
||||||
return error();
|
return error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error set_property(
|
||||||
|
config::context& config,
|
||||||
|
const string& property,
|
||||||
|
const any& value
|
||||||
|
){
|
||||||
|
log::println("config::set_property() called");
|
||||||
|
if(property == "username") config.username = std::any_cast<string>(value);
|
||||||
|
else if(property == "password") config.password = std::any_cast<string>(value);
|
||||||
|
else if(property == "path") config.path = std::any_cast<string>(value);
|
||||||
|
else if(property == "token") config.token = std::any_cast<string>(value);
|
||||||
|
else if(property == "packages_dir") config.packages_dir = std::any_cast<string>(value);
|
||||||
|
else if(property == "tmp_dir") config.tmp_dir = std::any_cast<string>(value);
|
||||||
|
else if(property == "remote_sources") config.remote_sources = std::any_cast<string_map>(value);
|
||||||
|
else if(property == "jobs") config.jobs = std::any_cast<int>(value);
|
||||||
|
else if(property == "timeout") config.timeout = std::any_cast<int>(value);
|
||||||
|
else if(property == "enable_sync") config.enable_sync = std::any_cast<bool>(value);
|
||||||
|
else if(property == "enable_cache") config.enable_cache = std::any_cast<bool>(value);
|
||||||
|
else if(property == "skip_prompt") config.skip_prompt = std::any_cast<bool>(value);
|
||||||
|
else if(property == "enable_file_logging") config.enable_file_logging = std::any_cast<bool>(value);
|
||||||
|
else if(property == "clean_temporary") config.clean_temporary = std::any_cast<bool>(value);
|
||||||
|
else{
|
||||||
|
return log::error_rc(error(
|
||||||
|
constants::error::INVALID_CONFIG,
|
||||||
|
"Could not find property"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T& get_property(
|
||||||
|
const config::context& config,
|
||||||
|
const string& property
|
||||||
|
){
|
||||||
|
log::println("config::get_property() called");
|
||||||
|
if(property == "username") return config.username;
|
||||||
|
else if(property == "password") return config.password;
|
||||||
|
else if(property == "path") return config.path;
|
||||||
|
else if(property == "token") return config.token;
|
||||||
|
else if(property == "package_dir") return config.packages_dir;
|
||||||
|
}
|
||||||
|
|
||||||
context make_context(
|
context make_context(
|
||||||
const string& username,
|
const string& username,
|
||||||
|
|
@ -240,8 +282,8 @@ namespace gdpm::config{
|
||||||
const string& packages_dir,
|
const string& packages_dir,
|
||||||
const string& tmp_dir,
|
const string& tmp_dir,
|
||||||
const string_map& remote_sources,
|
const string_map& remote_sources,
|
||||||
size_t threads,
|
int jobs,
|
||||||
size_t timeout,
|
int timeout,
|
||||||
bool enable_sync,
|
bool enable_sync,
|
||||||
bool enable_file_logging,
|
bool enable_file_logging,
|
||||||
int verbose
|
int verbose
|
||||||
|
|
@ -254,7 +296,7 @@ namespace gdpm::config{
|
||||||
.packages_dir = (packages_dir.empty()) ? string(getenv("HOME")) + ".gdpm" : packages_dir,
|
.packages_dir = (packages_dir.empty()) ? string(getenv("HOME")) + ".gdpm" : packages_dir,
|
||||||
.tmp_dir = tmp_dir,
|
.tmp_dir = tmp_dir,
|
||||||
.remote_sources = remote_sources,
|
.remote_sources = remote_sources,
|
||||||
.jobs = threads,
|
.jobs = jobs,
|
||||||
.timeout = timeout,
|
.timeout = timeout,
|
||||||
.enable_sync = enable_sync,
|
.enable_sync = enable_sync,
|
||||||
.enable_file_logging = enable_file_logging,
|
.enable_file_logging = enable_file_logging,
|
||||||
|
|
@ -293,6 +335,8 @@ namespace gdpm::config{
|
||||||
const context& config,
|
const context& config,
|
||||||
const string& property
|
const string& property
|
||||||
){
|
){
|
||||||
|
using namespace tabulate;
|
||||||
|
|
||||||
if(property.empty()) return;
|
if(property.empty()) return;
|
||||||
else if(property == "username") log::println("username: {}", config.username);
|
else if(property == "username") log::println("username: {}", config.username);
|
||||||
else if(property == "password") log::println("password: {}", config.password);
|
else if(property == "password") log::println("password: {}", config.password);
|
||||||
|
|
@ -311,34 +355,103 @@ namespace gdpm::config{
|
||||||
else if(property == "verbose") log::println("verbose: {}", config.verbose);
|
else if(property == "verbose") log::println("verbose: {}", config.verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void add_row(
|
||||||
|
tabulate::Table& table,
|
||||||
|
const context& config,
|
||||||
|
const string property
|
||||||
|
){
|
||||||
|
if(property.empty()) return;
|
||||||
|
else if(property == "username") table.add_row({"Username", config.username});
|
||||||
|
else if(property == "password") table.add_row({"Password", config.password});
|
||||||
|
else if(property == "path") table.add_row({"Path", config.path});
|
||||||
|
else if(property == "token") table.add_row({"Token", config.token});
|
||||||
|
else if(property == "packages_dir") table.add_row({"Package Directory", config.packages_dir});
|
||||||
|
else if(property == "tmp_dir") table.add_row({"Temp Directory", config.tmp_dir});
|
||||||
|
else if(property == "remote_sources") table.add_row({"Remotes", utils::join(config.remote_sources, "\t", "\n")});
|
||||||
|
else if(property == "jobs") table.add_row({"Threads", std::to_string(config.jobs)});
|
||||||
|
else if(property == "timeout") table.add_row({"Timeout", std::to_string(config.timeout)});
|
||||||
|
else if(property == "sync") table.add_row({"Fetch Assets", std::to_string(config.enable_sync)});
|
||||||
|
else if(property == "cache") table.add_row({"Cache", std::to_string(config.enable_cache)});
|
||||||
|
else if(property == "prompt") table.add_row({"Skip Prompt", std::to_string(config.skip_prompt)});
|
||||||
|
else if(property == "logging") table.add_row({"File Logging", std::to_string(config.enable_file_logging)});
|
||||||
|
else if(property == "clean") table.add_row({"Clean Temporary", std::to_string(config.clean_temporary)});
|
||||||
|
else if(property == "verbose") table.add_row({"Verbosity", std::to_string(config.verbose)});
|
||||||
|
}
|
||||||
|
|
||||||
void print_properties(
|
void print_properties(
|
||||||
const context& config,
|
const context& config,
|
||||||
const string_list& properties
|
const string_list& properties
|
||||||
){
|
){
|
||||||
if(properties.empty()){
|
using namespace tabulate;
|
||||||
_print_property(config, "username");
|
|
||||||
_print_property(config, "password");
|
if(config.style == config::print_style::list){
|
||||||
_print_property(config, "path");
|
if(properties.empty()){
|
||||||
_print_property(config, "token");
|
_print_property(config, "username");
|
||||||
_print_property(config, "packages_dir");
|
_print_property(config, "password");
|
||||||
_print_property(config, "tmp_dir");
|
_print_property(config, "path");
|
||||||
_print_property(config, "remote_sources");
|
_print_property(config, "token");
|
||||||
_print_property(config, "jobs");
|
_print_property(config, "packages_dir");
|
||||||
_print_property(config, "timeout");
|
_print_property(config, "tmp_dir");
|
||||||
_print_property(config, "sync");
|
_print_property(config, "remote_sources");
|
||||||
_print_property(config, "cache");
|
_print_property(config, "jobs");
|
||||||
_print_property(config, "prompt");
|
_print_property(config, "timeout");
|
||||||
_print_property(config, "logging");
|
_print_property(config, "sync");
|
||||||
_print_property(config, "clean");
|
_print_property(config, "cache");
|
||||||
_print_property(config, "verbose");
|
_print_property(config, "prompt");
|
||||||
}
|
_print_property(config, "logging");
|
||||||
std::for_each(
|
_print_property(config, "clean");
|
||||||
properties.begin(),
|
_print_property(config, "verbose");
|
||||||
properties.end(),
|
|
||||||
[&config](const string& property){
|
|
||||||
_print_property(config, property);
|
|
||||||
}
|
}
|
||||||
);
|
else {
|
||||||
|
std::for_each(
|
||||||
|
properties.begin(),
|
||||||
|
properties.end(),
|
||||||
|
[&config](const string& property){
|
||||||
|
_print_property(config, property);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(config.style == config::print_style::table){
|
||||||
|
Table table;
|
||||||
|
if(properties.empty()){
|
||||||
|
table.add_row({"Property", "Value"});
|
||||||
|
table.add_row({"Username", config.username});
|
||||||
|
table.add_row({"Password", config.password});
|
||||||
|
table.add_row({"Path", config.path});
|
||||||
|
table.add_row({"Token", config.token});
|
||||||
|
table.add_row({"Package Directory", config.token});
|
||||||
|
table.add_row({"Temp Directory", config.tmp_dir});
|
||||||
|
table.add_row({"Remotes", utils::join(config.remote_sources)});
|
||||||
|
table.add_row({"Threads", std::to_string(config.jobs)});
|
||||||
|
table.add_row({"Timeout", std::to_string(config.timeout)});
|
||||||
|
table.add_row({"Fetch Data", std::to_string(config.enable_sync)});
|
||||||
|
table.add_row({"Use Cache", std::to_string(config.enable_cache)});
|
||||||
|
table.add_row({"Logging", std::to_string(config.enable_file_logging)});
|
||||||
|
table.add_row({"Clean", std::to_string(config.clean_temporary)});
|
||||||
|
table.add_row({"Verbosity", std::to_string(config.verbose)});
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
std::for_each(
|
||||||
|
properties.begin(),
|
||||||
|
properties.end(),
|
||||||
|
[&table, &config](const string& property){
|
||||||
|
add_row(table, config, property);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
table[0].format()
|
||||||
|
.padding_top(1)
|
||||||
|
.padding_bottom(1)
|
||||||
|
.font_background_color(Color::red)
|
||||||
|
.font_style({FontStyle::bold});
|
||||||
|
table.column(1).format()
|
||||||
|
.font_color(Color::yellow);
|
||||||
|
table[0][1].format()
|
||||||
|
.font_background_color(Color::blue);
|
||||||
|
table.print(std::cout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
104
src/package.cpp
104
src/package.cpp
|
|
@ -15,6 +15,7 @@
|
||||||
#include <rapidjson/error/en.h>
|
#include <rapidjson/error/en.h>
|
||||||
#include <rapidjson/ostreamwrapper.h>
|
#include <rapidjson/ostreamwrapper.h>
|
||||||
#include <rapidjson/prettywriter.h>
|
#include <rapidjson/prettywriter.h>
|
||||||
|
#include <tabulate/table.hpp>
|
||||||
|
|
||||||
namespace gdpm::package{
|
namespace gdpm::package{
|
||||||
|
|
||||||
|
|
@ -39,8 +40,7 @@ namespace gdpm::package{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Append files from --file option */
|
/* Append files from --file option */
|
||||||
if(!params.input_files.empty()){
|
// if(!params.input_files.empty()){
|
||||||
log::print("input files");
|
|
||||||
for(const auto& filepath : params.input_files){
|
for(const auto& filepath : params.input_files){
|
||||||
string contents = utils::readfile(filepath);
|
string contents = utils::readfile(filepath);
|
||||||
log::print("contents: {}", contents);
|
log::print("contents: {}", contents);
|
||||||
|
|
@ -51,7 +51,7 @@ namespace gdpm::package{
|
||||||
std::end(input_titles)
|
std::end(input_titles)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
result_t result = cache::get_package_info_by_title(package_titles);
|
result_t result = cache::get_package_info_by_title(package_titles);
|
||||||
package::info_list p_found = {};
|
package::info_list p_found = {};
|
||||||
package::info_list p_cache = result.unwrap_unsafe();
|
package::info_list p_cache = result.unwrap_unsafe();
|
||||||
|
|
@ -445,16 +445,14 @@ namespace gdpm::package{
|
||||||
|
|
||||||
rest_api_params.filter = http.url_escape(p_title);
|
rest_api_params.filter = http.url_escape(p_title);
|
||||||
|
|
||||||
std::string request_url{constants::HostUrl};
|
string request_url{constants::HostUrl};
|
||||||
request_url += rest_api::endpoints::GET_Asset;
|
request_url += rest_api::endpoints::GET_Asset;
|
||||||
Document doc = rest_api::get_assets_list(request_url, rest_api_params);
|
Document doc = rest_api::get_assets_list(request_url, rest_api_params);
|
||||||
if(doc.IsNull()){
|
if(doc.IsNull()){
|
||||||
error error(
|
return log::error_rc(error(
|
||||||
constants::error::HOST_UNREACHABLE,
|
constants::error::HOST_UNREACHABLE,
|
||||||
"Could not fetch metadata."
|
"Could not fetch metadata."
|
||||||
);
|
));
|
||||||
log::error(error);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// log::info("{} package(s) found...", doc["total_items"].GetInt());
|
// log::info("{} package(s) found...", doc["total_items"].GetInt());
|
||||||
|
|
@ -476,18 +474,21 @@ namespace gdpm::package{
|
||||||
result_t r_installed = cache::get_installed_packages();
|
result_t r_installed = cache::get_installed_packages();
|
||||||
info_list p_installed = r_installed.unwrap_unsafe();
|
info_list p_installed = r_installed.unwrap_unsafe();
|
||||||
if(!p_installed.empty()){
|
if(!p_installed.empty()){
|
||||||
print_list(p_installed);
|
if(config.style == config::print_style::list)
|
||||||
|
print_list(p_installed);
|
||||||
|
else if(config.style == config::print_style::table){
|
||||||
|
print_table(p_installed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(show == "remote"){
|
else if(show == "remote"){
|
||||||
remote::print_repositories(config);
|
remote::print_repositories(config);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
error error(
|
log::error(error(
|
||||||
constants::error::UNKNOWN_COMMAND,
|
constants::error::UNKNOWN_COMMAND,
|
||||||
"Unrecognized subcommand. Try either 'packages' or 'remote' instead."
|
"Unrecognized subcommand. Try either 'packages' or 'remote' instead."
|
||||||
);
|
));
|
||||||
log::error(error);
|
|
||||||
}
|
}
|
||||||
return error();
|
return error();
|
||||||
}
|
}
|
||||||
|
|
@ -520,7 +521,7 @@ namespace gdpm::package{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::ofstream of(path);
|
std::ofstream of(path);
|
||||||
log::println("writing contents to file");
|
log::println("export: {}", path);
|
||||||
of << output;
|
of << output;
|
||||||
of.close();
|
of.close();
|
||||||
}
|
}
|
||||||
|
|
@ -532,17 +533,15 @@ namespace gdpm::package{
|
||||||
error link(
|
error link(
|
||||||
const config::context& config,
|
const config::context& config,
|
||||||
const title_list& package_titles,
|
const title_list& package_titles,
|
||||||
const package::params& params /* path is last arg */
|
const package::params& params
|
||||||
){
|
){
|
||||||
using namespace std::filesystem;
|
using namespace std::filesystem;
|
||||||
|
|
||||||
if(params.args.empty()){
|
if(params.paths.empty()){
|
||||||
error error(
|
return log::error_rc(error(
|
||||||
constants::error::INVALID_ARG_COUNT,
|
constants::error::PATH_NOT_DEFINED,
|
||||||
"Must supply at least 2 arguments (package name and path)"
|
"Path is required"
|
||||||
);
|
));
|
||||||
log::error(error);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for packages in cache to link */
|
/* Check for packages in cache to link */
|
||||||
|
|
@ -550,12 +549,10 @@ namespace gdpm::package{
|
||||||
info_list p_found = {};
|
info_list p_found = {};
|
||||||
info_list p_cache = r_cache.unwrap_unsafe();
|
info_list p_cache = r_cache.unwrap_unsafe();
|
||||||
if(p_cache.empty()){
|
if(p_cache.empty()){
|
||||||
error error(
|
return log::error_rc(error(
|
||||||
constants::error::NOT_FOUND,
|
constants::error::NOT_FOUND,
|
||||||
"Could not find any packages to link in cache."
|
"Could not find any packages to link in cache."
|
||||||
);
|
));
|
||||||
log::error(error);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const auto& p_title : package_titles){
|
for(const auto& p_title : package_titles){
|
||||||
|
|
@ -575,17 +572,15 @@ namespace gdpm::package{
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the storage paths for all packages to create symlinks */
|
/* Get the storage paths for all packages to create symlinks */
|
||||||
path_refs paths = path_refs({params.args.back()});
|
|
||||||
const path package_dir{config.packages_dir};
|
const path package_dir{config.packages_dir};
|
||||||
for(const auto& p : p_found){
|
for(const auto& p : p_found){
|
||||||
for(const auto& path : paths){
|
for(const auto& path : params.paths){
|
||||||
const string _path = path;
|
log::info_n("link: \"{}\" -> '{}'...", p.title, path + "/" + p.title);
|
||||||
log::info_n("link: \"{}\" -> '{}'...", p.title, _path + "/" + p.title);
|
|
||||||
// std::filesystem::path target{config.packages_dir + "/" + p.title};
|
// std::filesystem::path target{config.packages_dir + "/" + p.title};
|
||||||
std::filesystem::path target = {current_path().string() + "/" + config.packages_dir + "/" + p.title};
|
std::filesystem::path target = {current_path().string() + "/" + config.packages_dir + "/" + p.title};
|
||||||
std::filesystem::path symlink_path{_path + "/" + p.title};
|
std::filesystem::path symlink_path{path + "/" + p.title};
|
||||||
if(!std::filesystem::exists(symlink_path.string()))
|
if(!std::filesystem::exists(symlink_path.string()))
|
||||||
std::filesystem::create_directories(_path + "/");
|
std::filesystem::create_directories(path + "/");
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
std::filesystem::create_directory_symlink(target, symlink_path, ec);
|
std::filesystem::create_directory_symlink(target, symlink_path, ec);
|
||||||
if(ec){
|
if(ec){
|
||||||
|
|
@ -609,13 +604,11 @@ namespace gdpm::package{
|
||||||
){
|
){
|
||||||
using namespace std::filesystem;
|
using namespace std::filesystem;
|
||||||
|
|
||||||
if(params.args.empty()){
|
if(params.paths.empty()){
|
||||||
error error(
|
return log::error_rc(error(
|
||||||
constants::error::INVALID_ARG_COUNT,
|
constants::error::PATH_NOT_DEFINED,
|
||||||
"Must supply at least 2 arguments (package name and path)"
|
"Path is required"
|
||||||
);
|
));
|
||||||
log::error(error);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result_t r_cache = cache::get_package_info_by_title(package_titles);
|
result_t r_cache = cache::get_package_info_by_title(package_titles);
|
||||||
|
|
@ -624,12 +617,10 @@ namespace gdpm::package{
|
||||||
|
|
||||||
/* Check for installed packages to clone */
|
/* Check for installed packages to clone */
|
||||||
if(p_cache.empty()){
|
if(p_cache.empty()){
|
||||||
error error(
|
return log::error_rc(error(
|
||||||
constants::error::NO_PACKAGE_FOUND,
|
constants::error::NO_PACKAGE_FOUND,
|
||||||
"Could not find any packages to clone in cache."
|
"Could not find any packages to clone in cache."
|
||||||
);
|
));
|
||||||
log::error(error);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const auto& p_title : package_titles){
|
for(const auto& p_title : package_titles){
|
||||||
|
|
@ -694,7 +685,6 @@ namespace gdpm::package{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void print_list(const rapidjson::Document& json){
|
void print_list(const rapidjson::Document& json){
|
||||||
for(const auto& o : json["result"].GetArray()){
|
for(const auto& o : json["result"].GetArray()){
|
||||||
log::println(
|
log::println(
|
||||||
|
|
@ -717,6 +707,34 @@ namespace gdpm::package{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_table(const info_list& packages){
|
||||||
|
using namespace tabulate;
|
||||||
|
Table table;
|
||||||
|
table.add_row({
|
||||||
|
"Asset Name",
|
||||||
|
"Author",
|
||||||
|
"Category",
|
||||||
|
"Version",
|
||||||
|
"Godot Version",
|
||||||
|
"License/Cost",
|
||||||
|
"Last Modified",
|
||||||
|
"Support"
|
||||||
|
});
|
||||||
|
for(const auto& p : packages){
|
||||||
|
table.add_row({
|
||||||
|
p.title,
|
||||||
|
p.author,
|
||||||
|
p.category,
|
||||||
|
p.version,
|
||||||
|
p.godot_version,
|
||||||
|
p.cost,
|
||||||
|
p.modify_date,
|
||||||
|
p.support_level
|
||||||
|
});
|
||||||
|
}
|
||||||
|
table.print(std::cout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
result_t<info_list> get_package_info(const title_list& package_titles){
|
result_t<info_list> get_package_info(const title_list& package_titles){
|
||||||
return cache::get_package_info_by_title(package_titles);
|
return cache::get_package_info_by_title(package_titles);
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,11 @@
|
||||||
#include <rapidjson/document.h>
|
#include <rapidjson/document.h>
|
||||||
#include <cxxopts.hpp>
|
#include <cxxopts.hpp>
|
||||||
#include "clipp.h"
|
#include "clipp.h"
|
||||||
|
#include "argparse/argparse.hpp"
|
||||||
|
|
||||||
#include <rapidjson/ostreamwrapper.h>
|
#include <rapidjson/ostreamwrapper.h>
|
||||||
#include <rapidjson/prettywriter.h>
|
#include <rapidjson/prettywriter.h>
|
||||||
|
#include <stdexcept>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
|
||||||
|
|
@ -79,185 +81,426 @@ namespace gdpm::package_manager{
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, typename String = string>
|
||||||
|
auto set_if_used(
|
||||||
|
const argparse::ArgumentParser& cmd,
|
||||||
|
T& value,
|
||||||
|
const String& arg
|
||||||
|
){
|
||||||
|
using namespace argparse;
|
||||||
|
if(cmd.is_used(arg)){
|
||||||
|
value = cmd.get<T>(arg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
string_list get_packages_from_parser(
|
||||||
|
const argparse::ArgumentParser& cmd,
|
||||||
|
const std::string& arg = "packages"
|
||||||
|
){
|
||||||
|
if(cmd.is_used(arg))
|
||||||
|
return cmd.get<string_list>(arg);
|
||||||
|
return string_list();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
error parse_arguments(int argc, char **argv){
|
error parse_arguments(int argc, char **argv){
|
||||||
using namespace clipp;
|
using namespace clipp;
|
||||||
|
using namespace argparse;
|
||||||
|
|
||||||
/* Replace cxxopts with clipp */
|
/* Replace cxxopts with clipp */
|
||||||
action_e action = action_e::none;
|
action_e action = action_e::none;
|
||||||
package::title_list package_titles;
|
package::title_list package_titles;
|
||||||
package::params params;
|
package::params params;
|
||||||
|
|
||||||
auto doc_format = clipp::doc_formatting{}
|
ArgumentParser program(argv[0], "0.0.1", argparse::default_arguments::help);
|
||||||
.first_column(7)
|
ArgumentParser install_command("install");
|
||||||
.doc_column(45)
|
ArgumentParser add_command("add");
|
||||||
.last_column(99);
|
ArgumentParser remove_command("remove");
|
||||||
|
ArgumentParser update_command("update");
|
||||||
|
ArgumentParser search_command("search");
|
||||||
|
ArgumentParser export_command("export");
|
||||||
|
ArgumentParser list_command("list");
|
||||||
|
ArgumentParser link_command("link");
|
||||||
|
ArgumentParser clone_command("clone");
|
||||||
|
ArgumentParser clean_command("clean");
|
||||||
|
ArgumentParser config_command("config");
|
||||||
|
ArgumentParser fetch_command("fetch");
|
||||||
|
ArgumentParser version_command("version");
|
||||||
|
ArgumentParser remote_command("remote");
|
||||||
|
ArgumentParser ui_command("ui");
|
||||||
|
ArgumentParser help_command("help");
|
||||||
|
|
||||||
|
ArgumentParser config_get("get");
|
||||||
|
ArgumentParser config_set("set");
|
||||||
|
|
||||||
|
ArgumentParser remote_add("add");
|
||||||
|
ArgumentParser remote_remove("remove");
|
||||||
|
ArgumentParser remote_list("list");
|
||||||
|
|
||||||
|
program.add_description("Manage Godot engine assets from CLI");
|
||||||
|
program.add_argument("-v", "--verbose")
|
||||||
|
.action([&](const auto&){ config.verbose += 1; })
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true)
|
||||||
|
.help("set verbosity level")
|
||||||
|
.nargs(0);
|
||||||
|
|
||||||
|
install_command.add_description("install package(s)");
|
||||||
|
install_command.add_argument("packages")
|
||||||
|
.required()
|
||||||
|
.nargs(nargs_pattern::at_least_one)
|
||||||
|
.help("packages to install");
|
||||||
|
install_command.add_argument("--godot-version")
|
||||||
|
.help("set Godot version for request");
|
||||||
|
install_command.add_argument("--clean")
|
||||||
|
.help("clean temporary files")
|
||||||
|
.implicit_value(true)
|
||||||
|
.default_value(false)
|
||||||
|
.nargs(0);
|
||||||
|
install_command.add_argument("--disable-sync")
|
||||||
|
.help("enable syncing with remote before installing")
|
||||||
|
.implicit_value(true)
|
||||||
|
.default_value(false)
|
||||||
|
.nargs(0);
|
||||||
|
install_command.add_argument("--disable-cache")
|
||||||
|
.help("disable caching asset data")
|
||||||
|
.implicit_value(true)
|
||||||
|
.default_value(false)
|
||||||
|
.nargs(0);
|
||||||
|
install_command.add_argument("--remote")
|
||||||
|
.help("set the remote to use")
|
||||||
|
.nargs(1);
|
||||||
|
install_command.add_argument("-j", "--jobs")
|
||||||
|
.help("set the number of parallel downloads")
|
||||||
|
.default_value(1)
|
||||||
|
.nargs(1)
|
||||||
|
.scan<'i', int>();
|
||||||
|
install_command.add_argument("-y", "--skip-prompt")
|
||||||
|
.help("skip the yes/no prompt")
|
||||||
|
.implicit_value(true)
|
||||||
|
.default_value(false)
|
||||||
|
.nargs(0);
|
||||||
|
install_command.add_argument("-f", "--file")
|
||||||
|
.help("set the file(s) to read as input")
|
||||||
|
.append()
|
||||||
|
.nargs(1);
|
||||||
|
install_command.add_argument("-t", "--timeout")
|
||||||
|
.help("set the request timeout")
|
||||||
|
.default_value(30)
|
||||||
|
.nargs(0);
|
||||||
|
|
||||||
|
add_command.add_description("add package to project");
|
||||||
|
add_command.add_argument("packages").nargs(nargs_pattern::at_least_one);
|
||||||
|
add_command.add_argument("--remote");
|
||||||
|
add_command.add_argument("-j", "--jobs")
|
||||||
|
.help("")
|
||||||
|
.nargs(1)
|
||||||
|
.default_value(1)
|
||||||
|
.nargs(1)
|
||||||
|
.scan<'i', int>();
|
||||||
|
add_command.add_argument("-y", "--skip-prompt");
|
||||||
|
add_command.add_argument("-f", "--file")
|
||||||
|
.help("set the file(s) to read as input")
|
||||||
|
.append()
|
||||||
|
.nargs(nargs_pattern::at_least_one);
|
||||||
|
|
||||||
|
remove_command.add_description("remove package(s)");
|
||||||
|
remove_command.add_argument("packages").nargs(nargs_pattern::at_least_one);
|
||||||
|
remove_command.add_argument("--clean");
|
||||||
|
remove_command.add_argument("-y", "--skip-prompt");
|
||||||
|
remove_command.add_argument("-f", "--file")
|
||||||
|
.help("set the file(s) to read as input")
|
||||||
|
.append()
|
||||||
|
.nargs(nargs_pattern::at_least_one);
|
||||||
|
|
||||||
/* Set global options */
|
update_command.add_description("update package(s)");
|
||||||
auto debugOpt = option("-d", "--debug").set(config.verbose, to_int(log::DEBUG)) % "show debug output";
|
update_command.add_argument("packages").nargs(nargs_pattern::at_least_one);
|
||||||
auto configOpt = option("--config-path").set(config.path) % "set config path";
|
update_command.add_argument("--clean");
|
||||||
auto pathOpt = option("--path").set(params.paths) % "specify a path to use with command";
|
update_command.add_argument("--remote");
|
||||||
auto typeOpt = option("--type").set(config.info.type) % "set package type (any|addon|project)";
|
update_command.add_argument("-f", "--file")
|
||||||
auto sortOpt = option("--sort").set(config.rest_api_params.sort) % "sort packages in order (rating|cost|name|updated)";
|
.help("set the file(s) to read as input")
|
||||||
auto supportOpt = option("--support").set(config.rest_api_params.support) % "set the support level for API (all|official|community|testing)";
|
.append()
|
||||||
auto maxResultsOpt = option("--max-results").set(config.rest_api_params.max_results) % "set the request max results";
|
.nargs(nargs_pattern::at_least_one);
|
||||||
auto godotVersionOpt = option("--godot-version").set(config.rest_api_params.godot_version) % "set the request Godot version";
|
|
||||||
auto packageDirOpt = option("--package-dir").set(config.packages_dir) % "set the global package location";
|
|
||||||
auto tmpDirOpt = option("--tmp-dir").set(config.tmp_dir) % "set the temporary download location";
|
|
||||||
auto timeoutOpt = option("--timeout").set(config.timeout) % "set the request timeout";
|
|
||||||
auto verboseOpt = joinable(repeatable(option("-v", "--verbose").call([]{ config.verbose += 1; }))) % "show verbose output";
|
|
||||||
|
|
||||||
/* Set the options */
|
search_command.add_description("search for package(s)");
|
||||||
// auto fileOpt = repeatable(option("--file", "-f").set(params.input_files) % "read file as input");
|
search_command.add_argument("packages").nargs(nargs_pattern::at_least_one);
|
||||||
auto fileOpt = repeatable(option("--file", "-f") & values("input", params.input_files)) % "read file as input";
|
search_command.add_argument("--godot-version");
|
||||||
auto cleanOpt = option("--clean").set(config.clean_temporary) % "enable/disable cleaning temps";
|
search_command.add_argument("--remote");
|
||||||
auto parallelOpt = option("--jobs").set(config.jobs) % "set number of parallel jobs";
|
search_command.add_argument("-f", "--file")
|
||||||
auto cacheOpt = option("--enable-cache").set(config.enable_cache) % "enable/disable local caching";
|
.help("set the file(s) to read as input")
|
||||||
auto syncOpt = option("--enable-sync").set(config.enable_sync) % "enable/disable remote syncing";
|
.append()
|
||||||
auto skipOpt = option("-y", "--skip-prompt").set(config.skip_prompt, true) % "skip the y/n prompt";
|
.nargs(nargs_pattern::at_least_one);
|
||||||
auto remoteOpt = option("--remote").set(params.remote_source) % "set remote source to use";
|
|
||||||
|
|
||||||
auto packageValues = values("packages", package_titles);
|
ui_command.add_description("show user interface (WIP)");
|
||||||
auto requiredPath = required("--path", params.args);
|
version_command.add_description("show version and exit");
|
||||||
|
help_command.add_description("show help message and exit");
|
||||||
|
|
||||||
|
export_command.add_description("export install package(s) list");
|
||||||
|
export_command.add_argument("paths")
|
||||||
|
.help("export list of installed packages")
|
||||||
|
.required()
|
||||||
|
.nargs(nargs_pattern::at_least_one);
|
||||||
|
|
||||||
|
list_command.add_description("show install package(s) and remotes");
|
||||||
|
list_command.add_argument("show")
|
||||||
|
.help("show installed packages or remote")
|
||||||
|
.nargs(nargs_pattern::any)
|
||||||
|
.default_value("packages");
|
||||||
|
list_command.add_argument("--style")
|
||||||
|
.help("set how to print output")
|
||||||
|
.nargs(1)
|
||||||
|
.default_value("list");
|
||||||
|
|
||||||
|
link_command.add_description("link package(s) to path");
|
||||||
|
link_command.add_argument("packages")
|
||||||
|
.help("package(s) to link")
|
||||||
|
.required()
|
||||||
|
.nargs(1);
|
||||||
|
link_command.add_argument("path")
|
||||||
|
.help("path to link")
|
||||||
|
.required()
|
||||||
|
.nargs(1);
|
||||||
|
|
||||||
|
clone_command.add_description("clone package(s) to path");
|
||||||
|
clone_command.add_argument("packages")
|
||||||
|
.help("package(s) to clone")
|
||||||
|
.required()
|
||||||
|
.nargs(1);;
|
||||||
|
clone_command.add_argument("path")
|
||||||
|
.help("path to clone")
|
||||||
|
.required()
|
||||||
|
.nargs(1);
|
||||||
|
|
||||||
|
clean_command.add_description("clean package(s) temporary files");
|
||||||
|
clean_command.add_argument("packages")
|
||||||
|
.help("package(s) to clean")
|
||||||
|
.required()
|
||||||
|
.nargs(nargs_pattern::at_least_one);
|
||||||
|
|
||||||
auto installCmd = "install" % (
|
fetch_command.add_description("fetch and sync asset data");
|
||||||
command("install").set(action, action_e::install),
|
fetch_command.add_argument("remote")
|
||||||
packageValues % "package(s) to install from asset library",
|
.help("remote to fetch")
|
||||||
godotVersionOpt, cleanOpt, parallelOpt, syncOpt, skipOpt, remoteOpt, fileOpt
|
.required()
|
||||||
);
|
.nargs(1);
|
||||||
auto addCmd = "add" % (
|
|
||||||
command("add").set(action, action_e::add),
|
|
||||||
packageValues % "package(s) to add to project",
|
|
||||||
parallelOpt, skipOpt, remoteOpt, fileOpt
|
|
||||||
);
|
|
||||||
auto removeCmd = "remove" % (
|
|
||||||
command("remove").set(action, action_e::remove),
|
|
||||||
packageValues % "packages(s) to remove from project",
|
|
||||||
fileOpt, skipOpt, cleanOpt
|
|
||||||
);
|
|
||||||
auto updateCmd = "update package(s)" % (
|
|
||||||
command("update").set(action, action_e::update),
|
|
||||||
packageValues % ""
|
|
||||||
);
|
|
||||||
auto searchCmd = "search for package(s)" % (
|
|
||||||
command("search").set(action, action_e::search),
|
|
||||||
packageValues % "",
|
|
||||||
godotVersionOpt, fileOpt, remoteOpt, configOpt
|
|
||||||
);
|
|
||||||
auto exportCmd = "export installed package list to file" % (
|
|
||||||
command("export").set(action, action_e::p_export),
|
|
||||||
values("paths", params.args) % ""
|
|
||||||
);
|
|
||||||
auto listCmd = "show installed packages" % (
|
|
||||||
command("list").set(action, action_e::list)
|
|
||||||
);
|
|
||||||
auto linkCmd = "create link from package to project" % (
|
|
||||||
command("link").set(action, action_e::link),
|
|
||||||
value("package", package_titles) % "",
|
|
||||||
value("path", params.args) % ""
|
|
||||||
);
|
|
||||||
auto cloneCmd = "clone package to project" % (
|
|
||||||
command("clone").set(action, action_e::clone),
|
|
||||||
value("package", package_titles) % "",
|
|
||||||
value("path", params.args) % ""
|
|
||||||
);
|
|
||||||
auto cleanCmd = "clean temporary download files" % (
|
|
||||||
command("clean").set(action, action_e::clean),
|
|
||||||
values("packages", package_titles) % ""
|
|
||||||
);
|
|
||||||
auto configCmd = "manage config properties" % (
|
|
||||||
command("config").set(action, action_e::config_get) ,
|
|
||||||
(
|
|
||||||
( greedy(command("get")).set(action, action_e::config_get),
|
|
||||||
option(repeatable(values("properties", params.args)))
|
|
||||||
) % "get config properties"
|
|
||||||
|
|
|
||||||
( command("set").set(action, action_e::config_set) ,
|
|
||||||
value("property", params.args[1]).call([]{}),
|
|
||||||
value("value", params.args[2]).call([]{})
|
|
||||||
) % "set config properties"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
auto fetchCmd = "fetch asset data from remote" % (
|
|
||||||
command("fetch").set(action, action_e::fetch),
|
|
||||||
option(values("remote", params.args)) % ""
|
|
||||||
);
|
|
||||||
auto versionCmd = "show the version and exit" %(
|
|
||||||
command("version").set(action, action_e::version)
|
|
||||||
);
|
|
||||||
auto add_arg = [¶ms](string arg) { params.args.emplace_back(arg); };
|
|
||||||
auto remoteCmd = "manage remote sources" % (
|
|
||||||
command("remote").set(action, action_e::remote_list).if_missing(
|
|
||||||
[]{ remote::print_repositories(config); }
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"add" % ( command("add").set(action, action_e::remote_add),
|
|
||||||
word("name").call(add_arg) % "",
|
|
||||||
value("url").call(add_arg) % ""
|
|
||||||
)
|
|
||||||
|
|
|
||||||
"remove a remote source" % ( command("remove").set(action, action_e::remote_remove),
|
|
||||||
words("names", params.args) % ""
|
|
||||||
)
|
|
||||||
|
|
|
||||||
"list remote sources" % ( command("list").set(action, action_e::remote_list))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
auto uiCmd = "start with UI" % (
|
|
||||||
command("ui").set(action, action_e::ui)
|
|
||||||
);
|
|
||||||
auto helpCmd = "show this message and exit" % (
|
|
||||||
command("help").set(action, action_e::help)
|
|
||||||
);
|
|
||||||
|
|
||||||
auto cli = (
|
config_get.add_argument("properties")
|
||||||
debugOpt, verboseOpt, configOpt,
|
.help("get config properties")
|
||||||
(installCmd | addCmd | removeCmd | updateCmd | searchCmd | exportCmd |
|
.nargs(nargs_pattern::any);
|
||||||
listCmd | linkCmd | cloneCmd | cleanCmd | configCmd | fetchCmd |
|
config_get.add_description("get config properties");
|
||||||
remoteCmd | uiCmd | helpCmd | versionCmd)
|
config_set.add_argument("property")
|
||||||
);
|
.help("property name")
|
||||||
|
.required()
|
||||||
|
.nargs(1);
|
||||||
|
config_set.add_argument("value")
|
||||||
|
.help("property value")
|
||||||
|
.required()
|
||||||
|
.nargs(1);
|
||||||
|
config_set.add_description("set config property");
|
||||||
|
|
||||||
/* Make help output */
|
config_command.add_description("manage config properties");
|
||||||
string man_page_format("");
|
config_command.add_subparser(config_get);
|
||||||
auto man_page = make_man_page(cli, argv[0], doc_format)
|
config_command.add_subparser(config_set);
|
||||||
.prepend_section("DESCRIPTION", "\tManage Godot Game Engine assets from the command-line.")
|
|
||||||
.append_section("LICENSE", "\tSee the 'LICENSE.md' file for more details.");
|
remote_add.add_argument("name")
|
||||||
std::for_each(man_page.begin(), man_page.end(),
|
.help("remote name")
|
||||||
[&man_page_format](const man_page::section& s){
|
.nargs(1);
|
||||||
man_page_format += s.title() + "\n";
|
remote_add.add_argument("url")
|
||||||
man_page_format += s.content() + "\n\n";
|
.help("remote url")
|
||||||
|
.nargs(1);
|
||||||
|
remote_remove.add_argument("names")
|
||||||
|
.help("remote name")
|
||||||
|
.nargs(nargs_pattern::at_least_one);
|
||||||
|
remote_list.add_argument("--style")
|
||||||
|
.help("set print style")
|
||||||
|
.nargs(1);
|
||||||
|
|
||||||
|
remote_command.add_description("manage remote(s)");
|
||||||
|
remote_command.add_subparser(remote_add);
|
||||||
|
remote_command.add_subparser(remote_remove);
|
||||||
|
remote_command.add_subparser(remote_list);
|
||||||
|
|
||||||
|
// version_command.add_argument(Targs f_args...)
|
||||||
|
|
||||||
|
program.add_subparser(install_command);
|
||||||
|
program.add_subparser(add_command);
|
||||||
|
program.add_subparser(remove_command);
|
||||||
|
program.add_subparser(update_command);
|
||||||
|
program.add_subparser(search_command);
|
||||||
|
program.add_subparser(export_command);
|
||||||
|
program.add_subparser(list_command);
|
||||||
|
program.add_subparser(link_command);
|
||||||
|
program.add_subparser(clone_command);
|
||||||
|
program.add_subparser(clean_command);
|
||||||
|
program.add_subparser(config_command);
|
||||||
|
program.add_subparser(fetch_command);
|
||||||
|
program.add_subparser(remote_command);
|
||||||
|
program.add_subparser(version_command);
|
||||||
|
program.add_subparser(ui_command);
|
||||||
|
program.add_subparser(help_command);
|
||||||
|
|
||||||
|
try{
|
||||||
|
program.parse_args(argc, argv);
|
||||||
|
// program.parse_known_args(argc, argv);
|
||||||
|
} catch(const std::runtime_error& e){
|
||||||
|
return log::error_rc(error(
|
||||||
|
constants::error::ARGPARSE_ERROR,
|
||||||
|
e.what())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(program.is_subcommand_used(install_command)){
|
||||||
|
action = action_e::install;
|
||||||
|
if(install_command.is_used("packages"))
|
||||||
|
package_titles = install_command.get<string_list>("packages");
|
||||||
|
set_if_used(install_command, config.rest_api_params.godot_version, "godot-version");
|
||||||
|
set_if_used(install_command, config.clean_temporary, "clean");
|
||||||
|
set_if_used(install_command, config.enable_sync, "disable-sync");
|
||||||
|
set_if_used(install_command, config.enable_cache, "disable-cache");
|
||||||
|
set_if_used(install_command, params.remote_source, "remote");
|
||||||
|
set_if_used(install_command, config.jobs, "jobs");
|
||||||
|
set_if_used(install_command, config.skip_prompt, "skip-prompt");
|
||||||
|
set_if_used(install_command, params.input_files, "file");
|
||||||
|
set_if_used(install_command, config.timeout, "timeout");
|
||||||
|
}
|
||||||
|
else if(program.is_subcommand_used(add_command)){
|
||||||
|
action = action_e::add;
|
||||||
|
package_titles = get_packages_from_parser(add_command);
|
||||||
|
set_if_used(add_command, params.remote_source, "remote");
|
||||||
|
set_if_used(add_command, config.jobs, "jobs");
|
||||||
|
set_if_used(add_command, config.skip_prompt, "skip-prompt");
|
||||||
|
set_if_used(add_command, params.input_files, "files");
|
||||||
|
}
|
||||||
|
else if(program.is_subcommand_used(remove_command)){
|
||||||
|
action = action_e::remove;
|
||||||
|
package_titles = get_packages_from_parser(remove_command);
|
||||||
|
set_if_used(remove_command, config.clean_temporary, "clean");
|
||||||
|
set_if_used(remove_command, config.skip_prompt, "skip-prompt");
|
||||||
|
set_if_used(remove_command, params.input_files, "file");
|
||||||
|
}
|
||||||
|
else if(program.is_subcommand_used(update_command)){
|
||||||
|
action = action_e::update;
|
||||||
|
package_titles = get_packages_from_parser(program);
|
||||||
|
set_if_used(update_command, config.clean_temporary, "clean");
|
||||||
|
set_if_used(update_command, params.remote_source, "remote");
|
||||||
|
set_if_used(update_command, params.input_files, "file");
|
||||||
|
}
|
||||||
|
else if(program.is_subcommand_used(search_command)){
|
||||||
|
action = action_e::search;
|
||||||
|
package_titles = get_packages_from_parser(search_command);
|
||||||
|
set_if_used(search_command, config.rest_api_params.godot_version, "godot-version");
|
||||||
|
set_if_used(search_command, params.remote_source, "remote");
|
||||||
|
set_if_used(search_command, params.input_files, "file");
|
||||||
|
}
|
||||||
|
else if(program.is_subcommand_used(export_command)){
|
||||||
|
action = action_e::p_export;
|
||||||
|
params.paths = export_command.get<string_list>("paths");
|
||||||
|
}
|
||||||
|
else if(program.is_subcommand_used(list_command)){
|
||||||
|
action = action_e::list;
|
||||||
|
// auto list = get_parser(program, "list");
|
||||||
|
if(list_command.is_used("show"))
|
||||||
|
params.args = list_command.get<string_list>("show");
|
||||||
|
if(list_command.is_used("style")){
|
||||||
|
string style = list_command.get<string>("style");
|
||||||
|
if(!style.compare("list"))
|
||||||
|
config.style = config::print_style::list;
|
||||||
|
else if(!style.compare("table"))
|
||||||
|
config.style = config::print_style::table;
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
|
else if(program.is_subcommand_used(link_command)){
|
||||||
// log::level = config.verbose;
|
action = action_e::link;
|
||||||
if(clipp::parse(argc, argv, cli)){
|
package_titles = get_packages_from_parser(link_command);
|
||||||
log::level = config.verbose;
|
set_if_used(link_command, params.paths, "path");
|
||||||
switch(action){
|
}
|
||||||
case action_e::install: package::install(config, package_titles, params); break;
|
else if(program.is_subcommand_used(clone_command)){
|
||||||
case action_e::add: package::add(config, package_titles);
|
action = action_e::clone;
|
||||||
case action_e::remove: package::remove(config, package_titles, params); break;
|
package_titles = get_packages_from_parser(clone_command);
|
||||||
case action_e::update: package::update(config, package_titles, params); break;
|
set_if_used(clone_command, params.paths, "path");
|
||||||
case action_e::search: package::search(config, package_titles, params); break;
|
}
|
||||||
case action_e::p_export: package::export_to(params.args); break;
|
else if(program.is_subcommand_used(clean_command)){
|
||||||
case action_e::list: package::list(config, params); break;
|
action = action_e::clean;
|
||||||
/* ...opts are the paths here */
|
package_titles = get_packages_from_parser(clean_command);
|
||||||
case action_e::link: package::link(config, package_titles, params); break;
|
}
|
||||||
case action_e::clone: package::clone(config, package_titles, params); break;
|
else if(program.is_subcommand_used(config_command)){
|
||||||
case action_e::clean: package::clean_temporary(config, package_titles); break;
|
if(config_command.is_subcommand_used(config_get)){
|
||||||
case action_e::config_get: config::print_properties(config, params.args); break;
|
action = action_e::config_get;
|
||||||
case action_e::config_set: config::handle_config(config, package_titles, params.opts); break;
|
if(config_get.is_used("properties"))
|
||||||
case action_e::fetch: package::synchronize_database(config, package_titles); break;
|
params.args = config_get.get<string_list>("properties");
|
||||||
case action_e::sync: package::synchronize_database(config, package_titles); break;
|
|
||||||
case action_e::remote_list: remote::print_repositories(config); break;
|
|
||||||
case action_e::remote_add: remote::add_repository(config, params.args); break;
|
|
||||||
case action_e::remote_remove: remote::remove_respositories(config, params.args); break;
|
|
||||||
case action_e::ui: log::println("UI not implemented yet"); break;
|
|
||||||
case action_e::help: log::println("{}", man_page_format); break;
|
|
||||||
case action_e::version: break;
|
|
||||||
case action_e::none: /* ...here to run with no command */ break;
|
|
||||||
}
|
}
|
||||||
} else {
|
else if(config_command.is_subcommand_used(config_set)){
|
||||||
log::println("usage:\n{}", usage_lines(cli, argv[0]).str());
|
action = action_e::config_set;
|
||||||
|
if(config_set.is_used("property"))
|
||||||
|
params.args.emplace_back(config_set.get<string>("property"));
|
||||||
|
if(config_set.is_used("value"))
|
||||||
|
params.args.emplace_back(config_set.get<string>("value"));
|
||||||
|
}
|
||||||
|
// else{
|
||||||
|
// action = action_e::config_get;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
else if(program.is_subcommand_used(fetch_command)){
|
||||||
|
action = action_e::fetch;
|
||||||
|
params.remote_source = fetch_command.get("remote");
|
||||||
|
}
|
||||||
|
else if(program.is_subcommand_used(version_command)){
|
||||||
|
action = action_e::version;
|
||||||
|
}
|
||||||
|
else if(program.is_subcommand_used(remote_command)){
|
||||||
|
if(remote_command.is_subcommand_used(remote_add)){
|
||||||
|
action = action_e::remote_add;
|
||||||
|
if(remote_add.is_used("name"))
|
||||||
|
params.args.emplace_back(remote_add.get<string>("name"));
|
||||||
|
if(remote_add.is_used("url"))
|
||||||
|
params.args.emplace_back(remote_add.get<string>("url"));
|
||||||
|
for(const auto& arg: params.args){
|
||||||
|
log::println("{}: {}", params.args[0], params.args[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(remote_command.is_subcommand_used(remote_remove)){
|
||||||
|
action = action_e::remote_remove;
|
||||||
|
if(remote_remove.is_used("names"))
|
||||||
|
params.args = remote_remove.get<string_list>("names");
|
||||||
|
}
|
||||||
|
if(remote_command.is_subcommand_used(remote_list)){
|
||||||
|
action = action_e::remote_list;
|
||||||
|
string style = remote_list.get<string>("style");
|
||||||
|
if(!style.compare("list"))
|
||||||
|
config.style = config::print_style::list;
|
||||||
|
else if(!style.compare("table"))
|
||||||
|
config.style = config::print_style::table;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(program.is_subcommand_used("ui")){
|
||||||
|
action = action_e::ui;
|
||||||
|
}
|
||||||
|
else if(program.is_subcommand_used("help")){
|
||||||
|
action = action_e::help;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(action){
|
||||||
|
case action_e::install: package::install(config, package_titles, params); break;
|
||||||
|
case action_e::add: package::add(config, package_titles, params);
|
||||||
|
case action_e::remove: package::remove(config, package_titles, params); break;
|
||||||
|
case action_e::update: package::update(config, package_titles, params); break;
|
||||||
|
case action_e::search: package::search(config, package_titles, params); break;
|
||||||
|
case action_e::p_export: package::export_to(params.paths); break;
|
||||||
|
case action_e::list: package::list(config, params); break;
|
||||||
|
/* ...opts are the paths here */
|
||||||
|
case action_e::link: package::link(config, package_titles, params); break;
|
||||||
|
case action_e::clone: package::clone(config, package_titles, params); break;
|
||||||
|
case action_e::clean: package::clean_temporary(config, package_titles); break;
|
||||||
|
case action_e::config_get: config::print_properties(config, params.args); break;
|
||||||
|
case action_e::config_set: config::set_property(config, params.args[0], params.args[1]); break;
|
||||||
|
case action_e::fetch: package::synchronize_database(config, package_titles); break;
|
||||||
|
case action_e::sync: package::synchronize_database(config, package_titles); break;
|
||||||
|
case action_e::remote_list: remote::print_repositories(config); break;
|
||||||
|
case action_e::remote_add: remote::add_repository(config, params.args); break;
|
||||||
|
case action_e::remote_remove: remote::remove_respositories(config, params.args); break;
|
||||||
|
case action_e::ui: log::println("UI not implemented"); break;
|
||||||
|
case action_e::help: program.print_help(); break;
|
||||||
|
case action_e::version: break;
|
||||||
|
case action_e::none: program.usage(); break;/* ...here to run with no command */ break;
|
||||||
}
|
}
|
||||||
return error();
|
return error();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
|
|
||||||
#include "remote.hpp"
|
#include "remote.hpp"
|
||||||
|
#include "config.hpp"
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
#include <readline/readline.h>
|
#include <readline/readline.h>
|
||||||
|
#include <tabulate/table.hpp>
|
||||||
|
|
||||||
namespace gdpm::remote{
|
namespace gdpm::remote{
|
||||||
|
|
||||||
|
|
@ -12,7 +14,7 @@ namespace gdpm::remote{
|
||||||
const args_t &args
|
const args_t &args
|
||||||
){
|
){
|
||||||
/* Check if enough args were provided. */
|
/* Check if enough args were provided. */
|
||||||
log::debug("arg count: {}\nargs: {}", args.size(), utils::join(args));
|
log::println("arg count: {}\nargs: {}", args.size(), utils::join(args));
|
||||||
if (args.size() < 2){
|
if (args.size() < 2){
|
||||||
return error(
|
return error(
|
||||||
constants::error::INVALID_ARG_COUNT,
|
constants::error::INVALID_ARG_COUNT,
|
||||||
|
|
@ -31,7 +33,7 @@ namespace gdpm::remote{
|
||||||
config::context& config,
|
config::context& config,
|
||||||
const args_t& args
|
const args_t& args
|
||||||
){
|
){
|
||||||
log::debug("arg count: {}\nargs: {}", args.size(), utils::join(args));
|
log::println("arg count: {}\nargs: {}", args.size(), utils::join(args));
|
||||||
if(args.size() < 1){
|
if(args.size() < 1){
|
||||||
return error(
|
return error(
|
||||||
constants::error::INVALID_ARG_COUNT,
|
constants::error::INVALID_ARG_COUNT,
|
||||||
|
|
@ -61,8 +63,19 @@ namespace gdpm::remote{
|
||||||
|
|
||||||
void print_repositories(const config::context& config){
|
void print_repositories(const config::context& config){
|
||||||
const auto &rs = config.remote_sources;
|
const auto &rs = config.remote_sources;
|
||||||
std::for_each(rs.begin(), rs.end(), [](const string_pair& p){
|
if(config.style == config::print_style::list){
|
||||||
log::println("{}: {}", p.first, p.second);
|
std::for_each(rs.begin(), rs.end(), [](const string_pair& p){
|
||||||
});
|
log::println("{}: {}", p.first, p.second);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if(config.style == config::print_style::table){
|
||||||
|
using namespace tabulate;
|
||||||
|
Table table;
|
||||||
|
table.add_row({"Name", "URL"});
|
||||||
|
std::for_each(rs.begin(), rs.end(), [&table](const string_pair& p){
|
||||||
|
table.add_row({p.first, p.second});
|
||||||
|
});
|
||||||
|
table.print(std::cout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -17,7 +17,9 @@
|
||||||
namespace gdpm::rest_api{
|
namespace gdpm::rest_api{
|
||||||
|
|
||||||
request_params make_from_config(const config::context& config){
|
request_params make_from_config(const config::context& config){
|
||||||
return config.rest_api_params;
|
request_params rp = config.rest_api_params;
|
||||||
|
rp.verbose = config.verbose;
|
||||||
|
return rp;
|
||||||
}
|
}
|
||||||
|
|
||||||
request_params make_request_params(
|
request_params make_request_params(
|
||||||
|
|
@ -212,7 +214,7 @@ namespace gdpm::rest_api{
|
||||||
http_params.headers.insert(http::header("Connection", "keep-alive"));
|
http_params.headers.insert(http::header("Connection", "keep-alive"));
|
||||||
string request_url = _prepare_request(url, c);
|
string request_url = _prepare_request(url, c);
|
||||||
http::response r = http.request_get(request_url, http_params);
|
http::response r = http.request_get(request_url, http_params);
|
||||||
if(c.verbose > 0)
|
if(c.verbose >= log::INFO)
|
||||||
log::info("get_asset().URL: {}", request_url);
|
log::info("get_asset().URL: {}", request_url);
|
||||||
return _parse_json(r.body, c.verbose);
|
return _parse_json(r.body, c.verbose);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -186,24 +186,24 @@ namespace gdpm::utils{
|
||||||
int verbose
|
int verbose
|
||||||
){
|
){
|
||||||
constexpr const char *prog = "gpdm";
|
constexpr const char *prog = "gpdm";
|
||||||
struct zip *za;
|
struct zip *zip;
|
||||||
struct zip_file *zf;
|
struct zip_file *zf;
|
||||||
struct zip_stat sb;
|
struct zip_stat sb;
|
||||||
char buf[100];
|
char buf[100];
|
||||||
int err;
|
int err;
|
||||||
int i, len, fd;
|
int i, len, fd;
|
||||||
zip_uint64_t sum;
|
zip_uint64_t sum;
|
||||||
|
|
||||||
// log::info_n("Extracting package contents to '{}'...", dest);
|
// log::info_n("Extracting package contents to '{}'...", dest);
|
||||||
log::info_n("Extracting package contents...");
|
log::info_n("Extracting package contents...");
|
||||||
if((za = zip_open(archive, 0, &err)) == nullptr){
|
if((zip = zip_open(archive, 0, &err)) == nullptr){
|
||||||
zip_error_to_str(buf, sizeof(buf), err, errno);
|
zip_error_to_str(buf, sizeof(buf), err, errno);
|
||||||
log::error("{}: can't open zip archive {}: {}", prog, archive, buf);
|
log::error("{}: can't open zip archive {}: {}", prog, archive, buf);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < zip_get_num_entries(za, 0); i++){
|
for(i = 0; i < zip_get_num_entries(zip, 0); i++){
|
||||||
if(zip_stat_index(za, i, 0, &sb) == 0){
|
if(zip_stat_index(zip, i, 0, &sb) == 0){
|
||||||
len = strlen(sb.name);
|
len = strlen(sb.name);
|
||||||
if(verbose > 1){
|
if(verbose > 1){
|
||||||
log::print("{}, ", sb.name);
|
log::print("{}, ", sb.name);
|
||||||
|
|
@ -215,7 +215,7 @@ namespace gdpm::utils{
|
||||||
// safe_create_dir(sb.name);
|
// safe_create_dir(sb.name);
|
||||||
std::filesystem::create_directory(path);
|
std::filesystem::create_directory(path);
|
||||||
} else {
|
} else {
|
||||||
zf = zip_fopen_index(za, i, 0);
|
zf = zip_fopen_index(zip, i, 0);
|
||||||
if(!zf){
|
if(!zf){
|
||||||
log::error("extract_zip: zip_fopen_index() failed.");
|
log::error("extract_zip: zip_fopen_index() failed.");
|
||||||
return 100;
|
return 100;
|
||||||
|
|
@ -248,7 +248,7 @@ namespace gdpm::utils{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(zip_close(za) == -1){
|
if(zip_close(zip) == -1){
|
||||||
log::error("{}: can't close zip archive '{}'", prog, archive);
|
log::error("{}: can't close zip archive '{}'", prog, archive);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ TEST_SUITE("Command functions"){
|
||||||
using namespace gdpm::package_manager;
|
using namespace gdpm::package_manager;
|
||||||
|
|
||||||
package::params params = package::params{
|
package::params params = package::params{
|
||||||
.remote_source = "test"
|
.remote_source = "test",
|
||||||
};
|
};
|
||||||
config::context config = config::context{
|
config::context config = config::context{
|
||||||
.username = "",
|
.username = "",
|
||||||
|
|
@ -33,9 +33,10 @@ TEST_SUITE("Command functions"){
|
||||||
.remote_sources = {
|
.remote_sources = {
|
||||||
{"test", "http://godotengine.org/asset-library/api"}
|
{"test", "http://godotengine.org/asset-library/api"}
|
||||||
},
|
},
|
||||||
|
.skip_prompt = true,
|
||||||
.info {
|
.info {
|
||||||
.godot_version = "latest",
|
.godot_version = "latest",
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
package::title_list package_titles{"ResolutionManagerPlugin","godot-hmac", "Godot"};
|
package::title_list package_titles{"ResolutionManagerPlugin","godot-hmac", "Godot"};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue