diff --git a/source/cli/metacallcli/CMakeLists.txt b/source/cli/metacallcli/CMakeLists.txt index b4dde9310..3bb2e64f0 100644 --- a/source/cli/metacallcli/CMakeLists.txt +++ b/source/cli/metacallcli/CMakeLists.txt @@ -1,3 +1,9 @@ +# Check if this loader is enabled +if(NOT OPTION_BUILD_LOADERS OR NOT OPTION_BUILD_LOADERS_EXT OR NOT OPTION_BUILD_EXTENSIONS OR NOT OPTION_BUILD_LOADERS_NODE) + message(WARNING "The Extension and NodeJS loaders are a dependency of the CLI, in order to compile the CLI, enable them with -DOPTION_BUILD_LOADERS_EXT=ON -DOPTION_BUILD_LOADERS_NODE=ON") + return() +endif() + # # Executable name and options # @@ -149,23 +155,33 @@ target_link_libraries(${target} # add_loader_dependencies(${target} - node_loader - py_loader - rb_loader - cs_loader - jsm_loader - js_loader - mock_loader c_loader + cob_loader + cs_loader + ext_loader file_loader + java_loader + mock_loader + py_loader + rb_loader + rs_loader + rpc_loader ts_loader + wasm_loader ) add_dependencies(${target} + node_loader cli_repl_plugin cli_core_plugin ) +if(TARGET cli_cmd_plugin) + add_dependencies(${target} + cli_cmd_plugin + ) +endif() + # # Deployment # diff --git a/source/cli/metacallcli/include/metacallcli/application.hpp b/source/cli/metacallcli/include/metacallcli/application.hpp index cf45d4ff1..f147a5b2b 100644 --- a/source/cli/metacallcli/include/metacallcli/application.hpp +++ b/source/cli/metacallcli/include/metacallcli/application.hpp @@ -67,6 +67,18 @@ class application */ void repl(); + /** + * @brief + * Initialize the CMD + * + * @param[in] arguments + * Vector of strings containing all the arguments from argv + * + * @return + * Return true if the load was successful, false otherwise + */ + bool cmd(std::vector &arguments); + /** * @brief * Fallback argument parser @@ -118,9 +130,9 @@ class application private: /* -- Private Member Data -- */ - void *plugin_cli_handle; /**< Handle containing all loaded plugins for CLI */ - void *plugin_repl_handle; /**< Handle containing all loaded plugins for REPL */ - std::vector arguments; /**< Vector containing a list of arguments */ + void *plugin_cli_handle; /**< Handle containing all loaded plugins for CLI */ + void *plugin_repl_handle; /**< Handle containing all loaded plugins for REPL */ + void *plugin_cmd_handle; /**< Handle containing all loaded plugins for CMD */ }; } /* namespace metacallcli */ diff --git a/source/cli/metacallcli/source/application.cpp b/source/cli/metacallcli/source/application.cpp index f40dc4419..3ef0a8ddd 100644 --- a/source/cli/metacallcli/source/application.cpp +++ b/source/cli/metacallcli/source/application.cpp @@ -40,8 +40,8 @@ static bool exit_condition = true; void application::repl() { - /* Initialize CLI plugin */ - if (!load_path("cli", &plugin_cli_handle)) + /* Initialize REPL plugins */ + if (!load_path("repl", &plugin_repl_handle)) { /* Do not enter into the main loop */ exit_condition = true; @@ -67,7 +67,7 @@ void application::repl() return NULL; }; - int result = metacall_register_loaderv(metacall_loader("ext"), plugin_cli_handle, "exit", exit, METACALL_INVALID, 0, NULL); + int result = metacall_register_loaderv(metacall_loader("ext"), plugin_repl_handle, "exit", exit, METACALL_INVALID, 0, NULL); if (result != 0) { @@ -79,13 +79,86 @@ void application::repl() exit_condition = false; } - void *ret = metacallhv_s(plugin_repl_handle, "initialize", metacall_null_args, 0); + std::string plugin_path(metacall_plugin_path()); + + void *args[] = { + metacall_value_create_string(plugin_path.c_str(), plugin_path.length()) + }; + + void *ret = metacallhv_s(plugin_cli_handle, "repl_initialize", args, sizeof(args) / sizeof(args[0])); + + metacall_value_destroy(args[0]); check_for_exception(ret); } +bool application::cmd(std::vector &arguments) +{ + /* Get the command parsing function */ + void *command_parse_func = metacall_handle_function(plugin_cli_handle, "command_parse"); + + if (command_parse_func == NULL) + { + return false; + } + + /* Initialize CMD plugins */ + if (!load_path("cmd", &plugin_cmd_handle)) + { + return false; + } + + /* Convert all arguments into metacall value strings */ + std::vector arguments_values; + arguments_values.reserve(arguments.size()); + + for (const std::string &str_argument : arguments) + { + arguments_values.push_back(metacall_value_create_string(str_argument.c_str(), str_argument.length())); + } + + /* Parse the arguments with the CMD plugin command parse function */ + void *ret = metacallhv_s(plugin_cmd_handle, "command_parse", arguments_values.data(), arguments_values.size()); + + /* Destroy all the command parse values */ + for (void *value_argument : arguments_values) + { + metacall_value_destroy(value_argument); + } + + /* Check for correct result of command parse */ + if (metacall_value_id(ret) != METACALL_ARRAY) + { + check_for_exception(ret); + return false; + } + + /* Get the argument map and the positional array */ + void **ret_array = metacall_value_to_array(ret); + void **command_map = metacall_value_to_map(ret_array[0]); + size_t command_size = metacall_value_count(ret_array[0]); + void **positional_array = metacall_value_to_map(ret_array[1]); + size_t positional_size = metacall_value_count(ret_array[1]); + + /* Execute the positional arguments */ + /* TODO: ... */ + + /* Note: If it has zero positional arguments, we should also run the repl, for example: + * $ metacall --some-option --another-option + */ + if (positional_size == 0) + { + /* Initialize the REPL */ + repl(); + } + + metacall_value_destroy(ret); + + return true; +} + application::application(int argc, char *argv[]) : - plugin_cli_handle(NULL), plugin_repl_handle(NULL) + plugin_cli_handle(NULL), plugin_repl_handle(NULL), plugin_cmd_handle(NULL) { /* Initialize MetaCall */ if (metacall_initialize() != 0) @@ -100,8 +173,8 @@ application::application(int argc, char *argv[]) : /* Print MetaCall information */ metacall_print_info(); - /* Initialize REPL plugin */ - if (!load_path("repl", &plugin_repl_handle)) + /* Initialize CLI internal plugins */ + if (!load_path("internal", &plugin_cli_handle)) { /* Do not enter into the main loop */ exit_condition = true; @@ -115,9 +188,10 @@ application::application(int argc, char *argv[]) : } else { - void *arguments_parse_func = metacall_handle_function(plugin_repl_handle, "arguments_parse"); + std::vector arguments(argv + 1, argv + argc); - if (arguments_parse_func == NULL) + /* Launch the CMD (parse arguments) */ + if (!cmd(arguments)) { std::cout << "Warning: CLI Arguments Parser was not loaded, " "using fallback argument parser with positional arguments only. " @@ -128,25 +202,8 @@ application::application(int argc, char *argv[]) : /* Use fallback parser, it can execute files but does not support command line arguments as options (i.e: -h, --help) */ /* Parse program arguments if any (e.g metacall (0) a.py (1) b.js (2) c.rb (3)) */ - std::vector arguments(argv + 1, argv + argc); - arguments_parse_fallback(arguments); } - else - { - /* TODO: Implement a new plugin for parsing command line options */ - std::cout << "TODO: CLI Arguments Parser Plugin is not implemented yet" << std::endl; - - /* Note: If it has zero positional arguments, we should also run the repl, for example: - * $ metacall --some-option --another-option --yeet - */ - // TODO: - // if (positional_arguments_size == 0) - // { - // /* Initialize the REPL */ - // repl(); - // } - } exit_condition = true; } @@ -244,6 +301,7 @@ bool application::load_path(const char *path, void **handle) /* Define the cli plugin path as string (core plugin path plus the subpath) */ fs::path plugin_cli_path(plugin_path); + plugin_cli_path /= "cli"; plugin_cli_path /= path; std::string plugin_cli_path_str(plugin_cli_path.string()); @@ -275,12 +333,13 @@ bool application::load_path(const char *path, void **handle) } metacall_value_destroy(ret); + return true; } void application::run() { - void *evaluate_func = metacall_handle_function(plugin_repl_handle, "evaluate"); + void *evaluate_func = metacall_handle_function(plugin_cli_handle, "repl_evaluate"); while (exit_condition != true) { @@ -373,9 +432,9 @@ void application::run() } /* Close REPL */ - if (plugin_repl_handle != NULL) + if (plugin_cli_handle != NULL) { - void *ret = metacallhv_s(plugin_repl_handle, "close", metacall_null_args, 0); + void *ret = metacallhv_s(plugin_cli_handle, "repl_close", metacall_null_args, 0); check_for_exception(ret); } @@ -394,7 +453,7 @@ void *application::execute(void *tokens) void **tokens_array = metacall_value_to_array(tokens); void *key = tokens_array[0]; - return metacallhv_s(plugin_cli_handle, metacall_value_to_string(key), &tokens_array[1], size - 1); + return metacallhv_s(plugin_repl_handle, metacall_value_to_string(key), &tokens_array[1], size - 1); } } diff --git a/source/cli/plugins/CMakeLists.txt b/source/cli/plugins/CMakeLists.txt index fa020ca0a..8d9118445 100644 --- a/source/cli/plugins/CMakeLists.txt +++ b/source/cli/plugins/CMakeLists.txt @@ -4,5 +4,15 @@ if(NOT OPTION_BUILD_LOADERS OR NOT OPTION_BUILD_LOADERS_EXT OR NOT OPTION_BUILD_ endif() # Extension sub-projects -add_subdirectory(cli_core_plugin) add_subdirectory(cli_repl_plugin) +add_subdirectory(cli_cmd_plugin) +add_subdirectory(cli_core_plugin) +add_subdirectory(cli_sandbox_plugin) + +# Generate output directories for CLI plugins +execute_process( + COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_OUTPUT_DIR}/plugins/cli" + COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_OUTPUT_DIR}/plugins/cli/internal" + COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_OUTPUT_DIR}/plugins/cli/repl" + COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_OUTPUT_DIR}/plugins/cli/cmd" +) diff --git a/source/cli/plugins/cli_cmd_plugin/CMakeLists.txt b/source/cli/plugins/cli_cmd_plugin/CMakeLists.txt new file mode 100644 index 000000000..997a9ca39 --- /dev/null +++ b/source/cli/plugins/cli_cmd_plugin/CMakeLists.txt @@ -0,0 +1,82 @@ +# Check if this loader is enabled +if(NOT OPTION_BUILD_LOADERS OR NOT OPTION_BUILD_LOADERS_EXT OR NOT OPTION_BUILD_EXTENSIONS OR NOT OPTION_BUILD_LOADERS_NODE) + return() +endif() + +find_package(NodeJS) + +if(NOT NodeJS_FOUND) + message(SEND_ERROR "NodeJS libraries not found") + return() +endif() + +# +# Plugin name and options +# + +# Target name +set(target cli_cmd_plugin) + +# Exit here if required dependencies are not met +message(STATUS "Plugin ${target}") + +# NodeJS added util.parseArgs([config]) in versions v18.3.0, v16.17.0 +# Check for compatibility, otherwise use fallback command parser in the CLI +if(NOT (NodeJS_VERSION VERSION_GREATER_EQUAL "18.3.0" OR (NodeJS_VERSION_MAJOR LESS 18 AND NodeJS_VERSION VERSION_GREATER_EQUAL "16.17.0"))) + message(WARNING "NodeJS version ${NodeJS_VERSION} does not support ${target}, at least v18.3.0 or v16.17.0 are required, using fallback command parser") + return() +endif() + +# +# Source +# + +set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/source") + +# +# Destination +# + +set(PLUGIN_OUTPUT_DIRECTORY "${PROJECT_OUTPUT_DIR}/plugins/cli/internal/${target}") + +# +# Project Target +# + +add_custom_target(${target} ALL + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy ${source_path}/metacall.json ${PLUGIN_OUTPUT_DIRECTORY}/metacall.json + COMMAND ${CMAKE_COMMAND} -E copy ${source_path}/cli_cmd_plugin.js ${PLUGIN_OUTPUT_DIRECTORY}/cli_cmd_plugin.js +) + +# +# Target Properties +# + +set_target_properties(${target} + PROPERTIES + FOLDER "${IDE_FOLDER}" +) + +# +# Dependencies +# + +add_dependencies(${target} + plugin_extension + node_loader +) + +# +# Define test +# + +# Check if tests are enabled +if(NOT OPTION_BUILD_TESTS) + return() +endif() + +add_test(NAME ${target} + COMMAND ${NodeJS_EXECUTABLE} test.js + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/source +) diff --git a/source/cli/plugins/cli_cmd_plugin/source/cli_cmd_plugin.js b/source/cli/plugins/cli_cmd_plugin/source/cli_cmd_plugin.js new file mode 100644 index 000000000..74f5aac68 --- /dev/null +++ b/source/cli/plugins/cli_cmd_plugin/source/cli_cmd_plugin.js @@ -0,0 +1,38 @@ +const util = require('util'); + +const options = {}; + +function command_register(cmd, type, short, multiple) { + const type_map = { + METACALL_STRING: 'string', + METACALL_BOOL: 'boolean' + }; + + options[cmd] = { + type: type_map[type || 'METACALL_BOOL'] + }; + + if (short) { + options[cmd]['short'] = short; + multiple + } + + if (multiple) { + options[cmd]['multiple'] = multiple; + } +} + +function command_parse(args) { + const { values, positionals } = util.parseArgs({ + args, + options, + allowPositionals: true + }); + + return [ { ...values }, positionals ]; +} + +module.exports = { + command_register, + command_parse +}; diff --git a/source/cli/plugins/cli_cmd_plugin/source/metacall.json b/source/cli/plugins/cli_cmd_plugin/source/metacall.json new file mode 100644 index 000000000..408e5ab54 --- /dev/null +++ b/source/cli/plugins/cli_cmd_plugin/source/metacall.json @@ -0,0 +1,7 @@ +{ + "language_id": "node", + "path": ".", + "scripts": [ + "cli_cmd_plugin.js" + ] +} diff --git a/source/cli/plugins/cli_cmd_plugin/source/test.js b/source/cli/plugins/cli_cmd_plugin/source/test.js new file mode 100644 index 000000000..8e89dc73d --- /dev/null +++ b/source/cli/plugins/cli_cmd_plugin/source/test.js @@ -0,0 +1,9 @@ +const assert = require('assert').strict; +const { command_register, command_parse } = require('./cli_cmd_plugin') + +command_register('help', 'METACALL_BOOL', 'h'); + +assert.deepEqual(command_parse([]), [{}, []]); +assert.deepEqual(command_parse(['-h']), [{ help: true }, []]); +assert.deepEqual(command_parse(['--help']), [{ help: true }, []]); +assert.deepEqual(command_parse(['--help', 'a.js']), [{ help: true }, [ 'a.js' ]]); diff --git a/source/cli/plugins/cli_core_plugin/CMakeLists.txt b/source/cli/plugins/cli_core_plugin/CMakeLists.txt index 486e308b8..634818484 100644 --- a/source/cli/plugins/cli_core_plugin/CMakeLists.txt +++ b/source/cli/plugins/cli_core_plugin/CMakeLists.txt @@ -1,5 +1,5 @@ # Check if this loader is enabled -if(NOT OPTION_BUILD_LOADERS OR NOT OPTION_BUILD_LOADERS_EXT OR NOT OPTION_BUILD_EXTENSIONS) +if(NOT OPTION_BUILD_LOADERS OR NOT OPTION_BUILD_LOADERS_EXT OR NOT OPTION_BUILD_EXTENSIONS OR NOT OPTION_BUILD_LOADERS_NODE) return() endif() @@ -45,13 +45,20 @@ set(sources ${source_path}/cli_core_plugin.cpp ) +set(scripts + ${source_path}/cli_core_plugin_repl.js +) + # Group source files set(header_group "Header Files (API)") set(source_group "Source Files") +set(script_group "Script Files") source_group_by_path(${include_path} "\\\\.h$|\\\\.hpp$" ${header_group} ${headers}) source_group_by_path(${source_path} "\\\\.cpp$|\\\\.c$|\\\\.h$|\\\\.hpp$" ${source_group} ${sources}) +source_group_by_path(${source_path} "\\\\.js$" + ${source_group} ${scripts}) # # Create library @@ -79,7 +86,7 @@ generate_export_header(${target} # Project options # -set(PLUGIN_OUTPUT_DIRECTORY "${PROJECT_OUTPUT_DIR}/plugins/cli/${target}") +set(PLUGIN_OUTPUT_DIRECTORY "${PROJECT_OUTPUT_DIR}/plugins/cli/repl/${target}") set_target_properties(${target} PROPERTIES @@ -182,6 +189,11 @@ target_link_libraries(${target} INTERFACE ) +add_dependencies(${target} + plugin_extension + cli_repl_plugin +) + # # Define dependencies # @@ -191,14 +203,10 @@ add_custom_target(${target}_config ALL WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E make_directory ${PLUGIN_OUTPUT_DIRECTORY} COMMAND ${CMAKE_COMMAND} -E copy ${source_path}/metacall.json ${PLUGIN_OUTPUT_DIRECTORY}/metacall.json + COMMAND ${CMAKE_COMMAND} -E copy ${source_path}/cli_core_plugin_repl.js ${PLUGIN_OUTPUT_DIRECTORY}/cli_core_plugin_repl.js ) set_target_properties(${target}_config PROPERTIES FOLDER "${IDE_FOLDER}" ) - -add_dependencies(${target} - ${target}_config - plugin_extension -) diff --git a/source/cli/plugins/cli_core_plugin/source/cli_core_plugin.cpp b/source/cli/plugins/cli_core_plugin/source/cli_core_plugin.cpp index dc4689308..5563fc426 100644 --- a/source/cli/plugins/cli_core_plugin/source/cli_core_plugin.cpp +++ b/source/cli/plugins/cli_core_plugin/source/cli_core_plugin.cpp @@ -671,6 +671,7 @@ void *debug(size_t argc, void *args[], void *data) int cli_core_plugin(void *loader, void *handle) { + /* Register functions */ EXTENSION_FUNCTION(METACALL_INT, load, METACALL_STRING, METACALL_ARRAY); EXTENSION_FUNCTION(METACALL_INT, inspect); EXTENSION_FUNCTION(METACALL_INT, eval, METACALL_STRING, METACALL_STRING); diff --git a/source/cli/plugins/cli_repl_plugin/source/cli_core_command.js b/source/cli/plugins/cli_core_plugin/source/cli_core_plugin_repl.js similarity index 68% rename from source/cli/plugins/cli_repl_plugin/source/cli_core_command.js rename to source/cli/plugins/cli_core_plugin/source/cli_core_plugin_repl.js index 7794d8552..42081d11e 100644 --- a/source/cli/plugins/cli_repl_plugin/source/cli_core_command.js +++ b/source/cli/plugins/cli_core_plugin/source/cli_core_plugin_repl.js @@ -3,16 +3,7 @@ const all_except_whitespaces = '^[^ \r\n\t\f\v]+'; const func = '^[a-zA-Z0-9_\.]+\\(.*\\)$'; const anychar = '.+'; -/* - * Normally this will be registered in the target plugin, check - * the cli_repl_plugin.js exports to check out how to register commands - * from the plugin initializer (for example, inside cli_core_plugin.cpp in - * the cli_core_plugin function). But we consider this is a necesary plugin - * of the CLI, which implements basic core functionalities for the CLI. In - * that case we can assume this dependency and register from here the REPL - * commands of an external plugin. - */ -const cli_core_command_map = { +module.exports = { load: { regexes: [loaders, all_except_whitespaces], /* Match everything except whitespaces, paths with whitespaces are not supported */ types: ['METACALL_STRING', 'METACALL_ARRAY'], @@ -54,5 +45,3 @@ const cli_core_command_map = { types: [], } }; - -module.exports = { cli_core_command_map }; diff --git a/source/cli/plugins/cli_repl_plugin/CMakeLists.txt b/source/cli/plugins/cli_repl_plugin/CMakeLists.txt index d10495eff..2a05061b6 100644 --- a/source/cli/plugins/cli_repl_plugin/CMakeLists.txt +++ b/source/cli/plugins/cli_repl_plugin/CMakeLists.txt @@ -1,5 +1,5 @@ # Check if this loader is enabled -if(NOT OPTION_BUILD_LOADERS OR NOT OPTION_BUILD_LOADERS_EXT OR NOT OPTION_BUILD_EXTENSIONS) +if(NOT OPTION_BUILD_LOADERS OR NOT OPTION_BUILD_LOADERS_EXT OR NOT OPTION_BUILD_EXTENSIONS OR NOT OPTION_BUILD_LOADERS_NODE) return() endif() @@ -17,13 +17,13 @@ message(STATUS "Plugin ${target}") # Source # -set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/source") +set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/source") # # Destination # -set(PLUGIN_OUTPUT_DIRECTORY "${PROJECT_OUTPUT_DIR}/plugins/repl/${target}") +set(PLUGIN_OUTPUT_DIRECTORY "${PROJECT_OUTPUT_DIR}/plugins/cli/internal/${target}") # # Project Target @@ -34,7 +34,6 @@ add_custom_target(${target} ALL COMMAND ${CMAKE_COMMAND} -E copy ${source_path}/metacall.json ${PLUGIN_OUTPUT_DIRECTORY}/metacall.json COMMAND ${CMAKE_COMMAND} -E copy ${source_path}/cli_repl_plugin.js ${PLUGIN_OUTPUT_DIRECTORY}/cli_repl_plugin.js COMMAND ${CMAKE_COMMAND} -E copy ${source_path}/parser.js ${PLUGIN_OUTPUT_DIRECTORY}/parser.js - COMMAND ${CMAKE_COMMAND} -E copy ${source_path}/cli_core_command.js ${PLUGIN_OUTPUT_DIRECTORY}/cli_core_command.js ) # @@ -52,6 +51,7 @@ set_target_properties(${target} add_dependencies(${target} plugin_extension + node_loader ) # @@ -68,7 +68,7 @@ set(NodeJS_EXECUTABLE_ONLY ON) find_package(NodeJS) if(NOT NodeJS_FOUND) - message(SEND_ERROR "NodeJS libraries not found") + message(SEND_ERROR "NodeJS executable not found") return() endif() diff --git a/source/cli/plugins/cli_repl_plugin/source/cli_repl_plugin.js b/source/cli/plugins/cli_repl_plugin/source/cli_repl_plugin.js index 6e89ce6f8..9551f8154 100644 --- a/source/cli/plugins/cli_repl_plugin/source/cli_repl_plugin.js +++ b/source/cli/plugins/cli_repl_plugin/source/cli_repl_plugin.js @@ -1,10 +1,8 @@ const vm = require('vm'); const r = require('repl'); -const { command_register, command_register_map, command_parse, command_completer } = require('./parser'); -const { cli_core_command_map } = require('./cli_core_command'); - -/* Register CLI Core command map into the parser */ -command_register_map(cli_core_command_map); +const fs = require('fs'); +const path = require('path'); +const { repl_register, repl_register_from_file, repl_parse, repl_completer } = require('./parser'); /* * Method for generating a continuous chain of promises for allowing the repl @@ -30,9 +28,31 @@ const new_repl_promise = () => { let repl_promise = null; let repl = null; -function initialize() { +function repl_initialize(plugin_path) { repl_promise = [new_repl_promise()]; + /* Initialize all REPL descriptors + * This will load all plugin descriptors like: + * plugins/cli/repl/${plugin_name}/${plugin_name}_repl.js + */ + const repl_path = path.join(plugin_path, 'cli', 'repl'); + const files = fs.readdirSync(repl_path); + + for (const file of files) { + const file_path = path.join(repl_path, file); + const file_stat = fs.statSync(file_path); + + if (file_stat.isDirectory()) { + const descriptor_path = path.join(file_path, `${file}_repl.js`); + const descriptor_stat = fs.statSync(descriptor_path); + + if (descriptor_stat.isFile()) { + repl_register_from_file(descriptor_path); + } + } + + } + /* Show welcome message */ console.log('Welcome to Tijuana, tequila, sexo & marijuana.'); @@ -58,7 +78,7 @@ function initialize() { const promise = repl_promise[repl_promise.length - 1]; try { - const result = command_parse(cmd.trim()); + const result = repl_parse(cmd.trim()); promise.resolve([result, cb]); } catch (e) { promise.resolve([e, cb]); @@ -68,7 +88,7 @@ function initialize() { } function completer(line) { - const completions = command_completer(); + const completions = repl_completer(); const hits = completions.filter(c => c.startsWith(line)); return [hits.length ? hits : completions, line]; } @@ -97,7 +117,7 @@ function initialize() { * console.error(e); * }); */ -const evaluate = async () => { +const repl_evaluate = async () => { if (repl_promise !== null) { if (repl_promise.length === 0) { repl_promise.push(new_repl_promise()); @@ -114,8 +134,8 @@ const evaluate = async () => { }; module.exports = { - initialize, - evaluate, + repl_initialize, + repl_evaluate, /* This function is exported so it can be called from other plugins: * * void *repl_handle = metacall_handle("ext", "cli_repl_plugin"); @@ -131,7 +151,7 @@ module.exports = { * void *types = metacall_value_to_array(args[2]); * types[0] = metacall_value_create_string("METACALL_STRING", sizeof("METACALL_STRING") - 1); * - * void *ret = metacallhv_s(repl_handle, "command_register", args, sizeof(args) / sizeof(args[0])); + * void *ret = metacallhv_s(repl_handle, "repl_register", args, sizeof(args) / sizeof(args[0])); * * metacall_value_destroy(args[0]); * metacall_value_destroy(args[1]); @@ -139,9 +159,23 @@ module.exports = { * * metacall_value_destroy(ret); */ - command_register, + repl_register, + + /* This function is exported so it can be called from other plugins: + * + * void *repl_handle = metacall_handle("ext", "cli_repl_plugin"); + * void *args[] = { + * metacall_value_create_string("./cli_core_plugin_repl.js", sizeof("./cli_core_plugin_repl.js") - 1), + * }; + * + * void *ret = metacallhv_s(repl_handle, "repl_register_from_file", args, sizeof(args) / sizeof(args[0])); + * + * metacall_value_destroy(args[0]); + * metacall_value_destroy(ret); + */ + repl_register_from_file, - close: () => { + repl_close: () => { if (repl) { repl.close(); repl = null; diff --git a/source/cli/plugins/cli_repl_plugin/source/parser.js b/source/cli/plugins/cli_repl_plugin/source/parser.js index bb87b1070..d9bd29623 100644 --- a/source/cli/plugins/cli_repl_plugin/source/parser.js +++ b/source/cli/plugins/cli_repl_plugin/source/parser.js @@ -1,6 +1,6 @@ -const command_parser_map = {}; +const repl_parser_map = {}; -function command_parse(cmd) { +function repl_parse(cmd) { const command_str = cmd.toString(); let current_position = command_str.indexOf(' '); @@ -14,7 +14,7 @@ function command_parse(cmd) { return []; } - const command = command_parser_map[key]; + const command = repl_parser_map[key]; if (!command) { throw new Error(`Command '${key}' not valid, use 'help' for more information`); @@ -80,21 +80,29 @@ function command_parse(cmd) { return [key, ...tokens] } -const command_register = (cmd, regexes, types) => { +function repl_register(cmd, regexes, types) { if (regexes.length !== types.length) { throw new Error('Number of Regexes and Types do not match') } - command_parser_map[cmd] = { + repl_parser_map[cmd] = { regexes: regexes.map(re => new RegExp(re, 'g')), types } } +function repl_register_map(map) { + Object.keys(map).forEach(key => repl_register(key, map[key].regexes, map[key].types)); +}; + +function repl_register_from_file(file) { + const map = require(file); + repl_register_map(map); +} + module.exports = { - command_register, - command_register_map: (map) => { - Object.keys(map).forEach(key => command_register(key, map[key].regexes, map[key].types)); - }, - command_completer: () => Object.keys(command_parser_map), - command_parse, + repl_register, + repl_register_map, + repl_register_from_file, + repl_completer: () => Object.keys(repl_parser_map), + repl_parse, }; diff --git a/source/cli/plugins/cli_repl_plugin/source/test.js b/source/cli/plugins/cli_repl_plugin/source/test.js index 4d1e9772b..45ebdb790 100644 --- a/source/cli/plugins/cli_repl_plugin/source/test.js +++ b/source/cli/plugins/cli_repl_plugin/source/test.js @@ -1,52 +1,55 @@ const assert = require('assert').strict; -const { command_register_map, command_parse } = require('./parser'); -const { cli_core_command_map } = require('./cli_core_command'); +const { repl_register_map, repl_parse } = require('./parser'); + +/* Integration Test */ +const cli_core_repl_map = require('../../cli_core_plugin/source/cli_core_plugin_repl'); /* Register commands */ -command_register_map(cli_core_command_map); +repl_register_map(cli_core_repl_map); -assert.deepEqual(command_parse('load py a.py b.py c.py ./a/b/c/d.py'), +assert.deepEqual(repl_parse('load py a.py b.py c.py ./a/b/c/d.py'), ['load', 'py', ['a.py', 'b.py', 'c.py', './a/b/c/d.py']]); -assert.deepEqual(command_parse('inspect'), +assert.deepEqual(repl_parse('inspect'), ['inspect']); -assert.deepEqual(command_parse('eval node console.log("hello world")'), +assert.deepEqual(repl_parse('eval node console.log("hello world")'), ['eval', 'node', 'console.log("hello world")']); -assert.deepEqual(command_parse('call asdf(234, 34, 2, 3, 4, 5)'), +assert.deepEqual(repl_parse('call asdf(234, 34, 2, 3, 4, 5)'), ['call', 'asdf(234, 34, 2, 3, 4, 5)']); -assert.deepEqual(command_parse('call asdf()'), +assert.deepEqual(repl_parse('call asdf()'), ['call', 'asdf()']); assert.throws(() => { - command_parse('call asdf(234, 34, 2, 3, 4, 5', + repl_parse('call asdf(234, 34, 2, 3, 4, 5', "Failed to parse the command: 'asdf(234, 34, 2, 3, 4, 5' of type METACALL_STRING, the expected regex was: /^[a-zA-Z0-9_]+(.+)$/g"); }) assert.throws(() => { - command_parse('call asdf234, 34, 2, 3, 4, 5)', + repl_parse('call asdf234, 34, 2, 3, 4, 5)', "Failed to parse the command: 'asdf234, 34, 2, 3, 4, 5)' of type METACALL_STRING, the expected regex was: /^[a-zA-Z0-9_]+(.+)$/g"); }) -assert.deepEqual(command_parse('clear py a.py'), +assert.deepEqual(repl_parse('clear py a.py'), ['clear', 'py', 'a.py']); -assert.deepEqual(command_parse('copyright'), +assert.deepEqual(repl_parse('copyright'), ['copyright']); -assert.deepEqual(command_parse('help'), +assert.deepEqual(repl_parse('help'), ['help']); -assert.deepEqual(command_parse('debug a b c 1 2 3'), +assert.deepEqual(repl_parse('debug a b c 1 2 3'), ['debug', ['a', 'b', 'c', '1', '2', '3']]); -/* Register test commands */ +/* Unit Test */ const letters = '^[a-zA-Z]+'; const numbers = '^[0-9]+'; -command_register_map({ +/* Register test commands */ +repl_register_map({ /* Following commands are for testing purposes only */ string_array_string: { regexes: [letters, numbers, letters], @@ -54,5 +57,5 @@ command_register_map({ } }); -assert.deepEqual(command_parse('string_array_string yeet 1 2 3 4 5555 6 7 8 9 yeet'), +assert.deepEqual(repl_parse('string_array_string yeet 1 2 3 4 5555 6 7 8 9 yeet'), ['string_array_string', 'yeet', ['1', '2', '3', '4', '5555', '6', '7', '8', '9'], 'yeet']); diff --git a/source/cli/plugins/cli_sandbox_plugin/CMakeLists.txt b/source/cli/plugins/cli_sandbox_plugin/CMakeLists.txt new file mode 100644 index 000000000..5b9823544 --- /dev/null +++ b/source/cli/plugins/cli_sandbox_plugin/CMakeLists.txt @@ -0,0 +1,53 @@ +# Check if this loader is enabled +if(NOT OPTION_BUILD_LOADERS OR NOT OPTION_BUILD_LOADERS_EXT OR NOT OPTION_BUILD_EXTENSIONS OR NOT OPTION_BUILD_LOADERS_NODE) + return() +endif() + +# +# Plugin name and options +# + +# Target name +set(target cli_sandbox_plugin) + +# Exit here if required dependencies are not met +message(STATUS "Plugin ${target}") + +# +# Source +# + +set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/source") + +# +# Destination +# + +set(PLUGIN_OUTPUT_DIRECTORY "${PROJECT_OUTPUT_DIR}/plugins/cli/cmd/${target}") + +# +# Project Target +# + +add_custom_target(${target} ALL + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy ${source_path}/cli_sandbox_plugin_cmd.js ${PLUGIN_OUTPUT_DIRECTORY}/cli_sandbox_plugin_cmd.js +) + +# +# Target Properties +# + +set_target_properties(${target} + PROPERTIES + FOLDER "${IDE_FOLDER}" +) + +# +# Dependencies +# + +add_dependencies(${target} + plugin_extension + node_loader +) diff --git a/source/cli/plugins/cli_sandbox_plugin/source/cli_sandbox_plugin_cmd.js b/source/cli/plugins/cli_sandbox_plugin/source/cli_sandbox_plugin_cmd.js new file mode 100644 index 000000000..9b09184df --- /dev/null +++ b/source/cli/plugins/cli_sandbox_plugin/source/cli_sandbox_plugin_cmd.js @@ -0,0 +1,4 @@ +/* TODO */ +module.exports = { + +}; diff --git a/source/extensions/plugin_extension/source/plugin_extension.cpp b/source/extensions/plugin_extension/source/plugin_extension.cpp index 8431a9e97..9bf4de4cc 100644 --- a/source/extensions/plugin_extension/source/plugin_extension.cpp +++ b/source/extensions/plugin_extension/source/plugin_extension.cpp @@ -38,6 +38,8 @@ namespace fs = std::experimental::filesystem; #include +static void *extension_loader = NULL; + void *plugin_load_from_path(size_t argc, void *args[], void *data) { /* TODO: Improve return values with throwable in the future */ @@ -70,6 +72,15 @@ void *plugin_load_from_path(size_t argc, void *args[], void *data) if (argc == 2) { handle_ptr = static_cast(metacall_value_to_ptr(args[1])); + + /* Initialize the handle in case it is null for the first iteration */ + if (*handle_ptr == NULL) + { + if (metacall_handle_initialize(extension_loader, ext_path.c_str(), handle_ptr) != 0) + { + log_write("metacall", LOG_LEVEL_ERROR, "Failed to initialize handle with plugin: %s", ext_path.c_str()); + } + } } static std::string m_begins = "metacall-"; @@ -96,17 +107,30 @@ void *plugin_load_from_path(size_t argc, void *args[], void *data) config.substr(config.size() - m_ends.size()) == m_ends)) { std::string dir_path = dir.path().string(); + void *current_handle = NULL; + void **current_handle_ptr = (handle_ptr != NULL && *handle_ptr != NULL) ? ¤t_handle : NULL; log_write("metacall", LOG_LEVEL_DEBUG, "Loading plugin: %s", dir_path.c_str()); - if (metacall_load_from_configuration(dir_path.c_str(), handle_ptr, config_allocator) != 0) + /* On each iteration, pass a new handle to metacall_load_from_configuration */ + if (metacall_load_from_configuration(dir_path.c_str(), current_handle_ptr, config_allocator) != 0) { log_write("metacall", LOG_LEVEL_ERROR, "Failed to load plugin: %s", dir_path.c_str()); metacall_allocator_destroy(config_allocator); return metacall_value_create_int(4); } + /* Populate the current handle into the handle_ptr */ + if (handle_ptr != NULL && *handle_ptr != NULL) + { + if (metacall_handle_populate(*handle_ptr, current_handle) != 0) + { + log_write("metacall", LOG_LEVEL_ERROR, "Failed to populate handle in plugin: %s", dir_path.c_str()); + } + } + i++; + if (i != fs::end(i) && i.depth() == 1) { i.pop(); @@ -128,5 +152,8 @@ int plugin_extension(void *loader, void *handle) /* Register function */ EXTENSION_FUNCTION(METACALL_INT, plugin_load_from_path, METACALL_STRING, METACALL_PTR); + /* Store the loader reference for later on */ + extension_loader = loader; + return 0; } diff --git a/source/loader/include/loader/loader.h b/source/loader/include/loader/loader.h index 52fe51f02..b7fec73ec 100644 --- a/source/loader/include/loader/loader.h +++ b/source/loader/include/loader/loader.h @@ -83,12 +83,16 @@ LOADER_API void loader_set_options(const loader_tag tag, void *options); LOADER_API void *loader_get_options(const loader_tag tag); +LOADER_API int loader_handle_initialize(loader_impl impl, const loader_path name, void **handle_ptr); + LOADER_API const char *loader_handle_id(void *handle); LOADER_API void *loader_handle_export(void *handle); LOADER_API loader_data loader_handle_get(void *handle, const char *name); +LOADER_API int loader_handle_populate(void *handle_dest, void *handle_src); + LOADER_API value loader_metadata(void); LOADER_API int loader_clear(void *handle); diff --git a/source/loader/include/loader/loader_impl.h b/source/loader/include/loader/loader_impl.h index 5160171e7..c6c8826d6 100644 --- a/source/loader/include/loader/loader_impl.h +++ b/source/loader/include/loader/loader_impl.h @@ -69,6 +69,10 @@ LOADER_API void loader_impl_set_options(loader_impl impl, void *options); LOADER_API void *loader_impl_get_options(loader_impl impl); +LOADER_API int loader_impl_handle_initialize(plugin_manager manager, plugin p, loader_impl impl, const loader_path name, void **handle_ptr); + +LOADER_API vector loader_impl_handle_populated(void *handle); + LOADER_API const char *loader_impl_handle_id(void *handle); LOADER_API value loader_impl_handle_export(void *handle); diff --git a/source/loader/source/loader.c b/source/loader/source/loader.c index 1507835f7..82bb7d5a4 100644 --- a/source/loader/source/loader.c +++ b/source/loader/source/loader.c @@ -554,6 +554,39 @@ void *loader_get_options(const loader_tag tag) return loader_impl_get_options(plugin_impl_type(p, loader_impl)); } +int loader_handle_initialize(loader_impl impl, const loader_path name, void **handle_ptr) +{ + if (loader_initialize() == 1) + { + return 1; + } + + plugin p = loader_impl_plugin(impl); + + return loader_impl_handle_initialize(&loader_manager, p, impl, name, handle_ptr); +} + +int loader_handle_populate(void *handle_dest, void *handle_src) +{ + context ctx_dest = loader_impl_handle_context(handle_dest); + context ctx_src = loader_impl_handle_context(handle_src); + char *duplicated_key; + + if (context_contains(ctx_src, ctx_dest, &duplicated_key) == 0 && duplicated_key != NULL) + { + log_write("metacall", LOG_LEVEL_ERROR, "Duplicated symbol found named '%s' already defined in the handle scope", duplicated_key); + return 1; + } + else if (context_append(ctx_dest, ctx_src) == 0) + { + vector_push_back_var(loader_impl_handle_populated(handle_src), handle_dest); + + return 0; + } + + return 1; +} + const char *loader_handle_id(void *handle) { return loader_impl_handle_id(handle); diff --git a/source/loader/source/loader_impl.c b/source/loader/source/loader_impl.c index f63fe9e23..c6ccf3297 100644 --- a/source/loader/source/loader_impl.c +++ b/source/loader/source/loader_impl.c @@ -579,7 +579,7 @@ void loader_impl_destroy_handle(loader_handle_impl handle_impl) log_write("metacall", LOG_LEVEL_ERROR, "Error when calling destructor from handle impl: %p (%s)", (void *)handle_impl, func_fini_name); } - if (handle_impl->iface->clear(handle_impl->impl, handle_impl->module) != 0) + if (handle_impl->module != NULL && handle_impl->iface->clear(handle_impl->impl, handle_impl->module) != 0) { log_write("metacall", LOG_LEVEL_ERROR, "Error when clearing handle impl: %p", (void *)handle_impl); } @@ -1168,6 +1168,81 @@ void *loader_impl_get_options(loader_impl impl) return NULL; } +int loader_impl_handle_initialize(plugin_manager manager, plugin p, loader_impl impl, const loader_path name, void **handle_ptr) +{ + if (impl != NULL) + { + loader_impl_interface iface = loader_iface(p); + + if (iface != NULL) + { + loader_path path; + size_t init_order; + + if (loader_impl_initialize(manager, p, impl) != 0) + { + return 1; + } + + if (loader_impl_handle_name(manager, name, path) > 1 && loader_impl_get_handle(impl, path) != NULL) + { + log_write("metacall", LOG_LEVEL_ERROR, "Initialize handle failed, handle with name %s already loaded", path); + + return 1; + } + + init_order = vector_size(impl->handle_impl_init_order); + + vector_push_back_empty(impl->handle_impl_init_order); + + loader_handle_impl handle_impl = loader_impl_load_handle(impl, iface, NULL, path, LOADER_PATH_SIZE); + + if (handle_impl != NULL) + { + handle_impl->populated = 1; + + if (set_insert(impl->handle_impl_path_map, handle_impl->path, handle_impl) == 0) + { + if (loader_impl_handle_register(manager, impl, path, handle_impl, handle_ptr) == 0) + { + vector_set_var(impl->handle_impl_init_order, init_order, handle_impl); + + return 0; + } + + set_remove(impl->handle_impl_path_map, handle_impl->path); + } + + { + size_t iterator; + + for (iterator = init_order + 1; iterator < vector_size(impl->handle_impl_init_order); ++iterator) + { + loader_handle_impl iterator_handle_impl = vector_at_type(impl->handle_impl_init_order, iterator, loader_handle_impl); + + loader_impl_destroy_handle(iterator_handle_impl); + } + + vector_pop_back(impl->handle_impl_init_order); + } + + log_write("metacall", LOG_LEVEL_ERROR, "Error when loading handle: %s", path); + + loader_impl_destroy_handle(handle_impl); + } + } + } + + return 1; +} + +vector loader_impl_handle_populated(void *handle) +{ + loader_handle_impl handle_impl = handle; + + return handle_impl->populated_handles; +} + const char *loader_impl_handle_id(void *handle) { loader_handle_impl handle_impl = handle; diff --git a/source/loaders/ext_loader/source/ext_loader_impl.cpp b/source/loaders/ext_loader/source/ext_loader_impl.cpp index 39d9db653..0b8f96ec8 100644 --- a/source/loaders/ext_loader/source/ext_loader_impl.cpp +++ b/source/loaders/ext_loader/source/ext_loader_impl.cpp @@ -194,6 +194,7 @@ dynlink ext_loader_impl_load_from_file_dynlink(loader_impl_ext ext_impl, const l int ext_loader_impl_load_from_file_handle(loader_impl_ext ext_impl, loader_impl_ext_handle ext_handle, const loader_path path) { auto iterator = ext_impl->destroy_list.find(path); + if (iterator != ext_impl->destroy_list.end()) { log_write("metacall", LOG_LEVEL_DEBUG, "Unloading handle: %s <%p>", iterator->second.name.c_str(), iterator->second.handle); diff --git a/source/metacall/include/metacall/metacall.h b/source/metacall/include/metacall/metacall.h index 1b130c40b..a1cea928f 100644 --- a/source/metacall/include/metacall/metacall.h +++ b/source/metacall/include/metacall/metacall.h @@ -498,6 +498,39 @@ METACALL_API void *metacallht_s(void *handle, const char *name, const enum metac */ METACALL_API void *metacall_function(const char *name); +/** +* @brief +* Create an empty handler into a loader with name @name +* +* @param[in] loader +* Pointer to the loader which the handle belongs to +* +* @param[in] name +* Name of the handle +* +* @param[out] handle_ptr +* On success, returns the pointer to the handle created, otherwise NULL +* +* @return +* Return zero on success, different from zero on error +*/ +METACALL_API int metacall_handle_initialize(void *loader, const char *name, void **handle_ptr); + +/** +* @brief +* Populate the objects of @handle_src into @handle_dest +* +* @param[inout] handle_dest +* Handle where the objects from @handle_src will be stored +* +* @param[in] handle_src +* Handle from where the objects will be copied +* +* @return +* Return zero on success, different from zero on error +*/ +METACALL_API int metacall_handle_populate(void *handle_dest, void *handle_src); + /** * @brief * Get the function by @name from @handle @@ -1426,6 +1459,15 @@ METACALL_API int metacall_clear(void *handle); */ METACALL_API void *metacall_plugin_extension(void); +/** +* @brief +* Get the handle containing all the functionality of the plugins from core +* +* @return +* Pointer to the core plugin handle, or null if it failed to load +*/ +METACALL_API void *metacall_plugin_core(void); + /** * @brief * Get the plugin extension path to be used for accessing the plugins folder diff --git a/source/metacall/source/metacall.c b/source/metacall/source/metacall.c index fa9458607..45ce6bf0f 100644 --- a/source/metacall/source/metacall.c +++ b/source/metacall/source/metacall.c @@ -59,6 +59,7 @@ static int metacall_config_flags = 0; static int metacall_initialize_argc = 0; static char **metacall_initialize_argv = NULL; static void *plugin_extension_handle = NULL; +static void *plugin_core_handle = NULL; static loader_path plugin_path = { 0 }; /* -- Private Methods -- */ @@ -109,7 +110,7 @@ int metacall_plugin_extension_load(void) /* Load core plugins into plugin extension handle */ args[0] = metacall_value_create_string(plugin_path, plugin_path_size - 1); - args[1] = metacall_value_create_ptr(&plugin_extension_handle); + args[1] = metacall_value_create_ptr(&plugin_core_handle); ret = metacallhv_s(plugin_extension_handle, "plugin_load_from_path", args, sizeof(args) / sizeof(args[0])); if (ret == NULL) @@ -862,6 +863,26 @@ void *metacall_function(const char *name) return f; } +int metacall_handle_initialize(void *loader, const char *name, void **handle_ptr) +{ + if (loader == NULL) + { + return 1; + } + + return loader_handle_initialize(loader, name, handle_ptr); +} + +int metacall_handle_populate(void *handle_dest, void *handle_src) +{ + if (handle_dest == NULL || handle_src == NULL) + { + return 1; + } + + return loader_handle_populate(handle_dest, handle_src); +} + void *metacall_handle_function(void *handle, const char *name) { if (loader_impl_handle_validate(handle) != 0) @@ -2210,6 +2231,11 @@ void *metacall_plugin_extension(void) return plugin_extension_handle; } +void *metacall_plugin_core(void) +{ + return plugin_core_handle; +} + const char *metacall_plugin_path(void) { if (plugin_extension_handle == NULL) @@ -2235,8 +2261,9 @@ int metacall_destroy(void) /* Print stats from functions, classes, objects and exceptions */ reflect_memory_tracker_debug(); - /* Set to null the plugin extension */ + /* Set to null the plugin extension and core plugin handles */ plugin_extension_handle = NULL; + plugin_core_handle = NULL; } return 0; diff --git a/source/tests/metacall_cli_core_plugin_await_test/CMakeLists.txt b/source/tests/metacall_cli_core_plugin_await_test/CMakeLists.txt index 79036d226..7b8eb00ca 100644 --- a/source/tests/metacall_cli_core_plugin_await_test/CMakeLists.txt +++ b/source/tests/metacall_cli_core_plugin_await_test/CMakeLists.txt @@ -92,12 +92,22 @@ target_link_libraries(${target} # Compile definitions # +set(METACALL_PLUGIN_PATH "${PROJECT_OUTPUT_DIR}/metacall_cli_core_plugin_await_test") + target_compile_definitions(${target} PRIVATE ${DEFAULT_COMPILE_DEFINITIONS} # Plugin path - METACALL_PLUGIN_PATH="${CMAKE_CURRENT_SOURCE_DIR}/plugins" + METACALL_PLUGIN_PATH="${METACALL_PLUGIN_PATH}" +) + +# Isolate the plugin into a different directory in order to make it fully reproducible +add_custom_command(TARGET ${target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${METACALL_PLUGIN_PATH}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${METACALL_PLUGIN_PATH}/cli_core_plugin" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${PROJECT_OUTPUT_DIR}/plugins/cli/repl/cli_core_plugin" "${METACALL_PLUGIN_PATH}/cli_core_plugin" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/plugins/await_test" "${METACALL_PLUGIN_PATH}/await_test" ) # @@ -108,14 +118,6 @@ target_compile_options(${target} PRIVATE ${DEFAULT_COMPILE_OPTIONS} ) -# -# Compile features -# - -target_compile_features(${target} - PRIVATE - cxx_std_17 # Required for filesystem -) # # Linker options diff --git a/source/tests/metacall_cli_core_plugin_await_test/plugins/await_test/await_test.js b/source/tests/metacall_cli_core_plugin_await_test/plugins/await_test/await_test.js index 462aaa947..9332bc90d 100644 --- a/source/tests/metacall_cli_core_plugin_await_test/plugins/await_test/await_test.js +++ b/source/tests/metacall_cli_core_plugin_await_test/plugins/await_test/await_test.js @@ -11,4 +11,4 @@ function await__test(await_cb) { return 22; } -module.exports = await__test +module.exports = await__test; diff --git a/source/tests/metacall_cli_core_plugin_await_test/source/metacall_cli_core_plugin_await_test.cpp b/source/tests/metacall_cli_core_plugin_await_test/source/metacall_cli_core_plugin_await_test.cpp index add0680cc..05b98823b 100644 --- a/source/tests/metacall_cli_core_plugin_await_test/source/metacall_cli_core_plugin_await_test.cpp +++ b/source/tests/metacall_cli_core_plugin_await_test/source/metacall_cli_core_plugin_await_test.cpp @@ -23,20 +23,6 @@ #include #include -#if defined __has_include - #if __has_include() - #include -namespace fs = std::filesystem; - #elif __has_include() - #include -namespace fs = std::experimental::filesystem; - #else - #error "Missing the header." - #endif -#else - #error "C++ standard too old for compiling this file." -#endif - class metacall_cli_core_plugin_await_test : public testing::Test { public: @@ -49,16 +35,17 @@ TEST_F(metacall_cli_core_plugin_await_test, DefaultConstructor) ASSERT_EQ((int)0, (int)metacall_initialize()); /* Extension */ - void *handle = metacall_plugin_extension(); + void *plugin_extension_handle = metacall_plugin_extension(); + void *cli_plugin_handle = NULL; - ASSERT_NE((void *)NULL, (void *)handle); + ASSERT_NE((void *)NULL, (void *)plugin_extension_handle); void *args[] = { metacall_value_create_string(METACALL_PLUGIN_PATH, sizeof(METACALL_PLUGIN_PATH) - 1), - metacall_value_create_ptr(&handle) + metacall_value_create_ptr(&cli_plugin_handle) }; - void *result = metacallhv_s(handle, "plugin_load_from_path", args, sizeof(args) / sizeof(args[0])); + void *result = metacallhv_s(plugin_extension_handle, "plugin_load_from_path", args, sizeof(args) / sizeof(args[0])); ASSERT_NE((void *)NULL, (void *)result); @@ -70,34 +57,6 @@ TEST_F(metacall_cli_core_plugin_await_test, DefaultConstructor) metacall_value_destroy(args[1]); metacall_value_destroy(result); - /* Get core plugin path and handle in order to load cli plugins */ - const char *plugin_path = metacall_plugin_path(); - void *plugin_extension_handle = metacall_plugin_extension(); - void *cli_plugin_handle = NULL; - - ASSERT_NE((const char *)plugin_path, (const char *)NULL); - ASSERT_NE((void *)plugin_extension_handle, (void *)NULL); - - /* Define the cli plugin path as string (core plugin path plus cli) */ - fs::path plugin_cli_path(plugin_path); - plugin_cli_path /= "cli"; - std::string plugin_cli_path_str(plugin_cli_path.string()); - - /* Load cli plugins into plugin cli handle */ - void *args_cli[] = { - metacall_value_create_string(plugin_cli_path_str.c_str(), plugin_cli_path_str.length()), - metacall_value_create_ptr(&cli_plugin_handle) - }; - - result = metacallhv_s(plugin_extension_handle, "plugin_load_from_path", args_cli, sizeof(args_cli) / sizeof(args_cli[0])); - - ASSERT_NE((void *)result, (void *)NULL); - ASSERT_EQ((int)0, (int)metacall_value_to_int(result)); - - metacall_value_destroy(args_cli[0]); - metacall_value_destroy(args_cli[1]); - metacall_value_destroy(result); - /* Test eval */ void *func = metacall_handle_function(cli_plugin_handle, "eval"); @@ -132,7 +91,7 @@ TEST_F(metacall_cli_core_plugin_await_test, DefaultConstructor) metacall_value_create_function(func) }; - result = metacallhv_s(handle, "await__test", args_test, sizeof(args_test) / sizeof(args_test[0])); + result = metacallhv_s(cli_plugin_handle, "await__test", args_test, sizeof(args_test) / sizeof(args_test[0])); EXPECT_NE((void *)NULL, (void *)result); diff --git a/source/tests/metacall_cli_core_plugin_test/CMakeLists.txt b/source/tests/metacall_cli_core_plugin_test/CMakeLists.txt index 8607fe9c2..0d595c18c 100644 --- a/source/tests/metacall_cli_core_plugin_test/CMakeLists.txt +++ b/source/tests/metacall_cli_core_plugin_test/CMakeLists.txt @@ -96,7 +96,7 @@ target_compile_definitions(${target} PRIVATE ${DEFAULT_COMPILE_DEFINITIONS} - CLI_CORE_PLUGIN_PATH="${PROJECT_OUTPUT_DIR}/plugins/cli/cli_core_plugin/metacall.json" + CLI_CORE_PLUGIN_PATH="${PROJECT_OUTPUT_DIR}/plugins/cli/repl/cli_core_plugin/metacall.json" ) # diff --git a/source/tests/metacall_plugin_extension_destroy_order_test/CMakeLists.txt b/source/tests/metacall_plugin_extension_destroy_order_test/CMakeLists.txt index 2eed9975b..31b7a87e8 100644 --- a/source/tests/metacall_plugin_extension_destroy_order_test/CMakeLists.txt +++ b/source/tests/metacall_plugin_extension_destroy_order_test/CMakeLists.txt @@ -92,11 +92,21 @@ target_link_libraries(${target} # Compile definitions # +set(METACALL_PLUGIN_PATH "${PROJECT_OUTPUT_DIR}/metacall_plugin_extension_destroy_order_test") + target_compile_definitions(${target} PRIVATE ${DEFAULT_COMPILE_DEFINITIONS} - METACALL_PLUGIN_PATH="${PROJECT_OUTPUT_DIR}/plugins/cli" + # Plugin path + METACALL_PLUGIN_PATH="${METACALL_PLUGIN_PATH}" +) + +# Isolate the plugin into a different directory in order to make it fully reproducible +add_custom_command(TARGET ${target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${METACALL_PLUGIN_PATH}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${METACALL_PLUGIN_PATH}/cli_core_plugin" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${PROJECT_OUTPUT_DIR}/plugins/cli/repl/cli_core_plugin" "${METACALL_PLUGIN_PATH}/cli_core_plugin" ) #