forked from EvergreenCrypto/docker-finance
container: finance: lib_root/completion: add Pluggable support
- Adds Pluggable auto-(un)load support - Adds plugin dispatcher for interpreter - Refactors to support new Pluggable system - Updates usage help and improves documentation
This commit is contained in:
@@ -145,7 +145,7 @@ function docker-finance::completion()
|
|||||||
mapfile -t _root < <({
|
mapfile -t _root < <({
|
||||||
find "${DOCKER_FINANCE_CONTAINER_PLUGINS}"/root "${_args[@]}" -printf 'plugins/custom/%P\n' 2>/dev/null
|
find "${DOCKER_FINANCE_CONTAINER_PLUGINS}"/root "${_args[@]}" -printf 'plugins/custom/%P\n' 2>/dev/null
|
||||||
find "${DOCKER_FINANCE_CONTAINER_REPO}"/plugins/root "${_args[@]}" -printf 'plugins/repo/%P\n' 2>/dev/null
|
find "${DOCKER_FINANCE_CONTAINER_REPO}"/plugins/root "${_args[@]}" -printf 'plugins/repo/%P\n' 2>/dev/null
|
||||||
find "${DOCKER_FINANCE_CONTAINER_REPO}"/src/root/macro "${_args[@]}" -printf 'macro/%P\n' 2>/dev/null
|
find "${DOCKER_FINANCE_CONTAINER_REPO}"/src/root/macro "${_args[@]}" -printf 'macros/repo/%P\n' 2>/dev/null
|
||||||
})
|
})
|
||||||
declare -r _root
|
declare -r _root
|
||||||
mapfile -t _reply < <(compgen -W "help ${_root[*]}" -- "$_cur")
|
mapfile -t _reply < <(compgen -W "help ${_root[*]}" -- "$_cur")
|
||||||
|
|||||||
@@ -59,9 +59,10 @@ function lib_root::__parse_root()
|
|||||||
|
|
||||||
[TAB COMPLETION]: load (and run) given macro/plugin when starting interpreter
|
[TAB COMPLETION]: load (and run) given macro/plugin when starting interpreter
|
||||||
|
|
||||||
macro = repository macros in repository location
|
macros/repo = macros in repository location
|
||||||
plugins/custom = custom plugins in custom plugin location
|
macros/custom = WIP (not currently supported)
|
||||||
plugins/repo = repository plugins in repository location
|
plugins/repo = plugins in repository location
|
||||||
|
plugins/custom = plugins in custom plugin location
|
||||||
|
|
||||||
[args]: arguments to macro or plugin
|
[args]: arguments to macro or plugin
|
||||||
|
|
||||||
@@ -72,30 +73,49 @@ function lib_root::__parse_root()
|
|||||||
|
|
||||||
\e[37;2m# The output of tab completion\e[0m
|
\e[37;2m# The output of tab completion\e[0m
|
||||||
$ $global_usage \\\t\\\t
|
$ $global_usage \\\t\\\t
|
||||||
help macro/crypto/random.C macro/test/unit.C plugins/custom/example.cc
|
help macros/repo/test/benchmark.C plugins/custom/example.cc
|
||||||
macro/crypto/hash.C macro/test/benchmark.C macro/web/server.C plugins/repo/example.cc
|
macros/repo/crypto/hash.C macros/repo/test/unit.C plugins/repo/bitcoin/bitcoin.cc
|
||||||
|
macros/repo/crypto/random.C macros/repo/web/server.C plugins/repo/example/example.cc
|
||||||
|
|
||||||
\e[37;2m# Load and run the repo's Web server macro\e[0m
|
\e[37;2m# Load and run repo's Web server macro\e[0m
|
||||||
\e[37;2m# NOTE: this macro will maintain a running ROOT instance\e[0m
|
\e[37;2m# NOTE: only server macros will maintain a running ROOT instance (others will 'one-off')\e[0m
|
||||||
$ $global_usage macro/web/server.C
|
$ $global_usage macros/repo/web/server.C
|
||||||
|
|
||||||
\e[37;2m# Load and run the repo's Hash macro with an argument\e[0m
|
\e[37;2m# Load and run repo's Hash macro with loader argument 'this is a test message'\e[0m
|
||||||
\e[37;2m# NOTE: this macro will 'one-off' the ROOT instance\e[0m
|
$ $global_usage macros/repo/crypto/hash.C 'this is a test message'
|
||||||
$ $global_usage macro/crypto/hash.C 'this is a test message'
|
|
||||||
|
|
||||||
\e[37;2m# Load repo example plugin, run within instance\e[0m
|
\e[37;2m# Load and run unit tests for only Pluggable types, using filter as loader argument\e[0m
|
||||||
$ $global_usage plugins/repo/example.cc
|
$ $global_usage macros/repo/test/unit.C 'Pluggable*:Macro*:Plugin*'
|
||||||
|
|
||||||
|
\e[37;2m# Load and use repo's example plugin, dispatching with trivial loader and unloader arguments\e[0m
|
||||||
|
$ $global_usage plugins/repo/example/example.cc 'int i{123}; i' 'std::cout << --i << std::endl;'
|
||||||
root [0]
|
root [0]
|
||||||
Interpreting: '.L /home/business/docker-finance/plugins/root/example.cc'
|
Processing macro/rootlogon.C...
|
||||||
root [1] dfi::plugin::my_plugin_namespace::example\\\t
|
|
||||||
example1
|
|
||||||
example2
|
|
||||||
example3
|
|
||||||
root [1] dfi::plugin::my_plugin_namespace::example2()
|
|
||||||
...
|
...
|
||||||
|
Loading: '${DOCKER_FINANCE_CONTAINER_REPO}/plugins/root/example/example.cc'
|
||||||
|
Interpreting: 'dfi::plugin::example::example_cc::load(\"int i{123}; i\")'
|
||||||
|
...
|
||||||
|
Interpreting: 'int i{123}; i'
|
||||||
|
(int) 123
|
||||||
|
root [3] dfi::plugin::example::Example e; // Plugin's Example class is now available to use
|
||||||
|
root [4] e.example2()
|
||||||
|
...
|
||||||
|
root [5] g_plugin_example_cc.unload() // Plugin is a global instance based on Pluggable entrypoint name
|
||||||
|
Interpreting: 'dfi::plugin::example::example_cc::unload(\"std::cout << --i << std::endl;\")'
|
||||||
|
Interpreting: 'std::cout << --i << std::endl;'
|
||||||
|
122
|
||||||
|
...
|
||||||
|
root [6] e.example2() // Since plugin has been unloaded, this is expected to not compile
|
||||||
|
input_line_27:2:3: error: use of undeclared identifier 'e'
|
||||||
|
(e.example2())
|
||||||
|
^
|
||||||
|
Error in <HandleInterpreterException>: Error evaluating expression (e.example2())
|
||||||
|
Execution of your code was aborted.
|
||||||
|
root [7] .quit
|
||||||
|
$
|
||||||
"
|
"
|
||||||
|
|
||||||
if [[ "$#" -gt 0 && ! "$_arg" =~ (^macro/|^plugins/) ]]; then
|
if [[ "$#" -gt 0 && ! "$_arg" =~ (^macros/|^plugins/) ]]; then
|
||||||
lib_utils::die_usage "$_usage"
|
lib_utils::die_usage "$_usage"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -106,19 +126,18 @@ function lib_root::__parse_root()
|
|||||||
# Macro
|
# Macro
|
||||||
#
|
#
|
||||||
|
|
||||||
if [[ "$_arg" =~ ^macro ]]; then
|
if [[ "$_arg" =~ ^macros ]]; then
|
||||||
# TODO: utilize stub when 'repo/' and 'custom/' is implemented (like plugins)
|
local -r _macro="${_stub#*/}"
|
||||||
local -r _macro="$_arg"
|
|
||||||
|
|
||||||
# Repo macros
|
# Repo macros
|
||||||
[ ! -f "${DOCKER_FINANCE_CONTAINER_REPO}/src/root/${_macro}" ] \
|
[ ! -f "${DOCKER_FINANCE_CONTAINER_REPO}/src/root/macro/${_macro}" ] \
|
||||||
&& lib_utils::die_fatal "repo macro not found '${_macro}'"
|
&& lib_utils::die_fatal "repo macro not found '${_macro}'"
|
||||||
|
|
||||||
# TODO: currently, only repo macros are supported
|
# TODO: currently, only repo macros are supported
|
||||||
# (no custom macros, use custom plugins instead)
|
# (no custom macros, use custom plugins instead)
|
||||||
|
|
||||||
# Per API (v1), requires path stub format
|
# Per API (v1), requires path stub format
|
||||||
declare -gr global_arg_macro="$_macro"
|
declare -gr global_arg_macro="$_stub"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -181,64 +200,82 @@ function lib_root::__root()
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# Macro: non-interactive opts
|
# Pluggable's arguments
|
||||||
|
#
|
||||||
|
|
||||||
|
local _load_arg="${*:2:1}"
|
||||||
|
local _unload_arg="${*:3}"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Pluggable: macro
|
||||||
#
|
#
|
||||||
|
|
||||||
if [ ! -z "$global_arg_macro" ]; then
|
if [ ! -z "$global_arg_macro" ]; then
|
||||||
_exec+=("-e" "dfi::macro::load(\"${global_arg_macro}\")")
|
|
||||||
|
|
||||||
# NOTE:
|
|
||||||
#
|
|
||||||
# - Currently, only repo macros are supported
|
|
||||||
#
|
|
||||||
# * Per API (v1):
|
|
||||||
#
|
|
||||||
# - filename is named after class
|
|
||||||
# * classes begin uppercase
|
|
||||||
# * filename begins lowercase
|
|
||||||
#
|
|
||||||
# - run() static function is the entry point for all macros
|
|
||||||
#
|
|
||||||
|
|
||||||
# TODO: modify substring when 'repo/' and 'custom/' is implemented (like plugins)
|
|
||||||
|
|
||||||
local _namespace="${global_arg_macro#*/}"
|
|
||||||
_namespace="${_namespace%/*}"
|
|
||||||
declare -r _namespace
|
|
||||||
|
|
||||||
local _class="${global_arg_macro##*/}"
|
local _class="${global_arg_macro##*/}"
|
||||||
_class="${_class^}"
|
_class="${_class^}"
|
||||||
_class="${_class%.*}"
|
_class="${_class%.*}"
|
||||||
declare -r _class
|
declare -r _class
|
||||||
|
|
||||||
local -r _caller="dfi::macro::${_namespace}::${_class}"
|
# NOTE: for benchmarks, google benchmark does not have a gtest equivalent of
|
||||||
|
# `GTEST_FLAG(filter)`, but will process shell environment `BENCHMARK_FILTER`
|
||||||
# Per-API signatures (v1)
|
if [[ "${_class%.*}" == "Benchmark" ]]; then
|
||||||
if [[ ${_class} == "Hash" ]]; then
|
declare -grx BENCHMARK_FILTER="$_load_arg"
|
||||||
# If no message is given, default to unique profile/subprofile
|
# Current impl will treat the load arg as code which, in this case, is not
|
||||||
[[ -z "$global_parent_profile" || -z "$global_arg_delim_1" || -z "$global_child_profile" ]] && lib_utils::die_fatal
|
unset _load_arg
|
||||||
[ -z "${*:2}" ] \
|
|
||||||
&& _run="run(\"${global_parent_profile}${global_arg_delim_1}${global_child_profile}\")" \
|
|
||||||
|| _run="run(\"${*:2}\")"
|
|
||||||
else
|
|
||||||
_run="run()"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_exec+=("-e" "${_caller}::${_run}")
|
_exec+=("-e" "dfi::macro::load(\"${global_arg_macro}\", \"${_load_arg}\")")
|
||||||
|
|
||||||
# NOTE: when called via shell, server(s) are implied to
|
# NOTE: when calling via shell, server(s) are implied to
|
||||||
# require an interactive ROOT instance (not a 'one-off').
|
# require an interactive ROOT instance (not a 'one-off')
|
||||||
if [[ "${_class%.*}" != "Server" ]]; then
|
if [[ "${_class%.*}" != "Server" ]]; then
|
||||||
_exec+=('-q')
|
_exec+=('-q')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# NOTE: currently no need to "dfi::macro::unload()" from here
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# Plugin: non-interactive opts
|
# Pluggable: plugin
|
||||||
#
|
#
|
||||||
|
|
||||||
if [ ! -z "$global_arg_plugin" ]; then
|
if [ ! -z "$global_arg_plugin" ]; then
|
||||||
_exec+=("-e" "dfi::plugin::load(\"${global_arg_plugin}\")")
|
|
||||||
|
#
|
||||||
|
# Instead of using one-off wrappers, the following leaves the plugin's state
|
||||||
|
# intact during interpreter runtime.
|
||||||
|
#
|
||||||
|
# WARNING:
|
||||||
|
#
|
||||||
|
# The dispatcher (or any declarations outside of the dispatcher)
|
||||||
|
# will appear in the global namespace of the interpreter!
|
||||||
|
#
|
||||||
|
|
||||||
|
# Gives plugin a global instance based on Pluggable entrypoint name
|
||||||
|
local _name="${global_arg_plugin##*/}"
|
||||||
|
_name="g_plugin_${_name%.*}_${_name#*.}"
|
||||||
|
declare -r _name
|
||||||
|
|
||||||
|
local _code
|
||||||
|
_code+="using t_path = dfi::plugin::common::PluginPath;"
|
||||||
|
_code+="t_path path{\"${global_arg_plugin}\"};"
|
||||||
|
|
||||||
|
_code+="using t_space = dfi::plugin::common::PluginSpace;"
|
||||||
|
_code+="t_space space{path.parent(), path.child()};"
|
||||||
|
|
||||||
|
_code+="using t_args = dfi::plugin::common::PluginArgs;"
|
||||||
|
_code+="t_args args{\"${_load_arg}\", \"${_unload_arg}\"};"
|
||||||
|
|
||||||
|
_code+="dfi::common::type::Pluggable<t_path, t_space, t_args> type{path, space, args};"
|
||||||
|
_code+="dfi::plugin::common::Plugin plugin{type};"
|
||||||
|
|
||||||
|
local _dispatch="auto dispatch = []() -> auto { $_code; return plugin; };"
|
||||||
|
_dispatch+="auto ${_name} = dispatch();"
|
||||||
|
|
||||||
|
# NOTE: unload() at will, inside the interpreter
|
||||||
|
_exec+=("-e" "$_dispatch" "-e" "${_name}.load();")
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
Reference in New Issue
Block a user