-- |
-- Module      :  System.AtomicWrite.Writer.String
-- Copyright   :  © 2015-2019 Stack Builders Inc.
-- License     :  MIT
--
-- Maintainer  :  Stack Builders <hackage@stackbuilders.com>
-- Stability   :  experimental
-- Portability :  portable
--
-- Provides functionality to dump the contents of a String
-- to a file.

module System.AtomicWrite.Writer.String (atomicWriteFile, atomicWithFile, atomicWriteFileWithMode, atomicWithFileAndMode) where

import           System.AtomicWrite.Internal (closeAndRename, maybeSetFileMode,
                                              tempFileFor)

import           System.IO                   (Handle, hPutStr)

import           System.Posix.Types          (FileMode)

-- | Creates or modifies a file atomically on POSIX-compliant
-- systems while preserving permissions.
atomicWriteFile ::
  FilePath   -- ^ The path where the file will be updated or created
  -> String  -- ^ The content to write to the file
  -> IO ()
atomicWriteFile :: FilePath -> FilePath -> IO ()
atomicWriteFile = (((Handle -> IO ()) -> IO ())
-> (FilePath -> Handle -> IO ()) -> FilePath -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Handle -> FilePath -> IO ()) -> FilePath -> Handle -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Handle -> FilePath -> IO ()
hPutStr) (((Handle -> IO ()) -> IO ()) -> FilePath -> IO ())
-> (FilePath -> (Handle -> IO ()) -> IO ())
-> FilePath
-> FilePath
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> (Handle -> IO ()) -> IO ()
atomicWithFile


-- | Creates or modifies a file atomically on
-- POSIX-compliant systems and updates permissions
atomicWriteFileWithMode ::
  FileMode    -- ^ The mode to set the file to
  -> FilePath -- ^ The path where the file will be updated or created
  -> String   -- ^ The content to write to the file
  -> IO ()
atomicWriteFileWithMode :: FileMode -> FilePath -> FilePath -> IO ()
atomicWriteFileWithMode FileMode
mode = ( ((Handle -> IO ()) -> IO ())
-> (FilePath -> Handle -> IO ()) -> FilePath -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Handle -> FilePath -> IO ()) -> FilePath -> Handle -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Handle -> FilePath -> IO ()
hPutStr)
                             (((Handle -> IO ()) -> IO ()) -> FilePath -> IO ())
-> (FilePath -> (Handle -> IO ()) -> IO ())
-> FilePath
-> FilePath
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
.  FileMode -> FilePath -> (Handle -> IO ()) -> IO ()
atomicWithFileAndMode FileMode
mode

-- | A general version of 'atomicWriteFile'
atomicWithFile :: FilePath -> (Handle -> IO ()) -> IO ()
atomicWithFile :: FilePath -> (Handle -> IO ()) -> IO ()
atomicWithFile = Maybe FileMode -> FilePath -> (Handle -> IO ()) -> IO ()
atomicWithFileAndMaybeMode Maybe FileMode
forall a. Maybe a
Nothing

-- | A general version of 'atomicWriteFileWithMode'
atomicWithFileAndMode :: FileMode
                      -> FilePath
                      -> (Handle -> IO ())
                      -> IO ()
atomicWithFileAndMode :: FileMode -> FilePath -> (Handle -> IO ()) -> IO ()
atomicWithFileAndMode = Maybe FileMode -> FilePath -> (Handle -> IO ()) -> IO ()
atomicWithFileAndMaybeMode (Maybe FileMode -> FilePath -> (Handle -> IO ()) -> IO ())
-> (FileMode -> Maybe FileMode)
-> FileMode
-> FilePath
-> (Handle -> IO ())
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileMode -> Maybe FileMode
forall a. a -> Maybe a
Just

-- | Helper function
atomicWithFileAndMaybeMode :: Maybe FileMode
                           -> FilePath
                           -> (Handle -> IO ())
                           -> IO ()
atomicWithFileAndMaybeMode :: Maybe FileMode -> FilePath -> (Handle -> IO ()) -> IO ()
atomicWithFileAndMaybeMode Maybe FileMode
mmode FilePath
path Handle -> IO ()
action =
  FilePath -> IO (FilePath, Handle)
tempFileFor FilePath
path IO (FilePath, Handle) -> ((FilePath, Handle) -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \(FilePath
tmpPath, Handle
h) -> Handle -> IO ()
action Handle
h
                    IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Handle -> FilePath -> FilePath -> IO ()
closeAndRename Handle
h FilePath
tmpPath FilePath
path
                    IO () -> IO () -> IO ()
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> FilePath -> Maybe FileMode -> IO ()
maybeSetFileMode FilePath
path Maybe FileMode
mmode