{-# LANGUAGE OverloadedStrings #-}
module Main (main) where
import Control.Exception.Safe (MonadThrow, SomeException)
import Control.Monad (void, forM_, when)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Trans.Either (runEitherT)
import Data.Either (isLeft)
import Data.List (foldl')
import Data.Monoid ((<>))
import Data.Text (Text)
import Safe (headMay)
import Turtle (Shell, sh, arguments, procStrictWithErr, ExitCode(..), cut, Pattern, newline, spaces, proc)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
-- | Call `execute` with a haskell-stack command
main :: IO ()
main = runEitherT getBuildCommand >>= sh . execute
where
-- Get a sub command of haskell-stack from CLI arguments.
-- This must be "build" or "test", or empty.
-- If CLI arguments is not given, return "build".
-- If CLI arguments is neither "build" nor "test", throw an exception.
getBuildCommand :: (MonadIO m, MonadThrow m) => m Text
getBuildCommand = do
args <- headMay <$> liftIO arguments
case args of
Nothing -> return "build" -- run 'build' by default
Just "test" -> return "test"
Just "build" -> return "build"
Just unknown -> fail . T.unpack $ "snowtify doesn't know '" <> unknown <> "' command x("
execute :: Either SomeException Text -> Shell ()
execute (Left err) = liftIO $ print err
execute (Right command) = do
(exitCode, out, err) <- procStrictWithErr "stack" [command] ""
let result = out <> err
let notifyer = if exitCode == ExitSuccess
then notifySucceeding
else notifyErrors
notifyer result
-- | Show succeeding with the notify-daemon
notifySucceeding :: Text -> Shell ()
notifySucceeding = void . notifySend . ("stack test is succeed: " <>)
-- | Show errors with the notify-daemon
notifyErrors :: Text -> Shell ()
notifyErrors result = do
let blobs = cut sections result
notifySend "stack test is finished with errors"
forM_ blobs $ \blob ->
when (isErrorSection blob) . void $ notifySend blob
where
sections :: Pattern ()
sections = void $ do
newline
spaces
newline
isErrorSection :: Text -> Bool
isErrorSection x =
case headMay $ T.lines x of
Nothing -> False
Just firstLine -> any (== "error:") $ T.words firstLine
-- | Send a message to the notify-daemon
notifySend :: Text -> Shell ExitCode
notifySend msg = proc "notify-send" ["snowtify", msg] ""