Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/github.com/spf13/afero/util.go
2875 views
1
// Copyright ©2015 Steve Francia <[email protected]>
2
// Portions Copyright ©2015 The Hugo Authors
3
// Portions Copyright 2016-present Bjørn Erik Pedersen <[email protected]>
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/runes"
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, 0o777) // rwx, rw, r
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
// 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, 0o777) // 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.ReplaceAll(subPath, "\\", "____")
117
}
118
dir = dir + UnicodeSanitize((subPath))
119
if FilePathSeparator == "\\" {
120
dir = strings.ReplaceAll(dir, "____", "\\")
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
// 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, 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
// Check if a file contains a specified byte slice.
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
// Check if a file contains any of the specified byte slices.
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
// readerContains reports whether any of the subslices is within r.
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
// shift left to catch overlapping matches
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
// DirExists checks if a path exists and is a directory.
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
// IsDir checks if a given path is a directory.
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
// IsEmpty checks if a given file or directory is empty.
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
// Check if a file or directory exists.
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
331