diff --git a/.gitignore b/.gitignore index 62980e3..d298786 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ versions/ version .terragrunt-version bin/terragrunt-* +.idea/* diff --git a/README.md b/README.md index 66a0e39..d675d43 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/cunymatthieu/tgenv.svg?branch=master)](https://travis-ci.org/cunymatthieu/tgenv) +[![Build Status](https://travis-ci.org/env0/tgenv.svg?branch=master)](https://travis-ci.org/env0/tgenv) # tgenv [Terragrunt](https://github.com/gruntwork-io/terragrunt) version manager inspired by [tfenv](https://github.com/kamatama41/tfenv) @@ -14,7 +14,7 @@ Currently tgenv supports the following OSes 1. Check out tgenv into any path (here is `${HOME}/.tgenv`) ```bash - $ git clone https://github.com/cunymatthieu/tgenv.git ~/.tgenv + $ git clone https://github.com/env0/tgenv.git ~/.tgenv ``` 2. Add `~/.tgenv/bin` to your `$PATH` any way you like @@ -130,29 +130,15 @@ $ echo latest:^0.10 > .terragrunt-version $ terragrunt --version terragrunt v0.10.3 ``` - ### Environment Variables #### TGENV -##### `TGENV_AUTO_INSTALL` - -String (Default: true) - -Should tgenv automatically install terragrunt if the version specified by defaults or a .terragrunt-version file is not currently installed. - -```console -TGENV_AUTO_INSTALL=false terragrunt plan -``` - -##### `TGENV_DEBUG` - -Integer (Default: "") +##### `TGENV_CONFIG_DIR` -Set the debug level for TGENV. +Path (Default: `$TGENV_ROOT`) -* unset/empty-string: No debug output -* set: Bash execution tracing +The path to a directory where the local terragrunt versions and configuration files exist. ## Upgrading ```bash @@ -165,5 +151,5 @@ $ rm -rf /some/path/to/tgenv ``` ## LICENSE -- [tgenv itself](https://github.com/cunymatthieu/tgenv/blob/master/LICENSE) -- [tfenv ](https://github.com/kamatama41/tgenv/blob/master/LICENSE) : tfenv mainly uses tfenv's source code +- [tgenv itself](https://github.com/env0/tgenv/blob/master/LICENSE) +- [tfenv ](https://github.com/kamatama41/tfenv/blob/master/LICENSE) : tgenv mainly uses tfenv's source code diff --git a/bin/tgenv b/bin/tgenv index bc48be4..a79480e 100755 --- a/bin/tgenv +++ b/bin/tgenv @@ -29,6 +29,13 @@ PATH="${TGENV_ROOT}/libexec:${PATH}" export PATH export TGENV_DIR="${PWD}" +if [ -z "${TGENV_CONFIG_DIR:-""}" ]; then + TGENV_CONFIG_DIR="$TGENV_ROOT"; +else + TGENV_CONFIG_DIR="${TGENV_CONFIG_DIR%/}"; +fi +export TGENV_CONFIG_DIR; + abort() { { if [ "${#}" -eq 0 ]; then cat - else echo "tgenv: ${*}" diff --git a/libexec/helpers b/libexec/helpers index e663ca6..79ee7a3 100755 --- a/libexec/helpers +++ b/libexec/helpers @@ -1,5 +1,9 @@ #!/usr/bin/env bash +function error_log() { + echo -e "tgenv: $(basename ${0}): \033[0;31m[ERROR] ${1}\033[0;39m" >&2 +} + function error_and_die() { echo -e "tgenv: $(basename ${0}): \033[0;31m[ERROR] ${1}\033[0;39m" >&2 exit 1 diff --git a/libexec/retry b/libexec/retry new file mode 100755 index 0000000..7dfeb81 --- /dev/null +++ b/libexec/retry @@ -0,0 +1,82 @@ +#!/usr/bin/env bash + +info_log() { + echo -e "\033[0;32m[INFO] ${1}\033[0;39m" >&2 +} + +retry() { + # Default values + local tries=3 + local sleep_interval=5 + local stop_on_exit_code="" + + # Function to display script usage + usage() { + echo "Usage: retry [options] " + echo "Options:" + echo " -sleep Sleep interval between tries (default: 5)" + echo " -tries Maximum number of tries (default: 3)" + echo " -stop-on-exit-code Exit loop if command returns the specified code" + echo " -help, -h Display this help message" + return 1 + } + + # Parse command-line options + while [[ $# -gt 0 ]]; do + case "$1" in + -sleep) + sleep_interval=$2 + shift 2 + ;; + -tries) + tries=$2 + shift 2 + ;; + -stop-on-exit-code) + stop_on_exit_code=$2 + shift 2 + ;; + -help | -h) + usage + ;; + *) + break + ;; + esac + done + + # Check if a command is provided + if [[ $# -eq 0 ]]; then + usage + return 1 + fi + + # Execute the command in a loop until success or maximum tries reached + local counter=0 + while [[ $counter -lt $tries ]]; do + "$@" + local exit_code=$? + + if [[ $exit_code -eq 0 ]]; then + return 0 + elif [[ -n $stop_on_exit_code && $exit_code -eq $stop_on_exit_code ]]; then + info_log "Exit code ($stop_on_exit_code) matching to condition. Won't retry, exiting." + return 1 + fi + + counter=$((counter + 1)) + + if [[ $counter -lt $tries ]]; then + info_log "Attempt $counter failed. Retrying after $sleep_interval seconds..." + sleep "$sleep_interval" + fi + done + + info_log "Command failed after $tries attempts." + return 1 +} + +# Call the retry function if the script is executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + retry "$@" +fi diff --git a/libexec/tgenv-exec b/libexec/tgenv-exec index e59f655..9c23e59 100755 --- a/libexec/tgenv-exec +++ b/libexec/tgenv-exec @@ -15,27 +15,8 @@ set -e [ -n "${TGENV_DEBUG}" ] && set -x -source "${TGENV_ROOT}/libexec/helpers" -info 'Getting version from tgenv-version-name'; -TGENV_VERSION="$(tgenv-version-name)" \ - && info "TGENV_VERSION is ${TGENV_VERSION}" \ - || { - # Errors will be logged from tgenv-version name, - # we don't need to trouble STDERR with repeat information here - error_and_die 'Failed to get version from tgenv-version-name'; - }; -export TGENV_VERSION; - -if [ ! -d "${TGENV_ROOT}/versions/${TGENV_VERSION}" ]; then - if [ "${TGENV_AUTO_INSTALL:-false}" == "true" ]; then - info "version '${TGENV_VERSION}' is not installed (set by $(tgenv-version-file)). Installing now as TGENV_AUTO_INSTALL==true"; - tgenv-install; - else - error_and_die "version '${TGENV_VERSION}' was requested, but not installed and TGENV_AUTO_INSTALL is not 'true'"; - fi; -fi; - -TG_BIN_PATH="${TGENV_ROOT}/versions/${TGENV_VERSION}/terragrunt" +export TGENV_VERSION="$(tgenv-version-name)" +TG_BIN_PATH="${TGENV_CONFIG_DIR}/versions/${TGENV_VERSION}/terragrunt" export PATH="${TG_BIN_PATH}:${PATH}" -"${TG_BIN_PATH}" "${@}" \ No newline at end of file +"${TG_BIN_PATH}" "${@}" diff --git a/libexec/tgenv-install b/libexec/tgenv-install index 43e1cb9..2646c1f 100755 --- a/libexec/tgenv-install +++ b/libexec/tgenv-install @@ -2,6 +2,7 @@ [ -n "${TGENV_DEBUG}" ] && set -x source "${TGENV_ROOT}/libexec/helpers" +source "${TGENV_ROOT}/libexec/retry" [ "${#}" -gt 1 ] && error_and_die "usage: tgenv install []" @@ -9,7 +10,7 @@ declare version_requested version regex if [ -z "${1}" ]; then version_file="$(tgenv-version-file)" - if [ "${version_file}" != "${TGENV_ROOT}/version" ]; then + if [ "${version_file}" != "${TGENV_CONFIG_DIR}/version" ]; then version_requested="$(cat "${version_file}" || true)" fi else @@ -28,10 +29,8 @@ else fi [ -n "${version}" ] || error_and_die "Version is not specified" -version="$(tgenv-list-remote | grep -e "${regex}" | head -n 1)" -[ -n "${version}" ] || error_and_die "No versions matching '${1}' found in remote" -dst_path="${TGENV_ROOT}/versions/${version}" +dst_path="${TGENV_CONFIG_DIR}/versions/${version}" if [ -f "${dst_path}/terragrunt" ]; then echo "Terragrunt v${version} is already installed" exit 0 @@ -62,12 +61,43 @@ tarball_name="terragrunt_${os}"; info "Installing Terragrunt v${version}" +function install_tg_version() { + local http_code + http_code=$(curlw -# --location-trusted -w "%{http_code}" -o "${dst_path}/terragrunt" "${version_url}/${tarball_name}") + local curl_exit_code=$? + + local result_code + if [[ $http_code =~ ^4 ]]; then + error_log "Got $http_code http code, TG version is invalid" + result_code=2 # do not retry + elif [[ $http_code =~ ^5 ]]; then + error_log "Got $http_code http code" + result_code=1 # retry + elif [[ $curl_exit_code -ne 0 ]]; then + result_code=1 # retry + else + result_code=0 # success + fi + + if [[ $result_code -ne 0 ]]; then + # make sure versions folder does not exist, so we can retry installation + rm -rf "${dst_path}" + fi + + return $result_code +} + + mkdir -p "${dst_path}" || error_and_die "Failed to make directory ${dst_path}" info "Downloading release tarball from ${version_url}/${tarball_name}" -curlw -# --location-trusted -f -o "${dst_path}/terragrunt" "${version_url}/${tarball_name}" || error_and_die "Tarball download failed" +retry -tries 5 -sleep 5 -stop-on-exit-code 2 install_tg_version || error_and_die "Tarball download failed" +install_exist_code=$? -chmod +x "${dst_path}/terragrunt" || error_and_die "Change rights failed" +if [ "$install_exist_code" -eq 0 ]; then -info "Installation of terragrunt v${version} successful" -tgenv-use "${version}" + chmod +x "${dst_path}/terragrunt" || error_and_die "Change rights failed" + + info "Installation of terragrunt v${version} successful" + retry -sleep 3 tgenv-use "${version}" || error_and_die "tgenv use failed" +fi diff --git a/libexec/tgenv-list b/libexec/tgenv-list index d03d155..afa5969 100755 --- a/libexec/tgenv-list +++ b/libexec/tgenv-list @@ -6,10 +6,10 @@ source "${TGENV_ROOT}/libexec/helpers" [ "${#}" -ne 0 ] \ && error_and_die "usage: tgenv list" -[ -d "${TGENV_ROOT}/versions" ] \ +[ -d "${TGENV_CONFIG_DIR}/versions" ] \ || error_and_die "No versions available. Please install one with: tgenv install" -[[ -x "${TGENV_ROOT}/versions" && -r "${TGENV_ROOT}/versions" ]] \ +[[ -x "${TGENV_CONFIG_DIR}/versions" && -r "${TGENV_CONFIG_DIR}/versions" ]] \ || error_and_die "tgenv versions directory is inaccessible!" print_version () { @@ -20,6 +20,6 @@ print_version () { fi } -for local_version in $(ls -1 "${TGENV_ROOT}/versions" | sort -t'.' -k 1nr,1 -k 2nr,2 -k 3nr,3); do +for local_version in $(ls -1 "${TGENV_CONFIG_DIR}/versions" | sort -t'.' -k 1nr,1 -k 2nr,2 -k 3nr,3); do print_version "${local_version}" done diff --git a/libexec/tgenv-list-remote b/libexec/tgenv-list-remote index 741d5c8..3cab3d0 100755 --- a/libexec/tgenv-list-remote +++ b/libexec/tgenv-list-remote @@ -1,5 +1,15 @@ #!/usr/bin/env bash -set -e +link_release="https://api.github.com/repos/gruntwork-io/terragrunt/tags?per_page=1000" + +# the response header (--head) contains a link to the last page, contains the last page number and the "last" keyword to help identify +page_curl=$(curl -s --tlsv1.2 --head "$link_release") +last_page_phrase=$(echo "$page_curl" | grep -o -E "&page=[0-9]+>; rel=\"last") +re="([0-9]+)" +if [[ $last_page_phrase =~ $re ]] ; then + pages=${BASH_REMATCH[0]} +else + pages=4 # default in case something changes in the way the responses are formatted +fi [ -n "${TGENV_DEBUG}" ] && set -x source "${TGENV_ROOT}/libexec/helpers" @@ -12,9 +22,15 @@ fi link_release="https://api.github.com/repos/gruntwork-io/terragrunt/tags?per_page=1000" print=$(curl --tlsv1.2 -sf $link_release) +for (( page=2; page <= pages; page++)) +do + link_release="https://api.github.com/repos/gruntwork-io/terragrunt/tags?per_page=1000&page=${page}" + print+=$(curl --tlsv1.2 -sf $link_release) +done + return_code=$? if [ $return_code -eq 22 ];then - warn_and_continue "Failed to get list verion on $link_release" + warn_and_continue "Failed to get list version on $link_release" print=`cat ${TGENV_ROOT}/list_all_versions_offline` fi diff --git a/libexec/tgenv-uninstall b/libexec/tgenv-uninstall index 7f0e895..bbcd0ae 100755 --- a/libexec/tgenv-uninstall +++ b/libexec/tgenv-uninstall @@ -9,7 +9,7 @@ declare version_requested version regex if [ -z "${1}" ]; then version_file="$(tgenv-version-file)" - if [ "${version_file}" != "${TGENV_ROOT}/version" ];then + if [ "${version_file}" != "${TGENV_CONFIG_DIR}/version" ];then version_requested="$(cat "${version_file}" || true)" fi else @@ -31,7 +31,7 @@ fi version="$(tgenv-list | sed -E 's/^(\*| )? //g; s/ \(set by .+\)$//' | grep -e "${regex}" | head -n 1)" [ -n "${version}" ] || error_and_die "No versions matching '${1}' found in local" -dst_path="${TGENV_ROOT}/versions/${version}" +dst_path="${TGENV_CONFIG_DIR}/versions/${version}" if [ -f "${dst_path}/terragrunt" ]; then info "Uninstall Terragrunt v${version}" rm -r "${dst_path}" diff --git a/libexec/tgenv-use b/libexec/tgenv-use index c4ef108..b569c9d 100755 --- a/libexec/tgenv-use +++ b/libexec/tgenv-use @@ -20,10 +20,10 @@ else regex="^${version_requested}$" fi -[ -d "${TGENV_ROOT}/versions" ] \ +[ -d "${TGENV_CONFIG_DIR}/versions" ] \ || error_and_die "No versions of terragrunt installed. Please install one with: tgenv install" -version="$(\ls "${TGENV_ROOT}/versions" \ +version="$(\ls "${TGENV_CONFIG_DIR}/versions" \ | sort -t'.' -k 1nr,1 -k 2nr,2 -k 3nr,3 \ | grep -e "${regex}" \ | head -n 1 @@ -31,7 +31,7 @@ version="$(\ls "${TGENV_ROOT}/versions" \ [ -n "${version}" ] || error_and_die "No installed versions of terragrunt matched '${1}'" -target_path="${TGENV_ROOT}/versions/${version}" +target_path="${TGENV_CONFIG_DIR}/versions/${version}" [ -f "${target_path}/terragrunt" ] \ || error_and_die "Version directory for ${version} is present, but the terragrunt binary is not! Manual intervention required." [ -x "${target_path}/terragrunt" ] \ diff --git a/libexec/tgenv-version-file b/libexec/tgenv-version-file index 2f178d1..0b9ad5f 100755 --- a/libexec/tgenv-version-file +++ b/libexec/tgenv-version-file @@ -17,4 +17,4 @@ find_local_version_file() { return 1 } -find_local_version_file "${TGENV_DIR}" || find_local_version_file "${HOME}" || echo "${TGENV_ROOT}/version" +find_local_version_file "${TGENV_DIR}" || find_local_version_file "${HOME}" || echo "${TGENV_CONFIG_DIR}/version" diff --git a/libexec/tgenv-version-name b/libexec/tgenv-version-name index 4fdecf6..7799c9d 100755 --- a/libexec/tgenv-version-name +++ b/libexec/tgenv-version-name @@ -5,7 +5,7 @@ set -e [ -n "${TGENV_DEBUG}" ] && set -x source "${TGENV_ROOT}/libexec/helpers" -[ -d "${TGENV_ROOT}/versions" ] \ +[ -d "${TGENV_CONFIG_DIR}/versions" ] \ || error_and_die "No versions of terragrunt installed. Please install one with: tgenv install" TGENV_VERSION_FILE="$(tgenv-version-file)" @@ -13,7 +13,7 @@ TGENV_VERSION="$(cat "${TGENV_VERSION_FILE}" || true)" if [[ "${TGENV_VERSION}" =~ ^latest.*$ ]]; then [[ "${TGENV_VERSION}" =~ ^latest\:.*$ ]] && regex="${TGENV_VERSION##*\:}" - version="$(\ls "${TGENV_ROOT}/versions" \ + version="$(\ls "${TGENV_CONFIG_DIR}/versions" \ | sort -t'.' -k 1nr,1 -k 2nr,2 -k 3nr,3 \ | grep -e "${regex}" \ | head -n 1 @@ -27,11 +27,11 @@ fi version_exists() { local version="${1}" - [ -d "${TGENV_ROOT}/versions/${version}" ] + [ -d "${TGENV_CONFIG_DIR}/versions/${version}" ] } -if ! version_exists "${TGENV_VERSION}"; then - warn_and_continue "version '${TGENV_VERSION}' is not installed (set by ${TGENV_VERSION_FILE})" +if version_exists "${TGENV_VERSION}"; then + echo "${TGENV_VERSION}" +else + error_and_die "version '${TGENV_VERSION}' is not installed (set by ${TGENV_VERSION_FILE})" fi - -echo "${TGENV_VERSION}" diff --git a/list_all_versions_offline b/list_all_versions_offline index 9a624b8..1ee28c6 100644 --- a/list_all_versions_offline +++ b/list_all_versions_offline @@ -1,3 +1,108 @@ +0.36.6 +0.36.5 +0.36.4 +0.36.3 +0.36.2 +0.36.1 +0.36.0 +0.35.20 +0.35.19 +0.35.18 +0.35.17 +0.35.16 +0.35.15 +0.35.14 +0.35.13 +0.35.12 +0.35.11 +0.35.10 +0.35.9 +0.35.8 +0.35.7 +0.35.6 +0.35.5 +0.35.4 +0.35.3 +0.35.2 +0.35.1 +0.35.0 +0.34.3 +0.34.2 +0.34.1 +0.34.0 +0.33.2 +0.33.1 +0.33.0 +0.32.6 +0.32.5 +0.32.4 +0.32.3 +0.32.2 +0.32.1 +0.32.0 +0.31.11 +0.31.10 +0.31.9 +0.31.8 +0.31.7 +0.31.6 +0.31.5 +0.31.4 +0.31.3 +0.31.2 +0.31.1 +0.31.0 +0.30.7 +0.30.6 +0.30.5 +0.30.4 +0.30.3 +0.30.2 +0.30.1 +0.30.0 +0.29.10 +0.29.9 +0.29.8 +0.29.7 +0.29.6 +0.29.5 +0.29.4 +0.29.3 +0.29.2 +0.29.1 +0.29.0 +0.28.24 +0.28.23 +0.28.22 +0.28.21 +0.28.20 +0.28.19 +0.28.18 +0.28.17 +0.28.16 +0.28.15 +0.28.14 +0.28.13 +0.28.12 +0.28.11 +0.28.10 +0.28.9 +0.28.8 +0.28.7 +0.28.6 +0.28.5 +0.28.4 +0.28.3 +0.28.2 +0.28.1 +0.28.0 +0.27.4 +0.27.3 +0.27.2 +0.27.1 +0.27.0 +0.26.7 +0.26.6 0.18.2 0.13.19 0.13.18