github.com/coveo/gotemplate@v2.7.7+incompatible/utils/io.go (about)

     1  package utils
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"strings"
     7  
     8  	"github.com/coveo/gotemplate/collections"
     9  	"github.com/coveo/gotemplate/errors"
    10  )
    11  
    12  var must = errors.Must
    13  
    14  // FindFiles returns the list of the files matching the array of patterns
    15  func FindFiles(folder string, recursive, followLinks bool, patterns ...string) ([]string, error) {
    16  	depth := 0
    17  	if recursive {
    18  		depth = 1 << 16
    19  	}
    20  	return FindFilesMaxDepth(folder, depth, followLinks, patterns...)
    21  }
    22  
    23  // FindFilesMaxDepth returns the list of the files matching the array of patterns
    24  func FindFilesMaxDepth(folder string, maxDepth int, followLinks bool, patterns ...string) ([]string, error) {
    25  	visited := map[string]bool{}
    26  	var walker func(folder string) ([]string, error)
    27  	walker = func(folder string) ([]string, error) {
    28  		results := must(findFiles(folder, patterns...)).([]string)
    29  		folder, _ = filepath.Abs(folder)
    30  		if maxDepth == 0 {
    31  			return results, nil
    32  		}
    33  
    34  		filepath.Walk(folder, func(path string, info os.FileInfo, err error) error {
    35  			if info == nil || path == folder {
    36  				return nil
    37  			}
    38  			if info.IsDir() {
    39  				visited[path] = true
    40  				depth := strings.Count(must(filepath.Rel(path, folder)).(string), "..")
    41  				if depth > maxDepth {
    42  					return filepath.SkipDir
    43  				}
    44  				files, err := findFiles(path, patterns...)
    45  				if err != nil {
    46  					return err
    47  				}
    48  				results = append(results, files...)
    49  				return nil
    50  			}
    51  
    52  			if info.Mode()&os.ModeSymlink != 0 && followLinks {
    53  				link, err := os.Readlink(path)
    54  				if err != nil {
    55  					return err
    56  				}
    57  
    58  				if !filepath.IsAbs(link) {
    59  					link = filepath.Join(filepath.Dir(path), link)
    60  				}
    61  				link, _ = filepath.Abs(link)
    62  				if !visited[link] {
    63  					// Check if we already visited that link to avoid recursive loop
    64  					linkFiles, err := walker(link)
    65  					if err != nil {
    66  						return err
    67  					}
    68  					results = append(results, linkFiles...)
    69  				}
    70  			}
    71  			return nil
    72  		})
    73  		return results, nil
    74  	}
    75  	return walker(folder)
    76  }
    77  
    78  // FindFiles returns the list of files in the specified folder that match one of the supplied patterns
    79  func findFiles(folder string, patterns ...string) ([]string, error) {
    80  	var matches []string
    81  	for _, pattern := range patterns {
    82  		files, err := filepath.Glob(filepath.Join(folder, pattern))
    83  		if err != nil {
    84  			return nil, err
    85  		}
    86  		matches = append(matches, files...)
    87  	}
    88  	return matches, nil
    89  }
    90  
    91  // MustFindFiles returns the list of the files matching the array of patterns with panic on error
    92  func MustFindFiles(folder string, recursive, followLinks bool, patterns ...string) []string {
    93  	return must(FindFiles(folder, recursive, followLinks, patterns...)).([]string)
    94  }
    95  
    96  // MustFindFilesMaxDepth returns the list of the files matching the array of patterns with panic on error
    97  func MustFindFilesMaxDepth(folder string, maxDepth int, followLinks bool, patterns ...string) []string {
    98  	return must(FindFilesMaxDepth(folder, maxDepth, followLinks, patterns...)).([]string)
    99  }
   100  
   101  func globFunc(trimUnmatch bool, args ...interface{}) (result []string) {
   102  	for _, arg := range collections.ToStrings(args) {
   103  		if strings.ContainsAny(arg, "*?[]") {
   104  			if expanded, _ := filepath.Glob(arg); expanded != nil {
   105  				result = append(result, expanded...)
   106  				continue
   107  			}
   108  			if trimUnmatch {
   109  				continue
   110  			}
   111  		}
   112  		result = append(result, arg)
   113  	}
   114  	return
   115  }
   116  
   117  // GlobFunc returns an array of string representing the expansion of the supplied arguments using filepath.Glob function
   118  func GlobFunc(args ...interface{}) []string { return globFunc(false, args...) }
   119  
   120  // GlobFuncTrim returns an array of string representing the expansion of the supplied arguments using filepath.Glob function, it removes the unmatched arguments
   121  func GlobFuncTrim(args ...interface{}) []string { return globFunc(true, args...) }
   122  
   123  // Pwd returns the current folder
   124  func Pwd() string {
   125  	return must(os.Getwd()).(string)
   126  }
   127  
   128  // Relative returns the relative path of file from folder
   129  func Relative(folder, file string) string {
   130  	if !filepath.IsAbs(file) {
   131  		return file
   132  	}
   133  	return must(filepath.Rel(folder, file)).(string)
   134  }