module Filesystem.Enumerator
( traverse
, enumDirectory
) where
import Prelude hiding (FilePath)
import Control.Exception (finally)
import Control.Monad.IO.Class (MonadIO)
import Data.Enumerator
import Filesystem
import Filesystem.Path ((</>))
import Filesystem.Path.CurrentOS (FilePath, encodeString, decodeString)
#ifdef CABAL_OS_WINDOWS
import qualified System.Win32 as Win32
#else
import qualified System.Posix as Posix
#endif
traverse :: MonadIO m
=> Bool
-> FilePath
-> Enumerator FilePath m a
traverse followSymlinks root s = tryIO (listDirectory root) >>= (\ps -> loop ps s) where
loop (p:ps) step@(Continue k) = do
isFile' <- tryIO (isFile p)
if isFile'
then k (Chunks [p]) >>== loop ps
else do
follow' <- tryIO (follow p)
if follow'
then traverse followSymlinks p step >>== loop ps
else loop ps step
loop _ step = returnI step
follow :: FilePath -> IO Bool
#ifdef CABAL_OS_WINDOWS
follow = isDirectory
#else
follow p = do
let path = encodeString p
stat <- if followSymlinks
then Posix.getFileStatus path
else Posix.getSymbolicLinkStatus path
return (Posix.isDirectory stat)
#endif
enumDirectory :: FilePath -> Enumerator FilePath IO a
enumDirectory root step = do
let boring str = str == "." || str == ".."
#ifdef CABAL_OS_WINDOWS
let search = root </> decodeString "*"
(h, findData) <- tryIO (Win32.findFirstFile (encodeString search))
let close = Win32.findClose h
let iter = checkContinue0 $ \loop k -> do
raw <- tryIO (Win32.getFindDataFileName findData)
let path = root </> decodeString raw
let checkNext s = do
hasNext <- tryIO (Win32.findNextFile h findData)
if hasNext
then loop s
else returnI s
if boring raw
then checkNext (Continue k)
else k (Chunks [path]) >>== checkNext
#else
dir <- tryIO (Posix.openDirStream (encodeString root))
let close = Posix.closeDirStream dir
let iter = checkContinue0 $ \loop k -> do
raw <- tryIO (Posix.readDirStream dir)
let path = root </> decodeString raw
case raw of
"" -> continue k
_ | boring raw -> loop (Continue k)
_ -> k (Chunks [path]) >>== loop
#endif
Iteratee (finally (runIteratee (iter step)) close)