github.com/haraldrudell/parl@v0.4.176/pfs/dir-iterator.go (about) 1 /* 2 © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package pfs 7 8 import ( 9 "github.com/haraldrudell/parl" 10 "github.com/haraldrudell/parl/iters" 11 ) 12 13 // DirIterator traverses file-system directories 14 type DirIterator struct { 15 // traverser is the file-system traverser. 16 // Only method is [Traverser.Next] 17 traverser Traverser 18 // BaseIterator provides iterator methods: 19 // [iters.Iterator.Cancel] [iters.Iterator.Cond] [iters.Iterator.Next] 20 iters.BaseIterator[ResultEntry] 21 } 22 23 // NewIterator returns an iterator for a file-system entry and any child entries if directory 24 // - path is the initial path for the file-system walk. 25 // it may be relative or absolute, contain symlinks and 26 // point to a file, directory or special file 27 // - only directories are returned. 28 // if directories are not skipped, they descended into. 29 // - symlinks are followed. 30 // Broken symlinks are ignored. 31 // - any errored file-system entry cancels the iterator with error. 32 func NewDirIterator(path string) (iterator iters.Iterator[ResultEntry]) { 33 i := DirIterator{traverser: *NewTraverser(path)} 34 i.BaseIterator = *iters.NewBaseIterator(i.iteratorAction) 35 return &i 36 } 37 38 // Init implements the right-hand side of a short variable declaration in 39 // the init statement of a Go “for” clause 40 // 41 // for i, iterator := iters.NewSlicePointerIterator(someSlice).Init(); iterator.Cond(&i); { 42 // // i is pointer to slice element 43 func (i *DirIterator) Init() (result ResultEntry, iterator iters.Iterator[ResultEntry]) { 44 iterator = i 45 return 46 } 47 48 // iteratorAction provides items to the BaseIterator 49 func (t *DirIterator) iteratorAction(isCancel bool) (result ResultEntry, err error) { 50 if isCancel { 51 return 52 } 53 for { 54 result = t.traverser.Next() 55 56 // handle end 57 if result.IsEnd() { 58 err = parl.ErrEndCallbacks 59 return 60 } 61 62 // ignore broken symlink 63 if result.Reason == RSymlinkBad { 64 continue 65 } 66 67 // any other error cancels iterator 68 if result.Err != nil { 69 err = result.Err 70 return 71 } 72 73 // - ignore any file-system entry that is not 74 // a directory 75 if !result.IsDir() { 76 continue 77 } 78 79 return // directory return 80 } 81 }