Skip to content

Commit

Permalink
Rework ChangeProductSymlink to avoid installableBinLocation usage
Browse files Browse the repository at this point in the history
This fix usage of bin path in configuration file on Windows
  • Loading branch information
PierreTechoueyres authored and Pierre Téchoueyres committed Jun 26, 2024
1 parent 6c9ea5f commit 33be9e7
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 37 deletions.
17 changes: 11 additions & 6 deletions lib/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@ func install(product Product, tfversion string, binPath string, installPath stri
installFileVersionPath := ConvertExecutableExt(filepath.Join(installLocation, product.GetVersionPrefix()+tfversion))
recentDownloadFile := CheckFileExist(installFileVersionPath)
if recentDownloadFile {
ChangeProductSymlink(product, installFileVersionPath, binPath)
logger.Infof("Switched %s to version %q", product.GetName(), tfversion)
addRecent(tfversion, installPath, product) //add to recent file for faster lookup
return nil
return switchToVersion(product, tfversion, binPath, installPath, installFileVersionPath)
}

// If the requested version had not been downloaded before
Expand All @@ -70,7 +67,7 @@ func install(product Product, tfversion string, binPath string, installPath stri
exist := versionExist(tfversion, tflist) // Check if version exists before downloading it

if !exist {
return fmt.Errorf("the provided terraform version does not exist: %q.\n Try `tfswitch -l` to see all available versions", tfversion)
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
Expand Down Expand Up @@ -107,7 +104,15 @@ func install(product Product, tfversion string, binPath string, installPath stri
/* remove zipped file to clear clutter */
RemoveFiles(zipFile)

ChangeProductSymlink(product, installFileVersionPath, binPath)
return switchToVersion(product, tfversion, binPath, installPath, installFileVersionPath)
}

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

logger.Infof("Switched %s to version %q", product.GetName(), tfversion)
addRecent(tfversion, installPath, product) //add to recent file for faster lookup
return nil
Expand Down
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 33be9e7

Please sign in to comment.