From ec2fcb2c4a80dc50cf57e4044eab6b8c1dcabffe Mon Sep 17 00:00:00 2001 From: Bryan O'Sullivan Date: Mon, 30 Apr 2007 19:46:06 +0000 Subject: [PATCH] Add Manip module. --HG-- extra : convert_revision : 38d40de52e0b82b618bdaa0bffe08d89ff60d830 --- FileManip.cabal | 3 ++- System/FilePath/Manip.hs | 49 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 System/FilePath/Manip.hs diff --git a/FileManip.cabal b/FileManip.cabal index 407be2a..9904cd9 100644 --- a/FileManip.cabal +++ b/FileManip.cabal @@ -12,4 +12,5 @@ Build-Depends: base, filepath, mtl, unix GHC-Options: -Wall Exposed-Modules: System.FilePath.Find, - System.FilePath.GlobPattern + System.FilePath.GlobPattern, + System.FilePath.Manip diff --git a/System/FilePath/Manip.hs b/System/FilePath/Manip.hs new file mode 100644 index 0000000..0883be2 --- /dev/null +++ b/System/FilePath/Manip.hs @@ -0,0 +1,49 @@ +module System.FilePath.Manip ( + renameWith + , modifyWith + , modifyWithBackup + , modifyInPlace + ) where + +import Control.Exception (bracket, bracket_, handle, throwIO) +import Control.Monad (liftM) +import Data.Bits ((.&.)) +import System.Directory (removeFile) +import System.IO (IOMode(..), hClose, openFile) +import System.Posix.Files (fileMode, getFileStatus, rename, setFileMode) +import System.Posix.Temp (mkstemp) +import qualified Data.ByteString.Lazy.Char8 as L + +renameWith :: (FilePath -> FilePath) -> FilePath -> IO () + +renameWith f path = rename path (f path) + +modifyWith :: (FilePath -> FilePath -> IO ()) + -> (L.ByteString -> L.ByteString) + -> FilePath + -> IO () + +modifyWith after transform path = + bracket (openFile path ReadMode) hClose $ \ih -> do + (tmpPath, oh) <- mkstemp (path ++ "XXXXXX") + let ignore = return () + nukeTmp = handle (const ignore) (removeFile tmpPath) + handle (\e -> nukeTmp >> throwIO e) $ do + bracket_ ignore (hClose oh) $ + transform `liftM` L.hGetContents ih >>= L.hPut oh + handle (const nukeTmp) $ do + mode <- fileMode `liftM` getFileStatus path + setFileMode tmpPath (mode .&. 0777) + after path tmpPath + +modifyInPlace :: (L.ByteString -> L.ByteString) -> FilePath -> IO () + +modifyInPlace = modifyWith (flip rename) + +modifyWithBackup :: (FilePath -> FilePath) + -> (L.ByteString -> L.ByteString) + -> FilePath + -> IO () + +modifyWithBackup f = modifyWith backup + where backup path tmpPath = renameWith f path >> rename tmpPath path