summaryrefslogtreecommitdiff
path: root/source/Felix/Output/Atomic.hs
diff options
context:
space:
mode:
authoradelon <22380201+adelon@users.noreply.github.com>2026-08-06 14:28:46 +0200
committeradelon <22380201+adelon@users.noreply.github.com>2026-08-06 14:28:46 +0200
commite0c34246eddc4470d89af0660fd2a8ddc1b393a5 (patch)
tree1cb74e79fc90580e54a0b22918fad8bd6fc174a4 /source/Felix/Output/Atomic.hs
parentde041252752b9e0358bdba93d8f836ba28aabad8 (diff)
Simplify entry/CLI, track slowest ATP tasks
Diffstat (limited to 'source/Felix/Output/Atomic.hs')
-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))