forked from Masterminds/glide
/
util.go
239 lines (201 loc) · 5.79 KB
/
util.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
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
}