1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package afero
18
19 import (
20 "bytes"
21 "fmt"
22 "io"
23 "os"
24 "path/filepath"
25 "strings"
26 "unicode"
27
28 "golang.org/x/text/runes"
29 "golang.org/x/text/transform"
30 "golang.org/x/text/unicode/norm"
31 )
32
33
34 const FilePathSeparator = string(filepath.Separator)
35
36
37 func (a Afero) WriteReader(path string, r io.Reader) (err error) {
38 return WriteReader(a.Fs, path, r)
39 }
40
41 func WriteReader(fs Fs, path string, r io.Reader) (err error) {
42 dir, _ := filepath.Split(path)
43 ospath := filepath.FromSlash(dir)
44
45 if ospath != "" {
46 err = fs.MkdirAll(ospath, 0o777)
47 if err != nil {
48 if err != os.ErrExist {
49 return err
50 }
51 }
52 }
53
54 file, err := fs.Create(path)
55 if err != nil {
56 return
57 }
58 defer file.Close()
59
60 _, err = io.Copy(file, r)
61 return
62 }
63
64
65 func (a Afero) SafeWriteReader(path string, r io.Reader) (err error) {
66 return SafeWriteReader(a.Fs, path, r)
67 }
68
69 func SafeWriteReader(fs Fs, path string, r io.Reader) (err error) {
70 dir, _ := filepath.Split(path)
71 ospath := filepath.FromSlash(dir)
72
73 if ospath != "" {
74 err = fs.MkdirAll(ospath, 0o777)
75 if err != nil {
76 return
77 }
78 }
79
80 exists, err := Exists(fs, path)
81 if err != nil {
82 return
83 }
84 if exists {
85 return fmt.Errorf("%v already exists", path)
86 }
87
88 file, err := fs.Create(path)
89 if err != nil {
90 return
91 }
92 defer file.Close()
93
94 _, err = io.Copy(file, r)
95 return
96 }
97
98 func (a Afero) GetTempDir(subPath string) string {
99 return GetTempDir(a.Fs, subPath)
100 }
101
102
103
104 func GetTempDir(fs Fs, subPath string) string {
105 addSlash := func(p string) string {
106 if FilePathSeparator != p[len(p)-1:] {
107 p = p + FilePathSeparator
108 }
109 return p
110 }
111 dir := addSlash(os.TempDir())
112
113 if subPath != "" {
114
115 if FilePathSeparator == "\\" {
116 subPath = strings.Replace(subPath, "\\", "____", -1)
117 }
118 dir = dir + UnicodeSanitize((subPath))
119 if FilePathSeparator == "\\" {
120 dir = strings.Replace(dir, "____", "\\", -1)
121 }
122
123 if exists, _ := Exists(fs, dir); exists {
124 return addSlash(dir)
125 }
126
127 err := fs.MkdirAll(dir, 0o777)
128 if err != nil {
129 panic(err)
130 }
131 dir = addSlash(dir)
132 }
133 return dir
134 }
135
136
137 func UnicodeSanitize(s string) string {
138 source := []rune(s)
139 target := make([]rune, 0, len(source))
140
141 for _, r := range source {
142 if unicode.IsLetter(r) ||
143 unicode.IsDigit(r) ||
144 unicode.IsMark(r) ||
145 r == '.' ||
146 r == '/' ||
147 r == '\\' ||
148 r == '_' ||
149 r == '-' ||
150 r == '%' ||
151 r == ' ' ||
152 r == '#' {
153 target = append(target, r)
154 }
155 }
156
157 return string(target)
158 }
159
160
161 func NeuterAccents(s string) string {
162 t := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
163 result, _, _ := transform.String(t, string(s))
164
165 return result
166 }
167
168 func (a Afero) FileContainsBytes(filename string, subslice []byte) (bool, error) {
169 return FileContainsBytes(a.Fs, filename, subslice)
170 }
171
172
173 func FileContainsBytes(fs Fs, filename string, subslice []byte) (bool, error) {
174 f, err := fs.Open(filename)
175 if err != nil {
176 return false, err
177 }
178 defer f.Close()
179
180 return readerContainsAny(f, subslice), nil
181 }
182
183 func (a Afero) FileContainsAnyBytes(filename string, subslices [][]byte) (bool, error) {
184 return FileContainsAnyBytes(a.Fs, filename, subslices)
185 }
186
187
188 func FileContainsAnyBytes(fs Fs, filename string, subslices [][]byte) (bool, error) {
189 f, err := fs.Open(filename)
190 if err != nil {
191 return false, err
192 }
193 defer f.Close()
194
195 return readerContainsAny(f, subslices...), nil
196 }
197
198
199 func readerContainsAny(r io.Reader, subslices ...[]byte) bool {
200 if r == nil || len(subslices) == 0 {
201 return false
202 }
203
204 largestSlice := 0
205
206 for _, sl := range subslices {
207 if len(sl) > largestSlice {
208 largestSlice = len(sl)
209 }
210 }
211
212 if largestSlice == 0 {
213 return false
214 }
215
216 bufflen := largestSlice * 4
217 halflen := bufflen / 2
218 buff := make([]byte, bufflen)
219 var err error
220 var n, i int
221
222 for {
223 i++
224 if i == 1 {
225 n, err = io.ReadAtLeast(r, buff[:halflen], halflen)
226 } else {
227 if i != 2 {
228
229 copy(buff[:], buff[halflen:])
230 }
231 n, err = io.ReadAtLeast(r, buff[halflen:], halflen)
232 }
233
234 if n > 0 {
235 for _, sl := range subslices {
236 if bytes.Contains(buff, sl) {
237 return true
238 }
239 }
240 }
241
242 if err != nil {
243 break
244 }
245 }
246 return false
247 }
248
249 func (a Afero) DirExists(path string) (bool, error) {
250 return DirExists(a.Fs, path)
251 }
252
253
254 func DirExists(fs Fs, path string) (bool, error) {
255 fi, err := fs.Stat(path)
256 if err == nil && fi.IsDir() {
257 return true, nil
258 }
259 if os.IsNotExist(err) {
260 return false, nil
261 }
262 return false, err
263 }
264
265 func (a Afero) IsDir(path string) (bool, error) {
266 return IsDir(a.Fs, path)
267 }
268
269
270 func IsDir(fs Fs, path string) (bool, error) {
271 fi, err := fs.Stat(path)
272 if err != nil {
273 return false, err
274 }
275 return fi.IsDir(), nil
276 }
277
278 func (a Afero) IsEmpty(path string) (bool, error) {
279 return IsEmpty(a.Fs, path)
280 }
281
282
283 func IsEmpty(fs Fs, path string) (bool, error) {
284 if b, _ := Exists(fs, path); !b {
285 return false, fmt.Errorf("%q path does not exist", path)
286 }
287 fi, err := fs.Stat(path)
288 if err != nil {
289 return false, err
290 }
291 if fi.IsDir() {
292 f, err := fs.Open(path)
293 if err != nil {
294 return false, err
295 }
296 defer f.Close()
297 list, err := f.Readdir(-1)
298 if err != nil {
299 return false, err
300 }
301 return len(list) == 0, nil
302 }
303 return fi.Size() == 0, nil
304 }
305
306 func (a Afero) Exists(path string) (bool, error) {
307 return Exists(a.Fs, path)
308 }
309
310
311 func Exists(fs Fs, path string) (bool, error) {
312 _, err := fs.Stat(path)
313 if err == nil {
314 return true, nil
315 }
316 if os.IsNotExist(err) {
317 return false, nil
318 }
319 return false, err
320 }
321
322 func FullBaseFsPath(basePathFs *BasePathFs, relativePath string) string {
323 combinedPath := filepath.Join(basePathFs.path, relativePath)
324 if parent, ok := basePathFs.source.(*BasePathFs); ok {
325 return FullBaseFsPath(parent, combinedPath)
326 }
327
328 return combinedPath
329 }
330
View as plain text