-
Notifications
You must be signed in to change notification settings - Fork 0
/
options.go
235 lines (195 loc) · 4.91 KB
/
options.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
package find
import (
"fmt"
"io"
"os"
"path"
"strings"
)
// Type of the searched object.
const (
File uint8 = iota
Folder
Both
)
var sensitive = func(s string) string { return s }
type (
optFunc func(*options)
matchFunc func(Templates, string) bool
caseFunc func(string) string
// Type to create custom slices of find options.
Options []optFunc
)
// options allows to configure Find behavior.
type options struct {
matchFunc matchFunc
caseFunc caseFunc
logger io.Writer
output io.Writer
orig string
resOrig string
max int
maxIter int
fType uint8
iterCh chan string
errCh chan error
rec bool
name bool
relative bool
full bool
skip bool
log bool
iter bool
out bool
}
// defaultOptions default [Find] options.
func defaultOptions() *options {
return &options{
matchFunc: MatchAny,
caseFunc: sensitive,
logger: os.Stdout,
output: os.Stdout,
maxIter: 100,
max: -1,
fType: Both,
}
}
func defaultOptionsWithCustom(opts ...optFunc) *options {
opt := defaultOptions()
for _, fn := range opts {
fn(opt)
}
return opt
}
func (o *options) logError(e error) error {
if o.log {
if _, err := fmt.Fprintf(o.logger, "error: %s\n", e); err != nil {
return fmt.Errorf("%w: %w", e, err)
}
}
if o.skip {
return nil
}
return e
}
func (o *options) printOutput(str string) error {
if o.out {
if _, err := fmt.Fprintln(o.output, str); err != nil {
return err
}
}
return nil
}
func (o *options) isSearchedType(isDir bool) bool {
switch {
case o.fType == Folder:
return isDir
case o.fType == File:
return !isDir
default:
return true
}
}
func (o *options) match(ts Templates, fullPath string) bool {
if o.full {
return o.matchFunc(ts, o.caseFunc(fullPath))
}
return o.matchFunc(ts, o.caseFunc(path.Base(fullPath)))
}
// Deprecated: use [Only] instead.
func SearchFor(t uint8) optFunc { return Only(t) }
// Only defines if result should contains files, folders or both.
func Only(t uint8) optFunc {
return func(o *options) {
o.fType = t
}
}
// Deprecated: use [Recursively] instead.
func SearchRecursively(o *options) { Recursively(o) }
// Recursively defines recursive search.
func Recursively(o *options) { o.rec = true }
// Deprecated: use [Name] instead.
func SearchName(o *options) { Name(o) }
// Name defines if only names of files/folders should be
// in the output.
func Name(o *options) { o.name = true }
// Deprecated: use [Strict] instead.
func SearchStrict(o *options) { Strict(o) }
// Strict requires all templates to match searched path.
func Strict(o *options) { o.matchFunc = MatchAll }
// MatchFullPath matches full path not just the name.
func MatchFullPath(o *options) { o.full = true }
// RelativePaths does not resolve paths in the output.
//
// Note: does not work with [Name] option.
func RelativePaths(o *options) { o.relative = true }
// WithErrorsSkip skips errors during find execution.
//
// Note: if the flag was set, [Find] will return nil error,
// only if the base path was resolved.
func WithErrorsSkip(o *options) { o.skip = true }
// WithErrorsLog logs errors during find execution.
// Defaults to [os.Stdout] and can be changed with [WithLogger].
func WithErrorsLog(o *options) { o.log = true }
// WithOutput prints results as soon as they match given [Templates].
// Defaults to [os.Stdout] and can be changed with [WithWriter].
func WithOutput(o *options) { o.out = true }
// WithWriter allows to set custom [io.Writer] for [WithPrint].
// Also sets [WithOutput] to true.
//
// Note: write error counts as critical and will be returned
// even if [WithErrorsSkip] was set.
func WithWriter(out io.Writer) optFunc {
return func(o *options) {
o.output = out
o.out = true
}
}
// WithLogger allows to set custom logger for [WithErrorsLog].
// Also sets [WithErrorsLog] to true.
//
// Note: write error counts as critical and will be returned
// even if [WithErrorsSkip] was set.
func WithLogger(l io.Writer) optFunc {
return func(o *options) {
o.logger = l
o.log = true
}
}
// WithMaxIterator allows to set custom output channel buffer.
//
// Note: can be used only with [FindWithIterator] or has no effect.
func WithMaxIterator(max int) optFunc {
return func(o *options) {
o.maxIter = max
}
}
// Max set maximum ammount of searched objects. [Find] will stop as
// soon as reach the limitation.
func Max(i int) optFunc {
return func(o *options) {
o.max = i
}
}
// Insensitive sets case insensitive search.
func Insensitive(o *options) {
o.caseFunc = strings.ToLower
}
// MatchAny returns true if any of the given templates match the string.
func MatchAny(ts Templates, str string) bool {
for _, t := range ts {
if t.Match(str) {
return true
}
}
return false
}
// MatchAll returns true if all of the given templates match the string.
func MatchAll(ts Templates, str string) bool {
for _, t := range ts {
if !t.Match(str) {
return false
}
}
return true
}