forked from Masterminds/glide
/
create.go
245 lines (209 loc) · 6.86 KB
/
create.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
240
241
242
243
244
245
package action
import (
"os"
"path/filepath"
"sort"
"strings"
"github.com/Masterminds/glide/cfg"
"github.com/Masterminds/glide/dependency"
"github.com/Masterminds/glide/gb"
"github.com/Masterminds/glide/godep"
"github.com/Masterminds/glide/gpm"
"github.com/Masterminds/glide/msg"
gpath "github.com/Masterminds/glide/path"
"github.com/Masterminds/glide/util"
)
// Create creates/initializes a new Glide repository.
//
// This will fail if a glide.yaml already exists.
//
// By default, this will scan the present source code directory for dependencies.
//
// If skipImport is set to true, this will not attempt to import from an existing
// GPM, Godep, or GB project if one should exist. However, it will still attempt
// to read the local source to determine required packages.
func Create(base string, skipImport, nonInteractive bool) {
glidefile := gpath.GlideFile
// Guard against overwrites.
guardYAML(glidefile)
// Guess deps
conf := guessDeps(base, skipImport)
// Write YAML
msg.Info("Writing configuration file (%s)", glidefile)
if err := conf.WriteFile(glidefile); err != nil {
msg.Die("Could not save %s: %s", glidefile, err)
}
var res bool
if !nonInteractive {
msg.Info("Would you like Glide to help you find ways to improve your glide.yaml configuration?")
msg.Info("If you want to revisit this step you can use the config-wizard command at any time.")
msg.Info("Yes (Y) or No (N)?")
res = msg.PromptUntilYorN()
if res {
ConfigWizard(base)
}
}
if !res {
msg.Info("You can now edit the glide.yaml file. Consider:")
msg.Info("--> Using versions and ranges. See https://glide.sh/docs/versions/")
msg.Info("--> Adding additional metadata. See https://glide.sh/docs/glide.yaml/")
msg.Info("--> Running the config-wizard command to improve the versions in your configuration")
}
}
// guardYAML fails if the given file already exists.
//
// This prevents an important file from being overwritten.
func guardYAML(filename string) {
if _, err := os.Stat(filename); err == nil {
msg.Die("Cowardly refusing to overwrite existing YAML.")
}
}
// guessDeps attempts to resolve all of the dependencies for a given project.
//
// base is the directory to start with.
// skipImport will skip running the automatic imports.
//
// FIXME: This function is likely a one-off that has a more standard alternative.
// It's also long and could use a refactor.
func guessDeps(base string, skipImport bool) *cfg.Config {
buildContext, err := util.GetBuildContext()
if err != nil {
msg.Die("Failed to build an import context: %s", err)
}
name := buildContext.PackageName(base)
msg.Info("Generating a YAML configuration file and guessing the dependencies")
config := new(cfg.Config)
// Get the name of the top level package
config.Name = name
// Import by looking at other package managers and looking over the
// entire directory structure.
// Attempt to import from other package managers.
if !skipImport {
guessImportDeps(base, config)
}
importLen := len(config.Imports)
if importLen == 0 {
msg.Info("Scanning code to look for dependencies")
} else {
msg.Info("Scanning code to look for dependencies not found in import")
}
// Resolve dependencies by looking at the tree.
r, err := dependency.NewResolver(base)
if err != nil {
msg.Die("Error creating a dependency resolver: %s", err)
}
// When creating resolve the test dependencies as well as the application ones.
r.ResolveTest = true
h := &dependency.DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}}
r.Handler = h
sortable, testSortable, err := r.ResolveLocal(false)
if err != nil {
msg.Die("Error resolving local dependencies: %s", err)
}
sort.Strings(sortable)
sort.Strings(testSortable)
vpath := r.VendorDir
if !strings.HasSuffix(vpath, "/") {
vpath = vpath + string(os.PathSeparator)
}
for _, pa := range sortable {
n := strings.TrimPrefix(pa, vpath)
root, subpkg := util.NormalizeName(n)
if !config.Imports.Has(root) && root != config.Name {
msg.Info("--> Found reference to %s\n", n)
d := &cfg.Dependency{
Name: root,
}
if len(subpkg) > 0 {
d.Subpackages = []string{subpkg}
}
config.Imports = append(config.Imports, d)
} else if config.Imports.Has(root) {
if len(subpkg) > 0 {
subpkg = strings.TrimPrefix(subpkg, "/")
d := config.Imports.Get(root)
if !d.HasSubpackage(subpkg) {
msg.Info("--> Adding sub-package %s to %s\n", subpkg, root)
d.Subpackages = append(d.Subpackages, subpkg)
}
}
}
}
for _, pa := range testSortable {
n := strings.TrimPrefix(pa, vpath)
root, subpkg := util.NormalizeName(n)
if config.Imports.Has(root) && root != config.Name {
msg.Debug("--> Found test reference to %s already listed as an import", n)
} else if !config.DevImports.Has(root) && root != config.Name {
msg.Info("--> Found test reference to %s", n)
d := &cfg.Dependency{
Name: root,
}
if len(subpkg) > 0 {
d.Subpackages = []string{subpkg}
}
config.DevImports = append(config.DevImports, d)
} else if config.DevImports.Has(root) {
if len(subpkg) > 0 {
subpkg = strings.TrimPrefix(subpkg, "/")
d := config.DevImports.Get(root)
if !d.HasSubpackage(subpkg) {
msg.Info("--> Adding test sub-package %s to %s\n", subpkg, root)
d.Subpackages = append(d.Subpackages, subpkg)
}
}
}
}
if len(config.Imports) == importLen && importLen != 0 {
msg.Info("--> Code scanning found no additional imports")
}
return config
}
func guessImportDeps(base string, config *cfg.Config) {
msg.Info("Attempting to import from other package managers (use --skip-import to skip)")
deps := []*cfg.Dependency{}
absBase, err := filepath.Abs(base)
if err != nil {
msg.Die("Failed to resolve location of %s: %s", base, err)
}
if d, ok := guessImportGodep(absBase); ok {
msg.Info("Importing Godep configuration")
msg.Warn("Godep uses commit id versions. Consider using Semantic Versions with Glide")
deps = d
} else if d, ok := guessImportGPM(absBase); ok {
msg.Info("Importing GPM configuration")
deps = d
} else if d, ok := guessImportGB(absBase); ok {
msg.Info("Importing GB configuration")
deps = d
}
for _, i := range deps {
if i.Reference == "" {
msg.Info("--> Found imported reference to %s", i.Name)
} else {
msg.Info("--> Found imported reference to %s at revision %s", i.Name, i.Reference)
}
config.Imports = append(config.Imports, i)
}
}
func guessImportGodep(dir string) ([]*cfg.Dependency, bool) {
d, err := godep.Parse(dir)
if err != nil || len(d) == 0 {
return []*cfg.Dependency{}, false
}
return d, true
}
func guessImportGPM(dir string) ([]*cfg.Dependency, bool) {
d, err := gpm.Parse(dir)
if err != nil || len(d) == 0 {
return []*cfg.Dependency{}, false
}
return d, true
}
func guessImportGB(dir string) ([]*cfg.Dependency, bool) {
d, err := gb.Parse(dir)
if err != nil || len(d) == 0 {
return []*cfg.Dependency{}, false
}
return d, true
}