Skip to content

Commit

Permalink
Merge branch 'master' into download-latest-version-if-regex-is-used
Browse files Browse the repository at this point in the history
  • Loading branch information
Zordrak authored Aug 14, 2021
2 parents a02314b + 7a27c10 commit 5eaa14f
Show file tree
Hide file tree
Showing 15 changed files with 130 additions and 99 deletions.
1 change: 0 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ jobs:
- 'macos-10.15'
- 'ubuntu-20.04'
- 'ubuntu-18.04'
- 'ubuntu-16.04'
- 'windows-2019'
steps:
- uses: 'actions/checkout@v2'
Expand Down
83 changes: 46 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ Currently tfenv supports the following OSes

Install via Homebrew

```console
$ brew install tfenv
```
```console
$ brew install tfenv
```

Install via Arch User Repository (AUR)

```console
$ yay --sync tfenv
```
```console
$ yay --sync tfenv
```

Install via puppet

Expand All @@ -42,31 +42,31 @@ include ::tfenv

1. Check out tfenv into any path (here is `${HOME}/.tfenv`)

```console
$ git clone https://github.com/tfutils/tfenv.git ~/.tfenv
```
```console
$ git clone https://github.com/tfutils/tfenv.git ~/.tfenv
```

2. Add `~/.tfenv/bin` to your `$PATH` any way you like

```console
$ echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ~/.bash_profile
```
```console
$ echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ~/.bash_profile
```

OR you can make symlinks for `tfenv/bin/*` scripts into a path that is already added to your `$PATH` (e.g. `/usr/local/bin`) `OSX/Linux Only!`

```console
$ ln -s ~/.tfenv/bin/* /usr/local/bin
```
```console
$ ln -s ~/.tfenv/bin/* /usr/local/bin
```

On Ubuntu/Debian touching `/usr/local/bin` might require sudo access, but you can create `${HOME}/bin` or `${HOME}/.local/bin` and on next login it will get added to the session `$PATH`
or by running `. ${HOME}/.profile` it will get added to the current shell session's `$PATH`.

```console
$ mkdir -p ~/.local/bin/
$ . ~/.profile
$ ln -s ~/.tfenv/bin/* ~/.local/bin
$ which tfenv
```
```console
$ mkdir -p ~/.local/bin/
$ . ~/.profile
$ ln -s ~/.tfenv/bin/* ~/.local/bin
$ which tfenv
```

## Usage

