mirror of
https://github.com/coreybutler/nvm-windows.git
synced 2025-09-01 18:35:13 +00:00
added custom Rename function with support across disparate hard disk volumes. Closes #1206.
This commit is contained in:
28
src/nvm.go
28
src/nvm.go
@@ -711,10 +711,11 @@ func install(version string, cpuarch string) {
|
||||
|
||||
if file.Exists(filepath.Join(root, "v"+version, "node_modules", "npm")) {
|
||||
utility.DebugLogf("move %v to %v", filepath.Join(root, "v"+version), filepath.Join(env.root, "v"+version))
|
||||
if rnerr := os.Rename(filepath.Join(root, "v"+version), filepath.Join(env.root, "v"+version)); rnerr != nil {
|
||||
if rnerr := utility.Rename(filepath.Join(root, "v"+version), filepath.Join(env.root, "v"+version)); rnerr != nil {
|
||||
status <- Status{Err: err}
|
||||
}
|
||||
utility.DebugFn(func() {
|
||||
utility.DebugLogf("env root: %v", env.root)
|
||||
cmd := exec.Command("cmd", "/C", "dir", filepath.Join(env.root, "v"+version))
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
@@ -768,13 +769,13 @@ func install(version string, cpuarch string) {
|
||||
}
|
||||
|
||||
// Standard npm support
|
||||
os.Rename(filepath.Join(tempNpmBin, "npm"), filepath.Join(root, "v"+version, "npm"))
|
||||
os.Rename(filepath.Join(tempNpmBin, "npm.cmd"), filepath.Join(root, "v"+version, "npm.cmd"))
|
||||
utility.Rename(filepath.Join(tempNpmBin, "npm"), filepath.Join(root, "v"+version, "npm"))
|
||||
utility.Rename(filepath.Join(tempNpmBin, "npm.cmd"), filepath.Join(root, "v"+version, "npm.cmd"))
|
||||
|
||||
// npx support
|
||||
if _, err := os.Stat(filepath.Join(tempNpmBin, "npx")); err == nil {
|
||||
os.Rename(filepath.Join(tempNpmBin, "npx"), filepath.Join(root, "v"+version, "npx"))
|
||||
os.Rename(filepath.Join(tempNpmBin, "npx.cmd"), filepath.Join(root, "v"+version, "npx.cmd"))
|
||||
utility.Rename(filepath.Join(tempNpmBin, "npx"), filepath.Join(root, "v"+version, "npx"))
|
||||
utility.Rename(filepath.Join(tempNpmBin, "npx.cmd"), filepath.Join(root, "v"+version, "npx.cmd"))
|
||||
}
|
||||
|
||||
npmSourcePath := filepath.Join(tempDir, "nvm-npm", "npm-"+npmv)
|
||||
@@ -783,21 +784,20 @@ func install(version string, cpuarch string) {
|
||||
npmSourcePath = filepath.Join(tempDir, "nvm-npm", "cli-"+npmv)
|
||||
}
|
||||
|
||||
moveNpmErr := os.Rename(npmSourcePath, filepath.Join(root, "v"+version, "node_modules", "npm"))
|
||||
moveNpmErr := utility.Rename(npmSourcePath, filepath.Join(root, "v"+version, "node_modules", "npm"))
|
||||
if moveNpmErr != nil {
|
||||
// sometimes Windows can take some time to enable access to large amounts of files after unzip, use exponential backoff to wait until it is ready
|
||||
for _, i := range [5]int{1, 2, 4, 8, 16} {
|
||||
time.Sleep(time.Duration(i) * time.Second)
|
||||
moveNpmErr = os.Rename(npmSourcePath, filepath.Join(root, "v"+version, "node_modules", "npm"))
|
||||
moveNpmErr = utility.Rename(npmSourcePath, filepath.Join(root, "v"+version, "node_modules", "npm"))
|
||||
if moveNpmErr == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if err == nil && moveNpmErr == nil {
|
||||
err = os.Rename(filepath.Join(root, "v"+version), filepath.Join(env.root, "v"+version))
|
||||
err = utility.Rename(filepath.Join(root, "v"+version), filepath.Join(env.root, "v"+version))
|
||||
if err != nil {
|
||||
status <- Status{Err: err}
|
||||
}
|
||||
@@ -812,7 +812,7 @@ func install(version string, cpuarch string) {
|
||||
status <- Status{Err: fmt.Errorf("Failed to extract npm: %v", err), Done: true}
|
||||
}
|
||||
} else {
|
||||
err = os.Rename(filepath.Join(root, "v"+version), filepath.Join(env.root, "v"+version))
|
||||
err = utility.Rename(filepath.Join(root, "v"+version), filepath.Join(env.root, "v"+version))
|
||||
if err != nil {
|
||||
status <- Status{Err: err}
|
||||
}
|
||||
@@ -1233,15 +1233,15 @@ func use(version string, cpuarch string, reload ...bool) {
|
||||
nodeexists := file.Exists(nodepath)
|
||||
if node32exists && cpuarch == "32" { // user wants 32, but node.exe is 64
|
||||
if nodeexists {
|
||||
os.Rename(nodepath, node64path) // node.exe -> node64.exe
|
||||
utility.Rename(nodepath, node64path) // node.exe -> node64.exe
|
||||
}
|
||||
os.Rename(node32path, nodepath) // node32.exe -> node.exe
|
||||
utility.Rename(node32path, nodepath) // node32.exe -> node.exe
|
||||
}
|
||||
if node64exists && cpuarch == "64" { // user wants 64, but node.exe is 32
|
||||
if nodeexists {
|
||||
os.Rename(nodepath, node32path) // node.exe -> node32.exe
|
||||
utility.Rename(nodepath, node32path) // node.exe -> node32.exe
|
||||
}
|
||||
os.Rename(node64path, nodepath) // node64.exe -> node.exe
|
||||
utility.Rename(node64path, nodepath) // node64.exe -> node.exe
|
||||
}
|
||||
|
||||
status <- Status{Done: true}
|
||||
|
117
src/utility/rename.go
Normal file
117
src/utility/rename.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package utility
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func Rename(old, new string) error {
|
||||
old_drive := filepath.VolumeName(old)
|
||||
new_drive := filepath.VolumeName(new)
|
||||
|
||||
if old_drive == new_drive {
|
||||
return os.Rename(old, new)
|
||||
}
|
||||
|
||||
// Get file or directory info
|
||||
info, err := os.Stat(old)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to stat source: %w", err)
|
||||
}
|
||||
|
||||
// If old is a directory, copy recursively
|
||||
if info.IsDir() {
|
||||
err = copyDir(old, new)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to copy directory: %w", err)
|
||||
}
|
||||
} else {
|
||||
// Otherwise, copy a single file
|
||||
err = copyFile(old, new)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to copy file: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the original source
|
||||
err = os.RemoveAll(old)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to remove source: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyFile copies a single file from source (old) to destination (new).
|
||||
func copyFile(old, new string) error {
|
||||
srcFile, err := os.Open(old)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open source file: %w", err)
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
// Ensure destination directory exists
|
||||
destDir := filepath.Dir(new)
|
||||
err = os.MkdirAll(destDir, os.ModePerm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create destination directory: %w", err)
|
||||
}
|
||||
|
||||
destFile, err := os.Create(new)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create destination file: %w", err)
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
_, err = io.Copy(destFile, srcFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to copy data: %w", err)
|
||||
}
|
||||
|
||||
// Copy file permissions
|
||||
info, err := srcFile.Stat()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get source file info: %w", err)
|
||||
}
|
||||
err = os.Chmod(new, info.Mode())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set permissions on destination file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyDir recursively copies a directory from old path to new path.
|
||||
func copyDir(old, new string) error {
|
||||
entries, err := os.ReadDir(old)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read source directory: %w", err)
|
||||
}
|
||||
|
||||
// Ensure destination directory exists
|
||||
err = os.MkdirAll(new, os.ModePerm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create destination directory: %w", err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
srcPath := filepath.Join(old, entry.Name())
|
||||
destPath := filepath.Join(new, entry.Name())
|
||||
|
||||
if entry.IsDir() {
|
||||
err = copyDir(srcPath, destPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to copy subdirectory: %w", err)
|
||||
}
|
||||
} else {
|
||||
err = copyFile(srcPath, destPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to copy file: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user