{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ViewPatterns #-}
module Headroom.FileSystem
(
CreateDirectoryFn
, DoesFileExistFn
, FindFilesFn
, FindFilesByExtsFn
, FindFilesByTypesFn
, GetCurrentDirectoryFn
, ListFilesFn
, LoadFileFn
, FileSystem(..)
, mkFileSystem
, findFiles
, findFilesByExts
, findFilesByTypes
, listFiles
, loadFile
, fileExtension
, excludePaths
)
where
import Headroom.Configuration.Types ( CtHeadersConfig )
import Headroom.Data.Regex ( Regex
, match
)
import Headroom.FileType ( listExtensions )
import Headroom.FileType.Types ( FileType )
import RIO
import RIO.Directory ( createDirectory
, doesDirectoryExist
, doesFileExist
, getCurrentDirectory
, getDirectoryContents
)
import RIO.FilePath ( isExtensionOf
, takeExtension
, (</>)
)
import qualified RIO.List as L
import qualified RIO.Text as T
type CreateDirectoryFn m
= FilePath
-> m ()
type DoesFileExistFn m
= FilePath
-> m Bool
type FindFilesFn m
= FilePath
-> (FilePath -> Bool)
-> m [FilePath]
type FindFilesByExtsFn m
= FilePath
-> [Text]
-> m [FilePath]
type FindFilesByTypesFn m
= CtHeadersConfig
-> [FileType]
-> FilePath
-> m [FilePath]
type GetCurrentDirectoryFn m = m FilePath
type ListFilesFn m
= FilePath
-> m [FilePath]
type LoadFileFn m
= FilePath
-> m Text
data FileSystem m = FileSystem
{ FileSystem m -> CreateDirectoryFn m
fsCreateDirectory :: CreateDirectoryFn m
, FileSystem m -> DoesFileExistFn m
fsDoesFileExist :: DoesFileExistFn m
, FileSystem m -> FindFilesFn m
fsFindFiles :: FindFilesFn m
, FileSystem m -> FindFilesByExtsFn m
fsFindFilesByExts :: FindFilesByExtsFn m
, FileSystem m -> FindFilesByTypesFn m
fsFindFilesByTypes :: FindFilesByTypesFn m
, FileSystem m -> GetCurrentDirectoryFn m
fsGetCurrentDirectory :: GetCurrentDirectoryFn m
, FileSystem m -> ListFilesFn m
fsListFiles :: ListFilesFn m
, FileSystem m -> LoadFileFn m
fsLoadFile :: LoadFileFn m
}
mkFileSystem :: MonadIO m => FileSystem m
mkFileSystem :: FileSystem m
mkFileSystem = FileSystem :: forall (m :: * -> *).
CreateDirectoryFn m
-> DoesFileExistFn m
-> FindFilesFn m
-> FindFilesByExtsFn m
-> FindFilesByTypesFn m
-> GetCurrentDirectoryFn m
-> ListFilesFn m
-> LoadFileFn m
-> FileSystem m
FileSystem { fsCreateDirectory :: CreateDirectoryFn m
fsCreateDirectory = CreateDirectoryFn m
forall (m :: * -> *). MonadIO m => FilePath -> m ()
createDirectory
, fsDoesFileExist :: DoesFileExistFn m
fsDoesFileExist = DoesFileExistFn m
forall (m :: * -> *). MonadIO m => FilePath -> m Bool
doesFileExist
, fsFindFiles :: FindFilesFn m
fsFindFiles = FindFilesFn m
forall (m :: * -> *). MonadIO m => FindFilesFn m
findFiles
, fsFindFilesByExts :: FindFilesByExtsFn m
fsFindFilesByExts = FindFilesByExtsFn m
forall (m :: * -> *). MonadIO m => FindFilesByExtsFn m
findFilesByExts
, fsFindFilesByTypes :: FindFilesByTypesFn m
fsFindFilesByTypes = FindFilesByTypesFn m
forall (m :: * -> *). MonadIO m => FindFilesByTypesFn m
findFilesByTypes
, fsGetCurrentDirectory :: GetCurrentDirectoryFn m
fsGetCurrentDirectory = GetCurrentDirectoryFn m
forall (m :: * -> *). MonadIO m => m FilePath
getCurrentDirectory
, fsListFiles :: ListFilesFn m
fsListFiles = ListFilesFn m
forall (m :: * -> *). MonadIO m => ListFilesFn m
listFiles
, fsLoadFile :: LoadFileFn m
fsLoadFile = LoadFileFn m
forall (m :: * -> *). MonadIO m => LoadFileFn m
loadFile
}
findFiles :: MonadIO m => FindFilesFn m
findFiles :: FindFilesFn m
findFiles FilePath
path FilePath -> Bool
predicate = ([FilePath] -> [FilePath]) -> m [FilePath] -> m [FilePath]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((FilePath -> Bool) -> [FilePath] -> [FilePath]
forall a. (a -> Bool) -> [a] -> [a]
filter FilePath -> Bool
predicate) (ListFilesFn m
forall (m :: * -> *). MonadIO m => ListFilesFn m
listFiles FilePath
path)
findFilesByExts :: MonadIO m => FindFilesByExtsFn m
findFilesByExts :: FindFilesByExtsFn m
findFilesByExts FilePath
path [Text]
exts = FindFilesFn m
forall (m :: * -> *). MonadIO m => FindFilesFn m
findFiles FilePath
path FilePath -> Bool
predicate
where predicate :: FilePath -> Bool
predicate FilePath
p = (FilePath -> Bool) -> [FilePath] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (FilePath -> FilePath -> Bool
`isExtensionOf` FilePath
p) ((Text -> FilePath) -> [Text] -> [FilePath]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> FilePath
T.unpack [Text]
exts)
findFilesByTypes :: MonadIO m => FindFilesByTypesFn m
findFilesByTypes :: FindFilesByTypesFn m
findFilesByTypes CtHeadersConfig
headersConfig [FileType]
types FilePath
path =
FindFilesByExtsFn m
forall (m :: * -> *). MonadIO m => FindFilesByExtsFn m
findFilesByExts FilePath
path ([FileType]
types [FileType] -> (FileType -> [Text]) -> [Text]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CtHeadersConfig -> FileType -> [Text]
listExtensions CtHeadersConfig
headersConfig)
listFiles :: MonadIO m => ListFilesFn m
listFiles :: ListFilesFn m
listFiles FilePath
fileOrDir = do
Bool
isDir <- FilePath -> m Bool
forall (m :: * -> *). MonadIO m => FilePath -> m Bool
doesDirectoryExist FilePath
fileOrDir
if Bool
isDir then ListFilesFn m
forall (m :: * -> *). MonadIO m => ListFilesFn m
listDirectory FilePath
fileOrDir else [FilePath] -> m [FilePath]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [FilePath
fileOrDir]
where
listDirectory :: FilePath -> m [FilePath]
listDirectory FilePath
dir = do
[FilePath]
names <- FilePath -> m [FilePath]
forall (m :: * -> *). MonadIO m => ListFilesFn m
getDirectoryContents FilePath
dir
let filteredNames :: [FilePath]
filteredNames = (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]]
paths <- [FilePath] -> (FilePath -> m [FilePath]) -> m [[FilePath]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [FilePath]
filteredNames ((FilePath -> m [FilePath]) -> m [[FilePath]])
-> (FilePath -> m [FilePath]) -> m [[FilePath]]
forall a b. (a -> b) -> a -> b
$ \FilePath
name -> do
let path :: FilePath
path = FilePath
dir FilePath -> FilePath -> FilePath
</> FilePath
name
Bool
isDirectory <- FilePath -> m Bool
forall (m :: * -> *). MonadIO m => FilePath -> m Bool
doesDirectoryExist FilePath
path
if Bool
isDirectory then FilePath -> m [FilePath]
forall (m :: * -> *). MonadIO m => ListFilesFn m
listFiles FilePath
path else [FilePath] -> m [FilePath]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [FilePath
path]
[FilePath] -> m [FilePath]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([FilePath] -> m [FilePath]) -> [FilePath] -> m [FilePath]
forall a b. (a -> b) -> a -> b
$ [[FilePath]] -> [FilePath]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[FilePath]]
paths
fileExtension :: FilePath
-> Maybe Text
fileExtension :: FilePath -> Maybe Text
fileExtension (FilePath -> FilePath
takeExtension -> Char
'.' : FilePath
xs) = Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ FilePath -> Text
T.pack FilePath
xs
fileExtension FilePath
_ = Maybe Text
forall a. Maybe a
Nothing
loadFile :: MonadIO m => LoadFileFn m
loadFile :: LoadFileFn m
loadFile = LoadFileFn m
forall (m :: * -> *). MonadIO m => LoadFileFn m
readFileUtf8
excludePaths :: [Regex]
-> [FilePath]
-> [FilePath]
excludePaths :: [Regex] -> [FilePath] -> [FilePath]
excludePaths [Regex]
_ [] = []
excludePaths [] [FilePath]
paths = [FilePath]
paths
excludePaths [Regex]
patterns [FilePath]
paths = (FilePath -> Bool) -> [FilePath] -> [FilePath]
forall a. (a -> Bool) -> [a] -> [a]
L.filter FilePath -> Bool
excluded [FilePath]
paths
where excluded :: FilePath -> Bool
excluded FilePath
item = (Regex -> Bool) -> [Regex] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (\Regex
p -> Maybe [Text] -> Bool
forall a. Maybe a -> Bool
isNothing (Maybe [Text] -> Bool) -> Maybe [Text] -> Bool
forall a b. (a -> b) -> a -> b
$ Regex -> Text -> Maybe [Text]
match Regex
p (FilePath -> Text
T.pack FilePath
item)) [Regex]
patterns