From 217f787df9d6474c9a57fd29b6b2fa29bef64a8a Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 18 Jun 2017 18:57:41 -0400 Subject: my pipe trick didn't work; fallback to NoBuffering Not sure what the problem was, but it hung. Also though, I noticed that stdin was still open when git fetch was run, so if git fetch itself decided to read from stdin, it would mess up the protocol forwarding. While git fetch should never read from stdin, that was reason enough to fall back to plan B. --- src/Propellor/Protocol.hs | 10 +++++++--- src/Propellor/Spin.hs | 22 ++++++++-------------- 2 files changed, 15 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/Propellor/Protocol.hs b/src/Propellor/Protocol.hs index e90155f3..ae7e0404 100644 --- a/src/Propellor/Protocol.hs +++ b/src/Propellor/Protocol.hs @@ -53,7 +53,11 @@ sendMarked' h marker s = do hFlush h getMarked :: Handle -> Marker -> IO (Maybe String) -getMarked h marker = go =<< catchMaybeIO (hGetLine h) +getMarked h marker = do + -- Avoid buffering anything in Handle, so that the data after + -- the marker will be available to be read from the underlying Fd. + hSetBuffering stdin NoBuffering + go =<< catchMaybeIO (hGetLine h) where go Nothing = return Nothing go (Just l) = case fromMarked marker l of @@ -65,8 +69,8 @@ getMarked h marker = go =<< catchMaybeIO (hGetLine h) debug ["received marked", marker] return (Just v) -req :: Stage -> Marker -> (String -> IO ()) -> IO () -req stage marker a = do +reqMarked :: Stage -> Marker -> (String -> IO ()) -> IO () +reqMarked stage marker a = do debug ["requested marked", marker] sendMarked' stdout statusMarker (show stage) maybe noop a =<< getMarked stdin marker diff --git a/src/Propellor/Spin.hs b/src/Propellor/Spin.hs index cc5fa0e8..cd964e16 100644 --- a/src/Propellor/Spin.hs +++ b/src/Propellor/Spin.hs @@ -178,11 +178,11 @@ getSshTarget target hst update :: Maybe HostName -> IO () update forhost = do whenM hasGitRepo $ - req NeedRepoUrl repoUrlMarker setRepoUrl + reqMarked NeedRepoUrl repoUrlMarker setRepoUrl makePrivDataDir createDirectoryIfMissing True (takeDirectory privfile) - req NeedPrivData privDataMarker $ + reqMarked NeedPrivData privDataMarker $ writeFileProtected privfile whenM hasGitRepo $ @@ -350,19 +350,13 @@ spinCommitMessage = "propellor spin" -- Request that it run git upload-pack, and connect that up to a git fetch -- to receive the data. gitPullFromUpdateServer :: IO () -gitPullFromUpdateServer = req NeedGitPush gitPushMarker $ \_ -> do - -- IO involving stdin can cause data to be buffered in the Handle - -- (even when it's set NoBuffering), but we need to pass a FD to - -- git fetch containing all of stdin after the gitPushMarker, - -- including any that has been buffered. - -- - -- To do so, create a pipe, and forward stdin, including any - -- buffered part, through it. - (pread, pwrite) <- System.Posix.IO.createPipe - hwrite <- fdToHandle pwrite - _ <- async $ stdin *>* hwrite - let hin = pread +gitPullFromUpdateServer = reqMarked NeedGitPush gitPushMarker $ \_ -> do + -- Note that this relies on data not being buffered in the stdin + -- Handle, since such buffered data would not be available in the + -- FD passed to git fetch. + hin <- dup stdInput hout <- dup stdOutput + hClose stdin hClose stdout -- Not using git pull because git 2.5.0 badly -- broke its option parser. -- cgit v1.2.3