github.com/golang/dep@v0.5.4/gps/filesystem.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gps 6 7 import ( 8 "os" 9 "path/filepath" 10 "strings" 11 12 "github.com/pkg/errors" 13 ) 14 15 // fsLink represents a symbolic link. 16 type fsLink struct { 17 path string 18 to string 19 20 // circular denotes if evaluating the symlink fails with "too many links" error. 21 // This error means that it's very likely that the symlink has a circular reference. 22 circular bool 23 24 // broken denotes that attempting to resolve the link fails, most likely because 25 // the destaination doesn't exist. 26 broken bool 27 } 28 29 // filesystemState represents the state of a file system. 30 type filesystemState struct { 31 root string 32 dirs []string 33 files []string 34 links []fsLink 35 } 36 37 func (s filesystemState) setup() error { 38 for _, dir := range s.dirs { 39 p := filepath.Join(s.root, dir) 40 41 if err := os.MkdirAll(p, 0777); err != nil { 42 return errors.Errorf("os.MkdirAll(%q, 0777) err=%q", p, err) 43 } 44 } 45 46 for _, file := range s.files { 47 p := filepath.Join(s.root, file) 48 49 f, err := os.Create(p) 50 if err != nil { 51 return errors.Errorf("os.Create(%q) err=%q", p, err) 52 } 53 54 if err := f.Close(); err != nil { 55 return errors.Errorf("file %q Close() err=%q", p, err) 56 } 57 } 58 59 for _, link := range s.links { 60 p := filepath.Join(s.root, link.path) 61 62 // On Windows, relative symlinks confuse filepath.Walk. So, we'll just sigh 63 // and do absolute links, assuming they are relative to the directory of 64 // link.path. 65 // 66 // Reference: https://github.com/golang/go/issues/17540 67 // 68 // TODO(ibrasho): This was fixed in Go 1.9. Remove this when support for 69 // 1.8 is dropped. 70 dir := filepath.Dir(p) 71 to := "" 72 if link.to != "" { 73 to = filepath.Join(dir, link.to) 74 } 75 76 if err := os.Symlink(to, p); err != nil { 77 return errors.Errorf("os.Symlink(%q, %q) err=%q", to, p, err) 78 } 79 } 80 81 return nil 82 } 83 84 // deriveFilesystemState returns a filesystemState based on the state of 85 // the filesystem on root. 86 func deriveFilesystemState(root string) (filesystemState, error) { 87 fs := filesystemState{root: root} 88 89 err := filepath.Walk(fs.root, func(path string, info os.FileInfo, err error) error { 90 if err != nil { 91 return err 92 } 93 94 if path == fs.root { 95 return nil 96 } 97 98 relPath, err := filepath.Rel(fs.root, path) 99 if err != nil { 100 return err 101 } 102 103 if (info.Mode() & os.ModeSymlink) != 0 { 104 l := fsLink{path: relPath} 105 106 l.to, err = filepath.EvalSymlinks(path) 107 if err != nil && strings.HasSuffix(err.Error(), "too many links") { 108 l.circular = true 109 } else if err != nil && os.IsNotExist(err) { 110 l.broken = true 111 } else if err != nil { 112 return err 113 } 114 115 fs.links = append(fs.links, l) 116 117 return nil 118 } 119 120 if info.IsDir() { 121 fs.dirs = append(fs.dirs, relPath) 122 123 return nil 124 } 125 126 fs.files = append(fs.files, relPath) 127 128 return nil 129 }) 130 131 if err != nil { 132 return filesystemState{}, err 133 } 134 135 return fs, nil 136 }