packages feed

bytepatch-0.3.0: app/CLI.hs

module CLI ( parse ) where

import           Config
import           Options.Applicative
import           Control.Monad.IO.Class
import qualified StreamPatch.Patch.Binary as Bin

parse :: MonadIO m => m Config
parse = execParserWithDefaults desc pConfig
  where desc = "Patch bytestrings (TODO)."

pConfig :: Parser Config
pConfig = Config
    <$> strArgument (metavar "PATCHSCRIPT" <> help "Path to patchscript")
    <*> pCStreamPair
    <*> pCPatchFormat
    <*> pPrintBinary

pCStreamPair :: Parser CStreamPair
pCStreamPair = CStreamPair <$> pCSIn <*> pCSOut
  where
    pCSIn    = pFileArg <|> pStdin
    pCSOut   = pFileOpt <|> pure CStreamStd
    pFileArg = CStreamFile <$> strArgument (metavar "FILE" <> help "Input file")
    pFileOpt = CStreamFile <$> strOption (metavar "FILE" <> long "out-file" <> short 'o' <> help "Output file")
    pStdin   = flag' CStreamStd (long "stdin"  <> help "Use stdin")

pCPatchFormat :: Parser CPatchFormat
pCPatchFormat = CPatchFormat <$> pCPatchDataType <*> pCPatchAlign <*> pBinCfg

pCPatchDataType :: Parser CPatchDataType
pCPatchDataType = option (maybeReader mapper) $
       long "type"
    <> short 't'
    <> help "How to interpret & use patch data (binary/text/text-only)"
    <> metavar "PATCH_TYPE"
  where mapper = \case "text-only" -> Just CTextPatch
                       "bin"       -> Just CBinPatch
                       "binary"    -> Just CBinPatch
                       "text"      -> Just CTextBinPatch
                       _           -> Nothing

pCPatchAlign :: Parser CPatchAlign
pCPatchAlign = flag CNoAlignPatch CAlignPatch $
       long "aligned"
    <> help "Parse alignment data"

pBinCfg :: Parser Bin.Cfg
pBinCfg = Bin.Cfg <$> pExactMatch
  where
    pExactMatch = flag True False $
           long "match-exact"
        <> help "Expected binary data must match exactly (rather than be a prefix)"

pPrintBinary :: Parser Bool
pPrintBinary = switch $
       long "print-binary"
    <> help "Force print binary to stdout"

--------------------------------------------------------------------------------

-- | Execute a 'Parser' with decent defaults.
execParserWithDefaults :: MonadIO m => String -> Parser a -> m a
execParserWithDefaults desc p = liftIO $ customExecParser
    (prefs $ showHelpOnError)
    (info (helper <*> p) (progDesc desc))