coformat-0.3.0.0: src/Language/Coformat/Formatter.hs
{-# LANGUAGE DataKinds, GADTs, RankNTypes, TypeApplications #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecordWildCards #-}
module Language.Coformat.Formatter where
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy.Char8 as LBS
import qualified Data.Text as T
import Control.Monad.Except.CoHas
import System.Command hiding(cmd)
import System.Exit
import Language.Coformat.Descr
import Language.Coformat.Formatter.Failure
import Language.Coformat.Util
data OptsDescription stage = OptsDescription
{ knownOpts :: [ConfigItemT stage]
, baseStyles :: [T.Text]
}
data OptsSource opts
= StaticOpts opts
| OptsFromFile FilePath (LBS.ByteString -> Either String opts)
| OptsFromCmd CmdArgs (BS.ByteString -> Either String opts)
parseOpts :: (MonadIO m, MonadError String m) => String -> OptsSource opts -> m opts
parseOpts _ (StaticOpts d) = pure d
parseOpts _ (OptsFromFile path parser) = parser <$> liftIO (LBS.readFile path) >>= liftEither
parseOpts exec (OptsFromCmd args parser) = convert (show @Failure) (runCommand exec args) >>= liftEither . parser
data FormatterInfo = FormatterInfo
{ execName :: String
, formatterOpts :: OptsSource (OptsDescription 'Supported)
, hardcodedOpts :: [ConfigItemT 'Value]
, defaultStyleOpts :: T.Text -> [ConfigItemT 'Supported] -> [ConfigItemT 'Value] -> OptsSource [ConfigItemT 'Value]
, formatFile :: T.Text -> [ConfigItemT 'Value] -> FilePath -> CmdArgs
, serializeOptions :: T.Text -> [ConfigItemT 'Value] -> BS.ByteString
}
newtype CmdArgs = CmdArgs
{ args :: [BS.ByteString]
} deriving (Show)
runCommand :: (MonadError err m, CoHas UnexpectedFailure err, CoHas ExpectedFailure err, MonadIO m)
=> String -> CmdArgs -> m BS.ByteString
runCommand exec (CmdArgs args) = do
(ec, stdout, stderr) <- liftIO $ command [] exec $ BS.unpack <$> args
case ec of ExitSuccess -> pure $ BS.pack $ fromStdout stdout
ExitFailure n | n == cfCrashRetCode -> throwError $ FormatterSegfaulted $ T.pack $ fromStderr stderr
| otherwise -> throwError $ FormatterFailure n $ T.pack $ fromStderr stderr
where
cfCrashRetCode = -8
data Formatter where
Formatter :: forall resumeObj.
{ formatterInfo :: FormatterInfo
, parseResumeObject :: BS.ByteString -> Either String resumeObj
, parseResumeOptions :: [ConfigItemT 'Supported] -> resumeObj -> Either String (T.Text, [ConfigItemT 'Value])
} -> Formatter