tfenvy
Tags: terraform, windows, gitbash
Published: 2024-01-29 17:52:40

**Terraform / Git-Bash / Windows**

For almost four years I'd been using a Macbook as my main work machine. One quality of life tool I'd gotten used to was [tfenv](https://github.com/tfutils/tfenv), a lovely little tool for managing terraform versions & quickly switching between them. 

I'm now using a Windows machine as my main work laptop having recently started a new job. I'm fairly pragmatic and don't really mind what OS my work laptop runs... at least until I found out that tfenv wasn't available on Windows/git-bash. Sad face. 

I was jealous that I wouldn't be able to use tfenv any more... I wanted something like tfenv for git-bash... tfenvy was born.

If you're starting to think I'm only writing this article because I'm super proud of the punny name I came up with... you would be right, but still, this might be useful to you if you're using git-bash on Windows to manage terraform code. 

'tfenvy' allows you to
- List available versions of terraform (stable versions only).
- List locally installed versions of terraform.
- Download a specific version of terraform locally. 
- Activate a specific version of terraform to use. 
- Update to the latest version of terraform for windows. 
- Remove a version of terraform you no longer need. 

I don't have an installer yet, but it's simple to setup: 

1. Copy the script below and place it in a suitable PATH for you, making sure it's executable. 
2. Update TF_DIR and replace YOURUSERNAME with your user name, and make sure you have a 'bin' folder, sorry - directory, there. 


```
#!/usr/bin/sh

# A super basic attempt to recreate the benefits of choosing a tf version since tfenv isn't yet supported on windows.

# Set Variables:
TF_DOWNLOAD="https://releases.hashicorp.com/terraform/"
TF_DIR="/c/Users/YOURUSERNAME/bin"
NUMARGS=$#



####################################################################################################################
# FUNCTIONS - anything we might need to do more than once - write a function for.

#
# Function to find current ACTIVE version of terraform
#
list_active_tf () {
        CURRENT=`terraform -v 2> /dev/null | head -1 | cut -f 2 -d v`
        if [ -z $CURRENT ] ; then
                echo "TF not currently installed."
                exit 1
        else
                export CURRENT
        fi
}


#
# Function to list ALL available stable releases of terraform
#
list_online_versions () {
        curl -s $TF_DOWNLOAD | grep href | egrep -v "alpha|rc|beta" | sort -n | cut -f 3 -d /
}


#
# Function to find the LATEST stable release of terraform
#
list_latest_version (){
        LATEST=`list_online_versions | tail -1`
        export LATEST
}


#
# Function to compare semantic formatted versions (e.g. 1.2.3)
# Credit to: https://stackoverflow.com/questions/4023830/how-to-compare-two-strings-in-dot-separated-version-format-in-bash
#
vercomp () {
    if [[ $1 == $2 ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
        then
            # fill empty fields in ver2 with zeros
            ver2[i]=0
        fi
        if ((10#${ver1[i]} > 10#${ver2[i]}))
        then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
        then
            return 2
        fi
    done
    return 0
}


#
# Function to compare current version with latest available
#
compare_versions () {
        list_latest_version
        list_active_tf
        vercomp $LATEST $CURRENT
        if [ $? == "1" ] ; then
                echo "Update available. Latest=${LATEST}. Current=${CURRENT}."
        else
                echo "Latest version, ${LATEST}, already installed."
        fi
}


#
# Function to list installed versions of terraform
#
list_local_versions () {
        ls $TF_DIR | grep ^terraform-[0-9]*
}


#
# Function to activate the choosen version of terraform
#
activate_tf_version () {
        cp -p ${TF_DIR}/terraform-${WANTED}.exe ${TF_DIR}/terraform.exe
}


#
# Function to download a specific version of terraform
#
get_tf (){
        curl -s ${TF_DOWNLOAD}${WANTED}/terraform_${WANTED}_windows_amd64.zip -o /tmp/terraform_${WANTED}_windows_arm64.zip
        unzip -qp /tmp/terraform_${WANTED}_windows_arm64.zip > ${TF_DIR}/terraform-${WANTED}.exe
}

#
# Function to install the latest version of terraform
#
get_latest_tf () {
        list_latest_version
        WANTED=$LATEST
        get_tf
}


#
# Function to DELETE a specific version of terraform
#
remove_tf (){
        rm -i ${TF_DIR}/terraform-${WANTED}.exe
}


#
# Function to print usage message
#
print_usage () {
        echo "Usage:"
        echo "  -a <version>    Activate terraform <version>."
        echo "          e.g. `basename $0` -a 1.6.6"
        echo ""
        echo "  -d <version>    Download a specific terraform <version>."
        echo "          e.g. `basename $0` -d 1.0.1"
        echo ""
        echo "  -i      List all installed versions of terraform. "
        echo "          e.g. `basename $0` -i"
        echo ""
        echo "  -l      List all stable Terraform versions available from Hashicorp. "
        echo "          e.g. `basename $0` -l"
        echo ""
        echo "  -R <version>    Remove the specified terraform <version>."
        echo "          e.g. `basename $0` -R 1.0.0"
        echo ""
        echo "  -u      Update to latest stable version of terraform."
        echo "          e.g. `basename $0` -u"
        echo ""

}

# End of Functions section. Fun starts now!
####################################################################################################################


# Define Flags
while getopts 'a:ilud:R:' OPTION; do
        case "$OPTION" in
                a)
                        WANTED="$OPTARG"
                        activate_tf_version
                        ;;
                i)
                        list_local_versions
                        ;;
                l)
                        list_online_versions
                        ;;
                u)
                        get_latest_tf
                        activate_tf_version
                        ;;
                d)
                        WANTED="$OPTARG"
                        get_tf
                        ;;
                R)
                        WANTED="$OPTARG"
                        remove_tf
                        ;;
                *)
                        print_usage
                        exit 1
                        ;;
        esac
done
shift "$((OPTIND -1))"

if [ $NUMARGS == 0 ] ; then
        print_usage
        exit
fi
```