From 044e5622c4e6b2ca9062da67178da4fe7835b48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Chastanet?= Date: Sun, 8 Sep 2024 15:27:07 +0200 Subject: [PATCH] Refactoring to remove duplicated code - move conf/.env to conf/defaultEnv/.env in order to be able to include the .env file using gtpl it avoids usage of @embed feature removing the need of tar command in BashTools::Conf::requireLoad - added src/_binaries/commandDefinitions/optionsDefault.yaml to set default binary options for all the binaries beforeParseCallback calling defaultBeforeParseCallback - avoid duplicated code by using the new fromDsnOptionLongDescription function - reformatted long description for all Database's binaries - better optionProfile default value management that can be default or empty depending the case - added src/_binaries/commandDefinitions/optionsTables.sh src/_binaries/commandDefinitions/optionsRatio.yaml in order to correctly order the options in help - move requirements to beforeParseCallback - recompiled all binaries to remove deprecated option --env-file --- .pre-commit-config-github.yaml | 6 +- .pre-commit-config.yaml | 6 +- bin/cli | 218 ++++--- bin/dbImport | 299 ++++++---- bin/dbImportProfile | 531 ++++++++++-------- bin/dbImportStream | 273 +++++---- bin/dbQueryAllDatabases | 220 +++++--- bin/dbScriptAllDatabases | 284 +++++----- bin/doc | 204 +++++-- bin/gitIsAncestorOf | 237 ++++---- bin/gitIsBranch | 237 ++++---- bin/gitRenameBranch | 243 ++++---- bin/installRequirements | 202 +++++-- bin/mysql2puml | 226 +++++--- bin/postmanCli | 204 +++++-- bin/upgradeGithubRelease | 231 +++++--- bin/waitForIt | 233 +++++--- bin/waitForMysql | 229 +++++--- conf/dbScripts/extractData | 210 +++---- conf/{ => defaultEnv}/.env | 0 conf/mysql2pumlSkins/default.png | Bin 954 -> 0 bytes conf/mysql2pumlSkins/default.svg | 1 - install | 217 +++++-- src/BashTools/Conf/requireLoad.bats | 8 +- src/BashTools/Conf/requireLoad.sh | 9 +- .../mysql2puml/mysql2puml-binary.yaml | 3 +- .../mysql2puml/testsData/mysql2puml.help.txt | 5 +- .../mysql2puml/testsData/mysql2puml.png | Bin 47049 -> 56573 bytes .../Database/dbImport/dbImport-binary.yaml | 7 +- .../Database/dbImport/dbImport-options.sh | 37 +- .../dbImport/testsData/dbImport.help.txt | 49 +- .../dbImportProfile-binary.yaml | 30 +- .../dbImportProfile/dbImportProfile-main.sh | 6 - .../dbImportProfile-options.sh | 43 +- .../dbImportProfile/dbImportProfile.bats | 3 +- .../testsData/dbImportProfile.help.txt | 77 +-- .../dbImportStream/dbImportStream-binary.yaml | 7 +- .../dbImportStream/dbImportStream-options.sh | 24 +- .../dbImportStream/dbImportStream.bats | 3 +- .../testsData/dbImportProfiles/all.sh | 4 + .../testsData/dbImportProfiles/default.sh | 15 + .../testsData/dbImportProfiles/none.sh | 6 + .../testsData/dbImportStream.help.txt | 46 +- .../dbQueryAllDatabases-binary.yaml | 8 +- .../dbQueryAllDatabases-options.sh | 34 +- .../dbQueryAllDatabases.bats | 7 +- .../testsData/dbQueryAllDatabases.help.txt | 50 +- .../dbScriptAllDatabases-binary.yaml | 11 +- .../dbScriptAllDatabases-options.sh | 43 +- .../dbScriptAllDatabases.bats | 5 +- .../dbScriptOneDatabase.sh | 4 +- .../extractData-binary.yaml | 2 +- .../testsData/dbScriptAllDatabases.help.txt | 56 +- src/_binaries/Docker/cli/cli-binary.yaml | 5 +- src/_binaries/Docker/cli/cli-options.sh | 5 +- src/_binaries/Docker/cli/cli.bats | 1 + .../Docker/cli/testsData/cli.help.txt | 5 +- .../gitIsAncestorOf-binary.yaml | 5 +- .../Git/gitIsAncestorOf/gitIsAncestorOf.bats | 2 +- .../testsData/gitIsAncestorOf.help.txt | 5 +- .../Git/gitIsBranch/gitIsBranch-binary.yaml | 5 +- .../Git/gitIsBranch/gitIsBranch.bats | 2 +- .../testsData/gitIsBranch.help.txt | 5 +- .../gitRenameBranch-binary.yaml | 5 +- .../Git/gitRenameBranch/gitRenameBranch.bats | 2 +- .../testsData/gitRenameBranch.help.txt | 5 +- src/_binaries/Git/gitToolsDefaultOptions.sh | 5 +- .../testsData/upgradeGithubRelease.help.txt | 5 +- .../upgradeGithubRelease-binary.yaml | 5 +- .../upgradeGithubRelease.bats | 2 +- .../Postman/postmanCli/postmanCli-binary.yaml | 5 +- .../Postman/postmanCli/postmanCli.bats | 16 +- .../postmanCli/testsData/postmanCli.help.txt | 5 +- .../waitForIt/testsData/waitForIt.help.txt | 5 +- .../Utils/waitForIt/waitForIt-binary.yaml | 6 +- src/_binaries/Utils/waitForIt/waitForIt.bats | 2 +- .../testsData/waitForMysql.help.txt | 5 +- .../waitForMysql/waitForMysql-binary.yaml | 5 +- .../Utils/waitForMysql/waitForMysql.bats | 2 +- src/_binaries/build/doc/doc-binary.yaml | 2 +- .../build/install/install-binary.yaml | 1 + src/_binaries/build/install/install-main.sh | 7 +- .../build/install/install-options.sh | 6 + .../installRequirements-binary.yaml | 2 +- .../commandDefinitions/optionsDefault.sh | 6 +- .../commandDefinitions/optionsDefault.yaml | 15 + .../commandDefinitions/optionsFromDsn.sh | 17 + .../commandDefinitions/optionsFromDsn.yaml | 2 + .../commandDefinitions/optionsJobs.yaml | 6 +- .../commandDefinitions/optionsMysqlSource.sh | 7 + .../optionsMysqlSource.yaml | 1 + .../optionsMysqlTarget.yaml | 1 + .../commandDefinitions/optionsProfile.sh | 46 +- .../commandDefinitions/optionsProfile.yaml | 15 - .../commandDefinitions/optionsRatio.sh | 11 + .../commandDefinitions/optionsRatio.yaml | 19 + .../commandDefinitions/optionsTables.sh | 8 + .../commandDefinitions/optionsTables.yaml | 21 + src/batsHeaders.sh | 2 +- 99 files changed, 3118 insertions(+), 2310 deletions(-) rename conf/{ => defaultEnv}/.env (100%) delete mode 100644 conf/mysql2pumlSkins/default.png delete mode 100644 conf/mysql2pumlSkins/default.svg create mode 100755 src/_binaries/Database/dbImportStream/testsData/dbImportProfiles/all.sh create mode 100755 src/_binaries/Database/dbImportStream/testsData/dbImportProfiles/default.sh create mode 100755 src/_binaries/Database/dbImportStream/testsData/dbImportProfiles/none.sh create mode 100644 src/_binaries/commandDefinitions/optionsDefault.yaml create mode 100755 src/_binaries/commandDefinitions/optionsFromDsn.sh create mode 100755 src/_binaries/commandDefinitions/optionsRatio.sh create mode 100644 src/_binaries/commandDefinitions/optionsRatio.yaml create mode 100755 src/_binaries/commandDefinitions/optionsTables.sh create mode 100644 src/_binaries/commandDefinitions/optionsTables.yaml diff --git a/.pre-commit-config-github.yaml b/.pre-commit-config-github.yaml index 28050360..f095b61a 100644 --- a/.pre-commit-config-github.yaml +++ b/.pre-commit-config-github.yaml @@ -161,7 +161,7 @@ repos: exclude: /testsData/ - repo: https://github.com/fchastanet/bash-tools-framework - rev: 5.1.0 + rev: 5.1.2 hooks: - id: fixShebangExecutionBit - id: awkLint @@ -192,6 +192,10 @@ repos: WARNING, ] - id: plantuml + exclude: | + (?x)( + ^conf/mysql2pumlSkins/default.puml$ + ) - repo: local hooks: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 43dec14b..7c89af86 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -156,7 +156,7 @@ repos: exclude: /testsData/ - repo: https://github.com/fchastanet/bash-tools-framework - rev: 5.1.0 + rev: 5.1.2 hooks: - id: fixShebangExecutionBit - id: awkLint @@ -187,6 +187,10 @@ repos: WARNING, ] - id: plantuml + exclude: | + (?x)( + ^conf/mysql2pumlSkins/default.puml$ + ) - repo: local hooks: diff --git a/bin/cli b/bin/cli index b2c220ca..75d631b3 100755 --- a/bin/cli +++ b/bin/cli @@ -352,18 +352,79 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + # @description loads ~/.bash-tools/.env if available # if not creates it from a default template # else check if new options need to be added BashTools::Conf::requireLoad() { -Linux::requireTarCommand -Compiler::Embed::extractFileFromBase64 \ - "${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" \ - "IyEvdXNyL2Jpbi9lbnYgYmFzaAojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKCiMgRGVmYXVsdCBzZXR0aW5ncwojIHlvdSBjYW4gb3ZlcnJpZGUgdGhlc2Ugc2V0dGluZ3MgYnkgY3JlYXRpbmcgJHtIT01FfS8uYmFzaC10b29scy8uZW52IGZpbGUKCiMjIwojIyMgRElTUExBWSBMZXZlbAojIyMgbWluaW11bSBsZXZlbCBvZiB0aGUgbWVzc2FnZXMgdGhhdCB3aWxsIGJlIGRpc3BsYXllZCBvbiBzY3JlZW4KIyMjCiMjIyAwOiBOTyBMT0cKIyMjIDE6IEVSUk9SCiMjIyAyOiBXQVJOSU5HCiMjIyAzOiBJTkZPCiMjIyA0OiBERUJVRwojIyMKQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTD0ke0JBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUw6LTN9CgojIyMKIyMjIERJU1BMQVkgZHVyYXRpb24KIyMjIDA6IG5vIGR1cmF0aW9uIGlzIGRpc3BsYXllZCBvbiB0aGUgbWVzc2FnZXMKIyMjIDE6IGR1cmF0aW9uIGJldHdlZW4gcHJldmlvdXMgbWVzc2FnZSBhbmQgY3VycmVudCBpcyBkaXNwbGF5ZWQKIyMjIHdpdGggdGhlIG1lc3NhZ2UKIyMjCkRJU1BMQVlfRFVSQVRJT049JHtESVNQTEFZX0RVUkFUSU9OOjB9CgojIyMKIyMjIExvZyB0byBmaWxlCiMjIwojIyMgYWxsIGxvZyBtZXNzYWdlcyB3aWxsIGJlIHJlZGlyZWN0ZWQgdG8gbG9nIGZpbGUgc3BlY2lmaWVkCiMjIyB0aGlzIHNhbWUgcGF0aCB3aWxsIGJlIHVzZWQgaW5zaWRlIGFuZCBvdXRzaWRlIG9mIHRoZSBjb250YWluZXIKIyMjCkJBU0hfRlJBTUVXT1JLX0xPR19GSUxFPSR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEU6LSR7RlJBTUVXT1JLX1JPT1RfRElSfS9sb2dzL2Jhc2gubG9nfQoKIyMjCiMjIyBMT0cgTGV2ZWwKIyMjIG1pbmltdW0gbGV2ZWwgb2YgdGhlIG1lc3NhZ2VzIHRoYXQgd2lsbCBiZSBsb2dnZWQgaW50byBMT0dfRklMRQojIyMKIyMjIDA6IE5PIExPRwojIyMgMTogRVJST1IKIyMjIDI6IFdBUk5JTkcKIyMjIDM6IElORk8KIyMjIDQ6IERFQlVHCiMjIwpCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw6LTB9CgojIGFic29sdXRlIGRpcmVjdG9yeSBjb250YWluaW5nIGRiIGltcG9ydCBzcWwgZHVtcHMKREJfSU1QT1JUX0RVTVBfRElSPSR7REJfSU1QT1JUX0RVTVBfRElSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2RiSW1wb3J0RHVtcHN9CgojIGdhcmJhZ2UgY29sbGVjdCBhbGwgZmlsZXMgZm9yIHdoaWNoIG1vZGlmaWNhdGlvbiBpcyBncmVhdGVyIHRoYW4gZWc6IDMwIGRheXMgKCszMCkKIyBlYWNoIHRpbWUgYW4gZXhpc3RpbmcgZmlsZSBpcyB1c2VkIGJ5IGRiSW1wb3J0L2RiSW1wb3J0VGFibGUKIyB0aGUgZmlsZSBtb2RpZmljYXRpb24gdGltZSBpcyBzZXQgdG8gbm93CkRCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUz0ke0RCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUzotKzMwfQoKIyBhYnNvbHV0ZSBkaXJlY3RvcnkgY29udGFpbmluZyBkYlNjcmlwdHMgdXNlZCBieSBkYlNjcmlwdEFsbERhdGFiYXNlcwpTQ1JJUFRTX0ZPTERFUj0ke1NDUklQVFNfRk9MREVSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2NvbmYvZGJTY3JpcHRzfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEFXUyBQYXJhbWV0ZXJzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KUzNfQkFTRV9VUkw9JHtTM19CQVNFX1VSTDotfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFBvc3RtYW4gUGFyYW1ldGVycwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tClBPU1RNQU5fQVBJX0tFWT0K" \ - "755" - -declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" - BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" @@ -391,7 +452,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ( echo "#!/usr/bin/env bash" # shellcheck disable=SC2154 - echo "${embed_file_bashToolsDefaultConfigTemplate}" + echo "${bashToolsDefaultConfigTemplate}" ) >"${envFile}" Log::displayInfo "Configuration file '${envFile}' created" else @@ -404,7 +465,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ) >>"${envFile}" fi fi - # shellcheck source=/conf/.env + # shellcheck source=/conf/defaultEnv/.env source "${envFile}" || { Log::displayError "impossible to load '${envFile}'" exit 1 @@ -412,36 +473,6 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp } -# @description convert base64 encoded back to target file -# if target file is executable prepend dir of target -# file to PATH to make binary available everywhere -# it is advised to include in the path of the target file -# the md5sum of the binFile -# -# @arg $1 targetFile:String the file to write -# @arg $2 binFileBase64:String the base64 encoded file -# @arg $3 fileMode:String the chmod to set on the file -# @set PATH String prepend target embedded file binary directory to PATH variable if binary executable -Compiler::Embed::extractFileFromBase64() { - local targetFile="$1" - local binFileBase64="$2" - local fileMode="${3:-+x}" - local targetDir="${targetFile%/*}" - - if [[ ! -f "${targetFile}" ]]; then - if [[ ! -d "${targetDir}" ]]; then - mkdir -p "${targetDir}" - fi - base64 -d >"${targetFile}" <<<"${binFileBase64}" - chmod "${fileMode}" "${targetFile}" - fi - - if [[ -x "${targetFile}" ]]; then - Env::pathPrepend "${targetDir}" - fi -} - - # @description get absolute conf file from specified conf folder deduced using these rules # * from absolute file (ignores and ) # * relative to where script is executed (ignores and ) @@ -680,19 +711,6 @@ Db::checkRequirements() { } -# @description prepend directories to the PATH environment variable -# @arg $@ args:String[] list of directories to prepend -# @set PATH update PATH with the directories prepended -Env::pathPrepend() { - local arg - for arg in "$@"; do - if [[ -d "${arg}" && ":${PATH}:" != *":${arg}:"* ]]; then - PATH="$(realpath "${arg}"):${PATH}" - fi - done -} - - # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -765,14 +783,6 @@ Linux::requireRealpathCommand() { } -# @description ensure command tar is available -# @exitcode 1 if tar command not available -# @stderr diagnostics information is displayed -Linux::requireTarCommand() { - Assert::commandExists tar -} - - declare -g FIRST_LOG_DATE LOG_LAST_LOG_DATE LOG_LAST_LOG_DATE_INIT LOG_LAST_DURATION_STR FIRST_LOG_DATE="${EPOCHREALTIME/[^0-9]/}" LOG_LAST_LOG_DATE="${FIRST_LOG_DATE}" @@ -1252,6 +1262,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -1295,16 +1306,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1479,9 +1480,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1497,6 +1495,19 @@ commandOptionParseFinished() { +defaultBeforeParseCallback() { + BashTools::Conf::requireLoad + Env::requireLoad + UI::requireTheme + Log::requireLoad +} + +beforeParseCallback() { + defaultBeforeParseCallback +} + + + # option values # shellcheck disable=SC2034 declare containerArg="default" @@ -1510,10 +1521,7 @@ declare PROFILES_DIR declare HOME_PROFILES_DIR beforeParseCallback() { - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad + defaultBeforeParseCallback Linux::requireRealpathCommand Assert::commandExists docker "check https://docs.docker.com/engine/install/ubuntu/" } @@ -1626,7 +1634,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1660,7 +1667,6 @@ cliCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1702,7 +1708,7 @@ cliCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/14 + # Option 1/13 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1718,7 +1724,7 @@ cliCommandParse() { ;; - # Option 2/14 + # Option 2/13 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1732,7 +1738,7 @@ cliCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 3/14 + # Option 3/13 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1753,7 +1759,7 @@ cliCommandParse() { ;; - # Option 4/14 + # Option 4/13 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1771,7 +1777,7 @@ cliCommandParse() { ;; - # Option 5/14 + # Option 5/13 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1789,7 +1795,7 @@ cliCommandParse() { ;; - # Option 6/14 + # Option 6/13 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1807,25 +1813,7 @@ cliCommandParse() { ;; - # Option 7/14 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 8/14 + # Option 7/13 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1853,7 +1841,7 @@ cliCommandParse() { ;; - # Option 9/14 + # Option 8/13 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1876,7 +1864,7 @@ cliCommandParse() { ;; - # Option 10/14 + # Option 9/13 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1904,7 +1892,7 @@ cliCommandParse() { ;; - # Option 11/14 + # Option 10/13 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -1922,7 +1910,7 @@ cliCommandParse() { ;; - # Option 12/14 + # Option 11/13 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -1950,7 +1938,7 @@ cliCommandParse() { ;; - # Option 13/14 + # Option 12/13 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -1966,7 +1954,7 @@ cliCommandParse() { ;; - # Option 14/14 + # Option 13/13 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -2081,7 +2069,7 @@ cliCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" + optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "cli" "${optionsAltList[@]}" @@ -2146,12 +2134,6 @@ cliCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/bin/dbImport b/bin/dbImport index d5afec12..284c816f 100755 --- a/bin/dbImport +++ b/bin/dbImport @@ -355,18 +355,79 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + # @description loads ~/.bash-tools/.env if available # if not creates it from a default template # else check if new options need to be added BashTools::Conf::requireLoad() { -Linux::requireTarCommand -Compiler::Embed::extractFileFromBase64 \ - "${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" \ - "IyEvdXNyL2Jpbi9lbnYgYmFzaAojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKCiMgRGVmYXVsdCBzZXR0aW5ncwojIHlvdSBjYW4gb3ZlcnJpZGUgdGhlc2Ugc2V0dGluZ3MgYnkgY3JlYXRpbmcgJHtIT01FfS8uYmFzaC10b29scy8uZW52IGZpbGUKCiMjIwojIyMgRElTUExBWSBMZXZlbAojIyMgbWluaW11bSBsZXZlbCBvZiB0aGUgbWVzc2FnZXMgdGhhdCB3aWxsIGJlIGRpc3BsYXllZCBvbiBzY3JlZW4KIyMjCiMjIyAwOiBOTyBMT0cKIyMjIDE6IEVSUk9SCiMjIyAyOiBXQVJOSU5HCiMjIyAzOiBJTkZPCiMjIyA0OiBERUJVRwojIyMKQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTD0ke0JBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUw6LTN9CgojIyMKIyMjIERJU1BMQVkgZHVyYXRpb24KIyMjIDA6IG5vIGR1cmF0aW9uIGlzIGRpc3BsYXllZCBvbiB0aGUgbWVzc2FnZXMKIyMjIDE6IGR1cmF0aW9uIGJldHdlZW4gcHJldmlvdXMgbWVzc2FnZSBhbmQgY3VycmVudCBpcyBkaXNwbGF5ZWQKIyMjIHdpdGggdGhlIG1lc3NhZ2UKIyMjCkRJU1BMQVlfRFVSQVRJT049JHtESVNQTEFZX0RVUkFUSU9OOjB9CgojIyMKIyMjIExvZyB0byBmaWxlCiMjIwojIyMgYWxsIGxvZyBtZXNzYWdlcyB3aWxsIGJlIHJlZGlyZWN0ZWQgdG8gbG9nIGZpbGUgc3BlY2lmaWVkCiMjIyB0aGlzIHNhbWUgcGF0aCB3aWxsIGJlIHVzZWQgaW5zaWRlIGFuZCBvdXRzaWRlIG9mIHRoZSBjb250YWluZXIKIyMjCkJBU0hfRlJBTUVXT1JLX0xPR19GSUxFPSR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEU6LSR7RlJBTUVXT1JLX1JPT1RfRElSfS9sb2dzL2Jhc2gubG9nfQoKIyMjCiMjIyBMT0cgTGV2ZWwKIyMjIG1pbmltdW0gbGV2ZWwgb2YgdGhlIG1lc3NhZ2VzIHRoYXQgd2lsbCBiZSBsb2dnZWQgaW50byBMT0dfRklMRQojIyMKIyMjIDA6IE5PIExPRwojIyMgMTogRVJST1IKIyMjIDI6IFdBUk5JTkcKIyMjIDM6IElORk8KIyMjIDQ6IERFQlVHCiMjIwpCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw6LTB9CgojIGFic29sdXRlIGRpcmVjdG9yeSBjb250YWluaW5nIGRiIGltcG9ydCBzcWwgZHVtcHMKREJfSU1QT1JUX0RVTVBfRElSPSR7REJfSU1QT1JUX0RVTVBfRElSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2RiSW1wb3J0RHVtcHN9CgojIGdhcmJhZ2UgY29sbGVjdCBhbGwgZmlsZXMgZm9yIHdoaWNoIG1vZGlmaWNhdGlvbiBpcyBncmVhdGVyIHRoYW4gZWc6IDMwIGRheXMgKCszMCkKIyBlYWNoIHRpbWUgYW4gZXhpc3RpbmcgZmlsZSBpcyB1c2VkIGJ5IGRiSW1wb3J0L2RiSW1wb3J0VGFibGUKIyB0aGUgZmlsZSBtb2RpZmljYXRpb24gdGltZSBpcyBzZXQgdG8gbm93CkRCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUz0ke0RCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUzotKzMwfQoKIyBhYnNvbHV0ZSBkaXJlY3RvcnkgY29udGFpbmluZyBkYlNjcmlwdHMgdXNlZCBieSBkYlNjcmlwdEFsbERhdGFiYXNlcwpTQ1JJUFRTX0ZPTERFUj0ke1NDUklQVFNfRk9MREVSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2NvbmYvZGJTY3JpcHRzfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEFXUyBQYXJhbWV0ZXJzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KUzNfQkFTRV9VUkw9JHtTM19CQVNFX1VSTDotfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFBvc3RtYW4gUGFyYW1ldGVycwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tClBPU1RNQU5fQVBJX0tFWT0K" \ - "755" - -declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" - BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" @@ -394,7 +455,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ( echo "#!/usr/bin/env bash" # shellcheck disable=SC2154 - echo "${embed_file_bashToolsDefaultConfigTemplate}" + echo "${bashToolsDefaultConfigTemplate}" ) >"${envFile}" Log::displayInfo "Configuration file '${envFile}' created" else @@ -407,7 +468,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ) >>"${envFile}" fi fi - # shellcheck source=/conf/.env + # shellcheck source=/conf/defaultEnv/.env source "${envFile}" || { Log::displayError "impossible to load '${envFile}'" exit 1 @@ -1431,6 +1492,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -1474,16 +1536,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1658,9 +1710,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1676,6 +1725,19 @@ commandOptionParseFinished() { +defaultBeforeParseCallback() { + BashTools::Conf::requireLoad + Env::requireLoad + UI::requireTheme + Log::requireLoad +} + +beforeParseCallback() { + defaultBeforeParseCallback +} + + + # shellcheck disable=SC2034 declare optionBashFrameworkConfig="${BASH_TOOLS_ROOT_DIR}/.framework-config" declare defaultTargetCharacterSet="" @@ -1688,10 +1750,7 @@ declare PROFILES_DIR declare HOME_PROFILES_DIR beforeParseCallback() { - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad + defaultBeforeParseCallback Linux::requireRealpathCommand Linux::requireExecutedAsUser } @@ -1709,32 +1768,16 @@ optionHelpCallback() { } longDescriptionFunction() { - local profilesList="" - local dsnList="" - dsnList="$(Conf::getMergedList "dsn" "env")" - profilesList="$(Conf::getMergedList "dbImportProfiles" "sh" || true)" - - echo -e "${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL}" - echo -e "${PROFILES_DIR-configuration error}" - - echo -e "${__HELP_TITLE}User profiles directory:${__HELP_NORMAL}" - echo -e "${HOME_PROFILES_DIR-configuration error}" - echo -e "Allows to override profiles defined in 'Default profiles directory'" - - echo -e "${__HELP_TITLE}List of available profiles:${__HELP_NORMAL}" - echo -e "${profilesList}" - - echo -e "${__HELP_TITLE}List of available dsn:${__HELP_NORMAL}" - echo -e "${dsnList}" - - echo -e "${__HELP_TITLE}Aws s3 location:${__HELP_NORMAL}" - echo -e "${S3_BASE_URL}" + mysqlSourceLongDescription + echo + profileOptionLongDescription echo - echo -e "${__HELP_TITLE}Example 1: from one database to another one${__HELP_NORMAL}" - echo -e "${__HELP_EXAMPLE}TODO${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Examples${__HELP_NORMAL}" + echo -e " 1. from one database to another one" + echo -e " ${__HELP_EXAMPLE}dbImport --from-dsn localhost --target-dsn remote fromDb toDb${__HELP_NORMAL}" echo - echo -e "${__HELP_TITLE}Example 2: import from S3${__HELP_NORMAL}" - echo -e "${__HELP_EXAMPLE}TODO${__HELP_NORMAL}" + echo -e " 2. import from S3" + echo -e " ${__HELP_EXAMPLE}dbImport --from-aws awsFile.tar.gz --target-dsn localhost fromDb toDb${__HELP_NORMAL}" Db::checkRequirements } @@ -1801,13 +1844,44 @@ initializeDefaultTargetMysqlOptions() { +profileOptionLongDescription() { + local profilesList="" + profilesList="$(Conf::getMergedList "dbImportProfiles" "sh" " - " || true)" + + echo -e " ${__HELP_TITLE}Profiles${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL}" + echo -e " ${PROFILES_DIR-configuration error}" + echo + echo -e " ${__HELP_TITLE}User profiles directory:${__HELP_NORMAL}" + echo -e " ${HOME_PROFILES_DIR-configuration error}" + echo -e ' Allows to override profiles defined in "Default profiles directory"' + echo + echo -e " ${__HELP_TITLE}List of available profiles:${__HELP_NORMAL}" + echo -e "${profilesList}" +} + profileOptionHelpFunction() { Array::wrap2 " " 80 4 \ " The name of the profile to use in order to include or exclude tables." echo } +initOptionProfileIfNotSet() { + if [[ -z "${optionProfile}" ]]; then + optionProfile="${defaultOptionProfile}" + fi + local -a profilesArray + readarray -t profilesArray < <(Conf::getMergedList "dbImportProfiles" "sh" "" || true) + if ! Array::contains "${optionProfile}" "${profilesArray[@]}"; then + Log::displayError "${SCRIPT_NAME} - invalid profile '${optionProfile}' provided" + return 1 + fi +} + +declare defaultOptionProfile="default" initProfileCommandCallback() { + initOptionProfileIfNotSet + # shellcheck disable=SC2154 if [[ "${optionProfile}" != "default" && -n "${optionTables}" ]]; then Log::fatal "Command ${SCRIPT_NAME} - you cannot use table and profile options at the same time" @@ -1836,16 +1910,12 @@ initProfileCommandCallback() { Log::displayInfo "${profileMsgInfo}" } -profileOptionCallback() { - local -a profilesArray - readarray -t profilesArray < <(Conf::getMergedList "dbImportProfiles" "sh" "" || true) - if ! Array::contains "$2" "${profilesArray[@]}"; then - Log::displayError "${SCRIPT_NAME} - invalid profile '$2' provided" - return 1 - fi -} + + + optionTablesCallback() { + # shellcheck disable=SC2154 if [[ ! ${optionTables} =~ ^[A-Za-z0-9_]+(,[A-Za-z0-9_]+)*$ ]]; then Log::fatal "Command ${SCRIPT_NAME} - Table list is not valid : ${optionTables}" fi @@ -1853,6 +1923,22 @@ optionTablesCallback() { +fromDsnOptionLongDescription() { + local dsnList="" + dsnList="$(Conf::getMergedList "dsn" "env" " - ")" + + echo -e " ${__HELP_TITLE}Data Source Name (DSN)${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default dsn directory:${__HELP_NORMAL}" + echo -e " ${BASH_TOOLS_ROOT_DIR}/conf/dsn" + echo + echo -e " ${__HELP_TITLE}User dsn directory:${__HELP_NORMAL}" + echo -e " ${HOME}/.bash-tools/dsn" + echo -e ' Allows to override dsn defined in "Default dsn directory"' + echo + echo -e " ${__HELP_TITLE}List of available dsn:${__HELP_NORMAL}" + echo -e "${dsnList}" +} + optionVersionCallback() { @@ -1868,6 +1954,13 @@ dsnHelpFunction() { echo " target mysql server" } +mysqlSourceLongDescription() { + fromDsnOptionLongDescription + echo + echo -e " ${__HELP_TITLE}Aws s3 location:${__HELP_NORMAL}" + echo -e " ${S3_BASE_URL}" +} + # ------------------------------------------ # Command dbImportCommand @@ -1877,7 +1970,7 @@ dsnHelpFunction() { declare optionCollationName="" declare optionTargetDsn="default.local" declare optionCharacterSet="" -declare optionProfile="default" +declare optionProfile="" declare optionTables="" declare optionSkipSchema="0" declare optionFromDsn="" @@ -1888,7 +1981,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1912,7 +2004,7 @@ dbImportCommandParse() { optionCharacterSet="" local -i options_parse_optionParsedCountOptionCharacterSet ((options_parse_optionParsedCountOptionCharacterSet = 0)) || true - optionProfile="default" + optionProfile="" local -i options_parse_optionParsedCountOptionProfile ((options_parse_optionParsedCountOptionProfile = 0)) || true optionTables="" @@ -1945,7 +2037,6 @@ dbImportCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1983,7 +2074,7 @@ dbImportCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/22 + # Option 1/21 # optionCollationName alts --collation-name|-o # type: String min 0 max 1 --collation-name | -o) @@ -2002,7 +2093,7 @@ dbImportCommandParse() { optionCollationName="$1" ;; - # Option 2/22 + # Option 2/21 # optionTargetDsn alts --target-dsn|-t # type: String min 0 max 1 --target-dsn | -t) @@ -2021,7 +2112,7 @@ dbImportCommandParse() { optionTargetDsn="$1" ;; - # Option 3/22 + # Option 3/21 # optionCharacterSet alts --character-set|-c # type: String min 0 max 1 --character-set | -c) @@ -2040,7 +2131,7 @@ dbImportCommandParse() { optionCharacterSet="$1" ;; - # Option 4/22 + # Option 4/21 # optionProfile alts --profile|-p # type: String min 0 max 1 --profile | -p) @@ -2057,11 +2148,9 @@ dbImportCommandParse() { ((++options_parse_optionParsedCountOptionProfile)) # shellcheck disable=SC2034 optionProfile="$1" - profileOptionCallback "${options_parse_arg}" "${optionProfile}" - ;; - # Option 5/22 + # Option 5/21 # optionTables alts --tables # type: String min 0 max 1 --tables) @@ -2082,7 +2171,7 @@ dbImportCommandParse() { ;; - # Option 6/22 + # Option 6/21 # optionSkipSchema alts --skip-schema|-s # type: Boolean min 0 max 1 --skip-schema | -s) @@ -2096,7 +2185,7 @@ dbImportCommandParse() { ((++options_parse_optionParsedCountOptionSkipSchema)) ;; - # Option 7/22 + # Option 7/21 # optionFromDsn alts --from-dsn|-f # type: String min 0 max 1 --from-dsn | -f) @@ -2115,7 +2204,7 @@ dbImportCommandParse() { optionFromDsn="$1" ;; - # Option 8/22 + # Option 8/21 # optionFromAws alts --from-aws|-a # type: String min 0 max 1 --from-aws | -a) @@ -2134,7 +2223,7 @@ dbImportCommandParse() { optionFromAws="$1" ;; - # Option 9/22 + # Option 9/21 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -2150,7 +2239,7 @@ dbImportCommandParse() { ;; - # Option 10/22 + # Option 10/21 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -2164,7 +2253,7 @@ dbImportCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 11/22 + # Option 11/21 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -2185,7 +2274,7 @@ dbImportCommandParse() { ;; - # Option 12/22 + # Option 12/21 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -2203,7 +2292,7 @@ dbImportCommandParse() { ;; - # Option 13/22 + # Option 13/21 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -2221,7 +2310,7 @@ dbImportCommandParse() { ;; - # Option 14/22 + # Option 14/21 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -2239,25 +2328,7 @@ dbImportCommandParse() { ;; - # Option 15/22 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 16/22 + # Option 15/21 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -2285,7 +2356,7 @@ dbImportCommandParse() { ;; - # Option 17/22 + # Option 16/21 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -2308,7 +2379,7 @@ dbImportCommandParse() { ;; - # Option 18/22 + # Option 17/21 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -2336,7 +2407,7 @@ dbImportCommandParse() { ;; - # Option 19/22 + # Option 18/21 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -2354,7 +2425,7 @@ dbImportCommandParse() { ;; - # Option 20/22 + # Option 19/21 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -2382,7 +2453,7 @@ dbImportCommandParse() { ;; - # Option 21/22 + # Option 20/21 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -2398,7 +2469,7 @@ dbImportCommandParse() { ;; - # Option 22/22 + # Option 21/21 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -2499,7 +2570,6 @@ dbImportCommandParse() { - if ((options_parse_argParsedCountFromDbName < 1 )); then @@ -2531,7 +2601,7 @@ dbImportCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--collation-name|-o ]" "[--target-dsn|-t ]" "[--character-set|-c ]" "[--profile|-p ]" "[--tables ]" "[--skip-schema|-s]" "[--from-dsn|-f ]" "[--from-aws|-a ]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" + optionsAltList=("[--collation-name|-o ]" "[--target-dsn|-t ]" "[--character-set|-c ]" "[--profile|-p ]" "[--tables ]" "[--skip-schema|-s]" "[--from-dsn|-f ]" "[--from-aws|-a ]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "dbImport" "${optionsAltList[@]}" @@ -2582,11 +2652,9 @@ dbImportCommandHelp() { - Array::wrap2 ' ' 76 6 " Default value: " "default" - echo echo -e " ${__HELP_OPTION_COLOR}--tables ${__HELP_NORMAL} {single}" - Array::wrap2 ' ' 76 4 " " "Import only table specified in the list." "If aws mode, ignore profile option." "" + Array::wrap2 ' ' 76 4 " " "Import only table specified in the list." "If aws mode, ignore profile option." echo @@ -2647,12 +2715,6 @@ dbImportCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo @@ -2699,6 +2761,13 @@ dbImportCommandHelp() { echo + # ------------------------------------------ + # longDescription section + # ------------------------------------------ + echo + echo + echo -e "${__HELP_TITLE_COLOR}DESCRIPTION:${__RESET_COLOR}" + longDescriptionFunction # ------------------------------------------ # version section # ------------------------------------------ diff --git a/bin/dbImportProfile b/bin/dbImportProfile index 1818bd57..b66bc280 100755 --- a/bin/dbImportProfile +++ b/bin/dbImportProfile @@ -139,6 +139,23 @@ export __VERBOSE_LEVEL_DEBUG=2 export __VERBOSE_LEVEL_TRACE=3 +# @description check if an element is contained in an array +# +# @arg $1 needle:String +# @arg $@ array:String[] +# @exitcode 0 if found +# @exitcode 1 otherwise +# @example +# Array::contains "${libPath}" "${__BASH_FRAMEWORK_IMPORTED_FILES[@]}" +Array::contains() { + local element + for element in "${@:2}"; do + [[ "${element}" = "$1" ]] && return 0 + done + return 1 +} + + # @description concatenate each element of an array with a separator # but wrapping text when line length is more than provided argument # The algorithm will try not to cut the array element if it can. @@ -338,18 +355,79 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + # @description loads ~/.bash-tools/.env if available # if not creates it from a default template # else check if new options need to be added BashTools::Conf::requireLoad() { -Linux::requireTarCommand -Compiler::Embed::extractFileFromBase64 \ - "${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" \ - "IyEvdXNyL2Jpbi9lbnYgYmFzaAojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKCiMgRGVmYXVsdCBzZXR0aW5ncwojIHlvdSBjYW4gb3ZlcnJpZGUgdGhlc2Ugc2V0dGluZ3MgYnkgY3JlYXRpbmcgJHtIT01FfS8uYmFzaC10b29scy8uZW52IGZpbGUKCiMjIwojIyMgRElTUExBWSBMZXZlbAojIyMgbWluaW11bSBsZXZlbCBvZiB0aGUgbWVzc2FnZXMgdGhhdCB3aWxsIGJlIGRpc3BsYXllZCBvbiBzY3JlZW4KIyMjCiMjIyAwOiBOTyBMT0cKIyMjIDE6IEVSUk9SCiMjIyAyOiBXQVJOSU5HCiMjIyAzOiBJTkZPCiMjIyA0OiBERUJVRwojIyMKQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTD0ke0JBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUw6LTN9CgojIyMKIyMjIERJU1BMQVkgZHVyYXRpb24KIyMjIDA6IG5vIGR1cmF0aW9uIGlzIGRpc3BsYXllZCBvbiB0aGUgbWVzc2FnZXMKIyMjIDE6IGR1cmF0aW9uIGJldHdlZW4gcHJldmlvdXMgbWVzc2FnZSBhbmQgY3VycmVudCBpcyBkaXNwbGF5ZWQKIyMjIHdpdGggdGhlIG1lc3NhZ2UKIyMjCkRJU1BMQVlfRFVSQVRJT049JHtESVNQTEFZX0RVUkFUSU9OOjB9CgojIyMKIyMjIExvZyB0byBmaWxlCiMjIwojIyMgYWxsIGxvZyBtZXNzYWdlcyB3aWxsIGJlIHJlZGlyZWN0ZWQgdG8gbG9nIGZpbGUgc3BlY2lmaWVkCiMjIyB0aGlzIHNhbWUgcGF0aCB3aWxsIGJlIHVzZWQgaW5zaWRlIGFuZCBvdXRzaWRlIG9mIHRoZSBjb250YWluZXIKIyMjCkJBU0hfRlJBTUVXT1JLX0xPR19GSUxFPSR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEU6LSR7RlJBTUVXT1JLX1JPT1RfRElSfS9sb2dzL2Jhc2gubG9nfQoKIyMjCiMjIyBMT0cgTGV2ZWwKIyMjIG1pbmltdW0gbGV2ZWwgb2YgdGhlIG1lc3NhZ2VzIHRoYXQgd2lsbCBiZSBsb2dnZWQgaW50byBMT0dfRklMRQojIyMKIyMjIDA6IE5PIExPRwojIyMgMTogRVJST1IKIyMjIDI6IFdBUk5JTkcKIyMjIDM6IElORk8KIyMjIDQ6IERFQlVHCiMjIwpCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw6LTB9CgojIGFic29sdXRlIGRpcmVjdG9yeSBjb250YWluaW5nIGRiIGltcG9ydCBzcWwgZHVtcHMKREJfSU1QT1JUX0RVTVBfRElSPSR7REJfSU1QT1JUX0RVTVBfRElSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2RiSW1wb3J0RHVtcHN9CgojIGdhcmJhZ2UgY29sbGVjdCBhbGwgZmlsZXMgZm9yIHdoaWNoIG1vZGlmaWNhdGlvbiBpcyBncmVhdGVyIHRoYW4gZWc6IDMwIGRheXMgKCszMCkKIyBlYWNoIHRpbWUgYW4gZXhpc3RpbmcgZmlsZSBpcyB1c2VkIGJ5IGRiSW1wb3J0L2RiSW1wb3J0VGFibGUKIyB0aGUgZmlsZSBtb2RpZmljYXRpb24gdGltZSBpcyBzZXQgdG8gbm93CkRCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUz0ke0RCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUzotKzMwfQoKIyBhYnNvbHV0ZSBkaXJlY3RvcnkgY29udGFpbmluZyBkYlNjcmlwdHMgdXNlZCBieSBkYlNjcmlwdEFsbERhdGFiYXNlcwpTQ1JJUFRTX0ZPTERFUj0ke1NDUklQVFNfRk9MREVSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2NvbmYvZGJTY3JpcHRzfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEFXUyBQYXJhbWV0ZXJzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KUzNfQkFTRV9VUkw9JHtTM19CQVNFX1VSTDotfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFBvc3RtYW4gUGFyYW1ldGVycwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tClBPU1RNQU5fQVBJX0tFWT0K" \ - "755" - -declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" - BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" @@ -377,7 +455,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ( echo "#!/usr/bin/env bash" # shellcheck disable=SC2154 - echo "${embed_file_bashToolsDefaultConfigTemplate}" + echo "${bashToolsDefaultConfigTemplate}" ) >"${envFile}" Log::displayInfo "Configuration file '${envFile}' created" else @@ -390,7 +468,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ) >>"${envFile}" fi fi - # shellcheck source=/conf/.env + # shellcheck source=/conf/defaultEnv/.env source "${envFile}" || { Log::displayError "impossible to load '${envFile}'" exit 1 @@ -398,36 +476,6 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp } -# @description convert base64 encoded back to target file -# if target file is executable prepend dir of target -# file to PATH to make binary available everywhere -# it is advised to include in the path of the target file -# the md5sum of the binFile -# -# @arg $1 targetFile:String the file to write -# @arg $2 binFileBase64:String the base64 encoded file -# @arg $3 fileMode:String the chmod to set on the file -# @set PATH String prepend target embedded file binary directory to PATH variable if binary executable -Compiler::Embed::extractFileFromBase64() { - local targetFile="$1" - local binFileBase64="$2" - local fileMode="${3:-+x}" - local targetDir="${targetFile%/*}" - - if [[ ! -f "${targetFile}" ]]; then - if [[ ! -d "${targetDir}" ]]; then - mkdir -p "${targetDir}" - fi - base64 -d >"${targetFile}" <<<"${binFileBase64}" - chmod "${fileMode}" "${targetFile}" - fi - - if [[ -x "${targetFile}" ]]; then - Env::pathPrepend "${targetDir}" - fi -} - - # @description get absolute conf file from specified conf folder deduced using these rules # * from absolute file (ignores and ) # * relative to where script is executed (ignores and ) @@ -762,19 +810,6 @@ Db::checkRequirements() { } -# @description prepend directories to the PATH environment variable -# @arg $@ args:String[] list of directories to prepend -# @set PATH update PATH with the directories prepended -Env::pathPrepend() { - local arg - for arg in "$@"; do - if [[ -d "${arg}" && ":${PATH}:" != *":${arg}:"* ]]; then - PATH="$(realpath "${arg}"):${PATH}" - fi - done -} - - # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -857,14 +892,6 @@ Linux::requireRealpathCommand() { } -# @description ensure command tar is available -# @exitcode 1 if tar command not available -# @stderr diagnostics information is displayed -Linux::requireTarCommand() { - Assert::commandExists tar -} - - declare -g FIRST_LOG_DATE LOG_LAST_LOG_DATE LOG_LAST_LOG_DATE_INIT LOG_LAST_DURATION_STR FIRST_LOG_DATE="${EPOCHREALTIME/[^0-9]/}" LOG_LAST_LOG_DATE="${FIRST_LOG_DATE}" @@ -1344,6 +1371,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2021-now François Chastanet" } @@ -1387,16 +1415,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1571,9 +1589,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1588,40 +1603,161 @@ commandOptionParseFinished() { } + +defaultBeforeParseCallback() { + BashTools::Conf::requireLoad + Env::requireLoad + UI::requireTheme + Log::requireLoad +} + +beforeParseCallback() { + defaultBeforeParseCallback +} + + + +profileOptionLongDescription() { + local profilesList="" + profilesList="$(Conf::getMergedList "dbImportProfiles" "sh" " - " || true)" + + echo -e " ${__HELP_TITLE}Profiles${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL}" + echo -e " ${PROFILES_DIR-configuration error}" + echo + echo -e " ${__HELP_TITLE}User profiles directory:${__HELP_NORMAL}" + echo -e " ${HOME_PROFILES_DIR-configuration error}" + echo -e ' Allows to override profiles defined in "Default profiles directory"' + echo + echo -e " ${__HELP_TITLE}List of available profiles:${__HELP_NORMAL}" + echo -e "${profilesList}" +} + +profileOptionHelpFunction() { + Array::wrap2 " " 80 4 \ + " The name of the profile to use in order to include or exclude tables." + echo +} + +initOptionProfileIfNotSet() { + if [[ -z "${optionProfile}" ]]; then + optionProfile="${defaultOptionProfile}" + fi + local -a profilesArray + readarray -t profilesArray < <(Conf::getMergedList "dbImportProfiles" "sh" "" || true) + if ! Array::contains "${optionProfile}" "${profilesArray[@]}"; then + Log::displayError "${SCRIPT_NAME} - invalid profile '${optionProfile}' provided" + return 1 + fi +} + +declare defaultOptionProfile="default" +initProfileCommandCallback() { + initOptionProfileIfNotSet + + # shellcheck disable=SC2154 + if [[ "${optionProfile}" != "default" && -n "${optionTables}" ]]; then + Log::fatal "Command ${SCRIPT_NAME} - you cannot use table and profile options at the same time" + fi + + # Profile selection + local profileMsgInfo + # shellcheck disable=SC2154 + if [[ "${optionProfile}" = 'default' && -n "${optionTables}" ]]; then + profileCommandFile=$(Framework::createTempFile "profileCmd.XXXXXXXXXXXX") + profileMsgInfo="only ${optionTables} will be imported" + ( + echo '#!/usr/bin/env bash' + if [[ -n "${optionTables}" ]]; then + echo "${optionTables}" | sed -E 's/([A-Za-z0-9_]+),?/echo "\1"\n/g' + else + # tables option not specified, we will import all tables of the profile + echo 'cat' + fi + ) >"${profileCommandFile}" + else + profileCommandFile="$(Conf::getAbsoluteFile "dbImportProfiles" "${optionProfile}" "sh")" || exit 1 + profileMsgInfo="Using profile ${profileCommandFile}" + fi + chmod +x "${profileCommandFile}" + Log::displayInfo "${profileMsgInfo}" +} + + + +optionRatioHelpFunction() { + Array::wrap2 " " 80 4 \ + " define the ratio to use (0 to 100% - default 70).\r" \ + "- 0 means profile will filter out all the tables\r" \ + "- 100 means profile will keep all the tables.\r" \ + "Eg: 70 means that tables with size(table+index)\r" \ + "that are greater than 70% of the max table size will be excluded." + echo +} + + + +fromDsnOptionLongDescription() { + local dsnList="" + dsnList="$(Conf::getMergedList "dsn" "env" " - ")" + + echo -e " ${__HELP_TITLE}Data Source Name (DSN)${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default dsn directory:${__HELP_NORMAL}" + echo -e " ${BASH_TOOLS_ROOT_DIR}/conf/dsn" + echo + echo -e " ${__HELP_TITLE}User dsn directory:${__HELP_NORMAL}" + echo -e " ${HOME}/.bash-tools/dsn" + echo -e ' Allows to override dsn defined in "Default dsn directory"' + echo + echo -e " ${__HELP_TITLE}List of available dsn:${__HELP_NORMAL}" + echo -e "${dsnList}" +} + + + +optionVersionCallback() { + # shellcheck disable=SC2154 + echo "${SCRIPT_NAME} version 3.0" + Db::checkRequirements + exit 0 +} + + declare defaultFromDsn="default.remote" # shellcheck disable=SC2034 declare PROFILES_DIR declare HOME_PROFILES_DIR +# shellcheck disable=SC2034 +defaultOptionProfile="" + +beforeParseCallback() { + defaultBeforeParseCallback + Linux::requireExecutedAsUser + Linux::requireRealpathCommand + Assert::commandExists mysql "sudo apt-get install -y mysql-client" + Assert::commandExists mysqlshow "sudo apt-get install -y mysql-client" +} initConf() { # shellcheck disable=SC2034 PROFILES_DIR="${BASH_TOOLS_ROOT_DIR}/conf/dbImportProfiles" + # shellcheck disable=SC2034 HOME_PROFILES_DIR="${HOME}/.bash-tools/dbImportProfiles" } +initProfileCommandCallback() { + : +} + optionHelpCallback() { dbImportProfileCommandHelp exit 0 } longDescriptionFunction() { - local profilesList="" - local dsnList="" - dsnList="$(Conf::getMergedList "dsn" "env")" - profilesList="$(Conf::getMergedList "dbImportProfiles" "sh" || true)" - - echo -e "${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL}" - echo -e "${PROFILES_DIR-configuration error}" - echo - echo -e "${__HELP_TITLE}User profiles directory:${__HELP_NORMAL}" - echo -e "${HOME_PROFILES_DIR-configuration error}" - echo -e 'Allows to override profiles defined in "Default profiles directory"' - echo - echo -e "${__HELP_TITLE}List of available profiles:${__HELP_NORMAL}" - echo -e "${profilesList}" + fromDsnOptionLongDescription echo - echo -e "${__HELP_TITLE}List of available dsn:${__HELP_NORMAL}" - echo -e "${dsnList}" + profileOptionLongDescription } optionProfileHelpFunction() { @@ -1638,16 +1774,6 @@ optionFromDsnHelpFunction() { echo } -optionRatioHelpFunction() { - Array::wrap2 " " 80 4 \ - " define the ratio to use (0 to 100% - default 70).\n" \ - "- 0 means profile will filter out all the tables\n" \ - "- 100 means profile will keep all the tables.\n" \ - "Eg: 70 means that tables with size(table+index)\n" \ - "that are greater than 70% of the max table size will be excluded." - echo -} - dbImportProfileCommandCallback() { if [[ -z "${fromDbName}" ]]; then Log::fatal "you must provide fromDbName" @@ -1669,29 +1795,13 @@ dbImportProfileCommandCallback() { } - -optionVersionCallback() { - # shellcheck disable=SC2154 - echo "${SCRIPT_NAME} version 3.0" - Db::checkRequirements - exit 0 -} - - - -beforeParseCallback() { - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad -} - - # ------------------------------------------ # Command dbImportProfileCommand # ------------------------------------------ # options variables initialization +declare optionRatio="70" +declare optionProfile="" declare optionFromDsn="" declare optionHelp="0" declare optionConfig="0" @@ -1699,7 +1809,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1707,14 +1816,18 @@ declare optionNoColor="0" declare optionTheme="default" declare optionVersion="0" declare optionQuiet="0" -declare optionProfile="" -declare optionRatio="70" # arguments variables initialization declare fromDbName="" # @description parse command options and arguments for dbImportProfileCommand dbImportProfileCommandParse() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" + optionRatio="70" + local -i options_parse_optionParsedCountOptionRatio + ((options_parse_optionParsedCountOptionRatio = 0)) || true + optionProfile="" + local -i options_parse_optionParsedCountOptionProfile + ((options_parse_optionParsedCountOptionProfile = 0)) || true optionFromDsn="" local -i options_parse_optionParsedCountOptionFromDsn ((options_parse_optionParsedCountOptionFromDsn = 0)) || true @@ -1736,7 +1849,6 @@ dbImportProfileCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1758,12 +1870,6 @@ dbImportProfileCommandParse() { optionQuiet="0" local -i options_parse_optionParsedCountOptionQuiet ((options_parse_optionParsedCountOptionQuiet = 0)) || true - optionProfile="" - local -i options_parse_optionParsedCountOptionProfile - ((options_parse_optionParsedCountOptionProfile = 0)) || true - optionRatio="70" - local -i options_parse_optionParsedCountOptionRatio - ((options_parse_optionParsedCountOptionRatio = 0)) || true fromDbName="" local -i options_parse_argParsedCountFromDbName @@ -1776,7 +1882,45 @@ dbImportProfileCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/17 + # Option 1/16 + # optionRatio alts --ratio|-r + # type: String min 0 max 1 + --ratio | -r) + shift + if (($# == 0)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" + return 1 + fi + + if ((options_parse_optionParsedCountOptionRatio >= 1 )); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionRatio)) + # shellcheck disable=SC2034 + optionRatio="$1" + ;; + + # Option 2/16 + # optionProfile alts --profile|-p + # type: String min 0 max 1 + --profile | -p) + shift + if (($# == 0)); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" + return 1 + fi + + if ((options_parse_optionParsedCountOptionProfile >= 1 )); then + Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" + return 1 + fi + ((++options_parse_optionParsedCountOptionProfile)) + # shellcheck disable=SC2034 + optionProfile="$1" + ;; + + # Option 3/16 # optionFromDsn alts --from-dsn|-f # type: String min 0 max 1 --from-dsn | -f) @@ -1795,7 +1939,7 @@ dbImportProfileCommandParse() { optionFromDsn="$1" ;; - # Option 2/17 + # Option 4/16 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1811,7 +1955,7 @@ dbImportProfileCommandParse() { ;; - # Option 3/17 + # Option 5/16 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1825,7 +1969,7 @@ dbImportProfileCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 4/17 + # Option 6/16 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1846,7 +1990,7 @@ dbImportProfileCommandParse() { ;; - # Option 5/17 + # Option 7/16 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1864,7 +2008,7 @@ dbImportProfileCommandParse() { ;; - # Option 6/17 + # Option 8/16 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1882,7 +2026,7 @@ dbImportProfileCommandParse() { ;; - # Option 7/17 + # Option 9/16 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1900,25 +2044,7 @@ dbImportProfileCommandParse() { ;; - # Option 8/17 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 9/17 + # Option 10/16 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1946,7 +2072,7 @@ dbImportProfileCommandParse() { ;; - # Option 10/17 + # Option 11/16 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1969,7 +2095,7 @@ dbImportProfileCommandParse() { ;; - # Option 11/17 + # Option 12/16 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1997,7 +2123,7 @@ dbImportProfileCommandParse() { ;; - # Option 12/17 + # Option 13/16 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -2015,7 +2141,7 @@ dbImportProfileCommandParse() { ;; - # Option 13/17 + # Option 14/16 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -2043,7 +2169,7 @@ dbImportProfileCommandParse() { ;; - # Option 14/17 + # Option 15/16 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -2059,7 +2185,7 @@ dbImportProfileCommandParse() { ;; - # Option 15/17 + # Option 16/16 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -2077,44 +2203,6 @@ dbImportProfileCommandParse() { ;; - # Option 16/17 - # optionProfile alts --profile|-p - # type: String min 0 max 1 - --profile | -p) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - if ((options_parse_optionParsedCountOptionProfile >= 1 )); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" - return 1 - fi - ((++options_parse_optionParsedCountOptionProfile)) - # shellcheck disable=SC2034 - optionProfile="$1" - ;; - - # Option 17/17 - # optionRatio alts --ratio|-r - # type: String min 0 max 1 - --ratio | -r) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - if ((options_parse_optionParsedCountOptionRatio >= 1 )); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - Maximum number of option occurrences reached(1)" - return 1 - fi - ((++options_parse_optionParsedCountOptionRatio)) - # shellcheck disable=SC2034 - optionRatio="$1" - ;; - -*) if [[ "${argOptDefaultBehavior}" = "0" ]]; then Log::displayError "Command ${SCRIPT_NAME} - Invalid option ${options_parse_arg}" @@ -2179,14 +2267,15 @@ dbImportProfileCommandParse() { - if ((options_parse_argParsedCountFromDbName < 1 )); then Log::displayError "Command ${SCRIPT_NAME} - Argument 'fromDbName' should be provided at least 1 time(s)" return 1 fi || return $? + commandOptionParseFinished + initProfileCommandCallback dbImportProfileCommandCallback } @@ -2207,7 +2296,7 @@ dbImportProfileCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--from-dsn|-f ]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--profile|-p ]" "[--ratio|-r ]" + optionsAltList=("[--ratio|-r ]" "[--profile|-p ]" "[--from-dsn|-f ]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "dbImportProfile" "${optionsAltList[@]}" @@ -2226,6 +2315,21 @@ dbImportProfileCommandHelp() { # ------------------------------------------ # options section # ------------------------------------------ + echo + echo -e "${__HELP_TITLE_COLOR}PROFILE OPTIONS:${__RESET_COLOR}" + echo -e " ${__HELP_OPTION_COLOR}--ratio${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-r ${__HELP_NORMAL} {single}" + optionRatioHelpFunction + + + + Array::wrap2 ' ' 76 6 " Default value: " "70" + echo + + echo -e " ${__HELP_OPTION_COLOR}--profile${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-p ${__HELP_NORMAL} {single}" + profileOptionHelpFunction + + + echo echo -e "${__HELP_TITLE_COLOR}SOURCE OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--from-dsn${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-f ${__HELP_NORMAL} {single}" @@ -2271,12 +2375,6 @@ dbImportProfileCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo @@ -2323,21 +2421,6 @@ dbImportProfileCommandHelp() { echo - echo - echo -e "${__HELP_TITLE_COLOR}OPTIONS:${__RESET_COLOR}" - echo -e " ${__HELP_OPTION_COLOR}--profile${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-p ${__HELP_NORMAL} {single}" - optionProfileHelpFunction - - - - - echo -e " ${__HELP_OPTION_COLOR}--ratio${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-r ${__HELP_NORMAL} {single}" - optionRatioHelpFunction - - - - Array::wrap2 ' ' 76 6 " Default value: " "70" - echo # ------------------------------------------ # longDescription section # ------------------------------------------ @@ -2395,12 +2478,6 @@ WHERE ORDER BY maxSize DESC EOM2 -# check dependencies -Linux::requireExecutedAsUser -Linux::requireRealpathCommand -Assert::commandExists mysql "sudo apt-get install -y mysql-client" -Assert::commandExists mysqlshow "sudo apt-get install -y mysql-client" - # create db instance declare -Agx dbFromInstance diff --git a/bin/dbImportStream b/bin/dbImportStream index 5729ab43..55ab96d1 100755 --- a/bin/dbImportStream +++ b/bin/dbImportStream @@ -355,18 +355,79 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + # @description loads ~/.bash-tools/.env if available # if not creates it from a default template # else check if new options need to be added BashTools::Conf::requireLoad() { -Linux::requireTarCommand -Compiler::Embed::extractFileFromBase64 \ - "${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" \ - "IyEvdXNyL2Jpbi9lbnYgYmFzaAojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKCiMgRGVmYXVsdCBzZXR0aW5ncwojIHlvdSBjYW4gb3ZlcnJpZGUgdGhlc2Ugc2V0dGluZ3MgYnkgY3JlYXRpbmcgJHtIT01FfS8uYmFzaC10b29scy8uZW52IGZpbGUKCiMjIwojIyMgRElTUExBWSBMZXZlbAojIyMgbWluaW11bSBsZXZlbCBvZiB0aGUgbWVzc2FnZXMgdGhhdCB3aWxsIGJlIGRpc3BsYXllZCBvbiBzY3JlZW4KIyMjCiMjIyAwOiBOTyBMT0cKIyMjIDE6IEVSUk9SCiMjIyAyOiBXQVJOSU5HCiMjIyAzOiBJTkZPCiMjIyA0OiBERUJVRwojIyMKQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTD0ke0JBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUw6LTN9CgojIyMKIyMjIERJU1BMQVkgZHVyYXRpb24KIyMjIDA6IG5vIGR1cmF0aW9uIGlzIGRpc3BsYXllZCBvbiB0aGUgbWVzc2FnZXMKIyMjIDE6IGR1cmF0aW9uIGJldHdlZW4gcHJldmlvdXMgbWVzc2FnZSBhbmQgY3VycmVudCBpcyBkaXNwbGF5ZWQKIyMjIHdpdGggdGhlIG1lc3NhZ2UKIyMjCkRJU1BMQVlfRFVSQVRJT049JHtESVNQTEFZX0RVUkFUSU9OOjB9CgojIyMKIyMjIExvZyB0byBmaWxlCiMjIwojIyMgYWxsIGxvZyBtZXNzYWdlcyB3aWxsIGJlIHJlZGlyZWN0ZWQgdG8gbG9nIGZpbGUgc3BlY2lmaWVkCiMjIyB0aGlzIHNhbWUgcGF0aCB3aWxsIGJlIHVzZWQgaW5zaWRlIGFuZCBvdXRzaWRlIG9mIHRoZSBjb250YWluZXIKIyMjCkJBU0hfRlJBTUVXT1JLX0xPR19GSUxFPSR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEU6LSR7RlJBTUVXT1JLX1JPT1RfRElSfS9sb2dzL2Jhc2gubG9nfQoKIyMjCiMjIyBMT0cgTGV2ZWwKIyMjIG1pbmltdW0gbGV2ZWwgb2YgdGhlIG1lc3NhZ2VzIHRoYXQgd2lsbCBiZSBsb2dnZWQgaW50byBMT0dfRklMRQojIyMKIyMjIDA6IE5PIExPRwojIyMgMTogRVJST1IKIyMjIDI6IFdBUk5JTkcKIyMjIDM6IElORk8KIyMjIDQ6IERFQlVHCiMjIwpCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw6LTB9CgojIGFic29sdXRlIGRpcmVjdG9yeSBjb250YWluaW5nIGRiIGltcG9ydCBzcWwgZHVtcHMKREJfSU1QT1JUX0RVTVBfRElSPSR7REJfSU1QT1JUX0RVTVBfRElSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2RiSW1wb3J0RHVtcHN9CgojIGdhcmJhZ2UgY29sbGVjdCBhbGwgZmlsZXMgZm9yIHdoaWNoIG1vZGlmaWNhdGlvbiBpcyBncmVhdGVyIHRoYW4gZWc6IDMwIGRheXMgKCszMCkKIyBlYWNoIHRpbWUgYW4gZXhpc3RpbmcgZmlsZSBpcyB1c2VkIGJ5IGRiSW1wb3J0L2RiSW1wb3J0VGFibGUKIyB0aGUgZmlsZSBtb2RpZmljYXRpb24gdGltZSBpcyBzZXQgdG8gbm93CkRCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUz0ke0RCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUzotKzMwfQoKIyBhYnNvbHV0ZSBkaXJlY3RvcnkgY29udGFpbmluZyBkYlNjcmlwdHMgdXNlZCBieSBkYlNjcmlwdEFsbERhdGFiYXNlcwpTQ1JJUFRTX0ZPTERFUj0ke1NDUklQVFNfRk9MREVSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2NvbmYvZGJTY3JpcHRzfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEFXUyBQYXJhbWV0ZXJzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KUzNfQkFTRV9VUkw9JHtTM19CQVNFX1VSTDotfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFBvc3RtYW4gUGFyYW1ldGVycwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tClBPU1RNQU5fQVBJX0tFWT0K" \ - "755" - -declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" - BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" @@ -394,7 +455,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ( echo "#!/usr/bin/env bash" # shellcheck disable=SC2154 - echo "${embed_file_bashToolsDefaultConfigTemplate}" + echo "${bashToolsDefaultConfigTemplate}" ) >"${envFile}" Log::displayInfo "Configuration file '${envFile}' created" else @@ -407,7 +468,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ) >>"${envFile}" fi fi - # shellcheck source=/conf/.env + # shellcheck source=/conf/defaultEnv/.env source "${envFile}" || { Log::displayError "impossible to load '${envFile}'" exit 1 @@ -1338,6 +1399,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -1381,16 +1443,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1565,9 +1617,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1583,16 +1632,26 @@ commandOptionParseFinished() { +defaultBeforeParseCallback() { + BashTools::Conf::requireLoad + Env::requireLoad + UI::requireTheme + Log::requireLoad +} + +beforeParseCallback() { + defaultBeforeParseCallback +} + + + declare PROFILES_DIR declare HOME_PROFILES_DIR # shellcheck disable=SC2034 declare defaultFromDsn="default.remote" beforeParseCallback() { - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad + defaultBeforeParseCallback Linux::requireExecutedAsUser Linux::requireRealpathCommand } @@ -1600,6 +1659,7 @@ beforeParseCallback() { initConf() { # shellcheck disable=SC2034 PROFILES_DIR="${BASH_TOOLS_ROOT_DIR}/conf/dbImportProfiles" + # shellcheck disable=SC2034 HOME_PROFILES_DIR="${HOME}/.bash-tools/dbImportProfiles" Db::checkRequirements } @@ -1610,23 +1670,9 @@ optionHelpCallback() { } longDescriptionFunction() { - local profilesList="" - local dsnList="" - dsnList="$(Conf::getMergedList "dsn" "env")" - profilesList="$(Conf::getMergedList "dbImportProfiles" "sh" || true)" - - echo -e "${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL}" - echo -e "${PROFILES_DIR-configuration error}" - echo - echo -e "${__HELP_TITLE}User profiles directory:${__HELP_NORMAL}" - echo -e "${HOME_PROFILES_DIR-configuration error}" - echo -e "Allows to override profiles defined in 'Default profiles directory'" - echo - echo -e "${__HELP_TITLE}List of available profiles:${__HELP_NORMAL}" - echo -e "${profilesList}" + fromDsnOptionLongDescription echo - echo -e "${__HELP_TITLE}List of available dsn:${__HELP_NORMAL}" - echo -e "${dsnList}" + profileOptionLongDescription } dbImportStreamCommandCallback() { @@ -1664,13 +1710,44 @@ initializeDefaultTargetMysqlOptions() { +profileOptionLongDescription() { + local profilesList="" + profilesList="$(Conf::getMergedList "dbImportProfiles" "sh" " - " || true)" + + echo -e " ${__HELP_TITLE}Profiles${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL}" + echo -e " ${PROFILES_DIR-configuration error}" + echo + echo -e " ${__HELP_TITLE}User profiles directory:${__HELP_NORMAL}" + echo -e " ${HOME_PROFILES_DIR-configuration error}" + echo -e ' Allows to override profiles defined in "Default profiles directory"' + echo + echo -e " ${__HELP_TITLE}List of available profiles:${__HELP_NORMAL}" + echo -e "${profilesList}" +} + profileOptionHelpFunction() { Array::wrap2 " " 80 4 \ " The name of the profile to use in order to include or exclude tables." echo } +initOptionProfileIfNotSet() { + if [[ -z "${optionProfile}" ]]; then + optionProfile="${defaultOptionProfile}" + fi + local -a profilesArray + readarray -t profilesArray < <(Conf::getMergedList "dbImportProfiles" "sh" "" || true) + if ! Array::contains "${optionProfile}" "${profilesArray[@]}"; then + Log::displayError "${SCRIPT_NAME} - invalid profile '${optionProfile}' provided" + return 1 + fi +} + +declare defaultOptionProfile="default" initProfileCommandCallback() { + initOptionProfileIfNotSet + # shellcheck disable=SC2154 if [[ "${optionProfile}" != "default" && -n "${optionTables}" ]]; then Log::fatal "Command ${SCRIPT_NAME} - you cannot use table and profile options at the same time" @@ -1699,16 +1776,10 @@ initProfileCommandCallback() { Log::displayInfo "${profileMsgInfo}" } -profileOptionCallback() { - local -a profilesArray - readarray -t profilesArray < <(Conf::getMergedList "dbImportProfiles" "sh" "" || true) - if ! Array::contains "$2" "${profilesArray[@]}"; then - Log::displayError "${SCRIPT_NAME} - invalid profile '$2' provided" - return 1 - fi -} + optionTablesCallback() { + # shellcheck disable=SC2154 if [[ ! ${optionTables} =~ ^[A-Za-z0-9_]+(,[A-Za-z0-9_]+)*$ ]]; then Log::fatal "Command ${SCRIPT_NAME} - Table list is not valid : ${optionTables}" fi @@ -1716,6 +1787,24 @@ optionTablesCallback() { +fromDsnOptionLongDescription() { + local dsnList="" + dsnList="$(Conf::getMergedList "dsn" "env" " - ")" + + echo -e " ${__HELP_TITLE}Data Source Name (DSN)${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default dsn directory:${__HELP_NORMAL}" + echo -e " ${BASH_TOOLS_ROOT_DIR}/conf/dsn" + echo + echo -e " ${__HELP_TITLE}User dsn directory:${__HELP_NORMAL}" + echo -e " ${HOME}/.bash-tools/dsn" + echo -e ' Allows to override dsn defined in "Default dsn directory"' + echo + echo -e " ${__HELP_TITLE}List of available dsn:${__HELP_NORMAL}" + echo -e "${dsnList}" +} + + + optionVersionCallback() { # shellcheck disable=SC2154 echo "${SCRIPT_NAME} version 3.0" @@ -1724,21 +1813,12 @@ optionVersionCallback() { } - -beforeParseCallback() { - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad -} - - # ------------------------------------------ # Command dbImportStreamCommand # ------------------------------------------ # options variables initialization -declare optionProfile="default" +declare optionProfile="" declare optionTables="" declare optionTargetDsn="default.local" declare optionCharacterSet="" @@ -1748,7 +1828,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1763,7 +1842,7 @@ declare argTargetDbName="" dbImportStreamCommandParse() { Log::displayDebug "Command ${SCRIPT_NAME} - parse arguments: ${BASH_FRAMEWORK_ARGV[*]}" Log::displayDebug "Command ${SCRIPT_NAME} - parse filtered arguments: ${BASH_FRAMEWORK_ARGV_FILTERED[*]}" - optionProfile="default" + optionProfile="" local -i options_parse_optionParsedCountOptionProfile ((options_parse_optionParsedCountOptionProfile = 0)) || true optionTables="" @@ -1793,7 +1872,6 @@ dbImportStreamCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1831,7 +1909,7 @@ dbImportStreamCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/18 + # Option 1/17 # optionProfile alts --profile|-p # type: String min 0 max 1 --profile | -p) @@ -1848,11 +1926,9 @@ dbImportStreamCommandParse() { ((++options_parse_optionParsedCountOptionProfile)) # shellcheck disable=SC2034 optionProfile="$1" - profileOptionCallback "${options_parse_arg}" "${optionProfile}" - ;; - # Option 2/18 + # Option 2/17 # optionTables alts --tables # type: String min 0 max 1 --tables) @@ -1873,7 +1949,7 @@ dbImportStreamCommandParse() { ;; - # Option 3/18 + # Option 3/17 # optionTargetDsn alts --target-dsn|-t # type: String min 0 max 1 --target-dsn | -t) @@ -1892,7 +1968,7 @@ dbImportStreamCommandParse() { optionTargetDsn="$1" ;; - # Option 4/18 + # Option 4/17 # optionCharacterSet alts --character-set|-c # type: String min 0 max 1 --character-set | -c) @@ -1911,7 +1987,7 @@ dbImportStreamCommandParse() { optionCharacterSet="$1" ;; - # Option 5/18 + # Option 5/17 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1927,7 +2003,7 @@ dbImportStreamCommandParse() { ;; - # Option 6/18 + # Option 6/17 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1941,7 +2017,7 @@ dbImportStreamCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 7/18 + # Option 7/17 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1962,7 +2038,7 @@ dbImportStreamCommandParse() { ;; - # Option 8/18 + # Option 8/17 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1980,7 +2056,7 @@ dbImportStreamCommandParse() { ;; - # Option 9/18 + # Option 9/17 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1998,7 +2074,7 @@ dbImportStreamCommandParse() { ;; - # Option 10/18 + # Option 10/17 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -2016,25 +2092,7 @@ dbImportStreamCommandParse() { ;; - # Option 11/18 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 12/18 + # Option 11/17 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -2062,7 +2120,7 @@ dbImportStreamCommandParse() { ;; - # Option 13/18 + # Option 12/17 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -2085,7 +2143,7 @@ dbImportStreamCommandParse() { ;; - # Option 14/18 + # Option 13/17 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -2113,7 +2171,7 @@ dbImportStreamCommandParse() { ;; - # Option 15/18 + # Option 14/17 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -2131,7 +2189,7 @@ dbImportStreamCommandParse() { ;; - # Option 16/18 + # Option 15/17 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -2159,7 +2217,7 @@ dbImportStreamCommandParse() { ;; - # Option 17/18 + # Option 16/17 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -2175,7 +2233,7 @@ dbImportStreamCommandParse() { ;; - # Option 18/18 + # Option 17/17 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -2274,7 +2332,6 @@ dbImportStreamCommandParse() { - if ((options_parse_argParsedCountArgDumpFile < 1 )); then Log::displayError "Command ${SCRIPT_NAME} - Argument 'argDumpFile' should be provided at least 1 time(s)" return 1 @@ -2309,7 +2366,7 @@ dbImportStreamCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--profile|-p ]" "[--tables ]" "[--target-dsn|-t ]" "[--character-set|-c ]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" + optionsAltList=("[--profile|-p ]" "[--tables ]" "[--target-dsn|-t ]" "[--character-set|-c ]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "dbImportStream" "${optionsAltList[@]}" @@ -2339,11 +2396,9 @@ dbImportStreamCommandHelp() { - Array::wrap2 ' ' 76 6 " Default value: " "default" - echo echo -e " ${__HELP_OPTION_COLOR}--tables ${__HELP_NORMAL} {single}" - Array::wrap2 ' ' 76 4 " " "Import only table specified in the list." "If aws mode, ignore profile option." "" + Array::wrap2 ' ' 76 4 " " "Import only table specified in the list." "If aws mode, ignore profile option." echo @@ -2400,12 +2455,6 @@ dbImportStreamCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/bin/dbQueryAllDatabases b/bin/dbQueryAllDatabases index fd019ddf..1741e4f6 100755 --- a/bin/dbQueryAllDatabases +++ b/bin/dbQueryAllDatabases @@ -338,18 +338,79 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + # @description loads ~/.bash-tools/.env if available # if not creates it from a default template # else check if new options need to be added BashTools::Conf::requireLoad() { -Linux::requireTarCommand -Compiler::Embed::extractFileFromBase64 \ - "${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" \ - "IyEvdXNyL2Jpbi9lbnYgYmFzaAojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKCiMgRGVmYXVsdCBzZXR0aW5ncwojIHlvdSBjYW4gb3ZlcnJpZGUgdGhlc2Ugc2V0dGluZ3MgYnkgY3JlYXRpbmcgJHtIT01FfS8uYmFzaC10b29scy8uZW52IGZpbGUKCiMjIwojIyMgRElTUExBWSBMZXZlbAojIyMgbWluaW11bSBsZXZlbCBvZiB0aGUgbWVzc2FnZXMgdGhhdCB3aWxsIGJlIGRpc3BsYXllZCBvbiBzY3JlZW4KIyMjCiMjIyAwOiBOTyBMT0cKIyMjIDE6IEVSUk9SCiMjIyAyOiBXQVJOSU5HCiMjIyAzOiBJTkZPCiMjIyA0OiBERUJVRwojIyMKQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTD0ke0JBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUw6LTN9CgojIyMKIyMjIERJU1BMQVkgZHVyYXRpb24KIyMjIDA6IG5vIGR1cmF0aW9uIGlzIGRpc3BsYXllZCBvbiB0aGUgbWVzc2FnZXMKIyMjIDE6IGR1cmF0aW9uIGJldHdlZW4gcHJldmlvdXMgbWVzc2FnZSBhbmQgY3VycmVudCBpcyBkaXNwbGF5ZWQKIyMjIHdpdGggdGhlIG1lc3NhZ2UKIyMjCkRJU1BMQVlfRFVSQVRJT049JHtESVNQTEFZX0RVUkFUSU9OOjB9CgojIyMKIyMjIExvZyB0byBmaWxlCiMjIwojIyMgYWxsIGxvZyBtZXNzYWdlcyB3aWxsIGJlIHJlZGlyZWN0ZWQgdG8gbG9nIGZpbGUgc3BlY2lmaWVkCiMjIyB0aGlzIHNhbWUgcGF0aCB3aWxsIGJlIHVzZWQgaW5zaWRlIGFuZCBvdXRzaWRlIG9mIHRoZSBjb250YWluZXIKIyMjCkJBU0hfRlJBTUVXT1JLX0xPR19GSUxFPSR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEU6LSR7RlJBTUVXT1JLX1JPT1RfRElSfS9sb2dzL2Jhc2gubG9nfQoKIyMjCiMjIyBMT0cgTGV2ZWwKIyMjIG1pbmltdW0gbGV2ZWwgb2YgdGhlIG1lc3NhZ2VzIHRoYXQgd2lsbCBiZSBsb2dnZWQgaW50byBMT0dfRklMRQojIyMKIyMjIDA6IE5PIExPRwojIyMgMTogRVJST1IKIyMjIDI6IFdBUk5JTkcKIyMjIDM6IElORk8KIyMjIDQ6IERFQlVHCiMjIwpCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw6LTB9CgojIGFic29sdXRlIGRpcmVjdG9yeSBjb250YWluaW5nIGRiIGltcG9ydCBzcWwgZHVtcHMKREJfSU1QT1JUX0RVTVBfRElSPSR7REJfSU1QT1JUX0RVTVBfRElSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2RiSW1wb3J0RHVtcHN9CgojIGdhcmJhZ2UgY29sbGVjdCBhbGwgZmlsZXMgZm9yIHdoaWNoIG1vZGlmaWNhdGlvbiBpcyBncmVhdGVyIHRoYW4gZWc6IDMwIGRheXMgKCszMCkKIyBlYWNoIHRpbWUgYW4gZXhpc3RpbmcgZmlsZSBpcyB1c2VkIGJ5IGRiSW1wb3J0L2RiSW1wb3J0VGFibGUKIyB0aGUgZmlsZSBtb2RpZmljYXRpb24gdGltZSBpcyBzZXQgdG8gbm93CkRCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUz0ke0RCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUzotKzMwfQoKIyBhYnNvbHV0ZSBkaXJlY3RvcnkgY29udGFpbmluZyBkYlNjcmlwdHMgdXNlZCBieSBkYlNjcmlwdEFsbERhdGFiYXNlcwpTQ1JJUFRTX0ZPTERFUj0ke1NDUklQVFNfRk9MREVSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2NvbmYvZGJTY3JpcHRzfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEFXUyBQYXJhbWV0ZXJzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KUzNfQkFTRV9VUkw9JHtTM19CQVNFX1VSTDotfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFBvc3RtYW4gUGFyYW1ldGVycwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tClBPU1RNQU5fQVBJX0tFWT0K" \ - "755" - -declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" - BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" @@ -377,7 +438,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ( echo "#!/usr/bin/env bash" # shellcheck disable=SC2154 - echo "${embed_file_bashToolsDefaultConfigTemplate}" + echo "${bashToolsDefaultConfigTemplate}" ) >"${envFile}" Log::displayInfo "Configuration file '${envFile}' created" else @@ -390,7 +451,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ) >>"${envFile}" fi fi - # shellcheck source=/conf/.env + # shellcheck source=/conf/defaultEnv/.env source "${envFile}" || { Log::displayError "impossible to load '${envFile}'" exit 1 @@ -1388,6 +1449,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -1431,16 +1493,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1615,9 +1667,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1633,13 +1682,17 @@ commandOptionParseFinished() { -beforeParseCallback() { +defaultBeforeParseCallback() { BashTools::Conf::requireLoad Env::requireLoad UI::requireTheme Log::requireLoad } +beforeParseCallback() { + defaultBeforeParseCallback +} + declare -a PARALLEL_OPTIONS @@ -1661,6 +1714,24 @@ optionJobsCallback() { +fromDsnOptionLongDescription() { + local dsnList="" + dsnList="$(Conf::getMergedList "dsn" "env" " - ")" + + echo -e " ${__HELP_TITLE}Data Source Name (DSN)${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default dsn directory:${__HELP_NORMAL}" + echo -e " ${BASH_TOOLS_ROOT_DIR}/conf/dsn" + echo + echo -e " ${__HELP_TITLE}User dsn directory:${__HELP_NORMAL}" + echo -e " ${HOME}/.bash-tools/dsn" + echo -e ' Allows to override dsn defined in "Default dsn directory"' + echo + echo -e " ${__HELP_TITLE}List of available dsn:${__HELP_NORMAL}" + echo -e "${dsnList}" +} + + + optionVersionCallback() { # shellcheck disable=SC2154 echo "${SCRIPT_NAME} version 3.0" @@ -1681,10 +1752,7 @@ declare copyrightBeginYear="2020" declare defaultFromDsn="default.remote" beforeParseCallback() { - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad + defaultBeforeParseCallback Linux::requireExecutedAsUser Linux::requireRealpathCommand } @@ -1716,32 +1784,31 @@ optionSeparatorCallback() { longDescriptionFunction() { local example1=$'dbQueryAllDatabases databaseSize -j 12 --separator "|" --bar 2>/dev/null | column -s "|" -t -n -c 40' - local dsnList queriesList - dsnList="$(Conf::getMergedList "dsn" "env" " - ")" - queriesList="$(Conf::getMergedList "dbQueries" "sql" " - " || true)" + local queriesList + queriesList="$(Conf::getMergedList "dbQueries" "sql" " - " || true)" - echo -e "${__HELP_TITLE} LIST OF AVAILABLE DSN:${__HELP_NORMAL}" - echo -e "${dsnList}" + fromDsnOptionLongDescription echo - echo -e "${__HELP_TITLE} DEFAULT QUERIES DIRECTORY:${__HELP_NORMAL}" - echo -e " ${QUERIES_DIR-configuration error}" + echo -e " ${__HELP_TITLE}QUERIES${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default queries directory:${__HELP_NORMAL}" + echo -e " ${QUERIES_DIR-configuration error}" echo - echo -e "${__HELP_TITLE} USER QUERIES DIRECTORY:${__HELP_NORMAL}" - echo -e " ${HOME_QUERIES_DIR-configuration error}" - echo -e " Allows to override queries defined in 'Default queries directory'" + echo -e " ${__HELP_TITLE}User queries directory:${__HELP_NORMAL}" + echo -e " ${HOME_QUERIES_DIR-configuration error}" + echo -e " Allows to override queries defined in 'Default queries directory'" echo - echo -e "${__HELP_TITLE} LIST OF AVAILABLE QUERIES:${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}List of available queries:${__HELP_NORMAL}" echo -e "${queriesList}" echo - echo -e "${__HELP_TITLE} EXAMPLES:${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}EXAMPLES:${__HELP_NORMAL}" echo -e " ${__HELP_EXAMPLE}${example1}${__HELP_NORMAL}" } argQueryHelpFunction() { Array::wrap2 " " 80 6 \ - " Query to execute" "\n" \ - "- , try to execute the mysql query provided by the file" "\n" \ - '- , search for query file in queries directory (see below)' "\n" \ + " Query to execute" "\r" \ + "- , try to execute the mysql query provided by the file" "\r" \ + '- , search for query file in queries directory (see below)' "\r" \ '- else the argument is interpreted as query string' } @@ -1788,7 +1855,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1830,7 +1896,6 @@ dbQueryAllDatabasesCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1867,7 +1932,7 @@ dbQueryAllDatabasesCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/18 + # Option 1/17 # optionJobs alts --jobs|-j # type: String min 0 max 1 --jobs | -j) @@ -1888,7 +1953,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 2/18 + # Option 2/17 # optionProgressBar alts --bar|-b # type: Boolean min 0 max 1 --bar | -b) @@ -1904,7 +1969,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 3/18 + # Option 3/17 # optionFromDsn alts --from-dsn|-f # type: String min 0 max 1 --from-dsn | -f) @@ -1923,7 +1988,7 @@ dbQueryAllDatabasesCommandParse() { optionFromDsn="$1" ;; - # Option 4/18 + # Option 4/17 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1939,7 +2004,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 5/18 + # Option 5/17 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1953,7 +2018,7 @@ dbQueryAllDatabasesCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 6/18 + # Option 6/17 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1974,7 +2039,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 7/18 + # Option 7/17 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1992,7 +2057,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 8/18 + # Option 8/17 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -2010,7 +2075,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 9/18 + # Option 9/17 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -2028,25 +2093,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 10/18 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 11/18 + # Option 10/17 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -2074,7 +2121,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 12/18 + # Option 11/17 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -2097,7 +2144,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 13/18 + # Option 12/17 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -2125,7 +2172,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 14/18 + # Option 13/17 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -2143,7 +2190,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 15/18 + # Option 14/17 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -2171,7 +2218,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 16/18 + # Option 15/17 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -2187,7 +2234,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 17/18 + # Option 16/17 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -2205,7 +2252,7 @@ dbQueryAllDatabasesCommandParse() { ;; - # Option 18/18 + # Option 17/17 # optionSeparator alts --separator|-s # type: String min 0 max 1 --separator | -s) @@ -2295,7 +2342,6 @@ dbQueryAllDatabasesCommandParse() { - if ((options_parse_argParsedCountArgQuery < 1 )); then Log::displayError "Command ${SCRIPT_NAME} - Argument 'argQuery' should be provided at least 1 time(s)" return 1 @@ -2310,7 +2356,7 @@ dbQueryAllDatabasesCommandParse() { # @description display command options and arguments help for dbQueryAllDatabasesCommand dbQueryAllDatabasesCommandHelp() { echo -e "${__HELP_TITLE_COLOR}SYNOPSIS:${__RESET_COLOR}" - Array::wrap2 ' ' 76 4 " " "Execute a query on multiple databases to generate a tsv format report.\\n The query can be parallelized on multiple databases." + Array::wrap2 ' ' 76 4 " " "Execute a query on multiple databases to generate a tsv format report." "The query can be parallelized on multiple databases." echo echo @@ -2323,7 +2369,7 @@ dbQueryAllDatabasesCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--jobs|-j ]" "[--bar|-b]" "[--from-dsn|-f ]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--separator|-s ]" + optionsAltList=("[--jobs|-j ]" "[--bar|-b]" "[--from-dsn|-f ]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--separator|-s ]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "dbQueryAllDatabases" "${optionsAltList[@]}" @@ -2353,7 +2399,7 @@ dbQueryAllDatabasesCommandHelp() { echo echo -e " ${__HELP_OPTION_COLOR}--bar${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-b${__HELP_NORMAL} {single}" - Array::wrap2 ' ' 76 4 " " "Show progress as a progress bar. In the bar is shown: % of jobs completed," "estimated seconds left, and number of jobs started." "" + Array::wrap2 ' ' 76 4 " " "Show progress as a progress bar. In the bar is shown: % of jobs" "completed, estimated seconds left, and number of jobs started." echo @@ -2402,12 +2448,6 @@ dbQueryAllDatabasesCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/bin/dbScriptAllDatabases b/bin/dbScriptAllDatabases index 4b34f5a7..23416349 100755 --- a/bin/dbScriptAllDatabases +++ b/bin/dbScriptAllDatabases @@ -338,18 +338,79 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + # @description loads ~/.bash-tools/.env if available # if not creates it from a default template # else check if new options need to be added BashTools::Conf::requireLoad() { -Linux::requireTarCommand -Compiler::Embed::extractFileFromBase64 \ - "${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" \ - "IyEvdXNyL2Jpbi9lbnYgYmFzaAojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKCiMgRGVmYXVsdCBzZXR0aW5ncwojIHlvdSBjYW4gb3ZlcnJpZGUgdGhlc2Ugc2V0dGluZ3MgYnkgY3JlYXRpbmcgJHtIT01FfS8uYmFzaC10b29scy8uZW52IGZpbGUKCiMjIwojIyMgRElTUExBWSBMZXZlbAojIyMgbWluaW11bSBsZXZlbCBvZiB0aGUgbWVzc2FnZXMgdGhhdCB3aWxsIGJlIGRpc3BsYXllZCBvbiBzY3JlZW4KIyMjCiMjIyAwOiBOTyBMT0cKIyMjIDE6IEVSUk9SCiMjIyAyOiBXQVJOSU5HCiMjIyAzOiBJTkZPCiMjIyA0OiBERUJVRwojIyMKQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTD0ke0JBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUw6LTN9CgojIyMKIyMjIERJU1BMQVkgZHVyYXRpb24KIyMjIDA6IG5vIGR1cmF0aW9uIGlzIGRpc3BsYXllZCBvbiB0aGUgbWVzc2FnZXMKIyMjIDE6IGR1cmF0aW9uIGJldHdlZW4gcHJldmlvdXMgbWVzc2FnZSBhbmQgY3VycmVudCBpcyBkaXNwbGF5ZWQKIyMjIHdpdGggdGhlIG1lc3NhZ2UKIyMjCkRJU1BMQVlfRFVSQVRJT049JHtESVNQTEFZX0RVUkFUSU9OOjB9CgojIyMKIyMjIExvZyB0byBmaWxlCiMjIwojIyMgYWxsIGxvZyBtZXNzYWdlcyB3aWxsIGJlIHJlZGlyZWN0ZWQgdG8gbG9nIGZpbGUgc3BlY2lmaWVkCiMjIyB0aGlzIHNhbWUgcGF0aCB3aWxsIGJlIHVzZWQgaW5zaWRlIGFuZCBvdXRzaWRlIG9mIHRoZSBjb250YWluZXIKIyMjCkJBU0hfRlJBTUVXT1JLX0xPR19GSUxFPSR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEU6LSR7RlJBTUVXT1JLX1JPT1RfRElSfS9sb2dzL2Jhc2gubG9nfQoKIyMjCiMjIyBMT0cgTGV2ZWwKIyMjIG1pbmltdW0gbGV2ZWwgb2YgdGhlIG1lc3NhZ2VzIHRoYXQgd2lsbCBiZSBsb2dnZWQgaW50byBMT0dfRklMRQojIyMKIyMjIDA6IE5PIExPRwojIyMgMTogRVJST1IKIyMjIDI6IFdBUk5JTkcKIyMjIDM6IElORk8KIyMjIDQ6IERFQlVHCiMjIwpCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw6LTB9CgojIGFic29sdXRlIGRpcmVjdG9yeSBjb250YWluaW5nIGRiIGltcG9ydCBzcWwgZHVtcHMKREJfSU1QT1JUX0RVTVBfRElSPSR7REJfSU1QT1JUX0RVTVBfRElSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2RiSW1wb3J0RHVtcHN9CgojIGdhcmJhZ2UgY29sbGVjdCBhbGwgZmlsZXMgZm9yIHdoaWNoIG1vZGlmaWNhdGlvbiBpcyBncmVhdGVyIHRoYW4gZWc6IDMwIGRheXMgKCszMCkKIyBlYWNoIHRpbWUgYW4gZXhpc3RpbmcgZmlsZSBpcyB1c2VkIGJ5IGRiSW1wb3J0L2RiSW1wb3J0VGFibGUKIyB0aGUgZmlsZSBtb2RpZmljYXRpb24gdGltZSBpcyBzZXQgdG8gbm93CkRCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUz0ke0RCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUzotKzMwfQoKIyBhYnNvbHV0ZSBkaXJlY3RvcnkgY29udGFpbmluZyBkYlNjcmlwdHMgdXNlZCBieSBkYlNjcmlwdEFsbERhdGFiYXNlcwpTQ1JJUFRTX0ZPTERFUj0ke1NDUklQVFNfRk9MREVSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2NvbmYvZGJTY3JpcHRzfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEFXUyBQYXJhbWV0ZXJzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KUzNfQkFTRV9VUkw9JHtTM19CQVNFX1VSTDotfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFBvc3RtYW4gUGFyYW1ldGVycwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tClBPU1RNQU5fQVBJX0tFWT0K" \ - "755" - -declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" - BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" @@ -377,7 +438,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ( echo "#!/usr/bin/env bash" # shellcheck disable=SC2154 - echo "${embed_file_bashToolsDefaultConfigTemplate}" + echo "${bashToolsDefaultConfigTemplate}" ) >"${envFile}" Log::displayInfo "Configuration file '${envFile}' created" else @@ -390,7 +451,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ) >>"${envFile}" fi fi - # shellcheck source=/conf/.env + # shellcheck source=/conf/defaultEnv/.env source "${envFile}" || { Log::displayError "impossible to load '${envFile}'" exit 1 @@ -398,36 +459,6 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp } -# @description convert base64 encoded back to target file -# if target file is executable prepend dir of target -# file to PATH to make binary available everywhere -# it is advised to include in the path of the target file -# the md5sum of the binFile -# -# @arg $1 targetFile:String the file to write -# @arg $2 binFileBase64:String the base64 encoded file -# @arg $3 fileMode:String the chmod to set on the file -# @set PATH String prepend target embedded file binary directory to PATH variable if binary executable -Compiler::Embed::extractFileFromBase64() { - local targetFile="$1" - local binFileBase64="$2" - local fileMode="${3:-+x}" - local targetDir="${targetFile%/*}" - - if [[ ! -f "${targetFile}" ]]; then - if [[ ! -d "${targetDir}" ]]; then - mkdir -p "${targetDir}" - fi - base64 -d >"${targetFile}" <<<"${binFileBase64}" - chmod "${fileMode}" "${targetFile}" - fi - - if [[ -x "${targetFile}" ]]; then - Env::pathPrepend "${targetDir}" - fi -} - - # @description get absolute conf file from specified conf folder deduced using these rules # * from absolute file (ignores and ) # * relative to where script is executed (ignores and ) @@ -759,19 +790,6 @@ Db::checkRequirements() { } -# @description prepend directories to the PATH environment variable -# @arg $@ args:String[] list of directories to prepend -# @set PATH update PATH with the directories prepended -Env::pathPrepend() { - local arg - for arg in "$@"; do - if [[ -d "${arg}" && ":${PATH}:" != *":${arg}:"* ]]; then - PATH="$(realpath "${arg}"):${PATH}" - fi - done -} - - # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -854,14 +872,6 @@ Linux::requireRealpathCommand() { } -# @description ensure command tar is available -# @exitcode 1 if tar command not available -# @stderr diagnostics information is displayed -Linux::requireTarCommand() { - Assert::commandExists tar -} - - declare -g FIRST_LOG_DATE LOG_LAST_LOG_DATE LOG_LAST_LOG_DATE_INIT LOG_LAST_DURATION_STR FIRST_LOG_DATE="${EPOCHREALTIME/[^0-9]/}" LOG_LAST_LOG_DATE="${FIRST_LOG_DATE}" @@ -1341,6 +1351,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -1384,16 +1395,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1568,9 +1569,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1586,13 +1584,17 @@ commandOptionParseFinished() { -beforeParseCallback() { +defaultBeforeParseCallback() { BashTools::Conf::requireLoad Env::requireLoad UI::requireTheme Log::requireLoad } +beforeParseCallback() { + defaultBeforeParseCallback +} + declare SCRIPTS_DIR @@ -1603,14 +1605,10 @@ declare defaultFromDsn="default.remote" declare outputDirectory="${HOME}/.bash-tools/output" beforeParseCallback() { + defaultBeforeParseCallback Assert::commandExists mysql "sudo apt-get install -y mysql-client" Assert::commandExists mysqlshow "sudo apt-get install -y mysql-client" Assert::commandExists parallel "sudo apt-get install -y parallel" - - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad Linux::requireExecutedAsUser Linux::requireRealpathCommand } @@ -1628,37 +1626,36 @@ optionHelpCallback() { } longDescriptionFunction() { - local dsnList scriptsList - dsnList="$(Conf::getMergedList "dsn" "env")" - scriptsList="$(Conf::getMergedList "dbScripts" "sh")" + local scriptsList + scriptsList="$(Conf::getMergedList "dbScripts" "sh" " - " || true)" - echo -e "${__HELP_TITLE}NOTE:${__HELP_NORMAL}" - echo -e "the use of output, log-format, verbose options highly depends on the script used" - echo - echo -e "${__HELP_TITLE}LIST OF AVAILABLE DSN:${__HELP_NORMAL}" - echo -e "${dsnList}" + fromDsnOptionLongDescription echo - echo -e "${__HELP_TITLE}DEFAULT SCRIPTS DIRECTORY:${__HELP_NORMAL}" - echo -e "${SCRIPTS_DIR-configuration error}" + echo -e " ${__HELP_TITLE}SCRIPTS${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default scripts directory:${__HELP_NORMAL}" + echo -e " ${SCRIPTS_DIR-configuration error}" echo - echo -e "${__HELP_TITLE}USER SCRIPTS DIRECTORY:${__HELP_NORMAL}" - echo -e "${HOME_SCRIPTS_DIR-configuration error}" - echo -e "Allows to override queries defined in 'Default scripts directory'" + echo -e " ${__HELP_TITLE}User scripts directory:${__HELP_NORMAL}" + echo -e " ${HOME_SCRIPTS_DIR-configuration error}" + echo -e " Allows to override queries defined in 'Default scripts directory'" echo - echo -e "${__HELP_TITLE}LIST OF AVAILABLE SCRIPTS:${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}List of available scripts:${__HELP_NORMAL}" echo -e "${scriptsList}" echo - echo -e "${__HELP_TITLE}EXAMPLES:${__HELP_NORMAL} script conf/dbScripts/extractData.sh" - echo -e " executes query databaseSize (see conf/dbQueries/databaseSize.sql) on each db and log the result in log file in default output dir, call it using" + echo -e " ${__HELP_TITLE}NOTE:${__HELP_NORMAL}" + echo -e " the use of output, log-format, verbose options highly depends on the script used" + echo + echo -e " ${__HELP_TITLE}EXAMPLES:${__HELP_NORMAL} script conf/dbScripts/extractData.sh" + echo -e " 1. executes query databaseSize (see conf/dbQueries/databaseSize.sql) on each db and log the result in log file in default output dir, call it using" echo -e " ${__HELP_EXAMPLE}$0 -j 10 extractData databaseSize${__HELP_NORMAL}" echo - echo -e " executes query databaseSize on each db and display the result on stdout (2>/dev/null hides information messages)" + echo -e " 2. executes query databaseSize on each db and display the result on stdout (2>/dev/null hides information messages)" echo -e " ${__HELP_EXAMPLE}$0 -j 10 --log-format none extractData databaseSize${__HELP_NORMAL}" echo - echo -e " use --verbose to get some debug information" + echo -e " 3. use --verbose to get some debug information" echo -e " ${__HELP_EXAMPLE}$0 -j 10 --log-format none --verbose extractData databaseSize${__HELP_NORMAL}" echo - echo -e "${__HELP_TITLE}USE CASES:${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}USE CASES:${__HELP_NORMAL}" echo -e " you can use this script in order to check that each db model conforms with your ORM schema" echo -e " simply create a new script in conf/dbQueries that will call your orm schema checker" echo @@ -1716,6 +1713,24 @@ optionJobsCallback() { +fromDsnOptionLongDescription() { + local dsnList="" + dsnList="$(Conf::getMergedList "dsn" "env" " - ")" + + echo -e " ${__HELP_TITLE}Data Source Name (DSN)${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default dsn directory:${__HELP_NORMAL}" + echo -e " ${BASH_TOOLS_ROOT_DIR}/conf/dsn" + echo + echo -e " ${__HELP_TITLE}User dsn directory:${__HELP_NORMAL}" + echo -e " ${HOME}/.bash-tools/dsn" + echo -e ' Allows to override dsn defined in "Default dsn directory"' + echo + echo -e " ${__HELP_TITLE}List of available dsn:${__HELP_NORMAL}" + echo -e "${dsnList}" +} + + + optionVersionCallback() { # shellcheck disable=SC2154 echo "${SCRIPT_NAME} version 3.0" @@ -1738,7 +1753,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1783,7 +1797,6 @@ dbScriptAllDatabasesCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1827,7 +1840,7 @@ dbScriptAllDatabasesCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/20 + # Option 1/19 # optionJobs alts --jobs|-j # type: String min 0 max 1 --jobs | -j) @@ -1848,7 +1861,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 2/20 + # Option 2/19 # optionProgressBar alts --bar|-b # type: Boolean min 0 max 1 --bar | -b) @@ -1864,7 +1877,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 3/20 + # Option 3/19 # optionFromDsn alts --from-dsn|-f # type: String min 0 max 1 --from-dsn | -f) @@ -1883,7 +1896,7 @@ dbScriptAllDatabasesCommandParse() { optionFromDsn="$1" ;; - # Option 4/20 + # Option 4/19 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1899,7 +1912,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 5/20 + # Option 5/19 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1913,7 +1926,7 @@ dbScriptAllDatabasesCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 6/20 + # Option 6/19 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1934,7 +1947,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 7/20 + # Option 7/19 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1952,7 +1965,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 8/20 + # Option 8/19 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1970,7 +1983,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 9/20 + # Option 9/19 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1988,25 +2001,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 10/20 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 11/20 + # Option 10/19 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -2034,7 +2029,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 12/20 + # Option 11/19 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -2057,7 +2052,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 13/20 + # Option 12/19 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -2085,7 +2080,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 14/20 + # Option 13/19 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -2103,7 +2098,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 15/20 + # Option 14/19 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -2131,7 +2126,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 16/20 + # Option 15/19 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -2147,7 +2142,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 17/20 + # Option 16/19 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -2165,7 +2160,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 18/20 + # Option 17/19 # optionDatabases alts --database # type: StringArray min 0 max 1 --database) @@ -2183,7 +2178,7 @@ dbScriptAllDatabasesCommandParse() { optionDatabases+=("$1") ;; - # Option 19/20 + # Option 18/19 # optionOutputDir alts --output|-o # type: String min 0 max 1 --output | -o) @@ -2204,7 +2199,7 @@ dbScriptAllDatabasesCommandParse() { ;; - # Option 20/20 + # Option 19/19 # optionLogFormat alts --log-format|-l # type: String min 0 max 1 # authorizedValues: none|log @@ -2310,7 +2305,6 @@ dbScriptAllDatabasesCommandParse() { - if ((options_parse_argParsedCountArgScriptToExecute < 1 )); then Log::displayError "Command ${SCRIPT_NAME} - Argument 'scriptToExecute' should be provided at least 1 time(s)" return 1 @@ -2338,7 +2332,7 @@ dbScriptAllDatabasesCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--jobs|-j ]" "[--bar|-b]" "[--from-dsn|-f ]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--database ]" "[--output|-o ]" "[--log-format|-l ]" + optionsAltList=("[--jobs|-j ]" "[--bar|-b]" "[--from-dsn|-f ]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--database ]" "[--output|-o ]" "[--log-format|-l ]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "dbScriptAllDatabases" "${optionsAltList[@]}" @@ -2372,7 +2366,7 @@ dbScriptAllDatabasesCommandHelp() { echo echo -e " ${__HELP_OPTION_COLOR}--bar${__HELP_NORMAL}, ${__HELP_OPTION_COLOR}-b${__HELP_NORMAL} {single}" - Array::wrap2 ' ' 76 4 " " "Show progress as a progress bar. In the bar is shown: % of jobs completed," "estimated seconds left, and number of jobs started." "" + Array::wrap2 ' ' 76 4 " " "Show progress as a progress bar. In the bar is shown: % of jobs" "completed, estimated seconds left, and number of jobs started." echo @@ -2421,12 +2415,6 @@ dbScriptAllDatabasesCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo @@ -2476,7 +2464,7 @@ dbScriptAllDatabasesCommandHelp() { echo echo -e "${__HELP_TITLE_COLOR}SCRIPTS OPTIONS:${__RESET_COLOR}" echo -e " ${__HELP_OPTION_COLOR}--database ${__HELP_NORMAL} {single}" - Array::wrap2 ' ' 76 4 " " "If provided will check only this db, otherwise script will be executed on all dbs of mysql server." + Array::wrap2 ' ' 76 4 " " "If provided will check only this db," "otherwise script will be executed on all dbs of mysql server." echo diff --git a/bin/doc b/bin/doc index 7f13186c..7129dfb5 100755 --- a/bin/doc +++ b/bin/doc @@ -307,6 +307,127 @@ Assert::tty() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" + if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then + FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" + else + # if the directory does not exist yet, give a value to FRAMEWORK_ROOT_DIR + FRAMEWORK_ROOT_DIR="${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" + fi + # shellcheck disable=SC2034 + FRAMEWORK_SRC_DIR="${FRAMEWORK_ROOT_DIR}/src" + # shellcheck disable=SC2034 + FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" + + if [[ -f "${HOME}/.bash-tools/.env" ]]; then + # shellcheck disable=SC2034 + BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") + fi + + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + # shellcheck disable=SC2154 + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/defaultEnv/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + + # @description get file content if file not expired # @arg $1 file:String the file to get content from # @arg $2 maxDuration:int number of seconds after which the file is considered expired @@ -1106,6 +1227,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2022-now François Chastanet" } @@ -1149,16 +1271,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1333,9 +1445,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1351,12 +1460,15 @@ commandOptionParseFinished() { -# shellcheck disable=SC2034 -declare optionContinuousIntegrationMode=0 +defaultBeforeParseCallback() { + BashTools::Conf::requireLoad + Env::requireLoad + UI::requireTheme + Log::requireLoad +} -# shellcheck disable=SC2317 # if function is overridden -updateOptionContinuousIntegrationMode() { - BASH_FRAMEWORK_ARGV_FILTERED+=("$1") +beforeParseCallback() { + defaultBeforeParseCallback } @@ -1382,7 +1494,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1416,7 +1527,6 @@ docCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1446,7 +1556,7 @@ docCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/15 + # Option 1/14 # optionContinuousIntegrationMode alts --ci # type: Boolean min 0 max 1 --ci) @@ -1462,7 +1572,7 @@ docCommandParse() { ;; - # Option 2/15 + # Option 2/14 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1478,7 +1588,7 @@ docCommandParse() { ;; - # Option 3/15 + # Option 3/14 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1492,7 +1602,7 @@ docCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 4/15 + # Option 4/14 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1513,7 +1623,7 @@ docCommandParse() { ;; - # Option 5/15 + # Option 5/14 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1531,7 +1641,7 @@ docCommandParse() { ;; - # Option 6/15 + # Option 6/14 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1549,7 +1659,7 @@ docCommandParse() { ;; - # Option 7/15 + # Option 7/14 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1567,25 +1677,7 @@ docCommandParse() { ;; - # Option 8/15 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 9/15 + # Option 8/14 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1613,7 +1705,7 @@ docCommandParse() { ;; - # Option 10/15 + # Option 9/14 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1636,7 +1728,7 @@ docCommandParse() { ;; - # Option 11/15 + # Option 10/14 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1664,7 +1756,7 @@ docCommandParse() { ;; - # Option 12/15 + # Option 11/14 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -1682,7 +1774,7 @@ docCommandParse() { ;; - # Option 13/15 + # Option 12/14 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -1710,7 +1802,7 @@ docCommandParse() { ;; - # Option 14/15 + # Option 13/14 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -1726,7 +1818,7 @@ docCommandParse() { ;; - # Option 15/15 + # Option 14/14 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -1785,7 +1877,7 @@ docCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--ci]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" + optionsAltList=("[--ci]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "doc" "${optionsAltList[@]}" @@ -1839,12 +1931,6 @@ docCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/bin/gitIsAncestorOf b/bin/gitIsAncestorOf index b5abf0e9..c337d386 100755 --- a/bin/gitIsAncestorOf +++ b/bin/gitIsAncestorOf @@ -338,18 +338,79 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + # @description loads ~/.bash-tools/.env if available # if not creates it from a default template # else check if new options need to be added BashTools::Conf::requireLoad() { -Linux::requireTarCommand -Compiler::Embed::extractFileFromBase64 \ - "${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" \ - "IyEvdXNyL2Jpbi9lbnYgYmFzaAojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKCiMgRGVmYXVsdCBzZXR0aW5ncwojIHlvdSBjYW4gb3ZlcnJpZGUgdGhlc2Ugc2V0dGluZ3MgYnkgY3JlYXRpbmcgJHtIT01FfS8uYmFzaC10b29scy8uZW52IGZpbGUKCiMjIwojIyMgRElTUExBWSBMZXZlbAojIyMgbWluaW11bSBsZXZlbCBvZiB0aGUgbWVzc2FnZXMgdGhhdCB3aWxsIGJlIGRpc3BsYXllZCBvbiBzY3JlZW4KIyMjCiMjIyAwOiBOTyBMT0cKIyMjIDE6IEVSUk9SCiMjIyAyOiBXQVJOSU5HCiMjIyAzOiBJTkZPCiMjIyA0OiBERUJVRwojIyMKQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTD0ke0JBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUw6LTN9CgojIyMKIyMjIERJU1BMQVkgZHVyYXRpb24KIyMjIDA6IG5vIGR1cmF0aW9uIGlzIGRpc3BsYXllZCBvbiB0aGUgbWVzc2FnZXMKIyMjIDE6IGR1cmF0aW9uIGJldHdlZW4gcHJldmlvdXMgbWVzc2FnZSBhbmQgY3VycmVudCBpcyBkaXNwbGF5ZWQKIyMjIHdpdGggdGhlIG1lc3NhZ2UKIyMjCkRJU1BMQVlfRFVSQVRJT049JHtESVNQTEFZX0RVUkFUSU9OOjB9CgojIyMKIyMjIExvZyB0byBmaWxlCiMjIwojIyMgYWxsIGxvZyBtZXNzYWdlcyB3aWxsIGJlIHJlZGlyZWN0ZWQgdG8gbG9nIGZpbGUgc3BlY2lmaWVkCiMjIyB0aGlzIHNhbWUgcGF0aCB3aWxsIGJlIHVzZWQgaW5zaWRlIGFuZCBvdXRzaWRlIG9mIHRoZSBjb250YWluZXIKIyMjCkJBU0hfRlJBTUVXT1JLX0xPR19GSUxFPSR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEU6LSR7RlJBTUVXT1JLX1JPT1RfRElSfS9sb2dzL2Jhc2gubG9nfQoKIyMjCiMjIyBMT0cgTGV2ZWwKIyMjIG1pbmltdW0gbGV2ZWwgb2YgdGhlIG1lc3NhZ2VzIHRoYXQgd2lsbCBiZSBsb2dnZWQgaW50byBMT0dfRklMRQojIyMKIyMjIDA6IE5PIExPRwojIyMgMTogRVJST1IKIyMjIDI6IFdBUk5JTkcKIyMjIDM6IElORk8KIyMjIDQ6IERFQlVHCiMjIwpCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw6LTB9CgojIGFic29sdXRlIGRpcmVjdG9yeSBjb250YWluaW5nIGRiIGltcG9ydCBzcWwgZHVtcHMKREJfSU1QT1JUX0RVTVBfRElSPSR7REJfSU1QT1JUX0RVTVBfRElSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2RiSW1wb3J0RHVtcHN9CgojIGdhcmJhZ2UgY29sbGVjdCBhbGwgZmlsZXMgZm9yIHdoaWNoIG1vZGlmaWNhdGlvbiBpcyBncmVhdGVyIHRoYW4gZWc6IDMwIGRheXMgKCszMCkKIyBlYWNoIHRpbWUgYW4gZXhpc3RpbmcgZmlsZSBpcyB1c2VkIGJ5IGRiSW1wb3J0L2RiSW1wb3J0VGFibGUKIyB0aGUgZmlsZSBtb2RpZmljYXRpb24gdGltZSBpcyBzZXQgdG8gbm93CkRCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUz0ke0RCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUzotKzMwfQoKIyBhYnNvbHV0ZSBkaXJlY3RvcnkgY29udGFpbmluZyBkYlNjcmlwdHMgdXNlZCBieSBkYlNjcmlwdEFsbERhdGFiYXNlcwpTQ1JJUFRTX0ZPTERFUj0ke1NDUklQVFNfRk9MREVSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2NvbmYvZGJTY3JpcHRzfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEFXUyBQYXJhbWV0ZXJzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KUzNfQkFTRV9VUkw9JHtTM19CQVNFX1VSTDotfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFBvc3RtYW4gUGFyYW1ldGVycwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tClBPU1RNQU5fQVBJX0tFWT0K" \ - "755" - -declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" - BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" @@ -377,7 +438,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ( echo "#!/usr/bin/env bash" # shellcheck disable=SC2154 - echo "${embed_file_bashToolsDefaultConfigTemplate}" + echo "${bashToolsDefaultConfigTemplate}" ) >"${envFile}" Log::displayInfo "Configuration file '${envFile}' created" else @@ -390,7 +451,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ) >>"${envFile}" fi fi - # shellcheck source=/conf/.env + # shellcheck source=/conf/defaultEnv/.env source "${envFile}" || { Log::displayError "impossible to load '${envFile}'" exit 1 @@ -419,36 +480,6 @@ BashTools::runVerboseIfNeeded() { } -# @description convert base64 encoded back to target file -# if target file is executable prepend dir of target -# file to PATH to make binary available everywhere -# it is advised to include in the path of the target file -# the md5sum of the binFile -# -# @arg $1 targetFile:String the file to write -# @arg $2 binFileBase64:String the base64 encoded file -# @arg $3 fileMode:String the chmod to set on the file -# @set PATH String prepend target embedded file binary directory to PATH variable if binary executable -Compiler::Embed::extractFileFromBase64() { - local targetFile="$1" - local binFileBase64="$2" - local fileMode="${3:-+x}" - local targetDir="${targetFile%/*}" - - if [[ ! -f "${targetFile}" ]]; then - if [[ ! -d "${targetDir}" ]]; then - mkdir -p "${targetDir}" - fi - base64 -d >"${targetFile}" <<<"${binFileBase64}" - chmod "${fileMode}" "${targetFile}" - fi - - if [[ -x "${targetFile}" ]]; then - Env::pathPrepend "${targetDir}" - fi -} - - # @description check if all requirements are satisfied # to execute dbImport commands Db::checkRequirements() { @@ -468,19 +499,6 @@ Db::checkRequirements() { } -# @description prepend directories to the PATH environment variable -# @arg $@ args:String[] list of directories to prepend -# @set PATH update PATH with the directories prepended -Env::pathPrepend() { - local arg - for arg in "$@"; do - if [[ -d "${arg}" && ":${PATH}:" != *":${arg}:"* ]]; then - PATH="$(realpath "${arg}"):${PATH}" - fi - done -} - - # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -535,14 +553,6 @@ Linux::requireExecutedAsUser() { } -# @description ensure command tar is available -# @exitcode 1 if tar command not available -# @stderr diagnostics information is displayed -Linux::requireTarCommand() { - Assert::commandExists tar -} - - declare -g FIRST_LOG_DATE LOG_LAST_LOG_DATE LOG_LAST_LOG_DATE_INIT LOG_LAST_DURATION_STR FIRST_LOG_DATE="${EPOCHREALTIME/[^0-9]/}" LOG_LAST_LOG_DATE="${FIRST_LOG_DATE}" @@ -622,19 +632,6 @@ Log::displayInfo() { } -# @description Display message using warning color (yellow) -# @arg $1 message:String the message to display -# @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs -# @env LOG_CONTEXT String allows to contextualize the log -Log::displayWarning() { - if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_WARNING)); then - Log::computeDuration - echo -e "${__WARNING_COLOR}WARN - ${LOG_CONTEXT:-}${LOG_LAST_DURATION_STR:-}${1}${__RESET_COLOR}" >&2 - fi - Log::logWarning "$1" -} - - # @description Display message using error color (red) and exit immediately with error status 1 # @arg $1 message:String the message to display # @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs @@ -718,15 +715,6 @@ Log::logMessage() { } -# @description log message to file -# @arg $1 message:String the message to display -Log::logWarning() { - if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_WARNING)); then - Log::logMessage "${2:-WARNING}" "$1" - fi -} - - # @description activate or not Log::display* and Log::log* functions # based on BASH_FRAMEWORK_DISPLAY_LEVEL and BASH_FRAMEWORK_LOG_LEVEL # environment variables loaded by Env::requireLoad @@ -1022,6 +1010,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -1065,16 +1054,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1249,9 +1228,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1267,14 +1243,24 @@ commandOptionParseFinished() { -beforeParseCallback() { - Linux::requireExecutedAsUser +defaultBeforeParseCallback() { BashTools::Conf::requireLoad Env::requireLoad UI::requireTheme Log::requireLoad } +beforeParseCallback() { + defaultBeforeParseCallback +} + + + +beforeParseCallback() { + defaultBeforeParseCallback + Linux::requireExecutedAsUser +} + declare optionRedirectCmdOutputs="" optionRedirectCmdOutputs() { export optionTraceVerbose @@ -1320,7 +1306,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1353,7 +1338,6 @@ gitIsAncestorOfCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1391,7 +1375,7 @@ gitIsAncestorOfCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/14 + # Option 1/13 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1407,7 +1391,7 @@ gitIsAncestorOfCommandParse() { ;; - # Option 2/14 + # Option 2/13 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1421,7 +1405,7 @@ gitIsAncestorOfCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 3/14 + # Option 3/13 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1442,7 +1426,7 @@ gitIsAncestorOfCommandParse() { ;; - # Option 4/14 + # Option 4/13 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1460,7 +1444,7 @@ gitIsAncestorOfCommandParse() { ;; - # Option 5/14 + # Option 5/13 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1478,7 +1462,7 @@ gitIsAncestorOfCommandParse() { ;; - # Option 6/14 + # Option 6/13 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1496,25 +1480,7 @@ gitIsAncestorOfCommandParse() { ;; - # Option 7/14 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 8/14 + # Option 7/13 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1542,7 +1508,7 @@ gitIsAncestorOfCommandParse() { ;; - # Option 9/14 + # Option 8/13 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1565,7 +1531,7 @@ gitIsAncestorOfCommandParse() { ;; - # Option 10/14 + # Option 9/13 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1593,7 +1559,7 @@ gitIsAncestorOfCommandParse() { ;; - # Option 11/14 + # Option 10/13 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -1611,7 +1577,7 @@ gitIsAncestorOfCommandParse() { ;; - # Option 12/14 + # Option 11/13 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -1639,7 +1605,7 @@ gitIsAncestorOfCommandParse() { ;; - # Option 13/14 + # Option 12/13 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -1655,7 +1621,7 @@ gitIsAncestorOfCommandParse() { ;; - # Option 14/14 + # Option 13/13 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -1750,7 +1716,6 @@ gitIsAncestorOfCommandParse() { - if ((options_parse_argParsedCountClaimedBranchArg < 1 )); then Log::displayError "Command ${SCRIPT_NAME} - Argument 'claimedBranch' should be provided at least 1 time(s)" return 1 @@ -1783,7 +1748,7 @@ gitIsAncestorOfCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" + optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "gitIsAncestorOf" "${optionsAltList[@]}" @@ -1844,12 +1809,6 @@ gitIsAncestorOfCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/bin/gitIsBranch b/bin/gitIsBranch index b9f09656..4ab4d29e 100755 --- a/bin/gitIsBranch +++ b/bin/gitIsBranch @@ -338,18 +338,79 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + # @description loads ~/.bash-tools/.env if available # if not creates it from a default template # else check if new options need to be added BashTools::Conf::requireLoad() { -Linux::requireTarCommand -Compiler::Embed::extractFileFromBase64 \ - "${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" \ - "IyEvdXNyL2Jpbi9lbnYgYmFzaAojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKCiMgRGVmYXVsdCBzZXR0aW5ncwojIHlvdSBjYW4gb3ZlcnJpZGUgdGhlc2Ugc2V0dGluZ3MgYnkgY3JlYXRpbmcgJHtIT01FfS8uYmFzaC10b29scy8uZW52IGZpbGUKCiMjIwojIyMgRElTUExBWSBMZXZlbAojIyMgbWluaW11bSBsZXZlbCBvZiB0aGUgbWVzc2FnZXMgdGhhdCB3aWxsIGJlIGRpc3BsYXllZCBvbiBzY3JlZW4KIyMjCiMjIyAwOiBOTyBMT0cKIyMjIDE6IEVSUk9SCiMjIyAyOiBXQVJOSU5HCiMjIyAzOiBJTkZPCiMjIyA0OiBERUJVRwojIyMKQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTD0ke0JBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUw6LTN9CgojIyMKIyMjIERJU1BMQVkgZHVyYXRpb24KIyMjIDA6IG5vIGR1cmF0aW9uIGlzIGRpc3BsYXllZCBvbiB0aGUgbWVzc2FnZXMKIyMjIDE6IGR1cmF0aW9uIGJldHdlZW4gcHJldmlvdXMgbWVzc2FnZSBhbmQgY3VycmVudCBpcyBkaXNwbGF5ZWQKIyMjIHdpdGggdGhlIG1lc3NhZ2UKIyMjCkRJU1BMQVlfRFVSQVRJT049JHtESVNQTEFZX0RVUkFUSU9OOjB9CgojIyMKIyMjIExvZyB0byBmaWxlCiMjIwojIyMgYWxsIGxvZyBtZXNzYWdlcyB3aWxsIGJlIHJlZGlyZWN0ZWQgdG8gbG9nIGZpbGUgc3BlY2lmaWVkCiMjIyB0aGlzIHNhbWUgcGF0aCB3aWxsIGJlIHVzZWQgaW5zaWRlIGFuZCBvdXRzaWRlIG9mIHRoZSBjb250YWluZXIKIyMjCkJBU0hfRlJBTUVXT1JLX0xPR19GSUxFPSR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEU6LSR7RlJBTUVXT1JLX1JPT1RfRElSfS9sb2dzL2Jhc2gubG9nfQoKIyMjCiMjIyBMT0cgTGV2ZWwKIyMjIG1pbmltdW0gbGV2ZWwgb2YgdGhlIG1lc3NhZ2VzIHRoYXQgd2lsbCBiZSBsb2dnZWQgaW50byBMT0dfRklMRQojIyMKIyMjIDA6IE5PIExPRwojIyMgMTogRVJST1IKIyMjIDI6IFdBUk5JTkcKIyMjIDM6IElORk8KIyMjIDQ6IERFQlVHCiMjIwpCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw6LTB9CgojIGFic29sdXRlIGRpcmVjdG9yeSBjb250YWluaW5nIGRiIGltcG9ydCBzcWwgZHVtcHMKREJfSU1QT1JUX0RVTVBfRElSPSR7REJfSU1QT1JUX0RVTVBfRElSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2RiSW1wb3J0RHVtcHN9CgojIGdhcmJhZ2UgY29sbGVjdCBhbGwgZmlsZXMgZm9yIHdoaWNoIG1vZGlmaWNhdGlvbiBpcyBncmVhdGVyIHRoYW4gZWc6IDMwIGRheXMgKCszMCkKIyBlYWNoIHRpbWUgYW4gZXhpc3RpbmcgZmlsZSBpcyB1c2VkIGJ5IGRiSW1wb3J0L2RiSW1wb3J0VGFibGUKIyB0aGUgZmlsZSBtb2RpZmljYXRpb24gdGltZSBpcyBzZXQgdG8gbm93CkRCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUz0ke0RCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUzotKzMwfQoKIyBhYnNvbHV0ZSBkaXJlY3RvcnkgY29udGFpbmluZyBkYlNjcmlwdHMgdXNlZCBieSBkYlNjcmlwdEFsbERhdGFiYXNlcwpTQ1JJUFRTX0ZPTERFUj0ke1NDUklQVFNfRk9MREVSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2NvbmYvZGJTY3JpcHRzfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEFXUyBQYXJhbWV0ZXJzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KUzNfQkFTRV9VUkw9JHtTM19CQVNFX1VSTDotfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFBvc3RtYW4gUGFyYW1ldGVycwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tClBPU1RNQU5fQVBJX0tFWT0K" \ - "755" - -declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" - BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" @@ -377,7 +438,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ( echo "#!/usr/bin/env bash" # shellcheck disable=SC2154 - echo "${embed_file_bashToolsDefaultConfigTemplate}" + echo "${bashToolsDefaultConfigTemplate}" ) >"${envFile}" Log::displayInfo "Configuration file '${envFile}' created" else @@ -390,7 +451,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ) >>"${envFile}" fi fi - # shellcheck source=/conf/.env + # shellcheck source=/conf/defaultEnv/.env source "${envFile}" || { Log::displayError "impossible to load '${envFile}'" exit 1 @@ -419,36 +480,6 @@ BashTools::runVerboseIfNeeded() { } -# @description convert base64 encoded back to target file -# if target file is executable prepend dir of target -# file to PATH to make binary available everywhere -# it is advised to include in the path of the target file -# the md5sum of the binFile -# -# @arg $1 targetFile:String the file to write -# @arg $2 binFileBase64:String the base64 encoded file -# @arg $3 fileMode:String the chmod to set on the file -# @set PATH String prepend target embedded file binary directory to PATH variable if binary executable -Compiler::Embed::extractFileFromBase64() { - local targetFile="$1" - local binFileBase64="$2" - local fileMode="${3:-+x}" - local targetDir="${targetFile%/*}" - - if [[ ! -f "${targetFile}" ]]; then - if [[ ! -d "${targetDir}" ]]; then - mkdir -p "${targetDir}" - fi - base64 -d >"${targetFile}" <<<"${binFileBase64}" - chmod "${fileMode}" "${targetFile}" - fi - - if [[ -x "${targetFile}" ]]; then - Env::pathPrepend "${targetDir}" - fi -} - - # @description check if all requirements are satisfied # to execute dbImport commands Db::checkRequirements() { @@ -468,19 +499,6 @@ Db::checkRequirements() { } -# @description prepend directories to the PATH environment variable -# @arg $@ args:String[] list of directories to prepend -# @set PATH update PATH with the directories prepended -Env::pathPrepend() { - local arg - for arg in "$@"; do - if [[ -d "${arg}" && ":${PATH}:" != *":${arg}:"* ]]; then - PATH="$(realpath "${arg}"):${PATH}" - fi - done -} - - # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -535,14 +553,6 @@ Linux::requireExecutedAsUser() { } -# @description ensure command tar is available -# @exitcode 1 if tar command not available -# @stderr diagnostics information is displayed -Linux::requireTarCommand() { - Assert::commandExists tar -} - - declare -g FIRST_LOG_DATE LOG_LAST_LOG_DATE LOG_LAST_LOG_DATE_INIT LOG_LAST_DURATION_STR FIRST_LOG_DATE="${EPOCHREALTIME/[^0-9]/}" LOG_LAST_LOG_DATE="${FIRST_LOG_DATE}" @@ -622,19 +632,6 @@ Log::displayInfo() { } -# @description Display message using warning color (yellow) -# @arg $1 message:String the message to display -# @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs -# @env LOG_CONTEXT String allows to contextualize the log -Log::displayWarning() { - if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_WARNING)); then - Log::computeDuration - echo -e "${__WARNING_COLOR}WARN - ${LOG_CONTEXT:-}${LOG_LAST_DURATION_STR:-}${1}${__RESET_COLOR}" >&2 - fi - Log::logWarning "$1" -} - - # @description Display message using error color (red) and exit immediately with error status 1 # @arg $1 message:String the message to display # @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs @@ -718,15 +715,6 @@ Log::logMessage() { } -# @description log message to file -# @arg $1 message:String the message to display -Log::logWarning() { - if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_WARNING)); then - Log::logMessage "${2:-WARNING}" "$1" - fi -} - - # @description activate or not Log::display* and Log::log* functions # based on BASH_FRAMEWORK_DISPLAY_LEVEL and BASH_FRAMEWORK_LOG_LEVEL # environment variables loaded by Env::requireLoad @@ -1022,6 +1010,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -1065,16 +1054,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1249,9 +1228,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1267,14 +1243,24 @@ commandOptionParseFinished() { -beforeParseCallback() { - Linux::requireExecutedAsUser +defaultBeforeParseCallback() { BashTools::Conf::requireLoad Env::requireLoad UI::requireTheme Log::requireLoad } +beforeParseCallback() { + defaultBeforeParseCallback +} + + + +beforeParseCallback() { + defaultBeforeParseCallback + Linux::requireExecutedAsUser +} + declare optionRedirectCmdOutputs="" optionRedirectCmdOutputs() { export optionTraceVerbose @@ -1320,7 +1306,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1352,7 +1337,6 @@ gitIsBranchCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1386,7 +1370,7 @@ gitIsBranchCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/14 + # Option 1/13 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1402,7 +1386,7 @@ gitIsBranchCommandParse() { ;; - # Option 2/14 + # Option 2/13 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1416,7 +1400,7 @@ gitIsBranchCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 3/14 + # Option 3/13 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1437,7 +1421,7 @@ gitIsBranchCommandParse() { ;; - # Option 4/14 + # Option 4/13 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1455,7 +1439,7 @@ gitIsBranchCommandParse() { ;; - # Option 5/14 + # Option 5/13 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1473,7 +1457,7 @@ gitIsBranchCommandParse() { ;; - # Option 6/14 + # Option 6/13 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1491,25 +1475,7 @@ gitIsBranchCommandParse() { ;; - # Option 7/14 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 8/14 + # Option 7/13 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1537,7 +1503,7 @@ gitIsBranchCommandParse() { ;; - # Option 9/14 + # Option 8/13 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1560,7 +1526,7 @@ gitIsBranchCommandParse() { ;; - # Option 10/14 + # Option 9/13 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1588,7 +1554,7 @@ gitIsBranchCommandParse() { ;; - # Option 11/14 + # Option 10/13 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -1606,7 +1572,7 @@ gitIsBranchCommandParse() { ;; - # Option 12/14 + # Option 11/13 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -1634,7 +1600,7 @@ gitIsBranchCommandParse() { ;; - # Option 13/14 + # Option 12/13 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -1650,7 +1616,7 @@ gitIsBranchCommandParse() { ;; - # Option 14/14 + # Option 13/13 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -1729,7 +1695,6 @@ gitIsBranchCommandParse() { - if ((options_parse_argParsedCountBranchNameArg < 1 )); then Log::displayError "Command ${SCRIPT_NAME} - Argument 'branchName' should be provided at least 1 time(s)" return 1 @@ -1757,7 +1722,7 @@ gitIsBranchCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" + optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "gitIsBranch" "${optionsAltList[@]}" @@ -1814,12 +1779,6 @@ gitIsBranchCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/bin/gitRenameBranch b/bin/gitRenameBranch index cac3a882..ef6c4ee7 100755 --- a/bin/gitRenameBranch +++ b/bin/gitRenameBranch @@ -338,18 +338,79 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + # @description loads ~/.bash-tools/.env if available # if not creates it from a default template # else check if new options need to be added BashTools::Conf::requireLoad() { -Linux::requireTarCommand -Compiler::Embed::extractFileFromBase64 \ - "${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" \ - "IyEvdXNyL2Jpbi9lbnYgYmFzaAojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKCiMgRGVmYXVsdCBzZXR0aW5ncwojIHlvdSBjYW4gb3ZlcnJpZGUgdGhlc2Ugc2V0dGluZ3MgYnkgY3JlYXRpbmcgJHtIT01FfS8uYmFzaC10b29scy8uZW52IGZpbGUKCiMjIwojIyMgRElTUExBWSBMZXZlbAojIyMgbWluaW11bSBsZXZlbCBvZiB0aGUgbWVzc2FnZXMgdGhhdCB3aWxsIGJlIGRpc3BsYXllZCBvbiBzY3JlZW4KIyMjCiMjIyAwOiBOTyBMT0cKIyMjIDE6IEVSUk9SCiMjIyAyOiBXQVJOSU5HCiMjIyAzOiBJTkZPCiMjIyA0OiBERUJVRwojIyMKQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTD0ke0JBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUw6LTN9CgojIyMKIyMjIERJU1BMQVkgZHVyYXRpb24KIyMjIDA6IG5vIGR1cmF0aW9uIGlzIGRpc3BsYXllZCBvbiB0aGUgbWVzc2FnZXMKIyMjIDE6IGR1cmF0aW9uIGJldHdlZW4gcHJldmlvdXMgbWVzc2FnZSBhbmQgY3VycmVudCBpcyBkaXNwbGF5ZWQKIyMjIHdpdGggdGhlIG1lc3NhZ2UKIyMjCkRJU1BMQVlfRFVSQVRJT049JHtESVNQTEFZX0RVUkFUSU9OOjB9CgojIyMKIyMjIExvZyB0byBmaWxlCiMjIwojIyMgYWxsIGxvZyBtZXNzYWdlcyB3aWxsIGJlIHJlZGlyZWN0ZWQgdG8gbG9nIGZpbGUgc3BlY2lmaWVkCiMjIyB0aGlzIHNhbWUgcGF0aCB3aWxsIGJlIHVzZWQgaW5zaWRlIGFuZCBvdXRzaWRlIG9mIHRoZSBjb250YWluZXIKIyMjCkJBU0hfRlJBTUVXT1JLX0xPR19GSUxFPSR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEU6LSR7RlJBTUVXT1JLX1JPT1RfRElSfS9sb2dzL2Jhc2gubG9nfQoKIyMjCiMjIyBMT0cgTGV2ZWwKIyMjIG1pbmltdW0gbGV2ZWwgb2YgdGhlIG1lc3NhZ2VzIHRoYXQgd2lsbCBiZSBsb2dnZWQgaW50byBMT0dfRklMRQojIyMKIyMjIDA6IE5PIExPRwojIyMgMTogRVJST1IKIyMjIDI6IFdBUk5JTkcKIyMjIDM6IElORk8KIyMjIDQ6IERFQlVHCiMjIwpCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw6LTB9CgojIGFic29sdXRlIGRpcmVjdG9yeSBjb250YWluaW5nIGRiIGltcG9ydCBzcWwgZHVtcHMKREJfSU1QT1JUX0RVTVBfRElSPSR7REJfSU1QT1JUX0RVTVBfRElSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2RiSW1wb3J0RHVtcHN9CgojIGdhcmJhZ2UgY29sbGVjdCBhbGwgZmlsZXMgZm9yIHdoaWNoIG1vZGlmaWNhdGlvbiBpcyBncmVhdGVyIHRoYW4gZWc6IDMwIGRheXMgKCszMCkKIyBlYWNoIHRpbWUgYW4gZXhpc3RpbmcgZmlsZSBpcyB1c2VkIGJ5IGRiSW1wb3J0L2RiSW1wb3J0VGFibGUKIyB0aGUgZmlsZSBtb2RpZmljYXRpb24gdGltZSBpcyBzZXQgdG8gbm93CkRCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUz0ke0RCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUzotKzMwfQoKIyBhYnNvbHV0ZSBkaXJlY3RvcnkgY29udGFpbmluZyBkYlNjcmlwdHMgdXNlZCBieSBkYlNjcmlwdEFsbERhdGFiYXNlcwpTQ1JJUFRTX0ZPTERFUj0ke1NDUklQVFNfRk9MREVSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2NvbmYvZGJTY3JpcHRzfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEFXUyBQYXJhbWV0ZXJzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KUzNfQkFTRV9VUkw9JHtTM19CQVNFX1VSTDotfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFBvc3RtYW4gUGFyYW1ldGVycwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tClBPU1RNQU5fQVBJX0tFWT0K" \ - "755" - -declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" - BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" @@ -377,7 +438,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ( echo "#!/usr/bin/env bash" # shellcheck disable=SC2154 - echo "${embed_file_bashToolsDefaultConfigTemplate}" + echo "${bashToolsDefaultConfigTemplate}" ) >"${envFile}" Log::displayInfo "Configuration file '${envFile}' created" else @@ -390,7 +451,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ) >>"${envFile}" fi fi - # shellcheck source=/conf/.env + # shellcheck source=/conf/defaultEnv/.env source "${envFile}" || { Log::displayError "impossible to load '${envFile}'" exit 1 @@ -419,36 +480,6 @@ BashTools::runVerboseIfNeeded() { } -# @description convert base64 encoded back to target file -# if target file is executable prepend dir of target -# file to PATH to make binary available everywhere -# it is advised to include in the path of the target file -# the md5sum of the binFile -# -# @arg $1 targetFile:String the file to write -# @arg $2 binFileBase64:String the base64 encoded file -# @arg $3 fileMode:String the chmod to set on the file -# @set PATH String prepend target embedded file binary directory to PATH variable if binary executable -Compiler::Embed::extractFileFromBase64() { - local targetFile="$1" - local binFileBase64="$2" - local fileMode="${3:-+x}" - local targetDir="${targetFile%/*}" - - if [[ ! -f "${targetFile}" ]]; then - if [[ ! -d "${targetDir}" ]]; then - mkdir -p "${targetDir}" - fi - base64 -d >"${targetFile}" <<<"${binFileBase64}" - chmod "${fileMode}" "${targetFile}" - fi - - if [[ -x "${targetFile}" ]]; then - Env::pathPrepend "${targetDir}" - fi -} - - # @description check if all requirements are satisfied # to execute dbImport commands Db::checkRequirements() { @@ -468,19 +499,6 @@ Db::checkRequirements() { } -# @description prepend directories to the PATH environment variable -# @arg $@ args:String[] list of directories to prepend -# @set PATH update PATH with the directories prepended -Env::pathPrepend() { - local arg - for arg in "$@"; do - if [[ -d "${arg}" && ":${PATH}:" != *":${arg}:"* ]]; then - PATH="$(realpath "${arg}"):${PATH}" - fi - done -} - - # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -535,14 +553,6 @@ Linux::requireExecutedAsUser() { } -# @description ensure command tar is available -# @exitcode 1 if tar command not available -# @stderr diagnostics information is displayed -Linux::requireTarCommand() { - Assert::commandExists tar -} - - declare -g FIRST_LOG_DATE LOG_LAST_LOG_DATE LOG_LAST_LOG_DATE_INIT LOG_LAST_DURATION_STR FIRST_LOG_DATE="${EPOCHREALTIME/[^0-9]/}" LOG_LAST_LOG_DATE="${FIRST_LOG_DATE}" @@ -622,19 +632,6 @@ Log::displayInfo() { } -# @description Display message using warning color (yellow) -# @arg $1 message:String the message to display -# @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs -# @env LOG_CONTEXT String allows to contextualize the log -Log::displayWarning() { - if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_WARNING)); then - Log::computeDuration - echo -e "${__WARNING_COLOR}WARN - ${LOG_CONTEXT:-}${LOG_LAST_DURATION_STR:-}${1}${__RESET_COLOR}" >&2 - fi - Log::logWarning "$1" -} - - # @description Display message using error color (red) and exit immediately with error status 1 # @arg $1 message:String the message to display # @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs @@ -718,15 +715,6 @@ Log::logMessage() { } -# @description log message to file -# @arg $1 message:String the message to display -Log::logWarning() { - if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_WARNING)); then - Log::logMessage "${2:-WARNING}" "$1" - fi -} - - # @description activate or not Log::display* and Log::log* functions # based on BASH_FRAMEWORK_DISPLAY_LEVEL and BASH_FRAMEWORK_LOG_LEVEL # environment variables loaded by Env::requireLoad @@ -1045,6 +1033,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -1088,16 +1077,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1272,9 +1251,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1290,14 +1266,24 @@ commandOptionParseFinished() { -beforeParseCallback() { - Linux::requireExecutedAsUser +defaultBeforeParseCallback() { BashTools::Conf::requireLoad Env::requireLoad UI::requireTheme Log::requireLoad } +beforeParseCallback() { + defaultBeforeParseCallback +} + + + +beforeParseCallback() { + defaultBeforeParseCallback + Linux::requireExecutedAsUser +} + declare optionRedirectCmdOutputs="" optionRedirectCmdOutputs() { export optionTraceVerbose @@ -1366,7 +1352,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1402,7 +1387,6 @@ gitRenameBranchCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1449,7 +1433,7 @@ gitRenameBranchCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/17 + # Option 1/16 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1465,7 +1449,7 @@ gitRenameBranchCommandParse() { ;; - # Option 2/17 + # Option 2/16 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1479,7 +1463,7 @@ gitRenameBranchCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 3/17 + # Option 3/16 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1500,7 +1484,7 @@ gitRenameBranchCommandParse() { ;; - # Option 4/17 + # Option 4/16 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1518,7 +1502,7 @@ gitRenameBranchCommandParse() { ;; - # Option 5/17 + # Option 5/16 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1536,7 +1520,7 @@ gitRenameBranchCommandParse() { ;; - # Option 6/17 + # Option 6/16 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1554,25 +1538,7 @@ gitRenameBranchCommandParse() { ;; - # Option 7/17 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 8/17 + # Option 7/16 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1600,7 +1566,7 @@ gitRenameBranchCommandParse() { ;; - # Option 9/17 + # Option 8/16 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1623,7 +1589,7 @@ gitRenameBranchCommandParse() { ;; - # Option 10/17 + # Option 9/16 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1651,7 +1617,7 @@ gitRenameBranchCommandParse() { ;; - # Option 11/17 + # Option 10/16 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -1669,7 +1635,7 @@ gitRenameBranchCommandParse() { ;; - # Option 12/17 + # Option 11/16 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -1697,7 +1663,7 @@ gitRenameBranchCommandParse() { ;; - # Option 13/17 + # Option 12/16 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -1713,7 +1679,7 @@ gitRenameBranchCommandParse() { ;; - # Option 14/17 + # Option 13/16 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -1731,7 +1697,7 @@ gitRenameBranchCommandParse() { ;; - # Option 15/17 + # Option 14/16 # optionAssumeYes alts --assume-yes|--yes|-y # type: Boolean min 0 max 1 --assume-yes | --yes | -y) @@ -1745,7 +1711,7 @@ gitRenameBranchCommandParse() { ((++options_parse_optionParsedCountOptionAssumeYes)) ;; - # Option 16/17 + # Option 15/16 # optionPush alts --push|-p # type: Boolean min 0 max 1 --push | -p) @@ -1759,7 +1725,7 @@ gitRenameBranchCommandParse() { ((++options_parse_optionParsedCountOptionPush)) ;; - # Option 17/17 + # Option 16/16 # optionDelete alts --delete|-d # type: Boolean min 0 max 1 --delete | -d) @@ -1853,7 +1819,6 @@ gitRenameBranchCommandParse() { - if ((options_parse_argParsedCountNewBranchNameArg < 1 )); then Log::displayError "Command ${SCRIPT_NAME} - Argument 'newBranchName' should be provided at least 1 time(s)" return 1 @@ -1883,7 +1848,7 @@ gitRenameBranchCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--assume-yes|--yes|-y]" "[--push|-p]" "[--delete|-d]" + optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--assume-yes|--yes|-y]" "[--push|-p]" "[--delete|-d]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "gitRenameBranch" "${optionsAltList[@]}" @@ -1944,12 +1909,6 @@ gitRenameBranchCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/bin/installRequirements b/bin/installRequirements index 2f74fdae..6452910f 100755 --- a/bin/installRequirements +++ b/bin/installRequirements @@ -307,6 +307,127 @@ Assert::tty() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" + if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then + FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" + else + # if the directory does not exist yet, give a value to FRAMEWORK_ROOT_DIR + FRAMEWORK_ROOT_DIR="${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" + fi + # shellcheck disable=SC2034 + FRAMEWORK_SRC_DIR="${FRAMEWORK_ROOT_DIR}/src" + # shellcheck disable=SC2034 + FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" + + if [[ -f "${HOME}/.bash-tools/.env" ]]; then + # shellcheck disable=SC2034 + BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") + fi + + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + # shellcheck disable=SC2154 + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/defaultEnv/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + + # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -849,6 +970,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2022-now François Chastanet" } @@ -892,16 +1014,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1076,9 +1188,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1094,6 +1203,19 @@ commandOptionParseFinished() { +defaultBeforeParseCallback() { + BashTools::Conf::requireLoad + Env::requireLoad + UI::requireTheme + Log::requireLoad +} + +beforeParseCallback() { + defaultBeforeParseCallback +} + + + # shellcheck disable=SC2034 declare optionBashFrameworkConfig="${BASH_TOOLS_ROOT_DIR}/.framework-config" @@ -1114,7 +1236,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1145,7 +1266,6 @@ installRequirementsCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1175,7 +1295,7 @@ installRequirementsCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/14 + # Option 1/13 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1191,7 +1311,7 @@ installRequirementsCommandParse() { ;; - # Option 2/14 + # Option 2/13 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1205,7 +1325,7 @@ installRequirementsCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 3/14 + # Option 3/13 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1226,7 +1346,7 @@ installRequirementsCommandParse() { ;; - # Option 4/14 + # Option 4/13 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1244,7 +1364,7 @@ installRequirementsCommandParse() { ;; - # Option 5/14 + # Option 5/13 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1262,7 +1382,7 @@ installRequirementsCommandParse() { ;; - # Option 6/14 + # Option 6/13 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1280,25 +1400,7 @@ installRequirementsCommandParse() { ;; - # Option 7/14 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 8/14 + # Option 7/13 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1326,7 +1428,7 @@ installRequirementsCommandParse() { ;; - # Option 9/14 + # Option 8/13 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1349,7 +1451,7 @@ installRequirementsCommandParse() { ;; - # Option 10/14 + # Option 9/13 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1377,7 +1479,7 @@ installRequirementsCommandParse() { ;; - # Option 11/14 + # Option 10/13 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -1395,7 +1497,7 @@ installRequirementsCommandParse() { ;; - # Option 12/14 + # Option 11/13 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -1423,7 +1525,7 @@ installRequirementsCommandParse() { ;; - # Option 13/14 + # Option 12/13 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -1439,7 +1541,7 @@ installRequirementsCommandParse() { ;; - # Option 14/14 + # Option 13/13 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -1498,7 +1600,7 @@ installRequirementsCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" + optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "installRequirements" "${optionsAltList[@]}" @@ -1545,12 +1647,6 @@ installRequirementsCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/bin/mysql2puml b/bin/mysql2puml index 788b9681..79e5830d 100755 --- a/bin/mysql2puml +++ b/bin/mysql2puml @@ -324,6 +324,127 @@ Assert::tty() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" + if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then + FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" + else + # if the directory does not exist yet, give a value to FRAMEWORK_ROOT_DIR + FRAMEWORK_ROOT_DIR="${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" + fi + # shellcheck disable=SC2034 + FRAMEWORK_SRC_DIR="${FRAMEWORK_ROOT_DIR}/src" + # shellcheck disable=SC2034 + FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" + + if [[ -f "${HOME}/.bash-tools/.env" ]]; then + # shellcheck disable=SC2034 + BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") + fi + + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + # shellcheck disable=SC2154 + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/defaultEnv/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + + # @description convert base64 encoded back to target file # if target file is executable prepend dir of target # file to PATH to make binary available everywhere @@ -672,19 +793,6 @@ Log::displayInfo() { } -# @description Display message using warning color (yellow) -# @arg $1 message:String the message to display -# @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs -# @env LOG_CONTEXT String allows to contextualize the log -Log::displayWarning() { - if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_WARNING)); then - Log::computeDuration - echo -e "${__WARNING_COLOR}WARN - ${LOG_CONTEXT:-}${LOG_LAST_DURATION_STR:-}${1}${__RESET_COLOR}" >&2 - fi - Log::logWarning "$1" -} - - # @description Display message using error color (red) and exit immediately with error status 1 # @arg $1 message:String the message to display # @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs @@ -768,15 +876,6 @@ Log::logMessage() { } -# @description log message to file -# @arg $1 message:String the message to display -Log::logWarning() { - if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_WARNING)); then - Log::logMessage "${2:-WARNING}" "$1" - fi -} - - # @description activate or not Log::display* and Log::log* functions # based on BASH_FRAMEWORK_DISPLAY_LEVEL and BASH_FRAMEWORK_LOG_LEVEL # environment variables loaded by Env::requireLoad @@ -980,6 +1079,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2021-now François Chastanet" } @@ -1023,16 +1123,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1207,9 +1297,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1225,6 +1312,19 @@ commandOptionParseFinished() { +defaultBeforeParseCallback() { + BashTools::Conf::requireLoad + Env::requireLoad + UI::requireTheme + Log::requireLoad +} + +beforeParseCallback() { + defaultBeforeParseCallback +} + + + # shellcheck disable=SC2034 declare optionBashFrameworkConfig="${BASH_TOOLS_ROOT_DIR}/.framework-config" @@ -1289,7 +1389,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1322,7 +1421,6 @@ mysql2pumlCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1359,7 +1457,7 @@ mysql2pumlCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/15 + # Option 1/14 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1375,7 +1473,7 @@ mysql2pumlCommandParse() { ;; - # Option 2/15 + # Option 2/14 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1389,7 +1487,7 @@ mysql2pumlCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 3/15 + # Option 3/14 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1410,7 +1508,7 @@ mysql2pumlCommandParse() { ;; - # Option 4/15 + # Option 4/14 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1428,7 +1526,7 @@ mysql2pumlCommandParse() { ;; - # Option 5/15 + # Option 5/14 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1446,7 +1544,7 @@ mysql2pumlCommandParse() { ;; - # Option 6/15 + # Option 6/14 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1464,25 +1562,7 @@ mysql2pumlCommandParse() { ;; - # Option 7/15 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 8/15 + # Option 7/14 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1510,7 +1590,7 @@ mysql2pumlCommandParse() { ;; - # Option 9/15 + # Option 8/14 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1533,7 +1613,7 @@ mysql2pumlCommandParse() { ;; - # Option 10/15 + # Option 9/14 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1561,7 +1641,7 @@ mysql2pumlCommandParse() { ;; - # Option 11/15 + # Option 10/14 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -1579,7 +1659,7 @@ mysql2pumlCommandParse() { ;; - # Option 12/15 + # Option 11/14 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -1607,7 +1687,7 @@ mysql2pumlCommandParse() { ;; - # Option 13/15 + # Option 12/14 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -1623,7 +1703,7 @@ mysql2pumlCommandParse() { ;; - # Option 14/15 + # Option 13/14 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -1641,7 +1721,7 @@ mysql2pumlCommandParse() { ;; - # Option 15/15 + # Option 14/14 # optionSkin alts --skin # type: String min 0 max 1 --skin) @@ -1732,7 +1812,7 @@ mysql2pumlCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--skin ]" + optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--skin ]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "mysql2puml" "${optionsAltList[@]}" @@ -1789,12 +1869,6 @@ mysql2pumlCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/bin/postmanCli b/bin/postmanCli index f51d1323..2eebe51d 100755 --- a/bin/postmanCli +++ b/bin/postmanCli @@ -355,6 +355,127 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" + if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then + FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" + else + # if the directory does not exist yet, give a value to FRAMEWORK_ROOT_DIR + FRAMEWORK_ROOT_DIR="${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" + fi + # shellcheck disable=SC2034 + FRAMEWORK_SRC_DIR="${FRAMEWORK_ROOT_DIR}/src" + # shellcheck disable=SC2034 + FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" + + if [[ -f "${HOME}/.bash-tools/.env" ]]; then + # shellcheck disable=SC2034 + BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") + fi + + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + # shellcheck disable=SC2154 + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/defaultEnv/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + + # @description check if all requirements are satisfied # to execute dbImport commands Db::checkRequirements() { @@ -1488,6 +1609,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -1531,16 +1653,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1715,9 +1827,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1733,6 +1842,19 @@ commandOptionParseFinished() { +defaultBeforeParseCallback() { + BashTools::Conf::requireLoad + Env::requireLoad + UI::requireTheme + Log::requireLoad +} + +beforeParseCallback() { + defaultBeforeParseCallback +} + + + longDescriptionFunction() { echo -e " ${__HELP_TITLE}EXIT CODES:${__HELP_NORMAL}" echo -e " ${__HELP_OPTION_COLOR}1${__HELP_NORMAL}: if commit does not exists" @@ -1812,7 +1934,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1846,7 +1967,6 @@ postmanCliCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1885,7 +2005,7 @@ postmanCliCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/15 + # Option 1/14 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1901,7 +2021,7 @@ postmanCliCommandParse() { ;; - # Option 2/15 + # Option 2/14 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1915,7 +2035,7 @@ postmanCliCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 3/15 + # Option 3/14 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1936,7 +2056,7 @@ postmanCliCommandParse() { ;; - # Option 4/15 + # Option 4/14 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1954,7 +2074,7 @@ postmanCliCommandParse() { ;; - # Option 5/15 + # Option 5/14 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1972,7 +2092,7 @@ postmanCliCommandParse() { ;; - # Option 6/15 + # Option 6/14 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1990,25 +2110,7 @@ postmanCliCommandParse() { ;; - # Option 7/15 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 8/15 + # Option 7/14 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -2036,7 +2138,7 @@ postmanCliCommandParse() { ;; - # Option 9/15 + # Option 8/14 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -2059,7 +2161,7 @@ postmanCliCommandParse() { ;; - # Option 10/15 + # Option 9/14 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -2087,7 +2189,7 @@ postmanCliCommandParse() { ;; - # Option 11/15 + # Option 10/14 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -2105,7 +2207,7 @@ postmanCliCommandParse() { ;; - # Option 12/15 + # Option 11/14 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -2133,7 +2235,7 @@ postmanCliCommandParse() { ;; - # Option 13/15 + # Option 12/14 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -2149,7 +2251,7 @@ postmanCliCommandParse() { ;; - # Option 14/15 + # Option 13/14 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -2167,7 +2269,7 @@ postmanCliCommandParse() { ;; - # Option 15/15 + # Option 14/14 # optionPostmanModelConfig alts --postman-model|-m # type: String min 0 max 1 --postman-model | -m) @@ -2264,7 +2366,7 @@ postmanCliCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--postman-model|-m ]" + optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--postman-model|-m ]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "postmanCli" "${optionsAltList[@]}" @@ -2325,12 +2427,6 @@ postmanCliCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/bin/upgradeGithubRelease b/bin/upgradeGithubRelease index be737dbe..5c62a189 100755 --- a/bin/upgradeGithubRelease +++ b/bin/upgradeGithubRelease @@ -380,6 +380,127 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" + if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then + FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" + else + # if the directory does not exist yet, give a value to FRAMEWORK_ROOT_DIR + FRAMEWORK_ROOT_DIR="${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" + fi + # shellcheck disable=SC2034 + FRAMEWORK_SRC_DIR="${FRAMEWORK_ROOT_DIR}/src" + # shellcheck disable=SC2034 + FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" + + if [[ -f "${HOME}/.bash-tools/.env" ]]; then + # shellcheck disable=SC2034 + BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") + fi + + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + # shellcheck disable=SC2154 + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/defaultEnv/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + + # @description check if all requirements are satisfied # to execute dbImport commands Db::checkRequirements() { @@ -662,19 +783,6 @@ Log::displaySuccess() { } -# @description Display message using warning color (yellow) -# @arg $1 message:String the message to display -# @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs -# @env LOG_CONTEXT String allows to contextualize the log -Log::displayWarning() { - if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_WARNING)); then - Log::computeDuration - echo -e "${__WARNING_COLOR}WARN - ${LOG_CONTEXT:-}${LOG_LAST_DURATION_STR:-}${1}${__RESET_COLOR}" >&2 - fi - Log::logWarning "$1" -} - - # @description Display message using error color (red) and exit immediately with error status 1 # @arg $1 message:String the message to display # @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs @@ -767,15 +875,6 @@ Log::logSuccess() { } -# @description log message to file -# @arg $1 message:String the message to display -Log::logWarning() { - if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_WARNING)); then - Log::logMessage "${2:-WARNING}" "$1" - fi -} - - # @description activate or not Log::display* and Log::log* functions # based on BASH_FRAMEWORK_DISPLAY_LEVEL and BASH_FRAMEWORK_LOG_LEVEL # environment variables loaded by Env::requireLoad @@ -1228,6 +1327,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -1271,16 +1371,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1455,9 +1545,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1473,6 +1560,19 @@ commandOptionParseFinished() { +defaultBeforeParseCallback() { + BashTools::Conf::requireLoad + Env::requireLoad + UI::requireTheme + Log::requireLoad +} + +beforeParseCallback() { + defaultBeforeParseCallback +} + + + specificRequirements() { Linux::requireJqCommand } @@ -1582,7 +1682,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1618,7 +1717,6 @@ upgradeGithubReleaseCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1665,7 +1763,7 @@ upgradeGithubReleaseCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/17 + # Option 1/16 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1681,7 +1779,7 @@ upgradeGithubReleaseCommandParse() { ;; - # Option 2/17 + # Option 2/16 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1695,7 +1793,7 @@ upgradeGithubReleaseCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 3/17 + # Option 3/16 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1716,7 +1814,7 @@ upgradeGithubReleaseCommandParse() { ;; - # Option 4/17 + # Option 4/16 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1734,7 +1832,7 @@ upgradeGithubReleaseCommandParse() { ;; - # Option 5/17 + # Option 5/16 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1752,7 +1850,7 @@ upgradeGithubReleaseCommandParse() { ;; - # Option 6/17 + # Option 6/16 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1770,25 +1868,7 @@ upgradeGithubReleaseCommandParse() { ;; - # Option 7/17 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 8/17 + # Option 7/16 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1816,7 +1896,7 @@ upgradeGithubReleaseCommandParse() { ;; - # Option 9/17 + # Option 8/16 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1839,7 +1919,7 @@ upgradeGithubReleaseCommandParse() { ;; - # Option 10/17 + # Option 9/16 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1867,7 +1947,7 @@ upgradeGithubReleaseCommandParse() { ;; - # Option 11/17 + # Option 10/16 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -1885,7 +1965,7 @@ upgradeGithubReleaseCommandParse() { ;; - # Option 12/17 + # Option 11/16 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -1913,7 +1993,7 @@ upgradeGithubReleaseCommandParse() { ;; - # Option 13/17 + # Option 12/16 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -1929,7 +2009,7 @@ upgradeGithubReleaseCommandParse() { ;; - # Option 14/17 + # Option 13/16 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -1947,7 +2027,7 @@ upgradeGithubReleaseCommandParse() { ;; - # Option 15/17 + # Option 14/16 # optionVersionArg alts --version-arg # type: String min 0 max 1 --version-arg) @@ -1966,7 +2046,7 @@ upgradeGithubReleaseCommandParse() { optionVersionArg="$1" ;; - # Option 16/17 + # Option 15/16 # optionCurrentVersion alts --current-version|-c # type: String min 0 max 1 --current-version | -c) @@ -1985,7 +2065,7 @@ upgradeGithubReleaseCommandParse() { optionCurrentVersion="$1" ;; - # Option 17/17 + # Option 16/16 # optionExactVersion alts --exact-version|-e # type: String min 0 max 1 --exact-version | -e) @@ -2086,7 +2166,6 @@ upgradeGithubReleaseCommandParse() { - if ((options_parse_argParsedCountTargetFileArg < 1 )); then Log::displayError "Command ${SCRIPT_NAME} - Argument 'targetFile' should be provided at least 1 time(s)" return 1 @@ -2117,7 +2196,7 @@ upgradeGithubReleaseCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--version-arg ]" "[--current-version|-c ]" "[--exact-version|-e ]" + optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--version-arg ]" "[--current-version|-c ]" "[--exact-version|-e ]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "upgradeGithubRelease" "${optionsAltList[@]}" @@ -2178,12 +2257,6 @@ upgradeGithubReleaseCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/bin/waitForIt b/bin/waitForIt index a286f4dd..3a5dbfc9 100755 --- a/bin/waitForIt +++ b/bin/waitForIt @@ -355,6 +355,127 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" + if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then + FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" + else + # if the directory does not exist yet, give a value to FRAMEWORK_ROOT_DIR + FRAMEWORK_ROOT_DIR="${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" + fi + # shellcheck disable=SC2034 + FRAMEWORK_SRC_DIR="${FRAMEWORK_ROOT_DIR}/src" + # shellcheck disable=SC2034 + FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" + + if [[ -f "${HOME}/.bash-tools/.env" ]]; then + # shellcheck disable=SC2034 + BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") + fi + + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + # shellcheck disable=SC2154 + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/defaultEnv/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + + # @description run command specified # @arg $@ array:String[] the command to run # @env optionInfoVerbose int - if 1 displays the command specified before running it @@ -518,19 +639,6 @@ Log::displayInfo() { } -# @description Display message using warning color (yellow) -# @arg $1 message:String the message to display -# @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs -# @env LOG_CONTEXT String allows to contextualize the log -Log::displayWarning() { - if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_WARNING)); then - Log::computeDuration - echo -e "${__WARNING_COLOR}WARN - ${LOG_CONTEXT:-}${LOG_LAST_DURATION_STR:-}${1}${__RESET_COLOR}" >&2 - fi - Log::logWarning "$1" -} - - # @description Display message using error color (red) and exit immediately with error status 1 # @arg $1 message:String the message to display # @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs @@ -614,15 +722,6 @@ Log::logMessage() { } -# @description log message to file -# @arg $1 message:String the message to display -Log::logWarning() { - if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_WARNING)); then - Log::logMessage "${2:-WARNING}" "$1" - fi -} - - # @description activate or not Log::display* and Log::log* functions # based on BASH_FRAMEWORK_DISPLAY_LEVEL and BASH_FRAMEWORK_LOG_LEVEL # environment variables loaded by Env::requireLoad @@ -918,6 +1017,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -961,16 +1061,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1145,9 +1235,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1163,6 +1250,19 @@ commandOptionParseFinished() { +defaultBeforeParseCallback() { + BashTools::Conf::requireLoad + Env::requireLoad + UI::requireTheme + Log::requireLoad +} + +beforeParseCallback() { + defaultBeforeParseCallback +} + + + declare -a availableAlgos=( "timeoutV1WithNc" "timeoutV2WithNc" @@ -1255,7 +1355,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1297,7 +1396,6 @@ waitForItCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1343,7 +1441,7 @@ waitForItCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/18 + # Option 1/17 # optionTimeout alts --timeout|-t # type: String min 0 max 1 --timeout | -t) @@ -1364,7 +1462,7 @@ waitForItCommandParse() { ;; - # Option 2/18 + # Option 2/17 # optionExecIfTimedOut alts --exec-command-on-timeout|--lax|-l # type: Boolean min 0 max 1 --exec-command-on-timeout | --lax | -l) @@ -1378,7 +1476,7 @@ waitForItCommandParse() { ((++options_parse_optionParsedCountOptionExecIfTimedOut)) ;; - # Option 3/18 + # Option 3/17 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1394,7 +1492,7 @@ waitForItCommandParse() { ;; - # Option 4/18 + # Option 4/17 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1408,7 +1506,7 @@ waitForItCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 5/18 + # Option 5/17 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1429,7 +1527,7 @@ waitForItCommandParse() { ;; - # Option 6/18 + # Option 6/17 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1447,7 +1545,7 @@ waitForItCommandParse() { ;; - # Option 7/18 + # Option 7/17 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1465,7 +1563,7 @@ waitForItCommandParse() { ;; - # Option 8/18 + # Option 8/17 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1483,25 +1581,7 @@ waitForItCommandParse() { ;; - # Option 9/18 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 10/18 + # Option 9/17 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1529,7 +1609,7 @@ waitForItCommandParse() { ;; - # Option 11/18 + # Option 10/17 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1552,7 +1632,7 @@ waitForItCommandParse() { ;; - # Option 12/18 + # Option 11/17 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1580,7 +1660,7 @@ waitForItCommandParse() { ;; - # Option 13/18 + # Option 12/17 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -1598,7 +1678,7 @@ waitForItCommandParse() { ;; - # Option 14/18 + # Option 13/17 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -1626,7 +1706,7 @@ waitForItCommandParse() { ;; - # Option 15/18 + # Option 14/17 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -1642,7 +1722,7 @@ waitForItCommandParse() { ;; - # Option 16/18 + # Option 15/17 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -1660,7 +1740,7 @@ waitForItCommandParse() { ;; - # Option 17/18 + # Option 16/17 # optionAlgo alts --algorithm|--algo # type: String min 0 max 1 --algorithm | --algo) @@ -1681,7 +1761,7 @@ waitForItCommandParse() { ;; - # Option 18/18 + # Option 17/17 # optionLegacy alts --user-nc # type: Boolean min 0 max 1 --user-nc) @@ -1785,7 +1865,6 @@ waitForItCommandParse() { - if ((options_parse_argParsedCountHostOrIpArg < 1 )); then Log::displayError "Command ${SCRIPT_NAME} - Argument 'hostOrIp' should be provided at least 1 time(s)" return 1 @@ -1818,7 +1897,7 @@ waitForItCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--timeout|-t ]" "[--exec-command-on-timeout|--lax|-l]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--algorithm|--algo ]" "[--user-nc]" + optionsAltList=("[--timeout|-t ]" "[--exec-command-on-timeout|--lax|-l]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--algorithm|--algo ]" "[--user-nc]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "waitForIt" "${optionsAltList[@]}" @@ -1898,12 +1977,6 @@ waitForItCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/bin/waitForMysql b/bin/waitForMysql index db71355d..afd01c54 100755 --- a/bin/waitForMysql +++ b/bin/waitForMysql @@ -338,6 +338,127 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" + if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then + FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" + else + # if the directory does not exist yet, give a value to FRAMEWORK_ROOT_DIR + FRAMEWORK_ROOT_DIR="${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" + fi + # shellcheck disable=SC2034 + FRAMEWORK_SRC_DIR="${FRAMEWORK_ROOT_DIR}/src" + # shellcheck disable=SC2034 + FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" + + if [[ -f "${HOME}/.bash-tools/.env" ]]; then + # shellcheck disable=SC2034 + BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") + fi + + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + # shellcheck disable=SC2154 + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/defaultEnv/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + + # @description run command specified # @arg $@ array:String[] the command to run # @env optionInfoVerbose int - if 1 displays the command specified before running it @@ -501,19 +622,6 @@ Log::displayInfo() { } -# @description Display message using warning color (yellow) -# @arg $1 message:String the message to display -# @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs -# @env LOG_CONTEXT String allows to contextualize the log -Log::displayWarning() { - if ((BASH_FRAMEWORK_DISPLAY_LEVEL >= __LEVEL_WARNING)); then - Log::computeDuration - echo -e "${__WARNING_COLOR}WARN - ${LOG_CONTEXT:-}${LOG_LAST_DURATION_STR:-}${1}${__RESET_COLOR}" >&2 - fi - Log::logWarning "$1" -} - - # @description Display message using error color (red) and exit immediately with error status 1 # @arg $1 message:String the message to display # @env DISPLAY_DURATION int (default 0) if 1 display elapsed time information between 2 info logs @@ -597,15 +705,6 @@ Log::logMessage() { } -# @description log message to file -# @arg $1 message:String the message to display -Log::logWarning() { - if ((BASH_FRAMEWORK_LOG_LEVEL >= __LEVEL_WARNING)); then - Log::logMessage "${2:-WARNING}" "$1" - fi -} - - # @description activate or not Log::display* and Log::log* functions # based on BASH_FRAMEWORK_DISPLAY_LEVEL and BASH_FRAMEWORK_LOG_LEVEL # environment variables loaded by Env::requireLoad @@ -901,6 +1000,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -944,16 +1044,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1128,9 +1218,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1146,6 +1233,19 @@ commandOptionParseFinished() { +defaultBeforeParseCallback() { + BashTools::Conf::requireLoad + Env::requireLoad + UI::requireTheme + Log::requireLoad +} + +beforeParseCallback() { + defaultBeforeParseCallback +} + + + longDescriptionFunction() { echo -e " ${__HELP_TITLE}EXIT STATUS CODES:${__HELP_NORMAL}" echo -e " ${__HELP_OPTION_COLOR}0${__HELP_NORMAL}: mysql is available" @@ -1202,7 +1302,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1244,7 +1343,6 @@ waitForMysqlCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1292,7 +1390,7 @@ waitForMysqlCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/16 + # Option 1/15 # optionTimeout alts --timeout|-t # type: String min 0 max 1 --timeout | -t) @@ -1313,7 +1411,7 @@ waitForMysqlCommandParse() { ;; - # Option 2/16 + # Option 2/15 # optionExecIfTimedOut alts --exec-command-on-timeout|--lax|-l # type: Boolean min 0 max 1 --exec-command-on-timeout | --lax | -l) @@ -1327,7 +1425,7 @@ waitForMysqlCommandParse() { ((++options_parse_optionParsedCountOptionExecIfTimedOut)) ;; - # Option 3/16 + # Option 3/15 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1343,7 +1441,7 @@ waitForMysqlCommandParse() { ;; - # Option 4/16 + # Option 4/15 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1357,7 +1455,7 @@ waitForMysqlCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 5/16 + # Option 5/15 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1378,7 +1476,7 @@ waitForMysqlCommandParse() { ;; - # Option 6/16 + # Option 6/15 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1396,7 +1494,7 @@ waitForMysqlCommandParse() { ;; - # Option 7/16 + # Option 7/15 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1414,7 +1512,7 @@ waitForMysqlCommandParse() { ;; - # Option 8/16 + # Option 8/15 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1432,25 +1530,7 @@ waitForMysqlCommandParse() { ;; - # Option 9/16 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 10/16 + # Option 9/15 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1478,7 +1558,7 @@ waitForMysqlCommandParse() { ;; - # Option 11/16 + # Option 10/15 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1501,7 +1581,7 @@ waitForMysqlCommandParse() { ;; - # Option 12/16 + # Option 11/15 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1529,7 +1609,7 @@ waitForMysqlCommandParse() { ;; - # Option 13/16 + # Option 12/15 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -1547,7 +1627,7 @@ waitForMysqlCommandParse() { ;; - # Option 14/16 + # Option 13/15 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -1575,7 +1655,7 @@ waitForMysqlCommandParse() { ;; - # Option 15/16 + # Option 14/15 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -1591,7 +1671,7 @@ waitForMysqlCommandParse() { ;; - # Option 16/16 + # Option 15/15 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -1729,7 +1809,6 @@ waitForMysqlCommandParse() { - if ((options_parse_argParsedCountMysqlHostArg < 1 )); then Log::displayError "Command ${SCRIPT_NAME} - Argument 'mysqlHost' should be provided at least 1 time(s)" return 1 @@ -1770,7 +1849,7 @@ waitForMysqlCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--timeout|-t ]" "[--exec-command-on-timeout|--lax|-l]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" + optionsAltList=("[--timeout|-t ]" "[--exec-command-on-timeout|--lax|-l]" "[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "waitForMysql" "${optionsAltList[@]}" @@ -1858,12 +1937,6 @@ waitForMysqlCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/conf/dbScripts/extractData b/conf/dbScripts/extractData index 439c37c4..e8c8111b 100755 --- a/conf/dbScripts/extractData +++ b/conf/dbScripts/extractData @@ -349,18 +349,79 @@ Bash::handlePipelineFailure() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + # @description loads ~/.bash-tools/.env if available # if not creates it from a default template # else check if new options need to be added BashTools::Conf::requireLoad() { -Linux::requireTarCommand -Compiler::Embed::extractFileFromBase64 \ - "${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" \ - "IyEvdXNyL2Jpbi9lbnYgYmFzaAojIHNoZWxsY2hlY2sgZGlzYWJsZT1TQzIwMzQKCiMgRGVmYXVsdCBzZXR0aW5ncwojIHlvdSBjYW4gb3ZlcnJpZGUgdGhlc2Ugc2V0dGluZ3MgYnkgY3JlYXRpbmcgJHtIT01FfS8uYmFzaC10b29scy8uZW52IGZpbGUKCiMjIwojIyMgRElTUExBWSBMZXZlbAojIyMgbWluaW11bSBsZXZlbCBvZiB0aGUgbWVzc2FnZXMgdGhhdCB3aWxsIGJlIGRpc3BsYXllZCBvbiBzY3JlZW4KIyMjCiMjIyAwOiBOTyBMT0cKIyMjIDE6IEVSUk9SCiMjIyAyOiBXQVJOSU5HCiMjIyAzOiBJTkZPCiMjIyA0OiBERUJVRwojIyMKQkFTSF9GUkFNRVdPUktfRElTUExBWV9MRVZFTD0ke0JBU0hfRlJBTUVXT1JLX0RJU1BMQVlfTEVWRUw6LTN9CgojIyMKIyMjIERJU1BMQVkgZHVyYXRpb24KIyMjIDA6IG5vIGR1cmF0aW9uIGlzIGRpc3BsYXllZCBvbiB0aGUgbWVzc2FnZXMKIyMjIDE6IGR1cmF0aW9uIGJldHdlZW4gcHJldmlvdXMgbWVzc2FnZSBhbmQgY3VycmVudCBpcyBkaXNwbGF5ZWQKIyMjIHdpdGggdGhlIG1lc3NhZ2UKIyMjCkRJU1BMQVlfRFVSQVRJT049JHtESVNQTEFZX0RVUkFUSU9OOjB9CgojIyMKIyMjIExvZyB0byBmaWxlCiMjIwojIyMgYWxsIGxvZyBtZXNzYWdlcyB3aWxsIGJlIHJlZGlyZWN0ZWQgdG8gbG9nIGZpbGUgc3BlY2lmaWVkCiMjIyB0aGlzIHNhbWUgcGF0aCB3aWxsIGJlIHVzZWQgaW5zaWRlIGFuZCBvdXRzaWRlIG9mIHRoZSBjb250YWluZXIKIyMjCkJBU0hfRlJBTUVXT1JLX0xPR19GSUxFPSR7QkFTSF9GUkFNRVdPUktfTE9HX0ZJTEU6LSR7RlJBTUVXT1JLX1JPT1RfRElSfS9sb2dzL2Jhc2gubG9nfQoKIyMjCiMjIyBMT0cgTGV2ZWwKIyMjIG1pbmltdW0gbGV2ZWwgb2YgdGhlIG1lc3NhZ2VzIHRoYXQgd2lsbCBiZSBsb2dnZWQgaW50byBMT0dfRklMRQojIyMKIyMjIDA6IE5PIExPRwojIyMgMTogRVJST1IKIyMjIDI6IFdBUk5JTkcKIyMjIDM6IElORk8KIyMjIDQ6IERFQlVHCiMjIwpCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw9JHtCQVNIX0ZSQU1FV09SS19MT0dfTEVWRUw6LTB9CgojIGFic29sdXRlIGRpcmVjdG9yeSBjb250YWluaW5nIGRiIGltcG9ydCBzcWwgZHVtcHMKREJfSU1QT1JUX0RVTVBfRElSPSR7REJfSU1QT1JUX0RVTVBfRElSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2RiSW1wb3J0RHVtcHN9CgojIGdhcmJhZ2UgY29sbGVjdCBhbGwgZmlsZXMgZm9yIHdoaWNoIG1vZGlmaWNhdGlvbiBpcyBncmVhdGVyIHRoYW4gZWc6IDMwIGRheXMgKCszMCkKIyBlYWNoIHRpbWUgYW4gZXhpc3RpbmcgZmlsZSBpcyB1c2VkIGJ5IGRiSW1wb3J0L2RiSW1wb3J0VGFibGUKIyB0aGUgZmlsZSBtb2RpZmljYXRpb24gdGltZSBpcyBzZXQgdG8gbm93CkRCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUz0ke0RCX0lNUE9SVF9HQVJCQUdFX0NPTExFQ1RfREFZUzotKzMwfQoKIyBhYnNvbHV0ZSBkaXJlY3RvcnkgY29udGFpbmluZyBkYlNjcmlwdHMgdXNlZCBieSBkYlNjcmlwdEFsbERhdGFiYXNlcwpTQ1JJUFRTX0ZPTERFUj0ke1NDUklQVFNfRk9MREVSOi0ke0hPTUV9Ly5iYXNoLXRvb2xzL2NvbmYvZGJTY3JpcHRzfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIEFXUyBQYXJhbWV0ZXJzCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KUzNfQkFTRV9VUkw9JHtTM19CQVNFX1VSTDotfQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFBvc3RtYW4gUGFyYW1ldGVycwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tClBPU1RNQU5fQVBJX0tFWT0K" \ - "755" - -declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp}/db87222729e0f1ed9c597a486a61a08c/bashToolsDefaultConfigTemplate" - BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" @@ -388,7 +449,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ( echo "#!/usr/bin/env bash" # shellcheck disable=SC2154 - echo "${embed_file_bashToolsDefaultConfigTemplate}" + echo "${bashToolsDefaultConfigTemplate}" ) >"${envFile}" Log::displayInfo "Configuration file '${envFile}' created" else @@ -401,7 +462,7 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp ) >>"${envFile}" fi fi - # shellcheck source=/conf/.env + # shellcheck source=/conf/defaultEnv/.env source "${envFile}" || { Log::displayError "impossible to load '${envFile}'" exit 1 @@ -409,36 +470,6 @@ declare -gx embed_file_bashToolsDefaultConfigTemplate="${PERSISTENT_TMPDIR:-/tmp } -# @description convert base64 encoded back to target file -# if target file is executable prepend dir of target -# file to PATH to make binary available everywhere -# it is advised to include in the path of the target file -# the md5sum of the binFile -# -# @arg $1 targetFile:String the file to write -# @arg $2 binFileBase64:String the base64 encoded file -# @arg $3 fileMode:String the chmod to set on the file -# @set PATH String prepend target embedded file binary directory to PATH variable if binary executable -Compiler::Embed::extractFileFromBase64() { - local targetFile="$1" - local binFileBase64="$2" - local fileMode="${3:-+x}" - local targetDir="${targetFile%/*}" - - if [[ ! -f "${targetFile}" ]]; then - if [[ ! -d "${targetDir}" ]]; then - mkdir -p "${targetDir}" - fi - base64 -d >"${targetFile}" <<<"${binFileBase64}" - chmod "${fileMode}" "${targetFile}" - fi - - if [[ -x "${targetFile}" ]]; then - Env::pathPrepend "${targetDir}" - fi -} - - # @description get absolute conf file from specified conf folder deduced using these rules # * from absolute file (ignores and ) # * relative to where script is executed (ignores and ) @@ -696,19 +727,6 @@ Db::checkRequirements() { } -# @description prepend directories to the PATH environment variable -# @arg $@ args:String[] list of directories to prepend -# @set PATH update PATH with the directories prepended -Env::pathPrepend() { - local arg - for arg in "$@"; do - if [[ -d "${arg}" && ":${PATH}:" != *":${arg}:"* ]]; then - PATH="$(realpath "${arg}"):${PATH}" - fi - done -} - - # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -791,14 +809,6 @@ Linux::requireRealpathCommand() { } -# @description ensure command tar is available -# @exitcode 1 if tar command not available -# @stderr diagnostics information is displayed -Linux::requireTarCommand() { - Assert::commandExists tar -} - - declare -g FIRST_LOG_DATE LOG_LAST_LOG_DATE LOG_LAST_LOG_DATE_INIT LOG_LAST_DURATION_STR FIRST_LOG_DATE="${EPOCHREALTIME/[^0-9]/}" LOG_LAST_LOG_DATE="${FIRST_LOG_DATE}" @@ -1278,6 +1288,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2020-now François Chastanet" } @@ -1321,16 +1332,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1505,9 +1506,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1523,13 +1521,17 @@ commandOptionParseFinished() { -beforeParseCallback() { +defaultBeforeParseCallback() { BashTools::Conf::requireLoad Env::requireLoad UI::requireTheme Log::requireLoad } +beforeParseCallback() { + defaultBeforeParseCallback +} + optionVersionCallback() { @@ -1585,9 +1587,7 @@ unknownArg() { } beforeParseCallback() { - Env::requireLoad - UI::requireTheme - Log::requireLoad + defaultBeforeParseCallback Linux::requireExecutedAsUser Linux::requireRealpathCommand init @@ -1605,7 +1605,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1636,7 +1635,6 @@ extractDataCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1666,7 +1664,7 @@ extractDataCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/14 + # Option 1/13 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1682,7 +1680,7 @@ extractDataCommandParse() { ;; - # Option 2/14 + # Option 2/13 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1696,7 +1694,7 @@ extractDataCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 3/14 + # Option 3/13 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1717,7 +1715,7 @@ extractDataCommandParse() { ;; - # Option 4/14 + # Option 4/13 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1735,7 +1733,7 @@ extractDataCommandParse() { ;; - # Option 5/14 + # Option 5/13 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1753,7 +1751,7 @@ extractDataCommandParse() { ;; - # Option 6/14 + # Option 6/13 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1771,25 +1769,7 @@ extractDataCommandParse() { ;; - # Option 7/14 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 8/14 + # Option 7/13 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1817,7 +1797,7 @@ extractDataCommandParse() { ;; - # Option 9/14 + # Option 8/13 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1840,7 +1820,7 @@ extractDataCommandParse() { ;; - # Option 10/14 + # Option 9/13 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1868,7 +1848,7 @@ extractDataCommandParse() { ;; - # Option 11/14 + # Option 10/13 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -1886,7 +1866,7 @@ extractDataCommandParse() { ;; - # Option 12/14 + # Option 11/13 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -1914,7 +1894,7 @@ extractDataCommandParse() { ;; - # Option 13/14 + # Option 12/13 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -1930,7 +1910,7 @@ extractDataCommandParse() { ;; - # Option 14/14 + # Option 13/13 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -1989,7 +1969,7 @@ extractDataCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" + optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "extractData" "${optionsAltList[@]}" @@ -2036,12 +2016,6 @@ extractDataCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo diff --git a/conf/.env b/conf/defaultEnv/.env similarity index 100% rename from conf/.env rename to conf/defaultEnv/.env diff --git a/conf/mysql2pumlSkins/default.png b/conf/mysql2pumlSkins/default.png deleted file mode 100644 index aaf7784b43255f532035d355498ed8d50af4ddee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 954 zcmV;r14aCaP)^?c_3(XbZ~PzFE4OxVQzGFZEP-MZ*6wY${zp#11@P)Safh~ zVQzGFZEOGm0001ZoTXK5Pa-i8{=UCrTnR!%Kqcm~0iuU;Q9wBnzg`MEK*Mf#uiHwv zUw_l?f^Z6_cO<0U&df7Ur}J`|C?=H-1Lp{|7)N1$oL8&P!GzEij|4oiQGkV{3h$Ro1 zT*4d;kEuiyL^mLbk!rzzY9s*@K7IHolW|1XGBOdVA3_Jg230cDp-8!wAg7kGS&UM{ zb!ivR({+-qDLn1%#c~0o@IeDy*P-ttxK86^xsjZrS|A8$kVe1bLOySh;DA2c9SgAq zQn%OeB>K&Io*y6_c63a5 zO^N^?(+jWSWKJ!O`(d~HhDf$KHs~WJb~@kGi-SER(wE$(kewM4!~5Is!<)S{nD%*e zlEgSxQimU6^nP5js)AIJ3tOC$PiHDi>_Wd&f;Rm}k(!k#j|Fb$->VO>;JGxf2gJ=t z*VX2w)o0TD^ZB`P5#8L#RSUV{&?sanQm^QLP2Tss*+l-7yU*dLS^iN6y8t(Aw;p=c z2UEpA+Z??twOhre39uK&ZGm`nUgzYMH_dLu#&fUr(0zDZ*I)@2WQJLuaI(#|_Q`3T zsW8Zn#*uFtW5G7tR;y^bIHE@?D)uTBNHH-Wt z{YYp&U}SPBabCxPwY*YF@(~S?TPm*s|AkO>$Q=zHt~jY*(%sEOaxT}y>HqQ9pnY?b zVXq4>)csADKP{hC&uZmbVZanz#S*F)a9Z=u&%LuM44+zH#6_p@t>1+t(sGQZCQ}z= zUv%#1N#Icv{g49o5Tm%e?yL^rM!awt2{TunyXW4k!bR=mD_1Z;Nlf6m=Un52=|GVM zJqFELkG!`}zBpYbrkYI&8->$~2v;siHgJ9e*J(~38P>250000HNkl diff --git a/install b/install index 94cd53e8..884310ae 100755 --- a/install +++ b/install @@ -355,6 +355,127 @@ Backup::dir() { } +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +# +# shellcheck disable=SC2034 + +# Default settings +# you can override these settings by creating ${HOME}/.bash-tools/.env file + +### +### DISPLAY Level +### minimum level of the messages that will be displayed on screen +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_DISPLAY_LEVEL=${BASH_FRAMEWORK_DISPLAY_LEVEL:-3} + +### +### DISPLAY duration +### 0: no duration is displayed on the messages +### 1: duration between previous message and current is displayed +### with the message +### +DISPLAY_DURATION=${DISPLAY_DURATION:0} + +### +### Log to file +### +### all log messages will be redirected to log file specified +### this same path will be used inside and outside of the container +### +BASH_FRAMEWORK_LOG_FILE=${BASH_FRAMEWORK_LOG_FILE:-${FRAMEWORK_ROOT_DIR}/logs/bash.log} + +### +### LOG Level +### minimum level of the messages that will be logged into LOG_FILE +### +### 0: NO LOG +### 1: ERROR +### 2: WARNING +### 3: INFO +### 4: DEBUG +### +BASH_FRAMEWORK_LOG_LEVEL=${BASH_FRAMEWORK_LOG_LEVEL:-0} + +# absolute directory containing db import sql dumps +DB_IMPORT_DUMP_DIR=${DB_IMPORT_DUMP_DIR:-${HOME}/.bash-tools/dbImportDumps} + +# garbage collect all files for which modification is greater than eg: 30 days (+30) +# each time an existing file is used by dbImport/dbImportTable +# the file modification time is set to now +DB_IMPORT_GARBAGE_COLLECT_DAYS=${DB_IMPORT_GARBAGE_COLLECT_DAYS:-+30} + +# absolute directory containing dbScripts used by dbScriptAllDatabases +SCRIPTS_FOLDER=${SCRIPTS_FOLDER:-${HOME}/.bash-tools/conf/dbScripts} + +# ----------------------------------------------------- +# AWS Parameters +# ----------------------------------------------------- +S3_BASE_URL=${S3_BASE_URL:-} + +# ----------------------------------------------------- +# Postman Parameters +# ----------------------------------------------------- +POSTMAN_API_KEY= +EOM + +# @description loads ~/.bash-tools/.env if available +# if not creates it from a default template +# else check if new options need to be added +BashTools::Conf::requireLoad() { + BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" + if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then + FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" + else + # if the directory does not exist yet, give a value to FRAMEWORK_ROOT_DIR + FRAMEWORK_ROOT_DIR="${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" + fi + # shellcheck disable=SC2034 + FRAMEWORK_SRC_DIR="${FRAMEWORK_ROOT_DIR}/src" + # shellcheck disable=SC2034 + FRAMEWORK_BIN_DIR="${FRAMEWORK_ROOT_DIR}/bin" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_DIR="${FRAMEWORK_ROOT_DIR}/vendor" + # shellcheck disable=SC2034 + FRAMEWORK_VENDOR_BIN_DIR="${FRAMEWORK_ROOT_DIR}/vendor/bin" + + if [[ -f "${HOME}/.bash-tools/.env" ]]; then + # shellcheck disable=SC2034 + BASH_FRAMEWORK_ENV_FILES=("${HOME}/.bash-tools/.env") + fi + + local envFile="${HOME}/.bash-tools/.env" + if [[ ! -f "${envFile}" ]]; then + mkdir -p "${HOME}/.bash-tools" + ( + echo "#!/usr/bin/env bash" + # shellcheck disable=SC2154 + echo "${bashToolsDefaultConfigTemplate}" + ) >"${envFile}" + Log::displayInfo "Configuration file '${envFile}' created" + else + if ! grep -q '^POSTMAN_API_KEY=' "${envFile}"; then + ( + echo '# -----------------------------------------------------' + echo '# Postman Parameters' + echo '# -----------------------------------------------------' + echo 'POSTMAN_API_KEY=' + ) >>"${envFile}" + fi + fi + # shellcheck source=/conf/defaultEnv/.env + source "${envFile}" || { + Log::displayError "impossible to load '${envFile}'" + exit 1 + } +} + + # @description ensure env files are loaded # @arg $@ list of default files to load at the end # @exitcode 1 if one of env files fails to load @@ -828,6 +949,7 @@ beforeParseCallback() { copyrightCallback() { # + # shellcheck disable=SC2155,SC2154,SC2250 echo "Copyright (c) 2022-now François Chastanet" } @@ -871,16 +993,6 @@ optionVersionCallback() { exit 0 } -# shellcheck disable=SC2317 # if function is overridden -optionEnvFileCallback() { - local envFile="$2" - Log::displayWarning "Command ${SCRIPT_NAME} - Option --env-file is deprecated and will be removed in the future" - if [[ ! -f "${envFile}" || ! -r "${envFile}" ]]; then - Log::displayError "Command ${SCRIPT_NAME} - Option --env-file - File '${envFile}' doesn't exist" - exit 1 - fi -} - # shellcheck disable=SC2317 # if function is overridden optionInfoVerboseCallback() { BASH_FRAMEWORK_ARGS_VERBOSE_OPTION='--verbose' @@ -1055,9 +1167,6 @@ commandOptionParseFinished() { defaultEnvFile="${PERSISTENT_TMPDIR}/.framework-config" echo "${defaultFrameworkConfig}" >"${defaultEnvFile}" local -a files=("${defaultEnvFile}") - if [[ -f "${envFile}" ]]; then - files+=("${envFile}") - fi # shellcheck disable=SC2154 if [[ -f "${optionBashFrameworkConfig}" ]]; then files+=("${optionBashFrameworkConfig}") @@ -1073,6 +1182,19 @@ commandOptionParseFinished() { +defaultBeforeParseCallback() { + BashTools::Conf::requireLoad + Env::requireLoad + UI::requireTheme + Log::requireLoad +} + +beforeParseCallback() { + defaultBeforeParseCallback +} + + + # shellcheck disable=SC2034 declare optionBashFrameworkConfig="${BASH_TOOLS_ROOT_DIR}/.framework-config" @@ -1081,6 +1203,12 @@ optionHelpCallback() { exit 0 } +beforeParseCallback() { + defaultBeforeParseCallback + Linux::requireExecutedAsUser + Linux::requireTarCommand +} + # ------------------------------------------ # Command installCommand @@ -1093,7 +1221,6 @@ declare optionBashFrameworkConfig="" declare optionInfoVerbose="0" declare optionDebugVerbose="0" declare optionTraceVerbose="0" -declare -a optionEnvFiles=() declare optionLogLevel="" declare optionLogFile="" declare optionDisplayLevel="" @@ -1125,7 +1252,6 @@ installCommandParse() { optionTraceVerbose="0" local -i options_parse_optionParsedCountOptionTraceVerbose ((options_parse_optionParsedCountOptionTraceVerbose = 0)) || true - optionLogLevel="" local -i options_parse_optionParsedCountOptionLogLevel ((options_parse_optionParsedCountOptionLogLevel = 0)) || true @@ -1158,7 +1284,7 @@ installCommandParse() { local options_parse_arg="$1" local argOptDefaultBehavior=0 case "${options_parse_arg}" in - # Option 1/15 + # Option 1/14 # optionHelp alts --help|-h # type: Boolean min 0 max 1 --help | -h) @@ -1174,7 +1300,7 @@ installCommandParse() { ;; - # Option 2/15 + # Option 2/14 # optionConfig alts --config # type: Boolean min 0 max 1 --config) @@ -1188,7 +1314,7 @@ installCommandParse() { ((++options_parse_optionParsedCountOptionConfig)) ;; - # Option 3/15 + # Option 3/14 # optionBashFrameworkConfig alts --bash-framework-config # type: String min 0 max 1 --bash-framework-config) @@ -1209,7 +1335,7 @@ installCommandParse() { ;; - # Option 4/15 + # Option 4/14 # optionInfoVerbose alts --verbose|-v # type: Boolean min 0 max 1 --verbose | -v) @@ -1227,7 +1353,7 @@ installCommandParse() { ;; - # Option 5/15 + # Option 5/14 # optionDebugVerbose alts -vv # type: Boolean min 0 max 1 -vv) @@ -1245,7 +1371,7 @@ installCommandParse() { ;; - # Option 6/15 + # Option 6/14 # optionTraceVerbose alts -vvv # type: Boolean min 0 max 1 -vvv) @@ -1263,25 +1389,7 @@ installCommandParse() { ;; - # Option 7/15 - # optionEnvFiles alts --env-file - # type: StringArray min 0 max -1 - --env-file) - shift - if (($# == 0)); then - Log::displayError "Command ${SCRIPT_NAME} - Option ${options_parse_arg} - a value needs to be specified" - return 1 - fi - - ((++options_parse_optionParsedCountOptionEnvFiles)) - optionEnvFiles+=("$1") - optionEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - updateArgListEnvFileCallback "${options_parse_arg}" "${optionEnvFiles[@]}" - - ;; - - # Option 8/15 + # Option 7/14 # optionLogLevel alts --log-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1309,7 +1417,7 @@ installCommandParse() { ;; - # Option 9/15 + # Option 8/14 # optionLogFile alts --log-file # type: String min 0 max 1 --log-file) @@ -1332,7 +1440,7 @@ installCommandParse() { ;; - # Option 10/15 + # Option 9/14 # optionDisplayLevel alts --display-level # type: String min 0 max 1 # authorizedValues: OFF|ERR|ERROR|WARN|WARNING|INFO|DEBUG|TRACE @@ -1360,7 +1468,7 @@ installCommandParse() { ;; - # Option 11/15 + # Option 10/14 # optionNoColor alts --no-color # type: Boolean min 0 max 1 --no-color) @@ -1378,7 +1486,7 @@ installCommandParse() { ;; - # Option 12/15 + # Option 11/14 # optionTheme alts --theme # type: String min 0 max 1 # authorizedValues: default|default-force|noColor @@ -1406,7 +1514,7 @@ installCommandParse() { ;; - # Option 13/15 + # Option 12/14 # optionVersion alts --version # type: Boolean min 0 max 1 --version) @@ -1422,7 +1530,7 @@ installCommandParse() { ;; - # Option 14/15 + # Option 13/14 # optionQuiet alts --quiet|-q # type: Boolean min 0 max 1 --quiet | -q) @@ -1440,7 +1548,7 @@ installCommandParse() { ;; - # Option 15/15 + # Option 14/14 # optionSkipBackup alts --skip-backup # type: Boolean min 0 max 1 --skip-backup) @@ -1495,7 +1603,7 @@ installCommandHelp() { # ------------------------------------------ # usage/options section # ------------------------------------------ - optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--env-file ]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--skip-backup]" + optionsAltList=("[--help|-h]" "[--config]" "[--bash-framework-config ]" "[--verbose|-v]" "[-vv]" "[-vvv]" "[--log-level ]" "[--log-file ]" "[--display-level ]" "[--no-color]" "[--theme ]" "[--version]" "[--quiet|-q]" "[--skip-backup]" ) Array::wrap2 " " 80 2 "${__HELP_TITLE_COLOR}USAGE:${__RESET_COLOR}" \ "install" "${optionsAltList[@]}" @@ -1542,12 +1650,6 @@ installCommandHelp() { - echo -e " ${__HELP_OPTION_COLOR}--env-file ${__HELP_NORMAL} {list} (optional)" - Array::wrap2 ' ' 76 4 " " "Load the specified env file (deprecated, please use --bash-framework-config option instead)" - echo - - - echo -e " ${__HELP_OPTION_COLOR}--log-level ${__HELP_NORMAL} {single}" Array::wrap2 ' ' 76 4 " " "Set log level" echo @@ -1652,9 +1754,6 @@ installCommandParse "$@" MAIN_FUNCTION_NAME="main" main() { -Linux::requireExecutedAsUser -Linux::requireTarCommand - if ! command -v parallel &>/dev/null; then Log::displayInfo "We will install GNU parallel software, please enter you sudo password" sudo apt-get update || true @@ -1680,6 +1779,7 @@ if [[ -d "${HOME}/.bash-tools" ]]; then Log::displayInfo "Updating configuration" cp -R --no-clobber "${BASH_TOOLS_ROOT_DIR}/conf/." "${HOME}/.bash-tools" + cp "${BASH_TOOLS_ROOT_DIR}/conf/defaultEnv/.env" "${HOME}/.bash-tools" if [[ "${FRAMEWORK_ROOT_DIR}/conf/.env" -nt "${HOME}/.bash-tools/.env" ]]; then Log::displayWarning "${FRAMEWORK_ROOT_DIR}/conf/.env is newer than ${HOME}/.bash-tools/.env, compare the files to check if some updates need to be applied" else @@ -1688,7 +1788,8 @@ if [[ -d "${HOME}/.bash-tools" ]]; then else Log::displayInfo "Installing configuration in ~/.bash-tools" mkdir -p "${HOME}/.bash-tools" - cp -R "${BASE_DIR}/conf/." "${HOME}/.bash-tools" + cp -R "${BASH_TOOLS_ROOT_DIR}/conf/." "${HOME}/.bash-tools" + cp "${BASH_TOOLS_ROOT_DIR}/conf/defaultEnv/.env" "${HOME}/.bash-tools" fi } diff --git a/src/BashTools/Conf/requireLoad.bats b/src/BashTools/Conf/requireLoad.bats index e0e77315..63035cd9 100755 --- a/src/BashTools/Conf/requireLoad.bats +++ b/src/BashTools/Conf/requireLoad.bats @@ -11,7 +11,7 @@ setup() { export TMPDIR="${BATS_TEST_TMPDIR}" export HOME="${BATS_TEST_TMPDIR}/home" export BASH_FRAMEWORK_THEME="noColor" - export bashToolsDefaultConfigTemplate="$(cat "${rootDir}/conf/.env")" + export bashToolsDefaultConfigTemplate="$(cat "${rootDir}/conf/defaultEnv/.env")" } function BashTools::Conf::requireLoad::envFileDoesNotExist { #@test @@ -25,7 +25,7 @@ function BashTools::Conf::requireLoad::envFileDoesNotExist { #@test function BashTools::Conf::requireLoad::envFileWithApiKeyExists { #@test mkdir -p "${HOME}/.bash-tools" - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" sed -i -E -e 's/^POSTMAN_API_KEY=/POSTMAN_API_KEY=fake2/' "${HOME}/.bash-tools/.env" local status=0 BashTools::Conf::requireLoad >"${BATS_TEST_TMPDIR}/result" 2>&1 || status=$? @@ -37,7 +37,7 @@ function BashTools::Conf::requireLoad::envFileWithApiKeyExists { #@test function BashTools::Conf::requireLoad::envFileExistsMissingApiKey { #@test mkdir -p "${HOME}/.bash-tools" - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" sed -i -E -e 's/^POSTMAN_API_KEY=//' "${HOME}/.bash-tools/.env" local status=0 BashTools::Conf::requireLoad >"${BATS_TEST_TMPDIR}/result" 2>&1 || status=$? @@ -50,7 +50,7 @@ function BashTools::Conf::requireLoad::envFileExistsMissingApiKey { #@test function BashTools::Conf::requireLoad::envFileImpossibleToLoad { #@test mkdir -p "${HOME}/.bash-tools" - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" echo "return 12" >>"${HOME}/.bash-tools/.env" run BashTools::Conf::requireLoad 2>&1 assert_failure 1 diff --git a/src/BashTools/Conf/requireLoad.sh b/src/BashTools/Conf/requireLoad.sh index 0a34b868..82734318 100755 --- a/src/BashTools/Conf/requireLoad.sh +++ b/src/BashTools/Conf/requireLoad.sh @@ -1,10 +1,13 @@ #!/bin/bash +read -r -d '\0' bashToolsDefaultConfigTemplate <<-EOM || true +#{{ include ".env" .Data . -}} +EOM + # @description loads ~/.bash-tools/.env if available # if not creates it from a default template # else check if new options need to be added BashTools::Conf::requireLoad() { - # @embed "${BASH_TOOLS_ROOT_DIR}/conf/.env" as bashToolsDefaultConfigTemplate BASH_TOOLS_ROOT_DIR="$(cd "${CURRENT_DIR}/${RELATIVE_FRAMEWORK_DIR_TO_CURRENT_DIR}" && pwd -P)" if [[ -d "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework/" ]]; then FRAMEWORK_ROOT_DIR="$(cd "${BASH_TOOLS_ROOT_DIR}/vendor/bash-tools-framework" && pwd -P)" @@ -32,7 +35,7 @@ BashTools::Conf::requireLoad() { ( echo "#!/usr/bin/env bash" # shellcheck disable=SC2154 - echo "${embed_file_bashToolsDefaultConfigTemplate}" + echo "${bashToolsDefaultConfigTemplate}" ) >"${envFile}" Log::displayInfo "Configuration file '${envFile}' created" else @@ -45,7 +48,7 @@ BashTools::Conf::requireLoad() { ) >>"${envFile}" fi fi - # shellcheck source=/conf/.env + # shellcheck source=/conf/defaultEnv/.env source "${envFile}" || { Log::displayError "impossible to load '${envFile}'" exit 1 diff --git a/src/_binaries/Converters/mysql2puml/mysql2puml-binary.yaml b/src/_binaries/Converters/mysql2puml/mysql2puml-binary.yaml index 3236b44e..a5ad19be 100644 --- a/src/_binaries/Converters/mysql2puml/mysql2puml-binary.yaml +++ b/src/_binaries/Converters/mysql2puml/mysql2puml-binary.yaml @@ -1,4 +1,5 @@ extends: + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -7,7 +8,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/mysql2puml" - relativeRootDirBasedOnTargetDir: .. + binData: commands: default: diff --git a/src/_binaries/Converters/mysql2puml/testsData/mysql2puml.help.txt b/src/_binaries/Converters/mysql2puml/testsData/mysql2puml.help.txt index 8561fa04..9b759192 100644 --- a/src/_binaries/Converters/mysql2puml/testsData/mysql2puml.help.txt +++ b/src/_binaries/Converters/mysql2puml/testsData/mysql2puml.help.txt @@ -4,7 +4,7 @@ USAGE: mysql2puml [OPTIONS] [ARGUMENTS] USAGE: mysql2puml [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] [--quiet|-q] [--skin ] @@ -25,9 +25,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE diff --git a/src/_binaries/Converters/mysql2puml/testsData/mysql2puml.png b/src/_binaries/Converters/mysql2puml/testsData/mysql2puml.png index 4cfcb8eb81a2b107fbc849ed717a640c088fa248..2f3081b62271fb6a52d8d923af5c96c67bad5b50 100644 GIT binary patch literal 56573 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%0DB4!qi}v-d6tqo8nc$Vu6VirO<#;c_`# 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

