diff --git a/container/src/finance/lib/internal/lib_root.bash b/container/src/finance/lib/internal/lib_root.bash index 7febbd4..efd166c 100644 --- a/container/src/finance/lib/internal/lib_root.bash +++ b/container/src/finance/lib/internal/lib_root.bash @@ -107,17 +107,18 @@ function lib_root::__parse_root() # if [[ "$_arg" =~ ^macro ]]; then - local -r _macro="$_stub" + # TODO: utilize stub when 'repo/' and 'custom/' is implemented (like plugins) + local -r _macro="$_arg" # Repo macros - [ ! -f "${DOCKER_FINANCE_CONTAINER_REPO}/src/root/macro/${_macro}" ] \ + [ ! -f "${DOCKER_FINANCE_CONTAINER_REPO}/src/root/${_macro}" ] \ && lib_utils::die_fatal "repo macro not found '${_macro}'" # TODO: currently, only repo macros are supported # (no custom macros, use custom plugins instead) # Per API (v1), requires path stub format - declare -gr global_arg_macro="$_stub" + declare -gr global_arg_macro="$_macro" fi # @@ -149,10 +150,29 @@ function lib_root::__root() { lib_utils::deps_check "root" - local _exec=("root" "-l") + local -r _path="${DOCKER_FINANCE_CONTAINER_REPO}/src/root" + pushd "$_path" 1>/dev/null || lib_utils::die_fatal "could not pushd '${_path}'" # - # Default + # Base command + # + + # NOTE: + # + # rootlogon.C *MUST* be loaded at any startup; as if fulfills loading + # of `dfi` source files and other library requirements. + # + # Typically, ROOT.cern would load rootlogon.C if we start `root` + # interactively within the macro directory. However, `dfi` has its own + # requirements. + # + # After rootlogon, any loading of macros, plugins or any `dfi` files + # can be completed using the `dfi` API. + + local _exec=("root" "-l" "macro/rootlogon.C") + + # + # Interactive opts # # Start interactive instance w/out loading/running macro or plugin @@ -161,7 +181,7 @@ function lib_root::__root() fi # - # Macro + # Macro: non-interactive opts # if [ ! -z "$global_arg_macro" ]; then @@ -179,11 +199,19 @@ function lib_root::__root() # # - run() static function is the entry point for all macros # - local -r _file="${global_arg_macro##*/}" - local -r _stub="${_file^}" - local -r _class="${_stub%.*}" - local -r _caller="dfi::macro::${global_arg_macro%%/*}::${_class}" + # 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##*/}" + _class="${_class^}" + _class="${_class%.*}" + declare -r _class + + local -r _caller="dfi::macro::${_namespace}::${_class}" # Per-API signatures (v1) if [[ ${_class} == "Hash" ]]; then @@ -195,6 +223,7 @@ function lib_root::__root() else _run="run()" fi + _exec+=("-e" "${_caller}::${_run}") # NOTE: when called via shell, server(s) are implied to @@ -205,7 +234,7 @@ function lib_root::__root() fi # - # Plugin + # Plugin: non-interactive opts # if [ ! -z "$global_arg_plugin" ]; then @@ -216,19 +245,8 @@ function lib_root::__root() # Execute # - # NOTE: - # - # This *MUST* be executed from within the macro directory, - # regardless of what is loaded (macro or plugin), as ROOT.cern - # will automatically load rootlogon.C (which `dfi` needs). - # - # Any loading or macros of plugins from within an interactive - # instance can use be completed with the `dfi` API. - # lib_utils::print_debug "${_exec[@]}" - pushd "${DOCKER_FINANCE_CONTAINER_REPO}/src/root/macro" 1>/dev/null \ - && "${_exec[@]}" \ - || lib_utils::die_fatal "could not pushd" + "${_exec[@]}" || lib_utils::die_fatal "root exited with: $?" } # vim: sw=2 sts=2 si ai et diff --git a/container/src/root/macro/rootlogon.C b/container/src/root/macro/rootlogon.C index 5963eba..321db19 100644 --- a/container/src/root/macro/rootlogon.C +++ b/container/src/root/macro/rootlogon.C @@ -24,6 +24,7 @@ #define CONTAINER_SRC_ROOT_MACRO_ROOTLOGON_C_ #include +#include //! \namespace dfi //! \since docker-finance 1.0.0 @@ -34,146 +35,161 @@ namespace dfi //! \since docker-finance 1.0.0 namespace macro { -//! \brief Global namespace help wrapper +//! \brief `dfi` macro-specific usage help //! \ingroup cpp_macro +//! \since docker-finance 1.0.0 void help() { - std::cout - << "Description:\n" - << "\n" - << " docker-finance C++ interpretations / interactive calculations\n" - << "\n" - << " *** TIP: save your fingers! Use tab completion! ***\n" - << "\n" - << " 1. Print current directory (all commands/files are relative to\n" - << " this directory):\n" - << "\n" - << " root [0] .!pwd // eg., " - << "${DOCKER_FINANCE_CONTAINER_REPO}/src/root/macro\n" - << "\n" - << "Library:\n" - << "\n" - << " 1. Directly access docker-finance crypto abstractions and\n" - << " print hundreds of SHA2-256 libsodium-generated hashes\n" - << " of Crypto++-generated cryptographically secure random\n" - << " numbers:\n" - << "\n" - << " root [0] using g_Random = " - "dfi::crypto::cryptopp::Random;\n" - << " root [1] using g_Hash = " - "dfi::crypto::libsodium::Hash;\n" - << " root [2] g_Random r; g_Hash h;\n" - << " root [3] for (size_t i{}; i < " - "std::numeric_limits::max(); i++) {\n" - << " root (cont'ed, cancel with .@) [4] uint32_t num = " - "r.generate();\n" - << " root (cont'ed, cancel with .@) [5] std::cout << " - "h.encode(num)\n" - << " root (cont'ed, cancel with .@) [6] << \" = \" << num << " - "\"\\n\";\n" - << " root (cont'ed, cancel with .@) [7] }\n" - << "\n" - << " Note: generate Doxygen to see all supported cryptographic\n" - << " libraries and hash types.\n" - << "\n" - << " 2. Use Tools utility\n" - << "\n" - << " root [0] dfi::utility::Tools tools;\n" - << "\n" - << " // Create a variable within interpreter\n" - << " root [1] btc=0.87654321+0.12345678+0.00000078\n" - << " (double) 1.0000008\n" - << "\n" - << " // Print variable up to N decimal places\n" - << " root [2] tools.print_value(btc, 8);\n" - << " 1.00000077\n" - << "\n" - << " // Use tab autocomplete for class members to print random\n" - << " // numbers within given intervals\n" - << " root [3] " - "tools.print_dist >, " - "double>(0.1, btc);\n" - << " 0.13787670\n" - << " 0.36534066\n" - << " 0.33885582\n" - << " 0.15792758\n" - << " Maximum = 1.00000077\n" - << " Printed = 1.00000077\n" - << "\n" - << "Plugins:\n" - << "\n" - << " WARNING: unlike macro loader, the prepended 'repo' and 'custom'\n" - << " are not real directories but rather indications that the file\n" - << " is either a repository plugin or an non-repo (custom) plugin.\n" - << "\n" - << " 1. Connect to docker-finance API via plugins:\n" - << "\n" - << " // Load and run an example repository plugin\n" - << " root [0] dfi::plugin::load(\"repo/example.cc\");\n" - << " root [1] " - "dfi::plugin::my_plugin_namespace::example1();\n" - << " root [2] " - "dfi::plugin::my_plugin_namespace::example2();\n" - << " root [3] " - "dfi::plugin::my_plugin_namespace::example3();\n" - << "\n" - << " // Load and run your own custom plugin\n" - << " root [4] dfi::plugin::load(\"custom/example.cc\");\n" - << " root [5] " - "dfi::plugin::your_plugin_namespace::example();\n" - << "\n" - << "Macros:\n" - << "\n" - << " NOTE: the macro loader interprets from base 'macro' path (.!pwd)\n" - << "\n" - << " 1. Load and run docker-finance unit tests and benchmarks:\n" - << "\n" - << " root [0] dfi::macro::load(\"test/unit.C\")\n" - << " root [1] dfi::macro::test::Unit::run()\n" - << " ...\n" - << " root [2] dfi::macro::load(\"test/benchmark.C\")\n" - << " root [3] dfi::macro::test::Benchmark::run()\n" - << " ...\n" - << "\n" - << " 2. Load and run docker-finance cryptographic macros:\n" - << "\n" - << " root [0] dfi::macro::load(\"crypto/hash.C\")\n" - << " root [1] " - << "dfi::macro::crypto::Hash::run(\"better to be raw than " - "digested\")\n" - << " ...\n" - << " root [2] dfi::macro::load(\"crypto/random.C\")\n" - << " root [3] dfi::macro::crypto::Random::run()\n" - << " ...\n" - << "\n" - << " 3. Load ROOT webserver and run commands for metadata analysis:\n" - << "\n" - << " root [0] dfi::macro::load(\"web/server.C\")\n" - << " root [1] dfi::macro::web::Server::run()\n" - << "\n" - << " Now, open your web browser to http://127.0.0.1:8080\n" - << "\n" - << "Help:\n" - << "\n" - << " 1. Print ROOT's help usage\n" - << " root [0] .help\n" - << "\n" - << " 2. Print this help usage\n" - << " root [0] help()\n" - << std::endl; - - // TODO(unassigned): add multi-threading example of generating numbers and/or hashes + std::cout << "Use `dfi::help()` instead" << std::endl; } } // namespace macro -} // namespace dfi +//! \brief `dfi` generic help descriptions //! \ingroup cpp_macro +//! \todo Factor out for specific help descriptions per-namespace +//! (e.g., dfi::macro::help()) +//! \since docker-finance 1.1.0 void help() { - dfi::macro::help(); + const std::string help = + "Description:\n" + "\n" + " docker-finance C++ interpretations / interactive calculations\n" + "\n" + " *** TIP: save your fingers! Use tab completion! ***\n" + "\n" + " 1. Print current directory (all commands/files are relative to\n" + " this directory):\n" + "\n" + " root [0] .!pwd // eg., " + "${DOCKER_FINANCE_CONTAINER_REPO}/src/root\n" + "\n" + "Library:\n" + "\n" + " 1. Directly access docker-finance crypto abstractions and\n" + " print hundreds of SHA2-256 libsodium-generated hashes\n" + " of Crypto++-generated cryptographically secure random\n" + " numbers:\n" + "\n" + " root [0] using g_Random = dfi::crypto::cryptopp::Random;\n" + " root [1] using g_Hash = dfi::crypto::libsodium::Hash;\n" + " root [2] g_Random r; g_Hash h;\n" + " root [3] for (size_t i{}; i < " + "std::numeric_limits::max(); i++) {\n" + " root (cont'ed, cancel with .@) [4] uint32_t num = r.generate();\n" + " root (cont'ed, cancel with .@) [5] std::cout << " + "h.encode(num)\n" + " root (cont'ed, cancel with .@) [6] << \" = \" << num << \"\\n\";\n" + " root (cont'ed, cancel with .@) [7] }\n" + "\n" + " Note: generate Doxygen to see all supported cryptographic\n" + " libraries and hash types.\n" + "\n" + " 2. Use Tools utility\n" + "\n" + " root [0] dfi::utility::Tools tools;\n" + "\n" + " // Create a variable within interpreter\n" + " root [1] btc=0.87654321+0.12345678+0.00000078\n" + " (double) 1.0000008\n" + "\n" + " // Print variable up to N decimal places\n" + " root [2] tools.print_value(btc, 8);\n" + " 1.00000077\n" + "\n" + " // Use tab autocomplete for class members to print random\n" + " // numbers within given intervals\n" + " root [3] " + "tools.print_dist >, " + "double>(0.1, btc);\n" + " 0.13787670\n" + " 0.36534066\n" + " 0.33885582\n" + " 0.15792758\n" + " Maximum = 1.00000077\n" + " Printed = 1.00000077\n" + "\n" + "Plugins:\n" + "\n" + " WARNING: unlike macro loader, the prepended 'repo' and 'custom'\n" + " are not real directories but rather indications that the file\n" + " is either a repository plugin or an non-repo (custom) plugin.\n" + "\n" + " 1. Connect to docker-finance API via plugins:\n" + "\n" + " // Load and run an example repository plugin\n" + " root [0] dfi::plugin::load(\"repo/example.cc\");\n" + " root [1] dfi::plugin::my_plugin_namespace::example1();\n" + " root [2] dfi::plugin::my_plugin_namespace::example2();\n" + " root [3] dfi::plugin::my_plugin_namespace::example3();\n" + "\n" + " // Load and run your own custom plugin\n" + " root [4] dfi::plugin::load(\"custom/example.cc\");\n" + " root [5] dfi::plugin::your_plugin_namespace::example();\n" + "\n" + "Macros:\n" + "\n" + " NOTE: the macro loader interprets from base 'macro' path (.!pwd)\n" + "\n" + " 1. Load and run docker-finance unit tests and benchmarks:\n" + "\n" + " root [0] dfi::macro::load(\"macro/test/unit.C\")\n" + " root [1] dfi::macro::test::Unit::run()\n" + " ...\n" + " root [2] dfi::macro::load(\"macro/test/benchmark.C\")\n" + " root [3] dfi::macro::test::Benchmark::run()\n" + " ...\n" + "\n" + " 2. Load and run docker-finance cryptographic macros:\n" + "\n" + " root [0] dfi::macro::load(\"macro/crypto/hash.C\")\n" + " root [1] dfi::macro::crypto::Hash::run(\"better to be raw than " + "digested\")\n" + " ...\n" + " root [2] dfi::macro::load(\"macro/crypto/random.C\")\n" + " root [3] dfi::macro::crypto::Random::run()\n" + " ...\n" + "\n" + " 3. Load ROOT webserver and run commands for metadata analysis:\n" + "\n" + " root [0] dfi::macro::load(\"macro/web/server.C\")\n" + " root [1] dfi::macro::web::Server::run()\n" + "\n" + " Now, open your web browser to http://127.0.0.1:8080\n" + "\n" + "Help:\n" + "\n" + " 1. Print all help options\n" + "\n" + " root [0] help()\n"; + // TODO(unassigned): add multi-threading example of generating numbers and/or hashes + + std::cout << help << std::endl; +} +} // namespace dfi + +//! \brief Print all help options +//! \ingroup cpp_macro +//! \since docker-finance 1.0.0 +void help() +{ + const std::string help = + "Help:\n" + "\n" + " 1. Print this help\n" + " root [0] help()\n" + "\n" + " 2. Print `root` help\n" + " root [0] .help\n" + "\n" + " 3. Print `dfi` help\n" + " root [0] dfi::help()\n"; + + std::cout << help << std::endl; } //! \brief ROOT logon macro, runs on `root` startup +//! \since docker-finance 1.0.0 void rootlogon() { // Add nested directory headers @@ -189,11 +205,11 @@ void rootlogon() gSystem->AddLinkedLibs("-lsodium"); // libsodium // Load default `dfi` public consumables - gInterpreter->ProcessLine(".L ../plugin/common/utility.hh"); - gInterpreter->ProcessLine(".L ../macro/common/utility.hh"); - gInterpreter->ProcessLine(".L ../src/hash.hh"); - gInterpreter->ProcessLine(".L ../src/random.hh"); - gInterpreter->ProcessLine(".L ../src/utility.hh"); + gInterpreter->ProcessLine(".L plugin/common/utility.hh"); + gInterpreter->ProcessLine(".L macro/common/utility.hh"); + gInterpreter->ProcessLine(".L src/hash.hh"); + gInterpreter->ProcessLine(".L src/random.hh"); + gInterpreter->ProcessLine(".L src/utility.hh"); } #endif // CONTAINER_SRC_ROOT_MACRO_ROOTLOGON_C_ diff --git a/container/src/root/macro/test/benchmark.C b/container/src/root/macro/test/benchmark.C index 26b1384..4b93c95 100644 --- a/container/src/root/macro/test/benchmark.C +++ b/container/src/root/macro/test/benchmark.C @@ -66,9 +66,9 @@ class Benchmark { static bool loaded{false}; static const std::initializer_list paths{ - {"../test/benchmark/hash.hh"}, - {"../test/benchmark/random.hh"}, - {"../test/benchmark/utility.hh"}}; + {"test/benchmark/hash.hh"}, + {"test/benchmark/random.hh"}, + {"test/benchmark/utility.hh"}}; if (!loaded) { diff --git a/container/src/root/macro/test/unit.C b/container/src/root/macro/test/unit.C index 0670538..0cf69b6 100644 --- a/container/src/root/macro/test/unit.C +++ b/container/src/root/macro/test/unit.C @@ -66,10 +66,10 @@ class Unit { static bool loaded{false}; static const std::initializer_list paths{ - {"../test/unit/hash.hh"}, - {"../test/unit/random.hh"}, - {"../test/unit/type.hh"}, - {"../test/unit/utility.hh"}}; + {"test/unit/hash.hh"}, + {"test/unit/random.hh"}, + {"test/unit/type.hh"}, + {"test/unit/utility.hh"}}; if (!loaded) { diff --git a/container/src/root/macro/web/server.C b/container/src/root/macro/web/server.C index 483aa4f..97bb9b2 100644 --- a/container/src/root/macro/web/server.C +++ b/container/src/root/macro/web/server.C @@ -60,16 +60,16 @@ class Server final //! \details Registers internal macros static void register_commands() { - namespace common = ::dfi::macro::common; + namespace macro = ::dfi::macro; - common::Command::load({"web/internal/crypto.C"}); - common::g_HTTPServer->RegisterCommand( + macro::load("macro/web/internal/crypto.C"); + macro::common::g_HTTPServer->RegisterCommand( "/rng_sample", "::dfi::macro::web::internal::Random::rng_sample(\"%arg1%" "\")"); - common::Command::load({"web/internal/meta.C"}); - common::g_HTTPServer->RegisterCommand( + macro::load("macro/web/internal/meta.C"); + macro::common::g_HTTPServer->RegisterCommand( "/meta_sample", "::dfi::macro::web::internal::Meta::meta_sample(\"%arg1%" "\")"); diff --git a/container/src/root/src/internal/generic.hh b/container/src/root/src/internal/generic.hh index 8199e67..0010cf6 100644 --- a/container/src/root/src/internal/generic.hh +++ b/container/src/root/src/internal/generic.hh @@ -136,7 +136,7 @@ class Transform : private ImplBase public: //! \brief Encode trivial types and std::string_view - //! \todo std::string_view is trivially copyable in c++23 but ROOT is c++17 + //! \todo std::string_view is trivially copyable in c++23 but `dfi` ROOT build is c++20 template < typename t_tag, typename t_encoded, diff --git a/container/src/root/src/internal/type.hh b/container/src/root/src/internal/type.hh index 7238f34..93d457f 100644 --- a/container/src/root/src/internal/type.hh +++ b/container/src/root/src/internal/type.hh @@ -187,7 +187,7 @@ struct has_const_iterator> // NOTE: Doxygen doesn't allow multiple groups for variables //! \ingroup cpp_type_traits -//! \todo std::string_view is trivially copyable in c++23 but ROOT is c++17... +//! \todo std::string_view is trivially copyable in c++23 but `dfi` ROOT build is c++20 template constexpr bool is_signature_with_trivial = (std::is_trivial_v || std::is_same_v); diff --git a/container/src/root/test/unit/utility.hh b/container/src/root/test/unit/utility.hh index 153cc10..3767a51 100644 --- a/container/src/root/test/unit/utility.hh +++ b/container/src/root/test/unit/utility.hh @@ -373,7 +373,9 @@ TEST_F(CommonRepoFiles, MacroLoad) ASSERT_NE(ecode, nullptr); EXPECT_NE(*ecode, EErrorCode::kNoError); - ASSERT_NO_THROW(::dfi::macro::load("crypto/hash.C")); + // TODO(afiore): macro loading should not need to be prepended with "macro/" + // (see TODO in common impl regarding plugins-like functionality) + ASSERT_NO_THROW(::dfi::macro::load("macro/crypto/hash.C")); gInterpreter->ProcessLine( "dfi::macro::common::crypto::botan::Hash h;", ecode.get()); ASSERT_NE(ecode, nullptr);