diff --git a/CMakeLists.txt b/CMakeLists.txt index aa83522..aefd15c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,6 +85,7 @@ CPMAddPackage( OPTIONS "BUILD_STATIC_LIBS ON" "JSON_BuildTests OFF" + "JSON_Diagnostics ON" ) diff --git a/build b/build index 1327ae9..0c23460 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 1327ae9b54691c4c6cdffabc2cfdd7131f6d2c1f +Subproject commit 0c234609ff6a9413ccdf1431a69b1391993adbf4 diff --git a/frate-project.json b/frate-project.json new file mode 100644 index 0000000..f5e57a8 --- /dev/null +++ b/frate-project.json @@ -0,0 +1,49 @@ +{ + "authors": [], + "build_dir": "build", + "cmake_version": "3.10", + "compiler": "g++", + "default_mode": "Release", + "dependencies": [], + "flags": [ + "-O3" + ], + "git": "null", + "homepage": "null", + "include_dir": "include", + "keywords": [], + "lang": "cpp", + "lang_version": "20", + "libs": [], + "modes": [ + { + "dependencies": [], + "flags": [ + "-O2" + ], + "name": "Release" + }, + { + "dependencies": [], + "flags": [ + "-g" + ], + "name": "Debug" + }, + { + "dependencies": [], + "flags": [ + "-g" + ], + "name": "Test" + } + ], + "project_description": "", + "project_name": "debug-frate", + "project_type": "executable", + "project_version": "0.0.1", + "prompts": {}, + "src_dir": "src", + "toolchains": [], + "variables": {} +} \ No newline at end of file diff --git a/include/Frate/Command.hpp b/include/Frate/Command.hpp index fc1a151..4b6ed27 100644 --- a/include/Frate/Command.hpp +++ b/include/Frate/Command.hpp @@ -19,41 +19,35 @@ namespace Frate::Command { using namespace Utils::CLI::Ansi; using namespace cxxopts; + class Package { + public: + std::string name; + std::string git; + std::string git_short; + std::string git_prefixed; + std::vector versions; + std::string target_link; + std::string description; + std::string selected_version; + std::string git_description; + std::string language; + std::string license; + std::string owner; + std::string owner_type; + int stars; + int forks; + int open_issues; + int watchers; + int score; + // json toJson(); + // void fromJson(json j); + bool addCallback(sol::state &lua); + friend void from_json(const json &j, Package& package); + friend void to_json(json &j, const Package& package); + Package(){}; + }; - /* - * Package structure from index - * @param name the name of the package - * @param url the url of the package - * @param versions the versions of the package - * @param target_link the target link of the package - * @param description the description of the package - * @param score the score of the package, used for sorting - */ - typedef struct Package_s { - std::string name; - std::string git; - std::string git_short; - std::string git_prefixed; - std::vector versions; - std::string target_link; - std::string description; - std::string selected_version; - std::string git_description; - std::string language; - std::string license; - std::string owner; - std::string owner_type; - int stars; - int forks; - int open_issues; - int watchers; - int score; - json toJson(); - void fromJson(json j); - bool addCallback(sol::state &lua); - } Package;//Deez nuts - - typedef struct RemoteServer{ + typedef struct RemoteServer_s{ std::string name; std::string ip; std::string username; @@ -76,82 +70,121 @@ namespace Frate::Command { } }; - typedef struct Mode{ - std::string name; - std::vector flags; - std::vector dependencies{}; - } Mode; - - typedef struct ProjectPrompt_s { - std::string value{""}; - std::string text{""}; - std::string type{"string"}; - // std::string key{""}; - std::string default_value{""}; - bool required{false}; - std::vector options{}; - std::function validator{ - [this](std::string s) -> bool { - if(options.size() == 0) { - return true; - }else{ - for (std::string option: options){ - if (s == option){ - return true; + class Mode{ + public: + std::string name; + std::vector flags; + std::vector dependencies{}; + friend void from_json(const json &j, Mode& mode); + friend void to_json(json &j, const Mode& mode); + Mode(std::string name = "", std::vector flags = {}, std::vector dependencies = {}); + }; + + class ProjectPrompt{ + public: + ProjectPrompt(){}; + std::string value{""}; + std::string text{""}; + std::string type{"string"}; + std::string default_value{""}; + bool required{false}; + std::vector options{}; + friend void from_json(const json &j, ProjectPrompt& prompt); + friend void to_json(json &j, const ProjectPrompt& prompt); + std::function validator{ + [this](std::string s) -> bool { + if(options.size() == 0) { + return true; + }else{ + for (std::string option: options){ + if (s == option){ + return true; + } } + return false; } - return false; } - } - }; - template - T get(); - } ProjectPrompt; + }; + template + T get(); + }; //TODO: MAKE MOST OF THESE OPTIONAL - typedef struct Project_s { - std::string name; - std::string description; - std::string type{""}; - RemoteServer build_server; - std::filesystem::path path; - std::string git{"null"}; - std::string homepage{"null"}; - std::string bugs{"null"}; - std::string lang{"cpp"}; - std::string cmake_version{"3.28"}; - std::string lang_version{"20"}; - std::string compiler{"g++"}; - std::string license{""}; - std::string default_mode{"Release"}; - std::string build_command; - std::vector modes{ - Mode{.name = "Release", .flags={"-O2 "}}, - Mode{.name= "Debug", .flags= {"-g"}}, - Mode{.name= "Test", .flags={"-g"}} - }; - std::vector authors; - std::vector keywords; - std::string src_dir{"src"}; - std::string include_dir{"include"}; - std::vector build_servers; - std::vector dependencies; - std::string build_dir{"build"}; - Package testing_lib; - std::string version{"0.0.1"}; - std::vector flags; - std::vector toolchains {}; - std::vector libs{}; - void fromJson(json j); - nlohmann::json toJson(); - bool save(); - void checkKeys(json j); - std::string getPath(){ - return path.string(); - }; - std::unordered_map prompts{}; - std::unordered_map variables{}; - } Project; + class Template; + class Project { + public: + Project(); + std::string name; + std::string description; + std::string type{""}; + RemoteServer build_server; + std::filesystem::path path; + std::string git{"null"}; + std::string homepage{"null"}; + std::string bugs{"null"}; + std::string lang{"cpp"}; + std::string cmake_version{"3.28"}; + std::string lang_version{"20"}; + std::string compiler{"g++"}; + std::string license{""}; + std::string default_mode{"Release"}; + std::string build_command{"cmake --build ."}; + std::vector modes{ + Mode("Release",{"-O2"}), + Mode("Debug",{"-g"}), + Mode("Test",{"-g"}) + }; + std::vector authors{}; + std::vector keywords{}; + std::string src_dir{"src"}; + std::string include_dir{"include"}; + std::vector build_servers{}; + std::vector dependencies{}; + std::string build_dir{"build"}; + Package testing_lib; + std::string version{"0.0.1"}; + std::vector flags{}; + std::vector toolchains {}; + std::vector libs{}; + //void fromJson(json j); + //nlohmann::json toJson(); + bool save(); + void checkKeys(json j); + std::string getPath(){ + return path.string(); + }; + std::unordered_map prompts{}; + std::unordered_map variables{}; + friend void from_json(const json &j, Project& pro); + friend void to_json(json &j, const Project& pro); + void fromTemplate(Template &t); + }; + class Template { + public: + Template(); + std::string name; + std::string description; + std::string version; + std::string src_dir{"src"}; + std::string include_dir{"include"}; + std::string build_dir{"build"}; + std::vector dependencies{}; + std::string default_mode{"Release"}; + std::vector modes{}; + std::vector flags{}; + std::vector system_libs{}; + std::vector supported_toolchains{}; + std::vector supported_languages{}; + std::vector supported_language_versions{}; + std::string min_cmake_version{"3.10"}; + std::vector supported_compilers{}; + std::vector keywords{}; + std::unordered_map prompts{}; + std::unordered_map variables{}; + friend void from_json(const json &j, Template& t); + friend void to_json(json &j, const Template& t); + friend void to_project(Project &pro, const Template &t); + }; typedef struct Handler_s Handler; @@ -180,7 +213,7 @@ namespace Frate::Command { Interface(int argc, char **argv); void getHelpString(std::string name,std::vector &handlers,bool is_subcommand = false); void getHelpString(Handler &handler); - bool runCommand(std::string,std::vector&); + //bool runCommand(std::string,std::vector&); std::shared_ptr pro; bool project_present{false}; //bool verbose{false}; @@ -195,7 +228,7 @@ namespace Frate::Command { bool confirm_all{false}; bool InitHeader(); bool CreateCMakelists(); - bool LoadProjectJson(); + bool loadProjectJson(); ~Interface(); }; @@ -212,4 +245,5 @@ namespace Frate::Command { bool updateIndex(); + bool runCommand(std::shared_ptr inter,std::string command, std::vector &handlers); } diff --git a/include/Frate/Constants.hpp b/include/Frate/Constants.hpp index d1d937a..eb80f62 100644 --- a/include/Frate/Constants.hpp +++ b/include/Frate/Constants.hpp @@ -24,6 +24,7 @@ namespace Frate::Constants { constexpr const std::string_view FRATE_TEMPLATES = "https://github.com/frate-templates/templates/releases/latest/download/index.json"; const std::string TEMPLATE_PATH = "template/"; + const std::string TEMPLATE_CALLBACKS_PATH = "frate-callbacks/"; const std::string INIT_SCRIPTS_PATH = "__init__/"; const std::string POST_SCRIPTS_PATH = "__post__/"; diff --git a/include/Frate/Reflection.hpp b/include/Frate/Reflection.hpp index 82101c4..9bdeb02 100644 --- a/include/Frate/Reflection.hpp +++ b/include/Frate/Reflection.hpp @@ -5,69 +5,12 @@ namespace Frate::Reflection { using nlohmann::json; using Command::Project; + //Project related reflection + // void to_json(const Project &p, json &j); + // void to_json(const Command::Package &p, json &j); + // void to_json(const Command::Mode &m, json &j); - static void to_json(json &j, const Project &p) { - j = json{ - {"name", p.name}, - {"description", p.description}, - {"type", p.type}, - {"version", p.version}, - {"authors", p.authors}, - {"license", p.license}, - {"dependencies", p.dependencies}, - {"keywords", p.keywords}, - {"git", p.git}, - {"homepage", p.homepage}, - {"bugs", p.bugs}, - {"compiler", p.compiler}, - {"lang", p.lang}, - {"lang_version", p.lang_version}, - {"build_dir", p.build_dir}, - {"include_dir", p.include_dir}, - {"src_dir", p.src_dir}, - {"toolchains", p.toolchains}, - {"flags", p.flags}, - {"libs", p.libs}, - {"default_mode", p.default_mode}, - {"modes", p.modes} - }; - } - static void from_json(Command::Package& package, const json &j){ - package.name = j.at("name").get(); - package.selected_version = j.at("version").get(); - package.description = j.at("description").get(); - package.license = j.at("license").get(); - } - static void from_json(Command::Mode& mode, const json &j){ - mode.name = j.at("name").get(); - mode.flags = j.at("flags").get>(); - mode.dependencies = json::array(); - for(Command::Package &dep : j.at("dependencies")){ - mode.dependencies.push_back(dep); - } - } - static void from_json(Project& pro, const json &j){ - pro.name = j.at("name").get(); - pro.description = j.at("description").get(); - pro.type = j.at("type").get(); - pro.version = j.at("version").get(); - pro.authors = j.at("authors").get>(); - pro.license = j.at("license").get(); - pro.dependencies = j.at("dependencies").get>(); - pro.keywords = j.at("keywords").get>(); - pro.git = j.at("git").get(); - pro.homepage = j.at("homepage").get(); - pro.bugs = j.at("bugs").get(); - pro.compiler = j.at("compiler").get(); - pro.lang = j.at("lang").get(); - pro.lang_version = j.at("lang_version").get(); - pro.build_dir = j.at("build_dir").get(); - pro.include_dir = j.at("include_dir").get(); - pro.src_dir = j.at("src_dir").get(); - pro.toolchains = j.at("toolchains").get>(); - pro.flags = j.at("flags").get>(); - pro.libs = j.at("libs").get>(); - pro.default_mode = j.at("default_mode").get(); - pro.modes = j.at("modes").get>(); - } + // void from_json(const json &j, Command::Package& package); + // void from_json(const json &j, Command::Mode& mode); + // void from_json(const json &j, Project &pro); } diff --git a/include/Frate/Test/Test.hpp b/include/Frate/Test/Test.hpp index bb10278..ea1de2e 100644 --- a/include/Frate/Test/Test.hpp +++ b/include/Frate/Test/Test.hpp @@ -12,16 +12,17 @@ namespace Tests{ namespace Tests::Command { + using Frate::Command::Interface; using std::filesystem::path; extern std::filesystem::path test_path; - extern Frate::Utils::Error error; - extern Frate::Utils::Info info; - extern Frate::Utils::Warning warning; + // extern Frate::Utils::Error error; + // extern Frate::Utils::Info info; + // extern Frate::Utils::Warning warning; void cleanUp(path test_path); - std::pair init(std::string command,bool check_config=false); + std::pair> init(std::string command,bool check_config=false); - bool validateProjectJson(Frate::Command::Interface* inter); + bool validateProjectJson(std::shared_ptr inter); std::filesystem::path genTestDirectory(); std::pair genCommand(std::string args); diff --git a/src/Command/Actions/Add.cpp b/src/Command/Actions/Add.cpp index 0c4aefb..a11c801 100644 --- a/src/Command/Actions/Add.cpp +++ b/src/Command/Actions/Add.cpp @@ -34,7 +34,9 @@ namespace Frate::Command::Add { return false; } - return inter->runCommand(subcommand, addHandlers); + inter->loadProjectJson(); + + return runCommand(inter,subcommand, addHandlers); return true; } @@ -46,7 +48,6 @@ namespace Frate::Command::Add { .positional_args = {"package_name"}, .docs = "Add a package to the project", .callback = &Packages::add, - .requires_project = true, .unlimited_args = true, }, Handler{ @@ -54,42 +55,36 @@ namespace Frate::Command::Add { .positional_args = {"\"flag\""}, .docs = "Add a flag to the project", .callback = &Flags::add, - .requires_project = true, }, Handler{ .aliases = {"lib","l"}, .positional_args = {"lib"}, .docs = "Add a library to link to your project", .callback = &Library::add, - .requires_project = true, }, Handler{ .aliases = {"mode","m"}, .positional_args = {"mode-name"}, .docs = "Adds a build mode to your project", .callback = &Modes::add, - .requires_project = true, }, Handler{ .aliases = {"server","s"}, //TODO: Don't know what inter requires .docs = "Add a remote server to your local config that you can later build to", .callback = &RemoteServers::add, - .requires_project = true, }, Handler{ .aliases = {"toolchain","t"}, .positional_args = {}, .docs = "Add a crosscompile toolchain to your project", .callback = &Toolchains::add, - .requires_project = true, }, Handler{ .aliases = {"author","a"}, .positional_args = {"author-name"}, .docs = "Add an author to your project", .callback = &Author::add, - .requires_project = true, .unlimited_args = true, }, Handler{ @@ -97,7 +92,6 @@ namespace Frate::Command::Add { .positional_args = {"keyword"}, .docs = "Add keywords to your project", .callback = &Keywords::add, - .requires_project = true, .unlimited_args = true, }, }; diff --git a/src/Command/Actions/List.cpp b/src/Command/Actions/List.cpp index d2ee046..f781e37 100644 --- a/src/Command/Actions/List.cpp +++ b/src/Command/Actions/List.cpp @@ -90,6 +90,6 @@ namespace Frate::Command::List{ inter->getHelpString("list", listHandlers); return false; } - return inter->runCommand(target, listHandlers); + return runCommand(inter,target, listHandlers); } } diff --git a/src/Command/Actions/New.cpp b/src/Command/Actions/New.cpp index b71bcf1..62916b8 100644 --- a/src/Command/Actions/New.cpp +++ b/src/Command/Actions/New.cpp @@ -174,6 +174,8 @@ bool options(std::shared_ptr inter) { return false; } } + + return true; } } // namespace Command diff --git a/src/Command/Actions/Remove.cpp b/src/Command/Actions/Remove.cpp index 60124e2..5f2fb85 100644 --- a/src/Command/Actions/Remove.cpp +++ b/src/Command/Actions/Remove.cpp @@ -1,5 +1,6 @@ #include "Frate/Command/Library.hpp" #include "Frate/Utils/General.hpp" +#include "Frate/Generators.hpp" #include #include #include @@ -77,7 +78,8 @@ namespace Frate::Command::Remove { return false; } - - return inter->runCommand(subcommand, removeHandlers); + inter->loadProjectJson(); + Generators::Project::refresh(inter->pro); + return runCommand(inter,subcommand, removeHandlers); } } // namespace Comman diff --git a/src/Command/Actions/Run.cpp b/src/Command/Actions/Run.cpp index 99172fb..58cacc1 100644 --- a/src/Command/Actions/Run.cpp +++ b/src/Command/Actions/Run.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace Frate::Command::Run { using std::filesystem::create_directories; bool options(std::shared_ptr inter) { @@ -8,6 +9,8 @@ bool options(std::shared_ptr inter) { } bool run(std::shared_ptr inter) { options(inter); + inter->loadProjectJson(); + Generators::Project::refresh(inter->pro); std::cout << "Running project: " << inter->pro->name << std::endl; const std::string work_dir_cmd = "cd " +inter->pro->path.string(); @@ -22,6 +25,7 @@ bool run(std::shared_ptr inter) { try{ create_directories(inter->pro->path / "build"); }catch(std::exception& e){ + Utils::error << "Error while creating build directory" << std::endl; Utils::debug(e.what()); return false; } diff --git a/src/Command/Actions/Search.cpp b/src/Command/Actions/Search.cpp index 2fd3750..601d154 100644 --- a/src/Command/Actions/Search.cpp +++ b/src/Command/Actions/Search.cpp @@ -49,7 +49,7 @@ namespace Frate::Command::Search { query = inter->args->operator[]("query").as(); - return inter->runCommand(target, searchHandlers); + return runCommand(inter,target, searchHandlers); } diff --git a/src/Command/Actions/Set.cpp b/src/Command/Actions/Set.cpp index fabf30e..155ed98 100644 --- a/src/Command/Actions/Set.cpp +++ b/src/Command/Actions/Set.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace Frate::Command::Set { bool options(std::shared_ptr inter) { @@ -66,6 +67,8 @@ namespace Frate::Command::Set { return false; } - return inter->runCommand(subcommand, setHandlers); + inter->loadProjectJson(); + Generators::Project::refresh(inter->pro); + return runCommand(inter,subcommand, setHandlers); } } diff --git a/src/Command/Actions/Update.cpp b/src/Command/Actions/Update.cpp index ddb4ab6..c898040 100644 --- a/src/Command/Actions/Update.cpp +++ b/src/Command/Actions/Update.cpp @@ -34,7 +34,7 @@ namespace Frate::Command::Update { } target = inter->args->operator[]("subcommand").as(); - return inter->runCommand(target, updateHandlers); + return runCommand(inter,target, updateHandlers); return true; } diff --git a/src/Command/Flags/AddFlags.cpp b/src/Command/Flags/AddFlags.cpp index d855e14..f3b540d 100644 --- a/src/Command/Flags/AddFlags.cpp +++ b/src/Command/Flags/AddFlags.cpp @@ -14,7 +14,6 @@ namespace Frate::Command::Flags { std::cout << "Adding flag: " << flag << std::endl; m.flags.push_back(flag); } - std::cout << "Writing frate-project.json" << std::endl; return true; } } @@ -23,7 +22,6 @@ namespace Frate::Command::Flags { std::cout << "Adding flag: " << flag << std::endl; inter->pro->flags.push_back(flag); } - std::cout << "Writing frate-project.json" << std::endl; return true; } } diff --git a/src/Command/Flags/RemoveFlags.cpp b/src/Command/Flags/RemoveFlags.cpp index e93c8fa..386ebbf 100644 --- a/src/Command/Flags/RemoveFlags.cpp +++ b/src/Command/Flags/RemoveFlags.cpp @@ -17,7 +17,6 @@ namespace Frate::Command::Flags { return f == flag; }); } - std::cout << "Writing frate-project.json" << std::endl; return true; } } @@ -28,7 +27,6 @@ namespace Frate::Command::Flags { return f == flag; }); } - std::cout << "Writing frate-project.json" << std::endl; return true; } } diff --git a/src/Command/Helpers/Interface.cpp b/src/Command/Helpers/Interface.cpp index dece799..9361e05 100644 --- a/src/Command/Helpers/Interface.cpp +++ b/src/Command/Helpers/Interface.cpp @@ -17,6 +17,7 @@ #include "Frate/Utils/General.hpp" #include #include "cxxopts.hpp" +#include "nlohmann/detail/json_ref.hpp" #include "termcolor/termcolor.hpp" #include #include @@ -176,7 +177,8 @@ namespace Frate::Command { .flags = {}, //TODO: Add flags .subcommands = Update::handlers(inter), .docs = "update sub command", - .callback = &Update::run + .callback = &Update::run, + .requires_project = false }); inter->commands.push_back({ @@ -211,14 +213,16 @@ namespace Frate::Command { for(std::string& alias : handler.aliases){ if(alias == command){ - if(handler.requires_project){ - - //Check if project loads successfully - inter->LoadProjectJson(); - - //if so refresh the project templates - Generators::Project::refresh(inter->pro); - } +// if(handler.requires_project){ +// +// //Check if project loads successfully +// inter->loadProjectJson(); +// Utils::verbose << "Project loaded successfully" << ENDL; +// Utils::verbose << nlohmann::json(*inter->pro).dump(2) << ENDL; +// +// //if so refresh the project templates +// Generators::Project::refresh(inter->pro); +// } //Checks if the callback ran successfully if(!handler.callback(inter)){ @@ -256,7 +260,7 @@ namespace Frate::Command { } } } - bool Interface::runCommand(std::string command, std::vector &handlers){ + bool runCommand(std::shared_ptr inter,std::string command, std::vector &handlers){ for(Handler handler : handlers){ for(std::string alias : handler.aliases){ if(alias == command){ @@ -264,17 +268,17 @@ namespace Frate::Command { Utils::error << "Command not implemented: " << command; return false; } - if(handler.requires_project && !project_present){ - Utils::error << "Error: Project not found and command: " << command << " requires a project" << ENDL; - return false; - } - if(!handler.callback(shared_from_this())){ - getHelpString(handler); + // if(handler.requires_project && !inter->project_present){ + // Utils::error << "Error: Project not found and command: " << command << " requires a project" << ENDL; + // return false; + // } + if(!handler.callback(inter)){ + inter->getHelpString(handler); return false; } if(handler.requires_project){ - pro->save(); - Generators::Project::refresh(pro); + Generators::Project::refresh(inter->pro); + inter->pro->save(); } return true; } diff --git a/src/Command/Helpers/Mode.cpp b/src/Command/Helpers/Mode.cpp new file mode 100644 index 0000000..a0f0e55 --- /dev/null +++ b/src/Command/Helpers/Mode.cpp @@ -0,0 +1,26 @@ +#include + + +namespace Frate::Command { + + Mode::Mode(std::string name, std::vector flags, std::vector dependencies) { + this->name = name; + this->flags = flags; + this->dependencies = dependencies; + } + + void from_json(const json &j, Command::Mode& mode){ + j.at("name").get_to(mode.name); + j.at("flags").get_to(mode.flags); + for (const Command::Package &element : j["dependencies"]) { + mode.dependencies.push_back(element); + } + } + void to_json(json &j, const Command::Mode &mode){ + j = json{ + {"name", mode.name}, + {"flags", mode.flags}, + {"dependencies", mode.dependencies} + }; + } +} diff --git a/src/Command/Helpers/Package.cpp b/src/Command/Helpers/Package.cpp new file mode 100644 index 0000000..1093217 --- /dev/null +++ b/src/Command/Helpers/Package.cpp @@ -0,0 +1,56 @@ +#include + + +namespace Frate::Command { + void to_json(json &j, const Package &p) { + j = json{ + {"name", p.name}, + {"selected_version,", p.selected_version}, + {"versions", p.versions}, + {"stars", p.stars}, + {"forks", p.forks}, + {"open_issues", p.open_issues}, + {"watchers", p.watchers}, + {"score", p.score}, + {"git", p.git}, + {"git_short", p.git_short}, + {"git_prefixed", p.git_prefixed}, + {"git_description", p.git_description}, + {"target_link", p.target_link}, + {"description", p.description}, + {"language", p.language}, + {"license", p.license}, + {"owner", p.owner}, + {"owner_type", p.owner_type}, + }; + } + void from_json(const json &j, Package &p){ + j.at("name").get_to(p.name); + if(j.contains("selected_version")){ + j.at("selected_version").get_to(p.selected_version); + } + + if(j.contains("versions")){ + if(!j.at("versions").is_null()){ + j.at("versions").get_to(p.versions); + } + } + j.at("stars").get_to(p.stars); + j.at("forks").get_to(p.forks); + j.at("open_issues").get_to(p.open_issues); + j.at("watchers").get_to(p.watchers); + if(j.contains("score")){ + j.at("score").get_to(p.score); + } + j.at("git").get_to(p.git); + j.at("git_short").get_to(p.git_short); + j.at("git_prefixed").get_to(p.git_prefixed); + j.at("git_description").get_to(p.git_description); + j.at("target_link").get_to(p.target_link); + j.at("description").get_to(p.description); + j.at("language").get_to(p.language); + j.at("license").get_to(p.license); + j.at("owner").get_to(p.owner); + j.at("owner_type").get_to(p.owner_type); + } +} diff --git a/src/Command/Helpers/Project.cpp b/src/Command/Helpers/Project.cpp index 8cf7ed3..a0fc2e5 100644 --- a/src/Command/Helpers/Project.cpp +++ b/src/Command/Helpers/Project.cpp @@ -2,22 +2,29 @@ #include #include #include +#include namespace Frate::Command { - + Project::Project(){}; bool Project::save(){ std::ofstream file; std::string file_name = "frate-project.json"; if(!std::filesystem::exists(this->path)){ - std::filesystem::create_directory(this->path); + try{ + std::filesystem::create_directory(this->path); + }catch(std::exception &e){ + Utils::debug(e.what()); + Utils::error << "Error while creating directory: " << this->path << std::endl; + return false; + } } if(!std::filesystem::exists(this->path / file_name)){ std::cout << "Creating new project file" << std::endl; } - json new_json = this->toJson(); + json new_json = *this; Utils::info << "Writing to file: " << this->path / file_name << std::endl; @@ -27,205 +34,133 @@ namespace Frate::Command { Utils::debug(e.what()); return false; } + file << new_json.dump(2); //Generators::CMakeList::createCMakeLists(std::make_shared(*this)); return true; } - /* - * Welp reflection is a bitch aint it - */ - void Project::fromJson(json j){ - checkKeys(j); - name = j["project_name"]; - cmake_version = j["cmake_version"]; - version = j["project_version"]; - type = j["project_type"]; - lang = j["lang"]; - lang_version = j["lang_version"]; - compiler = j["compiler"]; - src_dir = j["src_dir"]; - build_dir = j["build_dir"]; - include_dir = j["include_dir"]; - authors = j["authors"]; - type = j["project_type"]; - description = j["project_description"]; - default_mode = j["default_mode"]; - keywords = j["keywords"]; - libs = j["libs"]; - for (auto &dep : j["dependencies"]) { - Package d; - d.name = dep["name"].is_null() ? "" : dep["name"].is_null() ? "" : dep["name"]; - d.git = dep["git"].is_null() ? "" : dep["git"].is_null() ? "" : dep["git"]; - d.selected_version = dep["version"].is_null() ? "" : dep["version"]; - d.target_link = dep["target_link"].is_null() ? "" : dep["target_link"]; - if(d.target_link.empty()){ - Utils::warning << - "Warning: target_link is empty for dependency: " << d.name << std::endl; - } - dependencies.push_back(d); + void Project::fromTemplate(Template &t){ + this->src_dir = t.src_dir; + this->include_dir = t.include_dir; + this->build_dir = t.build_dir; + this->dependencies = t.dependencies; + this->default_mode = t.default_mode; + this->modes = t.modes; + this->flags = t.flags; + // Check is toolchain is present + // this->toolchains = t.toolchains; + this->variables = t.variables; + this->prompts = t.prompts; + this->libs = t.system_libs; + } + void from_json (const json &j, Project& pro){ + pro.name = j.contains("project_name") ? j["project_name"] : ""; + pro.cmake_version = j.contains("cmake_version") ? j["cmake_version"] : ""; + pro.version = j.contains("project_version") ? j["project_version"] : ""; + pro.type = j.contains("project_type") ? j["project_type"] : ""; + pro.lang = j.contains("lang") ? j["lang"] : ""; + pro.lang_version = j.contains("lang_version") ? j["lang_version"] : ""; + pro.compiler = j.contains("compiler") ? j["compiler"] : ""; + pro.src_dir = j.contains("src_dir") ? j["src_dir"] : ""; + pro.build_dir = j.contains("build_dir") ? j["build_dir"] : ""; + pro.build_command = j.contains("build_command") ? j["build_command"] : ""; + pro.include_dir = j.contains("include_dir") ? j["include_dir"] : ""; + if(j.contains("authors")){ + pro.authors = j["authors"]; } - std::vector temp_modes; - for (auto &mode: j["modes"]){ - Mode m; - m.name = mode["name"].is_null() ? "" : mode["name"]; - m.flags = mode["flags"]; - for (auto &dep : mode["dependencies"]) { - Package new_dep; - new_dep.name = dep["name"].is_null() ? "" : dep["name"]; - new_dep.git = dep["git"].is_null() ? "" : dep["git"]; - new_dep.selected_version = dep["version"].is_null() ? "" : dep["version"]; - new_dep.target_link = dep["target_link"].is_null() ? "" : dep["target_link"]; - if(new_dep.target_link == ""){ - Utils::warning << - "Warning: target_link is empty for dependency: " << new_dep.name << - " in mode: " << m.name << std::endl; - } - - m.dependencies.push_back(new_dep); - } - temp_modes.push_back(m); + pro.type = j.contains("project_type") ? j["project_type"] : ""; + pro.description = j.contains("project_description") ? j["project_description"] : ""; + pro.default_mode = j.contains("default_mode") ? j["default_mode"] : ""; + if(j.contains("keywords")){ + pro.keywords = j["keywords"]; + } + if(j.contains("libs")){ + pro.libs = j["libs"]; + } + if(j.contains("dependencies")){ + pro.dependencies = j["dependencies"]; + } + if(j.contains("flags")){ + pro.flags = j["flags"]; + } + if(j.contains("toolchains")){ + pro.toolchains = j["toolchains"]; + } + if(j.contains("prompts")){ + pro.prompts = j["prompts"]; } - modes = temp_modes; - flags = j["flags"]; - toolchains = j["toolchains"]; if(j.contains("variables")){ - for(auto [key, value] : j["variables"].items()){ - variables[key] = value; - } - }else{ - variables = json::object(); + pro.variables = j["variables"]; } - - if(!j.contains("prompts")){ - prompts = {}; - }else{ - for(auto [key, value] : j["prompts"].items()){ - ProjectPrompt prompt; - - prompt.type = value["type"].is_null() ? "string" : value["type"]; - - prompt.text = value["text"].is_null() ? "missing prompt text" : value["text"]; - - - if(value["options"].is_null()){ - prompt.options = {}; - }else{ - for(auto &option : value["options"]){ - prompt.options.push_back(option); - } - } - - - if(value["default_value"].is_null()){ - prompt.default_value = ""; - }else{ - prompt.default_value = value["default_value"]; - } - prompts[key] = prompt; - } + if(j.contains("modes")){ + pro.modes = j["modes"]; } - + pro.git = j.contains("git") ? j["git"] : ""; + pro.homepage = j.contains("homepage") ? j["homepage"] : ""; + pro.bugs = j.contains("bugs") ? j["bugs"] : ""; + } + void to_json(json &j, const Project& pro){ + j["project_name"] = pro.name; + j["cmake_version"] = pro.cmake_version; + j["project_version"] = pro.version; + j["project_type"] = pro.type; + j["lang"] = pro.lang; + j["lang_version"] = pro.lang_version; + j["compiler"] = pro.compiler; + j["src_dir"] = pro.src_dir; + j["build_dir"] = pro.build_dir; + j["include_dir"] = pro.include_dir; + j["authors"] = pro.authors; + j["project_type"] = pro.type; + j["project_description"] = pro.description; + j["default_mode"] = pro.default_mode; + j["keywords"] = pro.keywords; + j["libs"] = pro.libs; + j["dependencies"] = pro.dependencies; + j["flags"] = pro.flags; + j["toolchains"] = pro.toolchains; + j["prompts"] = pro.prompts; + j["variables"] = pro.variables; + j["modes"] = pro.modes; + j["git"] = pro.git; + j["homepage"] = pro.homepage; + j["bugs"] = pro.bugs; } - nlohmann::json Project::toJson(){ - using nlohmann::json; - json new_json; - new_json["dependencies"] = json::array(); - for (auto &dep : dependencies) { - json dep_json; - dep_json["name"] = dep.name; - dep_json["git"] = dep.git; - dep_json["version"] = dep.selected_version; - dep_json["target_link"] = dep.target_link; - new_json["dependencies"].push_back(dep_json); - } - std::vector modes_json; - for (auto &mode : modes) { - json mode_json; - json mode_deps = json::array(); - for (Package dep: mode.dependencies) { - json dep_json; - dep_json["name"] = dep.name; - dep_json["git"] = dep.git; - dep_json["version"] = dep.selected_version; - dep_json["target_link"] = dep.target_link; - mode_deps.push_back(dep_json); - } - - mode_json["name"] = mode.name; - mode_json["flags"] = mode.flags; - mode_json["dependencies"] = mode_deps; - modes_json.push_back(mode_json); - } - new_json["project_name"] = name; - new_json["project_type"] = type; - new_json["cmake_version"] = cmake_version; - new_json["project_version"] = version; - new_json["lang"] = lang; - new_json["lang_version"] = lang_version; - new_json["compiler"] = compiler; - new_json["src_dir"] = src_dir; - new_json["build_dir"] = build_dir; - new_json["include_dir"] = include_dir; - new_json["default_mode"] = default_mode; - new_json["modes"] = modes_json; - new_json["flags"] = flags; - new_json["keywords"] = keywords; - new_json["authors"] = authors; - new_json["project_type"] = type; - new_json["project_description"] = description; - new_json["toolchains"] = toolchains; - new_json["prompts"] = json::object(); - new_json["libs"] = libs; - for(auto [key, value] : prompts){ - json prompt; - prompt["value"] = value.value; - prompt["type"] = value.type; - prompt["text"] = value.text; - prompt["options"] = value.options; - prompt["default_value"] = value.default_value; - new_json["prompts"][key] = prompt; - } - for(auto [key, value] : variables){ - new_json["variables"][key] = value; - } - - return new_json; + void Project::checkKeys(json j){ + std::vector> required_keys = { + {"project_name", false}, + {"project_type", false}, + {"cmake_version", false}, + {"project_version", false}, + {"lang", false}, + {"lang_version", false}, + {"compiler", false}, + {"src_dir", false}, + {"build_dir", false}, + {"include_dir", false}, + {"default_mode", false}, + {"modes", false}, + {"dependencies", false}, + {"flags", false}, + {"keywords", false}, + {"authors", false}, + {"project_type", false}, + {"project_description", false}, + {"toolchains", false}, + {"prompts", false} }; - void Project::checkKeys(json j){ - std::vector> required_keys = { - {"project_name", false}, - {"project_type", false}, - {"cmake_version", false}, - {"project_version", false}, - {"lang", false}, - {"lang_version", false}, - {"compiler", false}, - {"src_dir", false}, - {"build_dir", false}, - {"include_dir", false}, - {"default_mode", false}, - {"modes", false}, - {"dependencies", false}, - {"flags", false}, - {"keywords", false}, - {"authors", false}, - {"project_type", false}, - {"project_description", false}, - {"toolchains", false}, - {"prompts", false} - }; - for (std::pair &key: required_keys){ - if (!j.contains(key.first)){ - Utils::error << "Missing required key: " << key.first << std::endl; - } else { - key.second = true; - } + for (std::pair &key: required_keys){ + if (!j.contains(key.first)){ + Utils::error << "Missing required key: " << key.first << std::endl; + } else { + key.second = true; } } - bool Interface::LoadProjectJson() { + } + bool Interface::loadProjectJson() { using nlohmann::json; std::fstream file; std::string file_name = "frate-project.json"; @@ -249,8 +184,11 @@ namespace Frate::Command { } try{ + std::filesystem::path current_path = pro->path; json j = json::parse(file); - pro->fromJson(j); + Project temp = j; + pro = std::make_shared(temp); + pro->path = current_path; }catch(std::exception &e){ Utils::debug(e.what()); return false; diff --git a/src/Command/Helpers/ProjectOption.cpp b/src/Command/Helpers/ProjectPrompt.cpp similarity index 82% rename from src/Command/Helpers/ProjectOption.cpp rename to src/Command/Helpers/ProjectPrompt.cpp index b938687..b1dec0b 100644 --- a/src/Command/Helpers/ProjectOption.cpp +++ b/src/Command/Helpers/ProjectPrompt.cpp @@ -12,10 +12,12 @@ namespace Frate::Command { // {"validator", p.validator} }; } - void from_json(const json &j, ProjectPrompt &p){ j.at("value").get_to(p.value); - j.at("default_value").get_to(p.default_value); - j.at("type").get_to(p.type); - j.at("required").get_to(p.required); + void from_json(const json &j, ProjectPrompt &p){ + j.contains("value") ? j.at("value").get_to(p.value) : p.value = ""; + j.contains("default_value") ? j.at("default_value").get_to(p.default_value) : p.default_value = ""; + j.contains("required") ? j.at("required").get_to(p.required) : p.required = false; + j.contains("type") ? j.at("type").get_to(p.type) : p.type = "string"; + j.contains("options") ? j.at("options").get_to(p.options) : p.options = {}; //j.at("validator").get_to(p.validator); need a way to make this a lua function } template<> diff --git a/src/Command/Helpers/Template.cpp b/src/Command/Helpers/Template.cpp new file mode 100644 index 0000000..2f926cd --- /dev/null +++ b/src/Command/Helpers/Template.cpp @@ -0,0 +1,71 @@ +#include +#include + + +namespace Frate::Command { + + Template::Template(){ + + } + void from_json(const json &j, Template& t){ + Utils::info << "Template from json" << std::endl; + t.name = j["name"]; + t.description = j["description"]; + t.version = j["version"]; + t.src_dir = j["src_dir"]; + t.include_dir = j["include_dir"]; + t.build_dir = j["build_dir"]; + t.dependencies = j["dependencies"].get>(); + t.default_mode = j["default_mode"]; + t.modes = j["modes"].get>(); + t.flags = j["flags"].get>(); + t.system_libs = j["system_libs"].get>(); + t.supported_toolchains = j["supported_toolchains"].get>(); + t.supported_languages = j["supported_languages"].get>(); + t.supported_language_versions = j["supported_language_versions"].get>(); + t.min_cmake_version = j["min_cmake_version"]; + t.supported_compilers = j["supported_compilers"].get>(); + t.keywords = j["keywords"].get>(); + t.prompts = j["prompts"].get>(); + t.variables = j["variables"].get>(); + Utils::info << "Template from json end" << std::endl; + } + + void to_json(json &j, const Template& t){ + Utils::info << "Template to json" << std::endl; + j["name"] = t.name; + j["description"] = t.description; + j["version"] = t.version; + j["src_dir"] = t.src_dir; + j["include_dir"] = t.include_dir; + j["build_dir"] = t.build_dir; + j["dependencies"] = t.dependencies; + j["default_mode"] = t.default_mode; + j["modes"] = t.modes; + j["flags"] = t.flags; + j["system_libs"] = t.system_libs; + j["supported_toolchains"] = t.supported_toolchains; + j["supported_languages"] = t.supported_languages; + j["supported_languages_versions"] = t.supported_language_versions; + j["min_cmake_version"] = t.min_cmake_version; + j["supported_compilers"] = t.supported_compilers; + j["keywords"] = t.keywords; + j["prompts"] = t.prompts; + j["variables"] = t.variables; + Utils::info << "Template to json end" << std::endl; + } + + void to_projet(Project &pro, const Template &t){ + Utils::info << "Template to project" << std::endl; + pro.name = t.name; + pro.description = t.description; + pro.version = t.version; + pro.src_dir = t.src_dir; + pro.include_dir = t.include_dir; + pro.build_dir = t.build_dir; + pro.dependencies = t.dependencies; + pro.default_mode = t.default_mode; + pro.modes = t.modes; + Utils::info << "Template to project end" << std::endl; + } +}; diff --git a/src/Command/Modes/CommandModes.cpp b/src/Command/Modes/CommandModes.cpp index b57eadf..a54cd1b 100644 --- a/src/Command/Modes/CommandModes.cpp +++ b/src/Command/Modes/CommandModes.cpp @@ -36,9 +36,6 @@ namespace Frate:: Command::Modes{ interface->pro->modes.push_back(mode); - std::cout << "Writing frate-project.json" << std::endl; - - if(!interface->pro->save()) return false; return true; } @@ -49,7 +46,6 @@ namespace Frate:: Command::Modes{ std::erase_if(inter->pro->modes, [&mode_name](Mode &mode){ return mode.name == mode_name; }); - if(!inter->pro->save()) return false; return true; } diff --git a/src/Command/Package/Package.cpp b/src/Command/Package/Package.cpp index a9b5453..ae2d78d 100644 --- a/src/Command/Package/Package.cpp +++ b/src/Command/Package/Package.cpp @@ -41,14 +41,12 @@ namespace Frate::Command::Packages { std::pair getExact(std::string query){ json index = fetchIndex(); - Package package; - for(json pi: index){ - package.fromJson(pi); - if(package.name == query){ - return {true, package}; + for(Package pi: index){ + if(pi.name == query){ + return {true, pi}; } } - return {false, package}; + return {false, {}}; } } @@ -57,58 +55,58 @@ namespace Frate::Command::Packages { namespace Frate::Command { using nlohmann::json; - json Package::toJson() { - json data; - data["name"] = this->name; - data["versions"] = this->versions; - data["description"] = this->description; - data["target_link"] = this->target_link; - data["git"] = this->git; - data["git_short"] = this->git_short; - data["git_prefixed"] = this->git_prefixed; - data["selected_version"] = this->selected_version; - data["git_description"] = this->git_description; - data["language"] = this->language; - data["license"] = this->license; - data["owner"] = this->owner; - data["owner_type"] = this->owner_type; - data["stars"] = this->stars; - data["forks"] = this->forks; - data["open_issues"] = this->open_issues; - data["watchers"] = this->watchers; - return data; - } - - void Package::fromJson(json data) { - this->name = data["name"]; - - if(data["versions"].is_null()){ - this->versions = {"master"}; - }else{ - this->versions = data["versions"]; - } - - this->description = data["description"]; - - if(target_link == ""){ - this->target_link = this->name; - }else{ - this->target_link = data["target_link"]; - } - - this->git = data["git"]; - this->git_short = data["git_short"]; - this->git_prefixed = data["git_prefixed"]; - this->git_description = data["git_description"]; - this->language = data["language"]; - this->license = data["license"]; - this->owner = data["owner"]; - this->owner_type = data["owner_type"]; - this->stars = data["stars"].get(); - this->forks = data["forks"].get(); - this->open_issues = data["open_issues"].get(); - this->watchers = data["watchers"].get(); - - } +// json Package::toJson() { +// json data; +// data["name"] = this->name; +// data["versions"] = this->versions; +// data["description"] = this->description; +// data["target_link"] = this->target_link; +// data["git"] = this->git; +// data["git_short"] = this->git_short; +// data["git_prefixed"] = this->git_prefixed; +// data["selected_version"] = this->selected_version; +// data["git_description"] = this->git_description; +// data["language"] = this->language; +// data["license"] = this->license; +// data["owner"] = this->owner; +// data["owner_type"] = this->owner_type; +// data["stars"] = this->stars; +// data["forks"] = this->forks; +// data["open_issues"] = this->open_issues; +// data["watchers"] = this->watchers; +// return data; +// } +// +// void Package::fromJson(json data) { +// this->name = data["name"]; +// +// if(data["versions"].is_null()){ +// this->versions = {"master"}; +// }else{ +// this->versions = data["versions"]; +// } +// +// this->description = data["description"]; +// +// if(target_link == ""){ +// this->target_link = this->name; +// }else{ +// this->target_link = data["target_link"]; +// } +// +// this->git = data["git"]; +// this->git_short = data["git_short"]; +// this->git_prefixed = data["git_prefixed"]; +// this->git_description = data["git_description"]; +// this->language = data["language"]; +// this->license = data["license"]; +// this->owner = data["owner"]; +// this->owner_type = data["owner_type"]; +// this->stars = data["stars"].get(); +// this->forks = data["forks"].get(); +// this->open_issues = data["open_issues"].get(); +// this->watchers = data["watchers"].get(); +// +// } } diff --git a/src/Command/Package/SearchPackages.cpp b/src/Command/Package/SearchPackages.cpp index b5778cd..636982b 100644 --- a/src/Command/Package/SearchPackages.cpp +++ b/src/Command/Package/SearchPackages.cpp @@ -12,9 +12,7 @@ namespace Frate::Command::Packages { Utils::toLower(query); - for(json json: rawIndex){ - Package package; - package.fromJson(json); + for(Package package: rawIndex){ int score = 0; score += Utils::getStringScore(package.name, query) * 10; @@ -29,11 +27,14 @@ namespace Frate::Command::Packages { std::sort(results.begin(), results.end(), [](Package a, Package b){ return a.score > b.score; }); + return results; } std::vector filterOutBest(std::vector &packages){ + std::vector filterResultsVec; + int totalScore = std::accumulate( packages.begin(), packages.end(), 0, [](int a, Package b){ return a + b.score; @@ -41,12 +42,12 @@ namespace Frate::Command::Packages { int averageScore = totalScore / packages.size(); - auto filterResults = packages | std::views::filter( - [&averageScore](Package package){ - return package.score > 2 * averageScore; - }); + for(Package package: packages){ + if(package.score > averageScore){ + filterResultsVec.push_back(package); + } + } - std::vector filterResultsVec(filterResults.begin(), filterResults.end()); return filterResultsVec; } @@ -54,9 +55,7 @@ namespace Frate::Command::Packages { std::pair getExactMatch(std::string &query){ json rawIndex = fetchIndex(); Utils::toLower(query); - for(json json: rawIndex){ - Package package; - package.fromJson(json); + for(Package package: rawIndex){ if(package.name == query){ return {true, package}; } diff --git a/src/Command/RemoteServers/RemoteServer.cpp b/src/Command/RemoteServers/RemoteServer.cpp index 34625f4..613724b 100644 --- a/src/Command/RemoteServers/RemoteServer.cpp +++ b/src/Command/RemoteServers/RemoteServer.cpp @@ -18,7 +18,14 @@ namespace Frate::Command::RemoteServers{ std::fstream file; std::string build_servers_dir= std::string(std::getenv("HOME")) + "/.config/frate/"; if (!std::filesystem::exists(build_servers_dir)){ - std::filesystem::create_directory(build_servers_dir); + try{ + std::filesystem::create_directory(build_servers_dir); + }catch(std::exception &e){ + Utils::debug(e.what()); + Utils::error << + "Error while creating directory: " << build_servers_dir << std::endl; + exit(1); + } } std::string build_servers= std::string(std::getenv("HOME")) + "/.config/frate/" + "build_server.json"; std::string current_build_server= std::string(std::getenv("HOME")) + "/.config/frate/" + "current_build_server.json"; diff --git a/src/Command/Toolchains/CommandToolchains.cpp b/src/Command/Toolchains/CommandToolchains.cpp index 7a1e793..69bd324 100644 --- a/src/Command/Toolchains/CommandToolchains.cpp +++ b/src/Command/Toolchains/CommandToolchains.cpp @@ -34,7 +34,12 @@ namespace Frate::Command::Toolchains{ Generators::Toolchain::generateToolchain(toolchain); std::ofstream file; if (!std::filesystem::exists(inter->pro->path / "toolchains/")){ - std::filesystem::create_directory(inter->pro->path / "toolchains/"); + try{ + std::filesystem::create_directory(inter->pro->path / "toolchains/"); + }catch(...){ + Utils::error << "Error while creating toolchains directory" << std::endl; + return false; + } } file.open(inter->pro->path / "toolchains/" / (toolchain + ".cmake")); diff --git a/src/Generators/CMakeTemplates.cpp b/src/Generators/CMakeTemplates.cpp index 00eddf8..130592c 100644 --- a/src/Generators/CMakeTemplates.cpp +++ b/src/Generators/CMakeTemplates.cpp @@ -18,7 +18,7 @@ namespace Frate::Generators::CMakeList { #ifdef DEBUG #ifndef TEST - std::cout << pro->toJson().dump(2) << std::endl; + std::cout << json(*pro).dump(2) << std::endl; #endif #endif std::string CPM = Utils::fetchText("https://raw.githubusercontent.com/cpm-cmake/CPM.cmake/v0.38.6/cmake/CPM.cmake"); @@ -41,7 +41,7 @@ namespace Frate::Generators::CMakeList { Utils::debug("Error while registering project"); return false; } - + if(!LuaAPI::registerProjectScripts(env, lua,pro->path / "templates/scripts",pro)){ Utils::debug("Error while registering project scripts"); return false; @@ -51,7 +51,7 @@ namespace Frate::Generators::CMakeList { std::string CMakeListsExecutable; try{ - CMakeListsExecutable = env.render_file(pro->path /"templates" / "CMakeLists.txt.inja", pro->toJson()); + CMakeListsExecutable = env.render_file(pro->path /"templates" / "CMakeLists.txt.inja", *pro); }catch(...){ Utils::debug("Error while rendering CMakeLists.txt"); return false; diff --git a/src/Generators/ConfigJsonGenerator.cpp b/src/Generators/ConfigJsonGenerator.cpp index c52e23d..21144b4 100644 --- a/src/Generators/ConfigJsonGenerator.cpp +++ b/src/Generators/ConfigJsonGenerator.cpp @@ -10,7 +10,7 @@ namespace Frate::Generators::ConfigJson{ std::ofstream file; std::string file_name = "frate-project.json"; file.open(pro->path / file_name); - file << pro->toJson().dump(2); + file << nlohmann::json(*pro).dump(2); file << '\n'; file.close(); return true; diff --git a/src/Generators/ProjectGenerator/DownloadTemplates.cpp b/src/Generators/ProjectGenerator/DownloadTemplates.cpp index 53dea89..e0f6fa6 100644 --- a/src/Generators/ProjectGenerator/DownloadTemplates.cpp +++ b/src/Generators/ProjectGenerator/DownloadTemplates.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -16,47 +17,91 @@ namespace Frate::Generators::Project { std::filesystem::remove_all(project_path / "template"); } - std::filesystem::create_directories(project_path / "template"); - - - Utils::info << "Downloading template" << std::endl; - git_repository* template_repo = NULL; - git_repository* callbacks_repo = NULL; - Utils::info << "Cloning " << git_url << " into " - << (project_path / "template").c_str() << std::endl; - - - int template_clone_status = git_clone(&template_repo, - git_url.c_str(), (project_path / "template").c_str(), NULL); + try{ + std::filesystem::create_directories(project_path / "template"); - if(template_clone_status != 0){ - Utils::error << "Error while cloning repository" << std::endl; + }catch(...){ + Utils::error << "Error while creating template directory" << std::endl; return false; } - - git_repository_free(template_repo); +// git_libgit2_init(); +// const git_error *template_clone_err; +// Utils::info << "Downloading template" << std::endl; +// git_repository* template_repo = NULL; +// git_repository* callbacks_repo = NULL; +// Utils::info << "Cloning " << git_url << " into " +// << (project_path / "template").c_str() << std::endl; +// +// +// int template_clone_status = git_clone(&template_repo, +// git_url.c_str(), (project_path / "template").c_str(), NULL); +// +// +// if(template_clone_status != 0){ +// template_clone_err = git_error_last(); +// Utils::error << "Clone status code: " << template_clone_status << std::endl; +// if(template_clone_err){ +// Utils::error << "Error while cloning repository error code: " << template_clone_err->klass << std::endl; +// }else{ +// Utils::error << "Error while cloning repository" << std::endl; +// } +// return false; +// } +// +// +// git_repository_free(template_repo); +// +// +// Utils::info << "Cloning " << callbacks_url << " into " +// << (project_path / "template/frate-callbacks").c_str() << std::endl; +// +// const git_error *callbacks_clone_err; +// int callbacks_clone_status= git_clone(&callbacks_repo, +// callbacks_url.c_str(), +// (project_path / "template/frate-callbacks").c_str(), NULL); +// +// +// if(callbacks_clone_status != 0){ +// callbacks_clone_err = git_error_last(); +// Utils::error << "Clone status code: " << callbacks_clone_status << std::endl; +// if(callbacks_clone_err){ +// Utils::error << "Error while cloning repository error code: " << callbacks_clone_err->klass << std::endl; +// }else{ +// Utils::error << "Error while cloning repository" << std::endl; +// } +// return false; +// } +// +// +// git_repository_free(callbacks_repo); +// +// git_libgit2_shutdown(); + + int status = Utils::hSystem( + "git clone -b " + + Constants::TEMPLATE_BRANCH + " " + + git_url + " " + (project_path / "template").string() + ); + if(status != 0){ + Utils::error << "Error while cloning template repo" << std::endl; + return false; + } const std::string callbacks_url = "https://github.com/frate-templates/frate-callbacks.git"; - - Utils::info << "Cloning " << callbacks_url << " into " - << (project_path / "template/frate-callbacks").c_str() << std::endl; - - - int callbacks_clone_status= git_clone(&callbacks_repo, - callbacks_url.c_str(), - (project_path / "template/frate-callbacks").c_str(), NULL); - - - if(callbacks_clone_status != 0){ - Utils::error << "Error while cloning repository" << std::endl; + status = Utils::hSystem( + "git clone -b " + + Constants::TEMPLATE_BRANCH + " " + + std::string(callbacks_url) + " " + + (project_path / "template/frate-callbacks").string() + ); + + if(status != 0){ + Utils::error << "Error while cloning callback repository" << std::endl; return false; } - - git_repository_free(callbacks_repo); - std::filesystem::rename(project_path / "template/frate-callbacks/scripts", project_path / "template/scripts"); diff --git a/src/Generators/ProjectGenerator/InitializeLua.cpp b/src/Generators/ProjectGenerator/InitializeLua.cpp index 1b23190..876b8c0 100644 --- a/src/Generators/ProjectGenerator/InitializeLua.cpp +++ b/src/Generators/ProjectGenerator/InitializeLua.cpp @@ -7,10 +7,12 @@ namespace Frate::Generators::Project { using inja::Environment; bool initializeLua(Environment &env, sol::state &lua, std::shared_ptr pro){ LuaAPI::registerAPI(lua); + Utils::info << "Registering project" << std::endl; if(!LuaAPI::registerProject(lua, pro)){ Utils::error << "Error while registering project" << std::endl; return false; } + Utils::info << "Registering project scripts at: " << pro->path / "template/scripts" << std::endl; if(!LuaAPI::registerProjectScripts(env,lua, pro->path / "template/scripts", pro)){ Utils::error << "Error while registering project scripts" << std::endl; return false; diff --git a/src/Generators/ProjectGenerator/LoadTemplateConfig.cpp b/src/Generators/ProjectGenerator/LoadTemplateConfig.cpp index 23db839..d8c5a41 100644 --- a/src/Generators/ProjectGenerator/LoadTemplateConfig.cpp +++ b/src/Generators/ProjectGenerator/LoadTemplateConfig.cpp @@ -10,41 +10,62 @@ namespace Frate::Generators::Project { bool loadTemplateConfig(std::shared_ptr pro){ +// try{ +// +// std::filesystem::copy( +// pro->path / "template/default.json", +// pro->path / "frate-project.json" +// ); +// +// }catch(...){ +// +// Utils::error << "Error while copying frate-project.json" << std::endl; +// return false; +// +// } +// +// +// std::ifstream file; +// +// +// try{ +// +// file.open(pro->path / "frate-project.json"); +// +// }catch(...){ +// +// Utils::error << "Error while opening file: " << pro->path / "frate-project.json" << std::endl; +// return false; +// +// } + + std::ifstream template_config_file; + try{ - std::filesystem::copy( - pro->path / "template/default.json", - pro->path / "frate-project.json" - ); + template_config_file.open(pro->path / "template/template.json"); }catch(...){ - Utils::error << "Error while copying frate-project.json" << std::endl; + Utils::error << "Error while opening file: " << pro->path / "template/template.json" << std::endl; return false; } - - - std::ifstream file; - try{ + json j = json::parse(template_config_file); - file.open(pro->path / "frate-project.json"); - - }catch(...){ - - Utils::error << "Error while opening file: " << pro->path / "frate-project.json" << std::endl; - return false; - - } + Command::Template template_config = j; - json current_j = pro->toJson(); - json j = json::parse(file); + //Utils::verbose << "Template config: " << nlohmann::json(template_config).dump(2) << std::endl; - j.merge_patch(current_j); + pro->fromTemplate(template_config); - pro->fromJson(j); +// Utils::info << "Merging frate-project.json" << std::endl; +// +// current_j.merge_patch(j); +// +// pro = std::make_shared(current_j); return true; diff --git a/src/Generators/ProjectGenerator/ProjectGenerator.cpp b/src/Generators/ProjectGenerator/ProjectGenerator.cpp index 556e141..20a813f 100644 --- a/src/Generators/ProjectGenerator/ProjectGenerator.cpp +++ b/src/Generators/ProjectGenerator/ProjectGenerator.cpp @@ -48,23 +48,24 @@ namespace Frate::Generators::Project { current_template = templ; Utils::info << "Creating project from template: " << templ.name << std::endl; } - + Utils::info << "Downloading template at: " << current_template.git << std::endl; if(!downloadTemplate(current_template.git, pro->path)){ Utils::error << "Error while downloading template" << std::endl; return false; } - + + Utils::info << "Copying template to project" << std::endl; std::filesystem::copy( pro->path / "template", pro->path, std::filesystem::copy_options::recursive | std::filesystem::copy_options::overwrite_existing ); - + Utils::info << "Loading template config" << std::endl; if(!loadTemplateConfig(pro)){ Utils::error << "Error while loading template config" << std::endl; return false; } - + Utils::info << "Running template prompts" << std::endl; if(!runTemplatePrompts(pro)){ Utils::error << "Error while running template prompts" << std::endl; return false; @@ -73,13 +74,15 @@ namespace Frate::Generators::Project { inja::Environment env; sol::state lua; + Utils::info << "Initializing lua" << std::endl; if(!initializeLua(env, lua, pro)){ Utils::error << "Error while initializing lua" << std::endl; return false; } LuaAPI::initScripts(lua, pro); - + + Utils::info << "Rendering template" << std::endl; if(!renderTemplate(env, pro)){ Utils::error << "Error while rendering template to tmp" << std::endl; return false; @@ -96,14 +99,15 @@ namespace Frate::Generators::Project { inja::Environment env; sol::state lua; - if(!initializeLua(env, lua, pro)){ Utils::error << "Error while initializing lua" << std::endl; return false; } + Utils::verbose << "Initializing lua scripts at: " << pro->path / "template/scripts" << std::endl; LuaAPI::initScripts(lua, pro); + Utils::verbose << "Refreshing template" << std::endl; if(!refreshTemplate(env,pro)){ Utils::error << "Error while rendering template to tmp" << std::endl; return false; diff --git a/src/Generators/ProjectGenerator/RefreshTemplates.cpp b/src/Generators/ProjectGenerator/RefreshTemplates.cpp index f3d54a5..d152204 100644 --- a/src/Generators/ProjectGenerator/RefreshTemplates.cpp +++ b/src/Generators/ProjectGenerator/RefreshTemplates.cpp @@ -11,7 +11,7 @@ namespace Frate::Generators::Project { }; for(const path& current_p: paths_to_refresh){ - std::string rendered_file = env.render_file(current_p, pro->toJson()); + std::string rendered_file = env.render_file(current_p, *pro); std::string new_file = current_p.string(); new_file = new_file.replace(new_file.find(".inja"), 5, ""); Utils::replaceKey(new_file, "template/", ""); diff --git a/src/Generators/ProjectGenerator/RenderTemplate.cpp b/src/Generators/ProjectGenerator/RenderTemplate.cpp index 5750d93..53903d1 100644 --- a/src/Generators/ProjectGenerator/RenderTemplate.cpp +++ b/src/Generators/ProjectGenerator/RenderTemplate.cpp @@ -9,8 +9,6 @@ namespace Frate::Generators::Project { std::shared_ptr pro){ - Utils::info << "Rendering templates" << std::endl; - std::string CPM; CPM = Utils::fetchText("https://raw.githubusercontent.com/cpm-cmake/CPM.cmake/v0.38.6/cmake/CPM.cmake"); @@ -69,7 +67,7 @@ namespace Frate::Generators::Project { continue; } if(current_p.extension() == ".inja"){ - std::string rendered_file = env.render_file(current_p, pro->toJson()); + std::string rendered_file = env.render_file(current_p, *pro); std::string new_file = current_p.string(); //Removes the .inja extension from the file new_file = new_file.replace(new_file.find(".inja"), 5, ""); diff --git a/src/Lua/API.cpp b/src/Lua/API.cpp index 241bc59..f87e6bc 100644 --- a/src/Lua/API.cpp +++ b/src/Lua/API.cpp @@ -5,47 +5,52 @@ #include #include #include -#include +#include #include - +#include namespace Frate::LuaAPI { -using Command::Project; -using std::filesystem::path; + using Command::Project; + using std::filesystem::path; bool registerProjectScripts(inja::Environment &env, sol::state &lua, path script_path, std::shared_ptr project) { + std::unordered_map scripts = {}; sol::table global_table = to_table(project->variables,lua); lua.set("global", global_table); + try{ + for (const std::filesystem::path &p : + std::filesystem::recursive_directory_iterator(script_path)) { + if (p.extension() == ".lua") { + std::string file_name = p.filename(); + std::string full_script_path = p.string(); + // Yoinkin off the lua extension + file_name = file_name.substr(0, file_name.find(".lua")); - for (const std::filesystem::path &p : - std::filesystem::recursive_directory_iterator(script_path)) { - if (p.extension() == ".lua") { - std::string file_name = p.filename(); - std::string full_script_path = p.string(); - // Yoinkin off the lua extension - file_name = file_name.substr(0, file_name.find(".lua")); - - std::string prefix; + std::string prefix; - // Remove the script path - Utils::replaceKey(full_script_path, script_path.string(), ""); + // Remove the script path + Utils::replaceKey(full_script_path, script_path.string(), ""); - // Remove the file name - Utils::replaceKey(full_script_path, file_name + ".lua", ""); + // Remove the file name + Utils::replaceKey(full_script_path, file_name + ".lua", ""); - // Remove the first slash - Utils::replaceKey(full_script_path, "/", "."); + // Remove the first slash + Utils::replaceKey(full_script_path, "/", "."); - // Remove the first dot - full_script_path = full_script_path.substr(1, full_script_path.size()); + // Remove the first dot + full_script_path = full_script_path.substr(1, full_script_path.size()); - prefix = full_script_path; + prefix = full_script_path; - scripts[prefix + file_name] = p.string(); + scripts[prefix + file_name] = p.string(); + } } + }catch(...){ + Utils::error << "Error while iterating over scripts" << std::endl; + return false; } @@ -156,6 +161,7 @@ bool registerProjectScripts(inja::Environment &env, sol::state &lua, path script_path = project->path / (Constants::TEMPLATE_PATH + Constants::POST_SCRIPTS_PATH); + if(!std::filesystem::exists(script_path)){ Utils::verbose << "No post scripts found" << " at: " << script_path << std::endl; return false; diff --git a/src/Reflection/Mode.cpp b/src/Reflection/Mode.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/Reflection/Package.cpp b/src/Reflection/Package.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/Reflection/Project.cpp b/src/Reflection/Project.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/Reflection/ProjectPrompt.cpp b/src/Reflection/ProjectPrompt.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/Reflection/RemoteServer.cpp b/src/Reflection/RemoteServer.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/Test/Commands/Mode/TestAddModeSingle.cpp b/src/Test/Commands/Mode/TestAddModeSingle.cpp index c5cdf1f..63531e9 100644 --- a/src/Test/Commands/Mode/TestAddModeSingle.cpp +++ b/src/Test/Commands/Mode/TestAddModeSingle.cpp @@ -10,7 +10,7 @@ bool Tests::Command::testAddMode(std::string mode_name){ if(failed) return false; - nlohmann::json config = inter->pro->toJson(); + nlohmann::json config = *inter->pro; for(auto &mode : config["modes"]){ if(mode["name"] == mode_name){ diff --git a/src/Test/Commands/Package/TestAddPackageMultiple.cpp b/src/Test/Commands/Package/TestAddPackageMultiple.cpp index b3cdf12..c916e67 100644 --- a/src/Test/Commands/Package/TestAddPackageMultiple.cpp +++ b/src/Test/Commands/Package/TestAddPackageMultiple.cpp @@ -21,7 +21,7 @@ bool Tests::Command::testAddPackageMultiple(std::vector packages) { if(failed) return false; - nlohmann::json config = inter->pro->toJson(); + nlohmann::json config = *inter->pro; std::vector> package_results; diff --git a/src/Test/Commands/Package/TestAddPackageWithDuplicate.cpp b/src/Test/Commands/Package/TestAddPackageWithDuplicate.cpp index 53bcc6c..da02a73 100644 --- a/src/Test/Commands/Package/TestAddPackageWithDuplicate.cpp +++ b/src/Test/Commands/Package/TestAddPackageWithDuplicate.cpp @@ -10,14 +10,14 @@ namespace Tests::Command { auto [failed, inter] = init("frate add package " + package_name + " -l"); if(failed){ - error << "Failed to add package" << std::endl; + Frate::Utils::error << "Failed to add package" << std::endl; return false; } auto [failed_dup, inter_dup] = init("frate add package " + package_name + " -l"); if(!failed_dup){ - error << "Failed to detect duplicate package" << std::endl; + Frate::Utils::error << "Failed to detect duplicate package" << std::endl; return false; } diff --git a/src/Test/Commands/Package/TestAddPackageWithMode.cpp b/src/Test/Commands/Package/TestAddPackageWithMode.cpp index 735aeb8..cfff0d5 100644 --- a/src/Test/Commands/Package/TestAddPackageWithMode.cpp +++ b/src/Test/Commands/Package/TestAddPackageWithMode.cpp @@ -14,7 +14,7 @@ bool Tests::Command::testAddPackageToMode(std::string mode_name, std::string pac return false; } - json config = inter->pro->toJson(); + json config = *inter->pro; for(json mode : config["modes"]){ if(mode["name"] == mode_name){ diff --git a/src/Test/Commands/Package/TestRemovePackageMultiple.cpp b/src/Test/Commands/Package/TestRemovePackageMultiple.cpp index 46afda3..185758f 100644 --- a/src/Test/Commands/Package/TestRemovePackageMultiple.cpp +++ b/src/Test/Commands/Package/TestRemovePackageMultiple.cpp @@ -18,7 +18,7 @@ namespace Tests::Command { if(failed) return false; - nlohmann::json config = inter->pro->toJson(); + nlohmann::json config = *inter->pro; for(auto &dep : config["dependencies"]){ for(auto &p : packages){ diff --git a/src/Test/Commands/TestCommandUtils.cpp b/src/Test/Commands/TestCommandUtils.cpp index dc76c70..27974de 100644 --- a/src/Test/Commands/TestCommandUtils.cpp +++ b/src/Test/Commands/TestCommandUtils.cpp @@ -3,13 +3,12 @@ #include #include #include +#include namespace Tests::Command { using std::filesystem::path; + using Frate::Command::Interface; - extern Frate::Utils::Error error =Frate::Utils::Error(); - extern Frate::Utils::Info info =Frate::Utils::Info(); - extern Frate::Utils::Warning warning =Frate::Utils::Warning(); std::filesystem::path genTestDirectory(){ Frate::Utils::info << "Generating test directory" << std::endl; @@ -23,7 +22,13 @@ namespace Tests::Command { std::filesystem::path("/tmp/frate-test-" + random_string); } - std::filesystem::create_directory(test_path); + try{ + std::filesystem::create_directory(test_path); + }catch(...){ + Frate::Utils::error << "Failed to create test directory" << std::endl; + return ""; + } + Frate::Utils::info << "Test directory generated at" << test_path << std::endl; return test_path; } @@ -69,20 +74,22 @@ namespace Tests::Command { return std::make_pair(command_split.size(), argv); } - std::pair init(std::string command,bool check_config) { + std::pair> init(std::string command,bool check_config) { auto [argc, argv] = genCommand(command); - Frate::Command::Interface *inter = new Frate::Command::Interface(argc, argv); + Frate::Command::Interface inter(argc, argv); + + std::shared_ptr inter_ptr = std::make_shared(inter); - inter->pro->path = std::filesystem::path(test_path); - if (!Frate::Command::execute( - std::make_shared(*inter))) { + inter.pro->path = std::filesystem::path(test_path); + + if (!Frate::Command::execute(inter_ptr)) { Frate::Utils::error << "Failed to run command: " << command << " : could not execute" << std::endl; - return std::make_pair(true,inter); + return std::make_pair(true,inter_ptr); } if(check_config){ std::ifstream config_file(test_path / "frate-project.json"); @@ -90,26 +97,15 @@ namespace Tests::Command { if(!std::filesystem::exists(test_path / "frate-project.json")){ Frate::Utils::error << "Failed to run command : " << command << " : no config file" << std::endl; - return std::make_pair(true,inter); + return std::make_pair(true,inter_ptr); } - - // try { - // Frate::Utils::info << "attempting to read config file" << std::endl; - // config_file >> config; - // } catch (...) { - // Frate::Utils::error << - // "Failed to add package : could not open file - file possibly never created" - // << std::endl; - // return std::make_pair(true,inter); - // } - - if(!validateProjectJson(inter)){ + if(!validateProjectJson(inter_ptr)){ Frate::Utils::error << "Failed to run command : " << command << " : invalid json" << std::endl; - return std::make_pair(true,inter); + return std::make_pair(true,inter_ptr); } } - return std::make_pair(false,inter); + return std::make_pair(false,inter_ptr); } } diff --git a/src/Test/Commands/TestValidateProjectJson.cpp b/src/Test/Commands/TestValidateProjectJson.cpp index b6f69b4..8aa29b1 100644 --- a/src/Test/Commands/TestValidateProjectJson.cpp +++ b/src/Test/Commands/TestValidateProjectJson.cpp @@ -6,7 +6,8 @@ namespace Tests::Command { - bool validateProjectJson(Frate::Command::Interface* inter){ + using Frate::Command::Interface; + bool validateProjectJson(std::shared_ptr inter){ Frate::Utils::Error error; Frate::Utils::Info info; bool valid = true; diff --git a/src/Test/TestCommands.cpp b/src/Test/TestCommands.cpp index 1eeb482..8d48bd6 100644 --- a/src/Test/TestCommands.cpp +++ b/src/Test/TestCommands.cpp @@ -37,11 +37,6 @@ namespace Tests::Command { REQUIRE(testNewWithLang("cpp")); REQUIRE(testNewWithLang("c")); - REQUIRE(testAddFlagsSingle()); - REQUIRE(testAddFlagsMultiple()); - REQUIRE(testAddFlagsWithMode()); - REQUIRE(testRemoveFlagsSingle("-Wall")); - REQUIRE(testRemoveFlagsSingle("-Wall -Werror")); REQUIRE(testNewWithType("executable")); //TODO: Add more types @@ -49,6 +44,12 @@ namespace Tests::Command { // REQUIRE(testNewWithType("shared_library")); // REQUIRE(testNewWithType("header_only")); + REQUIRE(testAddFlagsSingle()); + REQUIRE(testAddFlagsMultiple()); + REQUIRE(testAddFlagsWithMode()); + REQUIRE(testRemoveFlagsSingle("-Wall")); + REQUIRE(testRemoveFlagsSingle("-Wall -Werror")); + REQUIRE(testAddPackage("cxxopts")); REQUIRE(testAddPackageMultiple({"cxxopts","fmt","SDL2"})); REQUIRE(testAddPackageWithDuplicate("cxxopts"));