8cJUYQw?g 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 IBiHc%0rHCj6#xJL diff --git a/src/_binaries/Database/dbImport/dbImport-binary.yaml b/src/_binaries/Database/dbImport/dbImport-binary.yaml index b2c198bb..0cc15986 100644 --- a/src/_binaries/Database/dbImport/dbImport-binary.yaml +++ b/src/_binaries/Database/dbImport/dbImport-binary.yaml @@ -3,7 +3,9 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsMysqlCollationName.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsMysqlTarget.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsProfile.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsTables.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsMysqlSource.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -12,9 +14,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/dbImport" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: @@ -31,6 +31,7 @@ binData: 20: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbImport/dbImport-options.sh mainFile: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbImport/dbImport-main.sh help: Import source db into target db using eventual table filter. + longDescription: longDescriptionFunction args: - help: The name of the source/remote database. type: String diff --git a/src/_binaries/Database/dbImport/dbImport-options.sh b/src/_binaries/Database/dbImport/dbImport-options.sh index 7c3980a2..9ef914d0 100755 --- a/src/_binaries/Database/dbImport/dbImport-options.sh +++ b/src/_binaries/Database/dbImport/dbImport-options.sh @@ -12,10 +12,7 @@ declare PROFILES_DIR declare HOME_PROFILES_DIR beforeParseCallback() { - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad + defaultBeforeParseCallback Linux::requireRealpathCommand Linux::requireExecutedAsUser } @@ -33,32 +30,16 @@ optionHelpCallback() { } longDescriptionFunction() { - local profilesList="" - local dsnList="" - dsnList="$(Conf::getMergedList "dsn" "env")" - profilesList="$(Conf::getMergedList "dbImportProfiles" "sh" || true)" - - echo -e "${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL}" - echo -e "${PROFILES_DIR-configuration error}" - - echo -e "${__HELP_TITLE}User profiles directory:${__HELP_NORMAL}" - echo -e "${HOME_PROFILES_DIR-configuration error}" - echo -e "Allows to override profiles defined in 'Default profiles directory'" - - echo -e "${__HELP_TITLE}List of available profiles:${__HELP_NORMAL}" - echo -e "${profilesList}" - - echo -e "${__HELP_TITLE}List of available dsn:${__HELP_NORMAL}" - echo -e "${dsnList}" - - echo -e "${__HELP_TITLE}Aws s3 location:${__HELP_NORMAL}" - echo -e "${S3_BASE_URL}" + mysqlSourceLongDescription + echo + profileOptionLongDescription echo - echo -e "${__HELP_TITLE}Example 1: from one database to another one${__HELP_NORMAL}" - echo -e "${__HELP_EXAMPLE}TODO${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Examples${__HELP_NORMAL}" + echo -e " 1. from one database to another one" + echo -e " ${__HELP_EXAMPLE}dbImport --from-dsn localhost --target-dsn remote fromDb toDb${__HELP_NORMAL}" echo - echo -e "${__HELP_TITLE}Example 2: import from S3${__HELP_NORMAL}" - echo -e "${__HELP_EXAMPLE}TODO${__HELP_NORMAL}" + echo -e " 2. import from S3" + echo -e " ${__HELP_EXAMPLE}dbImport --from-aws awsFile.tar.gz --target-dsn localhost fromDb toDb${__HELP_NORMAL}" Db::checkRequirements } diff --git a/src/_binaries/Database/dbImport/testsData/dbImport.help.txt b/src/_binaries/Database/dbImport/testsData/dbImport.help.txt index 7c2bf8ff..887fd667 100644 --- a/src/_binaries/Database/dbImport/testsData/dbImport.help.txt +++ b/src/_binaries/Database/dbImport/testsData/dbImport.help.txt @@ -7,9 +7,9 @@ [--profile|-p ] [--tables ] [--skip-schema|-s] [--from-dsn|-f ] [--from-aws|-a ] [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] - [-vv] [-vvv] [--env-file ] [--log-level ] - [--log-file ] [--display-level ] [--no-color] - [--theme ] [--version] [--quiet|-q] + [-vv] [-vvv] [--log-level ] [--log-file ] + [--display-level ] [--no-color] [--theme ] [--version] + [--quiet|-q] ARGUMENTS: fromDbName {single} (mandatory) @@ -31,12 +31,10 @@ PROFILE OPTIONS: --profile, -p  {single} The name of the profile to use in order to include or exclude tables. - Default value: default --tables  {single} Import only table specified in the list. If aws mode, ignore profile option. - SOURCE OPTIONS: --skip-schema, -s {single} Avoids to import the schema. @@ -62,9 +60,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE @@ -85,6 +80,44 @@ --quiet, -q {single} Quiet mode, doesn't display any output. + +DESCRIPTION: + Data Source Name (DSN) + Default dsn directory: + /bash/conf/dsn + + User dsn directory: + home/.bash-tools/dsn + Allows to override dsn defined in "Default dsn directory" + + List of available dsn: + - default.local + - default.remote + - localhost-root + + Aws s3 location: + s3://s3server/exports + + Profiles + Default profiles directory: + /bash/conf/dbImportProfiles + + User profiles directory: + home/.bash-tools/dbImportProfiles + Allows to override profiles defined in "Default profiles directory" + + List of available profiles: + - all + - default + - none + + Examples + 1. from one database to another one + dbImport --from-dsn localhost --target-dsn remote fromDb toDb + + 2. import from S3 + dbImport --from-aws awsFile.tar.gz --target-dsn localhost fromDb toDb + VERSION: 3.0 AUTHOR: [François Chastanet](https://github.com/fchastanet) diff --git a/src/_binaries/Database/dbImportProfile/dbImportProfile-binary.yaml b/src/_binaries/Database/dbImportProfile/dbImportProfile-binary.yaml index 7249502c..11a1ec54 100644 --- a/src/_binaries/Database/dbImportProfile/dbImportProfile-binary.yaml +++ b/src/_binaries/Database/dbImportProfile/dbImportProfile-binary.yaml @@ -1,6 +1,9 @@ extends: + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsRatio.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsProfile.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsFromDsn.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -9,9 +12,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/dbImportProfile" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: @@ -25,31 +26,10 @@ binData: callbacks: - dbImportProfileCommandCallback@100 definitionFiles: - 20: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbImportProfile/dbImportProfile-options.sh - 99: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.sh + 99: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbImportProfile/dbImportProfile-options.sh mainFile: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbImportProfile/dbImportProfile-main.sh help: Generate optimized profiles to be used by dbImport. longDescription: longDescriptionFunction - options: - - variableName: optionProfile - group: OptionsGroup - type: String - help: optionProfileHelpFunction - helpValueName: profile - alts: - - --profile - - -p - - - variableName: optionRatio - group: OptionsGroup - type: String - help: optionRatioHelpFunction - helpValueName: ratio - defaultValue: 70 - alts: - - --ratio - - -r - args: - help: The name of the source/remote database. type: String diff --git a/src/_binaries/Database/dbImportProfile/dbImportProfile-main.sh b/src/_binaries/Database/dbImportProfile/dbImportProfile-main.sh index 0aecadda..6485b4f9 100755 --- a/src/_binaries/Database/dbImportProfile/dbImportProfile-main.sh +++ b/src/_binaries/Database/dbImportProfile/dbImportProfile-main.sh @@ -12,12 +12,6 @@ WHERE ORDER BY maxSize DESC EOM2 -# check dependencies -Linux::requireExecutedAsUser -Linux::requireRealpathCommand -Assert::commandExists mysql "sudo apt-get install -y mysql-client" -Assert::commandExists mysqlshow "sudo apt-get install -y mysql-client" - # create db instance declare -Agx dbFromInstance diff --git a/src/_binaries/Database/dbImportProfile/dbImportProfile-options.sh b/src/_binaries/Database/dbImportProfile/dbImportProfile-options.sh index 7cf29b78..c8a7cf90 100755 --- a/src/_binaries/Database/dbImportProfile/dbImportProfile-options.sh +++ b/src/_binaries/Database/dbImportProfile/dbImportProfile-options.sh @@ -3,36 +3,37 @@ declare defaultFromDsn="default.remote" # shellcheck disable=SC2034 declare PROFILES_DIR declare HOME_PROFILES_DIR +# shellcheck disable=SC2034 +defaultOptionProfile="" + +beforeParseCallback() { + defaultBeforeParseCallback + Linux::requireExecutedAsUser + Linux::requireRealpathCommand + Assert::commandExists mysql "sudo apt-get install -y mysql-client" + Assert::commandExists mysqlshow "sudo apt-get install -y mysql-client" +} initConf() { # shellcheck disable=SC2034 PROFILES_DIR="${BASH_TOOLS_ROOT_DIR}/conf/dbImportProfiles" + # shellcheck disable=SC2034 HOME_PROFILES_DIR="${HOME}/.bash-tools/dbImportProfiles" } +initProfileCommandCallback() { + : +} + optionHelpCallback() { dbImportProfileCommandHelp exit 0 } longDescriptionFunction() { - local profilesList="" - local dsnList="" - dsnList="$(Conf::getMergedList "dsn" "env")" - profilesList="$(Conf::getMergedList "dbImportProfiles" "sh" || true)" - - echo -e "${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL}" - echo -e "${PROFILES_DIR-configuration error}" + fromDsnOptionLongDescription echo - echo -e "${__HELP_TITLE}User profiles directory:${__HELP_NORMAL}" - echo -e "${HOME_PROFILES_DIR-configuration error}" - echo -e 'Allows to override profiles defined in "Default profiles directory"' - echo - echo -e "${__HELP_TITLE}List of available profiles:${__HELP_NORMAL}" - echo -e "${profilesList}" - echo - echo -e "${__HELP_TITLE}List of available dsn:${__HELP_NORMAL}" - echo -e "${dsnList}" + profileOptionLongDescription } optionProfileHelpFunction() { @@ -49,16 +50,6 @@ optionFromDsnHelpFunction() { echo } -optionRatioHelpFunction() { - Array::wrap2 " " 80 4 \ - " define the ratio to use (0 to 100% - default 70).\n" \ - "- 0 means profile will filter out all the tables\n" \ - "- 100 means profile will keep all the tables.\n" \ - "Eg: 70 means that tables with size(table+index)\n" \ - "that are greater than 70% of the max table size will be excluded." - echo -} - dbImportProfileCommandCallback() { if [[ -z "${fromDbName}" ]]; then Log::fatal "you must provide fromDbName" diff --git a/src/_binaries/Database/dbImportProfile/dbImportProfile.bats b/src/_binaries/Database/dbImportProfile/dbImportProfile.bats index 57ee26f5..c397bc03 100755 --- a/src/_binaries/Database/dbImportProfile/dbImportProfile.bats +++ b/src/_binaries/Database/dbImportProfile/dbImportProfile.bats @@ -17,7 +17,8 @@ setup() { "${HOME}/.bash-tools/dbImportDumps" \ "${HOME}/.bash-tools/dbImportProfiles" cp "${BATS_TEST_DIRNAME}/testsData/dsn/"* "${HOME}/.bash-tools/dsn/" - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" + cp "${BATS_TEST_DIRNAME}/testsData/dbImportProfiles/"* "${HOME}/.bash-tools/dbImportProfiles/" touch "${HOME}/bin/mysql" "${HOME}/bin/mysqldump" "${HOME}/bin/mysqlshow" "${HOME}/bin/builtinCommandWrapper" chmod +x "${HOME}/bin/"* diff --git a/src/_binaries/Database/dbImportProfile/testsData/dbImportProfile.help.txt b/src/_binaries/Database/dbImportProfile/testsData/dbImportProfile.help.txt index 93a3a111..1fc8447f 100644 --- a/src/_binaries/Database/dbImportProfile/testsData/dbImportProfile.help.txt +++ b/src/_binaries/Database/dbImportProfile/testsData/dbImportProfile.help.txt @@ -2,16 +2,28 @@ Generate optimized profiles to be used by dbImport. USAGE: dbImportProfile [OPTIONS] [ARGUMENTS] -USAGE: dbImportProfile [--from-dsn|-f ] [--help|-h] [--config] +USAGE: dbImportProfile [--ratio|-r ] + [--profile|-p ] [--from-dsn|-f ] [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] - [--quiet|-q] [--profile|-p ] [--ratio|-r ] + [--quiet|-q] ARGUMENTS: fromDbName {single} (mandatory) The name of the source/remote database. +PROFILE OPTIONS: + --ratio, -r  {single} + define the ratio to use (0 to 100% - default 70). + - 0 means profile will filter out all the tables + - 100 means profile will keep all the tables. + Eg: 70 means that tables with size(table+index) + that are greater than 70% of the max table size will be excluded. + Default value: 70 + --profile, -p  {single} + The name of the profile to use in order to include or exclude tables. + SOURCE OPTIONS: --from-dsn, -f  {single} Target mysql server. @@ -29,9 +41,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE @@ -52,39 +61,33 @@ --quiet, -q {single} Quiet mode, doesn't display any output. -OPTIONS: - --profile, -p  {single} - The name of the profile to write in profiles directory. - - If not provided, the file name pattern will be 'auto__.sh' - --ratio, -r  {single} - define the ratio to use (0 to 100% - default 70). - - - 0 means profile will filter out all the tables - - - 100 means profile will keep all the tables. - - Eg: 70 means that tables with size(table+index) - - that are greater than 70% of the max table size will be excluded. - Default value: 70 - DESCRIPTION: -Default profiles directory: -/bash/conf/dbImportProfiles - -User profiles directory: -home/.bash-tools/dbImportProfiles -Allows to override profiles defined in "Default profiles directory" - -List of available profiles: - - -List of available dsn: - - default.local - - default.remote - - localhost-root + Data Source Name (DSN) + Default dsn directory: + /bash/conf/dsn + + User dsn directory: + home/.bash-tools/dsn + Allows to override dsn defined in "Default dsn directory" + + List of available dsn: + - default.local + - default.remote + - localhost-root + + Profiles + Default profiles directory: + /bash/conf/dbImportProfiles + + User profiles directory: + home/.bash-tools/dbImportProfiles + Allows to override profiles defined in "Default profiles directory" + + List of available profiles: + - all + - default + - none VERSION: 3.0 diff --git a/src/_binaries/Database/dbImportStream/dbImportStream-binary.yaml b/src/_binaries/Database/dbImportStream/dbImportStream-binary.yaml index a1012ed5..a1fb8e42 100644 --- a/src/_binaries/Database/dbImportStream/dbImportStream-binary.yaml +++ b/src/_binaries/Database/dbImportStream/dbImportStream-binary.yaml @@ -1,7 +1,9 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsProfile.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsTables.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsMysqlTarget.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -10,9 +12,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/dbImportStream" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: @@ -27,7 +27,6 @@ binData: - dbImportStreamCommandCallback@100 definitionFiles: 20: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbImportStream/dbImportStream-options.sh - 99: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.sh mainFile: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbImportStream/dbImportStream-main.sh help: Stream tar.gz file or gz file through mysql. longDescription: longDescriptionFunction diff --git a/src/_binaries/Database/dbImportStream/dbImportStream-options.sh b/src/_binaries/Database/dbImportStream/dbImportStream-options.sh index 7a7d923a..beb477a9 100755 --- a/src/_binaries/Database/dbImportStream/dbImportStream-options.sh +++ b/src/_binaries/Database/dbImportStream/dbImportStream-options.sh @@ -6,10 +6,7 @@ declare HOME_PROFILES_DIR declare defaultFromDsn="default.remote" beforeParseCallback() { - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad + defaultBeforeParseCallback Linux::requireExecutedAsUser Linux::requireRealpathCommand } @@ -17,6 +14,7 @@ beforeParseCallback() { initConf() { # shellcheck disable=SC2034 PROFILES_DIR="${BASH_TOOLS_ROOT_DIR}/conf/dbImportProfiles" + # shellcheck disable=SC2034 HOME_PROFILES_DIR="${HOME}/.bash-tools/dbImportProfiles" Db::checkRequirements } @@ -27,23 +25,9 @@ optionHelpCallback() { } longDescriptionFunction() { - local profilesList="" - local dsnList="" - dsnList="$(Conf::getMergedList "dsn" "env")" - profilesList="$(Conf::getMergedList "dbImportProfiles" "sh" || true)" - - echo -e "${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL}" - echo -e "${PROFILES_DIR-configuration error}" - echo - echo -e "${__HELP_TITLE}User profiles directory:${__HELP_NORMAL}" - echo -e "${HOME_PROFILES_DIR-configuration error}" - echo -e "Allows to override profiles defined in 'Default profiles directory'" - echo - echo -e "${__HELP_TITLE}List of available profiles:${__HELP_NORMAL}" - echo -e "${profilesList}" + fromDsnOptionLongDescription echo - echo -e "${__HELP_TITLE}List of available dsn:${__HELP_NORMAL}" - echo -e "${dsnList}" + profileOptionLongDescription } dbImportStreamCommandCallback() { diff --git a/src/_binaries/Database/dbImportStream/dbImportStream.bats b/src/_binaries/Database/dbImportStream/dbImportStream.bats index 27bcba65..5af80c7e 100755 --- a/src/_binaries/Database/dbImportStream/dbImportStream.bats +++ b/src/_binaries/Database/dbImportStream/dbImportStream.bats @@ -19,7 +19,8 @@ setup() { cp "${BATS_TEST_DIRNAME}/testsData/dsn/"* "${HOME}/.bash-tools/dsn/" touch "${HOME}/bin/mysql" "${HOME}/bin/mysqldump" "${HOME}/bin/mysqlshow" "${HOME}/bin/builtinCommandWrapper" chmod +x "${HOME}/bin/"* - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" + cp "${BATS_TEST_DIRNAME}/testsData/dbImportProfiles/"* "${HOME}/.bash-tools/dbImportProfiles/" export BASH_FRAMEWORK_COMMAND="builtinCommandWrapper" diff --git a/src/_binaries/Database/dbImportStream/testsData/dbImportProfiles/all.sh b/src/_binaries/Database/dbImportStream/testsData/dbImportProfiles/all.sh new file mode 100755 index 00000000..09b79b19 --- /dev/null +++ b/src/_binaries/Database/dbImportStream/testsData/dbImportProfiles/all.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# cat represents the whole list of tables +cat diff --git a/src/_binaries/Database/dbImportStream/testsData/dbImportProfiles/default.sh b/src/_binaries/Database/dbImportStream/testsData/dbImportProfiles/default.sh new file mode 100755 index 00000000..8cf9b92b --- /dev/null +++ b/src/_binaries/Database/dbImportStream/testsData/dbImportProfiles/default.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# cat represents the whole list of tables +cat | + grep -v '.*_log' | + grep -v '.*logs' | + grep -v '.*tracking' | + grep -v '.*stats' | + grep -v '.*history.*' | + # always finish by a cat to be sure the command does not return exit code != 0 + cat || { + # avoid failure on premature process close (check Bash::handlePipelineFailure) + declare exitCode=$?; if (( exitCode == 141 )); then exit 0; fi + exit "${exitCode}" + } diff --git a/src/_binaries/Database/dbImportStream/testsData/dbImportProfiles/none.sh b/src/_binaries/Database/dbImportStream/testsData/dbImportProfiles/none.sh new file mode 100755 index 00000000..5604fdca --- /dev/null +++ b/src/_binaries/Database/dbImportStream/testsData/dbImportProfiles/none.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# useful if you want to dump only the db structure + +# cat represents the whole list of tables +echo 'propel_migration' diff --git a/src/_binaries/Database/dbImportStream/testsData/dbImportStream.help.txt b/src/_binaries/Database/dbImportStream/testsData/dbImportStream.help.txt index c954c747..ca1e89ea 100644 --- a/src/_binaries/Database/dbImportStream/testsData/dbImportStream.help.txt +++ b/src/_binaries/Database/dbImportStream/testsData/dbImportStream.help.txt @@ -6,7 +6,7 @@ [--tables ] [--target-dsn|-t ] [--character-set|-c ] [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] [--quiet|-q] @@ -19,12 +19,10 @@ PROFILE OPTIONS: --profile, -p  {single} The name of the profile to use in order to include or exclude tables. - Default value: default --tables  {single} Import only table specified in the list. If aws mode, ignore profile option. - TARGET OPTIONS: --target-dsn, -t  {single} Dsn to use for target database. @@ -45,9 +43,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE @@ -70,20 +65,31 @@ DESCRIPTION: -Default profiles directory: -/bash/conf/dbImportProfiles - -User profiles directory: -home/.bash-tools/dbImportProfiles -Allows to override profiles defined in 'Default profiles directory' - -List of available profiles: - - -List of available dsn: - - default.local - - default.remote - - localhost-root + Data Source Name (DSN) + Default dsn directory: + /bash/conf/dsn + + User dsn directory: + home/.bash-tools/dsn + Allows to override dsn defined in "Default dsn directory" + + List of available dsn: + - default.local + - default.remote + - localhost-root + + Profiles + Default profiles directory: + /bash/conf/dbImportProfiles + + User profiles directory: + home/.bash-tools/dbImportProfiles + Allows to override profiles defined in "Default profiles directory" + + List of available profiles: + - all + - default + - none VERSION: 3.0 diff --git a/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases-binary.yaml b/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases-binary.yaml index cd5110ec..3ae2f25a 100644 --- a/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases-binary.yaml +++ b/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases-binary.yaml @@ -2,6 +2,7 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsJobs.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsFromDsn.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -10,9 +11,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/dbQueryAllDatabases" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: @@ -28,12 +27,11 @@ binData: everyArgumentCallbacks: - dbQueryAllDatabasesEveryArgumentCallback definitionFiles: - 11: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.sh 99: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases-options.sh mainFile: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases-main.sh help: "Execute a query on multiple databases to generate a tsv format - report.\\n The query can be parallelized on multiple databases." + report.\nThe query can be parallelized on multiple databases." longDescription: longDescriptionFunction optionGroups: groupQueryOptions: diff --git a/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases-options.sh b/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases-options.sh index 82e0f446..27d491b3 100755 --- a/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases-options.sh +++ b/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases-options.sh @@ -11,10 +11,7 @@ declare copyrightBeginYear="2020" declare defaultFromDsn="default.remote" beforeParseCallback() { - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad + defaultBeforeParseCallback Linux::requireExecutedAsUser Linux::requireRealpathCommand } @@ -46,32 +43,31 @@ optionSeparatorCallback() { longDescriptionFunction() { local example1=$'dbQueryAllDatabases databaseSize -j 12 --separator "|" --bar 2>/dev/null | column -s "|" -t -n -c 40' - local dsnList queriesList - dsnList="$(Conf::getMergedList "dsn" "env" " - ")" - queriesList="$(Conf::getMergedList "dbQueries" "sql" " - " || true)" + local queriesList + queriesList="$(Conf::getMergedList "dbQueries" "sql" " - " || true)" - echo -e "${__HELP_TITLE} LIST OF AVAILABLE DSN:${__HELP_NORMAL}" - echo -e "${dsnList}" + fromDsnOptionLongDescription echo - echo -e "${__HELP_TITLE} DEFAULT QUERIES DIRECTORY:${__HELP_NORMAL}" - echo -e " ${QUERIES_DIR-configuration error}" + echo -e " ${__HELP_TITLE}QUERIES${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default queries directory:${__HELP_NORMAL}" + echo -e " ${QUERIES_DIR-configuration error}" echo - echo -e "${__HELP_TITLE} USER QUERIES DIRECTORY:${__HELP_NORMAL}" - echo -e " ${HOME_QUERIES_DIR-configuration error}" - echo -e " Allows to override queries defined in 'Default queries directory'" + echo -e " ${__HELP_TITLE}User queries directory:${__HELP_NORMAL}" + echo -e " ${HOME_QUERIES_DIR-configuration error}" + echo -e " Allows to override queries defined in 'Default queries directory'" echo - echo -e "${__HELP_TITLE} LIST OF AVAILABLE QUERIES:${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}List of available queries:${__HELP_NORMAL}" echo -e "${queriesList}" echo - echo -e "${__HELP_TITLE} EXAMPLES:${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}EXAMPLES:${__HELP_NORMAL}" echo -e " ${__HELP_EXAMPLE}${example1}${__HELP_NORMAL}" } argQueryHelpFunction() { Array::wrap2 " " 80 6 \ - " Query to execute" "\n" \ - "- , try to execute the mysql query provided by the file" "\n" \ - '- , search for query file in queries directory (see below)' "\n" \ + " Query to execute" "\r" \ + "- , try to execute the mysql query provided by the file" "\r" \ + '- , search for query file in queries directory (see below)' "\r" \ '- else the argument is interpreted as query string' } diff --git a/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases.bats b/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases.bats index baf31aa8..3cab8ea0 100755 --- a/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases.bats +++ b/src/_binaries/Database/dbQueryAllDatabases/dbQueryAllDatabases.bats @@ -17,12 +17,13 @@ setup() { cp "${BATS_TEST_DIRNAME}/testsData/pv" "${HOME}/bin" cp "${BATS_TEST_DIRNAME}/testsData/gawk" "${HOME}/bin" cp "${BATS_TEST_DIRNAME}/testsData/gawk" "${HOME}/bin/awk" - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" touch \ "${HOME}/bin/mysql" \ "${HOME}/bin/mysqldump" \ "${HOME}/bin/mysqlshow" \ - "${HOME}/bin/builtinCommandWrapper" + "${HOME}/bin/builtinCommandWrapper" \ + "${HOME}/.bash-tools/dbQueries/fakeQuery.sql" chmod +x "${HOME}/bin/"* export BASH_FRAMEWORK_COMMAND="builtinCommandWrapper" @@ -32,10 +33,12 @@ setup() { } teardown() { + rm -Rf "${HOME}" || true unstub_all } function Database::dbQueryAllDatabases::display_help { #@test + testCommand "${binDir}/dbQueryAllDatabases" dbQueryAllDatabases.help.txt } diff --git a/src/_binaries/Database/dbQueryAllDatabases/testsData/dbQueryAllDatabases.help.txt b/src/_binaries/Database/dbQueryAllDatabases/testsData/dbQueryAllDatabases.help.txt index c3451ef0..723a2944 100644 --- a/src/_binaries/Database/dbQueryAllDatabases/testsData/dbQueryAllDatabases.help.txt +++ b/src/_binaries/Database/dbQueryAllDatabases/testsData/dbQueryAllDatabases.help.txt @@ -1,34 +1,28 @@ SYNOPSIS: Execute a query on multiple databases to generate a tsv format report. - The query can be parallelized on multiple databases. USAGE: dbQueryAllDatabases [OPTIONS] [ARGUMENTS] USAGE: dbQueryAllDatabases [--jobs|-j ] [--bar|-b] [--from-dsn|-f ] [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] [--quiet|-q] [--separator|-s ] ARGUMENTS: argQuery {single} (mandatory) - Query to execute - - - , try to execute the mysql query provided by the file - - - , search for query file in queries directory (see below) - + Query to execute + - , try to execute the mysql query provided by the file + - , search for query file in queries directory (see below) - else the argument is interpreted as query string JOB OPTIONS: --jobs, -j  {single} The number of databases to query in parallel. Default value: 1 --bar, -b {single} - - Show progress as a progress bar. In the bar is shown: % of jobs completed, - estimated seconds left, and number of jobs started. - + Show progress as a progress bar. In the bar is shown: % of jobs + completed, estimated seconds left, and number of jobs started. SOURCE OPTIONS: --from-dsn, -f  {single} @@ -47,9 +41,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE @@ -77,21 +68,30 @@ DESCRIPTION: - LIST OF AVAILABLE DSN: - - dsn_local - - dsn_valid + Data Source Name (DSN) + Default dsn directory: + /bash/conf/dsn + + User dsn directory: + home/.bash-tools/dsn + Allows to override dsn defined in "Default dsn directory" - DEFAULT QUERIES DIRECTORY: - /bash/conf/dbQueries + List of available dsn: + - dsn_local + - dsn_valid - USER QUERIES DIRECTORY: - home/.bash-tools/dbQueries - Allows to override queries defined in 'Default queries directory' + QUERIES + Default queries directory: + /bash/conf/dbQueries - LIST OF AVAILABLE QUERIES: + User queries directory: + home/.bash-tools/dbQueries + Allows to override queries defined in 'Default queries directory' + List of available queries: + - fakeQuery - EXAMPLES: + EXAMPLES: dbQueryAllDatabases databaseSize -j 12 --separator "|" --bar 2>/dev/null | column -s "|" -t -n -c 40 VERSION: 3.0 diff --git a/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases-binary.yaml b/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases-binary.yaml index cf0e8bb7..9a9d8b5a 100644 --- a/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases-binary.yaml +++ b/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases-binary.yaml @@ -2,6 +2,8 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsJobs.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsFromDsn.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -10,9 +12,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/dbScriptAllDatabases" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: @@ -26,7 +26,6 @@ binData: callbacks: - dbScriptAllDatabasesCommandCallback@100 definitionFiles: - 11: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.sh 20: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases-options.sh mainFile: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases-main.sh help: | @@ -57,8 +56,8 @@ binData: group: groupScriptsOptions type: StringArray help: - If provided will check only this db, otherwise script will be - executed on all dbs of mysql server. + "If provided will check only this db,\notherwise script will be + executed on all dbs of mysql server." helpValueName: dbName alts: - --database diff --git a/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases-options.sh b/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases-options.sh index abd36d41..e0c11658 100755 --- a/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases-options.sh +++ b/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases-options.sh @@ -8,14 +8,10 @@ declare defaultFromDsn="default.remote" declare outputDirectory="${HOME}/.bash-tools/output" beforeParseCallback() { + defaultBeforeParseCallback Assert::commandExists mysql "sudo apt-get install -y mysql-client" Assert::commandExists mysqlshow "sudo apt-get install -y mysql-client" Assert::commandExists parallel "sudo apt-get install -y parallel" - - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad Linux::requireExecutedAsUser Linux::requireRealpathCommand } @@ -33,37 +29,36 @@ optionHelpCallback() { } longDescriptionFunction() { - local dsnList scriptsList - dsnList="$(Conf::getMergedList "dsn" "env")" - scriptsList="$(Conf::getMergedList "dbScripts" "sh")" + local scriptsList + scriptsList="$(Conf::getMergedList "dbScripts" "sh" " - " || true)" - echo -e "${__HELP_TITLE}NOTE:${__HELP_NORMAL}" - echo -e "the use of output, log-format, verbose options highly depends on the script used" - echo - echo -e "${__HELP_TITLE}LIST OF AVAILABLE DSN:${__HELP_NORMAL}" - echo -e "${dsnList}" + fromDsnOptionLongDescription echo - echo -e "${__HELP_TITLE}DEFAULT SCRIPTS DIRECTORY:${__HELP_NORMAL}" - echo -e "${SCRIPTS_DIR-configuration error}" + echo -e " ${__HELP_TITLE}SCRIPTS${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default scripts directory:${__HELP_NORMAL}" + echo -e " ${SCRIPTS_DIR-configuration error}" echo - echo -e "${__HELP_TITLE}USER SCRIPTS DIRECTORY:${__HELP_NORMAL}" - echo -e "${HOME_SCRIPTS_DIR-configuration error}" - echo -e "Allows to override queries defined in 'Default scripts directory'" + echo -e " ${__HELP_TITLE}User scripts directory:${__HELP_NORMAL}" + echo -e " ${HOME_SCRIPTS_DIR-configuration error}" + echo -e " Allows to override queries defined in 'Default scripts directory'" echo - echo -e "${__HELP_TITLE}LIST OF AVAILABLE SCRIPTS:${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}List of available scripts:${__HELP_NORMAL}" echo -e "${scriptsList}" echo - echo -e "${__HELP_TITLE}EXAMPLES:${__HELP_NORMAL} script conf/dbScripts/extractData.sh" - echo -e " executes query databaseSize (see conf/dbQueries/databaseSize.sql) on each db and log the result in log file in default output dir, call it using" + echo -e " ${__HELP_TITLE}NOTE:${__HELP_NORMAL}" + echo -e " the use of output, log-format, verbose options highly depends on the script used" + echo + echo -e " ${__HELP_TITLE}EXAMPLES:${__HELP_NORMAL} script conf/dbScripts/extractData.sh" + echo -e " 1. executes query databaseSize (see conf/dbQueries/databaseSize.sql) on each db and log the result in log file in default output dir, call it using" echo -e " ${__HELP_EXAMPLE}$0 -j 10 extractData databaseSize${__HELP_NORMAL}" echo - echo -e " executes query databaseSize on each db and display the result on stdout (2>/dev/null hides information messages)" + echo -e " 2. executes query databaseSize on each db and display the result on stdout (2>/dev/null hides information messages)" echo -e " ${__HELP_EXAMPLE}$0 -j 10 --log-format none extractData databaseSize${__HELP_NORMAL}" echo - echo -e " use --verbose to get some debug information" + echo -e " 3. use --verbose to get some debug information" echo -e " ${__HELP_EXAMPLE}$0 -j 10 --log-format none --verbose extractData databaseSize${__HELP_NORMAL}" echo - echo -e "${__HELP_TITLE}USE CASES:${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}USE CASES:${__HELP_NORMAL}" echo -e " you can use this script in order to check that each db model conforms with your ORM schema" echo -e " simply create a new script in conf/dbQueries that will call your orm schema checker" echo diff --git a/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases.bats b/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases.bats index a032b493..20dfe1e9 100755 --- a/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases.bats +++ b/src/_binaries/Database/dbScriptAllDatabases/dbScriptAllDatabases.bats @@ -15,11 +15,12 @@ setup() { "${HOME}/.bash-tools/dbQueries" \ "${HOME}/.bash-tools/dbScripts" cp "${BATS_TEST_DIRNAME}/testsData/pv" "${HOME}/bin" - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" touch \ "${HOME}/bin/mysqldump" \ "${HOME}/bin/mysqlshow" \ - "${HOME}/bin/builtinCommandWrapper" + "${HOME}/bin/builtinCommandWrapper" \ + "${HOME}/.bash-tools/dbScripts/fakeScript.sh" chmod +x "${HOME}/bin/"* export BASH_FRAMEWORK_COMMAND="builtinCommandWrapper" diff --git a/src/_binaries/Database/dbScriptAllDatabases/dbScriptOneDatabase.sh b/src/_binaries/Database/dbScriptAllDatabases/dbScriptOneDatabase.sh index 9e0b7b86..2ca4d01b 100755 --- a/src/_binaries/Database/dbScriptAllDatabases/dbScriptOneDatabase.sh +++ b/src/_binaries/Database/dbScriptAllDatabases/dbScriptOneDatabase.sh @@ -44,9 +44,7 @@ unknownArg() { } beforeParseCallback() { - Env::requireLoad - UI::requireTheme - Log::requireLoad + defaultBeforeParseCallback Linux::requireExecutedAsUser Linux::requireRealpathCommand init diff --git a/src/_binaries/Database/dbScriptAllDatabases/extractData-binary.yaml b/src/_binaries/Database/dbScriptAllDatabases/extractData-binary.yaml index d9a4bea0..5ebd536f 100644 --- a/src/_binaries/Database/dbScriptAllDatabases/extractData-binary.yaml +++ b/src/_binaries/Database/dbScriptAllDatabases/extractData-binary.yaml @@ -1,5 +1,6 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -23,6 +24,5 @@ binData: unknownArgumentCallbacks: - unknownArg definitionFiles: - 11: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.sh 99: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbScriptAllDatabases/dbScriptOneDatabase.sh mainFile: ${BASH_TOOLS_ROOT_DIR}/src/_binaries/Database/dbScriptAllDatabases/extractData.sh diff --git a/src/_binaries/Database/dbScriptAllDatabases/testsData/dbScriptAllDatabases.help.txt b/src/_binaries/Database/dbScriptAllDatabases/testsData/dbScriptAllDatabases.help.txt index 682d92fc..4c699c78 100644 --- a/src/_binaries/Database/dbScriptAllDatabases/testsData/dbScriptAllDatabases.help.txt +++ b/src/_binaries/Database/dbScriptAllDatabases/testsData/dbScriptAllDatabases.help.txt @@ -6,7 +6,7 @@ USAGE: dbScriptAllDatabases [--jobs|-j ] [--bar|-b] [--from-dsn|-f ] [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] [--quiet|-q] [--database ] [--output|-o ] [--log-format|-l ] @@ -22,10 +22,8 @@ The number of databases to query in parallel. Default value: 1 --bar, -b {single} - - Show progress as a progress bar. In the bar is shown: % of jobs completed, - estimated seconds left, and number of jobs started. - + Show progress as a progress bar. In the bar is shown: % of jobs + completed, estimated seconds left, and number of jobs started. SOURCE OPTIONS: --from-dsn, -f  {single} @@ -44,9 +42,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE @@ -69,8 +64,8 @@ SCRIPTS OPTIONS: --database  {single} - If provided will check only this db, otherwise script will be executed o - n all dbs of mysql server. + If provided will check only this db, + otherwise script will be executed on all dbs of mysql server. --output, -o  {single} Output directory, see log-format option. --log-format, -l  {single} @@ -80,34 +75,43 @@ DESCRIPTION: -NOTE: -the use of output, log-format, verbose options highly depends on the script used + Data Source Name (DSN) + Default dsn directory: + /bash/conf/dsn + + User dsn directory: + home/.bash-tools/dsn + Allows to override dsn defined in "Default dsn directory" -LIST OF AVAILABLE DSN: - - dsn_local - - dsn_valid + List of available dsn: + - dsn_local + - dsn_valid -DEFAULT SCRIPTS DIRECTORY: -/bash/conf/dbScripts + SCRIPTS + Default scripts directory: + /bash/conf/dbScripts -USER SCRIPTS DIRECTORY: -home/.bash-tools/dbScripts -Allows to override queries defined in 'Default scripts directory' + User scripts directory: + home/.bash-tools/dbScripts + Allows to override queries defined in 'Default scripts directory' -LIST OF AVAILABLE SCRIPTS: + List of available scripts: + - fakeScript + NOTE: + the use of output, log-format, verbose options highly depends on the script used -EXAMPLES: script conf/dbScripts/extractData.sh - executes query databaseSize (see conf/dbQueries/databaseSize.sql) on each db and log the result in log file in default output dir, call it using + EXAMPLES: script conf/dbScripts/extractData.sh + 1. executes query databaseSize (see conf/dbQueries/databaseSize.sql) on each db and log the result in log file in default output dir, call it using /bash/bin/dbScriptAllDatabases -j 10 extractData databaseSize - executes query databaseSize on each db and display the result on stdout (2>/dev/null hides information messages) + 2. executes query databaseSize on each db and display the result on stdout (2>/dev/null hides information messages) /bash/bin/dbScriptAllDatabases -j 10 --log-format none extractData databaseSize - use --verbose to get some debug information + 3. use --verbose to get some debug information /bash/bin/dbScriptAllDatabases -j 10 --log-format none --verbose extractData databaseSize -USE CASES: + USE CASES: you can use this script in order to check that each db model conforms with your ORM schema simply create a new script in conf/dbQueries that will call your orm schema checker diff --git a/src/_binaries/Docker/cli/cli-binary.yaml b/src/_binaries/Docker/cli/cli-binary.yaml index 979ea398..65b0131f 100644 --- a/src/_binaries/Docker/cli/cli-binary.yaml +++ b/src/_binaries/Docker/cli/cli-binary.yaml @@ -1,5 +1,6 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -8,9 +9,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/cli" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: diff --git a/src/_binaries/Docker/cli/cli-options.sh b/src/_binaries/Docker/cli/cli-options.sh index cc8f297f..0a112e03 100755 --- a/src/_binaries/Docker/cli/cli-options.sh +++ b/src/_binaries/Docker/cli/cli-options.sh @@ -13,10 +13,7 @@ declare PROFILES_DIR declare HOME_PROFILES_DIR beforeParseCallback() { - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad + defaultBeforeParseCallback Linux::requireRealpathCommand Assert::commandExists docker "check https://docs.docker.com/engine/install/ubuntu/" } diff --git a/src/_binaries/Docker/cli/cli.bats b/src/_binaries/Docker/cli/cli.bats index f76dd647..dd5bbd21 100755 --- a/src/_binaries/Docker/cli/cli.bats +++ b/src/_binaries/Docker/cli/cli.bats @@ -12,6 +12,7 @@ setup() { touch "${HOME}/bin/docker" chmod +x "${HOME}/bin/"* cp -R "${rootDir}/conf" "${HOME}/.bash-tools" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools" export PATH="${PATH}:${HOME}/bin" } diff --git a/src/_binaries/Docker/cli/testsData/cli.help.txt b/src/_binaries/Docker/cli/testsData/cli.help.txt index 7839be46..aced4feb 100644 --- a/src/_binaries/Docker/cli/testsData/cli.help.txt +++ b/src/_binaries/Docker/cli/testsData/cli.help.txt @@ -4,7 +4,7 @@ USAGE: cli [OPTIONS] [ARGUMENTS] USAGE: cli [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] [--quiet|-q] @@ -45,9 +45,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE diff --git a/src/_binaries/Git/gitIsAncestorOf/gitIsAncestorOf-binary.yaml b/src/_binaries/Git/gitIsAncestorOf/gitIsAncestorOf-binary.yaml index e64ec961..736f4a23 100644 --- a/src/_binaries/Git/gitIsAncestorOf/gitIsAncestorOf-binary.yaml +++ b/src/_binaries/Git/gitIsAncestorOf/gitIsAncestorOf-binary.yaml @@ -1,6 +1,7 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/Git/gitToolsDefaultOptions.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -9,9 +10,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/gitIsAncestorOf" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: diff --git a/src/_binaries/Git/gitIsAncestorOf/gitIsAncestorOf.bats b/src/_binaries/Git/gitIsAncestorOf/gitIsAncestorOf.bats index 06a86e19..33c1bea2 100755 --- a/src/_binaries/Git/gitIsAncestorOf/gitIsAncestorOf.bats +++ b/src/_binaries/Git/gitIsAncestorOf/gitIsAncestorOf.bats @@ -10,7 +10,7 @@ setup() { export HOME="${BATS_TEST_TMPDIR}/home" export BASH_FRAMEWORK_ENV_FILEPATH="${BATS_TEST_DIRNAME}/testsData/.env" mkdir -p "${HOME}/.bash-tools" - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" } teardown() { diff --git a/src/_binaries/Git/gitIsAncestorOf/testsData/gitIsAncestorOf.help.txt b/src/_binaries/Git/gitIsAncestorOf/testsData/gitIsAncestorOf.help.txt index 054c5c23..b7a62a3e 100644 --- a/src/_binaries/Git/gitIsAncestorOf/testsData/gitIsAncestorOf.help.txt +++ b/src/_binaries/Git/gitIsAncestorOf/testsData/gitIsAncestorOf.help.txt @@ -4,7 +4,7 @@ USAGE: gitIsAncestorOf [OPTIONS] [ARGUMENTS] USAGE: gitIsAncestorOf [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] [--quiet|-q] @@ -27,9 +27,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE diff --git a/src/_binaries/Git/gitIsBranch/gitIsBranch-binary.yaml b/src/_binaries/Git/gitIsBranch/gitIsBranch-binary.yaml index 743d2325..a77ef75a 100644 --- a/src/_binaries/Git/gitIsBranch/gitIsBranch-binary.yaml +++ b/src/_binaries/Git/gitIsBranch/gitIsBranch-binary.yaml @@ -1,6 +1,7 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/Git/gitToolsDefaultOptions.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -9,9 +10,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/gitIsBranch" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: diff --git a/src/_binaries/Git/gitIsBranch/gitIsBranch.bats b/src/_binaries/Git/gitIsBranch/gitIsBranch.bats index 83564465..c7998a68 100755 --- a/src/_binaries/Git/gitIsBranch/gitIsBranch.bats +++ b/src/_binaries/Git/gitIsBranch/gitIsBranch.bats @@ -10,7 +10,7 @@ setup() { export HOME="${BATS_TEST_TMPDIR}/home" export BASH_FRAMEWORK_ENV_FILEPATH="${BATS_TEST_DIRNAME}/testsData/.env" mkdir -p "${HOME}/.bash-tools" - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" } teardown() { diff --git a/src/_binaries/Git/gitIsBranch/testsData/gitIsBranch.help.txt b/src/_binaries/Git/gitIsBranch/testsData/gitIsBranch.help.txt index a844954f..1d03b7b8 100644 --- a/src/_binaries/Git/gitIsBranch/testsData/gitIsBranch.help.txt +++ b/src/_binaries/Git/gitIsBranch/testsData/gitIsBranch.help.txt @@ -4,7 +4,7 @@ USAGE: gitIsBranch [OPTIONS] [ARGUMENTS] USAGE: gitIsBranch [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] [--quiet|-q] @@ -25,9 +25,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE diff --git a/src/_binaries/Git/gitRenameBranch/gitRenameBranch-binary.yaml b/src/_binaries/Git/gitRenameBranch/gitRenameBranch-binary.yaml index d31c5e3e..8d7ef91e 100644 --- a/src/_binaries/Git/gitRenameBranch/gitRenameBranch-binary.yaml +++ b/src/_binaries/Git/gitRenameBranch/gitRenameBranch-binary.yaml @@ -1,6 +1,7 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/Git/gitToolsDefaultOptions.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -9,9 +10,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/gitRenameBranch" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: diff --git a/src/_binaries/Git/gitRenameBranch/gitRenameBranch.bats b/src/_binaries/Git/gitRenameBranch/gitRenameBranch.bats index 54f2feab..99d616d9 100755 --- a/src/_binaries/Git/gitRenameBranch/gitRenameBranch.bats +++ b/src/_binaries/Git/gitRenameBranch/gitRenameBranch.bats @@ -10,7 +10,7 @@ setup() { export HOME="${BATS_TEST_TMPDIR}/home" mkdir -p "${HOME}/.bash-tools" - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" mkdir "${BATS_TEST_TMPDIR}/gitRepo" mkdir "${BATS_TEST_TMPDIR}/gitRepoFake" diff --git a/src/_binaries/Git/gitRenameBranch/testsData/gitRenameBranch.help.txt b/src/_binaries/Git/gitRenameBranch/testsData/gitRenameBranch.help.txt index c14be34d..23d53f7a 100644 --- a/src/_binaries/Git/gitRenameBranch/testsData/gitRenameBranch.help.txt +++ b/src/_binaries/Git/gitRenameBranch/testsData/gitRenameBranch.help.txt @@ -4,7 +4,7 @@ USAGE: gitRenameBranch [OPTIONS] [ARGUMENTS] USAGE: gitRenameBranch [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] [--quiet|-q] [--assume-yes|--yes|-y] [--push|-p] [--delete|-d] @@ -27,9 +27,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE diff --git a/src/_binaries/Git/gitToolsDefaultOptions.sh b/src/_binaries/Git/gitToolsDefaultOptions.sh index 210e4067..994b3563 100755 --- a/src/_binaries/Git/gitToolsDefaultOptions.sh +++ b/src/_binaries/Git/gitToolsDefaultOptions.sh @@ -1,11 +1,8 @@ #!/usr/bin/env bash beforeParseCallback() { + defaultBeforeParseCallback Linux::requireExecutedAsUser - BashTools::Conf::requireLoad - Env::requireLoad - UI::requireTheme - Log::requireLoad } declare optionRedirectCmdOutputs="" diff --git a/src/_binaries/Github/upgradeGithubRelease/testsData/upgradeGithubRelease.help.txt b/src/_binaries/Github/upgradeGithubRelease/testsData/upgradeGithubRelease.help.txt index 0917fa79..38a220e6 100644 --- a/src/_binaries/Github/upgradeGithubRelease/testsData/upgradeGithubRelease.help.txt +++ b/src/_binaries/Github/upgradeGithubRelease/testsData/upgradeGithubRelease.help.txt @@ -4,7 +4,7 @@ USAGE: upgradeGithubRelease [OPTIONS] [ARGUMENTS] USAGE: upgradeGithubRelease [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] [--quiet|-q] [--version-arg ] [--current-version|-c ] [--exact-version|-e ] @@ -31,9 +31,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE diff --git a/src/_binaries/Github/upgradeGithubRelease/upgradeGithubRelease-binary.yaml b/src/_binaries/Github/upgradeGithubRelease/upgradeGithubRelease-binary.yaml index b0edc529..0d7bd316 100644 --- a/src/_binaries/Github/upgradeGithubRelease/upgradeGithubRelease-binary.yaml +++ b/src/_binaries/Github/upgradeGithubRelease/upgradeGithubRelease-binary.yaml @@ -1,5 +1,6 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -8,9 +9,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/upgradeGithubRelease" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: diff --git a/src/_binaries/Github/upgradeGithubRelease/upgradeGithubRelease.bats b/src/_binaries/Github/upgradeGithubRelease/upgradeGithubRelease.bats index d739e202..09a65140 100755 --- a/src/_binaries/Github/upgradeGithubRelease/upgradeGithubRelease.bats +++ b/src/_binaries/Github/upgradeGithubRelease/upgradeGithubRelease.bats @@ -10,7 +10,7 @@ setup() { export HOME="${BATS_TEST_TMPDIR}/home" export BASH_FRAMEWORK_ENV_FILEPATH="${BATS_TEST_DIRNAME}/testsData/.env" mkdir -p "${HOME}/.bash-tools" - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" } diff --git a/src/_binaries/Postman/postmanCli/postmanCli-binary.yaml b/src/_binaries/Postman/postmanCli/postmanCli-binary.yaml index ed68379a..fe482bd3 100644 --- a/src/_binaries/Postman/postmanCli/postmanCli-binary.yaml +++ b/src/_binaries/Postman/postmanCli/postmanCli-binary.yaml @@ -1,5 +1,6 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -8,9 +9,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/postmanCli" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: diff --git a/src/_binaries/Postman/postmanCli/postmanCli.bats b/src/_binaries/Postman/postmanCli/postmanCli.bats index 71ddecfc..efcc60bb 100755 --- a/src/_binaries/Postman/postmanCli/postmanCli.bats +++ b/src/_binaries/Postman/postmanCli/postmanCli.bats @@ -9,6 +9,7 @@ setup() { export HOME="${BATS_TEST_TMPDIR}/home" mkdir -p "${HOME}" cp -R "${rootDir}/conf" "${HOME}/.bash-tools" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools" } teardown() { @@ -27,11 +28,12 @@ function PostmanCli::config { #@test assert_line --index 2 "BASH_FRAMEWORK_ARGV = ([0]=\"--config\" [1]=\"-m\" [2]=\"${rootDir}/conf/postmanCli/openApis.json\")" assert_line --index 3 "BASH_FRAMEWORK_ARGV_FILTERED = ()" assert_line --index 4 'BASH_FRAMEWORK_DISPLAY_LEVEL = "3"' - assert_line --index 5 "BASH_FRAMEWORK_LOG_FILE = \"${TMPDIR}/logFile\"" - assert_line --index 6 'BASH_FRAMEWORK_LOG_FILE_MAX_ROTATION = "5"' - assert_line --index 7 'BASH_FRAMEWORK_LOG_LEVEL = "0"' - assert_line --index 8 'BASH_FRAMEWORK_THEME = "default"' - assert_line --index 9 "--------------------------------------------------------------------------------" - assert_line --index 10 'POSTMAN_API_KEY = ...(truncated)' - assert_lines_count 11 + assert_line --index 5 "BASH_FRAMEWORK_ENV_FILES = ([0]=\"${HOME}/.bash-tools/.env\")" + assert_line --index 6 "BASH_FRAMEWORK_LOG_FILE = \"${TMPDIR}/logFile\"" + assert_line --index 7 'BASH_FRAMEWORK_LOG_FILE_MAX_ROTATION = "5"' + assert_line --index 8 'BASH_FRAMEWORK_LOG_LEVEL = "0"' + assert_line --index 9 'BASH_FRAMEWORK_THEME = "default"' + assert_line --index 10 "--------------------------------------------------------------------------------" + assert_line --index 11 'POSTMAN_API_KEY = ...(truncated)' + assert_lines_count 12 } diff --git a/src/_binaries/Postman/postmanCli/testsData/postmanCli.help.txt b/src/_binaries/Postman/postmanCli/testsData/postmanCli.help.txt index 78ef2487..21ba2db6 100644 --- a/src/_binaries/Postman/postmanCli/testsData/postmanCli.help.txt +++ b/src/_binaries/Postman/postmanCli/testsData/postmanCli.help.txt @@ -4,7 +4,7 @@ USAGE: postmanCli [OPTIONS] [ARGUMENTS] USAGE: postmanCli [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] [--quiet|-q] [--postman-model|-m ] @@ -31,9 +31,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE diff --git a/src/_binaries/Utils/waitForIt/testsData/waitForIt.help.txt b/src/_binaries/Utils/waitForIt/testsData/waitForIt.help.txt index c1cda629..7a5d30b7 100644 --- a/src/_binaries/Utils/waitForIt/testsData/waitForIt.help.txt +++ b/src/_binaries/Utils/waitForIt/testsData/waitForIt.help.txt @@ -5,7 +5,7 @@ USAGE: waitForIt [--timeout|-t ] [--exec-command-on-timeout|--lax|-l] [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] [--quiet|-q] [--algorithm|--algo ] [--user-nc] @@ -38,9 +38,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE diff --git a/src/_binaries/Utils/waitForIt/waitForIt-binary.yaml b/src/_binaries/Utils/waitForIt/waitForIt-binary.yaml index 4ea5411f..82975ce6 100644 --- a/src/_binaries/Utils/waitForIt/waitForIt-binary.yaml +++ b/src/_binaries/Utils/waitForIt/waitForIt-binary.yaml @@ -1,6 +1,8 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsTimeout.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -9,9 +11,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/waitForIt" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: diff --git a/src/_binaries/Utils/waitForIt/waitForIt.bats b/src/_binaries/Utils/waitForIt/waitForIt.bats index f32340ea..5ed69028 100755 --- a/src/_binaries/Utils/waitForIt/waitForIt.bats +++ b/src/_binaries/Utils/waitForIt/waitForIt.bats @@ -9,7 +9,7 @@ setup() { export HOME="${BATS_TEST_TMPDIR}/home" mkdir -p "${HOME}/.bash-tools" mkdir -p "${HOME}/bin" - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" export PATH="${HOME}/bin:${PATH}" } diff --git a/src/_binaries/Utils/waitForMysql/testsData/waitForMysql.help.txt b/src/_binaries/Utils/waitForMysql/testsData/waitForMysql.help.txt index a9e6e3b9..88377118 100644 --- a/src/_binaries/Utils/waitForMysql/testsData/waitForMysql.help.txt +++ b/src/_binaries/Utils/waitForMysql/testsData/waitForMysql.help.txt @@ -5,7 +5,7 @@ USAGE: waitForMysql [--timeout|-t ] [--exec-command-on-timeout|--lax|-l] [--help|-h] [--config] [--bash-framework-config ] [--verbose|-v] [-vv] [-vvv] - [--env-file ] [--log-level ] [--log-file ] + [--log-level ] [--log-file ] [--display-level ] [--no-color] [--theme ] [--version] [--quiet|-q] @@ -42,9 +42,6 @@ Debug level verbose mode (alias of --display-level DEBUG) -vvv {single} Trace level verbose mode (alias of --display-level TRACE) - --env-file  {list} (optional) - Load the specified env file (deprecated, please use --bash-framework-con - fig option instead) --log-level  {single} Set log level Possible values: OFF, ERR, ERROR, WARN, WARNING, INFO, DEBUG, TRACE diff --git a/src/_binaries/Utils/waitForMysql/waitForMysql-binary.yaml b/src/_binaries/Utils/waitForMysql/waitForMysql-binary.yaml index eabfb55b..2dc22cd7 100644 --- a/src/_binaries/Utils/waitForMysql/waitForMysql-binary.yaml +++ b/src/_binaries/Utils/waitForMysql/waitForMysql-binary.yaml @@ -1,6 +1,7 @@ extends: - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsTimeout.yaml" - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsVersion.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -9,9 +10,7 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/waitForMysql" - relativeRootDirBasedOnTargetDir: .. - srcDirs: - - ${BASH_TOOLS_ROOT_DIR}/src + binData: commands: default: diff --git a/src/_binaries/Utils/waitForMysql/waitForMysql.bats b/src/_binaries/Utils/waitForMysql/waitForMysql.bats index e0c54717..6cdd9fb6 100755 --- a/src/_binaries/Utils/waitForMysql/waitForMysql.bats +++ b/src/_binaries/Utils/waitForMysql/waitForMysql.bats @@ -10,7 +10,7 @@ setup() { mkdir -p "${HOME}/.bash-tools" mkdir -p "${HOME}/bin" export PATH="${HOME}/bin:${PATH}" - cp "${rootDir}/conf/.env" "${HOME}/.bash-tools/.env" + cp "${rootDir}/conf/defaultEnv/.env" "${HOME}/.bash-tools/.env" } teardown() { diff --git a/src/_binaries/build/doc/doc-binary.yaml b/src/_binaries/build/doc/doc-binary.yaml index f6fb90df..255dc363 100644 --- a/src/_binaries/build/doc/doc-binary.yaml +++ b/src/_binaries/build/doc/doc-binary.yaml @@ -1,5 +1,6 @@ extends: - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/optionsCi.yaml" + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -8,7 +9,6 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/doc" - relativeRootDirBasedOnTargetDir: .. binData: commands: default: diff --git a/src/_binaries/build/install/install-binary.yaml b/src/_binaries/build/install/install-binary.yaml index f77d051c..2973f4fa 100644 --- a/src/_binaries/build/install/install-binary.yaml +++ b/src/_binaries/build/install/install-binary.yaml @@ -1,4 +1,5 @@ extends: + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" diff --git a/src/_binaries/build/install/install-main.sh b/src/_binaries/build/install/install-main.sh index fe7a4391..08efb1e3 100755 --- a/src/_binaries/build/install/install-main.sh +++ b/src/_binaries/build/install/install-main.sh @@ -1,8 +1,5 @@ #!/usr/bin/env bash -Linux::requireExecutedAsUser -Linux::requireTarCommand - if ! command -v parallel &>/dev/null; then Log::displayInfo "We will install GNU parallel software, please enter you sudo password" sudo apt-get update || true @@ -28,6 +25,7 @@ if [[ -d "${HOME}/.bash-tools" ]]; then Log::displayInfo "Updating configuration" cp -R --no-clobber "${BASH_TOOLS_ROOT_DIR}/conf/." "${HOME}/.bash-tools" + cp "${BASH_TOOLS_ROOT_DIR}/conf/defaultEnv/.env" "${HOME}/.bash-tools" if [[ "${FRAMEWORK_ROOT_DIR}/conf/.env" -nt "${HOME}/.bash-tools/.env" ]]; then Log::displayWarning "${FRAMEWORK_ROOT_DIR}/conf/.env is newer than ${HOME}/.bash-tools/.env, compare the files to check if some updates need to be applied" else @@ -36,5 +34,6 @@ if [[ -d "${HOME}/.bash-tools" ]]; then else Log::displayInfo "Installing configuration in ~/.bash-tools" mkdir -p "${HOME}/.bash-tools" - cp -R "${BASE_DIR}/conf/." "${HOME}/.bash-tools" + cp -R "${BASH_TOOLS_ROOT_DIR}/conf/." "${HOME}/.bash-tools" + cp "${BASH_TOOLS_ROOT_DIR}/conf/defaultEnv/.env" "${HOME}/.bash-tools" fi diff --git a/src/_binaries/build/install/install-options.sh b/src/_binaries/build/install/install-options.sh index b1cd70fd..bdd6da78 100755 --- a/src/_binaries/build/install/install-options.sh +++ b/src/_binaries/build/install/install-options.sh @@ -7,3 +7,9 @@ optionHelpCallback() { installCommandHelp exit 0 } + +beforeParseCallback() { + defaultBeforeParseCallback + Linux::requireExecutedAsUser + Linux::requireTarCommand +} diff --git a/src/_binaries/build/installRequirements/installRequirements-binary.yaml b/src/_binaries/build/installRequirements/installRequirements-binary.yaml index 33e71db9..1d310961 100644 --- a/src/_binaries/build/installRequirements/installRequirements-binary.yaml +++ b/src/_binaries/build/installRequirements/installRequirements-binary.yaml @@ -1,4 +1,5 @@ extends: + - "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/defaultCommand.yaml" - "${FRAMEWORK_ROOT_DIR}/src/_binaries/commandDefinitions/frameworkConfig.yaml" @@ -7,7 +8,6 @@ vars: compilerConfig: targetFile: "${BASH_TOOLS_ROOT_DIR}/bin/installRequirements" - relativeRootDirBasedOnTargetDir: .. binData: commands: default: diff --git a/src/_binaries/commandDefinitions/optionsDefault.sh b/src/_binaries/commandDefinitions/optionsDefault.sh index 7a6b250f..554c49f7 100755 --- a/src/_binaries/commandDefinitions/optionsDefault.sh +++ b/src/_binaries/commandDefinitions/optionsDefault.sh @@ -1,8 +1,12 @@ #!/usr/bin/env bash -beforeParseCallback() { +defaultBeforeParseCallback() { BashTools::Conf::requireLoad Env::requireLoad UI::requireTheme Log::requireLoad } + +beforeParseCallback() { + defaultBeforeParseCallback +} diff --git a/src/_binaries/commandDefinitions/optionsDefault.yaml b/src/_binaries/commandDefinitions/optionsDefault.yaml new file mode 100644 index 00000000..6e232b19 --- /dev/null +++ b/src/_binaries/commandDefinitions/optionsDefault.yaml @@ -0,0 +1,15 @@ +--- +compilerConfig: + relativeRootDirBasedOnTargetDir: .. + srcDirs: + - ${BASH_TOOLS_ROOT_DIR}/src + templateDirs: + - ${BASH_TOOLS_ROOT_DIR}/conf/defaultEnv + +binData: + commands: + default: + definitionFiles: + 11: "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsDefault.sh" + beforeParseCallbacks: + - beforeParseCallback diff --git a/src/_binaries/commandDefinitions/optionsFromDsn.sh b/src/_binaries/commandDefinitions/optionsFromDsn.sh new file mode 100755 index 00000000..ec487d25 --- /dev/null +++ b/src/_binaries/commandDefinitions/optionsFromDsn.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +fromDsnOptionLongDescription() { + local dsnList="" + dsnList="$(Conf::getMergedList "dsn" "env" " - ")" + + echo -e " ${__HELP_TITLE}Data Source Name (DSN)${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default dsn directory:${__HELP_NORMAL}" + echo -e " ${BASH_TOOLS_ROOT_DIR}/conf/dsn" + echo + echo -e " ${__HELP_TITLE}User dsn directory:${__HELP_NORMAL}" + echo -e " ${HOME}/.bash-tools/dsn" + echo -e ' Allows to override dsn defined in "Default dsn directory"' + echo + echo -e " ${__HELP_TITLE}List of available dsn:${__HELP_NORMAL}" + echo -e "${dsnList}" +} diff --git a/src/_binaries/commandDefinitions/optionsFromDsn.yaml b/src/_binaries/commandDefinitions/optionsFromDsn.yaml index 415204b8..a46d4462 100644 --- a/src/_binaries/commandDefinitions/optionsFromDsn.yaml +++ b/src/_binaries/commandDefinitions/optionsFromDsn.yaml @@ -2,6 +2,8 @@ binData: commands: default: + definitionFiles: + 29: "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsFromDsn.sh" optionGroups: groupSourceDbOptions: title: "SOURCE OPTIONS:" diff --git a/src/_binaries/commandDefinitions/optionsJobs.yaml b/src/_binaries/commandDefinitions/optionsJobs.yaml index d5352c4d..4d09ceab 100644 --- a/src/_binaries/commandDefinitions/optionsJobs.yaml +++ b/src/_binaries/commandDefinitions/optionsJobs.yaml @@ -23,9 +23,9 @@ binData: - variableName: optionProgressBar group: groupJobOptions type: Boolean - help: | - Show progress as a progress bar. In the bar is shown: % of jobs completed, - estimated seconds left, and number of jobs started. + help: + "Show progress as a progress bar. In the bar is shown: % of + jobs\ncompleted, estimated seconds left, and number of jobs started." callbacks: - optionProgressBarCallback alts: diff --git a/src/_binaries/commandDefinitions/optionsMysqlSource.sh b/src/_binaries/commandDefinitions/optionsMysqlSource.sh index b4d0d502..653bf543 100755 --- a/src/_binaries/commandDefinitions/optionsMysqlSource.sh +++ b/src/_binaries/commandDefinitions/optionsMysqlSource.sh @@ -3,3 +3,10 @@ dsnHelpFunction() { echo " target mysql server" } + +mysqlSourceLongDescription() { + fromDsnOptionLongDescription + echo + echo -e " ${__HELP_TITLE}Aws s3 location:${__HELP_NORMAL}" + echo -e " ${S3_BASE_URL}" +} diff --git a/src/_binaries/commandDefinitions/optionsMysqlSource.yaml b/src/_binaries/commandDefinitions/optionsMysqlSource.yaml index 255d4ab2..0110e894 100644 --- a/src/_binaries/commandDefinitions/optionsMysqlSource.yaml +++ b/src/_binaries/commandDefinitions/optionsMysqlSource.yaml @@ -3,6 +3,7 @@ binData: commands: default: definitionFiles: + 29: "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsFromDsn.sh" 40: "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsMysqlSource.sh" optionGroups: groupSourceDbOptions: diff --git a/src/_binaries/commandDefinitions/optionsMysqlTarget.yaml b/src/_binaries/commandDefinitions/optionsMysqlTarget.yaml index c8313238..743f636f 100644 --- a/src/_binaries/commandDefinitions/optionsMysqlTarget.yaml +++ b/src/_binaries/commandDefinitions/optionsMysqlTarget.yaml @@ -4,6 +4,7 @@ binData: default: definitionFiles: 23: "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsMysqlTarget.sh" + 29: "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsFromDsn.sh" optionGroups: groupTargetOptions: title: "TARGET OPTIONS:" diff --git a/src/_binaries/commandDefinitions/optionsProfile.sh b/src/_binaries/commandDefinitions/optionsProfile.sh index 54bbac73..e908832e 100755 --- a/src/_binaries/commandDefinitions/optionsProfile.sh +++ b/src/_binaries/commandDefinitions/optionsProfile.sh @@ -1,12 +1,43 @@ #!/usr/bin/env bash +profileOptionLongDescription() { + local profilesList="" + profilesList="$(Conf::getMergedList "dbImportProfiles" "sh" " - " || true)" + + echo -e " ${__HELP_TITLE}Profiles${__HELP_NORMAL}" + echo -e " ${__HELP_TITLE}Default profiles directory:${__HELP_NORMAL}" + echo -e " ${PROFILES_DIR-configuration error}" + echo + echo -e " ${__HELP_TITLE}User profiles directory:${__HELP_NORMAL}" + echo -e " ${HOME_PROFILES_DIR-configuration error}" + echo -e ' Allows to override profiles defined in "Default profiles directory"' + echo + echo -e " ${__HELP_TITLE}List of available profiles:${__HELP_NORMAL}" + echo -e "${profilesList}" +} + profileOptionHelpFunction() { Array::wrap2 " " 80 4 \ " The name of the profile to use in order to include or exclude tables." echo } +initOptionProfileIfNotSet() { + if [[ -z "${optionProfile}" ]]; then + optionProfile="${defaultOptionProfile}" + fi + local -a profilesArray + readarray -t profilesArray < <(Conf::getMergedList "dbImportProfiles" "sh" "" || true) + if ! Array::contains "${optionProfile}" "${profilesArray[@]}"; then + Log::displayError "${SCRIPT_NAME} - invalid profile '${optionProfile}' provided" + return 1 + fi +} + +declare defaultOptionProfile="default" initProfileCommandCallback() { + initOptionProfileIfNotSet + # shellcheck disable=SC2154 if [[ "${optionProfile}" != "default" && -n "${optionTables}" ]]; then Log::fatal "Command ${SCRIPT_NAME} - you cannot use table and profile options at the same time" @@ -34,18 +65,3 @@ initProfileCommandCallback() { chmod +x "${profileCommandFile}" Log::displayInfo "${profileMsgInfo}" } - -profileOptionCallback() { - local -a profilesArray - readarray -t profilesArray < <(Conf::getMergedList "dbImportProfiles" "sh" "" || true) - if ! Array::contains "$2" "${profilesArray[@]}"; then - Log::displayError "${SCRIPT_NAME} - invalid profile '$2' provided" - return 1 - fi -} - -optionTablesCallback() { - if [[ ! ${optionTables} =~ ^[A-Za-z0-9_]+(,[A-Za-z0-9_]+)*$ ]]; then - Log::fatal "Command ${SCRIPT_NAME} - Table list is not valid : ${optionTables}" - fi -} diff --git a/src/_binaries/commandDefinitions/optionsProfile.yaml b/src/_binaries/commandDefinitions/optionsProfile.yaml index df305689..f5d47a54 100644 --- a/src/_binaries/commandDefinitions/optionsProfile.yaml +++ b/src/_binaries/commandDefinitions/optionsProfile.yaml @@ -14,22 +14,7 @@ binData: group: groupProfileOptions type: String help: profileOptionHelpFunction - callbacks: - - profileOptionCallback - defaultValue: default helpValueName: profile alts: - --profile - -p - - - variableName: optionTables - group: groupProfileOptions - type: String - help: | - Import only table specified in the list. - If aws mode, ignore profile option. - callbacks: - - optionTablesCallback - helpValueName: tablesSeparatedByComma - alts: - - --tables diff --git a/src/_binaries/commandDefinitions/optionsRatio.sh b/src/_binaries/commandDefinitions/optionsRatio.sh new file mode 100755 index 00000000..c5a7f3ce --- /dev/null +++ b/src/_binaries/commandDefinitions/optionsRatio.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +optionRatioHelpFunction() { + Array::wrap2 " " 80 4 \ + " define the ratio to use (0 to 100% - default 70).\r" \ + "- 0 means profile will filter out all the tables\r" \ + "- 100 means profile will keep all the tables.\r" \ + "Eg: 70 means that tables with size(table+index)\r" \ + "that are greater than 70% of the max table size will be excluded." + echo +} diff --git a/src/_binaries/commandDefinitions/optionsRatio.yaml b/src/_binaries/commandDefinitions/optionsRatio.yaml new file mode 100644 index 00000000..c03b7ad4 --- /dev/null +++ b/src/_binaries/commandDefinitions/optionsRatio.yaml @@ -0,0 +1,19 @@ +--- +binData: + commands: + default: + definitionFiles: + 28: "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsRatio.sh" + optionGroups: + groupProfileOptions: + title: "PROFILE OPTIONS:" + options: + - variableName: optionRatio + group: groupProfileOptions + type: String + help: optionRatioHelpFunction + helpValueName: ratio + defaultValue: 70 + alts: + - --ratio + - -r diff --git a/src/_binaries/commandDefinitions/optionsTables.sh b/src/_binaries/commandDefinitions/optionsTables.sh new file mode 100755 index 00000000..d4328ce5 --- /dev/null +++ b/src/_binaries/commandDefinitions/optionsTables.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +optionTablesCallback() { + # shellcheck disable=SC2154 + if [[ ! ${optionTables} =~ ^[A-Za-z0-9_]+(,[A-Za-z0-9_]+)*$ ]]; then + Log::fatal "Command ${SCRIPT_NAME} - Table list is not valid : ${optionTables}" + fi +} diff --git a/src/_binaries/commandDefinitions/optionsTables.yaml b/src/_binaries/commandDefinitions/optionsTables.yaml new file mode 100644 index 00000000..5bac08ba --- /dev/null +++ b/src/_binaries/commandDefinitions/optionsTables.yaml @@ -0,0 +1,21 @@ +--- +binData: + commands: + default: + definitionFiles: + 28: "${BASH_TOOLS_ROOT_DIR}/src/_binaries/commandDefinitions/optionsTables.sh" + optionGroups: + groupProfileOptions: + title: "PROFILE OPTIONS:" + options: + - variableName: optionTables + group: groupProfileOptions + type: String + help: + "Import only table specified in the list.\nIf aws mode, ignore + profile option." + callbacks: + - optionTablesCallback + helpValueName: tablesSeparatedByComma + alts: + - --tables diff --git a/src/batsHeaders.sh b/src/batsHeaders.sh index d9786497..2a8fb64c 100755 --- a/src/batsHeaders.sh +++ b/src/batsHeaders.sh @@ -16,7 +16,7 @@ export BASH_FRAMEWORK_DISPLAY_LEVEL="${__LEVEL_INFO}" export BASH_FRAMEWORK_LOG_LEVEL=${__LEVEL_OFF} export SKIP_REQUIREMENTS_CHECKS=1 -Env::requireLoad "${rootDir}/conf/.env" +Env::requireLoad "${rootDir}/conf/defaultEnv/.env" Log::requireLoad # @description test command help