module Darcs.Util.File
(
getFileStatus
, withCurrentDirectory
, doesDirectoryReallyExist
, removeFileMayNotExist
, xdgCacheDir
, osxCacheDir
, getDirectoryContents
, getRecursiveContents
, getRecursiveContentsFullPath
) where
import Prelude ( lookup )
import Darcs.Prelude
import Control.Exception ( catch, bracket )
import Control.Monad ( when, unless, forM )
import System.Environment ( getEnvironment )
import System.Directory ( removeFile, getHomeDirectory,
getAppUserDataDirectory, doesDirectoryExist,
createDirectory, getDirectoryContents )
import System.IO.Error ( isDoesNotExistError, catchIOError )
import System.Posix.Files( getSymbolicLinkStatus, FileStatus, isDirectory )
#ifndef WIN32
import System.Posix.Files( setFileMode, ownerModes )
#endif
import System.FilePath.Posix ( (</>) )
import Darcs.Util.Exception ( catchall )
import Darcs.Util.Path( FilePathLike, getCurrentDirectory, setCurrentDirectory, toFilePath )
withCurrentDirectory :: FilePathLike p
=> p
-> IO a
-> IO a
withCurrentDirectory name m =
bracket
(do cwd <- getCurrentDirectory
when (toFilePath name /= "") (setCurrentDirectory name)
return cwd)
(\oldwd -> setCurrentDirectory oldwd `catchall` return ())
(const m)
getFileStatus :: FilePath -> IO (Maybe FileStatus)
getFileStatus f =
Just `fmap` getSymbolicLinkStatus f `catchIOError` (\_-> return Nothing)
doesDirectoryReallyExist :: FilePath -> IO Bool
doesDirectoryReallyExist f =
catchNonExistence (isDirectory `fmap` getSymbolicLinkStatus f) False
removeFileMayNotExist :: FilePathLike p => p -> IO ()
removeFileMayNotExist f = catchNonExistence (removeFile $ toFilePath f) ()
catchNonExistence :: IO a -> a -> IO a
catchNonExistence job nonexistval =
catch job $
\e -> if isDoesNotExistError e then return nonexistval
else ioError e
osxCacheDir :: IO (Maybe FilePath)
osxCacheDir = do
home <- getHomeDirectory
return $ Just $ home </> "Library" </> "Caches"
`catchall` return Nothing
xdgCacheDir :: IO (Maybe FilePath)
xdgCacheDir = do
env <- getEnvironment
d <- case lookup "XDG_CACHE_HOME" env of
Just d -> return d
Nothing -> getAppUserDataDirectory "cache"
exists <- doesDirectoryExist d
unless exists $ do createDirectory d
#ifndef WIN32
setFileMode d ownerModes
#endif
return $ Just d
`catchall` return Nothing
getRecursiveContents :: FilePath -> IO [FilePath]
getRecursiveContents topdir = do
names <- getDirectoryContents topdir
let properNames = filter (`notElem` [".", ".."]) names
paths <- forM properNames $ \name -> do
let path = topdir </> name
isDir <- doesDirectoryExist path
if isDir
then getRecursiveContents path
else return [name]
return (concat paths)
getRecursiveContentsFullPath :: FilePath -> IO [FilePath]
getRecursiveContentsFullPath topdir = do
names <- getDirectoryContents topdir
let properNames = filter (`notElem` [".", ".."]) names
paths <- forM properNames $ \name -> do
let path = topdir </> name
isDir <- doesDirectoryExist path
if isDir
then getRecursiveContentsFullPath path
else return [path]
return (concat paths)