@@ -11,36 +11,56 @@ import (
1111)
1212
1313// CreateSymlink : create symlink or copy file to bin directory if windows
14- func CreateSymlink (cwd string , dir string ) error {
14+ func CreateSymlink (target string , link string ) error {
1515 // If we are on windows the symlink is not working correctly.
1616 // Copy the desired terraform binary to the path environment.
1717 if runtime .GOOS == windows {
18- r , err := os .Open (cwd )
18+ r , err := os .Open (target )
1919 if err != nil {
20- return fmt .Errorf ("Unable to open source binary: %q" , cwd )
20+ return fmt .Errorf ("Unable to open source binary %q: %v " , target , err )
2121 }
2222 defer r .Close ()
2323
24- w , err := os .Create (dir )
24+ w , err := os .Create (link )
2525 if err != nil {
26- return fmt .Errorf ("Could not create target binary: %q" , dir )
26+ return fmt .Errorf ("Could not create target binary %q: %v " , link , err )
2727 }
2828 defer func () {
2929 if c := w .Close (); err == nil {
3030 err = c
3131 }
3232 }()
33+ logger .Infof ("Copying binary from %q to %q" , target , link )
3334 _ , err = io .Copy (w , r )
35+ if err != nil {
36+ return fmt .Errorf ("Failed to copy binary from %q to %q: %v" , target , link , err )
37+ }
3438 } else {
35- err := os .Symlink (cwd , dir )
39+ // Get absolute path of target
40+ target , errTarget := GetAbsolutePath (target ) //nolint:govet
41+ if errTarget != nil {
42+ return fmt .Errorf ("Unable to get absolute path of %q: %v" , target , errTarget )
43+ }
44+
45+ // Get absolute path of link
46+ link , errLink := GetAbsolutePath (link ) //nolint:govet
47+ if errLink != nil {
48+ return fmt .Errorf ("Unable to get absolute path of %q: %v" , link , errLink )
49+ }
50+
51+ // Use absolute paths for symlink creation to allow
52+ // `--install <path_dir>` and `--bin <path_file>` to be used together
53+ // (don't mess with relative paths — it's complicated and error-prone)
54+ logger .Debugf ("Symlinking %q to %q" , link , target )
55+ err := os .Symlink (target , link )
3656 if err != nil {
3757 return fmt .Errorf (`
3858 Unable to create new symlink.
3959 Maybe symlink already exist. Try removing existing symlink manually.
4060 Try running "unlink %q" to remove existing symlink.
4161 If error persist, you may not have the permission to create a symlink at %q.
4262 Error: %v
43- ` , dir , dir , err )
63+ ` , link , link , err )
4464 }
4565 }
4666 return nil
@@ -59,6 +79,7 @@ func RemoveSymlink(symlinkPath string) error {
5979 ` , symlinkPath , symlinkPath , err )
6080 }
6181
82+ logger .Debugf ("Removing existing symlink at %q" , symlinkPath )
6283 if errRemove := os .Remove (symlinkPath ); errRemove != nil {
6384 return fmt .Errorf (`
6485 Unable to remove symlink.
@@ -141,14 +162,15 @@ func ChangeProductSymlink(product Product, binVersionPath string, userBinPath st
141162 // If directory does not exist, check if we should create it, otherwise skip
142163 if ! CheckDirExist (dirPath ) {
143164 logger .Warnf ("Installation directory %q doesn't exist!" , dirPath )
144- if location .create {
145- logger .Infof ("Creating %q directory" , dirPath )
146- err = os .MkdirAll (dirPath , 0o755 )
147- if err != nil {
148- logger .Errorf ("Unable to create %q directory: %v" , dirPath , err )
149- continue
150- }
151- } else {
165+
166+ if ! location .create {
167+ continue
168+ }
169+
170+ logger .Infof ("Creating %q directory" , dirPath )
171+ err = os .MkdirAll (dirPath , 0o755 )
172+ if err != nil {
173+ logger .Errorf ("Unable to create %q directory: %v" , dirPath , err )
152174 continue
153175 }
154176 } else if ! CheckIsDir (dirPath ) {
@@ -175,17 +197,23 @@ func ChangeProductSymlink(product Product, binVersionPath string, userBinPath st
175197 if runtime .GOOS != windows {
176198 isDirInPath := false
177199
178- for _ , envPathElement := range strings .Split (os .Getenv ("PATH" ), ":" ) {
200+ absDirPath , errAbs := GetAbsolutePath (dirPath )
201+ if errAbs != nil {
202+ return fmt .Errorf ("Could not derive absolute path to %q: %v" , dirPath , errAbs )
203+ }
204+ absDirPath = strings .TrimRight (absDirPath , "/" )
205+
206+ for envPathElement := range strings .SplitSeq (os .Getenv ("PATH" ), ":" ) {
179207 expandedEnvPathElement := strings .TrimRight (strings .Replace (envPathElement , "~" , homedir , 1 ), "/" )
180208
181- if expandedEnvPathElement == strings . TrimRight ( dirPath , "/" ) {
209+ if expandedEnvPathElement == absDirPath {
182210 isDirInPath = true
183211 break
184212 }
185213 }
186214
187215 if ! isDirInPath {
188- logger .Warnf ("Run `export PATH=\" $PATH:%s\" ` to append %q to $PATH" , dirPath , location .path )
216+ logger .Warnf ("Run `export PATH=\" $PATH:%s\" ` to append %q to $PATH" , absDirPath , location .path )
189217 }
190218 }
191219
0 commit comments