]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/spf13/afero/util.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / 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 }