#!/usr/bin/env bash # docker-finance | modern accounting for the power-user # # Copyright (C) 2025 Aaron Fiore (Founder, Evergreen Crypto LLC) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # "Libraries" # [ -z "$DOCKER_FINANCE_CONTAINER_REPO" ] && exit 1 source "${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/lib_utils.bash" || exit 1 # # Facade # function lib_root::root() { lib_root::__parse_root "$@" lib_root::__root "$@" lib_utils::catch $? } # # Implementation # function lib_root::__parse_root() { [ -z "$global_usage" ] && lib_utils::die_fatal local -r _arg="$1" local -r _usage=" \e[32mDescription:\e[0m docker-finance ROOT.cern interpreter \e[32mUsage:\e[0m $ $global_usage [help | [TAB COMPLETION]] [args] \e[32mArguments:\e[0m None: start interactive interpreter w/out running any given macro or plugins [TAB COMPLETION]: load (and run) given macro/plugin when starting interpreter macro = repository macros in repository location plugins/custom = custom plugins in custom plugin location plugins/repo = repository plugins in repository location [args]: arguments to macro or plugin \e[32mExamples:\e[0m \e[37;2m# See this usage help\e[0m $ $global_usage help \e[37;2m# The output of tab completion\e[0m $ $global_usage \\\t\\\t help macro/crypto/random.C macro/test/unit.C plugins/custom/example.cc macro/crypto/hash.C macro/test/benchmark.C macro/web/server.C plugins/repo/example.cc \e[37;2m# Load and run the repo's Web server macro\e[0m \e[37;2m# NOTE: this macro will maintain a running ROOT instance\e[0m $ $global_usage macro/web/server.C \e[37;2m# Load and run the repo's Hash macro with an argument\e[0m \e[37;2m# NOTE: this macro will 'one-off' the ROOT instance\e[0m $ $global_usage macro/crypto/hash.C 'this is a test message' \e[37;2m# Load repo example plugin, run within instance\e[0m $ $global_usage plugins/repo/example.cc root [0] Interpreting: '.L /home/business/docker-finance/plugins/root/example.cc' root [1] dfi::plugin::my_plugin_namespace::example\\\t example1 example2 example3 root [1] dfi::plugin::my_plugin_namespace::example2() ... " if [[ "$#" -gt 0 && ! "$_arg" =~ (^macro/|^plugins/) ]]; then lib_utils::die_usage "$_usage" fi # Type determined by path stub local -r _stub="${_arg#*/}" # # Macro # if [[ "$_arg" =~ ^macro ]]; then # 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}" ] \ && 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="$_macro" fi # # Plugin # if [[ "$_arg" =~ ^plugins ]]; then local -r _plugin="${_stub#*/}" # Repo plugins if [[ "$_stub" =~ ^repo ]]; then [ ! -f "${DOCKER_FINANCE_CONTAINER_REPO}/plugins/root/${_plugin}" ] \ && lib_utils::die_fatal "repo plugin not found '${_plugin}'" fi # Custom plugins if [[ "$_stub" =~ ^custom ]]; then [ -z "$DOCKER_FINANCE_CONTAINER_PLUGINS" ] && lib_utils::die_fatal [ ! -f "${DOCKER_FINANCE_CONTAINER_PLUGINS}/root/${_plugin}" ] \ && lib_utils::die_fatal "custom plugin not found '${_plugin}'" fi # Per API (v1), requires path stub format declare -gr global_arg_plugin="$_stub" fi } function lib_root::__root() { lib_utils::deps_check "root" local -r _path="${DOCKER_FINANCE_CONTAINER_REPO}/src/root" pushd "$_path" 1>/dev/null || lib_utils::die_fatal "could not pushd '${_path}'" # # 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 if [[ -z "$global_arg_macro" && -z "$global_arg_plugin" ]]; then _exec+=("-e" "help()") fi # # Macro: non-interactive opts # 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##*/}" _class="${_class^}" _class="${_class%.*}" declare -r _class local -r _caller="dfi::macro::${_namespace}::${_class}" # Per-API signatures (v1) if [[ ${_class} == "Hash" ]]; then # If no message is given, default to unique profile/subprofile [[ -z "$global_parent_profile" || -z "$global_arg_delim_1" || -z "$global_child_profile" ]] && lib_utils::die_fatal [ -z "${*:2}" ] \ && _run="run(\"${global_parent_profile}${global_arg_delim_1}${global_child_profile}\")" \ || _run="run(\"${*:2}\")" else _run="run()" fi _exec+=("-e" "${_caller}::${_run}") # NOTE: when called via shell, server(s) are implied to # require an interactive ROOT instance (not a 'one-off'). if [[ "${_class%.*}" != "Server" ]]; then _exec+=('-q') fi fi # # Plugin: non-interactive opts # if [ ! -z "$global_arg_plugin" ]; then _exec+=("-e" "dfi::plugin::load(\"${global_arg_plugin}\")") fi # # Execute # lib_utils::print_debug "${_exec[@]}" "${_exec[@]}" || lib_utils::die_fatal "root exited with: $?" } # vim: sw=2 sts=2 si ai et