Expand All @@ -78,7 +78,7 @@ If no parameter is passed, the version to use is resolved automatically via [.te

If a parameter is passed, available options:

- `i.j.k` exact version to install
- `x.y.z` [Semver 2.0.0](https://semver.org/) string specifying the 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.
Expand Down Expand Up @@ -110,7 +110,7 @@ validation failure.

#### .terraform-version

If you use a [.terraform-version file](#terraform-version-file), `tfenv install` (no argument) will install the version written in it.
If you use a [.terraform-version](#terraform-version-file) file, `tfenv install` (no argument) will install the version written in it.

#### min-required

Expand Down Expand Up @@ -141,7 +141,7 @@ String (Default: amd64)
Specify architecture. Architecture other than the default amd64 can be specified with the `TFENV_ARCH` environment variable

```console
TFENV_ARCH=arm tfenv install 0.7.9
$ TFENV_ARCH=arm tfenv install 0.7.9
```

##### `TFENV_AUTO_INSTALL`
Expand All @@ -151,7 +151,7 @@ String (Default: true)
Should tfenv automatically install terraform if the version specified by defaults or a .terraform-version file is not currently installed.

```console
TFENV_AUTO_INSTALL=false terraform plan
$ TFENV_AUTO_INSTALL=false terraform plan
```

##### `TFENV_CURL_OUTPUT`
Expand Down Expand Up @@ -182,7 +182,17 @@ String (Default: https://releases.hashicorp.com)
To install from a remote other than the default

```console
TFENV_REMOTE=https://example.jfrog.io/artifactory/hashicorp
$ TFENV_REMOTE=https://example.jfrog.io/artifactory/hashicorp
```

##### `TFENV_CONFIG_DIR`

Path (Default: `$TFENV_ROOT`)

The path to a directory where the local terraform versions and configuration files exist.

```console
TFENV_CONFIG_DIR="$XDG_CONFIG_HOME/tfenv"
```

##### `TFENV_TERRAFORM_VERSION`
Expand All @@ -196,7 +206,7 @@ If not empty string, this variable overrides Terraform version, specified in [.t
e.g.

```console
TFENV_TERRAFORM_VERSION=latest:^0.11. terraform --version
$ TFENV_TERRAFORM_VERSION=latest:^0.11. terraform --version
```

#### Bashlog Logging Library
Expand Down Expand Up @@ -237,7 +247,7 @@ Each executable logs to its own file.
e.g.

```console
BASHLOG_FILE=1 tfenv use latest
$ BASHLOG_FILE=1 tfenv use latest
```

will log to `/tmp/tfenv-use.log`
Expand All @@ -259,7 +269,7 @@ This variable allows you to pass a string containing a command that will be exec
e.g.

```console
BASHLOG_I_PROMISE_TO_BE_CAREFUL_CUSTOM_EVAL_PREFIX='echo "${$$} "'
$ BASHLOG_I_PROMISE_TO_BE_CAREFUL_CUSTOM_EVAL_PREFIX='echo "${$$} "'
```
will prefix every log line with the calling process' PID.

Expand All @@ -275,7 +285,7 @@ Each executable logs to its own file.
e.g.

```console
BASHLOG_JSON=1 tfenv use latest
$ BASHLOG_JSON=1 tfenv use latest
```

will log in JSON format to `/tmp/tfenv-use.log.json`
Expand All @@ -299,11 +309,10 @@ To log to syslog using the `logger` binary, set this to 1.
The basic functionality is thus:

```console
local tag="${BASHLOG_SYSLOG_TAG:-$(basename "${0}")}";
local facility="${BASHLOG_SYSLOG_FACILITY:-local0}";
local pid="${$}";

logger --id="${pid}" -t "${tag}" -p "${facility}.${severity}" "${syslog_line}"
$ local tag="${BASHLOG_SYSLOG_TAG:-$(basename "${0}")}";
$ local facility="${BASHLOG_SYSLOG_FACILITY:-local0}";
$ local pid="${$}";
$ logger --id="${pid}" -t "${tag}" -p "${facility}.${severity}" "${syslog_line}"
```

##### `BASHLOG_SYSLOG_FACILITY`
Expand Down Expand Up @@ -359,7 +368,7 @@ $ tfenv uninstall latest:^0.8
List installed versions

```console
% tfenv list
$ tfenv list
* 0.10.7 (set by /opt/tfenv/version)
0.9.0-beta2
0.8.8
Expand All @@ -376,7 +385,7 @@ List installed versions
List installable versions

```console
% tfenv list-remote
$ tfenv list-remote
0.9.0-beta2
0.9.0-beta1
0.8.8
Expand Down
2 changes: 1 addition & 1 deletion bin/terraform
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ 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";
[ "${TFENV_DEBUG:-0}" -gt 0 ] && >&2 echo "[DEBUG] Sourcing helpers from ${TFENV_ROOT}/lib/helpers.sh";
if source "${TFENV_ROOT}/lib/helpers.sh"; then
log 'debug' 'Helpers sourced successfully';
else
Expand Down
2 changes: 1 addition & 1 deletion bin/tfenv
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ 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";
[ "${TFENV_DEBUG:-0}" -gt 0 ] && >&2 echo "[DEBUG] Sourcing helpers from ${TFENV_ROOT}/lib/helpers.sh";
if source "${TFENV_ROOT}/lib/helpers.sh"; then
log 'debug' 'Helpers sourced successfully';
else
Expand Down
2 changes: 1 addition & 1 deletion lib/bashlog.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function log() {

local level="${1}";
local upper="$(echo "${level}" | awk '{print toupper($0)}')";
local debug_level="${DEBUG:-0}";
local debug_level="${TFENV_DEBUG:-0}";
local stdout_colours="${BASHLOG_COLOURS:-1}";
local stdout_extra="${BASHLOG_EXTRA:-0}";

Expand Down
24 changes: 17 additions & 7 deletions lib/helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,18 @@ else
fi;
export TFENV_ROOT;

if [ -z "${TFENV_CONFIG_DIR:-""}" ]; then
TFENV_CONFIG_DIR="$TFENV_ROOT";
else
TFENV_CONFIG_DIR="${TFENV_CONFIG_DIR%/}";
fi
export TFENV_CONFIG_DIR;

if [ "${TFENV_DEBUG:-0}" -gt 0 ]; then
[ "${DEBUG:-0}" -gt "${TFENV_DEBUG:-0}" ] || export DEBUG="${TFENV_DEBUG:-0}";
# Only reset DEBUG if TFENV_DEBUG is set, and DEBUG is unset or already a number
if [[ "${DEBUG:-0}" =~ ^[0-9]+$ ]] && [ "${DEBUG:-0}" -gt "${TFENV_DEBUG:-0}" ]; then
export DEBUG="${TFENV_DEBUG:-0}";
fi;
if [[ "${TFENV_DEBUG}" -gt 2 ]]; then
export PS4='+ [${BASH_SOURCE##*/}:${LINENO}] ';
set -x;
Expand All @@ -43,13 +53,13 @@ resolve_version () {
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)";
if [ "${version_file}" != "${TFENV_CONFIG_DIR}/version" ]; then
log 'debug' "Version File (${version_file}) is not the default \${TFENV_CONFIG_DIR}/version (${TFENV_CONFIG_DIR}/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)";
log 'debug' "Version File is the default \${TFENV_CONFIG_DIR}/version (${TFENV_CONFIG_DIR}/version)";
version_requested="$(cat "${version_file}")" \
|| log 'error' "Failed to open ${version_file}";

Expand All @@ -60,7 +70,7 @@ resolve_version () {
fi;

else
log 'debug' "Version File is the default \${TFENV_ROOT}/version (${TFENV_ROOT}/version) but it doesn't exist";
log 'debug' "Version File is the default \${TFENV_CONFIG_DIR}/version (${TFENV_CONFIG_DIR}/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;
Expand Down Expand Up @@ -118,14 +128,14 @@ export -f check_active_version;

check_installed_version() {
local v="${1}";
local bin="${TFENV_ROOT}/versions/${v}/terraform";
local bin="${TFENV_CONFIG_DIR}/versions/${v}/terraform";
[ -n "$(${bin} version | grep -E "^Terraform v${v}((-dev)|( \([a-f0-9]+\)))?$")" ];
};
export -f check_installed_version;

check_default_version() {
local v="${1}";
local def="$(cat "${TFENV_ROOT}/version")";
local def="$(cat "${TFENV_CONFIG_DIR}/version")";
[ "${def}" == "${v}" ];
};
export -f check_default_version;
Expand Down
4 changes: 2 additions & 2 deletions libexec/tfenv-exec
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ TFENV_VERSION="$(tfenv-version-name)" \
};
export TFENV_VERSION;

if [ ! -d "${TFENV_ROOT}/versions/${TFENV_VERSION}" ]; then
if [ ! -d "${TFENV_CONFIG_DIR}/versions/${TFENV_VERSION}" ]; then
if [ "${TFENV_AUTO_INSTALL:-true}" == "true" ]; then
if [ -z "${TFENV_TERRAFORM_VERSION:-""}" ]; then
TFENV_VERSION_SOURCE="$(tfenv-version-file)";
Expand All @@ -97,7 +97,7 @@ if [ ! -d "${TFENV_ROOT}/versions/${TFENV_VERSION}" ]; then
fi;
fi;

TF_BIN_PATH="${TFENV_ROOT}/versions/${TFENV_VERSION}/terraform";
TF_BIN_PATH="${TFENV_CONFIG_DIR}/versions/${TFENV_VERSION}/terraform";
export PATH="${TF_BIN_PATH}:${PATH}";
log 'debug' "TF_BIN_PATH added to PATH: ${TF_BIN_PATH}";
log 'debug' "Executing: ${TF_BIN_PATH} $@";
Expand Down
26 changes: 18 additions & 8 deletions libexec/tfenv-install
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ done;
declare requested="${1:-""}";

log debug "Resolving version with: tfenv-resolve-version ${requested}";
declare resolved="$(tfenv-resolve-version ${requested})";
declare resolved;
resolved="$(tfenv-resolve-version ${requested})" || log 'error' "Failed to resolve ${requested} version";

declare version="${resolved%%\:*}";
declare regex="${resolved##*\:}";
Expand All @@ -75,13 +76,22 @@ 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 '${requested}' found in remote";

dst_path="${TFENV_ROOT}/versions/${version}";
dst_path="${TFENV_CONFIG_DIR}/versions/${version}";
if [ -f "${dst_path}/terraform" ]; then
echo "Terraform v${version} is already installed";
exit 0;
fi;

TFENV_ARCH="${TFENV_ARCH:-amd64}";
# Add support of ARM64 for Linux & Apple Silicon
case "$(uname -m)" in
aarch64* | arm64*)
TFENV_ARCH="${TFENV_ARCH:-arm64}";
;;
*)
TFENV_ARCH="${TFENV_ARCH:-amd64}";
;;
esac;

case "$(uname -s)" in
Darwin*)
os="darwin_${TFENV_ARCH}";
Expand Down Expand Up @@ -171,12 +181,12 @@ if [[ $(uname) == 'Darwin' ]] && [ $(which brew) ]; then
fi

# Verify signature if verification mechanism (keybase, gpg, etc) is present
if [[ -f "${TFENV_ROOT}/use-gnupg" ]]; then
if [[ -f "${TFENV_CONFIG_DIR}/use-gnupg" ]]; then
# GnuPG uses the user's keyring, and any web-of-trust or local signatures or
# anything else they have setup. This is the crazy-powerful mode which is
# overly confusing to newcomers. We don't support it without the user creating
# the file use-gnupg, optionally with directives in it.
gnupg_command="$(sed -E -n -e 's/^binary: *//p' <"${TFENV_ROOT}/use-gnupg")";
gnupg_command="$(sed -E -n -e 's/^binary: *//p' <"${TFENV_CONFIG_DIR}/use-gnupg")";
[[ -n "${gnupg_command}" ]] || gnupg_command=gpg;

download_signature;
Expand All @@ -187,13 +197,13 @@ if [[ -f "${TFENV_ROOT}/use-gnupg" ]]; then
"${download_tmp}/${shasums_name}" \
|| log 'error' 'PGP signature rejected by GnuPG';

elif [[ -f "${TFENV_ROOT}/use-gpgv" ]]; then
elif [[ -f "${TFENV_CONFIG_DIR}/use-gpgv" ]]; then
# gpgv is a much simpler interface to verification, but does require that the
# key have been downloaded and marked trusted.
# We don't force the caller to trust the tfenv repo's copy of their key, they
# have to choose to make that trust decision.
gpgv_command="$(sed -E -n -e 's/^binary: *//p' <"${TFENV_ROOT}/use-gpgv")";
trust_tfenv="$(sed -E -n -e 's/^trust.?tfenv: *//p' <"${TFENV_ROOT}/use-gpgv")";
gpgv_command="$(sed -E -n -e 's/^binary: *//p' <"${TFENV_CONFIG_DIR}/use-gpgv")";
trust_tfenv="$(sed -E -n -e 's/^trust.?tfenv: *//p' <"${TFENV_CONFIG_DIR}/use-gpgv")";
[[ -n "${gpgv_command}" ]] || gpgv_command=gpgv;

download_signature;
Expand Down
Loading

0 comments on commit 5eaa14f

Please sign in to comment.