github.com/franciscocpg/glide@v0.0.0-20160823235512-96aa2921b647/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, _ := os.Open(source)
   239  
   240  	objects, err := d.Readdir(-1)
   241  
   242  	for _, obj := range objects {
   243  
   244  		sp := filepath.Join(source, "/", obj.Name())
   245  
   246  		dp := filepath.Join(dest, "/", obj.Name())
   247  
   248  		if obj.IsDir() {
   249  			err = CopyDir(sp, dp)
   250  			if err != nil {
   251  				return err
   252  			}
   253  		} else {
   254  			// perform copy
   255  			err = CopyFile(sp, dp)
   256  			if err != nil {
   257  				return err
   258  			}
   259  		}
   260  
   261  	}
   262  	return nil
   263  }
   264  
   265  // CopyFile copies a source file to a destination.
   266  //
   267  // It follows symbolic links and retains modes.
   268  func CopyFile(source string, dest string) error {
   269  	ln, err := os.Readlink(source)
   270  	if err == nil {
   271  		return os.Symlink(ln, dest)
   272  	}
   273  	s, err := os.Open(source)
   274  	if err != nil {
   275  		return err
   276  	}
   277  
   278  	defer s.Close()
   279  
   280  	d, err := os.Create(dest)
   281  	if err != nil {
   282  		return err
   283  	}
   284  
   285  	defer d.Close()
   286  
   287  	_, err = io.Copy(d, s)
   288  	if err != nil {
   289  		return err
   290  	}
   291  
   292  	si, err := os.Stat(source)
   293  	if err != nil {
   294  		return err
   295  	}
   296  	err = os.Chmod(dest, si.Mode())
   297  
   298  	return err
   299  }