Fixed minor issues

- Fixed error message formatting
- Fixed setting verbosity levels
- Fixed implementation of `replace_first` and `replace_all`
- Fixed issue where installing a package would failed because of unescaped single quotes in SQL statement
- Fixed error code returned from SQLITE related errors
- Fixed verbose flag not being repeatable and set correctly
- Fixed some error messages to correctly reflect occuring error
- Fixed the prompt asking the user twice and not taking a default input
- Added functions to get logging default prefixes
- Added `version` command (not implemented yet)
This commit is contained in:
David Allen 2023-06-18 21:10:50 -06:00
parent 02a4e879a8
commit c88cb08e03
9 changed files with 126 additions and 121 deletions

View file

@ -13,6 +13,10 @@
namespace gdpm::cache{
std::string _escape_sql(const std::string& s){
return utils::replace_all(s, "'", "''");
}
error create_package_database(
bool overwrite,
const params& params
@ -31,13 +35,12 @@ namespace gdpm::cache{
int rc = sqlite3_open(params.cache_path.c_str(), &db);
if(rc != SQLITE_OK){
error error(rc,
error error(constants::error::SQLITE_ERR,
std::format(
"create_package_database.sqlite3_open(): {}",
sqlite3_errmsg(db)
)
);
log::error(error);
sqlite3_close(db);
return error;
}
@ -67,11 +70,10 @@ namespace gdpm::cache{
rc = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errmsg);
if(rc != SQLITE_OK){
// log::error("Failed to fetch data: {}\n", sqlite3_errmsg(db));
error error(rc, std::format(
error error(constants::error::SQLITE_ERR, std::format(
"create_package_database.sqlite3_exec(): {}",
errmsg
));
log::error(error);
sqlite3_free(errmsg);
sqlite3_close(db);
return error;
@ -99,11 +101,10 @@ namespace gdpm::cache{
// log::println("{}", sql);
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(
"insert_package_info.sqlite3_open(): {}",
sqlite3_errmsg(db)
));
log::error(error);
sqlite3_close(db);
return error;
}
@ -162,10 +163,9 @@ namespace gdpm::cache{
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(
"get_package_info_by_id.sqlite3_open(): {}", sqlite3_errmsg(db)
));
log::error(error);
sqlite3_close(db);
return result_t(package::info_list(), error);
}
@ -176,10 +176,9 @@ namespace gdpm::cache{
sql += "COMMIT;\n";
rc = sqlite3_exec(db, sql.c_str(), callback, (void*)&p_vector, &errmsg);
if(rc != SQLITE_OK){
error error(rc, std::format(
error error(constants::error::SQLITE_ERR, std::format(
"get_package_info_by_id.sqlite3_exec(): {}", errmsg
));
log::error("get_package_info_by_id.sqlite3_exec(): {}", errmsg);
sqlite3_free(errmsg);
sqlite3_close(db);
return result_t(package::info_list(), error);
@ -232,10 +231,9 @@ namespace gdpm::cache{
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(
"get_package_info_by_title.sqlite3_open(): {}", sqlite3_errmsg(db)
));
log::error(error);
sqlite3_close(db);
return result_t(package::info_list(), error);
}
@ -248,10 +246,9 @@ namespace gdpm::cache{
// log::println(sql);
rc = sqlite3_exec(db, sql.c_str(), callback, (void*)&p_vector, &errmsg);
if(rc != SQLITE_OK){
error error(rc, std::format(
error error(constants::error::SQLITE_ERR, std::format(
"get_package_info_by_title.sqlite3_exec(): {}", errmsg
));
log::error(error);
sqlite3_free(errmsg);
sqlite3_close(db);
return result_t(package::info_list(), error);
@ -295,10 +292,9 @@ namespace gdpm::cache{
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(
"get_installed_packages.sqlite3_open(): {}", sqlite3_errmsg(db)
));
log::error(error);
sqlite3_close(db);
return result_t(package::info_list(), error);
}
@ -339,34 +335,33 @@ namespace gdpm::cache{
string sql;
for(const auto& p : packages){
sql += "UPDATE " + params.table_name + " SET "
" asset_id=" + std::to_string(p.asset_id) + ", "
" type='" + p.type + "', "
" title='" + p.title + "', "
" author='" + p.author + "', " +
" author_id=" + std::to_string(p.author_id) + ", "
" version='" + p.version + "', " +
" godot_version='" + p.godot_version + "', " +
" cost='" + p.cost + "', " +
" description='" + p.description + "', " +
" modify_date='" + p.modify_date + "', " +
" support_level='" + p.support_level + "', " +
" category='" + p.category + "', " +
" remote_source='" + p.remote_source + "', " +
" download_url='" + p.download_url + "', " +
" download_hash='" + p.download_hash + "', " +
" is_installed=" + std::to_string(p.is_installed) + ", "
" install_path='" + p.install_path + "'"
sql += "UPDATE " + params.table_name + " SET "
" asset_id=" + std::to_string(p.asset_id) + ", "
" type='" + _escape_sql(p.type) + "', "
" title='" + _escape_sql(p.title) + "', "
" author='" + _escape_sql(p.author) + "', " +
" author_id=" + std::to_string(p.author_id) + ", "
" version='" + _escape_sql(p.version) + "', " +
" godot_version='" + _escape_sql(p.godot_version) + "', " +
" cost='" + _escape_sql(p.cost) + "', " +
" description='" + _escape_sql(p.description) + "', " +
" modify_date='" + _escape_sql(p.modify_date) + "', " +
" support_level='" + _escape_sql(p.support_level) + "', " +
" category='" + _escape_sql(p.category) + "', " +
" remote_source='" + _escape_sql(p.remote_source) + "', " +
" download_url='" + _escape_sql(p.download_url) + "', " +
" download_hash='" + _escape_sql(p.download_hash) + "', " +
" is_installed=" + std::to_string(p.is_installed) + ", "
" install_path='" + _escape_sql(p.install_path) + "'"
// " dependencies='" + p.dependencies + "'"
" WHERE title='" + p.title + "' AND asset_id=" + std::to_string(p.asset_id)
" WHERE title='" + p.title + "' AND asset_id=" + std::to_string(p.asset_id)
+ ";\n";
}
rc = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errmsg);
if(rc != SQLITE_OK){
error error(rc, std::format(
"update_package_info.sqlite3_exec(): {}", errmsg
error error(constants::error::SQLITE_ERR, std::format(
"update_package_info.sqlite3_exec(): {}\n\t{}", errmsg, sql
));
log::error(error);
sqlite3_free(errmsg);
sqlite3_close(db);
return error;
@ -387,10 +382,9 @@ namespace gdpm::cache{
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(
"delete_packages.sqlite3_open(): {}", sqlite3_errmsg(db)
));
log::error(error);
sqlite3_close(db);
return error;
}
@ -401,10 +395,9 @@ namespace gdpm::cache{
}
rc = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errmsg);
if(rc != SQLITE_OK){
error error(rc, std::format(
error error(constants::error::SQLITE_ERR, std::format(
"delete_packages.sqlite3_exec(): {}", errmsg
));
log::error(error);
sqlite3_free(errmsg);
sqlite3_close(db);
return error;
@ -425,10 +418,9 @@ namespace gdpm::cache{
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(
"delete_packages.sqlite3_open(): {}", errmsg
));
log::error(error);
sqlite3_close(db);
return error;
}
@ -439,10 +431,9 @@ namespace gdpm::cache{
}
rc = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errmsg);
if(rc != SQLITE_OK){
error error(rc, std::format(
error error(constants::error::SQLITE_ERR, std::format(
"delete_packages.sqlite3_exec(): {}", errmsg
));
log::error(error);
sqlite3_free(errmsg);
sqlite3_close(db);
return error;
@ -460,20 +451,18 @@ namespace gdpm::cache{
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(
"drop_package_database.sqlite3_open(): {}", sqlite3_errmsg(db)
));
log::error(error);
sqlite3_close(db);
return error;
}
rc = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errmsg);
if(rc != SQLITE_OK){
error error(rc, std::format(
error error(constants::error::SQLITE_ERR, std::format(
"drop_package_database.sqlite3_exec(): {}", errmsg
));
log::error(error);
sqlite3_free(errmsg);
sqlite3_close(db);
return error;

View file

@ -1,5 +1,6 @@
#include "package.hpp"
#include "colors.hpp"
#include "error.hpp"
#include "log.hpp"
#include "rest_api.hpp"
@ -11,6 +12,7 @@
#include "utils.hpp"
#include <functional>
#include <future>
#include <rapidjson/error/en.h>
#include <rapidjson/ostreamwrapper.h>
#include <rapidjson/prettywriter.h>
@ -89,7 +91,7 @@ namespace gdpm::package{
log::println("");
if(!config.skip_prompt){
if(!utils::prompt_user_yn("Do you want to install these packages? (y/n)"))
if(!utils::prompt_user_yn("Do you want to install these packages? (Y/n)"))
return error();
}
@ -118,13 +120,14 @@ namespace gdpm::package{
/* Retrieve necessary asset data if it was found already in cache */
Document doc;
bool is_valid = p.download_url.empty() || p.category.empty() || p.description.empty() || p.support_level.empty();
if(is_valid){
bool is_missing_data = p.download_url.empty() || p.category.empty() || p.description.empty() || p.support_level.empty();
if(is_missing_data){
doc = rest_api::get_asset(url, p.asset_id, rest_api_params);
if(doc.HasParseError() || doc.IsNull()){
constexpr const char *message = "\nError parsing HTTP response.";
const std::string message = std::format("Error parsing JSON: {}", GetParseError_En(doc.GetParseError()));
log::error(message);
return error(doc.GetParseError(), message);
return error(constants::error::JSON_ERR, std::format("{}: {}", message, GetParseError_En(doc.GetParseError())));
}
p.category = doc["category"].GetString();
p.description = doc["description"].GetString();
@ -133,7 +136,7 @@ namespace gdpm::package{
p.download_hash = doc["download_hash"].GetString();
}
else{
log::error("Not a valid package.");
log::info("Found asset data found for \"{}\"", p.title);
}
/* Set directory and temp paths for storage */
@ -162,10 +165,8 @@ namespace gdpm::package{
}
else{
/* Download all the package files and place them in tmp directory. */
log::info_n("Downloading \"{}\"...", p.title);
std::string download_url = p.download_url;// doc["download_url"].GetString();
std::string title = p.title;// doc["title"].GetString();
http::response response = http::download_file(download_url, tmp_zip);
log::info("Downloading \"{}\"...", p.title);
http::response response = http::download_file(p.download_url, tmp_zip);
if(response.code == http::OK){
log::println("Done.");
}else{
@ -190,12 +191,13 @@ namespace gdpm::package{
/* Update the cache data with information from */
log::info_n("Updating local asset data...");
error error = cache::update_package_info(p_found);
if(error()){
log::error(error);
if(error.has_occurred()){
string prefix = std::format(log::get_error_prefix(), utils::timestamp());
log::println(GDPM_COLOR_LOG_ERROR"\n{}{}" GDPM_COLOR_RESET, prefix, error.get_message());
return error;
}
log::println("done.");
log::println("Done.");
// })
// );
}
@ -301,11 +303,11 @@ namespace gdpm::package{
{
error error = cache::update_package_info(p_cache);
if(error.has_occurred()){
log::error(error);
log::error("\n{}", error.get_message());
return error;
}
}
log::println("done.");
log::println("Done.");
return error();
}

View file

@ -106,8 +106,9 @@ namespace gdpm::package_manager{
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";
auto verboseOpt = joinable(repeatable(option("-v", "--verbose").call([]{ config.verbose += 1; }))) % "show verbose output";
auto versionOpt = option("--version").set(action, action_e::version);
/* Set the options */
auto cleanOpt = option("--clean").set(config.clean_temporary) % "enable/disable cleaning temps";
auto parallelOpt = option("--jobs").set(config.jobs) % "set number of parallel jobs";
@ -207,7 +208,7 @@ namespace gdpm::package_manager{
);
auto cli = (
debugOpt, configOpt,
debugOpt, configOpt, verboseOpt, versionOpt,
(installCmd | addCmd | removeCmd | updateCmd | searchCmd | exportCmd |
listCmd | linkCmd | cloneCmd | cleanCmd | configCmd | fetchCmd |
remoteCmd | uiCmd | helpCmd)
@ -249,6 +250,7 @@ namespace gdpm::package_manager{
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 {

View file

@ -18,8 +18,9 @@
namespace gdpm::rest_api{
request_params make_from_config(const config::context& config){
request_params params = make_request_params();
params.godot_version = config.info.godot_version;
bool is_latest = (config.info.godot_version.empty() || config.info.godot_version == "latest");
request_params params = make_request_params();
params.godot_version = (is_latest) ? "" : config.info.godot_version;
params.verbose = config.verbose;
return params;
}
@ -37,7 +38,7 @@ namespace gdpm::rest_api{
bool reverse,
int verbose
){
request_params params{
return request_params{
.type = type,
.category = category,
.support = support,
@ -50,7 +51,6 @@ namespace gdpm::rest_api{
.reverse = reverse,
.verbose = verbose
};
return params;
}
bool register_account(
@ -211,7 +211,7 @@ namespace gdpm::rest_api{
string request_url = _prepare_request(url, c);
http::response r = http::request_get(request_url);
if(c.verbose > 0)
log::info("URL: {}", request_url);
log::info("get_asset().URL: {}", request_url);
return _parse_json(r.body, c.verbose);
}
@ -220,11 +220,10 @@ namespace gdpm::rest_api{
int asset_id,
const request_params& params
){
string request_url = _prepare_request(url, params);
utils::replace_all(request_url, "{id}", std::to_string(asset_id));
string request_url = utils::replace_all(_prepare_request(url, params), "{id}", std::to_string(asset_id));
http::response r = http::request_get(request_url.c_str());
if(params.verbose > 0)
log::info("URL: {}", request_url);
if(params.verbose >= log::INFO)
log::info("get_asset().URL: {}", request_url);
return _parse_json(r.body);
}

View file

@ -102,27 +102,29 @@ namespace gdpm::utils{
}
std::string replace_first(
std::string &s,
const std::string &s,
const std::string &from,
const std::string &to
){
size_t pos = s.find(from);
std::string copy = s; // make string copy
size_t pos = copy.find(from);
if(pos == std::string::npos)
return s;
return s.replace(pos, from.length(), to);
return copy;
return copy.replace(pos, from.length(), to);
}
std::string replace_all(
std::string& s,
const std::string& s,
const std::string& from,
const std::string& to
){
std::string copy = s; // make string copy
size_t pos = 0;
while((pos = s.find(from, pos)) != std::string::npos){
s.replace(pos, s.length(), to);
while((pos = copy.find(from, pos)) != std::string::npos){
copy.replace(pos, s.length(), to);
pos += to.length();
}
return s;
return copy;
}
/* Ref: https://gist.github.com/mobius/1759816 */
@ -204,17 +206,18 @@ namespace gdpm::utils{
std::string prompt_user(const char *message){
log::print("{} ", message);
std::string input;
std::cin >> input;
// std::cin >> input;
getline(std::cin, input);
return input;
}
bool prompt_user_yn(const char *message){
std::string input{"y"};
do{
input = utils::prompt_user(message);
to_lower(input);
input = (input == "\0" || input == "\n" || input.empty()) ? "y" : input;
}while( !std::cin.fail() && input != "y" && input != "n");
std::string input{""};
while( !std::cin.fail() && input != "y" && input != "n" ){
bool is_default = (input == "\0" || input == "\n" || input == "\r\n" || input.empty());
input = to_lower(utils::prompt_user(message));
input = is_default ? "y" : input;
}
return input == "y";
}