Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / github.com / spf13 / afero / util.go
1 // Copyright ©2015 Steve Francia <spf@spf13.com>
2 // Portions Copyright ©2015 The Hugo Authors
3 // Portions Copyright 2016-present Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
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/transform"
29         "golang.org/x/text/unicode/norm"
30 )
31
32 // Filepath separator defined by os.Separator.
33 const FilePathSeparator = string(filepath.Separator)
34
35 // Takes a reader and a path and writes the content
36 func (a Afero) WriteReader(path string, r io.Reader) (err error) {
37         return WriteReader(a.Fs, path, r)
38 }
39
40 func WriteReader(fs Fs, path string, r io.Reader) (err error) {
41         dir, _ := filepath.Split(path)
42         ospath := filepath.FromSlash(dir)
43
44         if ospath != "" {
45                 err = fs.MkdirAll(ospath, 0777) // rwx, rw, r
46                 if err != nil {
47                         if err != os.ErrExist {
48                                 return err
49                         }
50                 }
51         }
52
53         file, err := fs.Create(path)
54         if err != nil {
55                 return
56         }
57         defer file.Close()
58
59         _, err = io.Copy(file, r)
60         return
61 }
62
63 // Same as WriteReader but checks to see if file/directory already exists.
64 func (a Afero) SafeWriteReader(path string, r io.Reader) (err error) {
65         return SafeWriteReader(a.Fs, path, r)
66 }
67
68 func SafeWriteReader(fs Fs, path string, r io.Reader) (err error) {
69         dir, _ := filepath.Split(path)
70         ospath := filepath.FromSlash(dir)
71
72         if ospath != "" {
73                 err = fs.MkdirAll(ospath, 0777) // rwx, rw, r
74                 if err != nil {
75                         return
76                 }
77         }
78
79         exists, err := Exists(fs, path)
80         if err != nil {
81                 return
82         }
83         if exists {
84                 return fmt.Errorf("%v already exists", path)
85         }
86
87         file, err := fs.Create(path)
88         if err != nil {
89                 return
90         }
91         defer file.Close()
92
93         _, err = io.Copy(file, r)
94         return
95 }
96
97 func (a Afero) GetTempDir(subPath string) string {
98         return GetTempDir(a.Fs, subPath)
99 }
100
101 // GetTempDir returns the default temp directory with trailing slash
102 // if subPath is not empty then it will be created recursively with mode 777 rwx rwx rwx
103 func GetTempDir(fs Fs, subPath string) string {
104         addSlash := func(p string) string {
105                 if FilePathSeparator != p[len(p)-1:] {
106                         p = p + FilePathSeparator
107                 }
108                 return p
109         }
110         dir := addSlash(os.TempDir())
111
112         if subPath != "" {
113                 // preserve windows backslash :-(
114                 if FilePathSeparator == "\\" {
115                         subPath = strings.Replace(subPath, "\\", "____", -1)
116                 }
117                 dir = dir + UnicodeSanitize((subPath))
118                 if FilePathSeparator == "\\" {
119                         dir = strings.Replace(dir, "____", "\\", -1)
120                 }
121
122                 if exists, _ := Exists(fs, dir); exists {
123                         return addSlash(dir)
124                 }
125
126                 err := fs.MkdirAll(dir, 0777)
127                 if err != nil {
128                         panic(err)
129                 }
130                 dir = addSlash(dir)
131         }
132         return dir
133 }
134
135 // Rewrite string to remove non-standard path characters
136 func UnicodeSanitize(s string) string {
137         source := []rune(s)
138         target := make([]rune, 0, len(source))
139
140         for _, r := range source {
141                 if unicode.IsLetter(r) ||
142                         unicode.IsDigit(r) ||
143                         unicode.IsMark(r) ||
144                         r == '.' ||
145                         r == '/' ||
146                         r == '\\' ||
147                         r == '_' ||
148                         r == '-' ||
149                         r == '%' ||
150                         r == ' ' ||
151                         r == '#' {
152                         target = append(target, r)
153                 }
154         }
155
156         return string(target)
157 }
158
159 // Transform characters with accents into plain forms.
160 func NeuterAccents(s string) string {
161         t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
162         result, _, _ := transform.String(t, string(s))
163
164         return result
165 }
166
167 func isMn(r rune) bool {
168         return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
169 }
170
171 func (a Afero) FileContainsBytes(filename string, subslice []byte) (bool, error) {
172         return FileContainsBytes(a.Fs, filename, subslice)
173 }
174
175 // Check if a file contains a specified byte slice.
176 func FileContainsBytes(fs Fs, filename string, subslice []byte) (bool, error) {
177         f, err := fs.Open(filename)
178         if err != nil {
179                 return false, err
180         }
181         defer f.Close()
182
183         return readerContainsAny(f, subslice), nil
184 }
185
186 func (a Afero) FileContainsAnyBytes(filename string, subslices [][]byte) (bool, error) {
187         return FileContainsAnyBytes(a.Fs, filename, subslices)
188 }
189
190 // Check if a file contains any of the specified byte slices.
191 func FileContainsAnyBytes(fs Fs, filename string, subslices [][]byte) (bool, error) {
192         f, err := fs.Open(filename)
193         if err != nil {
194                 return false, err
195         }
196         defer f.Close()
197
198         return readerContainsAny(f, subslices...), nil
199 }
200
201 // readerContains reports whether any of the subslices is within r.
202 func readerContainsAny(r io.Reader, subslices ...[]byte) bool {
203
204         if r == nil || len(subslices) == 0 {
205                 return false
206         }
207
208         largestSlice := 0
209
210         for _, sl := range subslices {
211                 if len(sl) > largestSlice {
212                         largestSlice = len(sl)
213                 }
214         }
215
216         if largestSlice == 0 {
217                 return false
218         }
219
220         bufflen := largestSlice * 4
221         halflen := bufflen / 2
222         buff := make([]byte, bufflen)
223         var err error
224         var n, i int
225
226         for {
227                 i++
228                 if i == 1 {
229                         n, err = io.ReadAtLeast(r, buff[:halflen], halflen)
230                 } else {
231                         if i != 2 {
232                                 // shift left to catch overlapping matches
233                                 copy(buff[:], buff[halflen:])
234                         }
235                         n, err = io.ReadAtLeast(r, buff[halflen:], halflen)
236                 }
237
238                 if n > 0 {
239                         for _, sl := range subslices {
240                                 if bytes.Contains(buff, sl) {
241                                         return true
242                                 }
243                         }
244                 }
245
246                 if err != nil {
247                         break
248                 }
249         }
250         return false
251 }
252
253 func (a Afero) DirExists(path string) (bool, error) {
254         return DirExists(a.Fs, path)
255 }
256
257 // DirExists checks if a path exists and is a directory.
258 func DirExists(fs Fs, path string) (bool, error) {
259         fi, err := fs.Stat(path)
260         if err == nil && fi.IsDir() {
261                 return true, nil
262         }
263         if os.IsNotExist(err) {
264                 return false, nil
265         }
266         return false, err
267 }
268
269 func (a Afero) IsDir(path string) (bool, error) {
270         return IsDir(a.Fs, path)
271 }
272
273 // IsDir checks if a given path is a directory.
274 func IsDir(fs Fs, path string) (bool, error) {
275         fi, err := fs.Stat(path)
276         if err != nil {
277                 return false, err
278         }
279         return fi.IsDir(), nil
280 }
281
282 func (a Afero) IsEmpty(path string) (bool, error) {
283         return IsEmpty(a.Fs, path)
284 }
285
286 // IsEmpty checks if a given file or directory is empty.
287 func IsEmpty(fs Fs, path string) (bool, error) {
288         if b, _ := Exists(fs, path); !b {
289                 return false, fmt.Errorf("%q path does not exist", path)
290         }
291         fi, err := fs.Stat(path)
292         if err != nil {
293                 return false, err
294         }
295         if fi.IsDir() {
296                 f, err := fs.Open(path)
297                 if err != nil {
298                         return false, err
299                 }
300                 defer f.Close()
301                 list, err := f.Readdir(-1)
302                 return len(list) == 0, nil
303         }
304         return fi.Size() == 0, nil
305 }
306
307 func (a Afero) Exists(path string) (bool, error) {
308         return Exists(a.Fs, path)
309 }
310
311 // Check if a file or directory exists.
312 func Exists(fs Fs, path string) (bool, error) {
313         _, err := fs.Stat(path)
314         if err == nil {
315                 return true, nil
316         }
317         if os.IsNotExist(err) {
318                 return false, nil
319         }
320         return false, err
321 }
322
323 func FullBaseFsPath(basePathFs *BasePathFs, relativePath string) string {
324         combinedPath := filepath.Join(basePathFs.path, relativePath)
325         if parent, ok := basePathFs.source.(*BasePathFs); ok {
326                 return FullBaseFsPath(parent, combinedPath)
327         }
328
329         return combinedPath
330 }