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