From 4ff23567d0f423b8021231a8d48701f8a6244bf0 Mon Sep 17 00:00:00 2001 From: to-bar <46519524+to-bar@users.noreply.github.com> Date: Wed, 10 Mar 2021 18:53:15 +0100 Subject: [PATCH 1/5] Add 'import_repo_gpg_keys' function with retries --- .../centos-7/download-requirements.sh | 103 ++++++++++++++++-- .../redhat-7/download-requirements.sh | 103 ++++++++++++++++-- 2 files changed, 192 insertions(+), 14 deletions(-) diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh index 0b0d5e9404..c9f883b66a 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# VERSION 1.0.4 +# VERSION 1.0.5 # NOTE: You can run only one instance of this script, new instance kills the previous one # This limitation is for Ansible @@ -34,8 +34,12 @@ add_repo_as_file() { echol "Adding repository: $repo_id" cat <<< "$config_file_content" > "/etc/yum.repos.d/$config_file_name" || exit_with_error "Function add_repo_as_file failed for repo: $repo_id" - # to accept import of GPG keys - yum -y repolist > /dev/null || exit_with_error "Command failed: yum -y repolist" + local -a gpg_key_urls + IFS=" " read -r -a gpg_key_urls \ + <<< "$(grep -i --only-matching --perl-regexp '(?<=^gpgkey=)http[^#\n]+' <<< "$config_file_content")" + if (( ${#gpg_key_urls[@]} > 0 )); then + import_repo_gpg_keys "${gpg_key_urls[@]}" + fi fi } @@ -239,6 +243,15 @@ get_unique_array() { eval $result_var_name='("${array[@]}")' } +# params: +import_repo_gpg_keys() { + local urls=("$@") + + for url in "${urls[@]}"; do + run_cmd_with_retries rpm --import "$url" 30 + done +} + # params: [package_name] install_package() { local package_name_or_url="$1" @@ -335,12 +348,56 @@ remove_installed_packages() { fi } -# params: +# Runs command as array with printing it, doesn't support commands with shell operators (such as pipe or redirection) +# params: [--no-exit-on-error] run_cmd() { - local cmd_arr=("$@") + local -a cmd_arr=("$@") - echol "Executing: ${cmd_arr[*]}" - "${cmd_arr[@]}" || exit_with_error "Command failed: ${cmd_arr[*]}" + local exit_on_error=1 + if [[ ${cmd_arr[-1]} == '--no-exit-on-error' ]]; then + exit_on_error=0 + cmd_arr=( "${cmd_arr[@]:0:$# - 1}" ) # remove last item + fi + + local escaped_string return_code + escaped_string=$(_print_array_as_shell_escaped_string "${cmd_arr[@]}") + echol "Executing: ${escaped_string}" + "${cmd_arr[@]}"; return_code=$? + if (( return_code != 0 )) && (( exit_on_error )); then + exit_with_error "Command failed: ${escaped_string}" + else + return $return_code + fi +} + +# Runs command with retries, doesn't support commands with shell operators (such as pipe or redirection) +# params: +run_cmd_with_retries() { + # pop 'retries' argument + local retries="${!#}" # get last argument (indirect expansion) + set -- "${@:1:$#-1}" # set new values of arguments + + local -a cmd_arr=("$@") + ( # sub-shell is used to limit scope for 'set +e' + set +e + trap - ERR # disable global trap locally + for ((i=0; i <= retries; i++)); do + run_cmd "${cmd_arr[@]}" '--no-exit-on-error' + return_code=$? + if (( return_code == 0 )); then + break + elif (( i < retries )); then + sleep 1 + echol "retrying ($(( i+1 ))/${retries})" + else + echol "ERROR: all attempts failed" + local escaped_string + escaped_string=$(_print_array_as_shell_escaped_string "${cmd_arr[@]}") + exit_with_error "Command failed: ${escaped_string}" + fi + done + return $return_code + ) } usage() { @@ -349,8 +406,40 @@ usage() { [ -z "$1" ] || exit "$1" } +validate_bash_version() { + local major_version=${BASH_VERSINFO[0]} + local minor_version=${BASH_VERSINFO[1]} + local required_version=(4 2) # (minor major) + if (( major_version < ${required_version[0]} )) || (( minor_version < ${required_version[1]} )); then + exit_with_error "This script requires Bash version ${required_version[0]}.${required_version[1]} or higher." + fi +} + +# === Helper functions (in alphabetical order) === + +_get_shell_escaped_array() { + if (( $# > 0 )); then + printf '%q\n' "$@" + fi +} + +# Prints string in format that can be reused as shell input (escapes non-printable characters) +_print_array_as_shell_escaped_string() { + local output + output=$(_get_shell_escaped_array "$@") + local -a escaped=() + if [ -n "$output" ]; then + readarray -t escaped <<< "$output" + fi + if (( ${#escaped[@]} > 0 )); then + printf '%s\n' "${escaped[*]}" + fi +} + # === Start === +validate_bash_version + [ $# -gt 0 ] || usage 1 >&2 readonly START_TIME=$(date +%s) diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh index ed525b87c3..0aeeb16905 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# VERSION 1.0.4 +# VERSION 1.0.5 # NOTE: You can run only one instance of this script, new instance kills the previous one # This limitation is for Ansible @@ -34,8 +34,12 @@ add_repo_as_file() { echol "Adding repository: $repo_id" cat <<< "$config_file_content" > "/etc/yum.repos.d/$config_file_name" || exit_with_error "Function add_repo_as_file failed for repo: $repo_id" - # to accept import of GPG keys - yum -y repolist > /dev/null || exit_with_error "Command failed: yum -y repolist" + local -a gpg_key_urls + IFS=" " read -r -a gpg_key_urls \ + <<< "$(grep -i --only-matching --perl-regexp '(?<=^gpgkey=)http[^#\n]+' <<< "$config_file_content")" + if (( ${#gpg_key_urls[@]} > 0 )); then + import_repo_gpg_keys "${gpg_key_urls[@]}" + fi fi } @@ -256,6 +260,15 @@ get_unique_array() { eval $result_var_name='("${array[@]}")' } +# params: +import_repo_gpg_keys() { + local urls=("$@") + + for url in "${urls[@]}"; do + run_cmd_with_retries rpm --import "$url" 30 + done +} + # params: [package_name] install_package() { local package_name_or_url="$1" @@ -352,12 +365,56 @@ remove_installed_packages() { fi } -# params: +# Runs command as array with printing it, doesn't support commands with shell operators (such as pipe or redirection) +# params: [--no-exit-on-error] run_cmd() { - local cmd_arr=("$@") + local -a cmd_arr=("$@") - echol "Executing: ${cmd_arr[*]}" - "${cmd_arr[@]}" || exit_with_error "Command failed: ${cmd_arr[*]}" + local exit_on_error=1 + if [[ ${cmd_arr[-1]} == '--no-exit-on-error' ]]; then + exit_on_error=0 + cmd_arr=( "${cmd_arr[@]:0:$# - 1}" ) # remove last item + fi + + local escaped_string return_code + escaped_string=$(_print_array_as_shell_escaped_string "${cmd_arr[@]}") + echol "Executing: ${escaped_string}" + "${cmd_arr[@]}"; return_code=$? + if (( return_code != 0 )) && (( exit_on_error )); then + exit_with_error "Command failed: ${escaped_string}" + else + return $return_code + fi +} + +# Runs command with retries, doesn't support commands with shell operators (such as pipe or redirection) +# params: +run_cmd_with_retries() { + # pop 'retries' argument + local retries="${!#}" # get last argument (indirect expansion) + set -- "${@:1:$#-1}" # set new values of arguments + + local -a cmd_arr=("$@") + ( # sub-shell is used to limit scope for 'set +e' + set +e + trap - ERR # disable global trap locally + for ((i=0; i <= retries; i++)); do + run_cmd "${cmd_arr[@]}" '--no-exit-on-error' + return_code=$? + if (( return_code == 0 )); then + break + elif (( i < retries )); then + sleep 1 + echol "retrying ($(( i+1 ))/${retries})" + else + echol "ERROR: all attempts failed" + local escaped_string + escaped_string=$(_print_array_as_shell_escaped_string "${cmd_arr[@]}") + exit_with_error "Command failed: ${escaped_string}" + fi + done + return $return_code + ) } usage() { @@ -366,8 +423,40 @@ usage() { [ -z "$1" ] || exit "$1" } +validate_bash_version() { + local major_version=${BASH_VERSINFO[0]} + local minor_version=${BASH_VERSINFO[1]} + local required_version=(4 2) # (minor major) + if (( major_version < ${required_version[0]} )) || (( minor_version < ${required_version[1]} )); then + exit_with_error "This script requires Bash version ${required_version[0]}.${required_version[1]} or higher." + fi +} + +# === Helper functions (in alphabetical order) === + +_get_shell_escaped_array() { + if (( $# > 0 )); then + printf '%q\n' "$@" + fi +} + +# Prints string in format that can be reused as shell input (escapes non-printable characters) +_print_array_as_shell_escaped_string() { + local output + output=$(_get_shell_escaped_array "$@") + local -a escaped=() + if [ -n "$output" ]; then + readarray -t escaped <<< "$output" + fi + if (( ${#escaped[@]} > 0 )); then + printf '%s\n' "${escaped[*]}" + fi +} + # === Start === +validate_bash_version + [ $# -gt 0 ] || usage 1 >&2 readonly START_TIME=$(date +%s) From bc5110acfb43c5568a92ba0aacdfea06049ab373 Mon Sep 17 00:00:00 2001 From: to-bar <46519524+to-bar@users.noreply.github.com> Date: Wed, 10 Mar 2021 19:55:03 +0100 Subject: [PATCH 2/5] Fix gpgkey for PostgreSQL repo --- .../download-requirements/centos-7/download-requirements.sh | 2 +- .../download-requirements/redhat-7/download-requirements.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh index c9f883b66a..a4ce442aac 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh @@ -658,7 +658,7 @@ name=PostgreSQL 10 for RHEL/CentOS $releasever - $basearch baseurl=https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-$releasever-$basearch enabled=1 gpgcheck=1 -gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG +gpgkey=https://download.postgresql.org/pub/repos/yum/RPM-GPG-KEY-PGDG EOF ) diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh index 0aeeb16905..86d38ed1f5 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh @@ -688,7 +688,7 @@ name=PostgreSQL 10 for RHEL/CentOS $releasever - $basearch baseurl=https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-$releasever-$basearch enabled=1 gpgcheck=1 -gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG +gpgkey=https://download.postgresql.org/pub/repos/yum/RPM-GPG-KEY-PGDG EOF ) From 225e1a54508ab3fbf4115d98626a4ea8338a4dc5 Mon Sep 17 00:00:00 2001 From: to-bar <46519524+to-bar@users.noreply.github.com> Date: Wed, 10 Mar 2021 20:28:25 +0100 Subject: [PATCH 3/5] Prefer Docker CE patched repo --- .../centos-7/download-requirements.sh | 18 ++++++++++-------- .../redhat-7/download-requirements.sh | 18 ++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh index a4ce442aac..0167d86efc 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh @@ -571,9 +571,9 @@ enable_repo 'extras' # --- Add repos --- -DOCKER_CE_FALLBACK_REPO_CONF=$(cat <<'EOF' -[docker-ce-stable-fallback] -name=Docker CE Stable - fallback centos/7/x86_64/stable +DOCKER_CE_PATCHED_REPO_CONF=$(cat <<'EOF' +[docker-ce-stable-patched] +name=Docker CE Stable - patched centos/7/x86_64/stable baseurl=https://download.docker.com/linux/centos/7/x86_64/stable enabled=1 gpgcheck=1 @@ -684,11 +684,13 @@ gpgkey=https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey EOF ) -add_repo 'docker-ce' 'https://download.docker.com/linux/centos/docker-ce.repo' -# occasionally docker-ce repo (at https://download.docker.com/linux/centos/7Server/x86_64/stable) is unavailable -if ! is_repo_available "docker-ce-stable"; then - disable_repo "docker-ce-stable" - add_repo_as_file 'docker-ce-stable-fallback' "$DOCKER_CE_FALLBACK_REPO_CONF" +# Official Docker CE repository, added with https://download.docker.com/linux/centos/docker-ce.repo, +# has broken URL (https://download.docker.com/linux/centos/7Server/x86_64/stable) for longer time. +# So direct (patched) link is used first if available. +add_repo_as_file 'docker-ce-stable-patched' "$DOCKER_CE_PATCHED_REPO_CONF" +if ! is_repo_available "docker-ce-stable-patched"; then + disable_repo "docker-ce-stable-patched" + add_repo 'docker-ce' 'https://download.docker.com/linux/centos/docker-ce.repo' fi add_repo_as_file 'elastic-6' "$ELASTIC_6_REPO_CONF" add_repo_as_file 'elasticsearch-7' "$ELASTICSEARCH_7_REPO_CONF" diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh index 86d38ed1f5..11cccf9eba 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh @@ -601,9 +601,9 @@ enable_repo "$REPO_ID" # --- Add repos --- -DOCKER_CE_FALLBACK_REPO_CONF=$(cat <<'EOF' -[docker-ce-stable-fallback] -name=Docker CE Stable - fallback centos/7/x86_64/stable +DOCKER_CE_PATCHED_REPO_CONF=$(cat <<'EOF' +[docker-ce-stable-patched] +name=Docker CE Stable - patched centos/7/x86_64/stable baseurl=https://download.docker.com/linux/centos/7/x86_64/stable enabled=1 gpgcheck=1 @@ -714,11 +714,13 @@ gpgkey=https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey EOF ) -add_repo 'docker-ce' 'https://download.docker.com/linux/centos/docker-ce.repo' -# occasionally docker-ce repo (at https://download.docker.com/linux/centos/7Server/x86_64/stable) is unavailable -if ! is_repo_available "docker-ce-stable"; then - disable_repo "docker-ce-stable" - add_repo_as_file 'docker-ce-stable-fallback' "$DOCKER_CE_FALLBACK_REPO_CONF" +# Official Docker CE repository, added with https://download.docker.com/linux/centos/docker-ce.repo, +# has broken URL (https://download.docker.com/linux/centos/7Server/x86_64/stable) for longer time. +# So direct (patched) link is used first if available. +add_repo_as_file 'docker-ce-stable-patched' "$DOCKER_CE_PATCHED_REPO_CONF" +if ! is_repo_available "docker-ce-stable-patched"; then + disable_repo "docker-ce-stable-patched" + add_repo 'docker-ce' 'https://download.docker.com/linux/centos/docker-ce.repo' fi add_repo_as_file 'elastic-6' "$ELASTIC_6_REPO_CONF" add_repo_as_file 'elasticsearch-7' "$ELASTICSEARCH_7_REPO_CONF" From 3f9ef69d880f5d6fd793f61e10c95e7dc438b3e2 Mon Sep 17 00:00:00 2001 From: to-bar <46519524+to-bar@users.noreply.github.com> Date: Wed, 10 Mar 2021 20:31:23 +0100 Subject: [PATCH 4/5] Update changelog --- CHANGELOG-0.10.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-0.10.md b/CHANGELOG-0.10.md index 10b0342b16..c9e0c66312 100644 --- a/CHANGELOG-0.10.md +++ b/CHANGELOG-0.10.md @@ -21,6 +21,7 @@ - [#2069](https://github.com/epiphany-platform/epiphany/issues/2069) - [CentOS] epicli fails on task [repository : Create epirepo repository] - [#2066](https://github.com/epiphany-platform/epiphany/issues/2066) - [CentOS] download-requirements.sh fails on extracting tar with backed up repos - [#2067](https://github.com/epiphany-platform/epiphany/issues/2067) - [CentOS] epicli fails on task "repository : Wait for yum lock to be released" on CentOS Minimal +- [#2115](https://github.com/epiphany-platform/epiphany/issues/2115) - Epicli hangs on importing GPG keys for kubernetes repository on RHEL ### Updated From 74ccd1fe1c8826fd2fc129184dd2619c95889eeb Mon Sep 17 00:00:00 2001 From: to-bar <46519524+to-bar@users.noreply.github.com> Date: Thu, 11 Mar 2021 12:59:30 +0100 Subject: [PATCH 5/5] Re-add 'yum -y repolist' to accept repo's GPG key --- .../centos-7/download-requirements.sh | 21 +++++++++++-------- .../redhat-7/download-requirements.sh | 21 +++++++++++-------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh index 0167d86efc..c72c07c299 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/centos-7/download-requirements.sh @@ -38,8 +38,10 @@ add_repo_as_file() { IFS=" " read -r -a gpg_key_urls \ <<< "$(grep -i --only-matching --perl-regexp '(?<=^gpgkey=)http[^#\n]+' <<< "$config_file_content")" if (( ${#gpg_key_urls[@]} > 0 )); then - import_repo_gpg_keys "${gpg_key_urls[@]}" + import_repo_gpg_keys "${gpg_key_urls[@]}" 3 fi + # to accept import of repo's GPG key (for repo_gpgcheck=1) + yum -y repolist > /dev/null || exit_with_error "Command failed: yum -y repolist" fi } @@ -243,12 +245,13 @@ get_unique_array() { eval $result_var_name='("${array[@]}")' } -# params: +# params: import_repo_gpg_keys() { - local urls=("$@") + local retries=${!#} # get last arg + local urls=( "${@:1:$# - 1}" ) # remove last arg for url in "${urls[@]}"; do - run_cmd_with_retries rpm --import "$url" 30 + run_cmd_with_retries rpm --import "$url" "$retries" done } @@ -351,7 +354,7 @@ remove_installed_packages() { # Runs command as array with printing it, doesn't support commands with shell operators (such as pipe or redirection) # params: [--no-exit-on-error] run_cmd() { - local -a cmd_arr=("$@") + local cmd_arr=("$@") local exit_on_error=1 if [[ ${cmd_arr[-1]} == '--no-exit-on-error' ]]; then @@ -374,10 +377,10 @@ run_cmd() { # params: run_cmd_with_retries() { # pop 'retries' argument - local retries="${!#}" # get last argument (indirect expansion) - set -- "${@:1:$#-1}" # set new values of arguments + local retries=${!#} # get last arg (indirect expansion) + set -- "${@:1:$#-1}" # set new "$@" - local -a cmd_arr=("$@") + local cmd_arr=("$@") ( # sub-shell is used to limit scope for 'set +e' set +e trap - ERR # disable global trap locally @@ -427,7 +430,7 @@ _get_shell_escaped_array() { _print_array_as_shell_escaped_string() { local output output=$(_get_shell_escaped_array "$@") - local -a escaped=() + local escaped=() if [ -n "$output" ]; then readarray -t escaped <<< "$output" fi diff --git a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh index 11cccf9eba..cf9c540785 100644 --- a/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh +++ b/core/src/epicli/data/common/ansible/playbooks/roles/repository/files/download-requirements/redhat-7/download-requirements.sh @@ -38,8 +38,10 @@ add_repo_as_file() { IFS=" " read -r -a gpg_key_urls \ <<< "$(grep -i --only-matching --perl-regexp '(?<=^gpgkey=)http[^#\n]+' <<< "$config_file_content")" if (( ${#gpg_key_urls[@]} > 0 )); then - import_repo_gpg_keys "${gpg_key_urls[@]}" + import_repo_gpg_keys "${gpg_key_urls[@]}" 3 fi + # to accept import of repo's GPG key (for repo_gpgcheck=1) + yum -y repolist > /dev/null || exit_with_error "Command failed: yum -y repolist" fi } @@ -260,12 +262,13 @@ get_unique_array() { eval $result_var_name='("${array[@]}")' } -# params: +# params: import_repo_gpg_keys() { - local urls=("$@") + local retries=${!#} # get last arg + local urls=( "${@:1:$# - 1}" ) # remove last arg for url in "${urls[@]}"; do - run_cmd_with_retries rpm --import "$url" 30 + run_cmd_with_retries rpm --import "$url" "$retries" done } @@ -368,7 +371,7 @@ remove_installed_packages() { # Runs command as array with printing it, doesn't support commands with shell operators (such as pipe or redirection) # params: [--no-exit-on-error] run_cmd() { - local -a cmd_arr=("$@") + local cmd_arr=("$@") local exit_on_error=1 if [[ ${cmd_arr[-1]} == '--no-exit-on-error' ]]; then @@ -391,10 +394,10 @@ run_cmd() { # params: run_cmd_with_retries() { # pop 'retries' argument - local retries="${!#}" # get last argument (indirect expansion) - set -- "${@:1:$#-1}" # set new values of arguments + local retries=${!#} # get last arg (indirect expansion) + set -- "${@:1:$#-1}" # set new "$@" - local -a cmd_arr=("$@") + local cmd_arr=("$@") ( # sub-shell is used to limit scope for 'set +e' set +e trap - ERR # disable global trap locally @@ -444,7 +447,7 @@ _get_shell_escaped_array() { _print_array_as_shell_escaped_string() { local output output=$(_get_shell_escaped_array "$@") - local -a escaped=() + local escaped=() if [ -n "$output" ]; then readarray -t escaped <<< "$output" fi