github.com/cobalt77/jfrog-client-go@v0.14.5/utils/io/fileutils/listfiles.go (about)

     1  package fileutils
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"path/filepath"
     7  	"sort"
     8  )
     9  
    10  var SkipDir = errors.New("skip this directory")
    11  
    12  type WalkFunc func(path string, info os.FileInfo, err error) error
    13  type Stat func(path string) (info os.FileInfo, err error)
    14  
    15  var stat = os.Stat
    16  var lStat = os.Lstat
    17  
    18  func walk(path string, info os.FileInfo, walkFn WalkFunc, visited map[string]bool, walkIntoDirSymlink bool) error {
    19  	realPath, err := filepath.EvalSymlinks(path)
    20  	if err != nil {
    21  		realPath = path
    22  	}
    23  	isRealPathDir, err := IsDirExists(realPath, false)
    24  	if err != nil {
    25  		return err
    26  	}
    27  	if isRealPathDir {
    28  		visited[realPath] = true
    29  	}
    30  	err = walkFn(path, info, nil)
    31  	if err != nil {
    32  		if info.IsDir() && err == SkipDir {
    33  			return nil
    34  		}
    35  		return err
    36  	}
    37  
    38  	if !info.IsDir() {
    39  		return nil
    40  	}
    41  
    42  	names, err := readDirNames(path)
    43  	if err != nil {
    44  		return walkFn(path, info, err)
    45  	}
    46  
    47  	for _, name := range names {
    48  		filename := filepath.Join(path, name)
    49  		realPath, err = filepath.EvalSymlinks(filename)
    50  		if err != nil {
    51  			realPath = filename
    52  		}
    53  
    54  		if walkIntoDirSymlink && visited[realPath] {
    55  			continue
    56  		}
    57  		var fileHandler Stat
    58  		if walkIntoDirSymlink {
    59  			fileHandler = stat
    60  		} else {
    61  			fileHandler = lStat
    62  		}
    63  		fileInfo, err := fileHandler(filename)
    64  		if err != nil {
    65  			if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir {
    66  				return err
    67  			}
    68  		} else {
    69  			err = walk(filename, fileInfo, walkFn, visited, walkIntoDirSymlink)
    70  			if err != nil {
    71  				if !fileInfo.IsDir() || err != SkipDir {
    72  					return err
    73  				}
    74  			}
    75  		}
    76  	}
    77  	return nil
    78  }
    79  
    80  // The same as filepath.Walk the only difference is that we can walk into symlink.
    81  // Avoiding infinite loops by saving the real paths we already visited.
    82  func Walk(root string, walkFn WalkFunc, walkIntoDirSymlink bool) error {
    83  	info, err := stat(root)
    84  	visited := make(map[string]bool)
    85  	if err != nil {
    86  		return walkFn(root, nil, err)
    87  	}
    88  	return walk(root, info, walkFn, visited, walkIntoDirSymlink)
    89  }
    90  
    91  // readDirNames reads the directory named by dirname and returns
    92  // a sorted list of directory entries.
    93  // The same as path/filepath readDirNames function
    94  func readDirNames(dirname string) ([]string, error) {
    95  	f, err := os.Open(dirname)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	names, err := f.Readdirnames(-1)
   100  	f.Close()
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	sort.Strings(names)
   105  	return names, nil
   106  }