mirror of
https://github.com/davidallendj/gdpm.git
synced 2025-12-20 03:27:02 -07:00
Recfactored and simplified more code
- Added function to convert color string to ansi color string - Added `trim` and `join` utility functions - Added initial plugin test case - Implemented `config get` command to see config properties - Improved logging functionality and removed duplicate logging functions - Removed unused functions - Fixed more styling issues - Fixed some CLI commands not working correctly - Fixed CLI documentation format - Fixed some error handling issues
This commit is contained in:
parent
e48c54aa40
commit
02a4e879a8
21 changed files with 541 additions and 384 deletions
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
#include "cache.hpp"
|
||||
#include "error.hpp"
|
||||
#include "log.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "package.hpp"
|
||||
|
|
@ -12,7 +13,10 @@
|
|||
|
||||
|
||||
namespace gdpm::cache{
|
||||
error create_package_database(bool overwrite, const params& params){
|
||||
error create_package_database(
|
||||
bool overwrite,
|
||||
const params& params
|
||||
){
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *res;
|
||||
char *errmsg;
|
||||
|
|
@ -77,7 +81,10 @@ namespace gdpm::cache{
|
|||
}
|
||||
|
||||
|
||||
error insert_package_info(const package::info_list& packages, const params& params){
|
||||
error insert_package_info(
|
||||
const package::info_list& packages,
|
||||
const params& params
|
||||
){
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *res;
|
||||
char *errmsg = nullptr;
|
||||
|
|
@ -115,7 +122,10 @@ namespace gdpm::cache{
|
|||
}
|
||||
|
||||
|
||||
result_t<package::info_list> get_package_info_by_id(const package::id_list& package_ids, const params& params){
|
||||
result_t<package::info_list> get_package_info_by_id(
|
||||
const package::id_list& package_ids,
|
||||
const params& params
|
||||
){
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *res;
|
||||
char *errmsg = nullptr;
|
||||
|
|
@ -179,7 +189,10 @@ namespace gdpm::cache{
|
|||
}
|
||||
|
||||
|
||||
result_t<package::info_list> get_package_info_by_title(const package::title_list& package_titles, const params& params){
|
||||
result_t<package::info_list> get_package_info_by_title(
|
||||
const package::title_list& package_titles,
|
||||
const params& params
|
||||
){
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *res;
|
||||
char *errmsg = nullptr;
|
||||
|
|
@ -306,17 +319,20 @@ namespace gdpm::cache{
|
|||
}
|
||||
|
||||
|
||||
error update_package_info(const package::info_list& packages, const params& params){
|
||||
error update_package_info(
|
||||
const package::info_list& packages,
|
||||
const params& params
|
||||
){
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *res;
|
||||
char *errmsg = nullptr;
|
||||
|
||||
int rc = sqlite3_open(params.cache_path.c_str(), &db);
|
||||
if(rc != SQLITE_OK){
|
||||
error error(rc, std::format(
|
||||
error error(
|
||||
constants::error::SQLITE_ERR, std::format(
|
||||
"update_package_info.sqlite3_open(): {}", sqlite3_errmsg(db)
|
||||
));
|
||||
log::error(error);
|
||||
sqlite3_close(db);
|
||||
return error;
|
||||
}
|
||||
|
|
@ -360,7 +376,10 @@ namespace gdpm::cache{
|
|||
}
|
||||
|
||||
|
||||
error delete_packages(const package::title_list& package_titles, const params& params){
|
||||
error delete_packages(
|
||||
const package::title_list& package_titles,
|
||||
const params& params
|
||||
){
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *res;
|
||||
char *errmsg = nullptr;
|
||||
|
|
@ -395,7 +414,10 @@ namespace gdpm::cache{
|
|||
}
|
||||
|
||||
|
||||
error delete_packages(const package::id_list& package_ids, const params& params){
|
||||
error delete_packages(
|
||||
const package::id_list& package_ids,
|
||||
const params& params
|
||||
){
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *res;
|
||||
char *errmsg = nullptr;
|
||||
|
|
|
|||
|
|
@ -37,8 +37,6 @@ namespace gdpm::config{
|
|||
const context& config,
|
||||
bool pretty_print
|
||||
){
|
||||
|
||||
|
||||
/* Build a JSON string to pass to document */
|
||||
string prefix = (pretty_print) ? "\n\t" : "";
|
||||
string spaces = (pretty_print) ? " " : "";
|
||||
|
|
@ -232,6 +230,7 @@ namespace gdpm::config{
|
|||
return error();
|
||||
}
|
||||
|
||||
|
||||
context make_context(
|
||||
const string& username,
|
||||
const string& password,
|
||||
|
|
@ -286,8 +285,60 @@ namespace gdpm::config{
|
|||
return error;
|
||||
}
|
||||
|
||||
void print(const context& config){
|
||||
void print_json(const context& config){
|
||||
log::println("{}", to_json(config, true));
|
||||
}
|
||||
|
||||
void _print_property(
|
||||
const context& config,
|
||||
const string& property
|
||||
){
|
||||
if(property.empty()) return;
|
||||
else if(property == "username") log::println("username: {}", config.username);
|
||||
else if(property == "password") log::println("password: {}", config.password);
|
||||
else if(property == "path") log::println("path: {}", config.path);
|
||||
else if(property == "token") log::println("token: {}", config.token);
|
||||
else if(property == "packages_dir") log::println("package directory: {}", config.packages_dir);
|
||||
else if(property == "tmp_dir") log::println("temporary directory: {}", config.tmp_dir);
|
||||
else if(property == "remote_sources") log::println("remote sources: \n{}", utils::join(config.remote_sources, "\t", "\n"));
|
||||
else if(property == "jobs") log::println("parallel jobs: {}", config.jobs);
|
||||
else if(property == "timeout") log::println("timeout: {}", config.timeout);
|
||||
else if(property == "sync") log::println("enable sync: {}", config.enable_sync);
|
||||
else if(property == "cache") log::println("enable cache: {}", config.enable_cache);
|
||||
else if(property == "prompt") log::println("skip prompt: {}", config.skip_prompt);
|
||||
else if(property == "logging") log::println("enable file logging: {}", config.enable_file_logging);
|
||||
else if(property == "clean") log::println("clean temporary files: {}", config.clean_temporary);
|
||||
else if(property == "verbose") log::println("verbose: {}", config.verbose);
|
||||
}
|
||||
|
||||
void print_properties(
|
||||
const context& config,
|
||||
const string_list& properties
|
||||
){
|
||||
if(properties.empty()){
|
||||
_print_property(config, "username");
|
||||
_print_property(config, "password");
|
||||
_print_property(config, "path");
|
||||
_print_property(config, "token");
|
||||
_print_property(config, "packages_dir");
|
||||
_print_property(config, "tmp_dir");
|
||||
_print_property(config, "remote_sources");
|
||||
_print_property(config, "jobs");
|
||||
_print_property(config, "timeout");
|
||||
_print_property(config, "sync");
|
||||
_print_property(config, "cache");
|
||||
_print_property(config, "prompt");
|
||||
_print_property(config, "logging");
|
||||
_print_property(config, "clean");
|
||||
_print_property(config, "verbose");
|
||||
}
|
||||
std::for_each(
|
||||
properties.begin(),
|
||||
properties.end(),
|
||||
[&config](const string& property){
|
||||
_print_property(config, property);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
#include "config.hpp"
|
||||
#include "package_manager.hpp"
|
||||
#include "result.hpp"
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
int main(int argc, char **argv){
|
||||
|
|
@ -13,6 +14,7 @@ int main(int argc, char **argv){
|
|||
|
||||
error error = initialize(argc, argv);
|
||||
parse_arguments(argc, argv);
|
||||
finalize();
|
||||
return 0;
|
||||
finalize();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
118
src/package.cpp
118
src/package.cpp
|
|
@ -8,6 +8,8 @@
|
|||
#include "http.hpp"
|
||||
#include "remote.hpp"
|
||||
#include "types.hpp"
|
||||
#include "utils.hpp"
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <rapidjson/ostreamwrapper.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
|
|
@ -31,6 +33,7 @@ namespace gdpm::package{
|
|||
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);
|
||||
|
|
@ -167,7 +170,7 @@ namespace gdpm::package{
|
|||
log::println("Done.");
|
||||
}else{
|
||||
error error(
|
||||
constants::error::HTTP_RESPONSE_ERROR,
|
||||
constants::error::HTTP_RESPONSE_ERR,
|
||||
std::format("HTTP Error: {}", response.code)
|
||||
);
|
||||
log::error(error);
|
||||
|
|
@ -186,7 +189,12 @@ namespace gdpm::package{
|
|||
|
||||
/* Update the cache data with information from */
|
||||
log::info_n("Updating local asset data...");
|
||||
cache::update_package_info(p_found);
|
||||
error error = cache::update_package_info(p_found);
|
||||
if(error()){
|
||||
log::error(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
log::println("done.");
|
||||
// })
|
||||
// );
|
||||
|
|
@ -201,7 +209,8 @@ namespace gdpm::package{
|
|||
const title_list& package_titles,
|
||||
const params& params
|
||||
){
|
||||
|
||||
/* Install packages in local project instead of package database.
|
||||
This will not cache the package information in the cache database. */
|
||||
return error();
|
||||
}
|
||||
|
||||
|
|
@ -289,7 +298,13 @@ namespace gdpm::package{
|
|||
}
|
||||
log::println("Done.");
|
||||
log::info_n("Updating local asset data...");
|
||||
cache::update_package_info(p_cache);
|
||||
{
|
||||
error error = cache::update_package_info(p_cache);
|
||||
if(error.has_occurred()){
|
||||
log::error(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
log::println("done.");
|
||||
|
||||
return error();
|
||||
|
|
@ -402,7 +417,7 @@ namespace gdpm::package{
|
|||
return error;
|
||||
}
|
||||
|
||||
log::info("{} package(s) found...", doc["total_items"].GetInt());
|
||||
// log::info("{} package(s) found...", doc["total_items"].GetInt());
|
||||
print_list(doc);
|
||||
}
|
||||
return error();
|
||||
|
|
@ -416,16 +431,13 @@ namespace gdpm::package{
|
|||
using namespace rapidjson;
|
||||
using namespace std::filesystem;
|
||||
|
||||
string show((!params.sub_commands.empty()) ? params.sub_commands[0] : "");
|
||||
string show((!params.args.empty()) ? params.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()){
|
||||
print_list(p_installed);
|
||||
}
|
||||
else{
|
||||
log::println("empty");
|
||||
}
|
||||
}
|
||||
else if(show == "remote"){
|
||||
remote::print_repositories(config);
|
||||
|
|
@ -476,30 +488,27 @@ namespace gdpm::package{
|
|||
error link(
|
||||
const config::context& config,
|
||||
const title_list& package_titles,
|
||||
const package::params& params
|
||||
const package::params& params /* path is last arg */
|
||||
){
|
||||
using namespace std::filesystem;
|
||||
|
||||
path_list paths = {};
|
||||
if(params.opts.contains("path")){
|
||||
paths = get<path_list>(params.opts.at("path"));
|
||||
}
|
||||
|
||||
if(paths.empty()){
|
||||
if(params.args.empty()){
|
||||
error error(
|
||||
constants::error::PATH_NOT_DEFINED,
|
||||
"No path set. Use '--path' option to set a path."
|
||||
constants::error::INVALID_ARG_COUNT,
|
||||
"Must supply at least 2 arguments (package name and path)"
|
||||
);
|
||||
log::error(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Check for packages in cache to link */
|
||||
result_t r_cache = cache::get_package_info_by_title(package_titles);
|
||||
info_list p_found = {};
|
||||
info_list p_cache = r_cache.unwrap_unsafe();
|
||||
if(p_cache.empty()){
|
||||
error error(
|
||||
constants::error::NOT_FOUND,
|
||||
"Could not find any packages to link."
|
||||
"Could not find any packages to link in cache."
|
||||
);
|
||||
log::error(error);
|
||||
return error;
|
||||
|
|
@ -522,20 +531,22 @@ namespace gdpm::package{
|
|||
}
|
||||
|
||||
/* 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};
|
||||
for(const auto& p : p_found){
|
||||
for(const auto& path : paths){
|
||||
log::info_n("Creating symlink for \"{}\" package to '{}'...", p.title, path + "/" + p.title);
|
||||
const string _path = path;
|
||||
log::info_n("link: \"{}\" -> '{}'...", p.title, _path + "/" + 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 symlink_path{path + "/" + p.title};
|
||||
std::filesystem::path symlink_path{_path + "/" + p.title};
|
||||
if(!std::filesystem::exists(symlink_path.string()))
|
||||
std::filesystem::create_directories(path + "/");
|
||||
std::filesystem::create_directories(_path + "/");
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directory_symlink(target, symlink_path, ec);
|
||||
if(ec){
|
||||
error error(
|
||||
constants::error::STD_ERROR,
|
||||
constants::error::STD_ERR,
|
||||
std::format("Could not create symlink: {}", ec.message())
|
||||
);
|
||||
log::error(error);
|
||||
|
|
@ -554,10 +565,10 @@ namespace gdpm::package{
|
|||
){
|
||||
using namespace std::filesystem;
|
||||
|
||||
if(params.opts.empty()){
|
||||
if(params.args.empty()){
|
||||
error error(
|
||||
constants::error::PATH_NOT_DEFINED,
|
||||
"No path set. Use '--path' option to set a path."
|
||||
constants::error::INVALID_ARG_COUNT,
|
||||
"Must supply at least 2 arguments (package name and path)"
|
||||
);
|
||||
log::error(error);
|
||||
return error;
|
||||
|
|
@ -565,18 +576,25 @@ namespace gdpm::package{
|
|||
|
||||
result_t r_cache = cache::get_package_info_by_title(package_titles);
|
||||
package::info_list p_found = {};
|
||||
package::info_list p_cache = r_cache.unwrap_unsafe();
|
||||
package::info_list p_cache = r_cache.unwrap_unsafe();
|
||||
|
||||
/* Check for installed packages to clone */
|
||||
if(p_cache.empty()){
|
||||
error error(
|
||||
constants::error::NO_PACKAGE_FOUND,
|
||||
"Could not find any packages to clone."
|
||||
"Could not find any packages to clone in cache."
|
||||
);
|
||||
log::error(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
for(const auto& p_title : package_titles){
|
||||
auto found = std::find_if(p_cache.begin(), p_cache.end(), [&p_title](const package::info& p){ return p.title == p_title; });
|
||||
auto found = std::find_if(
|
||||
p_cache.begin(),
|
||||
p_cache.end(),
|
||||
[&p_title](const package::info& p){
|
||||
return p.title == p_title;
|
||||
});
|
||||
if(found != p_cache.end()){
|
||||
p_found.emplace_back(*found);
|
||||
}
|
||||
|
|
@ -592,15 +610,17 @@ namespace gdpm::package{
|
|||
}
|
||||
|
||||
/* Get the storage paths for all packages to create clones */
|
||||
path_list paths = get<path_list>(params.opts.at("--path"));
|
||||
path_refs paths = path_refs{params.args.back()};
|
||||
// path_list paths = path_list({params.args.back()});
|
||||
const path package_dir{config.packages_dir};
|
||||
for(const auto& p : p_found){
|
||||
for(const auto& path : paths){
|
||||
log::info("Cloning \"{}\" package to {}", p.title, path + "/" + p.title);
|
||||
const string _path = string(path);
|
||||
log::info("clone: \"{}\" -> {}", p.title, _path + "/" + p.title);
|
||||
std::filesystem::path from{config.packages_dir + "/" + p.title};
|
||||
std::filesystem::path to{path + "/" + p.title};
|
||||
std::filesystem::path to{_path + "/" + p.title};
|
||||
if(!std::filesystem::exists(to.string()))
|
||||
std::filesystem::create_directories(to);
|
||||
std::filesystem::create_directories(to); /* This should only occur if using a --force flag */
|
||||
|
||||
/* TODO: Add an option to force overwriting (i.e. --overwrite) */
|
||||
std::filesystem::copy(from, to, copy_options::update_existing | copy_options::recursive);
|
||||
|
|
@ -609,19 +629,23 @@ namespace gdpm::package{
|
|||
return error();
|
||||
}
|
||||
|
||||
|
||||
void print_list(const info_list& packages){
|
||||
for(const auto& p : packages){
|
||||
log::println("{}/{}/{} {} id={}\n\tGodot {}, {}, {}, Last Modified: {}",
|
||||
log::println(
|
||||
GDPM_COLOR_BLUE"{}/"
|
||||
GDPM_COLOR_RESET "{}/{}/{} "
|
||||
GDPM_COLOR_GREEN "v{} "
|
||||
GDPM_COLOR_CYAN "{} "
|
||||
GDPM_COLOR_RESET "Godot {}, {}",
|
||||
p.support_level,
|
||||
p.category,
|
||||
p.author,
|
||||
p.title,
|
||||
p.version,
|
||||
p.asset_id,
|
||||
p.modify_date,
|
||||
// p.asset_id,
|
||||
p.godot_version,
|
||||
p.cost,
|
||||
p.category,
|
||||
p.modify_date
|
||||
p.cost
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -629,16 +653,22 @@ namespace gdpm::package{
|
|||
|
||||
void print_list(const rapidjson::Document& json){
|
||||
for(const auto& o : json["result"].GetArray()){
|
||||
log::println("{}/{}/{} {} id={}\n\tGodot {}, {}, {}, Last Modified: {}",
|
||||
log::println(
|
||||
GDPM_COLOR_BLUE"{}/"
|
||||
GDPM_COLOR_CYAN "{}/"
|
||||
GDPM_COLOR_RESET "{}/{} "
|
||||
GDPM_COLOR_GREEN "v{} "
|
||||
GDPM_COLOR_CYAN "{} "
|
||||
GDPM_COLOR_RESET "Godot {}, {}",
|
||||
o["support_level"] .GetString(),
|
||||
utils::to_lower(o["category"].GetString()),
|
||||
o["author"] .GetString(),
|
||||
o["title"] .GetString(),
|
||||
o["version_string"] .GetString(),
|
||||
o["asset_id"] .GetString(),
|
||||
o["modify_date"] .GetString(),
|
||||
// o["asset_id"] .GetString(),
|
||||
o["godot_version"] .GetString(),
|
||||
o["cost"] .GetString(),
|
||||
o["category"] .GetString(),
|
||||
o["modify_date"] .GetString()
|
||||
o["cost"] .GetString()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,18 +36,16 @@
|
|||
*/
|
||||
|
||||
namespace gdpm::package_manager{
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
config::context config;
|
||||
remote::repository_map remote_sources;
|
||||
action_e action;
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
config::context config;
|
||||
action_e action;
|
||||
|
||||
// opts_t opts;
|
||||
bool skip_prompt = false;
|
||||
bool clean_tmp_dir = false;
|
||||
int priority = -1;
|
||||
|
||||
|
||||
error initialize(int argc, char **argv){
|
||||
// curl_global_init(CURL_GLOBAL_ALL);
|
||||
curl = curl_easy_init();
|
||||
|
|
@ -83,166 +81,178 @@ namespace gdpm::package_manager{
|
|||
|
||||
|
||||
error parse_arguments(int argc, char **argv){
|
||||
using namespace clipp;
|
||||
|
||||
/* Replace cxxopts with clipp */
|
||||
action_e action = action_e::none;
|
||||
package::title_list package_titles;
|
||||
string_list input;
|
||||
package::params params;
|
||||
args_t args;
|
||||
var_opts opts;
|
||||
|
||||
auto doc_format = clipp::doc_formatting{}
|
||||
.first_column(7)
|
||||
.doc_column(45)
|
||||
.last_column(99);
|
||||
|
||||
/* Set global options */
|
||||
auto configOpt = clipp::option("--config-path").set(config.path)% "set config path";
|
||||
auto fileOpt = clipp::option("--file", "-f").set(input) % "read file as input";
|
||||
auto pathOpt = clipp::option("--path").set(params.paths) % "specify a path to use with command";
|
||||
auto typeOpt = clipp::option("--type").set(config.info.type) % "set package type (any|addon|project)";
|
||||
auto sortOpt = clipp::option("--sort").set(config.api_params.sort) % "sort packages in order (rating|cost|name|updated)";
|
||||
auto supportOpt = clipp::option("--support").set(config.api_params.support) % "set the support level for API (all|official|community|testing)";
|
||||
auto maxResultsOpt = clipp::option("--max-results").set(config.api_params.max_results) % "set the request max results";
|
||||
auto godotVersionOpt = clipp::option("--godot-version").set(config.api_params.godot_version) % "set the request Godot version";
|
||||
auto packageDirOpt = clipp::option("--package-dir").set(config.packages_dir) % "set the global package location";
|
||||
auto tmpDirOpt = clipp::option("--tmp-dir").set(config.tmp_dir) % "set the temporary download location";
|
||||
auto timeoutOpt = clipp::option("--timeout").set(config.timeout) % "set the request timeout";
|
||||
auto verboseOpt = clipp::option("--verbose", "-v").set(config.verbose) % "show verbose output";
|
||||
auto debugOpt = option("-d", "--debug").set(config.verbose, to_int(log::DEBUG)) % "show debug output";
|
||||
auto configOpt = option("--config-path").set(config.path) % "set config path";
|
||||
auto fileOpt = repeatable(option("--file", "-f").set(params.args) % "read file as input");
|
||||
auto pathOpt = option("--path").set(params.paths) % "specify a path to use with command";
|
||||
auto typeOpt = option("--type").set(config.info.type) % "set package type (any|addon|project)";
|
||||
auto sortOpt = option("--sort").set(config.api_params.sort) % "sort packages in order (rating|cost|name|updated)";
|
||||
auto supportOpt = option("--support").set(config.api_params.support) % "set the support level for API (all|official|community|testing)";
|
||||
auto maxResultsOpt = option("--max-results").set(config.api_params.max_results) % "set the request max results";
|
||||
auto godotVersionOpt = option("--godot-version").set(config.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 = repeatable(option("-v", "--verbose", "-v").call([]{ config.verbose += 1; })) % "show verbose output";
|
||||
|
||||
/* Set the options */
|
||||
auto cleanOpt = clipp::option("--clean").set(config.clean_temporary) % "enable/disable cleaning temps";
|
||||
auto parallelOpt = clipp::option("--jobs").set(config.jobs) % "set number of parallel jobs";
|
||||
auto cacheOpt = clipp::option("--enable-cache").set(config.enable_cache) % "enable/disable local caching";
|
||||
auto syncOpt = clipp::option("--enable-sync").set(config.enable_sync) % "enable/disable remote syncing";
|
||||
auto skipOpt = clipp::option("--skip-prompt").set(config.skip_prompt) % "skip the y/n prompt";
|
||||
auto remoteOpt = clipp::option("--remote").set(params.remote_source) % "set remote source to use";
|
||||
auto cleanOpt = option("--clean").set(config.clean_temporary) % "enable/disable cleaning temps";
|
||||
auto parallelOpt = option("--jobs").set(config.jobs) % "set number of parallel jobs";
|
||||
auto cacheOpt = option("--enable-cache").set(config.enable_cache) % "enable/disable local caching";
|
||||
auto syncOpt = option("--enable-sync").set(config.enable_sync) % "enable/disable remote syncing";
|
||||
auto skipOpt = option("--skip-prompt").set(config.skip_prompt) % "skip the y/n prompt";
|
||||
auto remoteOpt = option("--remote").set(params.remote_source) % "set remote source to use";
|
||||
|
||||
auto packageValues = clipp::values("packages", package_titles);
|
||||
auto requiredPath = clipp::required("--path", input);
|
||||
|
||||
auto installCmd = (
|
||||
clipp::command("install")
|
||||
.set(action, action_e::install)
|
||||
.doc("Install packages from asset library"),
|
||||
clipp::values("packages", package_titles),
|
||||
clipp::option("--godot-version") & clipp::value("version", config.info.godot_version),
|
||||
cleanOpt, parallelOpt, syncOpt, skipOpt, remoteOpt
|
||||
auto packageValues = values("packages", package_titles);
|
||||
auto requiredPath = required("--path", params.args);
|
||||
|
||||
auto installCmd = "install" % (
|
||||
command("install").set(action, action_e::install),
|
||||
packageValues % "packages to install from asset library",
|
||||
godotVersionOpt, cleanOpt, parallelOpt, syncOpt, skipOpt, remoteOpt
|
||||
);
|
||||
auto addCmd = (
|
||||
clipp::command("add").set(action, action_e::add)
|
||||
.doc("Add a package to a local project"),
|
||||
packageValues
|
||||
auto addCmd = "add" % (
|
||||
command("add").set(action, action_e::add),
|
||||
packageValues % "package(s) to add to local project",
|
||||
parallelOpt, skipOpt, remoteOpt
|
||||
);
|
||||
auto removeCmd = (
|
||||
clipp::command("remove")
|
||||
.set(action, action_e::remove)
|
||||
.doc("Remove a package from local project"),
|
||||
packageValues
|
||||
auto removeCmd = "remove" % (
|
||||
command("remove").set(action, action_e::remove),
|
||||
packageValues % "package(s) to remove from local project"
|
||||
);
|
||||
auto updateCmd = (
|
||||
clipp::command("update")
|
||||
.set(action, action_e::update)
|
||||
.doc("Update package(s)"),
|
||||
packageValues
|
||||
auto updateCmd = "update" % (
|
||||
command("update").set(action, action_e::update),
|
||||
packageValues % "update package(s)"
|
||||
);
|
||||
auto searchCmd = (
|
||||
clipp::command("search")
|
||||
.set(action, action_e::search)
|
||||
.doc("Search for package(s)"),
|
||||
packageValues
|
||||
auto searchCmd = "search" % (
|
||||
command("search").set(action, action_e::search),
|
||||
packageValues % "package(s) to search for"
|
||||
);
|
||||
auto exportCmd = (
|
||||
clipp::command("export")
|
||||
.set(action, action_e::p_export)
|
||||
.doc("Export package list"),
|
||||
clipp::values("path", input)
|
||||
auto exportCmd = "export" % (
|
||||
command("export").set(action, action_e::p_export),
|
||||
values("paths", params.args) % "export installed package list to file"
|
||||
);
|
||||
auto listCmd = (
|
||||
clipp::command("list")
|
||||
.set(action, action_e::list)
|
||||
.doc("Show installed packages")
|
||||
auto listCmd = "show installed packages" % (
|
||||
command("list").set(action, action_e::list)
|
||||
);
|
||||
auto linkCmd = (
|
||||
clipp::command("link")
|
||||
.set(action, action_e::link)
|
||||
.doc("Create symlink packages to project"),
|
||||
packageValues,
|
||||
requiredPath
|
||||
auto linkCmd = "link" % (
|
||||
command("link").set(action, action_e::link),
|
||||
value("package", package_titles) % "package name to link",
|
||||
value("path", params.args) % "path to project"
|
||||
);
|
||||
auto cloneCmd = (
|
||||
clipp::command("clone")
|
||||
.set(action, action_e::clone)
|
||||
.doc("Clone packages to project"),
|
||||
packageValues,
|
||||
requiredPath
|
||||
auto cloneCmd = "clone" % (
|
||||
command("clone").set(action, action_e::clone),
|
||||
value("package", package_titles) % "packages to clone",
|
||||
value("path", params.args) % "path to project"
|
||||
);
|
||||
auto cleanCmd = (
|
||||
clipp::command("clean")
|
||||
.set(action, action_e::clean)
|
||||
.doc("Clean temporary files"),
|
||||
packageValues
|
||||
auto cleanCmd = "clean" % (
|
||||
command("clean").set(action, action_e::clean),
|
||||
values("packages", package_titles) % "package temporary files to remove"
|
||||
);
|
||||
auto configCmd = (
|
||||
clipp::command("config")
|
||||
.set(action, action_e::config)
|
||||
.doc("Set/get config properties")
|
||||
auto configCmd = "get/set 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([]{}) % "config property",
|
||||
value("value", params.args[2]).call([]{}) % "config value"
|
||||
)
|
||||
)
|
||||
);
|
||||
auto fetchCmd = (
|
||||
clipp::command("fetch")
|
||||
.set(action, action_e::fetch)
|
||||
.doc("Fetch asset metadata from remote source")
|
||||
auto fetchCmd = "fetch" % (
|
||||
command("fetch").set(action, action_e::fetch),
|
||||
option(values("remote", params.args)) % "remote to fetch asset data"
|
||||
);
|
||||
auto add_arg = [¶ms](string arg) { params.args.emplace_back(arg); };
|
||||
auto remoteCmd = (
|
||||
clipp::command("remote")
|
||||
.set(action, action_e::remote)
|
||||
.doc("Manage remote sources")
|
||||
.required("subcommand")
|
||||
command("remote").set(action, action_e::remote_list).if_missing(
|
||||
[]{
|
||||
remote::print_repositories(config);
|
||||
}
|
||||
),
|
||||
(
|
||||
"add a remote source" % ( command("add").set(action, action_e::remote_add),
|
||||
word("name").call(add_arg) % "remote name",
|
||||
value("url").call(add_arg) % "remote URL"
|
||||
)
|
||||
|
|
||||
"remove a remote source" % ( command("remove").set(action, action_e::remote_remove),
|
||||
words("names", params.args) % "remote name(s)"
|
||||
)
|
||||
|
|
||||
"list remote sources" % ( command("list").set(action, action_e::remote_list))
|
||||
)
|
||||
);
|
||||
auto uiCmd = (
|
||||
clipp::command("ui")
|
||||
.set(action, action_e::ui)
|
||||
.doc("Show the UI")
|
||||
auto uiCmd = "start with UI" % (
|
||||
command("ui").set(action, action_e::ui)
|
||||
);
|
||||
auto helpCmd = (
|
||||
clipp::command("help")
|
||||
.set(action, action_e::help)
|
||||
auto helpCmd = "show this message and exit" % (
|
||||
command("help").set(action, action_e::help)
|
||||
);
|
||||
|
||||
auto cli = (
|
||||
debugOpt, configOpt,
|
||||
(installCmd | addCmd | removeCmd | updateCmd | searchCmd | exportCmd |
|
||||
listCmd | linkCmd | cloneCmd | cleanCmd | configCmd | fetchCmd |
|
||||
remoteCmd | uiCmd | helpCmd)
|
||||
);
|
||||
|
||||
/* Make help output */
|
||||
string map_page_format("");
|
||||
auto man_page = clipp::make_man_page(cli);
|
||||
string man_page_format("");
|
||||
auto man_page = make_man_page(cli, argv[0], doc_format)
|
||||
.prepend_section("DESCRIPTION", "\tManage Godot Game Engine assets from the command-line.")
|
||||
.append_section("LICENSE", "\tSee the 'LICENSE.md' file for more details.");
|
||||
std::for_each(man_page.begin(), man_page.end(),
|
||||
[&map_page_format](const clipp::man_page::section& s){
|
||||
map_page_format += s.title() + "\n";
|
||||
map_page_format += s.content() + "\n";
|
||||
[&man_page_format](const man_page::section& s){
|
||||
man_page_format += s.title() + "\n";
|
||||
man_page_format += s.content() + "\n\n";
|
||||
}
|
||||
);
|
||||
|
||||
// log::level = config.verbose;
|
||||
if(clipp::parse(argc, argv, cli)){
|
||||
log::level = config.verbose;
|
||||
switch(action){
|
||||
case action_e::install: package::install(config, package_titles, params); break;
|
||||
case action_e::add: break;
|
||||
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(input); 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: config::handle_config(config, package_titles, opts); 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: remote::handle_remote(config, args, opts); break;
|
||||
case action_e::ui: log::info("ui not implemented yet"); break;
|
||||
case action_e::help: log::println("{}", map_page_format); break;
|
||||
case action_e::none: /* ...here to run with no command */ break;
|
||||
case action_e::install: package::install(config, package_titles, params); break;
|
||||
case action_e::add: package::add(config, package_titles);
|
||||
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.args); 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::handle_config(config, package_titles, params.opts); 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 yet"); break;
|
||||
case action_e::help: log::println("{}", man_page_format); break;
|
||||
case action_e::none: /* ...here to run with no command */ break;
|
||||
}
|
||||
} else {
|
||||
log::println("{}", map_page_format);
|
||||
log::println("usage:\n{}", usage_lines(cli, argv[0]).str());
|
||||
}
|
||||
return error();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,88 +6,48 @@
|
|||
#include <readline/readline.h>
|
||||
|
||||
namespace gdpm::remote{
|
||||
error handle_remote(
|
||||
config::context& config,
|
||||
const args_t& args,
|
||||
const var_opts& opts
|
||||
|
||||
error add_repository(
|
||||
config::context &config,
|
||||
const args_t &args
|
||||
){
|
||||
/* Check if enough arguments are supplied */
|
||||
size_t argc = args.size();
|
||||
if (argc < 1){
|
||||
print_repositories(config);
|
||||
return error();
|
||||
/* Check if enough args were provided. */
|
||||
log::debug("arg count: {}\nargs: {}", args.size(), utils::join(args));
|
||||
if (args.size() < 2){
|
||||
return error(
|
||||
constants::error::INVALID_ARG_COUNT,
|
||||
"Requires a remote name and url argument"
|
||||
);
|
||||
}
|
||||
|
||||
/* Check which subcommand is supplied */
|
||||
string sub_command = args.front();
|
||||
if(sub_command == "add"){
|
||||
if(args.size() < 3 || args.empty()){
|
||||
error error(
|
||||
constants::error::INVALID_ARG_COUNT,
|
||||
"Invalid number of args."
|
||||
);
|
||||
log::error(error);
|
||||
return error;
|
||||
}
|
||||
string name = args[1];
|
||||
string url = args[2];
|
||||
add_repositories(config, {{name, url}});
|
||||
}
|
||||
else if (sub_command == "remove") {
|
||||
if(args.size() < 2 || args.empty()){
|
||||
error error(
|
||||
constants::error::INVALID_ARG_COUNT,
|
||||
"Invalid number of args."
|
||||
);
|
||||
log::error(error);
|
||||
return error;
|
||||
}
|
||||
remove_respositories(config, {args.begin()+1, args.end()});
|
||||
}
|
||||
// else if (sub_command == "set") set_repositories(config::context &context, const repository_map &repos)
|
||||
else if (sub_command == "list") print_repositories(config);
|
||||
else{
|
||||
error error(
|
||||
constants::error::UNKNOWN,
|
||||
"Unknown sub-command. Try 'gdpm help remote' for options."
|
||||
);
|
||||
log::error(error);
|
||||
return error;
|
||||
}
|
||||
/* Get the first two args */
|
||||
log::println("{}", args[0]);
|
||||
config.remote_sources.insert({args[0], args[1]});
|
||||
return error();
|
||||
}
|
||||
|
||||
|
||||
void set_repositories(
|
||||
|
||||
error remove_respositories(
|
||||
config::context& config,
|
||||
const repository_map &repos
|
||||
const args_t& args
|
||||
){
|
||||
config.remote_sources = repos;
|
||||
}
|
||||
log::debug("arg count: {}\nargs: {}", args.size(), utils::join(args));
|
||||
if(args.size() < 1){
|
||||
return error(
|
||||
constants::error::INVALID_ARG_COUNT,
|
||||
"Requires at least one remote name argument"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void add_repositories(
|
||||
config::context& config,
|
||||
const repository_map &repos
|
||||
){
|
||||
std::for_each(repos.begin(), repos.end(),
|
||||
[&config](const string_pair& p){
|
||||
config.remote_sources.insert(p);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void remove_respositories(
|
||||
config::context& config,
|
||||
const repo_names& names
|
||||
){
|
||||
for(auto it = names.begin(); it != names.end();){
|
||||
for(auto it = args.begin(); it != args.end();){
|
||||
if(config.remote_sources.contains(*it)){
|
||||
log::println("{}", *it);
|
||||
config.remote_sources.erase(*it);
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
return error();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
#include "utils.hpp"
|
||||
#include "config.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
|
||||
|
|
@ -13,9 +14,12 @@
|
|||
#include <fcntl.h>
|
||||
#include <rapidjson/ostreamwrapper.h>
|
||||
#include <rapidjson/writer.h>
|
||||
#include <readline/chardefs.h>
|
||||
#include <readline/readline.h>
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <zip.h>
|
||||
|
||||
namespace gdpm::utils{
|
||||
|
|
@ -53,8 +57,38 @@ namespace gdpm::utils{
|
|||
}
|
||||
#endif
|
||||
|
||||
void to_lower(std::string& s){
|
||||
std::transform(s.begin(), s.end(), s.begin(), tolower);
|
||||
std::string to_lower(const std::string& s){
|
||||
std::string copy = s;
|
||||
std::transform(copy.begin(), copy.end(), copy.begin(), tolower);
|
||||
return copy;
|
||||
}
|
||||
|
||||
std::string trim(const std::string& s){
|
||||
return trim_right(trim_left(s));
|
||||
}
|
||||
|
||||
std::string trim_left(const std::string& s){
|
||||
return trim_left(s, constants::WHITESPACE);
|
||||
}
|
||||
|
||||
std::string trim_left(
|
||||
const std::string& s,
|
||||
const std::string& ref
|
||||
){
|
||||
size_t start = s.find_first_not_of(ref);
|
||||
return (start == std::string::npos) ? "" : s.substr(start);
|
||||
}
|
||||
|
||||
std::string trim_right(const std::string& s){
|
||||
return trim_right(s, constants::WHITESPACE);
|
||||
}
|
||||
|
||||
std::string trim_right(
|
||||
const std::string& s,
|
||||
const std::string& ref
|
||||
){
|
||||
size_t end = s.find_last_not_of(ref);
|
||||
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
|
||||
}
|
||||
|
||||
std::vector<std::string> parse_lines(const std::string &s){
|
||||
|
|
@ -97,7 +131,7 @@ namespace gdpm::utils{
|
|||
const char *dest,
|
||||
int verbose
|
||||
){
|
||||
const char *prog = "gpdm";
|
||||
constexpr const char *prog = "gpdm";
|
||||
struct zip *za;
|
||||
struct zip_file *zf;
|
||||
struct zip_stat sb;
|
||||
|
|
@ -198,9 +232,31 @@ namespace gdpm::utils{
|
|||
const std::string& delimiter
|
||||
){
|
||||
std::string o;
|
||||
std::for_each(target.begin(), target.end(), [&o, &delimiter](const std::string& s){
|
||||
o += s + delimiter;
|
||||
});
|
||||
std::for_each(
|
||||
target.begin(),
|
||||
target.end(),
|
||||
[&o, &delimiter](const std::string& s){
|
||||
o += s + delimiter;
|
||||
}
|
||||
);
|
||||
o = trim_right(o, delimiter);
|
||||
return o;
|
||||
}
|
||||
|
||||
std::string join(
|
||||
const std::unordered_map<std::string, std::string>& target,
|
||||
const std::string& prefix,
|
||||
const std::string& delimiter
|
||||
){
|
||||
std::string o;
|
||||
std::for_each(
|
||||
target.begin(),
|
||||
target.end(),
|
||||
[&o, &prefix, &delimiter](const std::pair<std::string, std::string>& p){
|
||||
o += prefix + p.first + ": " + p.second + delimiter;
|
||||
}
|
||||
);
|
||||
o = trim_right(o, delimiter);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue