github.com/xkeyideal/glide@v0.0.0-20171121052037-a806f0aaeda0/path/winbug.go (about) 1 package path 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "runtime" 8 "syscall" 9 10 "bytes" 11 "io/ioutil" 12 13 "github.com/xkeyideal/glide/msg" 14 ) 15 16 // extract the exit code from an os.exec error 17 func getExitCode(err error) int { 18 if err != nil { 19 if exitError, ok := err.(*exec.ExitError); ok { 20 waitStatus := exitError.Sys().(syscall.WaitStatus) 21 return waitStatus.ExitStatus() 22 } 23 } 24 return 0 25 } 26 27 // Hard to track down these codes - they are from windows.h and documented here: 28 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx 29 const ( 30 winErrorFileNotFound = 2 31 winErrorPathNotFound = 3 32 ) 33 34 // This file and its contents are to handle a Windows bug where large sets of 35 // files fail when using the `os` package. This has been seen in Windows 10 36 // including the Windows Linux Subsystem. 37 // Tracking the issue in https://github.com/golang/go/issues/20841. Once the 38 // upstream issue is fixed this change can be reverted. 39 40 // CustomRemoveAll is similar to os.RemoveAll but deals with the bug outlined 41 // at https://github.com/golang/go/issues/20841. 42 func CustomRemoveAll(p string) error { 43 44 // Handle the windows case first 45 if runtime.GOOS == "windows" { 46 msg.Debug("Detected Windows. Removing files using windows command") 47 cmd := exec.Command("cmd.exe", "/c", "rd", "/s", "/q", p) 48 output, err := cmd.CombinedOutput() 49 if err != nil { 50 exitCode := getExitCode(err) 51 if exitCode != winErrorFileNotFound && exitCode != winErrorPathNotFound { 52 return fmt.Errorf("Error removing files: %s. output: %s", err, output) 53 } 54 } 55 return nil 56 } else if detectWsl() { 57 cmd := exec.Command("rm", "-rf", p) 58 output, err2 := cmd.CombinedOutput() 59 msg.Debug("Detected Windows Subsystem for Linux. Removing files using subsystem command") 60 if err2 != nil { 61 return fmt.Errorf("Error removing files: %s. output: %s", err2, output) 62 } 63 return nil 64 } 65 return os.RemoveAll(p) 66 } 67 68 // CustomRename is similar to os.Rename but deals with the bug outlined 69 // at https://github.com/golang/go/issues/20841. 70 func CustomRename(o, n string) error { 71 72 // Handking windows cases first 73 if runtime.GOOS == "windows" { 74 msg.Debug("Detected Windows. Moving files using windows command") 75 //cmd := exec.Command("cmd.exe", "/c", "move", o, n) 76 cmd := exec.Command("cmd.exe", "/c", "xcopy /s/y", o, n+"\\") 77 output, err := cmd.CombinedOutput() 78 if err != nil { 79 return fmt.Errorf("Error moving files: %s. output: %s", err, output) 80 } 81 82 return nil 83 } else if detectWsl() { 84 cmd := exec.Command("mv", o, n) 85 output, err2 := cmd.CombinedOutput() 86 msg.Debug("Detected Windows Subsystem for Linux. Removing files using subsystem command") 87 if err2 != nil { 88 return fmt.Errorf("Error moving files: %s. output: %s", err2, output) 89 } 90 91 return nil 92 } 93 94 return os.Rename(o, n) 95 } 96 97 var procIsWin bool 98 var procDet bool 99 100 func detectWsl() bool { 101 102 if !procDet { 103 procDet = true 104 _, err := os.Stat("/proc/version") 105 if err == nil { 106 b, err := ioutil.ReadFile("/proc/version") 107 if err != nil { 108 msg.Warn("Unable to read /proc/version that was detected. May incorrectly detect WSL") 109 msg.Debug("Windows Subsystem for Linux detection error: %s", err) 110 return false 111 } 112 113 if bytes.Contains(b, []byte("Microsoft")) { 114 msg.Debug("Windows Subsystem for Linux detected") 115 procIsWin = true 116 } 117 } 118 } 119 120 return procIsWin 121 }