github.com/scalingdata/glide@v0.12.3/path/path.go (about) 1 // Package path contains path and environment utilities for Glide. 2 // 3 // This includes tools to find and manipulate Go path variables, as well as 4 // tools for copying from one path to another. 5 package path 6 7 import ( 8 "fmt" 9 "io" 10 "os" 11 "os/user" 12 "path/filepath" 13 "strings" 14 ) 15 16 // DefaultGlideFile is the default name for the glide.yaml file. 17 const DefaultGlideFile = "glide.yaml" 18 19 // VendorDir is the name of the directory that holds vendored dependencies. 20 // 21 // As of Go 1.5, this is always vendor. 22 var VendorDir = "vendor" 23 24 // Tmp is the temporary directory Glide should use. Defaults to "" which 25 // signals using the system default. 26 var Tmp = "" 27 28 // Cache the location of the homedirectory. 29 var homeDir = "" 30 31 // GlideFile is the name of the Glide file. 32 // 33 // Setting this is not concurrency safe. For consistency, it should really 34 // only be set once, at startup, or not at all. 35 var GlideFile = DefaultGlideFile 36 37 // LockFile is the default name for the lock file. 38 const LockFile = "glide.lock" 39 40 // Home returns the Glide home directory ($GLIDE_HOME or ~/.glide, typically). 41 // 42 // This normalizes to an absolute path, and passes through os.ExpandEnv. 43 func Home() string { 44 if homeDir != "" { 45 return homeDir 46 } 47 48 // Initialize the default user. 49 u, err := user.Current() 50 if err == nil && u.HomeDir != "" { 51 homeDir = filepath.Join(u.HomeDir, ".glide") 52 } else { 53 cwd, err := os.Getwd() 54 if err == nil { 55 homeDir = filepath.Join(cwd, ".glide") 56 } else { 57 homeDir = ".glide" 58 } 59 } 60 61 return homeDir 62 } 63 64 // SetHome sets the home directory for Glide. 65 func SetHome(h string) { 66 homeDir = h 67 } 68 69 // Vendor calculates the path to the vendor directory. 70 // 71 // Based on working directory, VendorDir and GlideFile, this attempts to 72 // guess the location of the vendor directory. 73 func Vendor() (string, error) { 74 cwd, err := os.Getwd() 75 if err != nil { 76 return "", err 77 } 78 79 // Find the directory that contains glide.yaml 80 yamldir, err := GlideWD(cwd) 81 if err != nil { 82 return cwd, err 83 } 84 85 gopath := filepath.Join(yamldir, VendorDir) 86 87 // Resolve symlinks 88 info, err := os.Lstat(gopath) 89 if err != nil { 90 return gopath, nil 91 } 92 for i := 0; IsLink(info) && i < 255; i++ { 93 p, err := os.Readlink(gopath) 94 if err != nil { 95 return gopath, nil 96 } 97 98 if filepath.IsAbs(p) { 99 gopath = p 100 } else { 101 gopath = filepath.Join(filepath.Dir(gopath), p) 102 } 103 104 info, err = os.Lstat(gopath) 105 if err != nil { 106 return gopath, nil 107 } 108 } 109 110 return gopath, nil 111 } 112 113 // Glide gets the path to the closest glide file. 114 func Glide() (string, error) { 115 cwd, err := os.Getwd() 116 if err != nil { 117 return "", err 118 } 119 120 // Find the directory that contains glide.yaml 121 yamldir, err := GlideWD(cwd) 122 if err != nil { 123 return cwd, err 124 } 125 126 gf := filepath.Join(yamldir, GlideFile) 127 return gf, nil 128 } 129 130 // GlideWD finds the working directory of the glide.yaml file, starting at dir. 131 // 132 // If the glide file is not found in the current directory, it recurses up 133 // a directory. 134 func GlideWD(dir string) (string, error) { 135 fullpath := filepath.Join(dir, GlideFile) 136 137 if _, err := os.Stat(fullpath); err == nil { 138 return dir, nil 139 } 140 141 base := filepath.Dir(dir) 142 if base == dir { 143 return "", fmt.Errorf("Cannot resolve parent of %s", base) 144 } 145 146 return GlideWD(base) 147 } 148 149 // Gopath gets GOPATH from environment and return the most relevant path. 150 // 151 // A GOPATH can contain a colon-separated list of paths. This retrieves the 152 // GOPATH and returns only the FIRST ("most relevant") path. 153 // 154 // This should be used carefully. If, for example, you are looking for a package, 155 // you may be better off using Gopaths. 156 func Gopath() string { 157 gopaths := Gopaths() 158 if len(gopaths) == 0 { 159 return "" 160 } 161 return gopaths[0] 162 } 163 164 // Gopaths retrieves the Gopath as a list when there is more than one path 165 // listed in the Gopath. 166 func Gopaths() []string { 167 p := os.Getenv("GOPATH") 168 p = strings.Trim(p, string(filepath.ListSeparator)) 169 return filepath.SplitList(p) 170 } 171 172 // Basepath returns the current working directory. 173 // 174 // If there is an error getting the working directory, this returns ".", which 175 // should function in cases where the directory is unlinked... Then again, 176 // maybe not. 177 func Basepath() string { 178 base, err := os.Getwd() 179 if err != nil { 180 return "." 181 } 182 return base 183 } 184 185 // StripBasepath removes the base directory from a passed in path. 186 func StripBasepath(p string) string { 187 bp := Basepath() 188 return strings.TrimPrefix(p, bp+string(os.PathSeparator)) 189 } 190 191 // IsLink returns true if the given FileInfo references a link. 192 func IsLink(fi os.FileInfo) bool { 193 return fi.Mode()&os.ModeSymlink == os.ModeSymlink 194 } 195 196 // HasLock returns true if this can stat a lockfile at the givin location. 197 func HasLock(basepath string) bool { 198 _, err := os.Stat(filepath.Join(basepath, LockFile)) 199 return err == nil 200 } 201 202 // IsDirectoryEmpty checks if a directory is empty. 203 func IsDirectoryEmpty(dir string) (bool, error) { 204 f, err := os.Open(dir) 205 if err != nil { 206 return false, err 207 } 208 defer f.Close() 209 210 _, err = f.Readdir(1) 211 212 if err == io.EOF { 213 return true, nil 214 } 215 216 return false, err 217 } 218 219 // CopyDir copies an entire source directory to the dest directory. 220 // 221 // This is akin to `cp -a src/* dest/` 222 // 223 // We copy the directory here rather than jumping out to a shell so we can 224 // support multiple operating systems. 225 func CopyDir(source string, dest string) error { 226 227 // get properties of source dir 228 si, err := os.Stat(source) 229 if err != nil { 230 return err 231 } 232 233 err = os.MkdirAll(dest, si.Mode()) 234 if err != nil { 235 return err 236 } 237 238 d, err := os.Open(source) 239 if err != nil { 240 return err 241 } 242 defer d.Close() 243 244 objects, err := d.Readdir(-1) 245 246 for _, obj := range objects { 247 248 sp := filepath.Join(source, "/", obj.Name()) 249 250 dp := filepath.Join(dest, "/", obj.Name()) 251 252 if obj.IsDir() { 253 err = CopyDir(sp, dp) 254 if err != nil { 255 return err 256 } 257 } else { 258 // perform copy 259 err = CopyFile(sp, dp) 260 if err != nil { 261 return err 262 } 263 } 264 265 } 266 return nil 267 } 268 269 // CopyFile copies a source file to a destination. 270 // 271 // It follows symbolic links and retains modes. 272 func CopyFile(source string, dest string) error { 273 ln, err := os.Readlink(source) 274 if err == nil { 275 return os.Symlink(ln, dest) 276 } 277 s, err := os.Open(source) 278 if err != nil { 279 return err 280 } 281 282 defer s.Close() 283 284 d, err := os.Create(dest) 285 if err != nil { 286 return err 287 } 288 289 defer d.Close() 290 291 _, err = io.Copy(d, s) 292 if err != nil { 293 return err 294 } 295 296 si, err := os.Stat(source) 297 if err != nil { 298 return err 299 } 300 err = os.Chmod(dest, si.Mode()) 301 302 return err 303 }