gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

util.go (7335B)


      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/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.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 // 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 }