par-traverse-0.2.0.0: src/System/Directory/Parallel.hs
module System.Directory.Parallel ( parTraverse ) where
import Control.Concurrent (getNumCapabilities)
import Control.Concurrent.ParallelIO.Local (Pool, parallel_, withPool)
import Control.Monad (filterM)
import System.Directory (doesDirectoryExist,
listDirectory)
import System.FilePath ((</>))
partitionM :: Monad m => (a -> m Bool) -> [a] -> m ([a], [a])
partitionM _ [] = pure ([], [])
partitionM f (x:xs) = do
res <- f x
(as,bs) <- partitionM f xs
if res
then pure (x:as, bs)
else pure (as, x:bs)
parTraverse :: (FilePath -> IO ()) -- ^ Action to execute on files
-> (FilePath -> IO Bool) -- ^ Filter on files
-> (FilePath -> IO Bool) -- ^ Filter on directories
-> [FilePath] -- ^ Starting directories
-> IO ()
parTraverse act fileP dirP dirs = do
ncpu <- getNumCapabilities
withPool ncpu $ \pool ->
parallel_ pool $ fmap (loopPool pool) dirs
where loopPool :: Pool -> FilePath -> IO ()
loopPool pool fp = do
all' <- fmap (fp </>) <$> listDirectory fp
(dirs', files) <- partitionM doesDirectoryExist all'
dirs'' <- filterM dirP dirs'
files' <- filterM fileP files
parallel_ pool (fmap act files' ++ fmap (loopPool pool) dirs'')