rsync progress interception

Current implementation parses rsync's output a character a time, which
is hardly efficient. It could be sped up a lot by using hGetBufSome,
but that would require going really lowlevel, down to raw C style buffers
(good example of that here: http://users.aber.ac.uk/afc/stricthaskell.html)
But rsync doesn't output very much, so currently it seems ok.
This commit is contained in:
Joey Hess 2012-09-19 16:55:08 -04:00
parent aff09a1f33
commit e1037adebc
2 changed files with 25 additions and 10 deletions

View file

@ -245,7 +245,7 @@ copyFromRemote r key file dest
loc <- inRepo $ gitAnnexLocation key loc <- inRepo $ gitAnnexLocation key
upload u key file $ upload u key file $
rsyncOrCopyFile params loc dest rsyncOrCopyFile params loc dest
| Git.repoIsSsh r = rsyncHelper =<< rsyncParamsRemote r True key dest file | Git.repoIsSsh r = rsyncHelper Nothing =<< rsyncParamsRemote r True key dest file
| Git.repoIsHttp r = Annex.Content.downloadUrl (keyUrls r key) dest | Git.repoIsHttp r = Annex.Content.downloadUrl (keyUrls r key) dest
| otherwise = error "copying from non-ssh, non-http repo not supported" | otherwise = error "copying from non-ssh, non-http repo not supported"
@ -280,13 +280,13 @@ copyToRemote r key file p
) )
| Git.repoIsSsh r = commitOnCleanup r $ do | Git.repoIsSsh r = commitOnCleanup r $ do
keysrc <- inRepo $ gitAnnexLocation key keysrc <- inRepo $ gitAnnexLocation key
rsyncHelper =<< rsyncParamsRemote r False key keysrc file rsyncHelper (Just p) =<< rsyncParamsRemote r False key keysrc file
| otherwise = error "copying to non-ssh repo not supported" | otherwise = error "copying to non-ssh repo not supported"
rsyncHelper :: [CommandParam] -> Annex Bool rsyncHelper :: Maybe ProgressCallback -> [CommandParam] -> Annex Bool
rsyncHelper p = do rsyncHelper callback params = do
showOutput -- make way for progress bar showOutput -- make way for progress bar
ifM (liftIO $ rsync p) ifM (liftIO $ (maybe rsync rsyncProgress callback) params)
( return True ( return True
, do , do
showLongNote "rsync failed -- run git annex again to resume file transfer" showLongNote "rsync failed -- run git annex again to resume file transfer"
@ -299,7 +299,7 @@ rsyncOrCopyFile :: [CommandParam] -> FilePath -> FilePath -> ProgressCallback ->
rsyncOrCopyFile rsyncparams src dest p = rsyncOrCopyFile rsyncparams src dest p =
ifM (sameDeviceIds src dest) ifM (sameDeviceIds src dest)
( liftIO $ copyFileExternal src dest ( liftIO $ copyFileExternal src dest
, rsyncHelper $ rsyncparams ++ [Param src, Param dest] , rsyncHelper (Just p) $ rsyncparams ++ [Param src, Param dest]
) )
where where
sameDeviceIds a b = (==) <$> (getDeviceId a) <*> (getDeviceId b) sameDeviceIds a b = (==) <$> (getDeviceId a) <*> (getDeviceId b)

View file

@ -7,11 +7,8 @@
module Utility.Rsync where module Utility.Rsync where
import Utility.SafeCommand import Common
import Utility.PartialPrelude
import Data.String.Utils
import Data.List
import Data.Char import Data.Char
{- Generates parameters to make rsync use a specified command as its remote {- Generates parameters to make rsync use a specified command as its remote
@ -49,6 +46,24 @@ rsyncServerParams =
rsync :: [CommandParam] -> IO Bool rsync :: [CommandParam] -> IO Bool
rsync = boolSystem "rsync" rsync = boolSystem "rsync"
{- Runs rsync, but intercepts its progress output and feeds bytes
- complete values into the callback. The progress output is also output
- to stdout. -}
rsyncProgress :: (Integer -> IO ()) -> [CommandParam] -> IO Bool
rsyncProgress callback params = catchBoolIO $
withHandle StdoutHandle createProcessSuccess p (feedprogress [])
where
p = proc "rsync" (toCommand params)
feedprogress buf h =
catchMaybeIO (hGetChar h) >>= \v -> case v of
Just c -> do
putChar c
hFlush stdout
let (mbytes, buf') = parseRsyncProgress (buf++[c])
maybe noop callback mbytes
feedprogress buf' h
Nothing -> return True
{- Checks if an rsync url involves the remote shell (ssh or rsh). {- Checks if an rsync url involves the remote shell (ssh or rsh).
- Use of such urls with rsync requires additional shell - Use of such urls with rsync requires additional shell
- escaping. -} - escaping. -}