--- a/Filename.st Wed May 29 11:33:14 2019 +0200
+++ b/Filename.st Wed May 29 11:33:34 2019 +0200
@@ -2883,6 +2883,138 @@
"Modified: / 06-02-2019 / 11:45:22 / Stefan Vogel"
!
+recursiveFilesDo:fileBlock directoriesDo:dirBlock filterForVisitingDirectories:filterOrNil
+ "evaluate aBlock for all files and directories found under the receiver.
+ The blocks are invoked with a relative pathname as string-argument.
+ The walk is depth-first (but files first, then directories).
+ This excludes any entries for '.' or '..'.
+ A proceedable exception is raised for non-accessible directories.
+ If filterOrNil is nonNil, it is passed every directory about to be walked into;
+ if it returns false, that directory is not entered.
+ Warning: this may take a long time to execute
+ (especially with deep and/or remote fileSystems).
+ Names are enumerated in the order they appear in the folder,
+ (which is not required to be sorted).
+ "
+
+ self
+ recursiveFilesDo:fileBlock directoriesDo:dirBlock
+ filterForVisitingDirectories:filterOrNil sortedBy:nil
+
+ "
+ '.' asFilename
+ recursiveFilesDo:[:f | Transcript show:'file: '; showCR:f]
+ directoriesDo:[:f | Transcript show:'dir: '; showCR:f]
+ filterForVisitingDirectories:nil
+ "
+
+ "Created: / 29-05-2019 / 09:58:12 / Claus Gittinger"
+ "Modified (comment): / 29-05-2019 / 11:24:57 / Claus Gittinger"
+!
+
+recursiveFilesDo:fileBlock directoriesDo:dirBlock filterForVisitingDirectories:filterOrNil sortedBy:sortedByBlock
+ "evaluate aBlock for all files and directories found under the receiver.
+ The blocks are invoked with a relative pathname as string-argument.
+ The walk is breadth-first (files first, then directories).
+ This excludes any entries for '.' or '..'.
+ A proceedable exception is raised for non-accessible directories.
+ If filterOrNil is nonNil, it is passed every directory about to be walked into;
+ if it returns false, that directory is not entered.
+ Warning: this may take a long time to execute
+ (especially with deep and/or remote fileSystems).
+ By default, names are enumerated in the order they appear in the folder,
+ (which is not required to be sorted).
+ If sortedByBlock is non nil, it is applied with the file names to sort them
+ (usually a block is provided to sort by name, aka [:a :b | a name < b name]
+ or by caseless name, like [:a :b | a name caselessBefore: b name]
+ "
+
+ |getFilesAndDirs toDo fileNames dirNames job thisDir|
+
+ toDo := OrderedCollection new.
+
+ getFilesAndDirs :=
+ [:aRoot |
+ |contents fileNames dirNames wrap|
+
+ "/ first collect files and dirs
+ fileNames := OrderedCollection new.
+ dirNames := OrderedCollection new.
+
+ contents := aRoot directoryContents.
+ sortedByBlock notNil ifTrue:[
+ contents sort:[:a :b | sortedByBlock value:(aRoot construct:a) value:(aRoot construct:b)].
+ ].
+ contents do:[:f | |t|
+ t := aRoot construct:f.
+ t isDirectory ifTrue:[
+ (filterOrNil isNil or:[filterOrNil value:t]) ifTrue:[
+ dirBlock notNil ifTrue:[
+ t isSymbolicLink ifFalse:[
+ dirNames add:f
+ ]
+ ]
+ ]
+ ] ifFalse:[
+ fileBlock notNil ifTrue:[
+ fileNames add:f
+ ]
+ ]
+ ].
+ toDo add:{ aRoot . fileNames . dirNames }
+ ].
+
+ getFilesAndDirs value:self.
+
+ [toDo notEmpty] whileTrue:[
+ job := toDo removeFirst.
+ "/ process files..
+ thisDir := job at:1.
+ fileNames := job at:2.
+ dirNames := job at:3.
+
+ fileNames do:[:fN | fileBlock value:(thisDir constructString:fN)].
+ dirNames do:[:dN |
+ |subDir|
+
+ subDir := (thisDir construct:dN).
+ (filterOrNil isNil or:[filterOrNil value:subDir]) ifTrue:[
+ dirBlock value:(subDir name).
+ getFilesAndDirs value:subDir.
+ ].
+ ].
+ ].
+
+ "
+ '.' asFilename
+ recursiveFilesDo:[:f | Transcript show:'file: '; showCR:f]
+ directoriesDo:[:f | Transcript show:'dir: '; showCR:f]
+ filterForVisitingDirectories:nil
+ sortedBy:[:a :b | a name caselessBefore: b name]
+
+ '.' asFilename
+ recursiveFilesDo:[:f | Transcript showCR:f]
+ directoriesDo:[:f | Transcript showCR:f]
+ filterForVisitingDirectories:nil
+ sortedBy:[:a :b | a name caselessBefore: b name]
+
+ '../../..' asFilename
+ recursiveFilesDo:[:f | Transcript show:'file: '; showCR:f]
+ directoriesDo:[:f | Transcript show:'dir: '; showCR:f]
+ filterForVisitingDirectories:nil
+ sortedBy:[:a :b | a name caselessBefore: b name]
+
+ '../../..' asFilename
+ recursiveFilesDo:[:f | Transcript show:'file: '; showCR:f]
+ directoriesDo:[:f | Transcript show:'dir: '; showCR:f]
+ filterForVisitingDirectories:nil
+ sortedBy:nil
+ "
+
+ "Created: / 29-05-2019 / 10:15:40 / Claus Gittinger"
+ "Modified (comment): / 29-05-2019 / 11:28:57 / Claus Gittinger"
+!
+
withAllDirectoriesDo:aBlock
"evaluate aBlock for myself and all (recursive) directories contained in the directory represented by the receiver.
The block is invoked with a filename-arguments.