packages feed

posix-paths 0.2.1.6 → 0.3.0.0

raw patch · 2 files changed

+78/−41 lines, 2 filesdep +unliftioPVP ok

version bump matches the API change (PVP)

Dependencies added: unliftio

API changes (from Hackage documentation)

+ System.Posix.Directory.Traversals: traverseDirectoryContents :: MonadUnliftIO m => (s -> (DirType, RawFilePath) -> m s) -> s -> RawFilePath -> m s
- System.Posix.Directory.Traversals: traverseDirectory :: (s -> RawFilePath -> IO s) -> s -> RawFilePath -> IO s
+ System.Posix.Directory.Traversals: traverseDirectory :: MonadUnliftIO m => (s -> RawFilePath -> m s) -> s -> RawFilePath -> m s

Files

posix-paths.cabal view
@@ -1,5 +1,5 @@ name:  posix-paths-version:  0.2.1.6+version:  0.3.0.0 license: BSD3 license-file: LICENSE maintainer: jwlato@gmail.com@@ -27,7 +27,8 @@                         System.Posix.FilePath     build-depends:      base >= 4.2 && < 5,                         bytestring >= 0.9.2.0,-                        unix >= 2.5.1.0+                        unix >= 2.5.1.0,+                        unliftio >= 0.2  test-suite doctests     default-language:   Haskell2010
src/System/Posix/Directory/Traversals.hs view
@@ -7,6 +7,7 @@ module System.Posix.Directory.Traversals (    getDirectoryContents+, traverseDirectoryContents  , allDirectoryContents , allDirectoryContents'@@ -22,16 +23,18 @@  import Control.Applicative import Control.Monad+import Control.Monad.IO.Class (liftIO) import System.Posix.FilePath ((</>)) import System.Posix.Directory.Foreign  import qualified System.Posix as Posix import System.IO.Error-import Control.Exception import qualified Data.ByteString.Char8 as BS import System.Posix.ByteString.FilePath import System.Posix.Directory.ByteString as PosixBS import System.Posix.Files.ByteString+import UnliftIO (MonadUnliftIO, withRunInIO)+import UnliftIO.Exception  import System.IO.Unsafe import Unsafe.Coerce (unsafeCoerce)@@ -71,20 +74,25 @@ -- this uses traverseDirectory because it's more efficient than forcing the -- lazy version. --- | Recursively apply the 'action' to the parent directory and all+-- | Recursively apply the 'action' to the parent file or directory and all -- files/subdirectories. --+-- Like UNIX @find@, this includes the parent file/directory!+--+-- As for @find@, emitted file paths of subdirectories contain slashes,+-- starting with the parent directory.+-- -- This function allows for memory-efficient traversals.-traverseDirectory :: (s -> RawFilePath -> IO s) -> s -> RawFilePath -> IO s-traverseDirectory act s0 topdir = toploop+traverseDirectory :: (MonadUnliftIO m) => (s -> RawFilePath -> m s) -> s -> RawFilePath -> m s+traverseDirectory act s0 topDirOrFile = toploop   where     toploop = do-        isDir <- isDirectory <$> getFileStatus topdir-        s' <- act s0 topdir-        if isDir then actOnDirContents topdir s' loop+        isDir <- liftIO $ isDirectory <$> getFileStatus topDirOrFile+        s' <- act s0 topDirOrFile+        if isDir then actOnDirContents topDirOrFile s' loop                  else return s'     loop typ path acc = do-        isDir <- case () of+        isDir <- liftIO $ case () of             () | typ == dtDir     -> return True                | typ == dtUnknown -> isDirectory <$> getFileStatus path                | otherwise        -> return False@@ -92,27 +100,22 @@           then act acc path >>= \acc' -> actOnDirContents path acc' loop           else act acc path -actOnDirContents :: RawFilePath+actOnDirContents :: (MonadUnliftIO m)+                 => RawFilePath                  -> b-                 -> (DirType -> RawFilePath -> b -> IO b)-                 -> IO b+                 -> (DirType -> RawFilePath -> b -> m b)+                 -> m b actOnDirContents pathRelToTop b f =-  modifyIOError ((`ioeSetFileName` (BS.unpack pathRelToTop)) .-                 (`ioeSetLocation` "findBSTypRel")) $ do-    bracket-      (openDirStream pathRelToTop)-      (Posix.closeDirStream)-      (\dirp -> loop dirp b)- where-  loop dirp b' = do-    (typ,e) <- readDirEnt dirp-    if (e == "")-      then return b'-      else do-          if (e == "." || e == "..")-              then loop dirp b'-              else f typ (pathRelToTop </> e) b' >>= loop dirp+  traverseDirectoryContents+    (\b' (typ, e) -> f typ (pathRelToTop </> e) b')+    b+    pathRelToTop +-- | `withRunInIO` lifted to `MonadUnliftIO`.+modifyIOErrorUnliftIO :: (MonadUnliftIO m) => (IOError -> IOError) -> m a -> m a+modifyIOErrorUnliftIO f action =+  withRunInIO $ \runInIO -> do+    modifyIOError f (runInIO action)  ---------------------------------------------------------- -- dodgy stuff@@ -131,7 +134,13 @@  -- the __hscore_* functions are defined in the unix package.  We can import them and let -- the linker figure it out.-foreign import ccall unsafe "__hscore_readdir"+--+-- In contrast to current `unix` we use `safe` calls for anything that+-- does file system IO, because it can take a substantial amount of time+-- on spinning disks or networked file systems, and `unsafe` calls block+-- a capability.+-- See https://github.com/haskell/unix/issues/34.+foreign import ccall safe "__hscore_readdir"   c_readdir  :: Ptr CDir -> Ptr (Ptr CDirent) -> IO CInt  foreign import ccall unsafe "__hscore_free_dirent"@@ -176,20 +185,47 @@                     then return (dtUnknown,BS.empty)                     else throwErrno "readDirEnt" +-- | Apply the 'action' to the given directory (must be a directory),+-- without recursing into subdirectories.+--+-- This function does filter out the @.@ and @..@ entries.+--+-- Emitted file paths are the directory entry names,+-- thus not prefixed with the given parent directory.+--+-- This function allows for memory-efficient traversals.+--+-- Use this if you want to implement your own recursive subdirectory+-- traversal, deciding e.g. into which directories or symlinks to traverse.+--+-- You SHOULD check if the obtained 'DirType'+-- is 'System.Posix.Directory.Foreign.dtUnknown'+-- (see comments in @man 3 readdir@ on @d_type@),+-- and do a 'System.Posix.Files.ByteString.getFileStatus'+-- in that case (results in @stat()@), as not all file systems+-- implement obtaining a 'DirType'.+traverseDirectoryContents :: (MonadUnliftIO m) => (s -> (DirType, RawFilePath) -> m s) -> s -> RawFilePath -> m s+traverseDirectoryContents act state path =+  modifyIOErrorUnliftIO+    ((`ioeSetFileName` (BS.unpack path)) .+     (`ioeSetLocation` "System.Posix.Directory.Traversals.traverseDirectoryContents")) $ do+    bracket+      (liftIO $ PosixBS.openDirStream path)+      (liftIO . PosixBS.closeDirStream)+      (\dirp -> loop state dirp)+  where+   loop state0 dirp = do+      t@(_typ,e) <- liftIO $ readDirEnt dirp+      if BS.null e then return state0 else do+        if (e == "." || e == "..")+          then loop state0 dirp+          else do+            state1 <- act state0 t+            loop state1 dirp+ getDirectoryContents :: RawFilePath -> IO [(DirType, RawFilePath)] getDirectoryContents path =-  modifyIOError ((`ioeSetFileName` (BS.unpack path)) .-                 (`ioeSetLocation` "System.Posix.Directory.Traversals.getDirectoryContents")) $ do-    bracket-      (PosixBS.openDirStream path)-      PosixBS.closeDirStream-      loop- where-  loop dirp = do-     t@(_typ,e) <- readDirEnt dirp-     if BS.null e then return [] else do-       es <- loop dirp-       return (t:es)+  traverseDirectoryContents (\l e -> pure (e:l)) [] path  -- | return the canonicalized absolute pathname --