{-# LANGUAGE MultiWayIf #-}
module Data.VCS.Ignore.FileSystem
( findPaths
, listPaths
, walkPaths
, toPosixPath
)
where
import Control.Monad ( forM
, mfilter
)
import Control.Monad.IO.Class ( MonadIO
, liftIO
)
import Data.Maybe ( catMaybes
, fromMaybe
)
import System.Directory ( doesDirectoryExist
, doesFileExist
, getDirectoryContents
)
import System.FilePath ( (</>) )
findPaths :: MonadIO m
=> FilePath
-> (FilePath -> m Bool)
-> m [FilePath]
findPaths :: FilePath -> (FilePath -> m Bool) -> m [FilePath]
findPaths FilePath
entryPath FilePath -> m Bool
predicate = [Maybe FilePath] -> [FilePath]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe FilePath] -> [FilePath])
-> m [Maybe FilePath] -> m [FilePath]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> (FilePath -> m (Maybe FilePath)) -> m [Maybe FilePath]
forall (m :: * -> *) a.
MonadIO m =>
FilePath -> (FilePath -> m a) -> m [a]
walkPaths FilePath
entryPath FilePath -> m (Maybe FilePath)
process
where
process :: FilePath -> m (Maybe FilePath)
process FilePath
path = (\Bool
p -> if Bool
p then FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
path else Maybe FilePath
forall a. Maybe a
Nothing) (Bool -> Maybe FilePath) -> m Bool -> m (Maybe FilePath)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> m Bool
predicate FilePath
path
listPaths :: MonadIO m
=> FilePath
-> m [FilePath]
listPaths :: FilePath -> m [FilePath]
listPaths FilePath
entryPath = FilePath -> (FilePath -> m FilePath) -> m [FilePath]
forall (m :: * -> *) a.
MonadIO m =>
FilePath -> (FilePath -> m a) -> m [a]
walkPaths FilePath
entryPath FilePath -> m FilePath
forall (f :: * -> *) a. Applicative f => a -> f a
pure
walkPaths :: MonadIO m
=> FilePath
-> (FilePath -> m a)
-> m [a]
walkPaths :: FilePath -> (FilePath -> m a) -> m [a]
walkPaths FilePath
entryPath FilePath -> m a
fn = do
Bool
isDir <- IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> IO Bool -> m Bool
forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesDirectoryExist FilePath
entryPath
Bool
isFile <- IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> IO Bool -> m Bool
forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesFileExist FilePath
entryPath
if
| Bool
isDir -> FilePath -> m a
fn FilePath
entryPath m a -> (a -> m [a]) -> m [a]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (\a
p -> (a
p a -> [a] -> [a]
forall a. a -> [a] -> [a]
:) ([a] -> [a]) -> m [a] -> m [a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> m [a]
listDirectory FilePath
entryPath)
| Bool
isFile -> a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> [a]) -> m a -> m [a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> m a
fn FilePath
entryPath
| Bool
otherwise -> [a] -> m [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
where
listDirectory :: FilePath -> m [a]
listDirectory FilePath
dir = do
[FilePath]
names <- IO [FilePath] -> m [FilePath]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO [FilePath] -> m [FilePath]) -> IO [FilePath] -> m [FilePath]
forall a b. (a -> b) -> a -> b
$ FilePath -> IO [FilePath]
getDirectoryContents FilePath
dir
[[a]]
paths <- [FilePath] -> (FilePath -> m [a]) -> m [[a]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM ((FilePath -> Bool) -> [FilePath] -> [FilePath]
forall a. (a -> Bool) -> [a] -> [a]
filter (FilePath -> [FilePath] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [FilePath
".", FilePath
".."]) [FilePath]
names) ((FilePath -> m [a]) -> m [[a]]) -> (FilePath -> m [a]) -> m [[a]]
forall a b. (a -> b) -> a -> b
$ \FilePath
name -> do
let path :: FilePath
path = FilePath
dir FilePath -> FilePath -> FilePath
</> FilePath
name
Bool
isDirectory <- IO Bool -> m Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> IO Bool -> m Bool
forall a b. (a -> b) -> a -> b
$ FilePath -> IO Bool
doesDirectoryExist FilePath
path
if Bool
isDirectory then FilePath -> (FilePath -> m a) -> m [a]
forall (m :: * -> *) a.
MonadIO m =>
FilePath -> (FilePath -> m a) -> m [a]
walkPaths FilePath
path FilePath -> m a
fn else a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> [a]) -> m a -> m [a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> m a
fn FilePath
path
[a] -> m [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([a] -> m [a]) -> [a] -> m [a]
forall a b. (a -> b) -> a -> b
$ [[a]] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[a]]
paths
toPosixPath :: FilePath
-> FilePath
toPosixPath :: FilePath -> FilePath
toPosixPath = Char -> Char -> FilePath -> FilePath
forall (f :: * -> *) b. (Functor f, Eq b) => b -> b -> f b -> f b
replace Char
'\\' Char
'/'
where replace :: b -> b -> f b -> f b
replace b
a b
b = (b -> b) -> f b -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((b -> b) -> f b -> f b) -> (b -> b) -> f b -> f b
forall a b. (a -> b) -> a -> b
$ b -> Maybe b -> b
forall a. a -> Maybe a -> a
fromMaybe b
b (Maybe b -> b) -> (b -> Maybe b) -> b -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (b -> Bool) -> Maybe b -> Maybe b
forall (m :: * -> *) a. MonadPlus m => (a -> Bool) -> m a -> m a
mfilter (b -> b -> Bool
forall a. Eq a => a -> a -> Bool
/= b
a) (Maybe b -> Maybe b) -> (b -> Maybe b) -> b -> Maybe b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> Maybe b
forall a. a -> Maybe a
Just