Major refactor and API changes

- Updated `.gitignore` file
- Updated `CMakeLists.txt` to build static exectuable
- Changed some `Doxyfile` configurations to build more robust and complete documentation (WIP)
- Changed how `remote` works to better reflect `git`'s API (WIP)
- Changed how error handling works
- Improved `bin/compile.sh` script
- Improved `bin/lines.sh` script (kinda)
- Removed some instances of `fmt` in favor of `std` string functions
- Restructed style for better readibility
This commit is contained in:
David Allen 2023-05-22 17:54:45 -06:00
parent ba23299777
commit 5a73651ad1
29 changed files with 1836 additions and 1140 deletions

View file

@ -1,7 +1,9 @@
#include "config.hpp"
#include "error.hpp"
#include "log.hpp"
#include "utils.hpp"
#include "constants.hpp"
#include "error.hpp"
// RapidJSON
#include <rapidjson/ostreamwrapper.h>
@ -23,6 +25,8 @@
#include <fstream>
#include <ios>
#include <memory>
#include <set>
#include <unordered_map>
namespace gdpm::config{
@ -38,8 +42,19 @@ namespace gdpm::config{
return o;
};
auto _build_json_object = [](const string_map& m){
string o{"{"};
std::for_each(m.begin(), m.end(), [&o](const string_pair& p){
o += std::format("\n\"{}\": \"{}\",", p.first, p.second);
});
if(o.back() == ',')
o.pop_back();
o += "}";
return o;
};
/* Build a JSON string to pass to document */
std::string json{
string json{
"{\"username\":\"" + params.username + "\","
+ "\"password\":\"" + params.password + "\","
+ "\"path\":\"" + params.path + "\","
@ -47,7 +62,7 @@ namespace gdpm::config{
+ "\"godot_version\":\"" + params.godot_version + "\","
+ "\"packages_dir\":\"" + params.packages_dir + "\","
+ "\"tmp_dir\":\"" + params.tmp_dir + "\","
+ "\"remote_sources\":" + _build_json_array(params.remote_sources) + ","
+ "\"remote_sources\":" + _build_json_object(params.remote_sources) + ","
+ "\"threads\":" + fmt::to_string(params.threads) + ","
+ "\"timeout\":" + fmt::to_string(params.timeout) + ","
+ "\"enable_sync\":" + fmt::to_string(params.enable_sync) + ","
@ -58,17 +73,19 @@ namespace gdpm::config{
}
gdpm::error load(std::filesystem::path path, context& config, int verbose){
error load(
std::filesystem::path path,
context& config,
int verbose
){
std::fstream file;
gdpm::error error;
file.open(path, std::ios::in);
if(!file){
if(verbose){
if(verbose)
log::info("No configuration file found. Creating a new one.");
config = make_context();
save(config.path, config, verbose);
}
return error;
config = make_context();
save(config.path, config, verbose);
return error();
}
else if(file.is_open()){
/*
@ -79,24 +96,30 @@ namespace gdpm::config{
using namespace rapidjson;
/* Read JSON from config, parse, and check document. Must make sure that program does not crash here and use default config instead! */
std::string contents, line;
string contents, line;
while(std::getline(file, line))
contents += line + "\n";
if(verbose > 0)
log::info("Load config...\n{}", contents.c_str());
log::info("Loading configuration file...\n{}", contents.c_str());
Document doc;
ParseErrorCode status = doc.Parse(contents.c_str()).GetParseError();
if(!doc.IsObject()){
log::error("Could not load config file.");
error error(
constants::error::FILE_NOT_FOUND,
"Could not load config file."
);
log::error(error);
return error;
}
assert(doc.IsObject());
assert(doc.HasMember("remote_sources"));
assert(doc["remote_sources"].IsArray());
error error = validate(doc);
if(error()){
log::error(error);
return error;
}
/* Make sure contents were read correctly. */
// if(!status){
@ -105,16 +128,23 @@ namespace gdpm::config{
// return context();
// }
/* Must check if keys exists first, then populate _config_params. */
/* Must check if keys exists first, then populate `_config_params`. */
if(doc.HasMember("remote_sources")){
if(doc["remote_sources"].IsArray()){
const Value& srcs = doc["remote_sources"];
for(auto& src : srcs.GetArray()){
for(auto& src : srcs.GetObject()){
// config.remote_sources.push_back(src.GetString());
config.remote_sources.insert(src.GetString());
config.remote_sources.insert(
std::pair(src.name.GetString(), src.value.GetString())
);
}
} else{
log::error("Malformed sources found.");
} else {
gdpm::error error(
constants::error::INVALID_KEY,
"Could not read key `remote_sources`."
);
log::error(error);
return error;
}
}
auto _get_value_string = [](Document& doc, const char *property){
@ -135,23 +165,27 @@ namespace gdpm::config{
config.path = _get_value_string(doc, "path");
config.token = _get_value_string(doc, "token");
config.godot_version = _get_value_string(doc, "godot_version");
config.packages_dir = _get_value_string(doc, "packages_dir");
config.tmp_dir = _get_value_string(doc, "tmp_dir");
config.packages_dir = _get_value_string(doc, "packages_dir");
config.tmp_dir = _get_value_string(doc, "tmp_dir");
config.threads = _get_value_int(doc, "threads");
config.enable_sync = _get_value_int(doc, "enable_sync");
config.enable_file_logging = _get_value_int(doc, "enable_file_logging");
}
return error;
return error();
}
gdpm::error save(std::filesystem::path path, const context& config, int verbose){
error save(
std::filesystem::path path,
const context& config,
int verbose
){
using namespace rapidjson;
/* Build a JSON string to pass to document */
std::string json = to_json(config);
string json = to_json(config);
if(verbose > 0)
log::info("Save config...\n{}", json.c_str());
log::info("Saving configuration file...\n{}", json.c_str());
/* Dump JSON config to file */
Document doc;
@ -166,14 +200,28 @@ namespace gdpm::config{
}
context make_context(const std::string& username, const std::string& password, const std::string& path, const std::string& token, const std::string& godot_version, const std::string& packages_dir, const std::string& tmp_dir, const std::set<std::string>& remote_sources, size_t threads, size_t timeout, bool enable_sync, bool enable_file_logging, int verbose){
context make_context(
const string& username,
const string& password,
const string& path,
const string& token,
const string& godot_version,
const string& packages_dir,
const string& tmp_dir,
const string_map& remote_sources,
size_t threads,
size_t timeout,
bool enable_sync,
bool enable_file_logging,
int verbose
){
context config {
.username = username,
.password = password,
.path = path,
.token = token,
.godot_version = godot_version,
.packages_dir = (packages_dir.empty()) ? std::string(getenv("HOME")) + ".gdpm" : packages_dir,
.packages_dir = (packages_dir.empty()) ? string(getenv("HOME")) + ".gdpm" : packages_dir,
.tmp_dir = tmp_dir,
.remote_sources = remote_sources,
.threads = threads,
@ -185,4 +233,23 @@ namespace gdpm::config{
return config;
}
error validate(const rapidjson::Document& doc){
error error(constants::error::INVALID_CONFIG, "");
if(!doc.IsObject()){
error.set_message("Document is not a JSON object.");
return error;
}
if(!doc.HasMember("remote_sources")){
error.set_message("Could not find `remote_sources` in config.");
return error;
}
if(!doc["remote_sources"].IsObject()){
error.set_message("Key `remote_sources` is not a JSON object.");
return error;
}
error.set_code(constants::error::NONE);
return error;
}
}