Skip to content

Commit

Permalink
Refactor code - if version exist, simply change symlink
Browse files Browse the repository at this point in the history
  • Loading branch information
warrensbox committed Nov 29, 2021
1 parent 1a7aa80 commit 09816b6
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 85 deletions.
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
EXE := tfswitch
PKG := github.com/warrensbox/terraform-switcher
#VER := $(shell git ls-remote --tags . | awk '{print $$2}'| awk -F"/" '{print $$3}' | sort -n -t. -k1,1 -k2,2 -k3,3 | tail -n 2 | head -n1)
VER := $(shell git ls-remote --tags . | awk '{print $$2}'| awk -F"/" '{print $$3}' | sort -n -t. -k1,1 -k2,2 -k3,3 | tail -n 1)
VER := $(shell git ls-remote --tags git://github.com/warrensbox/terraform-switcher | awk '{print $$2}'| awk -F"/" '{print $$3}' | sort -n -t. -k1,1 -k2,2 -k3,3 | tail -n 2 | head -n1)
PATH := build:$(PATH)
GOOS ?= $(shell go env GOOS)
GOARCH ?= $(shell go env GOARCH)
Expand Down
13 changes: 3 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ Installation for other linux operation systems.
curl -L https://github.com/raw/warrensbox/terraform-switcher/release/install.sh | bash
```

### Snapcraft for CentOS, Ubuntu, Linux Mint, RHEL, Debian, Fedora

Support for snap will be removed on Set 16, 2021
```sh
sudo snap install tfswitch
```

### Arch User Repository (AUR) packages for Arch Linux

```sh
Expand Down Expand Up @@ -166,10 +159,10 @@ terraform_version_constraint = ">= 0.13, < 0.14"
...
```

### Gather the version from a subdirectory
### Get the version from a subdirectory
```bash
tfswitch --chdir terraform
tfswitch -c terraform
tfswitch --chdir terraform_dir
tfswitch -c terraform_dir
```

### Use custom mirror
Expand Down
6 changes: 3 additions & 3 deletions lib/download_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestDownloadFromURL_FileNameMatch(t *testing.T) {

hashiURL := "https://releases.hashicorp.com/terraform/"
installVersion := "terraform_"
installPath := getInstallLocation(".terraform.versions_test")
installPath := GetInstallLocation(".terraform.versions_test")
macOS := "_darwin_amd64.zip"

// get current user
Expand Down Expand Up @@ -92,7 +92,7 @@ func TestDownloadFromURL_FileExist(t *testing.T) {
hashiURL := "https://releases.hashicorp.com/terraform/"
installFile := "terraform"
installVersion := "terraform_"
installPath := getInstallLocation(".terraform.versions_test")
installPath := GetInstallLocation(".terraform.versions_test")
macOS := "_darwin_amd64.zip"

// get current user
Expand Down Expand Up @@ -166,7 +166,7 @@ func TestInvalidURL(t *testing.T) {

hashiURL := "https://releases.hashicorp.com/terraform/"
installVersion := "terraform_"
installPath := getInstallLocation(".terraform.versions_test")
installPath := GetInstallLocation(".terraform.versions_test")
macOS := "_darwin_amd64.zip"
invalidVersion := "0.11.7-nonexistent"

Expand Down
110 changes: 48 additions & 62 deletions lib/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ import (
"path/filepath"
"runtime"
"strings"

"github.com/hashicorp/go-version"
)

const (
installFile = "terraform"
installVersion = "terraform_"
installPath = ".terraform.versions"
recentFile = "RECENT"
defaultBin = "/usr/local/bin/terraform" //default bin installation dir
tfDarwinArm64StartVersion = "1.0.2"
installFile = "terraform"
versionPrefix = "terraform_"
installPath = ".terraform.versions"
recentFile = "RECENT"
defaultBin = "/usr/local/bin/terraform" //default bin installation dir
tfDarwinArm64StartVersion = "1.0.2"
)

var (
Expand Down Expand Up @@ -53,9 +54,9 @@ func initialize() {

}

// getInstallLocation : get location where the terraform binary will be installed,
// GetInstallLocation : get location where the terraform binary will be installed,
// will create a directory in the home location if it does not exist
func getInstallLocation() string {
func GetInstallLocation() string {
/* get current user */
usr, errCurr := user.Current()
if errCurr != nil {
Expand All @@ -64,13 +65,6 @@ func getInstallLocation() string {

userCommon := usr.HomeDir

/* For snapcraft users, SNAP_USER_COMMON environment variable is set by default.
* tfswitch does not have permission to save to $HOME/.terraform.versions for snapcraft users
* tfswitch will save binaries into $SNAP_USER_COMMON/.terraform.versions */
if os.Getenv("SNAP_USER_COMMON") != "" {
userCommon = os.Getenv("SNAP_USER_COMMON")
}

/* set installation location */
installLocation = filepath.Join(userCommon, installPath)

Expand All @@ -84,35 +78,33 @@ func getInstallLocation() string {
//Install : Install the provided version in the argument
func Install(tfversion string, binPath string, mirrorURL string) {

if !ValidVersionFormat(tfversion) {
fmt.Printf("The provided terraform version format does not exist - %s. Try `tfswitch -l` to see all available versions.\n", tfversion)
os.Exit(1)
}
// if !ValidVersionFormat(tfversion) {
// fmt.Printf("The provided terraform version format does not exist - %s. Try `tfswitch -l` to see all available versions.\n", tfversion)
// os.Exit(1)
// }

pathDir := Path(binPath) //get path directory from binary path
//binDirExist := CheckDirExist(pathDir) //check bin path exist
/* Check to see if user has permission to the default bin location which is "/usr/local/bin/terraform"
* If user does not have permission to default bin location, proceed to create $HOME/bin and install the tfswitch there
* Inform user that they dont have permission to default location, therefore tfswitch was installed in $HOME/bin
* Tell users to add $HOME/bin to their path
*/
binPath = InstallableBinLocation(pathDir)
binPath = InstallableBinLocation(binPath)

initialize() //initialize path
installLocation = getInstallLocation() //get installation location - this is where we will put our terraform binary file
installLocation = GetInstallLocation() //get installation location - this is where we will put our terraform binary file

goarch := runtime.GOARCH
goos := runtime.GOOS

// Terraform darwin arm64 comes with 1.0.2 and next version
tfver, _ := version.NewVersion(tfversion)
tf102, _ := version.NewVersion(tfDarwinArm64StartVersion)
if goos == "darwin" && goarch == "arm64" && tfver.LessThan(tf102) {
if goos == "darwin" && goarch == "arm64" && tfver.LessThan(tf102) {
goarch = "amd64"
}

/* check if selected version already downloaded */
installFileVersionPath := ConvertExecutableExt(filepath.Join(installLocation, installVersion+tfversion))
installFileVersionPath := ConvertExecutableExt(filepath.Join(installLocation, versionPrefix+tfversion))
fileExist := CheckFileExist(installFileVersionPath)

/* if selected version already exist, */
Expand All @@ -127,7 +119,7 @@ func Install(tfversion string, binPath string, mirrorURL string) {

/* set symlink to desired version */
CreateSymlink(installFileVersionPath, binPath)
fmt.Printf("Switched terraform to version %q \n", tfversion)
fmt.Printf("Switched1 terraform to version %q \n", tfversion)
AddRecent(tfversion) //add to recent file for faster lookup
os.Exit(0)
}
Expand All @@ -140,7 +132,7 @@ func Install(tfversion string, binPath string, mirrorURL string) {

/* if selected version already exist, */
/* proceed to download it from the hashicorp release page */
url := mirrorURL + tfversion + "/" + installVersion + tfversion + "_" + goos + "_" + goarch + ".zip"
url := mirrorURL + tfversion + "/" + versionPrefix + tfversion + "_" + goos + "_" + goarch + ".zip"
zipFile, errDownload := DownloadFromURL(installLocation, url)

/* If unable to download file from url, exit(1) immediately */
Expand Down Expand Up @@ -181,7 +173,7 @@ func Install(tfversion string, binPath string, mirrorURL string) {
// AddRecent : add to recent file
func AddRecent(requestedVersion string) {

installLocation = getInstallLocation() //get installation location - this is where we will put our terraform binary file
installLocation = GetInstallLocation() //get installation location - this is where we will put our terraform binary file
versionFile := filepath.Join(installLocation, recentFile)

fileExist := CheckFileExist(versionFile)
Expand Down Expand Up @@ -224,7 +216,7 @@ func AddRecent(requestedVersion string) {
// GetRecentVersions : get recent version from file
func GetRecentVersions() ([]string, error) {

installLocation = getInstallLocation() //get installation location - this is where we will put our terraform binary file
installLocation = GetInstallLocation() //get installation location - this is where we will put our terraform binary file
versionFile := filepath.Join(installLocation, recentFile)

fileExist := CheckFileExist(versionFile)
Expand Down Expand Up @@ -263,7 +255,7 @@ func GetRecentVersions() ([]string, error) {
//CreateRecentFile : create a recent file
func CreateRecentFile(requestedVersion string) {

installLocation = getInstallLocation() //get installation location - this is where we will put our terraform binary file
installLocation = GetInstallLocation() //get installation location - this is where we will put our terraform binary file

WriteLines([]string{requestedVersion}, filepath.Join(installLocation, recentFile))
}
Expand All @@ -282,55 +274,49 @@ func ConvertExecutableExt(fpath string) string {
}

//InstallableBinLocation : Checks if terraform is installable in the location provided by the user.
//If not, create $HOME/bin. Ask users to add $HOME/bin to $PATH
//Return $HOME/bin as install location
func InstallableBinLocation(userBin string) string {
//If not, create $HOME/bin. Ask users to add $HOME/bin to $PATH and return $HOME/bin as install location
func InstallableBinLocation(userBinPath string) string {

usr, errCurr := user.Current()
if errCurr != nil {
log.Fatal(errCurr)
}

/* Setup for SNAPCRAFT Users */
SNAP := os.Getenv("SNAP_REAL_HOME")
if SNAP != "" { //if SNAP_USER_COMMON env is set, install
snapHomePath := filepath.Join(SNAP, "bin")
fmt.Println(snapHomePath)
CreateDirIfNotExist(snapHomePath)
fmt.Printf("Installing terraform at %s\n", snapHomePath)
fmt.Printf("RUN `export PATH=$PATH:%s` to append bin to $PATH\n", snapHomePath)
return filepath.Join(snapHomePath, "terraform")
}

existDefaultBin := CheckDirExist(userBin) //the default is /usr/local/bin but users can provide custom bin locations
binDir := Path(userBinPath) //get path directory from binary path
binPathExist := CheckDirExist(binDir) //the default is /usr/local/bin but users can provide custom bin locations

if existDefaultBin { //if exist - now see if we can write to to it
if binPathExist == true { //if bin path exist - check if we can write to to it

writableToDefault := false
binPathWritable := false //assume bin path is not writable
if runtime.GOOS != "windows" {
writableToDefault = CheckDirWritable(userBin) //check if is writable on ( only works on LINUX)
binPathWritable = CheckDirWritable(binDir) //check if is writable on ( only works on LINUX)
}

if !writableToDefault {
exisHomeBin := CheckDirExist(filepath.Join(usr.HomeDir, "bin"))
if exisHomeBin {
// IF: "/usr/local/bin" or `custom bin path` provided by user is non-writable, (binPathWritable == false), we will attempt to install terraform at the ~/bin location. See ELSE
if binPathWritable == false {

homeBinExist := CheckDirExist(filepath.Join(usr.HomeDir, "bin")) //check to see if ~/bin exist
if homeBinExist { //if ~/bin exist, install at ~/bin/terraform
fmt.Printf("Installing terraform at %s\n", filepath.Join(usr.HomeDir, "bin"))
return filepath.Join(usr.HomeDir, "bin", "terraform")
} else { //if ~/bin directory does not exist, create ~/bin for terraform installation
fmt.Printf("Unable to write to: %s\n", userBinPath)
fmt.Printf("Creating bin directory at: %s\n", filepath.Join(usr.HomeDir, "bin"))
CreateDirIfNotExist(filepath.Join(usr.HomeDir, "bin")) //create ~/bin
fmt.Printf("RUN `export PATH=$PATH:%s` to append bin to $PATH\n", filepath.Join(usr.HomeDir, "bin"))
return filepath.Join(usr.HomeDir, "bin", "terraform")
}
PrintCreateDirStmt(userBin, filepath.Join(usr.HomeDir, "bin"))
CreateDirIfNotExist(filepath.Join(usr.HomeDir, "bin"))
return filepath.Join(usr.HomeDir, "bin", "terraform")
} else { // ELSE: the "/usr/local/bin" or custom path provided by user is writable, we will return installable location
return filepath.Join(userBinPath)
}
return filepath.Join(userBin, "terraform")
}
fmt.Printf("[Error] : Binary path does not exist: %s\n", userBin)
fmt.Printf("[Error] : Manually create bin directory at: %s and try again.\n", userBin)
fmt.Printf("[Error] : Binary path does not exist: %s\n", userBinPath)
fmt.Printf("[Error] : Manually create bin directory at: %s and try again.\n", userBinPath)
os.Exit(1)
return ""
}

func PrintCreateDirStmt(unableDir string, writable string) {
fmt.Printf("Unable to write to: %s\n", unableDir)
fmt.Printf("Creating bin directory at: %s\n", writable)
fmt.Printf("RUN `export PATH=$PATH:%s` to append bin to $PATH\n", writable)
}
// func PrintCreateDirStmt(unableDir string, writable string) {
// fmt.Printf("Creating bin directory at: %s\n", writable)
// fmt.Printf("RUN `export PATH=$PATH:%s` to append bin to $PATH\n", writable)
// }
2 changes: 1 addition & 1 deletion lib/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

// TestAddRecent : Create a file, check filename exist,
// rename file, check new filename exit
func getInstallLocation(installPath string) string {
func GetInstallLocation(installPath string) string {
return string(os.PathSeparator) + installPath + string(os.PathSeparator)
}

Expand Down
17 changes: 17 additions & 0 deletions lib/symlink.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,20 @@ func CheckSymlink(symlinkPath string) bool {

return false
}

// ChangeSymlink : move symlink to existing binary
func ChangeSymlink(binVersionPath string, binPath string) {

//installLocation = GetInstallLocation() //get installation location - this is where we will put our terraform binary file
binPath = InstallableBinLocation(binPath)

/* remove current symlink if exist*/
symlinkExist := CheckSymlink(binPath)
if symlinkExist {
RemoveSymlink(binPath)
}

/* set symlink to desired version */
CreateSymlink(binVersionPath, binPath)

}
14 changes: 14 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const (
rcFilename = ".tfswitchrc"
tomlFilename = ".tfswitch.toml"
tgHclFilename = "terragrunt.hcl"
versionPrefix = "terraform_"
)

var version = "0.12.0\n"
Expand Down Expand Up @@ -285,6 +286,19 @@ func showLatestImplicitVersion(requestedVersion string, custBinPath, mirrorURL *
func installVersion(arg string, custBinPath *string, mirrorURL *string) {
if lib.ValidVersionFormat(arg) {
requestedVersion := arg

//check to see if the requested version has been downloaded before
installLocation := lib.GetInstallLocation()
installFileVersionPath := lib.ConvertExecutableExt(filepath.Join(installLocation, versionPrefix+requestedVersion))
recentDownloadFile := lib.CheckFileExist(installFileVersionPath)
if recentDownloadFile {
lib.ChangeSymlink(installFileVersionPath, *custBinPath)
fmt.Printf("Switched terraform to version %q \n", requestedVersion)
lib.AddRecent(requestedVersion) //add to recent file for faster lookup
os.Exit(0)
}

//if the requested version had not been downloaded before
listAll := true //set list all true - all versions including beta and rc will be displayed
tflist, _ := lib.GetTFList(*mirrorURL, listAll) //get list of versions
exist := lib.VersionExist(requestedVersion, tflist) //check if version exist before downloading it
Expand Down
2 changes: 1 addition & 1 deletion version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
RELEASE_VERSION=0.12
RELEASE_VERSION=0.13
6 changes: 0 additions & 6 deletions www/docs/Install.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ Installation for Linux operation systems.
curl -L https://github.com/raw/warrensbox/terraform-switcher/release/install.sh | bash
```

### Snapcraft for CentOS, Ubuntu, Linux Mint, RHEL, Debian, Fedora

```sh
sudo snap install tfswitch
```

### Arch User Repository (AUR) packages for Arch Linux

```sh
Expand Down
6 changes: 6 additions & 0 deletions www/docs/Quick-Start.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ terraform_version_constraint = ">= 0.13, < 0.14"
...
```

### Get the version from a subdirectory
```bash
tfswitch --chdir terraform_dir
tfswitch -c terraform_dir
```

### Use custom mirror
To install from a remote mirror other than the default(https://releases.hashicorp.com/terraform). Use the `-m` or `--mirror` parameter.
Ex: `tfswitch --mirror https://example.jfrog.io/artifactory/hashicorp`
Expand Down

0 comments on commit 09816b6

Please sign in to comment.