{-# LANGUAGE GeneralizedNewtypeDeriving #-} import Options.Applicative as Opt import Data.Aeson import Control.Exception.Safe import qualified Data.Text as T import qualified Data.Text.IO as TIO import Control.Monad import Control.Monad.IO.Class import Data.Semigroup ((<>)) -- required for GHC 8.2 import qualified Data.ByteString as B import System.Exit import System.IO.Error (isDoesNotExistError, ioeGetFileName) import App import ProcessRequest import STExcept data AppMode = FileInput FilePath | Interactive data Params = Params AppMode -- mode FilePath -- config file mkParams :: Opt.Parser Params mkParams = Params <$> (fileInput <|> interactive) <*> config where fileInput = FileInput <$> strOption (long "file" <> short 'f' <> metavar "FILENAME" <> help "Input file" ) interactive = flag Interactive Interactive (long "interactive" <> short 'i' <> help "Interactive mode") config = strOption (long "conf" <> short 'c' <> value "config.json" <> showDefault <> metavar "CONFIGNAME" <> help "Configuration file" ) withConfig :: Params -> IO () withConfig (Params appMode config) = do wauth <- eitherDecodeStrict <$> B.readFile config case wauth of Right wauth' -> runMyApp (run appMode) wauth' Left _ -> throwString $ "Error parsing configuration file" where run (FileInput fname) = liftIO (TIO.readFile fname) >>= processMany . T.lines run Interactive = processInteractively main = (execParser opts >>= withConfig) `catches` [Handler parserExit, Handler printIOError, Handler decodeConfigError, Handler printOtherErrors] where opts = info (mkParams <**> helper) (fullDesc <> progDesc "Reports sunrise/sunset times for the specified location") parserExit :: ExitCode -> IO () parserExit _ = pure () printIOError :: IOException -> IO () printIOError e | isDoesNotExistError e = do let mbfn = ioeGetFileName e putStrLn $ "File " ++ maybe "" id mbfn ++ " not found" | otherwise = putStrLn $ "I/O error: " ++ show e decodeConfigError :: StringException -> IO () decodeConfigError (StringException s _) = putStrLn s printOtherErrors :: SomeException -> IO () printOtherErrors = print