common/util/Util/Directory.hs (39 lines of code) (raw):
-- Copyright 2004-present Facebook. All Rights Reserved.
module Util.Directory (
Directory(..),
listFilesRecursive,
) where
import Control.Monad.Extra (concatMapM)
import Control.Monad.State
import qualified Data.HashSet as Set
import qualified System.Directory as IO
import System.FilePath
-- | An effect class for modelling directory I/O
class Directory f where
doesDirectoryExist :: FilePath -> f Bool
listDirectory :: FilePath -> f [FilePath]
instance Directory IO where
doesDirectoryExist = IO.doesDirectoryExist
listDirectory = IO.listDirectory
{- | A version of 'listFilesRecursive' from the 'extra' package offering more
control and termination in the presence of cyclic symlinks.
-}
listFilesRecursive ::
(Directory f, Monad f) =>
-- | Whether to recurse in a directory
(FilePath -> Bool) ->
FilePath ->
f [FilePath]
listFilesRecursive predDir = flip evalStateT mempty . go
where
go relDir = do
visited <- get
if Set.member relDir visited
then return []
else do
modify $ Set.insert relDir
ls <- lift $ map (relDir </>) <$> listDirectory relDir
dirs <- lift $ filterM (\d -> (&& predDir d) <$> doesDirectoryExist d) ls
(ls ++) <$> concatMapM go dirs
{-# SPECIALIZE
listFilesRecursive :: (FilePath -> Bool) -> FilePath -> IO [FilePath] #-}