action.noVend   F
last analyzed

Complexity

Conditions 14

Size

Total Lines 49
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 28
nop 3
dl 0
loc 49
rs 3.6
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like action.noVend 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
	"os"
5
	"path/filepath"
6
	"strings"
7
8
	"github.com/Masterminds/glide/msg"
9
)
10
11
// NoVendor generates a list of source code directories, excepting `vendor/`.
12
//
13
// If "onlyGo" is true, only folders that have Go code in them will be returned.
14
//
15
// If suffix is true, this will append `/...` to every directory.
16
func NoVendor(path string, onlyGo, suffix bool) {
17
	// This is responsible for printing the results of noVend.
18
	paths, err := noVend(path, onlyGo, suffix)
19
	if err != nil {
20
		msg.Err("Failed to walk file tree: %s", err)
21
		msg.Warn("FIXME: NoVendor should exit with non-zero exit code.")
22
		return
23
	}
24
25
	for _, p := range paths {
26
		msg.Puts(p)
27
	}
28
}
29
30
// noVend takes a directory and returns a list of Go-like files or directories,
31
// provided the directory is not a vendor directory.
32
//
33
// If onlyGo is true, this will filter out all directories that do not contain
34
// ".go" files.
35
//
36
// TODO: Should we move this to its own package?
37
func noVend(path string, onlyGo, suffix bool) ([]string, error) {
38
39
	info, err := os.Stat(path)
40
	if err != nil {
41
		return []string{}, err
42
	}
43
44
	if !info.IsDir() {
45
		return []string{path}, nil
46
	}
47
48
	res := []string{}
49
	f, err := os.Open(path)
50
	if err != nil {
51
		return res, err
52
	}
53
54
	fis, err := f.Readdir(0)
55
	if err != nil {
56
		return res, err
57
	}
58
59
	cur := false
60
61
	for _, fi := range fis {
62
		if exclude(fi) {
63
			continue
64
		}
65
66
		full := filepath.Join(path, fi.Name())
67
		if fi.IsDir() && !isVend(fi) {
68
			p := "./" + full + "/..."
69
			res = append(res, p)
70
		} else if !fi.IsDir() && isGoish(fi) {
71
			//res = append(res, full)
72
			cur = true
73
		}
74
	}
75
76
	// Filter out directories that do not contain Go code
77
	if onlyGo {
78
		res = hasGoSource(res, suffix)
79
	}
80
81
	if cur {
82
		res = append(res, ".")
83
	}
84
85
	return res, nil
86
}
87
88
// hasGoSource returns a list of directories that contain Go source.
89
func hasGoSource(dirs []string, suffix bool) []string {
90
	suf := "/"
91
	if suffix {
92
		suf = "/..."
93
	}
94
	buf := []string{}
95
	for _, d := range dirs {
96
		d := filepath.Dir(d)
97
		found := false
98
		walker := func(p string, fi os.FileInfo, err error) error {
99
			// Dumb optimization
100
			if found {
101
				return nil
102
			}
103
104
			// If the file ends with .go, report a match.
105
			if strings.ToLower(filepath.Ext(p)) == ".go" {
106
				found = true
107
			}
108
109
			return nil
110
		}
111
		filepath.Walk(d, walker)
112
113
		if found {
114
			buf = append(buf, "./"+d+suf)
115
		}
116
	}
117
	return buf
118
}
119
120
// isVend returns true of this directory is a vendor directory.
121
//
122
// TODO: Should we return true for Godeps directory?
123
func isVend(fi os.FileInfo) bool {
124
	return fi.Name() == "vendor"
125
}
126
127
// exclude returns true if the directory should be excluded by Go toolchain tools.
128
//
129
// Examples: directories prefixed with '.' or '_'.
130
func exclude(fi os.FileInfo) bool {
131
	if strings.HasPrefix(fi.Name(), "_") {
132
		return true
133
	}
134
	if strings.HasPrefix(fi.Name(), ".") {
135
		return true
136
	}
137
	return false
138
}
139
140
// isGoish returns true if the file appears to be Go source.
141
func isGoish(fi os.FileInfo) bool {
142
	return filepath.Ext(fi.Name()) == ".go"
143
}
144