{-# LANGUAGE ScopedTypeVariables #-}
module OrgStat.IO
( readOrgFile
, readConfig
) where
import qualified Prelude
import Universum
import qualified Data.ByteString as BS
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Data.Yaml (decodeEither')
import System.Directory (doesFileExist)
import System.FilePath (takeBaseName, takeExtension)
import Turtle (ExitCode (..), procStrict)
import OrgStat.Ast (Org)
import OrgStat.Config (ConfigException (ConfigParseException), OrgStatConfig)
import OrgStat.Logging
import OrgStat.Parser (runParser)
import OrgStat.Util (dropEnd)
data OrgIOException
= OrgIOException Text
| ExternalException Text
deriving (Typeable)
instance Show OrgIOException where
show (OrgIOException r) = "IOException: " <> T.unpack r
show (ExternalException r) = "ExternalException: " <> T.unpack r
instance Exception OrgIOException
readOrgFile
:: (MonadIO m, MonadCatch m)
=> [Text] -> FilePath -> m (Text, Org)
readOrgFile todoKeywords fp = do
logDebug $ "Reading org file " <> fpt
unlessM (liftIO $ doesFileExist fp) $
throwM $ OrgIOException $ "Org file " <> fpt <> " doesn't exist"
(content, fname) <- case takeExtension fp of
".gpg" -> (,dropEnd 4 fp) <$> decryptGpg
".org" -> (,fp) <$> liftIO (TIO.readFile fp)
_ -> throwM $ OrgIOException $
"File " <> fpt <> " has unknown extension. Need to be .org or .org.gpg"
let filename = T.pack $ takeBaseName fname
logDebug $ "Parsing org file " <> fpt
parsed <- runParser todoKeywords content
pure (filename, parsed)
where
fpt = T.pack fp
failExternal = throwM . ExternalException
decryptGpg = do
logDebug $ "Decrypting gpg file: " <> fpt
(exCode, output) <-
(procStrict "gpg" ["--quiet", "--decrypt", fpt] empty)
`catch`
(\(e :: SomeException) -> failExternal $ "gpg procStrict failed: " <> show e)
case exCode of
ExitSuccess -> pass
ExitFailure n -> failExternal $ "Gpg failed with code " <> show n
pure output
readConfig :: (MonadIO m, MonadThrow m) => FilePath -> m OrgStatConfig
readConfig fp = do
unlessM (liftIO $ doesFileExist fp) $
throwM $ OrgIOException $ "Config file " <> fpt <> " doesn't exist"
res <- liftIO $ BS.readFile fp
either (throwM . ConfigParseException . show) pure $ decodeEither' res
where
fpt = T.pack fp