module System.Posix.Recursive.Unsafe (
list,
followList,
listMatching,
followListMatching,
listDirectories,
listRegularFiles,
listSymbolicLinks,
Conf (..),
defConf,
listCustom,
) where
import Control.Exception (bracket)
import Data.Foldable (fold)
import System.IO.Unsafe (unsafeInterleaveIO)
import qualified System.Posix.Directory as Posix
import qualified System.Posix.Files as Posix
import System.Posix.Recursive (Conf (..), defConf)
foldMapA :: (Monoid b, Traversable t, Applicative f) => (a -> f b) -> t a -> f b
foldMapA :: (a -> f b) -> t a -> f b
foldMapA = ((t b -> b) -> f (t b) -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap t b -> b
forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold (f (t b) -> f b) -> (t a -> f (t b)) -> t a -> f b
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((t a -> f (t b)) -> t a -> f b)
-> ((a -> f b) -> t a -> f (t b)) -> (a -> f b) -> t a -> f b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> f b) -> t a -> f (t b)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse
{-# INLINE listDir #-}
listDir :: (FilePath -> Bool) -> FilePath -> IO [FilePath]
listDir :: (FilePath -> Bool) -> FilePath -> IO [FilePath]
listDir FilePath -> Bool
predicate FilePath
path =
IO DirStream
-> (DirStream -> IO ())
-> (DirStream -> IO [FilePath])
-> IO [FilePath]
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
(FilePath -> IO DirStream
Posix.openDirStream FilePath
path)
DirStream -> IO ()
Posix.closeDirStream
([FilePath] -> DirStream -> IO [FilePath]
go [])
where
go :: [FilePath] -> Posix.DirStream -> IO [FilePath]
go :: [FilePath] -> DirStream -> IO [FilePath]
go [FilePath]
acc DirStream
dirp = do
FilePath
e <- DirStream -> IO FilePath
Posix.readDirStream DirStream
dirp
if FilePath -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null FilePath
e
then [FilePath] -> IO [FilePath]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [FilePath]
acc
else
if FilePath
e FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
/= FilePath
"." Bool -> Bool -> Bool
&& FilePath
e FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
/= FilePath
".."
then
let fullPath :: FilePath
fullPath = FilePath
path FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> FilePath
"/" FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> FilePath
e
in if FilePath -> Bool
predicate FilePath
fullPath
then [FilePath] -> DirStream -> IO [FilePath]
go (FilePath
fullPath FilePath -> [FilePath] -> [FilePath]
forall a. a -> [a] -> [a]
: [FilePath]
acc) DirStream
dirp
else [FilePath] -> DirStream -> IO [FilePath]
go [FilePath]
acc DirStream
dirp
else [FilePath] -> DirStream -> IO [FilePath]
go [FilePath]
acc DirStream
dirp
{-# INLINE listAll' #-}
listAll' :: Bool -> (FilePath -> Bool) -> FilePath -> IO [FilePath]
listAll' :: Bool -> (FilePath -> Bool) -> FilePath -> IO [FilePath]
listAll' Bool
followSymlinks FilePath -> Bool
predicate FilePath
path =
do
FileStatus
file <- FilePath -> IO FileStatus
getFileStatus FilePath
path
if FileStatus -> Bool
Posix.isDirectory FileStatus
file
then do
[FilePath]
content <- (FilePath -> Bool) -> FilePath -> IO [FilePath]
listDir FilePath -> Bool
predicate FilePath
path
[FilePath]
next <- IO [FilePath] -> IO [FilePath]
forall a. IO a -> IO a
unsafeInterleaveIO (IO [FilePath] -> IO [FilePath]) -> IO [FilePath] -> IO [FilePath]
forall a b. (a -> b) -> a -> b
$ (FilePath -> IO [FilePath]) -> [FilePath] -> IO [FilePath]
forall b (t :: * -> *) (f :: * -> *) a.
(Monoid b, Traversable t, Applicative f) =>
(a -> f b) -> t a -> f b
foldMapA (Bool -> (FilePath -> Bool) -> FilePath -> IO [FilePath]
listAll' Bool
followSymlinks FilePath -> Bool
predicate) [FilePath]
content
[FilePath] -> IO [FilePath]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([FilePath] -> IO [FilePath]) -> [FilePath] -> IO [FilePath]
forall a b. (a -> b) -> a -> b
$ [FilePath]
content [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++ [FilePath]
next
else [FilePath] -> IO [FilePath]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
where
{-# INLINE getFileStatus #-}
getFileStatus :: FilePath -> IO FileStatus
getFileStatus
| Bool
followSymlinks = FilePath -> IO FileStatus
Posix.getFileStatus
| Bool
otherwise = FilePath -> IO FileStatus
Posix.getSymbolicLinkStatus
{-# INLINE listAll'' #-}
listAll'' :: Bool -> (FilePath -> Bool) -> FilePath -> IO [FilePath]
listAll'' :: Bool -> (FilePath -> Bool) -> FilePath -> IO [FilePath]
listAll'' Bool
followSymlinks FilePath -> Bool
predicate FilePath
path =
(FilePath
path FilePath -> [FilePath] -> [FilePath]
forall a. a -> [a] -> [a]
:) ([FilePath] -> [FilePath]) -> IO [FilePath] -> IO [FilePath]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Bool -> (FilePath -> Bool) -> FilePath -> IO [FilePath]
listAll' Bool
followSymlinks FilePath -> Bool
predicate FilePath
path
listMatching :: (FilePath -> Bool) -> FilePath -> IO [FilePath]
listMatching :: (FilePath -> Bool) -> FilePath -> IO [FilePath]
listMatching =
Bool -> (FilePath -> Bool) -> FilePath -> IO [FilePath]
listAll'' Bool
False
followListMatching :: (FilePath -> Bool) -> FilePath -> IO [FilePath]
followListMatching :: (FilePath -> Bool) -> FilePath -> IO [FilePath]
followListMatching =
Bool -> (FilePath -> Bool) -> FilePath -> IO [FilePath]
listAll'' Bool
True
list :: FilePath -> IO [FilePath]
list :: FilePath -> IO [FilePath]
list =
Bool -> (FilePath -> Bool) -> FilePath -> IO [FilePath]
listAll'' Bool
False (Bool -> FilePath -> Bool
forall a b. a -> b -> a
const Bool
True)
followList :: FilePath -> IO [FilePath]
followList :: FilePath -> IO [FilePath]
followList =
Bool -> (FilePath -> Bool) -> FilePath -> IO [FilePath]
listAll'' Bool
True (Bool -> FilePath -> Bool
forall a b. a -> b -> a
const Bool
True)
{-# INLINE listAccessible' #-}
listAccessible' :: Conf -> FilePath -> IO [FilePath]
listAccessible' :: Conf -> FilePath -> IO [FilePath]
listAccessible' Conf{Bool
FilePath -> Bool
FileStatus -> FilePath -> IO Bool
followSymlinks :: Conf -> Bool
includeFile :: Conf -> FileStatus -> FilePath -> IO Bool
filterPath :: Conf -> FilePath -> Bool
followSymlinks :: Bool
includeFile :: FileStatus -> FilePath -> IO Bool
filterPath :: FilePath -> Bool
..} FilePath
path =
do
FileStatus
file <- FilePath -> IO FileStatus
getFileStatus FilePath
path
[FilePath]
next <-
if FileStatus -> Bool
Posix.isDirectory FileStatus
file
then do
[FilePath]
content <- (FilePath -> Bool) -> FilePath -> IO [FilePath]
listDir FilePath -> Bool
filterPath FilePath
path
IO [FilePath] -> IO [FilePath]
forall a. IO a -> IO a
unsafeInterleaveIO (IO [FilePath] -> IO [FilePath]) -> IO [FilePath] -> IO [FilePath]
forall a b. (a -> b) -> a -> b
$ (FilePath -> IO [FilePath]) -> [FilePath] -> IO [FilePath]
forall b (t :: * -> *) (f :: * -> *) a.
(Monoid b, Traversable t, Applicative f) =>
(a -> f b) -> t a -> f b
foldMapA (Conf -> FilePath -> IO [FilePath]
listAccessible' Conf :: (FilePath -> Bool)
-> (FileStatus -> FilePath -> IO Bool) -> Bool -> Conf
Conf{Bool
FilePath -> Bool
FileStatus -> FilePath -> IO Bool
followSymlinks :: Bool
includeFile :: FileStatus -> FilePath -> IO Bool
filterPath :: FilePath -> Bool
followSymlinks :: Bool
includeFile :: FileStatus -> FilePath -> IO Bool
filterPath :: FilePath -> Bool
..}) [FilePath]
content
else [FilePath] -> IO [FilePath]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
Bool
include <- FileStatus -> FilePath -> IO Bool
includeFile FileStatus
file FilePath
path
if Bool
include
then [FilePath] -> IO [FilePath]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([FilePath] -> IO [FilePath]) -> [FilePath] -> IO [FilePath]
forall a b. (a -> b) -> a -> b
$ FilePath
path FilePath -> [FilePath] -> [FilePath]
forall a. a -> [a] -> [a]
: [FilePath]
next
else [FilePath] -> IO [FilePath]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [FilePath]
next
where
{-# INLINE getFileStatus #-}
getFileStatus :: FilePath -> IO FileStatus
getFileStatus
| Bool
followSymlinks = FilePath -> IO FileStatus
Posix.getFileStatus
| Bool
otherwise = FilePath -> IO FileStatus
Posix.getSymbolicLinkStatus
listCustom :: Conf -> FilePath -> IO [FilePath]
listCustom :: Conf -> FilePath -> IO [FilePath]
listCustom =
Conf -> FilePath -> IO [FilePath]
listAccessible'
listDirectories :: FilePath -> IO [FilePath]
listDirectories :: FilePath -> IO [FilePath]
listDirectories =
Conf -> FilePath -> IO [FilePath]
listAccessible' Conf
defConf{includeFile :: FileStatus -> FilePath -> IO Bool
includeFile = \FileStatus
file FilePath
_ -> Bool -> IO Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> IO Bool) -> Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ FileStatus -> Bool
Posix.isDirectory FileStatus
file}
listRegularFiles :: FilePath -> IO [FilePath]
listRegularFiles :: FilePath -> IO [FilePath]
listRegularFiles =
Conf -> FilePath -> IO [FilePath]
listAccessible' Conf
defConf{includeFile :: FileStatus -> FilePath -> IO Bool
includeFile = \FileStatus
file FilePath
_ -> Bool -> IO Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> IO Bool) -> Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ FileStatus -> Bool
Posix.isRegularFile FileStatus
file}
listSymbolicLinks :: FilePath -> IO [FilePath]
listSymbolicLinks :: FilePath -> IO [FilePath]
listSymbolicLinks =
Conf -> FilePath -> IO [FilePath]
listAccessible' Conf
defConf{includeFile :: FileStatus -> FilePath -> IO Bool
includeFile = \FileStatus
file FilePath
_ -> Bool -> IO Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> IO Bool) -> Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ FileStatus -> Bool
Posix.isSymbolicLink FileStatus
file}