-- File created: 2008-10-16 12:12:50moduleSystem.FilePath.Glob.Directory(globDir)whereimportControl.Monad(forM)importqualifiedData.DListasDLimportData.DList(DList)importData.List((\\))importSystem.Directory(doesDirectoryExist,getDirectoryContents)importSystem.FilePath((</>))importSystem.FilePath.Glob.BaseimportSystem.FilePath.Glob.Match(match)importSystem.FilePath.Glob.Utils(getRecursiveContents,nubOrd,pathParts,partitionDL)-- The Patterns in TypedPattern don't contain PathSeparator or AnyDirectorydataTypedPattern=AnyPattern-- pattern|DirPattern-- pattern/|AnyDirPattern-- pattern**/derivingShow-- |Matches each given 'Pattern' against the contents of the given 'FilePath',-- recursively. The result pair\'s first component contains the matched paths,-- grouped for each given 'Pattern', and the second contains all paths which-- were not matched by any 'Pattern'.---- If multiple 'Pattern's match a single 'FilePath', that path will be included-- in multiple groups.---- This function is different from a simple 'filter' over all the contents of-- the directory: the matching is performed relative to the directory, so that-- for instance the following is true:---- > fmap (head.fst) (globDir [compile "*"] dir) == getDirectoryContents dir---- If @dir@ is @\"foo\"@ the pattern should be @\"foo/*\"@ to get the same-- results with a plain 'filter'.---- Any results deeper than in the given directory are enumerated lazily, using-- 'unsafeInterleaveIO'.---- Directories without read permissions are returned as entries but their-- contents, of course, are not.globDir::[Pattern]->FilePath->IO([[FilePath]],[FilePath])globDir[]dir=doc<-getRecursiveContentsdirreturn([],DL.toListc)globDirpatsdir=doresults<-mapM(\p->globDir'(separatep)dir)patslet(matches,others)=unzipresultsallMatches=DL.toList.DL.concat$matchesallOthers=DL.toList.DL.concat$othersreturn(mapDL.toListmatches,nubOrdallOthers\\allMatches)globDir'::[TypedPattern]->FilePath->IO(DListFilePath,DListFilePath)globDir'[]dir=didn'tMatchdirTrueglobDir'patsdir=doraw<-getDirectoryContentsdirletentries=raw\\[".",".."]results<-forMentries$\e->matchTypedAndGopatse(dir</>e)let(matches,others)=unzipresultsreturn(DL.concatmatches,DL.concatothers)matchTypedAndGo::[TypedPattern]->FilePath->FilePath->IO(DListFilePath,DListFilePath)-- (Any p) is always the last elementmatchTypedAndGo[Anyp]pathabsPath=ifmatchppaththenreturn(DL.singletonabsPath,DL.empty)elsedoesDirectoryExistabsPath>>=didn'tMatchabsPathmatchTypedAndGo(Dirp:ps)pathabsPath=doisDir<-doesDirectoryExistabsPathifisDir&&matchppaththenglobDir'psabsPathelsedidn'tMatchabsPathisDirmatchTypedAndGo(AnyDirp:ps)pathabsPath=doisDir<-doesDirectoryExistabsPathletm=match(unseparateps)casenull(unPatternp)||matchppathofTrue|isDir->fmap(partitionDL(anym.pathParts))(getRecursiveContentsabsPath)True|mpath->return(DL.singletonabsPath,DL.empty)_->didn'tMatchabsPathisDirmatchTypedAndGo___=error"Glob.matchTypedAndGo :: internal error"didn'tMatch::FilePath->Bool->IO(DListFilePath,DListFilePath)didn'tMatchabsPathisDir=(fmap$(,)DL.empty)$ifisDirthengetRecursiveContentsabsPathelsereturn$DL.singletonabsPathseparate::Pattern->[TypedPattern]separate=go[].unPatternwherego[][]=[]gogr[]=[Any$fgr]-- ./foo should not be split into [. , foo], it's just foogogr(ExtSeparator:PathSeparator:ps)=gogrpsgogr(PathSeparator:ps)=(Dir$fgr):go[]psgogr(AnyDirectory:ps)=(AnyDir$fgr):go[]psgogr(p:ps)=go(p:gr)psf=Pattern.reverseunseparate::[TypedPattern]->Patternunseparate=Pattern.foldrf[]wheref(AnyDirp)ts=unPatternp++AnyDirectory:tsf(Dirp)ts=unPatternp++PathSeparator:tsf(Anyp)ts=unPatternp++ts