start on serializing Messages
Json objects not yet handled, and some other special cases, but this is the bulk of the messages. For progress meters, POSIXTime does not have a Read instance (or a suitable Show instance), so had to switch to using a Double for progress meters. This commit was sponsored by Ethan Aubin on Patreon.
This commit is contained in:
parent
63839532c9
commit
5a41e46bd4
5 changed files with 62 additions and 25 deletions
|
@ -285,9 +285,10 @@ debugEnabled = do
|
||||||
commandProgressDisabled :: Annex Bool
|
commandProgressDisabled :: Annex Bool
|
||||||
commandProgressDisabled = withMessageState $ \s -> return $
|
commandProgressDisabled = withMessageState $ \s -> return $
|
||||||
case outputType s of
|
case outputType s of
|
||||||
|
NormalOutput -> concurrentOutputEnabled s
|
||||||
QuietOutput -> True
|
QuietOutput -> True
|
||||||
JSONOutput _ -> True
|
JSONOutput _ -> True
|
||||||
NormalOutput -> concurrentOutputEnabled s
|
SerializedOutput -> True
|
||||||
|
|
||||||
jsonOutputEnabled :: Annex Bool
|
jsonOutputEnabled :: Annex Bool
|
||||||
jsonOutputEnabled = withMessageState $ \s -> return $
|
jsonOutputEnabled = withMessageState $ \s -> return $
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{- git-annex output messages, including concurrent output to display regions
|
{- git-annex output messages, including concurrent output to display regions
|
||||||
-
|
-
|
||||||
- Copyright 2010-2018 Joey Hess <id@joeyh.name>
|
- Copyright 2010-2020 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- Licensed under the GNU AGPL version 3 or higher.
|
- Licensed under the GNU AGPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
@ -29,6 +29,7 @@ outputMessage' jsonoutputter jsonbuilder msg = withMessageState $ \s -> case out
|
||||||
| otherwise -> liftIO $ flushed $ S.putStr msg
|
| otherwise -> liftIO $ flushed $ S.putStr msg
|
||||||
JSONOutput _ -> void $ jsonoutputter jsonbuilder s
|
JSONOutput _ -> void $ jsonoutputter jsonbuilder s
|
||||||
QuietOutput -> q
|
QuietOutput -> q
|
||||||
|
SerializedOutput -> liftIO $ outputSerialized $ OutputMessage (decodeBS' msg)
|
||||||
|
|
||||||
-- Buffer changes to JSON until end is reached and then emit it.
|
-- Buffer changes to JSON until end is reached and then emit it.
|
||||||
bufferJSON :: JSONBuilder -> MessageState -> Annex Bool
|
bufferJSON :: JSONBuilder -> MessageState -> Annex Bool
|
||||||
|
@ -67,6 +68,8 @@ outputError msg = withMessageState $ \s -> case (outputType s, jsonBuffer s) of
|
||||||
let jb' = Just (JSON.addErrorMessage (lines msg) jb)
|
let jb' = Just (JSON.addErrorMessage (lines msg) jb)
|
||||||
in Annex.changeState $ \st ->
|
in Annex.changeState $ \st ->
|
||||||
st { Annex.output = s { jsonBuffer = jb' } }
|
st { Annex.output = s { jsonBuffer = jb' } }
|
||||||
|
(SerializedOutput, _) ->
|
||||||
|
liftIO $ outputSerialized $ OutputError msg
|
||||||
_
|
_
|
||||||
| concurrentOutputEnabled s -> concurrentMessage s True msg go
|
| concurrentOutputEnabled s -> concurrentMessage s True msg go
|
||||||
| otherwise -> go
|
| otherwise -> go
|
||||||
|
@ -81,3 +84,6 @@ q = noop
|
||||||
|
|
||||||
flushed :: IO () -> IO ()
|
flushed :: IO () -> IO ()
|
||||||
flushed a = a >> hFlush stdout
|
flushed a = a >> hFlush stdout
|
||||||
|
|
||||||
|
outputSerialized :: SerializedOutput -> IO ()
|
||||||
|
outputSerialized = print
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{- git-annex progress output
|
{- git-annex progress output
|
||||||
-
|
-
|
||||||
- Copyright 2010-2019 Joey Hess <id@joeyh.name>
|
- Copyright 2010-2020 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- Licensed under the GNU AGPL version 3 or higher.
|
- Licensed under the GNU AGPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
@ -20,6 +20,7 @@ import Types.KeySource
|
||||||
import Utility.InodeCache
|
import Utility.InodeCache
|
||||||
import qualified Messages.JSON as JSON
|
import qualified Messages.JSON as JSON
|
||||||
import Messages.Concurrent
|
import Messages.Concurrent
|
||||||
|
import Messages.Internal
|
||||||
|
|
||||||
import qualified System.Console.Regions as Regions
|
import qualified System.Console.Regions as Regions
|
||||||
import qualified System.Console.Concurrent as Console
|
import qualified System.Console.Concurrent as Console
|
||||||
|
@ -72,7 +73,7 @@ metered othermeter sizer a = withMessageState $ \st ->
|
||||||
showOutput
|
showOutput
|
||||||
meter <- liftIO $ mkMeter msize $
|
meter <- liftIO $ mkMeter msize $
|
||||||
displayMeterHandle stdout bandwidthMeter
|
displayMeterHandle stdout bandwidthMeter
|
||||||
m <- liftIO $ rateLimitMeterUpdate 0.2 meter $
|
m <- liftIO $ rateLimitMeterUpdate consoleratelimit meter $
|
||||||
updateMeter meter
|
updateMeter meter
|
||||||
r <- a meter (combinemeter m)
|
r <- a meter (combinemeter m)
|
||||||
liftIO $ clearMeterHandle meter stdout
|
liftIO $ clearMeterHandle meter stdout
|
||||||
|
@ -82,19 +83,24 @@ metered othermeter sizer a = withMessageState $ \st ->
|
||||||
meter <- liftIO $ mkMeter msize $ \_ msize' old new ->
|
meter <- liftIO $ mkMeter msize $ \_ msize' old new ->
|
||||||
let s = bandwidthMeter msize' old new
|
let s = bandwidthMeter msize' old new
|
||||||
in Regions.setConsoleRegion r ('\n' : s)
|
in Regions.setConsoleRegion r ('\n' : s)
|
||||||
m <- liftIO $ rateLimitMeterUpdate 0.2 meter $
|
m <- liftIO $ rateLimitMeterUpdate consoleratelimit meter $
|
||||||
updateMeter meter
|
updateMeter meter
|
||||||
a meter (combinemeter m)
|
a meter (combinemeter m)
|
||||||
go msize (MessageState { outputType = JSONOutput jsonoptions })
|
go msize (MessageState { outputType = JSONOutput jsonoptions })
|
||||||
| jsonProgress jsonoptions = do
|
| jsonProgress jsonoptions = do
|
||||||
buf <- withMessageState $ return . jsonBuffer
|
buf <- withMessageState $ return . jsonBuffer
|
||||||
meter <- liftIO $ mkMeter msize $ \_ msize' _old (new, _now) ->
|
meter <- liftIO $ mkMeter msize $ \_ msize' _old new ->
|
||||||
JSON.progress buf msize' new
|
JSON.progress buf msize' (meterBytesProcessed new)
|
||||||
m <- liftIO $ rateLimitMeterUpdate 0.1 meter $
|
m <- liftIO $ rateLimitMeterUpdate jsonratelimit meter $
|
||||||
updateMeter meter
|
updateMeter meter
|
||||||
a meter (combinemeter m)
|
a meter (combinemeter m)
|
||||||
| otherwise = nometer
|
| otherwise = nometer
|
||||||
|
go msize (MessageState { outputType = SerializedOutput }) = do
|
||||||
|
meter <- liftIO $ mkMeter msize $ \_ msize' old new ->
|
||||||
|
outputSerialized $ ProgressMeter msize' old new
|
||||||
|
m <- liftIO $ rateLimitMeterUpdate minratelimit meter $
|
||||||
|
updateMeter meter
|
||||||
|
a meter (combinemeter m)
|
||||||
nometer = do
|
nometer = do
|
||||||
dummymeter <- liftIO $ mkMeter Nothing $
|
dummymeter <- liftIO $ mkMeter Nothing $
|
||||||
\_ _ _ _ -> return ()
|
\_ _ _ _ -> return ()
|
||||||
|
@ -104,6 +110,12 @@ metered othermeter sizer a = withMessageState $ \st ->
|
||||||
Nothing -> m
|
Nothing -> m
|
||||||
Just om -> combineMeterUpdate m om
|
Just om -> combineMeterUpdate m om
|
||||||
|
|
||||||
|
consoleratelimit = 0.2
|
||||||
|
|
||||||
|
jsonratelimit = 0.1
|
||||||
|
|
||||||
|
minratelimit = min consoleratelimit jsonratelimit
|
||||||
|
|
||||||
{- Poll file size to display meter. -}
|
{- Poll file size to display meter. -}
|
||||||
meteredFile :: FilePath -> Maybe MeterUpdate -> Key -> Annex a -> Annex a
|
meteredFile :: FilePath -> Maybe MeterUpdate -> Key -> Annex a -> Annex a
|
||||||
meteredFile file combinemeterupdate key a =
|
meteredFile file combinemeterupdate key a =
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{- git-annex Messages data types
|
{- git-annex Messages data types
|
||||||
-
|
-
|
||||||
- Copyright 2012-2018 Joey Hess <id@joeyh.name>
|
- Copyright 2012-2020 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- Licensed under the GNU AGPL version 3 or higher.
|
- Licensed under the GNU AGPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
@ -8,11 +8,16 @@
|
||||||
module Types.Messages where
|
module Types.Messages where
|
||||||
|
|
||||||
import qualified Utility.Aeson as Aeson
|
import qualified Utility.Aeson as Aeson
|
||||||
|
import Utility.Metered
|
||||||
|
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
import System.Console.Regions (ConsoleRegion)
|
import System.Console.Regions (ConsoleRegion)
|
||||||
|
|
||||||
data OutputType = NormalOutput | QuietOutput | JSONOutput JSONOptions
|
data OutputType
|
||||||
|
= NormalOutput
|
||||||
|
| QuietOutput
|
||||||
|
| JSONOutput JSONOptions
|
||||||
|
| SerializedOutput
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
data JSONOptions = JSONOptions
|
data JSONOptions = JSONOptions
|
||||||
|
@ -53,3 +58,9 @@ newMessageState = do
|
||||||
, jsonBuffer = Nothing
|
, jsonBuffer = Nothing
|
||||||
, promptLock = promptlock
|
, promptLock = promptlock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data SerializedOutput
|
||||||
|
= OutputMessage String
|
||||||
|
| OutputError String
|
||||||
|
| ProgressMeter (Maybe Integer) MeterState MeterState
|
||||||
|
deriving (Show, Read)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
module Utility.Metered (
|
module Utility.Metered (
|
||||||
MeterUpdate,
|
MeterUpdate,
|
||||||
|
MeterState(..),
|
||||||
nullMeterUpdate,
|
nullMeterUpdate,
|
||||||
combineMeterUpdate,
|
combineMeterUpdate,
|
||||||
TotalSize(..),
|
TotalSize(..),
|
||||||
|
@ -77,7 +78,7 @@ combineMeterUpdate a b = \n -> a n >> b n
|
||||||
|
|
||||||
{- Total number of bytes processed so far. -}
|
{- Total number of bytes processed so far. -}
|
||||||
newtype BytesProcessed = BytesProcessed Integer
|
newtype BytesProcessed = BytesProcessed Integer
|
||||||
deriving (Eq, Ord, Show)
|
deriving (Eq, Ord, Show, Read)
|
||||||
|
|
||||||
class AsBytesProcessed a where
|
class AsBytesProcessed a where
|
||||||
toBytesProcessed :: a -> BytesProcessed
|
toBytesProcessed :: a -> BytesProcessed
|
||||||
|
@ -379,19 +380,24 @@ rateLimitMeterUpdate delta (Meter totalsizev _ _ _) meterupdate = do
|
||||||
|
|
||||||
data Meter = Meter (MVar (Maybe Integer)) (MVar MeterState) (MVar String) DisplayMeter
|
data Meter = Meter (MVar (Maybe Integer)) (MVar MeterState) (MVar String) DisplayMeter
|
||||||
|
|
||||||
type MeterState = (BytesProcessed, POSIXTime)
|
data MeterState = MeterState
|
||||||
|
{ meterBytesProcessed :: BytesProcessed
|
||||||
|
, meterTimeStamp :: Double
|
||||||
|
} deriving (Show, Read)
|
||||||
|
|
||||||
type DisplayMeter = MVar String -> Maybe Integer -> (BytesProcessed, POSIXTime) -> (BytesProcessed, POSIXTime) -> IO ()
|
type DisplayMeter = MVar String -> Maybe Integer -> MeterState -> MeterState -> IO ()
|
||||||
|
|
||||||
type RenderMeter = Maybe Integer -> (BytesProcessed, POSIXTime) -> (BytesProcessed, POSIXTime) -> String
|
type RenderMeter = Maybe Integer -> MeterState -> MeterState -> String
|
||||||
|
|
||||||
-- | Make a meter. Pass the total size, if it's known.
|
-- | Make a meter. Pass the total size, if it's known.
|
||||||
mkMeter :: Maybe Integer -> DisplayMeter -> IO Meter
|
mkMeter :: Maybe Integer -> DisplayMeter -> IO Meter
|
||||||
mkMeter totalsize displaymeter = Meter
|
mkMeter totalsize displaymeter = do
|
||||||
<$> newMVar totalsize
|
ts <- realToFrac <$> getPOSIXTime
|
||||||
<*> ((\t -> newMVar (zeroBytesProcessed, t)) =<< getPOSIXTime)
|
Meter
|
||||||
<*> newMVar ""
|
<$> newMVar totalsize
|
||||||
<*> pure displaymeter
|
<*> newMVar (MeterState zeroBytesProcessed ts)
|
||||||
|
<*> newMVar ""
|
||||||
|
<*> pure displaymeter
|
||||||
|
|
||||||
setMeterTotalSize :: Meter -> Integer -> IO ()
|
setMeterTotalSize :: Meter -> Integer -> IO ()
|
||||||
setMeterTotalSize (Meter totalsizev _ _ _) = void . swapMVar totalsizev . Just
|
setMeterTotalSize (Meter totalsizev _ _ _) = void . swapMVar totalsizev . Just
|
||||||
|
@ -399,11 +405,12 @@ setMeterTotalSize (Meter totalsizev _ _ _) = void . swapMVar totalsizev . Just
|
||||||
-- | Updates the meter, displaying it if necessary.
|
-- | Updates the meter, displaying it if necessary.
|
||||||
updateMeter :: Meter -> MeterUpdate
|
updateMeter :: Meter -> MeterUpdate
|
||||||
updateMeter (Meter totalsizev sv bv displaymeter) new = do
|
updateMeter (Meter totalsizev sv bv displaymeter) new = do
|
||||||
now <- getPOSIXTime
|
now <- realToFrac <$> getPOSIXTime
|
||||||
(old, before) <- swapMVar sv (new, now)
|
let curms = MeterState new now
|
||||||
when (old /= new) $ do
|
oldms <- swapMVar sv curms
|
||||||
|
when (meterBytesProcessed oldms /= new) $ do
|
||||||
totalsize <- readMVar totalsizev
|
totalsize <- readMVar totalsizev
|
||||||
displaymeter bv totalsize (old, before) (new, now)
|
displaymeter bv totalsize oldms curms
|
||||||
|
|
||||||
-- | Display meter to a Handle.
|
-- | Display meter to a Handle.
|
||||||
displayMeterHandle :: Handle -> RenderMeter -> DisplayMeter
|
displayMeterHandle :: Handle -> RenderMeter -> DisplayMeter
|
||||||
|
@ -428,7 +435,7 @@ clearMeterHandle (Meter _ _ v _) h = do
|
||||||
-- or when total size is not known:
|
-- or when total size is not known:
|
||||||
-- 1.3 MiB 300 KiB/s
|
-- 1.3 MiB 300 KiB/s
|
||||||
bandwidthMeter :: RenderMeter
|
bandwidthMeter :: RenderMeter
|
||||||
bandwidthMeter mtotalsize (BytesProcessed old, before) (BytesProcessed new, now) =
|
bandwidthMeter mtotalsize (MeterState (BytesProcessed old) before) (MeterState (BytesProcessed new) now) =
|
||||||
unwords $ catMaybes
|
unwords $ catMaybes
|
||||||
[ Just percentamount
|
[ Just percentamount
|
||||||
-- Pad enough for max width: "100% xxxx.xx KiB xxxx KiB/s"
|
-- Pad enough for max width: "100% xxxx.xx KiB xxxx KiB/s"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue