File: walk.go

package info (click to toggle)
golang-github-twpayne-go-vfs 4.1.0-1.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 212 kB
  • sloc: makefile: 30
file content (75 lines) | stat: -rw-r--r-- 2,074 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package vfs

//nolint:godox
// FIXME implement path/filepath.WalkDir

import (
	"errors"
	"io/fs"
	"path/filepath"
	"sort"
)

// SkipDir is fs.SkipDir.
//nolint:gochecknoglobals
var SkipDir = fs.SkipDir

// A LstatReadDirer implements all the functionality needed by Walk.
type LstatReadDirer interface {
	Lstat(name string) (fs.FileInfo, error)
	ReadDir(name string) ([]fs.DirEntry, error)
}

type dirEntriesByName []fs.DirEntry

func (is dirEntriesByName) Len() int           { return len(is) }
func (is dirEntriesByName) Less(i, j int) bool { return is[i].Name() < is[j].Name() }
func (is dirEntriesByName) Swap(i, j int)      { is[i], is[j] = is[j], is[i] }

// walk recursively walks fileSystem from path.
func walk(fileSystem LstatReadDirer, path string, walkFn filepath.WalkFunc, info fs.FileInfo, err error) error {
	if err != nil {
		return walkFn(path, info, err)
	}
	err = walkFn(path, info, nil)
	if !info.IsDir() {
		return err
	}
	if errors.Is(err, fs.SkipDir) {
		return nil
	}
	dirEntries, err := fileSystem.ReadDir(path)
	if err != nil {
		return err
	}
	sort.Sort(dirEntriesByName(dirEntries))
	for _, dirEntry := range dirEntries {
		name := dirEntry.Name()
		if name == "." || name == ".." {
			continue
		}
		info, err := dirEntry.Info()
		if err != nil {
			return err
		}
		if err := walk(fileSystem, filepath.Join(path, dirEntry.Name()), walkFn, info, nil); err != nil {
			return err
		}
	}
	return nil
}

// Walk is the equivalent of filepath.Walk but operates on fileSystem. Entries
// are returned in lexicographical order.
func Walk(fileSystem LstatReadDirer, path string, walkFn filepath.WalkFunc) error {
	info, err := fileSystem.Lstat(path)
	return walk(fileSystem, path, walkFn, info, err)
}

// WalkSlash is the equivalent of Walk but all paths are converted to use
// forward slashes with filepath.ToSlash.
func WalkSlash(fileSystem LstatReadDirer, path string, walkFn filepath.WalkFunc) error {
	return Walk(fileSystem, path, func(path string, info fs.FileInfo, err error) error {
		return walkFn(filepath.ToSlash(path), info, err)
	})
}