summaryrefslogtreecommitdiff
path: root/source/Felix/Output
diff options
context:
space:
mode:
Diffstat (limited to 'source/Felix/Output')
-rw-r--r--source/Felix/Output/Atomic.hs29
1 files changed, 29 insertions, 0 deletions
diff --git a/source/Felix/Output/Atomic.hs b/source/Felix/Output/Atomic.hs
new file mode 100644
index 0000000..39ea9c8
--- /dev/null
+++ b/source/Felix/Output/Atomic.hs
@@ -0,0 +1,29 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-- | Sibling-temporary replacement for generated byte artifacts.
+module Felix.Output.Atomic (writeBytesAtomically) where
+
+import Base
+
+import Data.ByteString (ByteString)
+import Data.ByteString qualified as ByteString
+import System.Directory qualified as Directory
+import System.FilePath.Posix qualified as Posix
+
+writeBytesAtomically :: FilePath -> ByteString -> IO ()
+writeBytesAtomically destination bytes = do
+ let directory = Posix.takeDirectory destination
+ template = Posix.takeFileName destination <> ".tmp"
+ bracketOnError
+ (openBinaryTempFileWithDefaultPermissions directory template)
+ cleanupTemporary
+ \(temporary, handle) -> do
+ ByteString.hPut handle bytes
+ hFlush handle
+ hClose handle
+ Directory.renameFile temporary destination
+
+cleanupTemporary :: (FilePath, Handle) -> IO ()
+cleanupTemporary (temporary, handle) = do
+ void (tryIOError (hClose handle))
+ void (tryIOError (Directory.removeFile temporary))