{-# 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))