#553: Fixed issue with moving vendor directory cross devices with copy
diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b80ea1..7e757f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ others are deprecated and no longer needed. ## Fixed +- #553: Export was failing with different physical devices - #542: Glide failed to detect some test dependencies (thanks @sdboyer) - #517: Fixed failure to install testImport from lock when no imports present or when same dependency on both import and testImport
diff --git a/glide.go b/glide.go index ce39ede..77c39a7 100644 --- a/glide.go +++ b/glide.go
@@ -105,6 +105,12 @@ Usage: "The location of Glide files", EnvVar: "GLIDE_HOME", }, + cli.StringFlag{ + Name: "tmp", + Value: "", + Usage: "The temp directory to use. Defaults to systems temp", + EnvVar: "GLIDE_TMP", + }, cli.BoolFlag{ Name: "no-color", Usage: "Turn off colored output for log messages", @@ -858,6 +864,7 @@ action.Quiet(c.Bool("quiet")) action.Init(c.String("yaml"), c.String("home")) action.EnsureGoVendor() + gpath.Tmp = c.String("tmp") return nil }
diff --git a/path/path.go b/path/path.go index ecc8a10..48e95fb 100644 --- a/path/path.go +++ b/path/path.go
@@ -21,6 +21,10 @@ // As of Go 1.5, this is always vendor. var VendorDir = "vendor" +// Tmp is the temporary directory Glide should use. Defaults to "" which +// signals using the system default. +var Tmp = "" + // Cache the location of the homedirectory. var homeDir = "" @@ -211,3 +215,85 @@ return false, err } + +// CopyDir copies an entire source directory to the dest directory. +// +// This is akin to `cp -a src/* dest/` +// +// We copy the directory here rather than jumping out to a shell so we can +// support multiple operating systems. +func CopyDir(source string, dest string) error { + + // get properties of source dir + si, err := os.Stat(source) + if err != nil { + return err + } + + err = os.MkdirAll(dest, si.Mode()) + if err != nil { + return err + } + + d, _ := os.Open(source) + + objects, err := d.Readdir(-1) + + for _, obj := range objects { + + sp := filepath.Join(source, "/", obj.Name()) + + dp := filepath.Join(dest, "/", obj.Name()) + + if obj.IsDir() { + err = CopyDir(sp, dp) + if err != nil { + return err + } + } else { + // perform copy + err = CopyFile(sp, dp) + if err != nil { + return err + } + } + + } + return nil +} + +// CopyFile copies a source file to a destination. +// +// It follows symbolic links and retains modes. +func CopyFile(source string, dest string) error { + ln, err := os.Readlink(source) + if err == nil { + return os.Symlink(ln, dest) + } + s, err := os.Open(source) + if err != nil { + return err + } + + defer s.Close() + + d, err := os.Create(dest) + if err != nil { + return err + } + + defer d.Close() + + _, err = io.Copy(d, s) + if err != nil { + return err + } + + si, err := os.Stat(source) + if err != nil { + return err + } + err = os.Chmod(dest, si.Mode()) + + return err +}
diff --git a/repo/installer.go b/repo/installer.go index a5d6aee..8110245 100644 --- a/repo/installer.go +++ b/repo/installer.go
@@ -244,7 +244,7 @@ // Export from the cache to the vendor directory func (i *Installer) Export(conf *cfg.Config) error { - tempDir, err := ioutil.TempDir("", "glide-vendor") + tempDir, err := ioutil.TempDir(gpath.Tmp, "glide-vendor") if err != nil { return err } @@ -358,6 +358,15 @@ } err = os.Rename(vp, i.VendorPath()) + + // When there are different physical devices we cannot rename cross device. + // Fall back to manual copy. + if strings.Contains(err.Error(), "invalid cross-device link") { + msg.Debug("Cross link err, trying manual copy: %s", err) + + err = gpath.CopyDir(vp, i.VendorPath()) + } + return err }