OSDN Git Service

Hulk did something
[bytom/vapor.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         "log"
24         "os"
25         "path/filepath"
26         "strings"
27         "unicode"
28
29         "golang.org/x/text/transform"
30         "golang.org/x/text/unicode/norm"
31 )
32
33 // Filepath separator defined by os.Separator.
34 const FilePathSeparator = string(filepath.Separator)
35
36 // Takes a reader and a path and writes the content
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, 0777) // rwx, rw, r
47                 if err != nil {
48                         if err != os.ErrExist {
49                                 log.Panicln(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 // Same as WriteReader but checks to see if file/directory already exists.
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, 0777) // rwx, rw, r
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 // GetTempDir returns the default temp directory with trailing slash
103 // if subPath is not empty then it will be created recursively with mode 777 rwx rwx rwx
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                 // preserve windows backslash :-(
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, 0777)
128                 if err != nil {
129                         panic(err)
130                 }
131                 dir = addSlash(dir)
132         }
133         return dir
134 }
135
136 // Rewrite string to remove non-standard path characters
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 // Transform characters with accents into plain forms.
161 func NeuterAccents(s string) string {
162         t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
163         result, _, _ := transform.String(t, string(s))
164
165         return result
166 }
167
168 func isMn(r rune) bool {
169         return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
170 }
171
172 func (a Afero) FileContainsBytes(filename string, subslice []byte) (bool, error) {
173         return FileContainsBytes(a.Fs, filename, subslice)
174 }
175
176 // Check if a file contains a specified byte slice.
177 func FileContainsBytes(fs Fs, filename string, subslice []byte) (bool, error) {
178         f, err := fs.Open(filename)
179         if err != nil {
180                 return false, err
181         }
182         defer f.Close()
183
184         return readerContainsAny(f, subslice), nil
185 }
186
187 func (a Afero) FileContainsAnyBytes(filename string, subslices [][]byte) (bool, error) {
188         return FileContainsAnyBytes(a.Fs, filename, subslices)
189 }
190
191 // Check if a file contains any of the specified byte slices.
192 func FileContainsAnyBytes(fs Fs, filename string, subslices [][]byte) (bool, error) {
193         f, err := fs.Open(filename)
194         if err != nil {
195                 return false, err
196         }
197         defer f.Close()
198
199         return readerContainsAny(f, subslices...), nil
200 }
201
202 // readerContains reports whether any of the subslices is within r.
203 func readerContainsAny(r io.Reader, subslices ...[]byte) bool {
204
205         if r == nil || len(subslices) == 0 {
206                 return false
207         }
208
209         largestSlice := 0
210
211         for _, sl := range subslices {
212                 if len(sl) > largestSlice {
213                         largestSlice = len(sl)
214                 }
215         }
216
217         if largestSlice == 0 {
218                 return false
219         }
220
221         bufflen := largestSlice * 4
222         halflen := bufflen / 2
223         buff := make([]byte, bufflen)
224         var err error
225         var n, i int
226
227         for {
228                 i++
229                 if i == 1 {
230                         n, err = io.ReadAtLeast(r, buff[:halflen], halflen)
231                 } else {
232                         if i != 2 {
233                                 // shift left to catch overlapping matches
234                                 copy(buff[:], buff[halflen:])
235                         }
236                         n, err = io.ReadAtLeast(r, buff[halflen:], halflen)
237                 }
238
239                 if n > 0 {
240                         for _, sl := range subslices {
241                                 if bytes.Contains(buff, sl) {
242                                         return true
243                                 }
244                         }
245                 }
246
247                 if err != nil {
248                         break
249                 }
250         }
251         return false
252 }
253
254 func (a Afero) DirExists(path string) (bool, error) {
255         return DirExists(a.Fs, path)
256 }
257
258 // DirExists checks if a path exists and is a directory.
259 func DirExists(fs Fs, path string) (bool, error) {
260         fi, err := fs.Stat(path)
261         if err == nil && fi.IsDir() {
262                 return true, nil
263         }
264         if os.IsNotExist(err) {
265                 return false, nil
266         }
267         return false, err
268 }
269
270 func (a Afero) IsDir(path string) (bool, error) {
271         return IsDir(a.Fs, path)
272 }
273
274 // IsDir checks if a given path is a directory.
275 func IsDir(fs Fs, path string) (bool, error) {
276         fi, err := fs.Stat(path)
277         if err != nil {
278                 return false, err
279         }
280         return fi.IsDir(), nil
281 }
282
283 func (a Afero) IsEmpty(path string) (bool, error) {
284         return IsEmpty(a.Fs, path)
285 }
286
287 // IsEmpty checks if a given file or directory is empty.
288 func IsEmpty(fs Fs, path string) (bool, error) {
289         if b, _ := Exists(fs, path); !b {
290                 return false, fmt.Errorf("%q path does not exist", path)
291         }
292         fi, err := fs.Stat(path)
293         if err != nil {
294                 return false, err
295         }
296         if fi.IsDir() {
297                 f, err := fs.Open(path)
298                 if err != nil {
299                         return false, err
300                 }
301                 defer f.Close()
302                 list, err := f.Readdir(-1)
303                 return len(list) == 0, nil
304         }
305         return fi.Size() == 0, nil
306 }
307
308 func (a Afero) Exists(path string) (bool, error) {
309         return Exists(a.Fs, path)
310 }
311
312 // Check if a file or directory exists.
313 func Exists(fs Fs, path string) (bool, error) {
314         _, err := fs.Stat(path)
315         if err == nil {
316                 return true, nil
317         }
318         if os.IsNotExist(err) {
319                 return false, nil
320         }
321         return false, err
322 }
323
324 func FullBaseFsPath(basePathFs *BasePathFs, relativePath string) string {
325         combinedPath := filepath.Join(basePathFs.path, relativePath)
326         if parent, ok := basePathFs.source.(*BasePathFs); ok {
327                 return FullBaseFsPath(parent, combinedPath)
328         }
329
330         return combinedPath
331 }