Skip to content

Commit

Permalink
A shot at v2.0.0-beta2 without use-on-install
Browse files Browse the repository at this point in the history
  • Loading branch information
Zordrak committed Mar 15, 2020
1 parent a9c7e38 commit 0007f77
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 89 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
## 2.0.0 (Unreleased)

* New logging library
* New bash4 dependency
* New logging and debugging library
* Massive testing, logging and loading refactoring
* Fix to 'use' logic: don't overwrite .terraform-version files
* Fix #167 - Never invoke use automatically on install - multiple code and testing changes for new logic
* Fix to not use 0.12.22 during testing which reports its version incorrectly
* Introduce tfenv-resolve-version to deduplicate translation of requested version into actual version
* README.md updates

## 1.0.2 (October 29, 2019)

Expand Down
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,23 @@ include ::tfenv

### tfenv install [version]

Install a specific version of Terraform. Available options for version:
Install a specific version of Terraform.

If no parameter is passed, the version to use is resolved automatically via .terraform-version files, defaulting to 'latest' if none are found.

If a parameter is passed, available options:

- `i.j.k` exact version to install
- `latest` is a syntax to install latest version
- `latest:<regex>` is a syntax to install latest version matching regex (used by grep -e)
- `min-required` is a syntax to recursively scan your Terraform files to detect which version is minimally required. See [required_version](https://www.terraform.io/docs/configuration/terraform.html) docs. Also [see min-required](#min-required) section below.

```console
$ tfenv install
$ tfenv install 0.7.0
$ tfenv install latest
$ tfenv install latest:^0.8
$ tfenv install min-required
$ tfenv install
```

If `shasum` is present in the path, tfenv will verify the download against Hashicorp's published sha256 hash.
Expand Down Expand Up @@ -146,6 +150,15 @@ Set the mechanism used for displaying download progress when downloading terrafo

##### `TFENV_DEBUG`

Integer (Default: 0)

Set the debug level for TFENV.

* 0: No debug output
* 1: Simple debug output
* 2: Extended debug output, with source file names and interactive debug shells on error
* 3: Debug level 2 + Bash execution tracing

##### `TFENV_REMOTE`

String (Default: https://releases.hashicorp.com)
Expand Down Expand Up @@ -279,17 +292,20 @@ Defaults to the PID of the calling process.



### tfenv use &lt;version>
### tfenv use [version]

Switch a version to use

If no parameter is passed, the version to use is resolved automatically via .terraform-version files, defaulting to 'latest' if none are found.

`latest` is a syntax to use the latest installed version

`latest:<regex>` is a syntax to use latest installed version matching regex (used by grep -e)

`min-required` will switch to the version minimally required by your terraform sources (see above `tfenv install`)

```console
$ tfenv use
$ tfenv use min-required
$ tfenv use 0.7.0
$ tfenv use latest
Expand Down
60 changes: 60 additions & 0 deletions lib/helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,66 @@ fi;

source "${TFENV_ROOT}/lib/bashlog.sh";

resolve_version () {
declare version_requested version regex min_required version_file;

declare arg="${1:-""}";

if [ -z "${arg}" ]; then
version_file="$(tfenv-version-file)";
log 'debug' "Version File: ${version_file}";

if [ "${version_file}" != "${TFENV_ROOT}/version" ]; then
log 'debug' "Version File (${version_file}) is not the default \${TFENV_ROOT}/version (${TFENV_ROOT}/version)";
version_requested="$(cat "${version_file}")" \
|| log 'error' "Failed to open ${version_file}";

elif [ -f "${version_file}" ]; then
log 'debug' "Version File is the default \${TFENV_ROOT}/version (${TFENV_ROOT}/version)";
version_requested="$(cat "${version_file}")" \
|| log 'error' "Failed to open ${version_file}";

# Absolute fallback
if [ -z "${version_requested}" ]; then
log 'debug' 'Version file had no content. Falling back to "latest"';
version_requested='latest';
fi;

else
log 'debug' "Version File is the default \${TFENV_ROOT}/version (${TFENV_ROOT}/version) but it doesn't exist";
log 'info' 'No version requested on the command line or in the version file search path. Installing "latest"';
version_requested='latest';
fi;
else
version_requested="${arg}";
fi;

log 'debug' "Version Requested: ${version_requested}";

if [[ "${version_requested}" =~ ^min-required$ ]]; then
log 'info' 'Detecting minimum required version...';
min_required="$(tfenv-min-required)" \
|| log 'error' 'tfenv-min-required failed';

log 'info' "Minimum required version detected: ${min_required}";
version_requested="${min_required}";
fi;

if [[ "${version_requested}" =~ ^latest\:.*$ ]]; then
version="${version_requested%%\:*}";
regex="${version_requested##*\:}";
log 'debug' "Version uses latest keyword with regex: ${regex}";
elif [[ "${version_requested}" =~ ^latest$ ]]; then
version="${version_requested}";
regex="^[0-9]\+\.[0-9]\+\.[0-9]\+$";
log 'debug' "Version uses latest keyword alone. Forcing regex to match stable versions only: ${regex}";
else
version="${version_requested}";
regex="^${version_requested}$";
log 'debug' "Version is explicit: ${version}. Regex enforces the version: ${regex}";
fi;
}

# Curl wrapper to switch TLS option for each OS
function curlw () {
local TLS_OPT="--tlsv1.2";
Expand Down
56 changes: 7 additions & 49 deletions libexec/tfenv-install
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env bash

set -uo pipefail;

####################################
Expand Down Expand Up @@ -61,60 +60,20 @@ done;

[ "${#}" -gt 1 ] && log 'error' 'usage: tfenv install [<version>]';

declare version_requested version regex;
declare arg="${1:-""}";

if [ -z "${arg}" ]; then
version_file="$(tfenv-version-file)";
log 'debug' "Version File: ${version_file}";
if [ "${version_file}" != "${TFENV_ROOT}/version" ]; then
log 'debug' "Version File (${version_file}) is not the default \${TFENV_ROOT}/version (${TFENV_ROOT}/version)";
version_requested="$(cat "${version_file}")" \
|| log 'error' "Failed to open ${version_file}";
elif [ -f "${version_file}" ]; then
log 'debug' "Version File is the default \${TFENV_ROOT}/version (${TFENV_ROOT}/version)";
version_requested="$(cat "${version_file}")" \
|| log 'error' "Failed to open ${version_file}";
else
log 'debug' "Version File is the default \${TFENV_ROOT}/version (${TFENV_ROOT}/version) but it doesn't exist";
log 'info' 'No version requested on the command line or in the version file search path. Installing "latest"';
version_requested='latest';
fi;
else
version_requested="${arg}";
fi;

log 'debug' "Version Requested: ${version_requested}";
declare requested="${1:-""}";

if [[ "${version_requested}" =~ ^min-required$ ]]; then
log 'info' 'Detecting minimal required version...';
found_min_required="$(tfenv-min-required)";
log debug "Resolving version with: tfenv-resolve-version ${requested}";
declare resolved="$(tfenv-resolve-version ${requested})";

if [[ $? -eq 0 ]]; then
log 'info' "Min required version is detected as ${found_min_required}";
version_requested="${found_min_required}";
else
exit 1;
fi;
fi;

if [[ "${version_requested}" =~ ^latest\:.*$ ]]; then
version="${version_requested%%\:*}";
regex="${version_requested##*\:}";
elif [[ "${version_requested}" =~ ^latest$ ]]; then
version="${version_requested}";
regex="^[0-9]\+\.[0-9]\+\.[0-9]\+$";
else
version="${version_requested}";
regex="^${version_requested}$";
fi;
declare version="${resolved%%\:*}";
declare regex="${resolved##*\:}";

[ -n "${version}" ] || log 'error' 'Version is not specified. This should not be possible as we default to latest';

log 'debug' "Processing install for version ${version}, using regex ${regex}";

version="$(tfenv-list-remote | grep -e "${regex}" | head -n 1)";
[ -n "${version}" ] || log 'error' "No versions matching '${arg}' found in remote";
[ -n "${version}" ] || log 'error' "No versions matching '${requested}' found in remote";

dst_path="${TFENV_ROOT}/versions/${version}";
if [ -f "${dst_path}/terraform" ]; then
Expand Down Expand Up @@ -279,5 +238,4 @@ while IFS= read -r unzip_line; do
log 'info' "${unzip_line}";
done < <(printf '%s\n' "${unzip_output}");

log 'info' "Installation of terraform v${version} successful";
tfenv-use "${version}";
log 'info' "Installation of terraform v${version} successful. To make this your default version, run 'tfenv use ${version}'";
122 changes: 122 additions & 0 deletions libexec/tfenv-resolve-version
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env bash
# Usage: tfenv resolve-version [<version>]
# Summary: Resolve the version to action based on the environment and optional input token

set -uo pipefail;

####################################
# Ensure we can execute standalone #
####################################

function early_death() {
echo "[FATAL] ${0}: ${1}" >&2;
exit 1;
};

if [ -z "${TFENV_ROOT:-""}" ]; then
# http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac
readlink_f() {
local target_file="${1}";
local file_name;

while [ "${target_file}" != "" ]; do
cd "$(dirname ${target_file})" || early_death "Failed to 'cd \$(dirname ${target_file})' while trying to determine TFENV_ROOT";
file_name="$(basename "${target_file}")" || early_death "Failed to 'basename \"${target_file}\"' while trying to determine TFENV_ROOT";
target_file="$(readlink "${file_name}")";
done;

echo "$(pwd -P)/${file_name}";
};

TFENV_ROOT="$(cd "$(dirname "$(readlink_f "${0}")")/.." && pwd)";
[ -n ${TFENV_ROOT} ] || early_death "Failed to 'cd \"\$(dirname \"\$(readlink_f \"${0}\")\")/..\" && pwd' while trying to determine TFENV_ROOT";
else
TFENV_ROOT="${TFENV_ROOT%/}";
fi;
export TFENV_ROOT;

if [ -n "${TFENV_HELPERS:-""}" ]; then
log 'debug' 'TFENV_HELPERS is set, not sourcing helpers again';
else
[ "${TFENV_DEBUG:-0}" -gt 0 ] && echo "[DEBUG] Sourcing helpers from ${TFENV_ROOT}/lib/helpers.sh";
if source "${TFENV_ROOT}/lib/helpers.sh"; then
log 'debug' 'Helpers sourced successfully';
else
early_death "Failed to source helpers from ${TFENV_ROOT}/lib/helpers.sh";
fi;
fi;

# Ensure libexec and bin are in $PATH
for dir in libexec bin; do
case ":${PATH}:" in
*:${TFENV_ROOT}/${dir}:*) log 'debug' "\$PATH already contains '${TFENV_ROOT}/${dir}', not adding it again";;
*)
log 'debug' "\$PATH does not contain '${TFENV_ROOT}/${dir}', prepending and exporting it now";
export PATH="${TFENV_ROOT}/${dir}:${PATH}";
;;
esac;
done;

#####################
# Begin Script Body #
#####################

declare version_requested version regex min_required version_file;

declare arg="${1:-""}";

if [ -z "${arg}" ]; then
version_file="$(tfenv-version-file)";
log 'debug' "Version File: ${version_file}";

if [ "${version_file}" != "${TFENV_ROOT}/version" ]; then
log 'debug' "Version File (${version_file}) is not the default \${TFENV_ROOT}/version (${TFENV_ROOT}/version)";
version_requested="$(cat "${version_file}")" \
|| log 'error' "Failed to open ${version_file}";

elif [ -f "${version_file}" ]; then
log 'debug' "Version File is the default \${TFENV_ROOT}/version (${TFENV_ROOT}/version)";
version_requested="$(cat "${version_file}")" \
|| log 'error' "Failed to open ${version_file}";

# Absolute fallback
if [ -z "${version_requested}" ]; then
log 'debug' 'Version file had no content. Falling back to "latest"';
version_requested='latest';
fi;

else
log 'debug' "Version File is the default \${TFENV_ROOT}/version (${TFENV_ROOT}/version) but it doesn't exist";
log 'info' 'No version requested on the command line or in the version file search path. Installing "latest"';
version_requested='latest';
fi;
else
version_requested="${arg}";
fi;

log 'debug' "Version Requested: ${version_requested}";

if [[ "${version_requested}" =~ ^min-required$ ]]; then
log 'info' 'Detecting minimum required version...';
min_required="$(tfenv-min-required)" \
|| log 'error' 'tfenv-min-required failed';

log 'info' "Minimum required version detected: ${min_required}";
version_requested="${min_required}";
fi;

if [[ "${version_requested}" =~ ^latest\:.*$ ]]; then
version="${version_requested%%\:*}";
regex="${version_requested##*\:}";
log 'debug' "Version uses latest keyword with regex: ${regex}";
elif [[ "${version_requested}" =~ ^latest$ ]]; then
version="${version_requested}";
regex="^[0-9]\+\.[0-9]\+\.[0-9]\+$";
log 'debug' "Version uses latest keyword alone. Forcing regex to match stable versions only: ${regex}";
else
version="${version_requested}";
regex="^${version_requested}$";
log 'debug' "Version is explicit: ${version}. Regex enforces the version: ${regex}";
fi;

echo "${version}:${regex}";
Loading

0 comments on commit 0007f77

Please sign in to comment.