{-# LANGUAGE RankNTypes #-}
module Data.Conduit.Filesystem
( sourceDirectory
, sourceDirectoryDeep
) where
import Data.Conduit
import Control.Monad.Trans.Resource (MonadResource)
import Control.Monad.IO.Class (liftIO)
import System.FilePath ((</>))
import qualified Data.Streaming.Filesystem as F
-- | Stream the contents of the given directory, without traversing deeply.
--
-- This function will return /all/ of the contents of the directory, whether
-- they be files, directories, etc.
--
-- Note that the generated filepaths will be the complete path, not just the
-- filename. In other words, if you have a directory @foo@ containing files
-- @bar@ and @baz@, and you use @sourceDirectory@ on @foo@, the results will be
-- @foo/bar@ and @foo/baz@.
--
-- Since 1.1.0
sourceDirectory :: MonadResource m => FilePath -> Producer m FilePath
sourceDirectory dir =
bracketP (F.openDirStream dir) F.closeDirStream go
where
go ds =
loop
where
loop = do
mfp <- liftIO $ F.readDirStream ds
case mfp of
Nothing -> return ()
Just fp -> do
yield $ dir </> fp
loop
-- | Deeply stream the contents of the given directory.
--
-- This works the same as @sourceDirectory@, but will not return directories at
-- all. This function also takes an extra parameter to indicate whether
-- symlinks will be followed.
--
-- Since 1.1.0
sourceDirectoryDeep :: MonadResource m
=> Bool -- ^ Follow directory symlinks
-> FilePath -- ^ Root directory
-> Producer m FilePath
sourceDirectoryDeep followSymlinks =
start
where
start :: MonadResource m => FilePath -> Producer m FilePath
start dir = sourceDirectory dir =$= awaitForever go
go :: MonadResource m => FilePath -> Producer m FilePath
go fp = do
ft <- liftIO $ F.getFileType fp
case ft of
F.FTFile -> yield fp
F.FTFileSym -> yield fp
F.FTDirectory -> start fp
F.FTDirectorySym
| followSymlinks -> start fp
| otherwise -> return ()
F.FTOther -> return ()