util.go - afero - [fork] go afero port for 9front
 (HTM) git clone https://git.drkhsh.at/afero.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) 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 }