Skip to content

Commit

Permalink
Merge branch 'master' into dependabot/go_modules/golang.org/x/sys-0.22.0
Browse files Browse the repository at this point in the history
  • Loading branch information
yermulnik authored Jul 5, 2024
2 parents 44394fa + c49ef30 commit 23a8e38
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 99 deletions.
96 changes: 28 additions & 68 deletions lib/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"

"github.com/manifoldco/promptui"
Expand Down Expand Up @@ -51,17 +50,25 @@ func GetInstallLocation(installPath string) string {
}

// install : install the provided version in the argument
func install(product Product, tfversion string, binPath string, installPath string, mirrorURL string) {
func install(product Product, tfversion string, binPath string, installPath string, mirrorURL string) error {
var wg sync.WaitGroup
/* 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 don't have permission to default location, therefore tfswitch was installed in $HOME/bin
* Tell users to add $HOME/bin to their path
*/
binPath = installableBinLocation(product, binPath)

initialize(binPath) //initialize path
installLocation = GetInstallLocation(installPath) //get installation location - this is where we will put our terraform binary file
//check to see if the requested version has been downloaded before
installLocation := GetInstallLocation(installPath)
installFileVersionPath := ConvertExecutableExt(filepath.Join(installLocation, product.GetVersionPrefix()+tfversion))
recentDownloadFile := CheckFileExist(installFileVersionPath)
if recentDownloadFile {
return switchToVersion(product, tfversion, binPath, installPath, installFileVersionPath)
}

// If the requested version had not been downloaded before
// Set list all true - all versions including beta and rc will be displayed
tflist, _ := getTFList(mirrorURL, true) // Get list of versions
exist := versionExist(tfversion, tflist) // Check if version exists before downloading it

if !exist {
return fmt.Errorf("the provided %s version does not exist: %q.\n Try `tfswitch -l` to see all available versions", product.GetId(), tfversion)
}

goarch := runtime.GOARCH
goos := runtime.GOOS
Expand All @@ -73,33 +80,6 @@ func install(product Product, tfversion string, binPath string, installPath stri
goarch = "amd64"
}

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

/* if selected version already exist, */
if fileExist {

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

if symlinkExist {
RemoveSymlink(binPath)
}

/* set symlink to desired version */
CreateSymlink(installFileVersionPath, binPath)
logger.Infof("Switched %s to version %q", product.GetName(), tfversion)
addRecent(tfversion, installPath, product) //add to recent file for faster lookup
return
}

//if does not have slash - append slash
hasSlash := strings.HasSuffix(mirrorURL, "/")
if !hasSlash {
mirrorURL = fmt.Sprintf("%s/", mirrorURL)
}

/* if selected version already exist, */
/* proceed to download it from the hashicorp release page */
zipFile, errDownload := DownloadProductFromURL(product, installLocation, product.GetArtifactUrl(mirrorURL, tfversion), tfversion, product.GetArchivePrefix(), goos, goarch)
Expand All @@ -124,18 +104,18 @@ func install(product Product, tfversion string, binPath string, installPath stri
/* remove zipped file to clear clutter */
RemoveFiles(zipFile)

/* remove current symlink if exist*/
symlinkExist := CheckSymlink(binPath)
return switchToVersion(product, tfversion, binPath, installPath, installFileVersionPath)
}

if symlinkExist {
RemoveSymlink(binPath)
func switchToVersion(product Product, tfversion string, binPath string, installPath string, installFileVersionPath string) error {
err := ChangeProductSymlink(product, installFileVersionPath, binPath)
if err != nil {
return err
}

/* set symlink to desired version */
CreateSymlink(installFileVersionPath, binPath)
logger.Infof("Switched %s to version %q", product.GetName(), tfversion)
addRecent(tfversion, installPath, product) //add to recent file for faster lookup
return
return nil
}

// ConvertExecutableExt : convert executable with local OS extension
Expand All @@ -153,6 +133,7 @@ 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 and return $HOME/bin as install location
// Deprecated: This function has been deprecated and will be removed in v2.0.0
func installableBinLocation(product Product, userBinPath string) string {
homedir := GetHomeDirectory() //get user's home directory
binDir := Path(userBinPath) //get path directory from binary path
Expand Down Expand Up @@ -199,7 +180,7 @@ func InstallLatestVersion(dryRun bool, customBinaryPath, installPath string, mir
func InstallLatestProductVersion(product Product, dryRun bool, customBinaryPath, installPath string, mirrorURL string) error {
tfversion, _ := getTFLatest(mirrorURL)
if !dryRun {
install(product, tfversion, customBinaryPath, installPath, mirrorURL)
return install(product, tfversion, customBinaryPath, installPath, mirrorURL)
}
return nil
}
Expand Down Expand Up @@ -242,28 +223,7 @@ func InstallProductVersion(product Product, dryRun bool, version, customBinaryPa
if !dryRun {
if validVersionFormat(version) {
requestedVersion := version

//check to see if the requested version has been downloaded before
installLocation := GetInstallLocation(installPath)
installFileVersionPath := ConvertExecutableExt(filepath.Join(installLocation, product.GetVersionPrefix()+requestedVersion))
recentDownloadFile := CheckFileExist(installFileVersionPath)
if recentDownloadFile {
ChangeProductSymlink(product, installFileVersionPath, customBinaryPath)
logger.Infof("Switched %s to version %q", product.GetName(), requestedVersion)
addRecent(requestedVersion, installPath, product) //add to recent file for faster lookup
return nil
}

// If the requested version had not been downloaded before
// Set list all true - all versions including beta and rc will be displayed
tflist, _ := getTFList(mirrorURL, true) // Get list of versions
exist := versionExist(requestedVersion, tflist) // Check if version exists before downloading it

if exist {
install(product, requestedVersion, customBinaryPath, installPath, mirrorURL)
} else {
return fmt.Errorf("the provided terraform version does not exist: %q.\n Try `tfswitch -l` to see all available versions", requestedVersion)
}
return install(product, requestedVersion, customBinaryPath, installPath, mirrorURL)
} else {
PrintInvalidTFVersion()
UsageMessage()
Expand Down Expand Up @@ -346,7 +306,7 @@ func InstallProductOption(product Product, listAll, dryRun bool, customBinaryPat
}
}
if !dryRun {
install(product, selectVersions[selectedItx].Version, customBinaryPath, installPath, mirrorURL)
return install(product, selectVersions[selectedItx].Version, customBinaryPath, installPath, mirrorURL)
}
return nil
}
83 changes: 52 additions & 31 deletions lib/symlink.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
package lib

import (
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"
)

// CreateSymlink : create symlink or copy file to bin directory if windows
func CreateSymlink(cwd string, dir string) {
func CreateSymlink(cwd string, dir string) error {
// If we are on windows the symlink is not working correctly.
// Copy the desired terraform binary to the path environment.
if runtime.GOOS == "windows" {
r, err := os.Open(cwd)
if err != nil {
logger.Fatalf("Unable to open source binary: %s", cwd)
os.Exit(1)
return fmt.Errorf("Unable to open source binary: %q", cwd)
}
defer r.Close()

w, err := os.Create(dir + ".exe")
if err != nil {
logger.Fatalf("Could not create target binary: %s", dir+".exe")
os.Exit(1)
return fmt.Errorf("Could not create target binary: %q.exe", dir)
}
defer func() {
if c := w.Close(); err == nil {
Expand All @@ -32,45 +33,44 @@ func CreateSymlink(cwd string, dir string) {
} else {
err := os.Symlink(cwd, dir)
if err != nil {
logger.Fatalf(`
return fmt.Errorf(`
Unable to create new symlink.
Maybe symlink already exist. Try removing existing symlink manually.
Try running "unlink %s" to remove existing symlink.
If error persist, you may not have the permission to create a symlink at %s.
Error: %s
Try running "unlink %q" to remove existing symlink.
If error persist, you may not have the permission to create a symlink at %q.
Error: %v
`, dir, dir, err)
os.Exit(1)
}
}
return nil
}

// RemoveSymlink : remove symlink
func RemoveSymlink(symlinkPath string) {
func RemoveSymlink(symlinkPath string) error {

_, err := os.Lstat(symlinkPath)
if err != nil {
logger.Fatalf(`
return fmt.Errorf(`
Unable to stat symlink.
Maybe symlink already exist. Try removing existing symlink manually.
Try running "unlink %s" to remove existing symlink.
If error persist, you may not have the permission to create a symlink at %s.
Error: %s
Try running "unlink %q" to remove existing symlink.
If error persist, you may not have the permission to create a symlink at %q.
Error: %v
`, symlinkPath, symlinkPath, err)
os.Exit(1)
} else {
errRemove := os.Remove(symlinkPath)

if errRemove != nil {
logger.Fatalf(`
return fmt.Errorf(`
Unable to remove symlink.
Maybe symlink already exist. Try removing existing symlink manually.
Try running "unlink %s" to remove existing symlink.
If error persist, you may not have the permission to create a symlink at %s.
Error: %s
Try running "unlink %q" to remove existing symlink.
If error persist, you may not have the permission to create a symlink at %q.
Error: %v
`, symlinkPath, symlinkPath, errRemove)
os.Exit(1)
}
}
return nil
}

// CheckSymlink : check file is symlink
Expand All @@ -93,21 +93,42 @@ func CheckSymlink(symlinkPath string) bool {
// Deprecated: This function has been deprecated in favor of ChangeProductSymlink and will be removed in v2.0.0
func ChangeSymlink(binVersionPath string, binPath string) {
product := getLegacyProduct()
ChangeProductSymlink(product, binVersionPath, binPath)
err := ChangeProductSymlink(product, binVersionPath, binPath)
if err != nil {
logger.Fatal(err)
}
}

// ChangeProductSymlink : move symlink for product to existing binary
func ChangeProductSymlink(product Product, binVersionPath string, binPath string) {

binPath = installableBinLocation(product, binPath)
func ChangeProductSymlink(product Product, binVersionPath string, userBinPath string) error {

homedir := GetHomeDirectory() //get user's home directory
homeBinPath := filepath.Join(homedir, "bin", product.GetExecutableName())
possibleInstallLocations := []string{userBinPath, homeBinPath}
var err error

for _, location := range possibleInstallLocations {
if CheckDirExist(Path(location)) {
/* remove current symlink if exist*/
symlinkExist := CheckSymlink(location)
if symlinkExist {
_ = RemoveSymlink(location)
}

/* remove current symlink if exist*/
symlinkExist := CheckSymlink(binPath)
if symlinkExist {
RemoveSymlink(binPath)
/* set symlink to desired version */
err = CreateSymlink(binVersionPath, location)
if err == nil {
logger.Debugf("Symlink created at %q", location)
return nil
}
}
}

/* set symlink to desired version */
CreateSymlink(binVersionPath, binPath)
if err == nil {
return fmt.Errorf("Unable to find existing directory in %q. %s",
strings. Join(possibleInstallLocations, " or "),
"Manually create one of them and try again.")
}

return err
}

0 comments on commit 23a8e38

Please sign in to comment.