Files
vystem-b/vybuild/vybuild.hpp
2026-05-27 19:34:54 +02:00

1023 lines
55 KiB
C++

// SPDX-License-Identifier: MPL-2.0
#ifndef VYBUILD_LIB_H
#define VYBUILD_LIB_H
#include <string>
#include <fstream>
#include <filesystem>
#include <iostream>
#include <variant>
#include <vector>
#include <unistd.h>
#include <limits.h>
#include "json.hpp"
#include "xxhash.h"
#include <uuid/uuid.h>
using json=nlohmann::json;
namespace fs=std::filesystem;
const std::string syntax_version="0.1";
const std::vector<std::string> threaded_actions={"run_submodule","run_submodule_if","run_actions_parallel","vyld_compilation","run_submodule_parallel","compile_multiple_cpp"};
namespace vybuild {
namespace fat32 {
void load_crypto_lib(std::string path);
bool is_crypto_lib_loaded();
bool is_vftm_target_set();
uint8_t* get_manifest_keypair_buffer();
void create_fat32(std::string key,size_t size);
void add_directory_fat32(std::string key,std::string full_path);
void add_file_fat32(std::string key,std::string full_path,uint8_t *buffer_in,size_t file_size,bool is_vftm_target);
std::vector<uint8_t> export_fat32(std::string key,bool generate_vftm,std::string disk_guid_var,std::string efi_part_unique_guid_var);
}
namespace disk {
std::array<uint8_t,16> uuid4_to_bytes(const std::string& uuid);
void create_disk(std::string key,size_t size,std::string disk_guid);
void add_partition(std::string key,size_t partition_size_bytes,std::string type_guid,std::string unique_guid,uint64_t attributes,std::string name,uint8_t* in_buf,size_t in_size);
std::vector<uint8_t> export_disk(std::string key);
}
namespace condition {
bool evaluate_condition(const json& condition);
}
namespace parser {
std::string root_folder_parsing(const std::string& root_folder,const std::string& file);
std::vector<std::string> vector_string_vars(std::vector<std::string> vector_in);
std::string string_vars(std::string string_in);
std::vector<std::string> vector_string_path_completions(std::vector<std::string> vector_in,std::string suffix);
}
namespace vars {
std::vector<std::string>& get_global_variables_list();
void set_global_variable(std::string key,std::string value);
std::string get_global_variable(std::string key);
}
namespace cache {
void init_cache(bool enable_smart_cache);
void store_file(std::string key,fs::path file_path);
bool cache_contains(std::string key);
void extract_file(std::string key,fs::path output_path);
void clean_cache();
std::string xxhash_to_string(XXH128_hash_t hash);
}
namespace actions {
void check_arg_string(const json& args,std::string field_name);
void check_arg_vector_string(const json& args,std::string field_name);
enum class ActionStatus {
Success,
Fail,
SystemError,
ExitSuccess,
ExitFail
};
class RunSubmoduleAction {
public:
RunSubmoduleAction(const json& args,std::string root_folder) {
char path[PATH_MAX];
getcwd(path,sizeof(path));
chdir(root_folder.c_str());
check_arg_string(args,"file");
if (!args.contains("wait")) throw std::runtime_error("Wait isn't provided.");
if (!args["wait"].is_boolean()) throw std::runtime_error("Wait isn't a boolean");
if (!args.contains("block_if_fail")) throw std::runtime_error("Block if fail isn't provided.");
if (!args["block_if_fail"].is_boolean()) throw std::runtime_error("Block if fail isn't a boolean");
this->file_variables=args["file_variables"].get<bool>();
this->file=args["file"].get<std::string>();
this->wait=args["wait"].get<bool>();
this->block_if_fail=args["block_if_fail"].get<bool>();
chdir(path);
}
bool file_variables;
std::string file;
bool wait;
bool block_if_fail;
ActionStatus run_action();
};
class RunCommandWaitAction {
public:
RunCommandWaitAction(const json& args) {
check_arg_vector_string(args,"command");
if (!args.contains("show_output")) throw std::runtime_error("Show output isn't provided.");
if (!args["show_output"].is_string()) throw std::runtime_error("Show output isn't a string");
if (args["show_output"]!="live" && args["show_output"]!="on_failure" && args["show_output"]!="silent") {
throw std::runtime_error("\""+args["show_output"].get<std::string>()+"\" isn't a valid output mode.");
}
if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided.");
if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean");
for (auto& arg:args["success_status"]) {
if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer.");
}
if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided.");
if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean");
this->command_variables=args["command_variables"].get<bool>();
this->command=args["command"].get<std::vector<std::string>>();
this->show_output=args["show_output"].get<std::string>();
this->success_status=args["success_status"].get<std::vector<int>>();
this->ignore_success_status=args["ignore_success_status"].get<bool>();
}
bool command_variables;
std::vector<std::string> command;
std::string show_output;
std::vector<int> success_status;
bool ignore_success_status;
ActionStatus run_action();
};
class SaveCommandContentAction {
public:
SaveCommandContentAction(const json& args) {
check_arg_vector_string(args,"command");
if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided.");
if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean");
for (auto& arg:args["success_status"]) {
if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer.");
}
if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided.");
if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean");
check_arg_string(args,"command_output_file");
this->command_variables=args["command_variables"].get<bool>();
this->command=args["command"].get<std::vector<std::string>>();
this->success_status=args["success_status"].get<std::vector<int>>();
this->ignore_success_status=args["ignore_success_status"].get<bool>();
this->command_output_file_variables=args["command_output_file_variables"].get<bool>();
this->command_output_file=args["command_output_file"].get<std::string>();
}
bool command_variables;
std::vector<std::string> command;
std::vector<int> success_status;
bool ignore_success_status;
bool command_output_file_variables;
std::string command_output_file;
ActionStatus run_action();
};
class CompileOneAsmAction {
public:
CompileOneAsmAction(const json& args) {
check_arg_string(args,"source");
check_arg_string(args,"assembler");
check_arg_vector_string(args,"pre_arguments");
check_arg_vector_string(args,"post_arguments");
check_arg_string(args,"output_file");
if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided.");
if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean");
for (auto& arg:args["success_status"]) {
if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer.");
}
if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided.");
if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean");
if (!args.contains("cache_authorized")) throw std::runtime_error("Cache authorized isn't provided.");
if (!args["cache_authorized"].is_boolean()) throw std::runtime_error("Cache authorized isn't a boolean");
this->source_variables=args["source_variables"].get<bool>();
this->assembler_variables=args["assembler_variables"].get<bool>();
this->pre_arguments_variables=args["pre_arguments_variables"].get<bool>();
this->post_arguments_variables=args["post_arguments_variables"].get<bool>();
this->output_file_variables=args["output_file_variables"].get<bool>();
this->source=args["source"].get<std::string>();
this->assembler=args["assembler"].get<std::string>();
this->output_file=args["output_file"].get<std::string>();
this->pre_arguments=args["pre_arguments"].get<std::vector<std::string>>();
this->post_arguments=args["post_arguments"].get<std::vector<std::string>>();
this->success_status=args["success_status"].get<std::vector<int>>();
this->ignore_success_status=args["ignore_success_status"].get<bool>();
this->cache_authorized=args["cache_authorized"].get<bool>();
}
bool source_variables;
std::string source;
bool assembler_variables;
std::string assembler;
bool pre_arguments_variables;
std::vector<std::string> pre_arguments;
bool post_arguments_variables;
std::vector<std::string> post_arguments;
bool output_file_variables;
std::string output_file;
std::vector<int> success_status;
bool ignore_success_status;
bool cache_authorized;
ActionStatus run_action();
};
class EnsureFolderExistenceAction {
public:
EnsureFolderExistenceAction(const json& args) {
check_arg_string(args,"path");
this->path_variables=args["path_variables"].get<bool>();
this->path=args["path"].get<std::string>();
}
bool path_variables;
std::string path;
ActionStatus run_action();
};
class MoveFileAction {
public:
MoveFileAction(const json& args) {
check_arg_string(args,"source_file");
check_arg_string(args,"destination_folder");
this->source_file_variables=args["source_file_variables"].get<bool>();
this->source_file=args["source_file"].get<std::string>();
this->destination_folder_variables=args["destination_folder_variables"].get<bool>();
this->destination_folder=args["destination_folder"].get<std::string>();
}
bool source_file_variables;
std::string source_file;
bool destination_folder_variables;
std::string destination_folder;
ActionStatus run_action();
};
class CompileOneCppAction {
public:
CompileOneCppAction(const json& args) {
check_arg_string(args,"source");
check_arg_string(args,"compiler");
check_arg_vector_string(args,"pre_arguments");
check_arg_vector_string(args,"post_arguments");
check_arg_string(args,"output_file");
check_arg_string(args,"headers_command");
if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided.");
if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean");
for (auto& arg:args["success_status"]) {
if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer.");
}
if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided.");
if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean");
if (!args.contains("cache_authorized")) throw std::runtime_error("Cache authorized isn't provided.");
if (!args["cache_authorized"].is_boolean()) throw std::runtime_error("Cache authorized isn't a boolean");
this->source_variables=args["source_variables"].get<bool>();
this->compiler_variables=args["compiler_variables"].get<bool>();
this->pre_arguments_variables=args["pre_arguments_variables"].get<bool>();
this->post_arguments_variables=args["post_arguments_variables"].get<bool>();
this->output_file_variables=args["output_file_variables"].get<bool>();
this->headers_command_variables=args["headers_command_variables"].get<bool>();
this->source=args["source"].get<std::string>();
this->compiler=args["compiler"].get<std::string>();
this->output_file=args["output_file"].get<std::string>();
this->pre_arguments=args["pre_arguments"].get<std::vector<std::string>>();
this->post_arguments=args["post_arguments"].get<std::vector<std::string>>();
this->success_status=args["success_status"].get<std::vector<int>>();
this->ignore_success_status=args["ignore_success_status"].get<bool>();
this->cache_authorized=args["cache_authorized"].get<bool>();
this->headers_command=args["headers_command"].get<std::string>();
}
bool source_variables;
std::string source;
bool compiler_variables;
std::string compiler;
bool pre_arguments_variables;
std::vector<std::string> pre_arguments;
bool post_arguments_variables;
std::vector<std::string> post_arguments;
bool output_file_variables;
std::string output_file;
std::vector<int> success_status;
bool ignore_success_status;
bool cache_authorized;
bool headers_command_variables;
std::string headers_command;
ActionStatus run_action();
};
class RunSubmoduleIfAction {
public:
RunSubmoduleIfAction(const json& args,std::string root_folder) {
char path[PATH_MAX];
getcwd(path,sizeof(path));
chdir(root_folder.c_str());
check_arg_string(args,"file");
if (!args.contains("wait")) throw std::runtime_error("Wait isn't provided.");
if (!args["wait"].is_boolean()) throw std::runtime_error("Wait isn't a boolean");
if (!args.contains("block_if_fail")) throw std::runtime_error("Block if fail isn't provided.");
if (!args["block_if_fail"].is_boolean()) throw std::runtime_error("Block if fail isn't a boolean");
if (!args.contains("condition")) throw std::runtime_error("Condition isn't provided.");
if (!args["condition"].is_object()) throw std::runtime_error("Condition isn't a dictionnary.");
this->condition=args["condition"];
this->file=args["file"].get<std::string>();
this->file=fs::absolute(fs::path(args["file"].get<std::string>()));
this->wait=args["wait"].get<bool>();
this->block_if_fail=args["block_if_fail"].get<bool>();
chdir(path);
}
json condition;
bool file_variables;
std::string file;
bool wait;
bool block_if_fail;
ActionStatus run_action();
};
class RunCommandWaitDirAction {
public:
RunCommandWaitDirAction(const json& args) {
check_arg_vector_string(args,"command");
check_arg_string(args,"working_dir");
if (!args.contains("show_output")) throw std::runtime_error("Show output isn't provided.");
if (!args["show_output"].is_string()) throw std::runtime_error("Show output isn't a string");
if (args["show_output"]!="live" && args["show_output"]!="on_failure" && args["show_output"]!="silent") {
throw std::runtime_error("\""+args["show_output"].get<std::string>()+"\" isn't a valid output mode.");
}
if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided.");
if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean");
for (auto& arg:args["success_status"]) {
if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer.");
}
if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided.");
if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean");
this->command_variables=args["command_variables"].get<bool>();
this->command=args["command"].get<std::vector<std::string>>();
this->show_output=args["show_output"].get<std::string>();
this->success_status=args["success_status"].get<std::vector<int>>();
this->ignore_success_status=args["ignore_success_status"].get<bool>();
this->working_dir_variables=args["working_dir_variables"].get<bool>();
this->working_dir=args["working_dir"].get<std::string>();
}
bool command_variables;
std::vector<std::string> command;
std::string show_output;
std::vector<int> success_status;
bool ignore_success_status;
bool working_dir_variables;
std::string working_dir;
ActionStatus run_action();
};
class CopyFolderAction {
public:
CopyFolderAction(const json& args) {
check_arg_string(args,"source_folder");
check_arg_string(args,"destination_folder");
this->source_folder_variables=args["source_folder_variables"].get<bool>();
this->source_folder=args["source_folder"].get<std::string>();
this->destination_folder_variables=args["destination_folder_variables"].get<bool>();
this->destination_folder=args["destination_folder"].get<std::string>();
}
bool source_folder_variables;
std::string source_folder;
bool destination_folder_variables;
std::string destination_folder;
ActionStatus run_action();
};
class ExtractFromCacheAction {
public:
ExtractFromCacheAction(const json& args) {
check_arg_string(args,"target");
check_arg_string(args,"output_file");
this->target_variables=args["target_variables"].get<bool>();
this->output_file_variables=args["output_file_variables"].get<bool>();
this->target=args["target"].get<std::string>();
this->output_file=args["output_file"].get<std::string>();
}
bool target_variables;
std::string target;
bool output_file_variables;
std::string output_file;
ActionStatus run_action();
};
class StoreInCacheAction {
public:
StoreInCacheAction(const json& args) {
check_arg_string(args,"key");
check_arg_string(args,"file");
this->key_variables=args["key_variables"].get<bool>();
this->file_variables=args["file_variables"].get<bool>();
this->overwrite_allowed=args["overwrite_allowed"].get<bool>();
this->key=args["key"].get<std::string>();
this->file=args["file"].get<std::string>();
}
bool key_variables;
std::string key;
bool file_variables;
std::string file;
bool overwrite_allowed;
ActionStatus run_action();
};
class EnsureFolderResetAction {
public:
EnsureFolderResetAction(const json& args) {
check_arg_string(args,"path");
this->path_variables=args["path_variables"].get<bool>();
this->path=args["path"].get<std::string>();
}
bool path_variables;
std::string path;
ActionStatus run_action();
};
class RunActionsIfAction {
public:
RunActionsIfAction(const json& args,bool is_threading_allowed,std::string root_folder) {
if (!args.contains("condition")) throw std::runtime_error("Condition isn't provided.");
if (!args["condition"].is_object()) throw std::runtime_error("Condition isn't a dictionnary.");
if (!args["actions"].is_array()) throw std::runtime_error("Provided actions aren't stored in a list.");
for (const auto& act:args["actions"]) {
if (!act.is_object()) throw std::runtime_error("One of the action isn't a dictionnary.");
if (!act.contains("action")) throw std::runtime_error("Action isn't provided.");
if (!act["action"].is_string()) throw std::runtime_error("Action isn't a string.");
if (find(threaded_actions.begin(),threaded_actions.end(),act["action"].get<std::string>())!=threaded_actions.end() && !is_threading_allowed) throw std::runtime_error("Multithreaded actions aren't allowed in this module, and so can not be executed from RunActionsIfAction.");
if (!act.contains("args")) throw std::runtime_error("Action arguments aren't provided.");
if (!act["args"].is_object()) throw std::runtime_error("Action arguments aren't stored in a dictionnary.");
actions.push_back(act);
}
this->condition=args["condition"];
this->is_threading_allowed=is_threading_allowed;
this->root_folder=root_folder;
}
json condition;
std::vector<json> actions;
bool is_threading_allowed;
std::string root_folder;
ActionStatus run_action();
};
class RunActionsIfElseAction {
public:
RunActionsIfElseAction(const json& args,bool is_threading_allowed,std::string root_folder) {
if (!args.contains("condition")) throw std::runtime_error("Condition isn't provided.");
if (!args["condition"].is_object()) throw std::runtime_error("Condition isn't a dictionnary.");
if (!args.contains("actions_if")) throw std::runtime_error("No actions are provided.");
if (!args["actions_if"].is_array()) throw std::runtime_error("Provided actions aren't stored in a list.");
for (const auto& act:args["actions_if"]) {
if (!act.is_object()) throw std::runtime_error("One of the action isn't a dictionnary.");
if (!act.contains("action")) throw std::runtime_error("Action isn't provided.");
if (!act["action"].is_string()) throw std::runtime_error("Action isn't a string.");
if (find(threaded_actions.begin(),threaded_actions.end(),act["action"].get<std::string>())!=threaded_actions.end() && !is_threading_allowed) throw std::runtime_error("Multithreaded actions aren't allowed in this module, and so can not be executed from RunActionsIfAction.");
if (!act.contains("args")) throw std::runtime_error("Action arguments aren't provided.");
if (!act["args"].is_object()) throw std::runtime_error("Action arguments aren't stored in a dictionnary.");
actions_if.push_back(act);
}
if (!args.contains("actions_else")) throw std::runtime_error("No actions are provided.");
if (!args["actions_else"].is_array()) throw std::runtime_error("Provided actions aren't stored in a list.");
for (const auto& act:args["actions_else"]) {
if (!act.is_object()) throw std::runtime_error("One of the action isn't a dictionnary.");
if (!act.contains("action")) throw std::runtime_error("Action isn't provided.");
if (!act["action"].is_string()) throw std::runtime_error("Action isn't a string.");
if (find(threaded_actions.begin(),threaded_actions.end(),act["action"].get<std::string>())!=threaded_actions.end() && !is_threading_allowed) throw std::runtime_error("Multithreaded actions aren't allowed in this module, and so can not be executed from RunActionsIfAction.");
if (!act.contains("args")) throw std::runtime_error("Action arguments aren't provided.");
if (!act["args"].is_object()) throw std::runtime_error("Action arguments aren't stored in a dictionnary.");
actions_else.push_back(act);
}
this->condition=args["condition"];
this->is_threading_allowed=is_threading_allowed;
this->root_folder=root_folder;
}
json condition;
std::vector<json> actions_if;
std::vector<json> actions_else;
bool is_threading_allowed;
std::string root_folder;
ActionStatus run_action();
};
class RunCommandStrAction {
public:
RunCommandStrAction(const json& args) {
check_arg_string(args,"command");
if (!args.contains("show_output")) throw std::runtime_error("Show output isn't provided.");
if (!args["show_output"].is_string()) throw std::runtime_error("Show output isn't a string");
if (args["show_output"]!="live" && args["show_output"]!="on_failure" && args["show_output"]!="silent") {
throw std::runtime_error("\""+args["show_output"].get<std::string>()+"\" isn't a valid output mode.");
}
if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided.");
if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean");
for (auto& arg:args["success_status"]) {
if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer.");
}
if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided.");
if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean");
this->command_variables=args["command_variables"].get<bool>();
this->command=args["command"].get<std::string>();
this->show_output=args["show_output"].get<std::string>();
this->success_status=args["success_status"].get<std::vector<int>>();
this->ignore_success_status=args["ignore_success_status"].get<bool>();
}
bool command_variables;
std::string command;
std::string show_output;
std::vector<int> success_status;
bool ignore_success_status;
ActionStatus run_action();
};
class ComputeElementHashAction {
public:
ComputeElementHashAction(const json& args) {
check_arg_string(args,"element");
if (!args.contains("output_variable")) throw std::runtime_error("Output variable isn't provided.");
if (!args["output_variable"].is_string()) throw std::runtime_error("Output variable isn't a string.");
this->element_variables=args["element_variables"].get<bool>();
this->element=args["element"].get<std::string>();
this->output_variable=args["output_variable"].get<std::string>();
}
bool element_variables;
std::string element;
std::string output_variable;
ActionStatus run_action();
};
class CompileMultipleCppAction {
public:
CompileMultipleCppAction(const json& args) {
check_arg_vector_string(args,"source_files");
check_arg_string(args,"compiler");
check_arg_vector_string(args,"pre_arguments");
check_arg_vector_string(args,"post_arguments");
check_arg_vector_string(args,"output_files");
check_arg_string(args,"headers_command");
if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided.");
if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean");
for (auto& arg:args["success_status"]) {
if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer.");
}
if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided.");
if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean");
if (!args.contains("cache_authorized")) throw std::runtime_error("Cache authorized isn't provided.");
if (!args["cache_authorized"].is_boolean()) throw std::runtime_error("Cache authorized isn't a boolean");
if (!args.contains("source_files_path_completion")) throw std::runtime_error("Source files path completion isn't provided.");
if (!args["source_files_path_completion"].is_boolean()) throw std::runtime_error("Source files path completion isn't a boolean");
this->source_files_path_completion=args["source_files_path_completion"].get<bool>();
if (this->source_files_path_completion) {
if (!args.contains("path_completion_source_ext")) throw std::runtime_error("Path completion sources extension isn't provided");
if (!args["path_completion_source_ext"].is_string()) throw std::runtime_error("Path completion sources extension isn't a string");
if (!args.contains("path_completion_output_ext")) throw std::runtime_error("Path completion output extension isn't provided");
if (!args["path_completion_output_ext"].is_string()) throw std::runtime_error("Path completion output extension isn't a string");
this->path_completion_source_ext=args["path_completion_source_ext"].get<std::string>();
this->path_completion_output_ext=args["path_completion_output_ext"].get<std::string>();
}
this->source_files_variables=args["source_files_variables"].get<bool>();
this->compiler_variables=args["compiler_variables"].get<bool>();
this->pre_arguments_variables=args["pre_arguments_variables"].get<bool>();
this->post_arguments_variables=args["post_arguments_variables"].get<bool>();
this->output_files_variables=args["output_files_variables"].get<bool>();
this->ignore_success_status=args["ignore_success_status"].get<bool>();
this->cache_authorized=args["cache_authorized"].get<bool>();
this->headers_command_variables=args["headers_command_variables"].get<bool>();
this->compiler=args["compiler"].get<std::string>();
this->headers_command=args["headers_command"].get<std::string>();
this->source_files=args["source_files"].get<std::vector<std::string>>();
this->pre_arguments=args["pre_arguments"].get<std::vector<std::string>>();
this->post_arguments=args["post_arguments"].get<std::vector<std::string>>();
this->output_files=args["output_files"].get<std::vector<std::string>>();
this->success_status=args["success_status"].get<std::vector<int>>();
}
bool source_files_path_completion;
bool source_files_variables;
std::vector<std::string> source_files;
bool compiler_variables;
std::string compiler;
bool pre_arguments_variables;
std::vector<std::string> pre_arguments;
bool post_arguments_variables;
std::vector<std::string> post_arguments;
bool output_files_variables;
std::vector<std::string> output_files;
std::vector<int> success_status;
bool ignore_success_status;
bool cache_authorized;
bool headers_command_variables;
std::string headers_command;
std::string path_completion_source_ext;
std::string path_completion_output_ext;
ActionStatus run_action();
};
class CopyFileAction {
public:
CopyFileAction(const json& args) {
check_arg_string(args,"source_file");
check_arg_string(args,"destination_folder");
this->source_file_variables=args["source_file_variables"].get<bool>();
this->source_file=args["source_file"].get<std::string>();
this->destination_folder_variables=args["destination_folder_variables"].get<bool>();
this->destination_folder=args["destination_folder"].get<std::string>();
}
bool source_file_variables;
std::string source_file;
bool destination_folder_variables;
std::string destination_folder;
ActionStatus run_action();
};
class CreateFat32Action {
public:
CreateFat32Action(const json& args) {
check_arg_string(args,"key");
if (!args.contains("size")) throw std::runtime_error("Size isn't provided.");
if (!args["size"].is_number_unsigned()) throw std::runtime_error("Size isn't an integer.");
this->key_variables=args["key_variables"].get<bool>();
this->key=args["key"].get<std::string>();
this->size=args["size"].get<size_t>();
}
bool key_variables;
std::string key;
size_t size;
ActionStatus run_action();
};
class CreateFolderFat32Action {
public:
CreateFolderFat32Action(const json& args) {
check_arg_string(args,"key");
check_arg_string(args,"full_path");
this->key_variables=args["key_variables"].get<bool>();
this->key=args["key"].get<std::string>();
this->full_path_variables=args["full_path_variables"].get<bool>();
this->full_path=args["full_path"].get<std::string>();
}
bool key_variables;
std::string key;
bool full_path_variables;
std::string full_path;
ActionStatus run_action();
};
class CreateFileFat32Action {
public:
CreateFileFat32Action(const json& args) {
check_arg_string(args,"key");
check_arg_string(args,"source_path");
check_arg_string(args,"full_path");
if (args.contains("is_vftm_target")) {
if (!args["is_vftm_target"].is_boolean()) throw std::runtime_error("Is VFTM target isn't an boolean.");
this->is_vftm_target=args["is_vftm_target"].get<bool>();
}
this->key_variables=args["key_variables"].get<bool>();
this->key=args["key"].get<std::string>();
this->source_path_variables=args["source_path_variables"].get<bool>();
this->source_path=args["source_path"].get<std::string>();
this->full_path_variables=args["full_path_variables"].get<bool>();
this->full_path=args["full_path"].get<std::string>();
}
bool is_vftm_target=false;
bool key_variables;
std::string key;
bool source_path_variables;
std::string source_path;
bool full_path_variables;
std::string full_path;
ActionStatus run_action();
};
class ExportFat32Action {
public:
ExportFat32Action(const json& args) {
check_arg_string(args,"key");
check_arg_string(args,"export_path");
if (!args.contains("generate_vftm")) throw std::runtime_error("Generate VFTM isn't provided.");
if (!args["generate_vftm"].is_boolean()) throw std::runtime_error("Generate VFTM isn't a boolean.");
this->generate_vftm=args["generate_vftm"].get<bool>();
if (this->generate_vftm) {
if (!args.contains("disk_guid_var")) throw std::runtime_error("Disk GUID variable must be provided when generate_vftm is true.");
if (!args["disk_guid_var"].is_string()) throw std::runtime_error("Disk GUID variable must be a string.");
if (!args.contains("efi_part_unique_guid_var")) throw std::runtime_error("EFI partition unique GUID variable must be provided when generate_vftm is true.");
if (!args["efi_part_unique_guid_var"].is_string()) throw std::runtime_error("EFI partition unique GUID variable must be a boolean.");
this->disk_guid_var=args["disk_guid_var"].get<std::string>();
this->efi_part_unique_guid_var=args["efi_part_unique_guid_var"].get<std::string>();
}
this->key_variables=args["key_variables"].get<bool>();
this->key=args["key"].get<std::string>();
this->export_path_variables=args["export_path_variables"].get<bool>();
this->export_path=args["export_path"].get<std::string>();
}
bool key_variables;
std::string key;
bool export_path_variables;
std::string export_path;
bool generate_vftm;
std::string disk_guid_var;
std::string efi_part_unique_guid_var;
ActionStatus run_action();
};
class CreateDiskAction {
public:
CreateDiskAction(const json& args) {
check_arg_string(args,"key");
check_arg_string(args,"disk_guid");
if (!args.contains("size")) throw std::runtime_error("Size isn't provided.");
if (!args["size"].is_number_unsigned()) throw std::runtime_error("Size isn't an integer.");
this->key_variables=args["key_variables"].get<bool>();
this->key=args["key"].get<std::string>();
this->disk_guid_variables=args["disk_guid_variables"].get<bool>();
this->disk_guid=args["disk_guid"].get<std::string>();
this->size=args["size"].get<size_t>();
}
bool key_variables;
std::string key;
size_t size;
bool disk_guid_variables;
std::string disk_guid;
ActionStatus run_action();
};
class AddPartitionDiskAction {
public:
AddPartitionDiskAction(const json& args) {
check_arg_string(args,"key");
check_arg_string(args,"type_guid");
check_arg_string(args,"unique_guid");
check_arg_string(args,"name");
check_arg_string(args,"source_file");
this->key_variables=args["key_variables"].get<bool>();
this->key=args["key"].get<std::string>();
this->type_guid_variables=args["type_guid_variables"].get<bool>();
this->type_guid=args["type_guid"].get<std::string>();
this->unique_guid_variables=args["unique_guid_variables"].get<bool>();
this->unique_guid=args["unique_guid"].get<std::string>();
this->name_variables=args["name_variables"].get<bool>();
this->name=args["name"].get<std::string>();
this->source_file_variables=args["source_file_variables"].get<bool>();
this->source_file=args["source_file"].get<std::string>();
}
bool key_variables;
std::string key;
bool type_guid_variables;
std::string type_guid;
bool unique_guid_variables;
std::string unique_guid;
bool name_variables;
std::string name;
bool source_file_variables;
std::string source_file;
ActionStatus run_action();
};
class ExportDiskAction {
public:
ExportDiskAction(const json& args) {
check_arg_string(args,"key");
check_arg_string(args,"export_path");
this->key_variables=args["key_variables"].get<bool>();
this->key=args["key"].get<std::string>();
this->export_path_variables=args["export_path_variables"].get<bool>();
this->export_path=args["export_path"].get<std::string>();
}
bool key_variables;
std::string key;
bool export_path_variables;
std::string export_path;
ActionStatus run_action();
};
class VFTMLoadCryptoLibAction {
public:
VFTMLoadCryptoLibAction(const json& args) {
check_arg_string(args,"lib_path");
this->lib_path_variables=args["lib_path_variables"].get<bool>();
this->lib_path=args["lib_path"].get<std::string>();
}
bool lib_path_variables;
std::string lib_path;
ActionStatus run_action();
};
class VFTMRunKeysGeneratorAction {
public:
VFTMRunKeysGeneratorAction(const json& args) {
check_arg_vector_string(args,"command");
check_arg_string(args,"working_dir");
check_arg_string(args,"socket_path");
if (!args.contains("success_status")) throw std::runtime_error("Success status isn't provided.");
if (!args["success_status"].is_array()) throw std::runtime_error("Success status isn't a boolean");
for (auto& arg:args["success_status"]) {
if (!arg.is_number_integer()) throw std::runtime_error("One of the status code isn't an integer.");
}
if (!args.contains("ignore_success_status")) throw std::runtime_error("Ignore success status isn't provided.");
if (!args["ignore_success_status"].is_boolean()) throw std::runtime_error("Ignore success status isn't a boolean");
this->command_variables=args["command_variables"].get<bool>();
this->command=args["command"].get<std::vector<std::string>>();
this->socket_path_variables=args["socket_path_variables"].get<bool>();
this->socket_path=args["socket_path"].get<std::string>();
this->success_status=args["success_status"].get<std::vector<int>>();
this->ignore_success_status=args["ignore_success_status"].get<bool>();
this->working_dir_variables=args["working_dir_variables"].get<bool>();
this->working_dir=args["working_dir"].get<std::string>();
}
bool command_variables;
std::vector<std::string> command;
bool socket_path_variables;
std::string socket_path;
std::vector<int> success_status;
bool ignore_success_status;
bool working_dir_variables;
std::string working_dir;
ActionStatus run_action();
};
using ParallelAction=std::variant<RunCommandWaitAction,
SaveCommandContentAction,
CompileOneAsmAction,
EnsureFolderExistenceAction,
MoveFileAction,
CompileOneCppAction,
RunCommandWaitDirAction,
CopyFolderAction,
ExtractFromCacheAction,
StoreInCacheAction,
EnsureFolderResetAction,
RunActionsIfAction,
RunCommandStrAction,
RunActionsIfElseAction,
ComputeElementHashAction,
CopyFileAction,
CreateFat32Action,
CreateFolderFat32Action,
CreateFileFat32Action,
ExportFat32Action,
CreateDiskAction,
AddPartitionDiskAction,
ExportDiskAction,
VFTMLoadCryptoLibAction,
VFTMRunKeysGeneratorAction>;
ParallelAction return_pararrel_action(const json& args,std::string action_name);
class RunActionsParallelAction {
public:
RunActionsParallelAction (const json& args) {
if (!args.contains("actions")) throw std::runtime_error("No actions are provided.");
if (!args["actions"].is_array()) throw std::runtime_error("Provided actions aren't stored in a list.");
for (const auto& act:args["actions"]) {
if (!act.is_object()) throw std::runtime_error("One of the action isn't a dictionnary.");
if (!act.contains("action")) throw std::runtime_error("Action isn't provided.");
if (!act["action"].is_string()) throw std::runtime_error("Action isn't a string.");
if (!act.contains("args")) throw std::runtime_error("Action arguments aren't provided.");
if (!act["args"].is_object()) throw std::runtime_error("Action arguments aren't stored in a dictionnary.");
actions.push_back(return_pararrel_action(act["args"],act["action"]));
}
}
std::vector<ParallelAction> actions;
ActionStatus run_action();
};
class RunSubmoduleParallelAction {
public:
RunSubmoduleParallelAction(const json& args) {
check_arg_vector_string(args,"submodules");
for (const auto& act:args["submodules"]) {
submodules.push_back(act.get<std::string>());
}
this->submodules_variables=args["submodules_variables"].get<bool>();
}
bool submodules_variables;
std::vector<std::string> submodules;
ActionStatus run_action();
};
class VyldCompilationAction {
public:
VyldCompilationAction(const json& args) {
check_arg_vector_string(args,"source_files");
check_arg_vector_string(args,"source_asm");
check_arg_string(args,"compiler");
check_arg_string(args,"assembler");
check_arg_string(args,"linker");
check_arg_string(args,"compiler_flags");
check_arg_string(args,"output_file");
check_arg_string(args,"headers_command");
if (!args.contains("source_files_path_completion")) throw std::runtime_error("Source file path completion isn't provided.");
if (!args["source_files_path_completion"].is_boolean()) throw std::runtime_error("Source file path completion isn't a boolean.");
if (!args.contains("source_asm_path_completion")) throw std::runtime_error("Source ASM path completion isn't provided.");
if (!args["source_asm_path_completion"].is_boolean()) throw std::runtime_error("Source ASM path completion isn't a boolean.");
if (!args.contains("block_if_fail")) throw std::runtime_error("Block if fail isn't provided.");
if (!args["block_if_fail"].is_boolean()) throw std::runtime_error("Block if fail isn't a boolean.");
if (!args.contains("object_files_cache_authorized")) throw std::runtime_error("Object files caching authorized isn't provided.");
if (!args["object_files_cache_authorized"].is_boolean()) throw std::runtime_error("Object files caching authorized isn't a boolean.");
if (!args.contains("payloads")) throw std::runtime_error("Payloads aren't provided.");
if (!args["payloads"].is_array()) throw std::runtime_error("Payloads aren't stored in a list.");
this->source_files_path_completion=args["source_files_path_completion"].get<bool>();
this->source_asm_path_completion=args["source_asm_path_completion"].get<bool>();
this->source_files_variables=args["source_files_variables"].get<bool>();
this->source_asm_variables=args["source_asm_variables"].get<bool>();
this->compiler_variables=args["compiler_variables"].get<bool>();
this->assembler_variables=args["assembler_variables"].get<bool>();
this->linker_variables=args["linker_variables"].get<bool>();
this->compiler_flags_variables=args["compiler_flags_variables"].get<bool>();
this->output_file_variables=args["output_file_variables"].get<bool>();
this->block_if_fail=args["block_if_fail"].get<bool>();
this->object_files_cache_authorized=args["object_files_cache_authorized"].get<bool>();
this->headers_command_variables=args["headers_command_variables"].get<bool>();
this->source_files=args["source_files"].get<std::vector<std::string>>();
this->source_asm=args["source_asm"].get<std::vector<std::string>>();
this->compiler=args["compiler"].get<std::string>();
this->assembler=args["assembler"].get<std::string>();
this->linker=args["linker"].get<std::string>();
this->compiler_flags=args["compiler_flags"].get<std::string>();
this->output_file=args["output_file"].get<std::string>();
this->headers_command=args["headers_command"].get<std::string>();
this->payloads=args["payloads"].get<std::vector<json>>();
}
bool source_files_path_completion;
bool source_files_variables;
std::vector<std::string> source_files;
bool compiler_variables;
std::string compiler;
bool source_asm_path_completion;
bool source_asm_variables;
std::vector<std::string> source_asm;
bool assembler_variables;
std::string assembler;
bool linker_variables;
std::string linker;
bool compiler_flags_variables;
std::string compiler_flags;
bool output_file_variables;
std::string output_file;
bool block_if_fail;
bool object_files_cache_authorized;
bool headers_command_variables;
std::string headers_command;
std::vector<json> payloads;
ActionStatus run_action();
};
using Action=std::variant<RunSubmoduleAction,
RunCommandWaitAction,
RunActionsParallelAction,
SaveCommandContentAction,
CompileOneAsmAction,
EnsureFolderExistenceAction,
MoveFileAction,
CompileOneCppAction,
VyldCompilationAction,
RunSubmoduleIfAction,
RunCommandWaitDirAction,
CopyFolderAction,
RunSubmoduleParallelAction,
ExtractFromCacheAction,
StoreInCacheAction,
EnsureFolderResetAction,
RunActionsIfAction,
RunCommandStrAction,
RunActionsIfElseAction,
ComputeElementHashAction,
CompileMultipleCppAction,
CopyFileAction,
CreateFat32Action,
CreateFolderFat32Action,
CreateFileFat32Action,
ExportFat32Action,
CreateDiskAction,
AddPartitionDiskAction,
ExportDiskAction,
VFTMLoadCryptoLibAction,
VFTMRunKeysGeneratorAction>;
Action return_action(const json &args,std::string action_name,bool is_threading_allowed,std::string root_folder);
}
namespace module {
class Module {
public:
Module(std::string file,bool is_threading_allowed) {
std::ifstream f(file);
if (!f) {
throw std::runtime_error(file+" couldn't be opened.");
}
json j=json::parse(f);
if (!j.contains("version")) throw std::runtime_error("Syntax version isn't provided.");
if (!j["version"].is_string()) throw std::runtime_error("Syntax version isn't a string.");
if (j["version"]!=syntax_version) throw std::runtime_error("Syntax version is "+j["version"].get<std::string>()+". Expected "+syntax_version+".");
if (j.contains("root_folder")) {
if (!j["root_folder"].is_string()) throw std::runtime_error("Root folder isn't a string.");
this->root_folder=vybuild::parser::root_folder_parsing(j["root_folder"].get<std::string>(),file);
} else {
this->root_folder=vybuild::parser::root_folder_parsing("%filefolder%",file);
}
if (!j.contains("run_context")) throw std::runtime_error("Run context isn't provided.");
if (!j["run_context"].is_string()) throw std::runtime_error("Run context isn't a string.");
if (j["run_context"]!="root" && j["run_context"]!="sub" && j["run_context"]!="both") throw std::runtime_error("\""+j["run_context"].get<std::string>()+"\" isn't a string.");
this->run_context=j["run_context"].get<std::string>();
if (!j.contains("name")) throw std::runtime_error("Name isn't provided.");
if (!j["name"].is_string()) throw std::runtime_error("Name isn't a string.");
this->name=j["name"].get<std::string>();
if (this->run_context=="root" && j.contains("global_vars")) {
if (!j["global_vars"].is_object()) throw std::runtime_error("Global variables aren't in a list.");
for (const auto& [var_name,value]:j["global_vars"].items()) {
vybuild::vars::set_global_variable("\\$"+var_name+"\\$",value);
}
} else if (this->run_context!="root" && j.contains("global_vars")){
throw std::runtime_error("Global variables are only available for modules that are guaranteed to be runned as root.");
}
if (this->run_context=="root" && j.contains("global_uuid")) {
if (!j["global_uuid"].is_array()) throw std::runtime_error("Global UUID aren't in a list.");
for (const auto& var_name:j["global_uuid"].items()) {
uuid_t id;
uuid_generate_random(id);
char out[37];
uuid_unparse_lower(id,out);
vybuild::vars::set_global_variable("\\$"+var_name.value().get<std::string>()+"\\$",std::string(out));
}
} else if (this->run_context!="root" && j.contains("global_uuid")){
throw std::runtime_error("Global UUID are only available for modules that are guaranteed to be runned as root.");
}
if (!j.contains("actions")) throw std::runtime_error("Couldn't find any action inside module.");
if (!j["actions"].is_array()) throw std::runtime_error("Actions aren't in a list.");
for (const auto& act:j["actions"]) {
if (!act.is_object()) throw std::runtime_error("One of the action isn't a dictionnary.");
if (!act.contains("action")) throw std::runtime_error("Action isn't provided.");
if (!act["action"].is_string()) throw std::runtime_error("Action isn't a string.");
if (!act.contains("args")) throw std::runtime_error("Action arguments aren't provided.");
if (!act["args"].is_object()) throw std::runtime_error("Action arguments aren't stored in a dictionnary.");
actions.push_back(vybuild::actions::return_action(act["args"],act["action"],is_threading_allowed,this->root_folder));
}
}
std::string root_folder;
std::string run_context;
std::string name;
std::vector<vybuild::actions::Action> actions;
vybuild::actions::ActionStatus run_module(bool is_root,bool is_threaded) {
if (this->run_context=="root" && !is_root) {
throw std::runtime_error("Module isn't supposed to be ran as a submodule.");
} else if (this->run_context=="sub" && is_root) {
throw std::runtime_error("Module isn't supposed to be ran as root module.");
}
if (is_threaded) unshare(CLONE_FS);
char path[PATH_MAX];
getcwd(path,sizeof(path));
chdir(this->root_folder.c_str());
for (auto& a:actions) {
vybuild::actions::ActionStatus status=std::visit([](auto& act) {
return act.run_action();
},a);
if (status!=vybuild::actions::ActionStatus::Success && status!=vybuild::actions::ActionStatus::ExitSuccess) {
chdir(path);
return status;
}
if (status==vybuild::actions::ActionStatus::ExitSuccess) {
chdir(path);
return vybuild::actions::ActionStatus::Success;
}
}
chdir(path);
return vybuild::actions::ActionStatus::Success;
}
};
}
}
#endif