module System where import Control.Monad import qualified Control.Monad.Parallel as P import Data.List import System.Directory import System.FilePath.Posix type FilesPredicate = [FilePath] -> Bool type StopSearchingPredicate = [FilePath] -> Bool listDirectoriesRecursive :: FilesPredicate -> StopSearchingPredicate -> FilePath -> IO [FilePath] listDirectoriesRecursive predicate stopSearchingPredicate absPath = do let path = appendSeparatorIfNeeded absPath subDirectories <- listDirectories path let predicateMatch = predicate subDirectories let stopSearchingMatch = stopSearchingPredicate subDirectories if null subDirectories then return [] else if predicateMatch then return [path] else if stopSearchingMatch then return [] else do restOfDirectories <- mapM (listDirectoriesRecursive predicate stopSearchingPredicate) subDirectories if predicateMatch then do let restOfGitDirectories = concat restOfDirectories return (path : restOfGitDirectories) else return (concat restOfDirectories) listDirectories :: FilePath -> IO [FilePath] listDirectories path = do subFilesAndSubDirectories <- listDirectory path let absolutePath = map (\sub -> path ++ sub) subFilesAndSubDirectories absPathsWithSeparators = map appendSeparatorIfNeeded absolutePath filterM isDirectory absPathsWithSeparators isDirectory :: FilePath -> IO Bool isDirectory absolutePath = do let isHidden = "." `isPrefixOf` absolutePath isDirectory <- doesDirectoryExist absolutePath return (isDirectory && not isHidden) appendSeparatorIfNeeded :: String -> String appendSeparatorIfNeeded absPath | last absPath == pathSeparator = absPath | otherwise = absPath ++ separator separator = [pathSeparator]