module RawFilePath.Directory
( RawFilePath
, doesPathExist
, doesFileExist
, doesDirectoryExist
, getHomeDirectory
, getTemporaryDirectory
, listDirectory
, getDirectoryFiles
, getDirectoryFilesRecursive
, createDirectory
, createDirectoryIfMissing
, removeFile
, tryRemoveFile
, removeDirectory
, removeDirectoryRecursive
) where
import RawFilePath.Import
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as B8
import qualified System.Posix.ByteString as U
import RawFilePath.Directory.Internal
doesPathExist :: RawFilePath -> IO Bool
doesPathExist :: RawFilePath -> IO Bool
doesPathExist RawFilePath
path = (Bool
True forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ RawFilePath -> IO FileStatus
U.getFileStatus RawFilePath
path) forall a. IO a -> (IOError -> IO a) -> IO a
`catchIOError`
forall a b. a -> b -> a
const (forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False)
doesDirectoryExist :: RawFilePath -> IO Bool
doesDirectoryExist :: RawFilePath -> IO Bool
doesDirectoryExist RawFilePath
path = RawFilePath -> IO Bool
pathIsDirectory RawFilePath
path forall a. IO a -> (IOError -> IO a) -> IO a
`catchIOError`
forall a b. a -> b -> a
const (forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False)
doesFileExist :: RawFilePath -> IO Bool
doesFileExist :: RawFilePath -> IO Bool
doesFileExist RawFilePath
path = (Bool -> Bool
not forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RawFilePath -> IO Bool
pathIsDirectory RawFilePath
path) forall a. IO a -> (IOError -> IO a) -> IO a
`catchIOError`
forall a b. a -> b -> a
const (forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False)
getHomeDirectory :: IO (Maybe RawFilePath)
getHomeDirectory :: IO (Maybe RawFilePath)
getHomeDirectory = RawFilePath -> IO (Maybe RawFilePath)
U.getEnv RawFilePath
"HOME"
getTemporaryDirectory :: IO ByteString
getTemporaryDirectory :: IO RawFilePath
getTemporaryDirectory = forall a. a -> Maybe a -> a
fromMaybe RawFilePath
"/tmp" forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RawFilePath -> IO (Maybe RawFilePath)
U.getEnv RawFilePath
"TMPDIR"
listDirectory
:: RawFilePath
-> IO [RawFilePath]
listDirectory :: RawFilePath -> IO [RawFilePath]
listDirectory RawFilePath
dirPath = forall a. (a -> Bool) -> [a] -> [a]
filter forall {a}. (Eq a, IsString a) => a -> Bool
f forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RawFilePath -> IO [RawFilePath]
getDirectoryFiles RawFilePath
dirPath
where
f :: a -> Bool
f a
p = a
p forall a. Eq a => a -> a -> Bool
/= a
"." Bool -> Bool -> Bool
&& a
p forall a. Eq a => a -> a -> Bool
/= a
".."
getDirectoryFiles
:: RawFilePath
-> IO [RawFilePath]
getDirectoryFiles :: RawFilePath -> IO [RawFilePath]
getDirectoryFiles RawFilePath
dirPath = forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket IO DirStream
open DirStream -> IO ()
close DirStream -> IO [RawFilePath]
repeatRead
where
open :: IO DirStream
open = RawFilePath -> IO DirStream
U.openDirStream RawFilePath
dirPath
close :: DirStream -> IO ()
close = DirStream -> IO ()
U.closeDirStream
repeatRead :: DirStream -> IO [RawFilePath]
repeatRead DirStream
stream = do
RawFilePath
d <- DirStream -> IO RawFilePath
U.readDirStream DirStream
stream
if RawFilePath -> Int
B.length RawFilePath
d forall a. Eq a => a -> a -> Bool
== Int
0 then forall (m :: * -> *) a. Monad m => a -> m a
return [] else do
[RawFilePath]
rest <- DirStream -> IO [RawFilePath]
repeatRead DirStream
stream
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ RawFilePath
d forall a. a -> [a] -> [a]
: [RawFilePath]
rest
getDirectoryFilesRecursive
:: RawFilePath
-> IO [RawFilePath]
getDirectoryFilesRecursive :: RawFilePath -> IO [RawFilePath]
getDirectoryFilesRecursive RawFilePath
path = do
[RawFilePath]
names <- forall a b. (a -> b) -> [a] -> [b]
map (RawFilePath
path RawFilePath -> RawFilePath -> RawFilePath
+/+) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
filter (\RawFilePath
x -> RawFilePath
x forall a. Eq a => a -> a -> Bool
/= RawFilePath
".." Bool -> Bool -> Bool
&& RawFilePath
x forall a. Eq a => a -> a -> Bool
/= RawFilePath
".") forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
RawFilePath -> IO [RawFilePath]
getDirectoryFiles RawFilePath
path
[[RawFilePath]]
inspectedNames <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM RawFilePath -> IO [RawFilePath]
inspect [RawFilePath]
names
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[RawFilePath]]
inspectedNames
where
inspect :: RawFilePath -> IO [RawFilePath]
inspect :: RawFilePath -> IO [RawFilePath]
inspect RawFilePath
p = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap FileStatus -> Bool
U.isDirectory (RawFilePath -> IO FileStatus
U.getFileStatus RawFilePath
p) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Bool
i -> if Bool
i
then RawFilePath -> IO [RawFilePath]
getDirectoryFilesRecursive RawFilePath
p else forall (m :: * -> *) a. Monad m => a -> m a
return [RawFilePath
p]
createDirectory :: RawFilePath -> IO ()
createDirectory :: RawFilePath -> IO ()
createDirectory RawFilePath
dir = RawFilePath -> FileMode -> IO ()
U.createDirectory RawFilePath
dir FileMode
0o755
createDirectoryIfMissing
:: Bool
-> RawFilePath
-> IO ()
createDirectoryIfMissing :: Bool -> RawFilePath -> IO ()
createDirectoryIfMissing Bool
willCreateParents RawFilePath
path
| Bool
willCreateParents = [RawFilePath] -> IO ()
createDirs [RawFilePath]
parents
| Bool
otherwise = RawFilePath -> (IOError -> IO ()) -> IO ()
createDir RawFilePath
path forall a. IOError -> IO a
ioError
where
createDirs :: [RawFilePath] -> IO ()
createDirs [] = forall (m :: * -> *) a. Monad m => a -> m a
return ()
createDirs [RawFilePath
dir] = RawFilePath -> (IOError -> IO ()) -> IO ()
createDir RawFilePath
dir forall a. IOError -> IO a
ioError
createDirs (RawFilePath
dir : [RawFilePath]
dirs) = RawFilePath -> (IOError -> IO ()) -> IO ()
createDir RawFilePath
dir forall a b. (a -> b) -> a -> b
$ \ IOError
_ ->
[RawFilePath] -> IO ()
createDirs [RawFilePath]
dirs forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> RawFilePath -> (IOError -> IO ()) -> IO ()
createDir RawFilePath
dir forall a. IOError -> IO a
ioError
createDir :: RawFilePath -> (IOError -> IO ()) -> IO ()
createDir RawFilePath
dir IOError -> IO ()
notExistHandler = forall a. IO a -> IO (Either IOError a)
tryIOError (RawFilePath -> IO ()
createDirectory RawFilePath
dir) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \ case
Right () -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
Left IOError
e
| IOError -> Bool
isDoesNotExistError IOError
e -> IOError -> IO ()
notExistHandler IOError
e
| IOError -> Bool
isAlreadyExistsError IOError
e
Bool -> Bool -> Bool
|| IOError -> Bool
isPermissionError IOError
e -> do
Bool
canIgnore <- forall a. IO a -> (IOError -> IO a) -> IO a
catchIOError (RawFilePath -> IO Bool
pathIsDirectory RawFilePath
dir) forall a b. (a -> b) -> a -> b
$ \ IOError
_ ->
forall (m :: * -> *) a. Monad m => a -> m a
return (IOError -> Bool
isAlreadyExistsError IOError
e)
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
canIgnore (forall a. IOError -> IO a
ioError IOError
e)
| Bool
otherwise -> forall a. IOError -> IO a
ioError IOError
e
parents :: [RawFilePath]
parents = forall a. [a] -> [a]
reverse forall a b. (a -> b) -> a -> b
$ forall a. (a -> a -> a) -> [a] -> [a]
scanl1 RawFilePath -> RawFilePath -> RawFilePath
(+/+) forall a b. (a -> b) -> a -> b
$ Word8 -> RawFilePath -> [RawFilePath]
B.split (Char -> Word8
w8 Char
'/') forall a b. (a -> b) -> a -> b
$ RawFilePath -> RawFilePath
stripSlash RawFilePath
path
removeFile :: RawFilePath -> IO ()
removeFile :: RawFilePath -> IO ()
removeFile = RawFilePath -> IO ()
U.removeLink
tryRemoveFile :: RawFilePath -> IO ()
tryRemoveFile :: RawFilePath -> IO ()
tryRemoveFile RawFilePath
path = forall a. IO a -> (IOError -> IO a) -> IO a
catchIOError (RawFilePath -> IO ()
U.removeLink RawFilePath
path) forall a b. (a -> b) -> a -> b
$
\ IOError
e -> forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (IOError -> Bool
isDoesNotExistError IOError
e) forall a b. (a -> b) -> a -> b
$ forall a. IOError -> IO a
ioError IOError
e
removeDirectory :: RawFilePath -> IO ()
removeDirectory :: RawFilePath -> IO ()
removeDirectory = RawFilePath -> IO ()
U.removeDirectory
removeDirectoryRecursive :: RawFilePath -> IO ()
removeDirectoryRecursive :: RawFilePath -> IO ()
removeDirectoryRecursive RawFilePath
path =
(IOError -> String -> IOError
`ioeAddLocation` String
"removeDirectoryRecursive") forall a. (IOError -> IOError) -> IO a -> IO a
`modifyIOError` do
FileStatus
m <- RawFilePath -> IO FileStatus
U.getSymbolicLinkStatus RawFilePath
path
case FileStatus -> FileType
fileTypeFromMetadata FileStatus
m of
FileType
Directory ->
RawFilePath -> IO ()
removeContentsRecursive RawFilePath
path
FileType
DirectoryLink ->
forall a. IOError -> IO a
ioError (IOError
err IOError -> String -> IOError
`ioeSetErrorString` String
"is a directory symbolic link")
FileType
_ ->
forall a. IOError -> IO a
ioError (IOError
err IOError -> String -> IOError
`ioeSetErrorString` String
"not a directory")
where err :: IOError
err = IOErrorType -> String -> Maybe Handle -> Maybe String -> IOError
mkIOError IOErrorType
InappropriateType String
"" forall a. Maybe a
Nothing (forall a. a -> Maybe a
Just (RawFilePath -> String
B8.unpack RawFilePath
path))
removePathRecursive :: RawFilePath -> IO ()
removePathRecursive :: RawFilePath -> IO ()
removePathRecursive RawFilePath
path =
(IOError -> String -> IOError
`ioeAddLocation` String
"removePathRecursive") forall a. (IOError -> IOError) -> IO a -> IO a
`modifyIOError` do
FileStatus
m <- RawFilePath -> IO FileStatus
U.getSymbolicLinkStatus RawFilePath
path
case FileStatus -> FileType
fileTypeFromMetadata FileStatus
m of
FileType
Directory -> RawFilePath -> IO ()
removeContentsRecursive RawFilePath
path
FileType
DirectoryLink -> RawFilePath -> IO ()
U.removeDirectory RawFilePath
path
FileType
_ -> RawFilePath -> IO ()
U.removeLink RawFilePath
path
removeContentsRecursive :: RawFilePath -> IO ()
removeContentsRecursive :: RawFilePath -> IO ()
removeContentsRecursive RawFilePath
path =
(IOError -> String -> IOError
`ioeAddLocation` String
"removeContentsRecursive") forall a. (IOError -> IOError) -> IO a -> IO a
`modifyIOError` do
[RawFilePath]
cont <- RawFilePath -> IO [RawFilePath]
listDirectory RawFilePath
path
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ RawFilePath -> IO ()
removePathRecursive [RawFilePath
path RawFilePath -> RawFilePath -> RawFilePath
+/+ RawFilePath
x | RawFilePath
x <- [RawFilePath]
cont]
RawFilePath -> IO ()
U.removeDirectory RawFilePath
path
w8 :: Char -> Word8
w8 :: Char -> Word8
w8 = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
ord
stripSlash :: ByteString -> ByteString
stripSlash :: RawFilePath -> RawFilePath
stripSlash RawFilePath
p = if HasCallStack => RawFilePath -> Word8
B.last RawFilePath
p forall a. Eq a => a -> a -> Bool
== Char -> Word8
w8 Char
'/' then HasCallStack => RawFilePath -> RawFilePath
B.init RawFilePath
p else RawFilePath
p
pathIsDirectory :: RawFilePath -> IO Bool
pathIsDirectory :: RawFilePath -> IO Bool
pathIsDirectory RawFilePath
path = FileStatus -> Bool
U.isDirectory forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RawFilePath -> IO FileStatus
U.getFileStatus RawFilePath
path
infixr 5 +/+
(+/+) :: RawFilePath -> RawFilePath -> RawFilePath
RawFilePath
a +/+ :: RawFilePath -> RawFilePath -> RawFilePath
+/+ RawFilePath
b = forall a. Monoid a => [a] -> a
mconcat [RawFilePath
a, RawFilePath
"/", RawFilePath
b]