main
1package util
2
3import (
4 "os"
5 "path/filepath"
6
7 "github.com/go-git/go-billy/v5"
8)
9
10// walk recursively descends path, calling walkFn
11// adapted from https://golang.org/src/path/filepath/path.go
12func walk(fs billy.Filesystem, path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
13 if !info.IsDir() {
14 return walkFn(path, info, nil)
15 }
16
17 names, err := readdirnames(fs, path)
18 err1 := walkFn(path, info, err)
19 // If err != nil, walk can't walk into this directory.
20 // err1 != nil means walkFn want walk to skip this directory or stop walking.
21 // Therefore, if one of err and err1 isn't nil, walk will return.
22 if err != nil || err1 != nil {
23 // The caller's behavior is controlled by the return value, which is decided
24 // by walkFn. walkFn may ignore err and return nil.
25 // If walkFn returns SkipDir, it will be handled by the caller.
26 // So walk should return whatever walkFn returns.
27 return err1
28 }
29
30 for _, name := range names {
31 filename := filepath.Join(path, name)
32 fileInfo, err := fs.Lstat(filename)
33 if err != nil {
34 if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
35 return err
36 }
37 } else {
38 err = walk(fs, filename, fileInfo, walkFn)
39 if err != nil {
40 if !fileInfo.IsDir() || err != filepath.SkipDir {
41 return err
42 }
43 }
44 }
45 }
46 return nil
47}
48
49// Walk walks the file tree rooted at root, calling fn for each file or
50// directory in the tree, including root. All errors that arise visiting files
51// and directories are filtered by fn: see the WalkFunc documentation for
52// details.
53//
54// The files are walked in lexical order, which makes the output deterministic
55// but requires Walk to read an entire directory into memory before proceeding
56// to walk that directory. Walk does not follow symbolic links.
57//
58// Function adapted from https://github.com/golang/go/blob/3b770f2ccb1fa6fecc22ea822a19447b10b70c5c/src/path/filepath/path.go#L500
59func Walk(fs billy.Filesystem, root string, walkFn filepath.WalkFunc) error {
60 info, err := fs.Lstat(root)
61 if err != nil {
62 err = walkFn(root, nil, err)
63 } else {
64 err = walk(fs, root, info, walkFn)
65 }
66
67 if err == filepath.SkipDir {
68 return nil
69 }
70
71 return err
72}