module Darcs.Util.Exception
( firstJustIO
, catchall
, catchNonExistence
, clarifyErrors
, prettyException
, prettyError
, die
, handleOnly
, handleOnlyIOError
, ifIOError
, ifDoesNotExistError
) where
import Darcs.Prelude
import Control.Exception
( Exception(fromException)
, SomeException
, catch
, handle
, throwIO
)
import Data.Maybe ( isJust )
import System.Exit ( exitFailure )
import System.IO ( stderr, hPutStrLn )
import System.IO.Error
( ioeGetErrorString
, ioeGetFileName
, isDoesNotExistError
, isUserError
)
import Darcs.Util.SignalHandler ( catchNonSignal )
catchall :: IO a
-> IO a
-> IO a
a `catchall` b = a `catchNonSignal` (\_ -> b)
catchNonExistence :: IO a -> a -> IO a
catchNonExistence job nonexistval =
catch job $
\e -> if isDoesNotExistError e then return nonexistval
else ioError e
firstJustM :: Monad m
=> [m (Maybe a)]
-> m (Maybe a)
firstJustM [] = return Nothing
firstJustM (e:es) = e >>= (\v -> if isJust v then return v else firstJustM es)
firstJustIO :: [IO (Maybe a)]
-> IO (Maybe a)
firstJustIO = firstJustM . map (`catchall` return Nothing)
clarifyErrors :: IO a
-> String
-> IO a
clarifyErrors a e = a `catch` (\x -> die $ unlines [prettyException x,e])
prettyException :: SomeException
-> String
prettyException e | Just ioe <- fromException e, isUserError ioe = ioeGetErrorString ioe
prettyException e | Just ioe <- fromException e, isDoesNotExistError ioe =
case ioeGetFileName ioe of
Just f -> f ++ " does not exist"
Nothing -> show e
prettyException e = show e
prettyError :: IOError -> String
prettyError e | isUserError e = ioeGetErrorString e
| otherwise = show e
die :: String -> IO a
die msg = hPutStrLn stderr msg >> exitFailure
handleOnlyIOError :: IO a -> IO a -> IO a
handleOnlyIOError = handleOnly (not . isUserError)
ifIOError :: a -> IO a -> IO a
ifIOError use_instead = handleOnlyIOError (return use_instead)
ifDoesNotExistError :: a -> IO a -> IO a
ifDoesNotExistError use_instead = handleOnly isDoesNotExistError (return use_instead)
handleOnly :: Exception e => (e -> Bool) -> IO a -> IO a -> IO a
handleOnly pred handler = handle (\e -> if pred e then handler else throwIO e)