Gabriella439 / turtle

Shell programming, Haskell style

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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 MVars. 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 &#8220;Classifying
-- I/O errors&#8221; 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'&#x2019;s lifetime automatically.
--
-- This computation throws 'IOError' on failure. See &#8220;Classifying
-- I/O errors&#8221; 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?