Initial commit

First commit with most of the main features implemented. May still need
some bug fixes here and there.
This commit is contained in:
David Allen 2021-12-30 12:56:37 -06:00
commit 1893c7c36b
26 changed files with 2839 additions and 0 deletions

179
src/config.cpp Normal file
View file

@ -0,0 +1,179 @@
#include "config.hpp"
#include "log.hpp"
#include "utils.hpp"
#include "constants.hpp"
// RapidJSON
#include <rapidjson/ostreamwrapper.h>
#include <rapidjson/rapidjson.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/prettywriter.h>
#include <rapidjson/document.h>
#include <rapidjson/error/en.h>
// fmt
#include <fmt/format.h>
#include <cxxopts.hpp>
#include <iostream>
#include <string>
#include <string_view>
#include <ostream>
#include <fstream>
#include <ios>
#include <memory>
namespace gdpm::config{
config_context config;
std::string to_json(const config_context& params){
auto _build_json_array = [](std::vector<std::string> a){
std::string o{"["};
for(const std::string& src : a)
o += "\"" + src + "\",";
if(o.back() == ',')
o.pop_back();
o += "]";
return o;
};
/* Build a JSON string to pass to document */
std::string json{
"{\"username\":\"" + params.username + "\","
+ "\"password\":\"" + params.password + "\","
+ "\"path\":\"" + params.path + "\","
+ "\"token\":\"" + params.token + "\","
+ "\"godot_version\":\"" + params.godot_version + "\","
+ "\"packages_dir\":\"" + params.packages_dir + "\","
+ "\"tmp_dir\":\"" + params.tmp_dir + "\","
+ "\"remote_sources\":" + _build_json_array(params.remote_sources) + ","
+ "\"threads\":" + fmt::to_string(params.threads) + ","
+ "\"timeout\":" + fmt::to_string(params.timeout) + ","
+ "\"enable_sync\":" + fmt::to_string(params.enable_sync) + ","
+ "\"enable_file_logging\":" + fmt::to_string(params.enable_file_logging)
+ "}"
};
return json;
}
config_context load(std::filesystem::path path, int verbose){
std::fstream file;
file.open(path, std::ios::in);
if(!file){
log::error("Could not open file");
return config;
}
else if(file.is_open()){
/*
* See RapidJson docs:
*
* https://rapidjson.org/md_doc_tutorial.html
*/
using namespace rapidjson;
/* Read JSON fro config, parse, and check document. Must make sure that program does not crash here and use default config instead! */
std::string contents, line;
while(std::getline(file, line))
contents += line + "\n";
if(verbose > 0)
log::info("Load config...\n{}", contents.c_str());
Document doc;
ParseErrorCode status = doc.Parse(contents.c_str()).GetParseError();
if(!doc.IsObject()){
log::error("Could not load config file.");
return config;
}
assert(doc.IsObject());
assert(doc.HasMember("remote_sources"));
assert(doc["remote_sources"].IsArray());
/* Make sure contents were read correctly. */
// if(!status){
// log::error("config::load: Could not parse contents of file (Error: {}/{}).", GetParseError_En(status), doc.GetErrorOffset());
// return config_context();
// }
/* 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()){
config.remote_sources.emplace_back(src.GetString());
}
} else{
log::error("Malformed sources found.");
}
}
auto _get_value_string = [](Document& doc, const char *property){
if(doc.HasMember(property))
if(doc[property].IsString())
return doc[property].GetString();
return "";
};
auto _get_value_int = [](Document& doc, const char *property){
if(doc.HasMember(property))
if(doc[property].IsInt())
return doc[property].GetInt();
return 0;
};
config.username = _get_value_string(doc, "username");
config.password = _get_value_string(doc, "password");
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.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 config;
}
int save(const config_context& config, int verbose){
using namespace rapidjson;
/* Build a JSON string to pass to document */
std::string json = to_json(config);
if(verbose > 0)
log::info("Save config...\n{}", json.c_str());
/* Dump JSON config to file */
Document doc;
doc.Parse(json.c_str());
std::ofstream ofs(config.path);
OStreamWrapper osw(ofs);
PrettyWriter<OStreamWrapper> writer(osw);
doc.Accept(writer);
return 0;
}
config_context make_config(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::vector<std::string>& remote_sources, size_t threads, size_t timeout, bool enable_sync, bool enable_file_logging, int verbose){
config_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,
.tmp_dir = tmp_dir,
.remote_sources = remote_sources,
.threads = threads,
.timeout = timeout,
.enable_sync = enable_sync,
.enable_file_logging = enable_file_logging,
.verbose = verbose
};
return config;
}
}