33module System.Nix.Nar.Effects
44 ( NarEffects (.. )
55 , narEffectsIO
6+ , IsExecutable (.. )
67 ) where
78
89import Control.Monad.Trans.Control (MonadBaseControl )
910import Control.Monad.IO.Class (MonadIO (liftIO ))
1011import Data.ByteString (ByteString )
12+ import Data.Bool (bool )
1113import Data.Int (Int64 )
1214import Data.Kind (Type )
1315import System.IO (Handle , IOMode (WriteMode ))
@@ -25,15 +27,17 @@ import System.Posix.Files ( createSymbolicLink
2527import qualified System.IO as IO
2628import qualified Control.Exception.Lifted as Exception.Lifted
2729
30+ data IsExecutable = NonExecutable | Executable
31+ deriving (Eq , Show )
32+
2833data NarEffects (m :: Type -> Type ) = NarEffects {
2934 narReadFile :: FilePath -> m Bytes.Lazy. ByteString
30- , narWriteFile :: FilePath -> Bytes.Lazy. ByteString -> m ()
31- , narStreamFile :: FilePath -> m (Maybe ByteString ) -> m ()
35+ , narWriteFile :: FilePath -> IsExecutable -> Bytes.Lazy. ByteString -> m ()
36+ , narStreamFile :: FilePath -> IsExecutable -> m (Maybe ByteString ) -> m ()
3237 , narListDir :: FilePath -> m [FilePath ]
3338 , narCreateDir :: FilePath -> m ()
3439 , narCreateLink :: FilePath -> FilePath -> m ()
35- , narGetPerms :: FilePath -> m Directory. Permissions
36- , narSetPerms :: FilePath -> Directory. Permissions -> m ()
40+ , narIsExec :: FilePath -> m IsExecutable
3741 , narIsDir :: FilePath -> m Bool
3842 , narIsSymLink :: FilePath -> m Bool
3943 , narFileSize :: FilePath -> m Int64
@@ -53,13 +57,15 @@ narEffectsIO
5357 => NarEffects m
5458narEffectsIO = NarEffects {
5559 narReadFile = liftIO . Bytes.Lazy. readFile
56- , narWriteFile = \ a -> liftIO . Bytes.Lazy. writeFile a
60+ , narWriteFile = \ f e c -> liftIO $ do
61+ Bytes.Lazy. writeFile f c
62+ p <- Directory. getPermissions f
63+ Directory. setPermissions f (p { Directory. executable = e == Executable })
5764 , narStreamFile = streamStringOutIO
5865 , narListDir = liftIO . Directory. listDirectory
5966 , narCreateDir = liftIO . Directory. createDirectory
6067 , narCreateLink = \ f -> liftIO . createSymbolicLink f
61- , narGetPerms = liftIO . Directory. getPermissions
62- , narSetPerms = \ f -> liftIO . Directory. setPermissions f
68+ , narIsExec = liftIO . (fmap (bool NonExecutable Executable . Directory. executable)) . Directory. getPermissions
6369 , narIsDir = fmap isDirectory . liftIO . getFileStatus
6470 , narIsSymLink = liftIO . Directory. pathIsSymbolicLink
6571 , narFileSize = fmap (fromIntegral . fileSize) . liftIO . getFileStatus
@@ -76,9 +82,10 @@ streamStringOutIO
7682 , MonadBaseControl IO m
7783 )
7884 => FilePath
85+ -> IsExecutable
7986 -> m (Maybe ByteString )
8087 -> m ()
81- streamStringOutIO f getChunk =
88+ streamStringOutIO f executable getChunk =
8289 Exception.Lifted. bracket
8390 (liftIO $ IO. openFile f WriteMode )
8491 (liftIO . IO. hClose)
@@ -93,6 +100,9 @@ streamStringOutIO f getChunk =
93100 Nothing -> pure ()
94101 Just c -> do
95102 liftIO $ Data.ByteString. hPut handle c
103+ Control.Monad. when (executable == Executable ) $ liftIO $ do
104+ p <- Directory. getPermissions f
105+ Directory. setPermissions f (p { Directory. executable = True })
96106 go handle
97107 cleanupException (e :: Exception.Lifted. SomeException ) = do
98108 liftIO $ Directory. removeFile f
0 commit comments