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