Lisää ReadM-monadi PandocIO-operaatioille
Tällä saadaan pandoc lukemaan tiedostot filestoren Git-tietovarannosta sekä estettyä niiden lukeminen muualta.
This commit is contained in:
parent
dcf00955e9
commit
373e34a9e4
@ -28,6 +28,7 @@
|
|||||||
(inputs (list ghc-acid-state
|
(inputs (list ghc-acid-state
|
||||||
ghc-cryptonite
|
ghc-cryptonite
|
||||||
ghc-case-insensitive
|
ghc-case-insensitive
|
||||||
|
ghc-glob
|
||||||
ghc-purebred-email
|
ghc-purebred-email
|
||||||
ghc-optparse-applicative
|
ghc-optparse-applicative
|
||||||
ghc-filestore
|
ghc-filestore
|
||||||
|
@ -26,7 +26,7 @@ import Web.Scotty (scotty, post, liftAndCatchIO, defaultHandler)
|
|||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Lazy.IO as LT
|
import qualified Data.Text.Lazy.IO as LT
|
||||||
|
|
||||||
import TiedoteMD.Read
|
import TiedoteMD.Read (updateMessages)
|
||||||
import TiedoteMD.Review
|
import TiedoteMD.Review
|
||||||
import TiedoteMD.Send
|
import TiedoteMD.Send
|
||||||
import TiedoteMD.State
|
import TiedoteMD.State
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
|
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
|
|
||||||
module TiedoteMD.Read where
|
module TiedoteMD.Read where
|
||||||
|
|
||||||
import Control.Exception (throwIO)
|
import Control.Exception (throwIO, catch)
|
||||||
import Control.Monad ((>=>), join, unless)
|
import Control.Monad ((>=>), join, unless)
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO, MonadIO)
|
||||||
|
import Control.Monad.Reader (ReaderT, MonadReader, runReaderT, ask)
|
||||||
|
import Control.Monad.Except (MonadError)
|
||||||
|
import Control.Monad.Trans (lift)
|
||||||
import Crypto.Hash (hashWith, SHA256(..))
|
import Crypto.Hash (hashWith, SHA256(..))
|
||||||
import Data.Acid (AcidState, update)
|
import Data.Acid (AcidState, update)
|
||||||
import Data.Bifunctor (first, second)
|
import Data.Bifunctor (first, second)
|
||||||
@ -13,20 +18,22 @@ import Data.ByteArray (convert)
|
|||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import Data.Default (def)
|
import Data.Default (def)
|
||||||
import Data.Either (rights, lefts)
|
import Data.Either (rights, lefts)
|
||||||
import Data.FileStore (FileStore(..), gitFileStore)
|
import Data.FileStore (FileStore(..), Revision(..), FileStoreError(..), gitFileStore)
|
||||||
import Data.List (singleton, isSuffixOf)
|
import Data.List (singleton, isSuffixOf)
|
||||||
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
|
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
|
||||||
import Data.Time (UTCTime, zonedTimeToUTC)
|
import Data.Time (UTCTime, zonedTimeToUTC)
|
||||||
import Data.Time (getCurrentTime)
|
import Data.Time (getCurrentTime)
|
||||||
import Data.Time.Format.ISO8601 (iso8601ParseM)
|
import Data.Time.Format.ISO8601 (iso8601ParseM)
|
||||||
import System.Exit (ExitCode(..))
|
import System.Exit (ExitCode(..))
|
||||||
|
import System.FilePath.Glob (match, compile)
|
||||||
import System.IO (hClose)
|
import System.IO (hClose)
|
||||||
import System.Process (createProcess, proc, waitForProcess, CreateProcess(..), StdStream(..))
|
import System.Process (createProcess, proc, waitForProcess, CreateProcess(..), StdStream(..))
|
||||||
import Text.Pandoc (Pandoc(..))
|
import Text.Pandoc (Pandoc(..), PandocMonad, PandocIO, PandocError)
|
||||||
import Text.Pandoc.Readers (readMarkdown)
|
import Text.Pandoc.Readers (readMarkdown)
|
||||||
import Text.Pandoc.Writers (writePlain, writeMarkdown, writeHtml5String)
|
import Text.Pandoc.Writers (writePlain, writeMarkdown, writeHtml5String)
|
||||||
|
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
|
import qualified Data.ByteString.Lazy as LBS
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.IO as T
|
import qualified Data.Text.IO as T
|
||||||
@ -51,13 +58,51 @@ readMessageFiles store = do
|
|||||||
pure $ filter ((currentTime <) . sendTime) $ rights messages
|
pure $ filter ((currentTime <) . sendTime) $ rights messages
|
||||||
-- TODO: files could be read in parallel instead of sequentially with mapM
|
-- TODO: files could be read in parallel instead of sequentially with mapM
|
||||||
|
|
||||||
|
newtype ReadM a = ReadM (ReaderT FileStore PandocIO a)
|
||||||
|
deriving (Functor, Applicative, Monad, MonadIO, MonadReader FileStore, MonadError PandocError)
|
||||||
|
|
||||||
|
liftPandoc :: PandocIO a -> ReadM a
|
||||||
|
liftPandoc = ReadM . lift
|
||||||
|
|
||||||
|
runReadM :: FileStore -> ReadM a -> IO (Either PandocError a)
|
||||||
|
runReadM store (ReadM m) = Pandoc.runIO $ runReaderT m store
|
||||||
|
|
||||||
|
readStoreFile :: FilePath -> ReadM LBS.ByteString
|
||||||
|
readStoreFile file = do
|
||||||
|
store <- ask
|
||||||
|
liftIO $ retrieve store file Nothing
|
||||||
|
|
||||||
|
instance PandocMonad ReadM where
|
||||||
|
readFileLazy = readStoreFile
|
||||||
|
readFileStrict = fmap LBS.toStrict . readStoreFile
|
||||||
|
getDataFileName = pure
|
||||||
|
getModificationTime file = do
|
||||||
|
store <- ask
|
||||||
|
liftIO $ fmap revDateTime . revision store =<< latest store file
|
||||||
|
fileExists file = do
|
||||||
|
store <- ask
|
||||||
|
liftIO $ (const True <$> latest store file) `catch` \NotFound -> pure False
|
||||||
|
glob pattern = do
|
||||||
|
store <- ask
|
||||||
|
filter (match $ compile pattern) <$> liftIO (index store)
|
||||||
|
lookupEnv = liftPandoc . Pandoc.lookupEnv
|
||||||
|
getCurrentTime = liftPandoc Pandoc.getCurrentTime
|
||||||
|
getCurrentTimeZone = liftPandoc Pandoc.getCurrentTimeZone
|
||||||
|
newStdGen = liftPandoc Pandoc.newStdGen
|
||||||
|
newUniqueHash = liftPandoc Pandoc.newUniqueHash
|
||||||
|
openURL = liftPandoc . Pandoc.openURL
|
||||||
|
readStdinStrict = pure mempty
|
||||||
|
getCommonState = liftPandoc Pandoc.getCommonState
|
||||||
|
putCommonState = liftPandoc . Pandoc.putCommonState
|
||||||
|
logOutput = liftPandoc . Pandoc.logOutput
|
||||||
|
|
||||||
readMessageFile :: FileStore -> FilePath -> IO (Either Error Message)
|
readMessageFile :: FileStore -> FilePath -> IO (Either Error Message)
|
||||||
readMessageFile store = flip (retrieve store) Nothing >=>
|
readMessageFile store = flip (retrieve store) Nothing >=>
|
||||||
uncurry parseMessageFile . addHash . T.filter (/= '\r') . decodeUtf8 . BS.toStrict
|
uncurry (parseMessageFile store) . addHash . T.filter (/= '\r') . decodeUtf8 . BS.toStrict
|
||||||
where addHash text = (convert $ hashWith SHA256 $ encodeUtf8 text, text)
|
where addHash text = (convert $ hashWith SHA256 $ encodeUtf8 text, text)
|
||||||
|
|
||||||
parseMessageFile :: ByteString -> T.Text -> IO (Either Error Message)
|
parseMessageFile :: FileStore -> ByteString -> T.Text -> IO (Either Error Message)
|
||||||
parseMessageFile hash text = fmap (join . first PandocError) . Pandoc.runIO $ do
|
parseMessageFile store hash text = fmap (join . first PandocError) . runReadM store $ do
|
||||||
pandoc@(Pandoc meta _) <- flip readMarkdown text
|
pandoc@(Pandoc meta _) <- flip readMarkdown text
|
||||||
def {Pandoc.readerStandalone = True, Pandoc.readerExtensions = Pandoc.pandocExtensions}
|
def {Pandoc.readerStandalone = True, Pandoc.readerExtensions = Pandoc.pandocExtensions}
|
||||||
let tiedoteMeta = do
|
let tiedoteMeta = do
|
||||||
|
@ -36,6 +36,7 @@ executable tiedote.md
|
|||||||
exit-codes,
|
exit-codes,
|
||||||
file-embed,
|
file-embed,
|
||||||
filestore,
|
filestore,
|
||||||
|
Glob,
|
||||||
hostname,
|
hostname,
|
||||||
lens,
|
lens,
|
||||||
memory,
|
memory,
|
||||||
|
Loading…
Reference in New Issue
Block a user