{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE CPP #-}
module System.FSNotify.Path (
findFiles
, findFilesAndDirs
, canonicalizeDirPath
, canonicalizePath
, hasThisExtension
) where
import Control.Monad
import qualified Data.Text as T
import Prelude hiding (FilePath)
import qualified System.Directory as D
import System.FilePath
import System.PosixCompat.Files as PF
getDirectoryContentsPath :: FilePath -> IO [FilePath]
getDirectoryContentsPath :: String -> IO [String]
getDirectoryContentsPath String
path =
((forall a b. (a -> b) -> [a] -> [b]
map (String
path String -> String -> String
</>)) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
dots) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO [String]
D.getDirectoryContents String
path) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM String -> IO Bool
exists
where
#if MIN_VERSION_directory(1, 2, 7)
exists :: String -> IO Bool
exists String
x = String -> IO Bool
D.doesPathExist String
x
#else
exists x = (||) <$> D.doesFileExist x <*> D.doesDirectoryExist x
#endif
dots :: String -> Bool
dots String
"." = Bool
True
dots String
".." = Bool
True
dots String
_ = Bool
False
fileDirContents :: FilePath -> IO ([FilePath], [FilePath])
fileDirContents :: String -> IO ([String], [String])
fileDirContents String
path = do
[String]
contents <- String -> IO [String]
getDirectoryContentsPath String
path
[FileStatus]
stats <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> IO FileStatus
getFileStatus [String]
contents
let pairs :: [(FileStatus, String)]
pairs = forall a b. [a] -> [b] -> [(a, b)]
zip [FileStatus]
stats [String]
contents
let files :: [String]
files = [ String
f | (FileStatus
s, String
f) <- [(FileStatus, String)]
pairs, FileStatus -> Bool
PF.isRegularFile FileStatus
s]
let dirs :: [String]
dirs = [ String
d | (FileStatus
s, String
d) <- [(FileStatus, String)]
pairs, FileStatus -> Bool
PF.isDirectory FileStatus
s]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String]
files, [String]
dirs)
findAllFiles :: FilePath -> IO [FilePath]
findAllFiles :: String -> IO [String]
findAllFiles String
path = do
([String]
files, [String]
dirs) <- String -> IO ([String], [String])
fileDirContents String
path
[[String]]
nestedFiles <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> IO [String]
findAllFiles [String]
dirs
forall (m :: * -> *) a. Monad m => a -> m a
return ([String]
files forall a. [a] -> [a] -> [a]
++ forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[String]]
nestedFiles)
findImmediateFiles :: FilePath -> IO [FilePath]
findImmediateFiles :: String -> IO [String]
findImmediateFiles = String -> IO ([String], [String])
fileDirContents forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM String -> IO String
D.canonicalizePath forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst
findFiles :: Bool -> FilePath -> IO [FilePath]
findFiles :: Bool -> String -> IO [String]
findFiles Bool
True String
path = String -> IO [String]
findAllFiles forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< String -> IO String
canonicalizeDirPath String
path
findFiles Bool
False String
path = String -> IO [String]
findImmediateFiles forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< String -> IO String
canonicalizeDirPath String
path
findFilesAndDirs :: Bool -> FilePath -> IO [FilePath]
findFilesAndDirs :: Bool -> String -> IO [String]
findFilesAndDirs Bool
False String
path = String -> IO [String]
getDirectoryContentsPath forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< String -> IO String
canonicalizeDirPath String
path
findFilesAndDirs Bool
True String
path = do
([String]
files, [String]
dirs) <- String -> IO ([String], [String])
fileDirContents String
path
[String]
nestedFilesAndDirs <- forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Bool -> String -> IO [String]
findFilesAndDirs Bool
False) [String]
dirs
forall (m :: * -> *) a. Monad m => a -> m a
return ([String]
files forall a. [a] -> [a] -> [a]
++ [String]
dirs forall a. [a] -> [a] -> [a]
++ [String]
nestedFilesAndDirs)
addTrailingSlash :: FilePath -> FilePath
addTrailingSlash :: String -> String
addTrailingSlash = String -> String
addTrailingPathSeparator
canonicalizeDirPath :: FilePath -> IO FilePath
canonicalizeDirPath :: String -> IO String
canonicalizeDirPath String
path = String -> String
addTrailingSlash forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` String -> IO String
D.canonicalizePath String
path
canonicalizePath :: FilePath -> IO FilePath
canonicalizePath :: String -> IO String
canonicalizePath String
path = let was_dir :: Bool
was_dir = forall (t :: * -> *) a. Foldable t => t a -> Bool
null (String -> String
takeFileName String
path) in
if Bool -> Bool
not Bool
was_dir then String -> IO String
D.canonicalizePath String
path
else String -> IO String
canonicalizeDirPath String
path
hasThisExtension :: FilePath -> T.Text -> Bool
hasThisExtension :: String -> Text -> Bool
hasThisExtension String
p Text
ext = String -> String
takeExtension String
p forall a. Eq a => a -> a -> Bool
== Text -> String
T.unpack Text
ext