blob: 3a27e6366ff7e65a45170029867e0059cae7d832 [file] [log] [blame]
package cmd
import (
"fmt"
"go/build"
"io"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"github.com/Masterminds/cookoo"
)
// Quiet, when set to true, can suppress Info and Debug messages.
var Quiet = false
var IsDebugging = false
var NoColor = false
// BeQuiet supresses Info and Debug messages.
func BeQuiet(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
Quiet = p.Get("quiet", false).(bool)
IsDebugging = p.Get("debug", false).(bool)
return Quiet, nil
}
// CheckColor turns off the colored output (and uses plain text output) for
// logging depending on the value of the "no-color" flag.
func CheckColor(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
NoColor = p.Get("no-color", false).(bool)
return NoColor, nil
}
// ReadyToGlide fails if the environment is not sufficient for using glide.
//
// Most importantly, it fails if glide.yaml is not present in the current
// working directory.
func ReadyToGlide(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
fname := p.Get("filename", "glide.yaml").(string)
if _, err := os.Stat(fname); err != nil {
cwd, _ := os.Getwd()
return false, fmt.Errorf("%s is missing from %s", fname, cwd)
}
return true, nil
}
// VersionGuard ensures that the Go version is correct.
func VersionGuard(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
// 6l was removed in 1.5, when vendoring was introduced.
cmd := exec.Command("go", "tool", "6l")
var out string
if _, err := cmd.CombinedOutput(); err == nil {
Warn("You must install the Go 1.5 or greater toolchain to work with Glide.\n")
}
if os.Getenv("GO15VENDOREXPERIMENT") != "1" {
Warn("To use Glide, you must set GO15VENDOREXPERIMENT=1\n")
}
// Verify the setup isn't for the old version of glide. That is, this is
// no longer assuming the _vendor directory as the GOPATH. Inform of
// the change.
if _, err := os.Stat("_vendor/"); err == nil {
Warn(`Your setup appears to be for the previous version of Glide.
Previously, vendor packages were stored in _vendor/src/ and
_vendor was set as your GOPATH. As of Go 1.5 the go tools
recognize the vendor directory as a location for these
files. Glide has embraced this. Please remove the _vendor
directory or move the _vendor/src/ directory to vendor/.` + "\n")
}
return out, nil
}
// CowardMode checks that the environment is setup before continuing on. If not
// setup and error is returned.
func CowardMode(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
gopath := Gopath()
if gopath == "" {
return false, fmt.Errorf("No GOPATH is set.\n")
}
_, err := os.Stat(path.Join(gopath, "src"))
if err != nil {
Error("Could not find %s/src.\n", gopath)
Info("As of Glide 0.5/Go 1.5, this is required.\n")
return false, err
}
return true, nil
}
// Check if a directory is empty or not.
func isDirectoryEmpty(dir string) (bool, error) {
f, err := os.Open(dir)
if err != nil {
return false, err
}
defer f.Close()
_, err = f.Readdir(1)
if err == io.EOF {
return true, nil
}
return false, err
}
// Gopath gets GOPATH from environment and return the most relevant path.
//
// A GOPATH can contain a colon-separated list of paths. This retrieves the
// GOPATH and returns only the FIRST ("most relevant") path.
//
// This should be used carefully. If, for example, you are looking for a package,
// you may be better off using Gopaths.
func Gopath() string {
gopaths := Gopaths()
if len(gopaths) == 0 {
return ""
}
return gopaths[0]
}
// Gopaths retrieves the Gopath as a list when there is more than one path
// listed in the Gopath.
func Gopaths() []string {
p := os.Getenv("GOPATH")
p = strings.Trim(p, string(filepath.ListSeparator))
return filepath.SplitList(p)
}
// BuildCtxt is a convenience wrapper for not having to import go/build
// anywhere else
type BuildCtxt struct {
build.Context
}
// GetBuildContext returns a build context from go/build. When the $GOROOT
// variable is not set in the users environment it sets the context's root
// path to the path returned by 'go env GOROOT'.
func GetBuildContext() (*BuildCtxt, error) {
buildContext := &BuildCtxt{build.Default}
if goRoot := os.Getenv("GOROOT"); len(goRoot) == 0 {
out, err := exec.Command("go", "env", "GOROOT").Output()
if goRoot = strings.TrimSpace(string(out)); len(goRoot) == 0 || err != nil {
return nil, fmt.Errorf("Please set the $GOROOT environment " +
"variable to use this command\n")
}
buildContext.GOROOT = goRoot
}
return buildContext, nil
}
func fileExist(name string) (bool, error) {
_, err := os.Stat(name)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return true, err
}
// We copy the directory here rather than jumping out to a shell so we can
// support multiple operating systems.
func copyDir(source string, dest string) error {
// get properties of source dir
si, err := os.Stat(source)
if err != nil {
return err
}
err = os.MkdirAll(dest, si.Mode())
if err != nil {
return err
}
d, _ := os.Open(source)
objects, err := d.Readdir(-1)
for _, obj := range objects {
sp := filepath.Join(source, "/", obj.Name())
dp := filepath.Join(dest, "/", obj.Name())
if obj.IsDir() {
err = copyDir(sp, dp)
if err != nil {
return err
}
} else {
// perform copy
err = copyFile(sp, dp)
if err != nil {
return err
}
}
}
return nil
}
func copyFile(source string, dest string) error {
ln, err := os.Readlink(source)
if err == nil {
return os.Symlink(ln, dest)
}
s, err := os.Open(source)
if err != nil {
return err
}
defer s.Close()
d, err := os.Create(dest)
if err != nil {
return err
}
defer d.Close()
_, err = io.Copy(d, s)
if err != nil {
return err
}
si, err := os.Stat(source)
if err != nil {
return err
}
err = os.Chmod(dest, si.Mode())
return err
}