...

Source file src/github.com/spf13/afero/util.go

Documentation: github.com/spf13/afero

     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  }
   330  

View as plain text