-
Notifications
You must be signed in to change notification settings - Fork 11
/
io.go
134 lines (118 loc) · 3.94 KB
/
io.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
package utils
import (
"os"
"path/filepath"
"strings"
"github.com/coveo/gotemplate/collections"
"github.com/coveo/gotemplate/errors"
)
var must = errors.Must
// FindFiles returns the list of the files matching the array of patterns
func FindFiles(folder string, recursive, followLinks bool, patterns ...string) ([]string, error) {
depth := 0
if recursive {
depth = 1 << 16
}
return FindFilesMaxDepth(folder, depth, followLinks, patterns...)
}
// FindFilesMaxDepth returns the list of the files matching the array of patterns
func FindFilesMaxDepth(folder string, maxDepth int, followLinks bool, patterns ...string) ([]string, error) {
visited := map[string]bool{}
var walker func(folder string) ([]string, error)
walker = func(folder string) ([]string, error) {
results := must(findFiles(folder, patterns...)).([]string)
folder, _ = filepath.Abs(folder)
if maxDepth == 0 {
return results, nil
}
filepath.Walk(folder, func(path string, info os.FileInfo, err error) error {
if info == nil || path == folder {
return nil
}
if info.IsDir() {
visited[path] = true
depth := strings.Count(must(filepath.Rel(path, folder)).(string), "..")
if depth > maxDepth {
return filepath.SkipDir
}
files, err := findFiles(path, patterns...)
if err != nil {
return err
}
results = append(results, files...)
return nil
}
if info.Mode()&os.ModeSymlink != 0 && followLinks {
link, err := os.Readlink(path)
if err != nil {
return err
}
if !filepath.IsAbs(link) {
link = filepath.Join(filepath.Dir(path), link)
}
link, _ = filepath.Abs(link)
if !visited[link] {
// Check if we already visited that link to avoid recursive loop
linkFiles, err := walker(link)
if err != nil {
return err
}
results = append(results, linkFiles...)
}
}
return nil
})
return results, nil
}
return walker(folder)
}
// FindFiles returns the list of files in the specified folder that match one of the supplied patterns
func findFiles(folder string, patterns ...string) ([]string, error) {
var matches []string
for _, pattern := range patterns {
files, err := filepath.Glob(filepath.Join(folder, pattern))
if err != nil {
return nil, err
}
matches = append(matches, files...)
}
return matches, nil
}
// MustFindFiles returns the list of the files matching the array of patterns with panic on error
func MustFindFiles(folder string, recursive, followLinks bool, patterns ...string) []string {
return must(FindFiles(folder, recursive, followLinks, patterns...)).([]string)
}
// MustFindFilesMaxDepth returns the list of the files matching the array of patterns with panic on error
func MustFindFilesMaxDepth(folder string, maxDepth int, followLinks bool, patterns ...string) []string {
return must(FindFilesMaxDepth(folder, maxDepth, followLinks, patterns...)).([]string)
}
func globFunc(trimUnmatch bool, args ...interface{}) (result []string) {
for _, arg := range collections.ToStrings(args) {
if strings.ContainsAny(arg, "*?[]") {
if expanded, _ := filepath.Glob(arg); expanded != nil {
result = append(result, expanded...)
continue
}
if trimUnmatch {
continue
}
}
result = append(result, arg)
}
return
}
// GlobFunc returns an array of string representing the expansion of the supplied arguments using filepath.Glob function
func GlobFunc(args ...interface{}) []string { return globFunc(false, args...) }
// GlobFuncTrim returns an array of string representing the expansion of the supplied arguments using filepath.Glob function, it removes the unmatched arguments
func GlobFuncTrim(args ...interface{}) []string { return globFunc(true, args...) }
// Pwd returns the current folder
func Pwd() string {
return must(os.Getwd()).(string)
}
// Relative returns the relative path of file from folder
func Relative(folder, file string) string {
if !filepath.IsAbs(file) {
return file
}
return must(filepath.Rel(folder, file)).(string)
}