{-# LANGUAGE CPP, ScopedTypeVariables #-}

module Propellor.Exception where

import Propellor.Types
import Propellor.Types.Exception
import Propellor.Message
import Utility.Exception

import Control.Exception (AsyncException)
#if MIN_VERSION_base(4,7,0)
import Control.Exception (SomeAsyncException)
#endif
import Control.Monad.Catch
import Control.Monad.IO.Class (MonadIO)
import Prelude

-- | Catches all exceptions (except for `StopPropellorException` and
-- `AsyncException` and `SomeAsyncException`) and returns FailedChange.
catchPropellor :: (MonadIO m, MonadCatch m) => m Result -> m Result
catchPropellor :: forall (m :: * -> *).
(MonadIO m, MonadCatch m) =>
m Result -> m Result
catchPropellor m Result
a = forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall {m :: * -> *} {a}. (MonadIO m, Show a) => a -> m Result
err forall (m :: * -> *) a. Monad m => a -> m a
return forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (m :: * -> *) a.
MonadCatch m =>
m a -> m (Either SomeException a)
tryPropellor m Result
a
  where
	err :: a -> m Result
err a
e =  forall (m :: * -> *). MonadIO m => String -> m ()
warningMessage (forall a. Show a => a -> String
show a
e) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return Result
FailedChange

catchPropellor' :: MonadCatch m => m a -> (SomeException -> m a) -> m a
catchPropellor' :: forall (m :: * -> *) a.
MonadCatch m =>
m a -> (SomeException -> m a) -> m a
catchPropellor' m a
a SomeException -> m a
onerr = m a
a forall (f :: * -> *) (m :: * -> *) a.
(Foldable f, MonadCatch m) =>
m a -> f (Handler m a) -> m a
`catches`
	[ forall (m :: * -> *) a e. Exception e => (e -> m a) -> Handler m a
Handler (\ (AsyncException
e :: AsyncException) -> forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM AsyncException
e)
#if MIN_VERSION_base(4,7,0)
	, forall (m :: * -> *) a e. Exception e => (e -> m a) -> Handler m a
Handler (\ (SomeAsyncException
e :: SomeAsyncException) -> forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM SomeAsyncException
e)
#endif
	, forall (m :: * -> *) a e. Exception e => (e -> m a) -> Handler m a
Handler (\ (StopPropellorException
e :: StopPropellorException) -> forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM StopPropellorException
e)
	, forall (m :: * -> *) a e. Exception e => (e -> m a) -> Handler m a
Handler (\ (SomeException
e :: SomeException) -> SomeException -> m a
onerr SomeException
e)
	]

-- | Catches all exceptions (except for `StopPropellorException` and
-- `AsyncException`).
tryPropellor :: MonadCatch m => m a -> m (Either SomeException a)
tryPropellor :: forall (m :: * -> *) a.
MonadCatch m =>
m a -> m (Either SomeException a)
tryPropellor m a
a = (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. b -> Either a b
Right forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m a
a) forall (m :: * -> *) a.
MonadCatch m =>
m a -> (SomeException -> m a) -> m a
`catchPropellor'` (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> Either a b
Left)