github.com/stevenshuang/glide@v0.13.3/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/Masterminds/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 output, err := cmd.CombinedOutput() 77 if err != nil { 78 return fmt.Errorf("Error moving files: %s. output: %s", err, output) 79 } 80 81 return nil 82 } else if detectWsl() { 83 cmd := exec.Command("mv", o, n) 84 output, err2 := cmd.CombinedOutput() 85 msg.Debug("Detected Windows Subsystem for Linux. Removing files using subsystem command") 86 if err2 != nil { 87 return fmt.Errorf("Error moving files: %s. output: %s", err2, output) 88 } 89 90 return nil 91 } 92 93 return os.Rename(o, n) 94 } 95 96 var procIsWin bool 97 var procDet bool 98 99 func detectWsl() bool { 100 101 if !procDet { 102 procDet = true 103 _, err := os.Stat("/proc/version") 104 if err == nil { 105 b, err := ioutil.ReadFile("/proc/version") 106 if err != nil { 107 msg.Warn("Unable to read /proc/version that was detected. May incorrectly detect WSL") 108 msg.Debug("Windows Subsystem for Linux detection error: %s", err) 109 return false 110 } 111 112 if bytes.Contains(b, []byte("Microsoft")) { 113 msg.Debug("Windows Subsystem for Linux detected") 114 procIsWin = true 115 } 116 } 117 } 118 119 return procIsWin 120 }