{-
  Util modul. Shold be dropped when misc is released as package.
-}

module Text.StringTemplates.Utils (directoryEntriesRecursive,directoryFilesRecursive,getRecursiveMTime) where

import System.Directory
import Data.List (isSuffixOf)
import Data.Time.Clock (UTCTime)

directoryEntriesRecursive :: FilePath -- ^ dir path to be searched for recursively
                          -> IO ([FilePath], [FilePath]) -- ^ (list of all subdirs, list of all files)
directoryEntriesRecursive :: FilePath -> IO ([FilePath], [FilePath])
directoryEntriesRecursive FilePath
path | FilePath
"." FilePath -> FilePath -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf` FilePath
path = ([FilePath], [FilePath]) -> IO ([FilePath], [FilePath])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([], [])
                               | Bool
otherwise = do
  Bool
isDir <- FilePath -> IO Bool
doesDirectoryExist FilePath
path
  if Bool
isDir then do
      [FilePath]
entries <- FilePath -> IO [FilePath]
getDirectoryContents FilePath
path
      let properEntries :: [FilePath]
properEntries = (FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map ((FilePath
path FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"/")FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++) [FilePath]
entries
      [([FilePath], [FilePath])]
results <- (FilePath -> IO ([FilePath], [FilePath]))
-> [FilePath] -> IO [([FilePath], [FilePath])]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM FilePath -> IO ([FilePath], [FilePath])
directoryEntriesRecursive [FilePath]
properEntries
      let ([FilePath]
dirs, [FilePath]
files) = [([FilePath], [FilePath])] -> ([FilePath], [FilePath])
forall {a} {a}. [([a], [a])] -> ([a], [a])
biConcat [([FilePath], [FilePath])]
results
      ([FilePath], [FilePath]) -> IO ([FilePath], [FilePath])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath
pathFilePath -> [FilePath] -> [FilePath]
forall a. a -> [a] -> [a]
:[FilePath]
dirs, [FilePath]
files)
   else
      ([FilePath], [FilePath]) -> IO ([FilePath], [FilePath])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([], [FilePath
path])
 where biConcat :: [([a], [a])] -> ([a], [a])
biConcat = (\([[a]]
x, [[a]]
y) -> ([[a]] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[a]]
x, [[a]] -> [a]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[a]]
y)) (([[a]], [[a]]) -> ([a], [a]))
-> ([([a], [a])] -> ([[a]], [[a]])) -> [([a], [a])] -> ([a], [a])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [([a], [a])] -> ([[a]], [[a]])
forall a b. [(a, b)] -> ([a], [b])
unzip

directoryFilesRecursive :: FilePath -- ^ dir path to be searched for recursively
                        -> IO [FilePath] -- ^ list of all files in that dir
directoryFilesRecursive :: FilePath -> IO [FilePath]
directoryFilesRecursive FilePath
path = ([FilePath], [FilePath]) -> [FilePath]
forall a b. (a, b) -> b
snd (([FilePath], [FilePath]) -> [FilePath])
-> IO ([FilePath], [FilePath]) -> IO [FilePath]
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` FilePath -> IO ([FilePath], [FilePath])
directoryEntriesRecursive FilePath
path

-- | Check recursively time of modification of any file(or dir) in directory
getRecursiveMTime :: FilePath -> IO UTCTime
getRecursiveMTime :: FilePath -> IO UTCTime
getRecursiveMTime FilePath
path = do
  ([FilePath]
dirs, [FilePath]
files) <- FilePath -> IO ([FilePath], [FilePath])
directoryEntriesRecursive FilePath
path
  [UTCTime]
mtimes <- (FilePath -> IO UTCTime) -> [FilePath] -> IO [UTCTime]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM FilePath -> IO UTCTime
getModificationTime ([FilePath] -> IO [UTCTime]) -> [FilePath] -> IO [UTCTime]
forall a b. (a -> b) -> a -> b
$ [FilePath]
dirs [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++ [FilePath]
files
  UTCTime -> IO UTCTime
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (UTCTime -> IO UTCTime) -> UTCTime -> IO UTCTime
forall a b. (a -> b) -> a -> b
$ [UTCTime] -> UTCTime
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [UTCTime]
mtimes