From 09816b66505e780b70de3ee167a2cd1f178e3857 Mon Sep 17 00:00:00 2001 From: "warren.veerasingam@gmail.com" Date: Sun, 28 Nov 2021 18:22:12 -0600 Subject: [PATCH] Refactor code - if version exist, simply change symlink --- Makefile | 3 +- README.md | 13 ++--- lib/download_test.go | 6 +-- lib/install.go | 110 ++++++++++++++++++---------------------- lib/install_test.go | 2 +- lib/symlink.go | 17 +++++++ main.go | 14 +++++ version | 2 +- www/docs/Install.md | 6 --- www/docs/Quick-Start.md | 6 +++ 10 files changed, 94 insertions(+), 85 deletions(-) diff --git a/Makefile b/Makefile index 22effda6..d754543b 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/README.md b/README.md index 11bc0cc5..5eb459aa 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 diff --git a/lib/download_test.go b/lib/download_test.go index 1019a8f4..851ff968 100644 --- a/lib/download_test.go +++ b/lib/download_test.go @@ -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 @@ -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 @@ -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" diff --git a/lib/install.go b/lib/install.go index 4a42f211..884addeb 100644 --- a/lib/install.go +++ b/lib/install.go @@ -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 ( @@ -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 { @@ -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) @@ -84,22 +78,20 @@ 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 @@ -107,12 +99,12 @@ func Install(tfversion string, binPath string, mirrorURL string) { // 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, */ @@ -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) } @@ -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 */ @@ -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) @@ -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) @@ -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)) } @@ -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) +// } diff --git a/lib/install_test.go b/lib/install_test.go index 89ec7c74..50fb1975 100644 --- a/lib/install_test.go +++ b/lib/install_test.go @@ -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) } diff --git a/lib/symlink.go b/lib/symlink.go index ba7f8291..1889d180 100644 --- a/lib/symlink.go +++ b/lib/symlink.go @@ -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) + +} diff --git a/main.go b/main.go index 47bb8f5a..ba2dfb97 100644 --- a/main.go +++ b/main.go @@ -51,6 +51,7 @@ const ( rcFilename = ".tfswitchrc" tomlFilename = ".tfswitch.toml" tgHclFilename = "terragrunt.hcl" + versionPrefix = "terraform_" ) var version = "0.12.0\n" @@ -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 diff --git a/version b/version index 94d73482..d7ded312 100644 --- a/version +++ b/version @@ -1 +1 @@ -RELEASE_VERSION=0.12 \ No newline at end of file +RELEASE_VERSION=0.13 \ No newline at end of file diff --git a/www/docs/Install.md b/www/docs/Install.md index adad4edc..5fbef88d 100644 --- a/www/docs/Install.md +++ b/www/docs/Install.md @@ -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 diff --git a/www/docs/Quick-Start.md b/www/docs/Quick-Start.md index 59679141..d7f7d2db 100644 --- a/www/docs/Quick-Start.md +++ b/www/docs/Quick-Start.md @@ -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`