{-# LANGUAGE OverloadedLists #-}

-- | CLI parsing for CommandLoggingArgs
module Shrun.Configuration.Args.Parsing.CommandLogging
  ( commandLoggingParser,
  )
where

import Data.Text qualified as T
import Options.Applicative (Parser)
import Options.Applicative qualified as OA
import Shrun.Configuration.Args.Parsing.Utils qualified as Utils
import Shrun.Configuration.Data.CommandLogging
  ( BufferLength,
    BufferTimeout (MkBufferTimeout),
    CommandLoggingArgs,
    CommandLoggingP
      ( MkCommandLoggingP,
        bufferLength,
        pollInterval,
        readSize,
        readStrategy,
        reportReadErrors
      ),
    ReportReadErrorsSwitch (MkReportReadErrorsSwitch),
  )
import Shrun.Configuration.Data.CommandLogging qualified as CommandLogging
import Shrun.Configuration.Data.CommandLogging.PollInterval (PollInterval)
import Shrun.Configuration.Data.CommandLogging.PollInterval qualified as PollInterval
import Shrun.Configuration.Data.CommandLogging.ReadSize (ReadSize)
import Shrun.Configuration.Data.CommandLogging.ReadSize qualified as ReadSize
import Shrun.Configuration.Data.CommandLogging.ReadStrategy (ReadStrategy)
import Shrun.Configuration.Data.CommandLogging.ReadStrategy qualified as ReadStrategy
import Shrun.Configuration.Data.Core.Timeout qualified as Timeout
import Shrun.Configuration.Default (Default (def))
import Shrun.Prelude
import Shrun.Utils qualified as SUtils

commandLoggingParser :: Parser CommandLoggingArgs
commandLoggingParser :: Parser CommandLoggingArgs
commandLoggingParser = do
  Maybe BufferLength
bufferLength <- Parser (Maybe BufferLength)
bufferLengthParser
  Maybe BufferTimeout
bufferTimeout <- Parser (Maybe BufferTimeout)
bufferTimeoutParser
  Maybe PollInterval
pollInterval <- Parser (Maybe PollInterval)
pollIntervalParser
  Maybe ReadSize
readSize <- Parser (Maybe ReadSize)
readSizeParser
  Maybe ReadStrategy
readStrategy <- Parser (Maybe ReadStrategy)
readStrategyParser
  Maybe ReportReadErrorsSwitch
reportReadErrors <- Parser (Maybe ReportReadErrorsSwitch)
reportReadErrorsParser

  pure
    $ MkCommandLoggingP
      { Maybe BufferLength
ConfigPhaseF 'ConfigPhaseArgs BufferLength
bufferLength :: ConfigPhaseF 'ConfigPhaseArgs BufferLength
bufferLength :: Maybe BufferLength
bufferLength,
        Maybe BufferTimeout
ConfigPhaseF 'ConfigPhaseArgs BufferTimeout
bufferTimeout :: Maybe BufferTimeout
bufferTimeout :: ConfigPhaseF 'ConfigPhaseArgs BufferTimeout
bufferTimeout,
        Maybe PollInterval
ConfigPhaseF 'ConfigPhaseArgs PollInterval
pollInterval :: ConfigPhaseF 'ConfigPhaseArgs PollInterval
pollInterval :: Maybe PollInterval
pollInterval,
        Maybe ReadSize
ConfigPhaseF 'ConfigPhaseArgs ReadSize
readSize :: ConfigPhaseF 'ConfigPhaseArgs ReadSize
readSize :: Maybe ReadSize
readSize,
        Maybe ReadStrategy
ConfigPhaseF 'ConfigPhaseArgs ReadStrategy
readStrategy :: ConfigPhaseF 'ConfigPhaseArgs ReadStrategy
readStrategy :: Maybe ReadStrategy
readStrategy,
        Maybe ReportReadErrorsSwitch
SwitchF 'ConfigPhaseArgs ReportReadErrorsSwitch
reportReadErrors :: SwitchF 'ConfigPhaseArgs ReportReadErrorsSwitch
reportReadErrors :: Maybe ReportReadErrorsSwitch
reportReadErrors
      }

bufferLengthParser :: Parser (Maybe BufferLength)
bufferLengthParser :: Parser (Maybe BufferLength)
bufferLengthParser = Parser (Maybe BufferLength)
mainParser
  where
    mainParser :: Parser (Maybe BufferLength)
mainParser =
      Parser BufferLength -> Parser (Maybe BufferLength)
forall (f :: Type -> Type) a. Alternative f => f a -> f (Maybe a)
OA.optional
        (Parser BufferLength -> Parser (Maybe BufferLength))
-> Parser BufferLength -> Parser (Maybe BufferLength)
forall a b. (a -> b) -> a -> b
$ ReadM BufferLength
-> Mod OptionFields BufferLength -> Parser BufferLength
forall a. ReadM a -> Mod OptionFields a -> Parser a
OA.option
          (ReadM Natural -> ReadM BufferLength
forall (m :: Type -> Type).
MonadFail m =>
m Natural -> m BufferLength
CommandLogging.parseBufferLength ReadM Natural
forall a. Read a => ReadM a
Utils.autoStripUnderscores)
          ( [Mod OptionFields BufferLength] -> Mod OptionFields BufferLength
forall a. Monoid a => [a] -> a
mconcat
              [ String -> Mod OptionFields BufferLength
forall (f :: Type -> Type) a. HasName f => String -> Mod f a
OA.long String
"command-log-buffer-length",
                String -> Mod OptionFields BufferLength
forall (f :: Type -> Type) a. String -> Mod f a
Utils.mkHelp String
helpTxt,
                String -> Mod OptionFields BufferLength
forall (f :: Type -> Type) a. HasMetavar f => String -> Mod f a
OA.metavar String
"NATURAL"
              ]
          )
    helpTxt :: String
helpTxt =
      [String] -> String
forall a. Monoid a => [a] -> a
mconcat
        [ String
Item [String]
"Max text length held by the log buffer, used in conjunction ",
          String
Item [String]
"with --command-log-read-strategy block-line-buffer. Defaults to ",
          String
Item [String]
"1,000 characters."
        ]

bufferTimeoutParser :: Parser (Maybe BufferTimeout)
bufferTimeoutParser :: Parser (Maybe BufferTimeout)
bufferTimeoutParser = Parser (Maybe BufferTimeout)
mainParser
  where
    mainParser :: Parser (Maybe BufferTimeout)
mainParser =
      Parser BufferTimeout -> Parser (Maybe BufferTimeout)
forall (f :: Type -> Type) a. Alternative f => f a -> f (Maybe a)
OA.optional
        (Parser BufferTimeout -> Parser (Maybe BufferTimeout))
-> Parser BufferTimeout -> Parser (Maybe BufferTimeout)
forall a b. (a -> b) -> a -> b
$ ReadM BufferTimeout
-> Mod OptionFields BufferTimeout -> Parser BufferTimeout
forall a. ReadM a -> Mod OptionFields a -> Parser a
OA.option
          (Timeout -> BufferTimeout
MkBufferTimeout (Timeout -> BufferTimeout) -> ReadM Timeout -> ReadM BufferTimeout
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> ReadM Natural -> ReadM Text -> ReadM Timeout
forall (f :: Type -> Type).
(Alternative f, MonadFail f) =>
f Natural -> f Text -> f Timeout
Timeout.parseTimeout ReadM Natural
forall a. Read a => ReadM a
Utils.autoStripUnderscores ReadM Text
forall s. IsString s => ReadM s
OA.str)
          ( [Mod OptionFields BufferTimeout] -> Mod OptionFields BufferTimeout
forall a. Monoid a => [a] -> a
mconcat
              [ String -> Mod OptionFields BufferTimeout
forall (f :: Type -> Type) a. HasName f => String -> Mod f a
OA.long String
"command-log-buffer-timeout",
                String -> Mod OptionFields BufferTimeout
forall (f :: Type -> Type) a. String -> Mod f a
Utils.mkHelp String
helpTxt,
                String -> Mod OptionFields BufferTimeout
forall (f :: Type -> Type) a. HasMetavar f => String -> Mod f a
OA.metavar String
"(NATURAL | TIME_STR)"
              ]
          )
    helpTxt :: String
helpTxt =
      [String] -> String
forall a. Monoid a => [a] -> a
mconcat
        [ String
Item [String]
"Max time the log buffer will hold a log before flushing it, used ",
          String
Item [String]
"in conjunction with --command-log-read-strategy ",
          String
Item [String]
"block-line-buffer. Defaults to 30 seconds."
        ]

pollIntervalParser :: Parser (Maybe PollInterval)
pollIntervalParser :: Parser (Maybe PollInterval)
pollIntervalParser = Parser (Maybe PollInterval)
mainParser
  where
    mainParser :: Parser (Maybe PollInterval)
mainParser =
      Parser PollInterval -> Parser (Maybe PollInterval)
forall (f :: Type -> Type) a. Alternative f => f a -> f (Maybe a)
OA.optional
        (Parser PollInterval -> Parser (Maybe PollInterval))
-> Parser PollInterval -> Parser (Maybe PollInterval)
forall a b. (a -> b) -> a -> b
$ ReadM PollInterval
-> Mod OptionFields PollInterval -> Parser PollInterval
forall a. ReadM a -> Mod OptionFields a -> Parser a
OA.option
          (ReadM Natural -> ReadM PollInterval
forall (m :: Type -> Type).
Functor m =>
m Natural -> m PollInterval
PollInterval.parsePollInterval ReadM Natural
forall a. Read a => ReadM a
Utils.autoStripUnderscores)
          ( [Mod OptionFields PollInterval] -> Mod OptionFields PollInterval
forall a. Monoid a => [a] -> a
mconcat
              [ String -> Mod OptionFields PollInterval
forall (f :: Type -> Type) a. HasName f => String -> Mod f a
OA.long String
"command-log-poll-interval",
                String -> Mod OptionFields PollInterval
forall (f :: Type -> Type) a. String -> Mod f a
Utils.mkHelp String
helpTxt,
                String -> Mod OptionFields PollInterval
forall (f :: Type -> Type) a. HasMetavar f => String -> Mod f a
OA.metavar String
"NATURAL"
              ]
          )
    helpTxt :: String
helpTxt =
      [String] -> String
forall a. Monoid a => [a] -> a
mconcat
        [ String
Item [String]
"Non-negative integer used in conjunction with --console-log-command and ",
          String
Item [String]
"--file-log that determines how quickly we poll commands for ",
          String
Item [String]
"logs, in microseconds. A value of 0 is interpreted as infinite ",
          String
Item [String]
"i.e. limited only by the CPU. Defaults to ",
          PollInterval -> String
prettyPollInterval PollInterval
forall a. Default a => a
def,
          String
Item [String]
". Note that lower values will increase CPU usage. In particular, ",
          String
Item [String]
"0 will max out a CPU thread."
        ]

    prettyPollInterval :: PollInterval -> String
    prettyPollInterval :: PollInterval -> String
prettyPollInterval =
      Text -> String
unpack
        (Text -> String)
-> (PollInterval -> Text) -> PollInterval -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> Text
T.reverse
        (Text -> Text) -> (PollInterval -> Text) -> PollInterval -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> [Text] -> Text
T.intercalate Text
","
        ([Text] -> Text)
-> (PollInterval -> [Text]) -> PollInterval -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Int -> Text -> [Text]
T.chunksOf Int
3
        (Text -> [Text])
-> (PollInterval -> Text) -> PollInterval -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> Text
T.reverse
        (Text -> Text) -> (PollInterval -> Text) -> PollInterval -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Natural -> Text
forall a. Show a => a -> Text
showt
        (Natural -> Text)
-> (PollInterval -> Natural) -> PollInterval -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Optic' An_Iso NoIx PollInterval Natural -> PollInterval -> Natural
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view Optic' An_Iso NoIx PollInterval Natural
#unPollInterval

readSizeParser :: Parser (Maybe ReadSize)
readSizeParser :: Parser (Maybe ReadSize)
readSizeParser = Parser (Maybe ReadSize)
mainParser
  where
    mainParser :: Parser (Maybe ReadSize)
mainParser =
      Parser ReadSize -> Parser (Maybe ReadSize)
forall (f :: Type -> Type) a. Alternative f => f a -> f (Maybe a)
OA.optional
        (Parser ReadSize -> Parser (Maybe ReadSize))
-> Parser ReadSize -> Parser (Maybe ReadSize)
forall a b. (a -> b) -> a -> b
$ ReadM ReadSize -> Mod OptionFields ReadSize -> Parser ReadSize
forall a. ReadM a -> Mod OptionFields a -> Parser a
OA.option
          (ReadM Text -> ReadM ReadSize
forall (m :: Type -> Type). MonadFail m => m Text -> m ReadSize
ReadSize.parseReadSize ReadM Text
forall s. IsString s => ReadM s
OA.str)
          ( [Mod OptionFields ReadSize] -> Mod OptionFields ReadSize
forall a. Monoid a => [a] -> a
mconcat
              [ String -> Mod OptionFields ReadSize
forall (f :: Type -> Type) a. HasName f => String -> Mod f a
OA.long String
"command-log-read-size",
                String -> Mod OptionFields ReadSize
forall (f :: Type -> Type) a. String -> Mod f a
Utils.mkHelp String
helpTxt,
                String -> Mod OptionFields ReadSize
forall (f :: Type -> Type) a. HasMetavar f => String -> Mod f a
OA.metavar String
"BYTES"
              ]
          )

    helpTxt :: String
helpTxt =
      [String] -> String
forall a. Monoid a => [a] -> a
mconcat
        [ String
Item [String]
"The max number of bytes in a single read when streaming command ",
          String
Item [String]
"logs (--console-log-command and --file-log). Logs larger than ",
          String
Item [String]
"--command-log-read-size will be read in a subsequent read, hence ",
          String
Item [String]
"broken across lines. The default is '16 kb'."
        ]

readStrategyParser :: Parser (Maybe ReadStrategy)
readStrategyParser :: Parser (Maybe ReadStrategy)
readStrategyParser = Parser (Maybe ReadStrategy)
mainParser
  where
    mainParser :: Parser (Maybe ReadStrategy)
mainParser =
      Parser ReadStrategy -> Parser (Maybe ReadStrategy)
forall (f :: Type -> Type) a. Alternative f => f a -> f (Maybe a)
OA.optional
        (Parser ReadStrategy -> Parser (Maybe ReadStrategy))
-> Parser ReadStrategy -> Parser (Maybe ReadStrategy)
forall a b. (a -> b) -> a -> b
$ ReadM ReadStrategy
-> Mod OptionFields ReadStrategy -> Parser ReadStrategy
forall a. ReadM a -> Mod OptionFields a -> Parser a
OA.option (ReadM Text -> ReadM ReadStrategy
forall (m :: Type -> Type). MonadFail m => m Text -> m ReadStrategy
ReadStrategy.parseReadStrategy ReadM Text
forall s. IsString s => ReadM s
OA.str)
        (Mod OptionFields ReadStrategy -> Parser ReadStrategy)
-> Mod OptionFields ReadStrategy -> Parser ReadStrategy
forall a b. (a -> b) -> a -> b
$ [Mod OptionFields ReadStrategy] -> Mod OptionFields ReadStrategy
forall a. Monoid a => [a] -> a
mconcat
          [ String -> Mod OptionFields ReadStrategy
forall (f :: Type -> Type) a. HasName f => String -> Mod f a
OA.long String
"command-log-read-strategy",
            [String] -> Mod OptionFields ReadStrategy
forall (f :: Type -> Type) a. HasCompleter f => [String] -> Mod f a
OA.completeWith [String
Item [String]
"block", String
Item [String]
"block-line-buffer"],
            String -> Mod OptionFields ReadStrategy
forall (f :: Type -> Type) a. HasMetavar f => String -> Mod f a
OA.metavar ((Bool, [String]) -> String
forall a. (IsString a, Monoid a) => (Bool, [a]) -> a
SUtils.mkMetaStr (Bool, [String])
forall a. IsString a => (Bool, [a])
ReadStrategy.readStrategyMeta),
            Item [Mod OptionFields ReadStrategy]
Mod OptionFields ReadStrategy
helpTxt
          ]
    helpTxt :: Mod OptionFields ReadStrategy
helpTxt =
      NESeq String -> Mod OptionFields ReadStrategy
forall a. NESeq String -> Mod OptionFields a
Utils.itemizeNoLine
        (NESeq String -> Mod OptionFields ReadStrategy)
-> NESeq String -> Mod OptionFields ReadStrategy
forall a b. (a -> b) -> a -> b
$ String
intro
        String -> Seq String -> NESeq String
forall a. a -> Seq a -> NESeq a
:<|| [ String
Item (Seq String)
block,
               String
Item (Seq String)
blockLineBuffer
             ]

    intro :: String
intro =
      [String] -> String
forall a. Monoid a => [a] -> a
mconcat
        [ String
Item [String]
"Strategy for reading command logs. 'block-line-buffer' is allowed ",
          String
Item [String]
"(and the default) as long as we do not have multiple commands with ",
          String
Item [String]
"file logging. In that scenario, we use 'block'."
        ]

    block :: String
block = String
"block: Reads N (--command-log-read-size) bytes at a time."
    blockLineBuffer :: String
blockLineBuffer =
      [String] -> String
forall a. Monoid a => [a] -> a
mconcat
        [ String
Item [String]
"block-line-buffer: Also reads N bytes at a time, but buffers ",
          String
Item [String]
"newlines, for potentially nicer formatted logs."
        ]

reportReadErrorsParser :: Parser (Maybe ReportReadErrorsSwitch)
reportReadErrorsParser :: Parser (Maybe ReportReadErrorsSwitch)
reportReadErrorsParser =
  Mod OptionFields Bool
-> (Bool -> ReportReadErrorsSwitch)
-> String
-> String
-> Parser (Maybe ReportReadErrorsSwitch)
forall a.
Mod OptionFields Bool
-> (Bool -> a) -> String -> String -> Parser (Maybe a)
Utils.switchParserOpts
    Mod OptionFields Bool
forall (f :: Type -> Type) a. Mod f a
OA.internal
    Bool -> ReportReadErrorsSwitch
MkReportReadErrorsSwitch
    String
"command-log-report-read-errors"
    String
helpTxt
  where
    helpTxt :: String
helpTxt = String
"If active, logs read errors when streaming commands."