module Path.IO
(getWorkingDir
,listDirectory
,resolveDir
,resolveFile
,resolveDirMaybe
,resolveFileMaybe
,ResolveException(..)
,removeFileIfExists
,removeTree
,removeTreeIfExists
,fileExists
,renameFileIfExists
,renameDirIfExists
,moveFileIfExists
,moveDirIfExists
,dirExists
,copyDirectoryRecursive
,createTree)
where
import Control.Exception hiding (catch)
import Control.Monad
import Control.Monad.Catch
import Control.Monad.IO.Class
import Data.Either
import Data.Maybe
import Data.Typeable
import Path
import System.Directory
import qualified System.FilePath as FP
import System.IO.Error
data ResolveException
= ResolveDirFailed (Path Abs Dir) FilePath FilePath
| ResolveFileFailed (Path Abs Dir) FilePath FilePath
deriving Typeable
instance Exception ResolveException
instance Show ResolveException where
show (ResolveDirFailed _ _ z) = "Could not resolve directory " ++ z
show (ResolveFileFailed _ _ z) = "Could not resolve file " ++ z
getWorkingDir :: (MonadIO m) => m (Path Abs Dir)
getWorkingDir = liftIO (canonicalizePath "." >>= parseAbsDir)
resolveDir :: (MonadIO m, MonadThrow m) => Path Abs Dir -> FilePath -> m (Path Abs Dir)
resolveDir x y =
do result <- resolveDirMaybe x y
case result of
Nothing ->
throwM $ ResolveDirFailed x y fp
where fp = toFilePath x FP.</> y
Just fp -> return fp
resolveFile :: (MonadIO m, MonadThrow m) => Path Abs Dir -> FilePath -> m (Path Abs File)
resolveFile x y =
do result <- resolveFileMaybe x y
case result of
Nothing ->
throwM $
ResolveFileFailed x y fp
where fp = toFilePath x FP.</> y
Just fp -> return fp
resolveDirMaybe :: (MonadIO m,MonadThrow m)
=> Path Abs Dir -> FilePath -> m (Maybe (Path Abs Dir))
resolveDirMaybe x y = do
let fp = toFilePath x FP.</> y
exists <- liftIO $ doesDirectoryExist fp
if exists
then do
dir <- liftIO $ canonicalizePath fp
liftM Just (parseAbsDir dir)
else return Nothing
resolveFileMaybe :: (MonadIO m,MonadThrow m)
=> Path Abs Dir -> FilePath -> m (Maybe (Path Abs File))
resolveFileMaybe x y = do
let fp = toFilePath x FP.</> y
exists <- liftIO $ doesFileExist fp
if exists
then do
file <- liftIO $ canonicalizePath fp
liftM Just (parseAbsFile file)
else return Nothing
listDirectory :: (MonadIO m,MonadThrow m) => Path Abs Dir -> m ([Path Abs Dir],[Path Abs File])
listDirectory dir =
do entriesFP <- liftIO (getDirectoryContents dirFP)
maybeEntries <-
forM (map (dirFP ++) entriesFP)
(\entryFP ->
do isDir <- liftIO (doesDirectoryExist entryFP)
if isDir
then case parseAbsDir entryFP of
Nothing -> return Nothing
Just entryDir ->
if dir `isParentOf` entryDir
then return (Just (Left entryDir))
else return Nothing
else case parseAbsFile entryFP of
Nothing -> return Nothing
Just entryFile -> return (Just (Right entryFile)))
let entries = catMaybes maybeEntries
return (lefts entries,rights entries)
where dirFP = toFilePath dir
removeFileIfExists :: MonadIO m => Path b File -> m ()
removeFileIfExists fp =
liftIO (catch
(removeFile
(toFilePath fp))
(\e ->
if isDoesNotExistError e
then return ()
else throwIO e))
renameFileIfExists :: MonadIO m => Path b File -> Path b File -> m ()
renameFileIfExists from to =
liftIO
(catch
(renameFile (toFilePath from)
(toFilePath to))
(\e ->
if isDoesNotExistError e
then return ()
else throwIO e))
renameDirIfExists :: MonadIO m => Path b Dir -> Path b Dir -> m ()
renameDirIfExists from to =
liftIO
(catch
(renameDirectory (toFilePath from)
(toFilePath to))
(\e ->
if isDoesNotExistError e
then return ()
else throwIO e))
createTree :: MonadIO m => Path b Dir -> m ()
createTree = liftIO . createDirectoryIfMissing True . toFilePath
moveFileIfExists :: MonadIO m => Path b File -> Path b Dir -> m ()
moveFileIfExists from to =
liftIO
(catch
(renameFile (toFilePath from)
(toFilePath (to </> filename from)))
(\e ->
if isDoesNotExistError e
then return ()
else throwIO e))
moveDirIfExists :: MonadIO m => Path b Dir -> Path b Dir -> m ()
moveDirIfExists from to =
liftIO
(catch
(renameDirectory
(toFilePath from)
(toFilePath (to </> dirname from)))
(\e ->
if isDoesNotExistError e
then return ()
else throwIO e))
removeTree :: MonadIO m => Path b Dir -> m ()
removeTree =
liftIO . removeDirectoryRecursive . toFilePath
removeTreeIfExists :: MonadIO m => Path b Dir -> m ()
removeTreeIfExists fp = do
liftIO (catch (removeTree fp)
(\e -> if isDoesNotExistError e
then return ()
else throwIO e))
fileExists :: MonadIO m => Path b File -> m Bool
fileExists =
liftIO . doesFileExist . toFilePath
dirExists :: MonadIO m => Path b Dir -> m Bool
dirExists =
liftIO . doesDirectoryExist . toFilePath
copyDirectoryRecursive :: (MonadIO m,MonadThrow m)
=> Path Abs Dir
-> Path Abs Dir
-> m ()
copyDirectoryRecursive srcDir destDir =
do liftIO (createDirectoryIfMissing False (toFilePath destDir))
(srcSubDirs,srcFiles) <- listDirectory srcDir
forM_ srcFiles
(\srcFile ->
case stripDir srcDir srcFile of
Nothing -> return ()
Just relFile -> liftIO (copyFile (toFilePath srcFile)
(toFilePath (destDir </> relFile))))
forM_ srcSubDirs
(\srcSubDir ->
case stripDir srcDir srcSubDir of
Nothing -> return ()
Just relSubDir -> copyDirectoryRecursive srcSubDir (destDir </> relSubDir))