marvin-0.2.1: preprocessor/Main.hs
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
import Control.Monad (filterM)
import Data.Aeson hiding (object)
import qualified Data.ByteString.Lazy as B
import qualified Data.Configurator as C
import Data.List (intercalate, isPrefixOf)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import qualified Data.Text.IO as T
import Marvin.Run (defaultConfigName, lookupFromAppConfig)
import Options.Applicative
import Prelude
import System.Directory
import System.FilePath
import Text.Mustache
import Text.Mustache.Compile
data Opts = Opts
{ adapter :: Maybe String
, sourceName :: FilePath
, sourceLocation :: FilePath
, targetFile :: FilePath
, externalScripts :: FilePath
, configLocation :: Maybe FilePath
}
slackRtmData :: (String, String)
slackRtmData = ("Marvin.Adapter.Slack.RTM", "(SlackAdapter RTM)")
adapters :: [(String, (String, String))]
adapters =
[ ("slack-rtm", slackRtmData)
, ("slack-events", ("Marvin.Adapter.Slack.EventsAPI", "(SlackAdapter EventsAPI)"))
, ("telegram-poll", ("Marvin.Adapter.Telegram.Poll", "(TelegramAdapter Poll)"))
, ("telegram-push", ("Marvin.Adapter.Telegram.Push", "(TelegramAdapter Push)"))
, ("shell", ("Marvin.Adapter.Shell", "ShellAdapter"))
, ("irc", ("Marvin.Adapter.IRC", "IRCAdapter"))
]
tpl :: Template
tpl = $(embedTemplate ["preprocessor"] "Main.mustache")
main :: IO ()
main = do
Opts{..} <- execParser infoParser
adapter' <- maybe
(do
(cfg, _) <- C.autoReload C.autoConfig $ maybe [] (return . C.Optional) configLocation
lookupFromAppConfig cfg "adapter"
)
(return . return)
adapter
let (adapterImport, adapterType) = fromMaybe slackRtmData $ adapter' >>= flip lookup adapters
let dir = takeDirectory sourceName
paths <- filter (not . ((||) <$> isPrefixOf "_" <*> isPrefixOf ".")) <$> getDirectoryContents dir
files <- filterM (doesFileExist . (dir </>)) paths
externals <- do
exists <- doesFileExist externalScripts
if exists
then do
f <- B.readFile externalScripts
either error return $ eitherDecode f
else return mempty
let hsFiles = map dropExtensions $ filter (/= takeFileName sourceName) $ filter ((`elem` [".hs", ".lhs"]) . takeExtension) files
scripts = hsFiles <> externals
processed = substitute tpl (object [ "scripts" ~> intercalate ", " (map (<> ".script") scripts)
, "imports" ~> scripts
, "adapter-import" ~> adapterImport
, "adapter-type" ~> adapterType
])
T.writeFile targetFile processed
where
infoParser = info
(helper <*> optsParser)
(fullDesc <> header "marvin-pp ~ the marvin preprocessor")
optsParser = Opts
<$> optional
(strOption
$ long "adapter"
<> short 'a'
<> metavar "ID"
<> help "adapter to use"
<> showDefault
)
<*> argument str (metavar "NAME")
<*> argument str (metavar "PATH")
<*> argument str (metavar "PATH")
<*> strOption
( long "external-scripts"
<> short 's'
<> value "external-scripts.json"
<> metavar "PATH"
<> help "config file of external scripts to load"
<> showDefault
)
<*> optional
(strOption
$ long "config-location"
<> short 'c'
<> metavar "PATH"
<> help "config to use"
<> showDefault
<> value defaultConfigName
)