action.Get   F
last analyzed

Complexity

Conditions 14

Size

Total Lines 76
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 40
nop 7
dl 0
loc 76
rs 3.6
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like action.Get often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
package action
2
3
import (
4
	"fmt"
5
	"path/filepath"
6
	"strings"
7
8
	"github.com/Masterminds/glide/cache"
9
	"github.com/Masterminds/glide/cfg"
10
	"github.com/Masterminds/glide/godep"
11
	"github.com/Masterminds/glide/msg"
12
	gpath "github.com/Masterminds/glide/path"
13
	"github.com/Masterminds/glide/repo"
14
	"github.com/Masterminds/glide/util"
15
	"github.com/Masterminds/semver"
16
)
17
18
// Get fetches one or more dependencies and installs.
19
//
20
// This includes resolving dependency resolution and re-generating the lock file.
21
func Get(names []string, installer *repo.Installer, insecure, skipRecursive, stripVendor, nonInteract, testDeps bool) {
22
	cache.SystemLock()
23
24
	base := gpath.Basepath()
25
	EnsureGopath()
26
	EnsureVendorDir()
27
	conf := EnsureConfig()
28
	glidefile, err := gpath.Glide()
29
	if err != nil {
30
		msg.Die("Could not find Glide file: %s", err)
31
	}
32
33
	// Add the packages to the config.
34
	if count, err2 := addPkgsToConfig(conf, names, insecure, nonInteract, testDeps); err2 != nil {
35
		msg.Die("Failed to get new packages: %s", err2)
36
	} else if count == 0 {
37
		msg.Warn("Nothing to do")
38
		return
39
	}
40
41
	// Fetch the new packages. Can't resolve versions via installer.Update if
42
	// get is called while the vendor/ directory is empty so we checkout
43
	// everything.
44
	err = installer.Checkout(conf)
45
	if err != nil {
46
		msg.Die("Failed to checkout packages: %s", err)
47
	}
48
49
	// Prior to resolving dependencies we need to start working with a clone
50
	// of the conf because we'll be making real changes to it.
51
	confcopy := conf.Clone()
52
53
	if !skipRecursive {
54
		// Get all repos and update them.
55
		// TODO: Can we streamline this in any way? The reason that we update all
56
		// of the dependencies is that we need to re-negotiate versions. For example,
57
		// if an existing dependency has the constraint >1.0 and this new package
58
		// adds the constraint <2.0, then this may re-resolve the existing dependency
59
		// to be between 1.0 and 2.0. But changing that dependency may then result
60
		// in that dependency's dependencies changing... so we sorta do the whole
61
		// thing to be safe.
62
		err = installer.Update(confcopy)
63
		if err != nil {
64
			msg.Die("Could not update packages: %s", err)
65
		}
66
	}
67
68
	// Set Reference
69
	if err := repo.SetReference(confcopy, installer.ResolveTest); err != nil {
70
		msg.Err("Failed to set references: %s", err)
71
	}
72
73
	err = installer.Export(confcopy)
74
	if err != nil {
75
		msg.Die("Unable to export dependencies to vendor directory: %s", err)
76
	}
77
78
	// Write YAML
79
	if err := conf.WriteFile(glidefile); err != nil {
80
		msg.Die("Failed to write glide YAML file: %s", err)
81
	}
82
	if !skipRecursive {
83
		// Write lock
84
		if stripVendor {
85
			confcopy = godep.RemoveGodepSubpackages(confcopy)
86
		}
87
		writeLock(conf, confcopy, base)
88
	} else {
89
		msg.Warn("Skipping lockfile generation because full dependency tree is not being calculated")
90
	}
91
92
	if stripVendor {
93
		msg.Info("Removing nested vendor and Godeps/_workspace directories...")
94
		err := gpath.StripVendor()
95
		if err != nil {
96
			msg.Err("Unable to strip vendor directories: %s", err)
97
		}
98
	}
99
}
100
101
func writeLock(conf, confcopy *cfg.Config, base string) {
102
	hash, err := conf.Hash()
103
	if err != nil {
104
		msg.Die("Failed to generate config hash. Unable to generate lock file.")
105
	}
106
	lock, err := cfg.NewLockfile(confcopy.Imports, confcopy.DevImports, hash)
107
	if err != nil {
108
		msg.Die("Failed to generate lock file: %s", err)
109
	}
110
	if err := lock.WriteFile(filepath.Join(base, gpath.LockFile)); err != nil {
111
		msg.Die("Failed to write glide lock file: %s", err)
112
	}
113
}
114
115
// addPkgsToConfig adds the given packages to the config file.
116
//
117
// Along the way it:
118
// - ensures that this package is not in the ignore list
119
// - checks to see if this is already in the dependency list.
120
// - splits version of of package name and adds the version attribute
121
// - separates repo from packages
122
// - sets up insecure repo URLs where necessary
123
// - generates a list of subpackages
124
func addPkgsToConfig(conf *cfg.Config, names []string, insecure, nonInteract, testDeps bool) (int, error) {
125
126
	if len(names) == 1 {
127
		msg.Info("Preparing to install %d package.", len(names))
128
	} else {
129
		msg.Info("Preparing to install %d packages.", len(names))
130
	}
131
	numAdded := 0
132
	for _, name := range names {
133
		var version string
134
		parts := strings.Split(name, "#")
135
		if len(parts) > 1 {
136
			name = parts[0]
137
			version = parts[1]
138
		}
139
140
		msg.Info("Attempting to get package %s", name)
141
142
		root, subpkg := util.NormalizeName(name)
143
		if len(root) == 0 {
144
			return 0, fmt.Errorf("Package name is required for %q.", name)
0 ignored issues
show
introduced by
error strings should not be capitalized or end with punctuation or a newline
Loading history...
145
		}
146
147
		if conf.HasDependency(root) {
148
149
			var moved bool
150
			var dep *cfg.Dependency
151
			// Move from DevImports to Imports
152
			if !testDeps && !conf.Imports.Has(root) && conf.DevImports.Has(root) {
153
				dep = conf.DevImports.Get(root)
154
				conf.Imports = append(conf.Imports, dep)
155
				conf.DevImports = conf.DevImports.Remove(root)
156
				moved = true
157
				numAdded++
158
				msg.Info("--> Moving %s from testImport to import", root)
159
			} else if testDeps && conf.Imports.Has(root) {
160
				msg.Warn("--> Test dependency %s already listed as import", root)
161
			}
162
163
			// Check if the subpackage is present.
164
			if subpkg != "" {
165
				if dep == nil {
166
					dep = conf.Imports.Get(root)
167
					if dep == nil && testDeps {
168
						dep = conf.DevImports.Get(root)
169
					}
170
				}
171
				if dep.HasSubpackage(subpkg) {
172
					if !moved {
173
						msg.Warn("--> Package %q is already in glide.yaml. Skipping", name)
174
					}
175
				} else {
176
					dep.Subpackages = append(dep.Subpackages, subpkg)
177
					msg.Info("--> Adding sub-package %s to existing import %s", subpkg, root)
178
					numAdded++
179
				}
180
			} else if !moved {
181
				msg.Warn("--> Package %q is already in glide.yaml. Skipping", root)
182
			}
183
			continue
184
		}
185
186
		if conf.HasIgnore(root) {
187
			msg.Warn("--> Package %q is set to be ignored in glide.yaml. Skipping", root)
188
			continue
189
		}
190
191
		dep := &cfg.Dependency{
192
			Name: root,
193
		}
194
195
		// When retriving from an insecure location set the repo to the
196
		// insecure location.
197
		if insecure {
198
			dep.Repository = "http://" + root
199
		}
200
201
		if version != "" {
202
			dep.Reference = version
203
		} else if !nonInteract {
204
			getWizard(dep)
205
		}
206
207
		if len(subpkg) > 0 {
208
			dep.Subpackages = []string{subpkg}
209
		}
210
211
		if dep.Reference != "" {
212
			msg.Info("--> Adding %s to your configuration with the version %s", dep.Name, dep.Reference)
213
		} else {
214
			msg.Info("--> Adding %s to your configuration", dep.Name)
215
		}
216
217
		if testDeps {
218
			conf.DevImports = append(conf.DevImports, dep)
219
		} else {
220
			conf.Imports = append(conf.Imports, dep)
221
		}
222
		numAdded++
223
	}
224
	return numAdded, nil
225
}
226
227
func getWizard(dep *cfg.Dependency) {
228
	remote := dep.Remote()
229
230
	// Lookup dependency info and store in cache.
231
	msg.Info("--> Gathering release information for %s", dep.Name)
232
	wizardFindVersions(dep)
233
234
	memlatest := cache.MemLatest(remote)
235
	if memlatest != "" {
236
		dres := wizardAskLatest(memlatest, dep)
237
		if dres {
238
			dep.Reference = memlatest
239
240
			sv, err := semver.NewVersion(dep.Reference)
241
			if err == nil {
242
				res := wizardAskRange(sv, dep)
243
				if res == "m" {
244
					dep.Reference = "^" + sv.String()
245
				} else if res == "p" {
246
					dep.Reference = "~" + sv.String()
247
				}
248
			}
249
		}
250
	}
251
}
252