packages feed

headroom-0.1.0.0: src/Headroom/FileSystem.hs

{-|
Module      : Headroom.FileSystem
Description : Files/directories manipulation
Copyright   : (c) 2019-2020 Vaclav Svejcar
License     : BSD-3
Maintainer  : vaclav.svejcar@gmail.com
Stability   : experimental
Portability : POSIX

Functions for manipulating files and directories.
-}
{-# LANGUAGE NoImplicitPrelude #-}
module Headroom.FileSystem
  ( findFiles
  , findFilesByExts
  , findFilesByTypes
  , listFiles
  , loadFile
  )
where

import           Headroom.FileType              ( FileType
                                                , listExtensions
                                                )
import           RIO
import           RIO.Directory                  ( doesDirectoryExist
                                                , getDirectoryContents
                                                )
import           RIO.FilePath                   ( isExtensionOf
                                                , (</>)
                                                )
import qualified RIO.Text                      as T


-- | Recursively finds files on given path whose filename matches the predicate.
findFiles :: MonadIO m
          => FilePath           -- ^ path to search
          -> (FilePath -> Bool) -- ^ predicate to match filename
          -> m [FilePath]       -- ^ found files
findFiles path predicate = fmap (filter predicate) (listFiles path)

-- | Recursively finds files on given path by file extensions.
findFilesByExts :: MonadIO m
                => FilePath     -- ^ path to search
                -> [Text]       -- ^ list of file extensions (without dot)
                -> m [FilePath] -- ^ list of found files
findFilesByExts path exts = findFiles path predicate
  where predicate p = any (`isExtensionOf` p) (fmap T.unpack exts)

-- | Recursively find files on given path by their file types.
findFilesByTypes :: MonadIO m
                 => FilePath     -- ^ path to search
                 -> [FileType]   -- ^ list of file types
                 -> m [FilePath] -- ^ list of found files
findFilesByTypes path types = findFilesByExts path (types >>= listExtensions)

-- | Recursively find all files on given path. If file reference is passed
-- instead of directory, such file path is returned.
listFiles :: MonadIO m
          => FilePath     -- ^ path to search
          -> m [FilePath] -- ^ list of found files
listFiles fileOrDir = do
  isDir <- doesDirectoryExist fileOrDir
  if isDir then listDirectory fileOrDir else return [fileOrDir]
 where
  listDirectory dir = do
    names <- getDirectoryContents dir
    let filteredNames = filter (`notElem` [".", ".."]) names
    paths <- forM filteredNames $ \name -> do
      let path = dir </> name
      isDirectory <- doesDirectoryExist path
      if isDirectory then listFiles path else return [path]
    return $ concat paths

-- | Loads file content in UTF8 encoding.
loadFile :: MonadIO m
         => FilePath -- ^ file path
         -> m Text   -- ^ file content
loadFile = readFileUtf8