{-# LANGUAGE CPP #-}
{-# LANGUAGE Rank2Types #-}
module System.Directory.Machine where

#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
#endif
import Control.Monad (filterM)
import Data.Machine
import System.Directory
import System.FilePath ((</>))
import System.IO.Machine

import System.Directory.Machine.Internal

-- | Recursively (breadth-first) walk thru the directory structure.
--
-- >>> runT (files <~ directoryWalk <~ source ["."])
-- ["./.gitignore",...
directoryWalk :: ProcessT IO FilePath FilePath
directoryWalk :: ProcessT IO FilePath FilePath
directoryWalk = (FilePath -> Bool) -> ProcessT IO FilePath FilePath
directoryWalk' (Bool -> FilePath -> Bool
forall a b. a -> b -> a
const Bool
True)

-- | A variant of 'directoryWalk' with a predicate whether to descend
-- into particular directory.
--
-- @
-- directoryWalk' (not . isSuffixOf ".git")
-- @
--
-- @since 0.2.1.0
directoryWalk' :: (FilePath -> Bool) -> ProcessT IO FilePath FilePath
directoryWalk' :: (FilePath -> Bool) -> ProcessT IO FilePath FilePath
directoryWalk' FilePath -> Bool
p = IO (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath))
-> ProcessT IO FilePath FilePath
forall (m :: * -> *) (k :: * -> *) o.
m (Step k o (MachineT m k o)) -> MachineT m k o
MachineT (IO (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath))
 -> ProcessT IO FilePath FilePath)
-> (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
    -> IO
         (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)))
-> Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
-> ProcessT IO FilePath FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
-> IO (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath))
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
 -> ProcessT IO FilePath FilePath)
-> Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
-> ProcessT IO FilePath FilePath
forall a b. (a -> b) -> a -> b
$ (FilePath -> ProcessT IO FilePath FilePath)
-> Is FilePath FilePath
-> ProcessT IO FilePath FilePath
-> Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
forall (k :: * -> *) o r t. (t -> r) -> k t -> r -> Step k o r
Await (\FilePath
root -> [FilePath] -> [FilePath] -> ProcessT IO FilePath FilePath
f [FilePath
root] []) Is FilePath FilePath
forall a. Is a a
Refl ProcessT IO FilePath FilePath
forall (k :: * -> *) b. Machine k b
stopped where
  f :: [FilePath] -> [FilePath] -> ProcessT IO FilePath FilePath
f []     []      = ProcessT IO FilePath FilePath
directoryWalk
  f [FilePath]
xs     (FilePath
y:[FilePath]
ys)  = IO (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath))
-> ProcessT IO FilePath FilePath
forall (m :: * -> *) (k :: * -> *) o.
m (Step k o (MachineT m k o)) -> MachineT m k o
MachineT (IO (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath))
 -> ProcessT IO FilePath FilePath)
-> (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
    -> IO
         (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)))
-> Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
-> ProcessT IO FilePath FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
-> IO (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath))
forall (m :: * -> *) a. Monad m => a -> m a
return (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
 -> ProcessT IO FilePath FilePath)
-> Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
-> ProcessT IO FilePath FilePath
forall a b. (a -> b) -> a -> b
$ FilePath
-> ProcessT IO FilePath FilePath
-> Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
forall (k :: * -> *) o r. o -> r -> Step k o r
Yield FilePath
y (ProcessT IO FilePath FilePath
 -> Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath))
-> ProcessT IO FilePath FilePath
-> Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)
forall a b. (a -> b) -> a -> b
$ [FilePath] -> [FilePath] -> ProcessT IO FilePath FilePath
f [FilePath]
xs [FilePath]
ys
  f (FilePath
x:[FilePath]
xs) []      = IO (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath))
-> ProcessT IO FilePath FilePath
forall (m :: * -> *) (k :: * -> *) o.
m (Step k o (MachineT m k o)) -> MachineT m k o
MachineT (IO (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath))
 -> ProcessT IO FilePath FilePath)
-> IO (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath))
-> ProcessT IO FilePath FilePath
forall a b. (a -> b) -> a -> b
$ do
    [FilePath]
ys <- FilePath -> IO [FilePath]
getDirectoryContents FilePath
x
    let contents :: [FilePath]
contents = (FilePath
x FilePath -> FilePath -> FilePath
</>) (FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((FilePath -> Bool) -> [FilePath] -> [FilePath]
forall a. (a -> Bool) -> [a] -> [a]
filter FilePath -> Bool
isDirectoryContentsValid ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> a -> b
$ [FilePath]
ys)
    [FilePath]
dirs <- (FilePath -> IO Bool) -> [FilePath] -> IO [FilePath]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM FilePath -> IO Bool
doesDirectoryExist ((FilePath -> Bool) -> [FilePath] -> [FilePath]
forall a. (a -> Bool) -> [a] -> [a]
filter FilePath -> Bool
p [FilePath]
contents)
    ProcessT IO FilePath FilePath
-> IO (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath))
forall (m :: * -> *) (k :: * -> *) o.
MachineT m k o -> m (Step k o (MachineT m k o))
runMachineT (ProcessT IO FilePath FilePath
 -> IO
      (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath)))
-> ProcessT IO FilePath FilePath
-> IO (Step (Is FilePath) FilePath (ProcessT IO FilePath FilePath))
forall a b. (a -> b) -> a -> b
$ [FilePath] -> [FilePath] -> ProcessT IO FilePath FilePath
f ([FilePath]
dirs [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++ [FilePath]
xs) [FilePath]
contents

directoryContents :: ProcessT IO FilePath [FilePath]
directoryContents :: ProcessT IO FilePath [FilePath]
directoryContents = ([FilePath] -> [FilePath]) -> Process [FilePath] [FilePath]
forall (k :: * -> * -> *) a b. Automaton k => k a b -> Process a b
auto ((FilePath -> Bool) -> [FilePath] -> [FilePath]
forall a. (a -> Bool) -> [a] -> [a]
filter FilePath -> Bool
isDirectoryContentsValid) MachineT IO (Is [FilePath]) [FilePath]
-> ProcessT IO FilePath [FilePath]
-> ProcessT IO FilePath [FilePath]
forall (m :: * -> *) b c (k :: * -> *).
Monad m =>
ProcessT m b c -> MachineT m k b -> MachineT m k c
<~ (FilePath -> IO [FilePath]) -> ProcessT IO FilePath [FilePath]
forall (k :: * -> * -> *) (m :: * -> *) a b.
(Category k, Monad m) =>
(a -> m b) -> MachineT m (k a) b
autoM FilePath -> IO [FilePath]
getDirectoryContents

directories :: ProcessT IO FilePath FilePath
directories :: ProcessT IO FilePath FilePath
directories = (FilePath -> IO Bool) -> ProcessT IO FilePath FilePath
forall a. (a -> IO Bool) -> ProcessT IO a a
filteredIO FilePath -> IO Bool
doesDirectoryExist

files :: ProcessT IO FilePath FilePath
files :: ProcessT IO FilePath FilePath
files = (FilePath -> IO Bool) -> ProcessT IO FilePath FilePath
forall a. (a -> IO Bool) -> ProcessT IO a a
filteredIO FilePath -> IO Bool
doesFileExist