-
Notifications
You must be signed in to change notification settings - Fork 3
/
file.go
112 lines (89 loc) · 2.24 KB
/
file.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
package file
import (
"fmt"
"io/fs"
"path/filepath"
)
// EntType describes the entity types which a filesystem may contain.
type EntType string
const (
// EntTypeNone matches no entities.
EntTypeNone EntType = ""
// EntTypeAll matches all entity types.
EntTypeAll EntType = "all"
// EntTypeDir matches directory entities.
EntTypeDir EntType = "dir"
// EntTypeFile matches file entities.
EntTypeFile EntType = "file"
)
// Find functions similarly to GNU find searching recursively
// from root for all entites which match the given options.
// By default all entity types (file, directory) will be returned
// including the root directory.
func Find(root string, opts ...FindOption) ([]string, error) {
var cfg findConfig
cfg.Option(opts...)
cfg.Default()
var result []string
hasCorrectType := func(fs.DirEntry) bool { return true }
switch cfg.EntType {
case EntTypeDir:
hasCorrectType = func(d fs.DirEntry) bool {
return d.IsDir()
}
case EntTypeFile:
hasCorrectType = func(d fs.DirEntry) bool {
return !d.IsDir()
}
}
searchFunc := func(path string, d fs.DirEntry, _ error) error {
if !hasCorrectType(d) {
return nil
}
matches, err := filepath.Match(cfg.Name, filepath.Base(path))
if err != nil {
return fmt.Errorf("matching %q against %q: %w", path, cfg.Name, err)
}
if matches {
result = append(result, path)
}
return nil
}
if err := filepath.WalkDir(root, searchFunc); err != nil {
return nil, fmt.Errorf("walking directories: %w", err)
}
return result, nil
}
type findConfig struct {
EntType EntType
Name string
}
func (c *findConfig) Option(opts ...FindOption) {
for _, opt := range opts {
opt.ConfigureFind(c)
}
}
func (c *findConfig) Default() {
if c.EntType == EntTypeNone {
c.EntType = EntTypeAll
}
if c.Name == "" {
c.Name = "*"
}
}
type FindOption interface {
ConfigureFind(*findConfig)
}
// WithEntType selects which entity types will be
// matched by the find function.
type WithEntType EntType
func (t WithEntType) ConfigureFind(c *findConfig) {
c.EntType = EntType(t)
}
// WithName supplies a glob pattern to filter the
// matched entities to only those which match
// the glob.
type WithName string
func (n WithName) ConfigureFind(c *findConfig) {
c.Name = string(n)
}