Output to fifo fails
ggreif opened this issue · comments
I have a named pipe created with mkfifo fifo
. I want turtle
to write to it:
output "fifo" (echo "bla)
It fails with
*** Exception: fifo: openFile: does not exist (Device not configured)
The reason is that opening must happen in a blocking fashion.
Not sure, but what I really need is pipe
(or pipeto
) which blocks (and optionally creates the fifo if not yet present).
@ggreif: Would it be possible to use an MVar
to coordinate creation of the pipe with writing to the pipe so that the write doesn't happen early?
Possibly.
Turtle.output
:: MonadIO io => Turtle.FilePath -> Shell Line -> io ()
so we can create MVar
s. I'll try to come back with a recipe.
I doubt it can be done with an MVar
and two threads. To avoid a missed handshake exactly one of the threads must block in I/O, not on listening to the MVar
.
So I went for a non-kludge solution. Tried to upstream fpco/haskell-filesystem#22, since this is the Turtle
dependency, but it is deprecated :-(
Here is my code, anyway, for posterity:
module Turtle.Pipe (pipe, writeonlyblocking) where
import Turtle
-- for missing stuff
import qualified System.IO
import qualified GHC.IO.Handle.FD
import qualified Control.Exception
import qualified Data.Text.IO (hPutStrLn)
import qualified Control.Monad.Managed
-- Stuff that is missing from Turtle
-- | Stream lines of `Text` to a file, blocking
pipe :: MonadIO io => Turtle.FilePath -> Shell Line -> io ()
pipe file s = sh (do
handle <- using (writeonlyblocking file)
line <- s
liftIO (Data.Text.IO.hPutStrLn handle (lineToText line)) )
-- | Acquire a `Managed` blocking write-only `Handle` from a `FilePath`
writeonlyblocking :: Control.Monad.Managed.MonadManaged managed => Turtle.FilePath -> managed System.IO.Handle
writeonlyblocking file = using (managed (withBlockingTextFile file System.IO.WriteMode))
-- Stuff that is missing from Filesystem
-- | Open a file in text mode, and pass its 'Handle' to a provided
-- computation. The 'Handle' will be automatically closed when the
-- computation returns.
--
-- This computation throws 'IOError' on failure. See “Classifying
-- I/O errors” in the "System.IO.Error" documentation for information on
-- why the failure occured.
withBlockingTextFile :: Turtle.FilePath -> System.IO.IOMode -> (System.IO.Handle -> IO a) -> IO a
withBlockingTextFile path mode = Control.Exception.bracket (openBlockingTextFile path mode) System.IO.hClose
-- | Open a file in text mode, and return an open 'Handle'. The 'Handle'
-- should be closed with 'IO.hClose' when it is no longer needed.
--
-- 'withBlockingTextFile' is easier to use, because it will handle the
-- 'Handle'’s lifetime automatically.
--
-- This computation throws 'IOError' on failure. See “Classifying
-- I/O errors” in the "System.IO.Error" documentation for information on
-- why the failure occured.
openBlockingTextFile path = GHC.IO.Handle.FD.openFileBlocking (encodeString path)
-- See discussion https://mail.haskell.org/pipermail/haskell-cafe/2012-October/104030.html
I have discovered a general caveat with using GHC.IO.Handle.FD.openFileBlocking
, see my MR for GHC. That makes such an approach dangerous to use. Closing.
Why was this issue closed? fifo's are still broken/unusable. Can we just not use fifo's in turtle?