Skip to content

Commit

Permalink
Merge pull request #857 from Masterminds/fix/windows-many-files
Browse files Browse the repository at this point in the history
Fixed #778: Removing and moving large sets of files fails on Windows
  • Loading branch information
mattfarina authored Jul 7, 2017
2 parents 4b407b3 + a7ffb17 commit 245cace
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 3 deletions.
2 changes: 1 addition & 1 deletion path/strip.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func StripVendor() error {
if _, err := os.Stat(path); err == nil {
if info.IsDir() {
msg.Info("Removing: %s", path)
return os.RemoveAll(path)
return CustomRemoveAll(path)
}

msg.Debug("%s is not a directory. Skipping removal", path)
Expand Down
96 changes: 96 additions & 0 deletions path/winbug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package path

import (
"fmt"
"os"
"os/exec"
"runtime"

"bytes"
"io/ioutil"

"github.com/Masterminds/glide/msg"
)

// This file and its contents are to handle a Windows bug where large sets of
// files fail when using the `os` package. This has been seen in Windows 10
// including the Windows Linux Subsystem.
// Tracking the issue in https://github.com/golang/go/issues/20841. Once the
// upstream issue is fixed this change can be reverted.

// CustomRemoveAll is similar to os.RemoveAll but deals with the bug outlined
// at https://github.com/golang/go/issues/20841.
func CustomRemoveAll(p string) error {

// Handle the windows case first
if runtime.GOOS == "windows" {
msg.Debug("Detected Windows. Removing files using windows command")
cmd := exec.Command("cmd.exe", "/c", fmt.Sprintf("rd /s /q %s", p))
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("Error removing files: %s. output: %s", err, output)
}
} else if detectWsl() {
cmd := exec.Command("rm", "-rf", p)
output, err2 := cmd.CombinedOutput()
msg.Debug("Detected Windows Subsystem for Linux. Removing files using subsystem command")
if err2 != nil {
return fmt.Errorf("Error removing files: %s. output: %s", err2, output)
}
}
return os.RemoveAll(p)
}

// CustomRename is similar to os.Rename but deals with the bug outlined
// at https://github.com/golang/go/issues/20841.
func CustomRename(o, n string) error {

// Handking windows cases first
if runtime.GOOS == "windows" {
msg.Debug("Detected Windows. Moving files using windows command")
cmd := exec.Command("cmd.exe", "/c", "move", o, n)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("Error moving files: %s. output: %s", err, output)
}

return nil
} else if detectWsl() {
cmd := exec.Command("mv", o, n)
output, err2 := cmd.CombinedOutput()
msg.Debug("Detected Windows Subsystem for Linux. Removing files using subsystem command")
if err2 != nil {
return fmt.Errorf("Error moving files: %s. output: %s", err2, output)
}

return nil
}

return os.Rename(o, n)
}

var procIsWin bool
var procDet bool

func detectWsl() bool {

if !procDet {
procDet = true
_, err := os.Stat("/proc/version")
if err == nil {
b, err := ioutil.ReadFile("/proc/version")
if err != nil {
msg.Warn("Unable to read /proc/version that was detected. May incorrectly detect WSL")
msg.Debug("Windows Subsystem for Linux detection error: %s", err)
return false
}

if bytes.Contains(b, []byte("Microsoft")) {
msg.Debug("Windows Subsystem for Linux detected")
procIsWin = true
}
}
}

return procIsWin
}
4 changes: 2 additions & 2 deletions repo/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,12 +380,12 @@ func (i *Installer) Export(conf *cfg.Config) error {
}
}

err = os.RemoveAll(i.VendorPath())
err = gpath.CustomRemoveAll(i.VendorPath())
if err != nil {
return err
}

err = os.Rename(vp, i.VendorPath())
err = gpath.CustomRename(vp, i.VendorPath())
if terr, ok := err.(*os.LinkError); ok {
return fixcle(vp, i.VendorPath(), terr)
}
Expand Down

0 comments on commit 245cace

Please sign in to comment.