2020-01-02 23:21:13 +03:00
|
|
|
-- Copyright (c) 2020 The DAML Authors. All rights reserved.
|
2019-04-09 16:09:10 +03:00
|
|
|
-- SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
2019-07-29 17:55:55 +03:00
|
|
|
module DA.Daml.Assistant.Util
|
|
|
|
( module DA.Daml.Assistant.Util
|
2019-05-10 19:32:41 +03:00
|
|
|
, ascendants
|
2019-04-09 16:09:10 +03:00
|
|
|
, fromRightM
|
|
|
|
) where
|
|
|
|
|
2019-07-29 17:55:55 +03:00
|
|
|
import DA.Daml.Assistant.Types
|
|
|
|
import DA.Daml.Project.Util
|
2019-05-09 15:41:45 +03:00
|
|
|
import System.Exit
|
2019-04-09 16:09:10 +03:00
|
|
|
import Control.Exception.Safe
|
|
|
|
import Control.Applicative
|
2019-05-14 09:46:55 +03:00
|
|
|
import Control.Monad.Extra
|
|
|
|
import Data.Either.Extra
|
2019-08-06 11:49:25 +03:00
|
|
|
import System.Process.Typed (ExitCodeException(..))
|
2019-04-09 16:09:10 +03:00
|
|
|
|
|
|
|
-- | Throw an assistant error.
|
|
|
|
throwErr :: Text -> IO a
|
|
|
|
throwErr msg = throwIO (assistantError msg)
|
|
|
|
|
2019-05-09 15:41:45 +03:00
|
|
|
-- | Handle synchronous exceptions by wrapping them in an AssistantError,
|
2019-04-09 16:09:10 +03:00
|
|
|
-- add context to any assistant errors that are missing context.
|
2019-05-09 15:41:45 +03:00
|
|
|
wrapErr :: Text -> IO a -> IO a
|
|
|
|
wrapErr ctx m = m `catches`
|
|
|
|
[ Handler $ throwIO @IO @ExitCode
|
2019-08-06 11:49:25 +03:00
|
|
|
, Handler $ \(ExitCodeException{eceExitCode}) -> exitWith eceExitCode
|
2019-05-09 15:41:45 +03:00
|
|
|
, Handler $ throwIO . addErrorContext
|
|
|
|
, Handler $ throwIO . wrapException
|
|
|
|
]
|
2019-04-09 16:09:10 +03:00
|
|
|
where
|
2019-05-09 15:41:45 +03:00
|
|
|
wrapException :: SomeException -> AssistantError
|
|
|
|
wrapException err =
|
2019-04-09 16:09:10 +03:00
|
|
|
AssistantError
|
|
|
|
{ errContext = Just ctx
|
|
|
|
, errMessage = Nothing
|
2019-05-09 15:41:45 +03:00
|
|
|
, errInternal = Just (pack (show err))
|
2019-04-09 16:09:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
addErrorContext :: AssistantError -> AssistantError
|
|
|
|
addErrorContext err =
|
|
|
|
err { errContext = errContext err <|> Just ctx }
|
|
|
|
|
2019-05-14 09:46:55 +03:00
|
|
|
-- | Catch a config error.
|
|
|
|
tryConfig :: IO t -> IO (Either ConfigError t)
|
|
|
|
tryConfig = try
|
|
|
|
|
|
|
|
-- | Catch an assistant error.
|
|
|
|
tryAssistant :: IO t -> IO (Either AssistantError t)
|
|
|
|
tryAssistant = try
|
|
|
|
|
|
|
|
-- | Catch an assistant error and ignore the error case.
|
|
|
|
tryAssistantM :: IO t -> IO (Maybe t)
|
|
|
|
tryAssistantM m = eitherToMaybe <$> tryAssistant m
|
|
|
|
|
2019-04-09 16:09:10 +03:00
|
|
|
|
|
|
|
-- | Throw an assistant error if the passed value is Nothing.
|
|
|
|
-- Otherwise return the underlying value.
|
|
|
|
--
|
|
|
|
-- required msg Nothing == throwErr msg
|
|
|
|
-- required msg . Just == pure
|
|
|
|
--
|
|
|
|
required :: Text -> Maybe t -> IO t
|
|
|
|
required msg = maybe (throwErr msg) pure
|
|
|
|
|
|
|
|
-- | Same as 'required' but operates over Either values.
|
|
|
|
--
|
|
|
|
-- requiredE msg (Left e) = throwErr (msg <> "\nInternal error: " <> show e)
|
|
|
|
-- requiredE msg . Right = pure
|
|
|
|
--
|
|
|
|
requiredE :: Exception e => Text -> Either e t -> IO t
|
|
|
|
requiredE msg = fromRightM (throwIO . assistantErrorBecause msg . pack . displayException)
|
|
|
|
|
|
|
|
-- | Catch IOExceptions and re-throw them as AssistantError with a helpful message.
|
|
|
|
requiredIO :: Text -> IO t -> IO t
|
2019-05-09 15:41:45 +03:00
|
|
|
requiredIO msg m = catchIO m (rethrow msg)
|
2019-04-09 16:09:10 +03:00
|
|
|
|
2019-05-09 15:41:45 +03:00
|
|
|
-- | Same as requiredIO but also catches and re-throws any synchronous exception.
|
|
|
|
requiredAny :: Text -> IO a -> IO a
|
|
|
|
requiredAny msg m = m `catches`
|
|
|
|
[ Handler $ \ (e :: AssistantError) -> throwIO e
|
|
|
|
, Handler $ \ (e :: SomeException) -> rethrow msg e
|
2019-05-02 16:12:31 +03:00
|
|
|
]
|
|
|
|
|
2019-05-09 15:41:45 +03:00
|
|
|
-- | Rethrow an exception with helpful message.
|
|
|
|
rethrow :: Exception e => Text -> e -> IO a
|
|
|
|
rethrow msg = throwIO . assistantErrorBecause msg . pack . displayException
|
2019-05-02 16:12:31 +03:00
|
|
|
|
2019-04-09 16:09:10 +03:00
|
|
|
-- | Like 'whenMaybeM' but only returns a 'Just' value if the test is false.
|
|
|
|
unlessMaybeM :: Monad m => m Bool -> m t -> m (Maybe t)
|
|
|
|
unlessMaybeM = whenMaybeM . fmap not
|