{-# LANGUAGE OverloadedStrings #-}
module Hledger.Flow.PathHelpers where
import Control.Monad.Catch (MonadThrow, Exception, throwM)
import Control.Monad.IO.Class (MonadIO)
import qualified Data.Text as T
import Path ((</>))
import qualified Path
import qualified Path.IO as Path
import qualified Turtle
import Hledger.Flow.DocHelpers (docURL)
type TurtlePath = Turtle.FilePath
type AbsFile = Path.Path Path.Abs Path.File
type RelFile = Path.Path Path.Rel Path.File
type AbsDir = Path.Path Path.Abs Path.Dir
type RelDir = Path.Path Path.Rel Path.Dir
data PathException = MissingBaseDir AbsDir | InvalidTurtleDir TurtlePath
deriving (Eq)
instance Show PathException where
show (MissingBaseDir d) = "Unable to find an import directory at " ++ show d ++
" (or in any of its parent directories).\n\n" ++
"Have a look at the documentation for more information:\n" ++
T.unpack (docURL "getting-started")
show (InvalidTurtleDir d) = "Expected a directory but got this instead: " ++ Turtle.encodeString d
instance Exception PathException
fromTurtleAbsFile :: MonadThrow m => TurtlePath -> m AbsFile
fromTurtleAbsFile turtlePath = Path.parseAbsFile $ Turtle.encodeString turtlePath
fromTurtleRelFile :: MonadThrow m => TurtlePath -> m RelFile
fromTurtleRelFile turtlePath = Path.parseRelFile $ Turtle.encodeString turtlePath
fromTurtleAbsDir :: MonadThrow m => TurtlePath -> m AbsDir
fromTurtleAbsDir turtlePath = Path.parseAbsDir $ Turtle.encodeString turtlePath
fromTurtleRelDir :: MonadThrow m => TurtlePath -> m RelDir
fromTurtleRelDir turtlePath = Path.parseRelDir $ Turtle.encodeString turtlePath
turtleToAbsDir :: (MonadIO m, MonadThrow m) => AbsDir -> TurtlePath -> m AbsDir
turtleToAbsDir baseDir p = do
isDir <- Turtle.testdir p
if isDir
then Path.resolveDir baseDir $ Turtle.encodeString p
else throwM $ InvalidTurtleDir p
pathToTurtle :: Path.Path b t -> TurtlePath
pathToTurtle = Turtle.decodeString . Path.toFilePath
forceTrailingSlash :: TurtlePath -> TurtlePath
forceTrailingSlash p = Turtle.directory (p Turtle.</> "temp")
pathSize :: Path.Path b Path.Dir -> Int
pathSize p = pathSize' p 0
pathSize' :: Path.Path b Path.Dir -> Int -> Int
pathSize' p count = if Path.parent p == p then count else pathSize' (Path.parent p) (count+1)
findFilesIn :: MonadIO m
=> (AbsDir -> Bool)
-> [RelDir]
-> AbsDir
-> m [AbsFile]
findFilesIn includePred excludeDirs = Path.walkDirAccum (Just excludeHandler) accumulator
where excludeHandler currentDir _ _ = return $ Path.WalkExclude (map (currentDir </>) excludeDirs)
accumulator currentDir _ files =
if includePred currentDir
then return $ excludeHiddenFiles files
else return []
excludeHiddenFiles :: [AbsFile] -> [AbsFile]
excludeHiddenFiles = filter (\ f -> head (Path.toFilePath (Path.filename f)) /= '.')