internal/gitaly/storage/walk_directory.go (47 lines of code) (raw):

package storage import ( "fmt" "io/fs" "os" "path/filepath" ) // walkCallback is a callback that that is invoked for each directory entry. type walkCallbackFunc func(path string, dirEntry fs.DirEntry) error // dirEntryFileInfo is an adapter that converts an `fs.FileMode` to conform // to the `fs.DirEntry` interface. type dirEntryFileInfo struct{ fs.FileInfo } func (d dirEntryFileInfo) Info() (fs.FileInfo, error) { return d.FileInfo, nil } func (d dirEntryFileInfo) Type() fs.FileMode { return d.FileInfo.Mode().Type() } // walkDirectory recursively walks a directory at a given and invokes callback for each directory // entry encountered. beforeChildren is invoked on directories before descending into their children. afterChildren // is invoked on directories after having walked all their children. onFile is invoked immediately on encountering a // file. func walkDirectory(storageRoot, relativePath string, beforeChildren, onFile, afterChildren walkCallbackFunc) error { info, err := os.Stat(filepath.Join(storageRoot, relativePath)) if err != nil { return fmt.Errorf("stat start point: %w", err) } return walkDirectoryRecursive(storageRoot, relativePath, dirEntryFileInfo{info}, beforeChildren, onFile, afterChildren) } func walkDirectoryRecursive(storageRoot, relativePath string, dirEntry fs.DirEntry, beforeChildren, onFile, afterChildren walkCallbackFunc) error { dirEntries, err := os.ReadDir(filepath.Join(storageRoot, relativePath)) if err != nil { return fmt.Errorf("read dir: %w", err) } if err := beforeChildren(relativePath, dirEntry); err != nil { return fmt.Errorf("before children: %w", err) } for _, childEntry := range dirEntries { childRelativePath := filepath.Join(relativePath, childEntry.Name()) if childEntry.IsDir() { if err := walkDirectory(storageRoot, childRelativePath, beforeChildren, onFile, afterChildren); err != nil { return fmt.Errorf("walk directory: %w", err) } continue } if err := onFile(childRelativePath, childEntry); err != nil { return fmt.Errorf("on file: %w", err) } } if err := afterChildren(relativePath, dirEntry); err != nil { return fmt.Errorf("after children: %w", err) } return nil }