Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ghc-unliftio for openSUSE:Factory checked in at 2021-06-01 10:39:11 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ghc-unliftio (Old) and /work/SRC/openSUSE:Factory/.ghc-unliftio.new.1898 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-unliftio" Tue Jun 1 10:39:11 2021 rev:17 rq:896220 version:0.2.17 Changes: -------- --- /work/SRC/openSUSE:Factory/ghc-unliftio/ghc-unliftio.changes 2021-05-11 23:04:18.816915744 +0200 +++ /work/SRC/openSUSE:Factory/.ghc-unliftio.new.1898/ghc-unliftio.changes 2021-06-01 10:40:48.381154701 +0200 @@ -1,0 +2,10 @@ +Sat May 29 15:59:30 UTC 2021 - [email protected] + +- Update unliftio to version 0.2.17. + ## 0.2.17 + + * Re-export `AsyncCancelled` in `UnliftIO.Async` [#80](https://github.com/fpco/unliftio/pull/80) + * Add `fromExceptionUnwrap` [#80](https://github.com/fpco/unliftio/pull/80) + * Add `catchSyncOrAsync`, `handleSyncOrAsync`, and `trySyncOrAsync` [#80](https://github.com/fpco/unliftio/pull/80) + +------------------------------------------------------------------- Old: ---- unliftio-0.2.16.tar.gz New: ---- unliftio-0.2.17.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ghc-unliftio.spec ++++++ --- /var/tmp/diff_new_pack.88pTI9/_old 2021-06-01 10:40:48.889155566 +0200 +++ /var/tmp/diff_new_pack.88pTI9/_new 2021-06-01 10:40:48.889155566 +0200 @@ -19,7 +19,7 @@ %global pkg_name unliftio %bcond_with tests Name: ghc-%{pkg_name} -Version: 0.2.16 +Version: 0.2.17 Release: 0 Summary: The MonadUnliftIO typeclass for unlifting monads to IO (batteries included) License: MIT ++++++ unliftio-0.2.16.tar.gz -> unliftio-0.2.17.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/unliftio-0.2.16/ChangeLog.md new/unliftio-0.2.17/ChangeLog.md --- old/unliftio-0.2.16/ChangeLog.md 2021-05-10 07:54:27.000000000 +0200 +++ new/unliftio-0.2.17/ChangeLog.md 2021-05-28 12:11:59.000000000 +0200 @@ -1,5 +1,11 @@ # Changelog for unliftio +## 0.2.17 + +* Re-export `AsyncCancelled` in `UnliftIO.Async` [#80](https://github.com/fpco/unliftio/pull/80) +* Add `fromExceptionUnwrap` [#80](https://github.com/fpco/unliftio/pull/80) +* Add `catchSyncOrAsync`, `handleSyncOrAsync`, and `trySyncOrAsync` [#80](https://github.com/fpco/unliftio/pull/80) + ## 0.2.16 * Add `createFileLink` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/unliftio-0.2.16/src/UnliftIO/Async.hs new/unliftio-0.2.17/src/UnliftIO/Async.hs --- old/unliftio-0.2.16/src/UnliftIO/Async.hs 2021-05-10 07:54:27.000000000 +0200 +++ new/unliftio-0.2.17/src/UnliftIO/Async.hs 2021-05-28 12:11:59.000000000 +0200 @@ -67,7 +67,12 @@ #if MIN_VERSION_base(4,8,0) Conc, conc, runConc, - ConcException (..) + ConcException (..), +#endif + + -- * Re-exports +#if MIN_VERSION_async(2,2,0) + A.AsyncCancelled (..), #endif ) where diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/unliftio-0.2.16/src/UnliftIO/Exception.hs new/unliftio-0.2.17/src/UnliftIO/Exception.hs --- old/unliftio-0.2.16/src/UnliftIO/Exception.hs 2021-05-10 07:54:27.000000000 +0200 +++ new/unliftio-0.2.17/src/UnliftIO/Exception.hs 2021-05-28 12:11:59.000000000 +0200 @@ -51,6 +51,11 @@ , catches , catchesDeep + -- * Catching async exceptions (with recovery) + , catchSyncOrAsync + , handleSyncOrAsync + , trySyncOrAsync + -- * Cleanup (no recovery) , onException , bracket @@ -65,6 +70,7 @@ , toSyncException , AsyncExceptionWrapper (..) , toAsyncException + , fromExceptionUnwrap -- * Check exception type , isSyncException @@ -155,6 +161,19 @@ catchJust :: (MonadUnliftIO m, Exception e) => (e -> Maybe b) -> m a -> (b -> m a) -> m a catchJust f a b = a `catch` \e -> maybe (liftIO (throwIO e)) b $ f e +-- | A variant of 'catch' that catches both synchronous and asynchronous exceptions. +-- +-- WARNING: This function (and other @*SyncOrAsync@ functions) is for advanced users. Most of the +-- time, you probably want to use the non-@SyncOrAsync@ versions. +-- +-- Before attempting to use this function, be familiar with the "Rules for async safe handling" +-- section in +-- [this blog post](https://www.fpcomplete.com/blog/2018/04/async-exception-handling-haskell/). +-- +-- @since 0.2.17 +catchSyncOrAsync :: (MonadUnliftIO m, Exception e) => m a -> (e -> m a) -> m a +catchSyncOrAsync f g = withRunInIO $ \run -> run f `EUnsafe.catch` \e -> run (g e) + -- | Flipped version of 'catch'. -- -- @since 0.1.0.0 @@ -191,6 +210,14 @@ handleJust :: (MonadUnliftIO m, Exception e) => (e -> Maybe b) -> (b -> m a) -> m a -> m a handleJust f = flip (catchJust f) +-- | A variant of 'handle' that catches both synchronous and asynchronous exceptions. +-- +-- See 'catchSyncOrAsync'. +-- +-- @since 0.2.17 +handleSyncOrAsync :: (MonadUnliftIO m, Exception e) => (e -> m a) -> m a -> m a +handleSyncOrAsync = flip catchSyncOrAsync + -- | Run the given action and catch any synchronous exceptions as a 'Left' value. -- -- This is parameterized on the exception type. To catch all synchronous exceptions, @@ -232,6 +259,14 @@ tryJust :: (MonadUnliftIO m, Exception e) => (e -> Maybe b) -> m a -> m (Either b a) tryJust f a = catch (Right `liftM` a) (\e -> maybe (throwIO e) (return . Left) (f e)) +-- | A variant of 'try' that catches both synchronous and asynchronous exceptions. +-- +-- See 'catchSyncOrAsync'. +-- +-- @since 0.2.17 +trySyncOrAsync :: (MonadUnliftIO m, Exception e) => m a -> m (Either e a) +trySyncOrAsync f = catchSyncOrAsync (liftM Right f) (return . Left) + -- | Evaluate the value to WHNF and catch any synchronous exceptions. -- -- The expression may still have bottom values within it; you may @@ -472,6 +507,20 @@ where se = toException e +-- | Convert from a possibly wrapped exception. +-- +-- The inverse of 'toAsyncException' and 'toSyncException'. When using those +-- functions (or functions that use them, like 'throwTo' or 'throwIO'), +-- 'fromException' might not be sufficient because the exception might be +-- wrapped within 'SyncExceptionWrapper' or 'AsyncExceptionWrapper'. +-- +-- @since 0.2.17 +fromExceptionUnwrap :: Exception e => SomeException -> Maybe e +fromExceptionUnwrap se + | Just (AsyncExceptionWrapper e) <- fromException se = cast e + | Just (SyncExceptionWrapper e) <- fromException se = cast e + | otherwise = fromException se + -- | Check if the given exception is synchronous. -- -- @since 0.1.0.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/unliftio-0.2.16/test/UnliftIO/ExceptionSpec.hs new/unliftio-0.2.17/test/UnliftIO/ExceptionSpec.hs --- old/unliftio-0.2.16/test/UnliftIO/ExceptionSpec.hs 2021-05-10 07:54:27.000000000 +0200 +++ new/unliftio-0.2.17/test/UnliftIO/ExceptionSpec.hs 2021-05-28 12:11:59.000000000 +0200 @@ -1,10 +1,92 @@ +{-# LANGUAGE CPP #-} + module UnliftIO.ExceptionSpec (spec) where +import qualified Control.Exception +import Control.Monad (void, (<=<)) +import Data.Bifunctor (first) import Test.Hspec import UnliftIO +import UnliftIO.Concurrent (threadDelay) + +#if MIN_VERSION_async(2,2,0) +cancelled :: AsyncCancelled +cancelled = AsyncCancelled +#else +cancelled :: Control.Exception.AsyncException +cancelled = Control.Exception.ThreadKilled +#endif spec :: Spec spec = do + let -- The callback will run in a thread that gets cancelled immediately, + -- then get Exception2 thrown synchronously after 1 second. + withAsyncExceptionThrown :: (IO a -> IO b) -> IO b + withAsyncExceptionThrown f = do + var <- newEmptyMVar + a <- async $ f $ do + putMVar var () + threadDelay 1000000 + throwIO Exception2 + -- wait until thread is running, then cancel + takeMVar var + cancel a + -- check result + wait a + -- The callback will run in a thread that gets Exception1 thrown as + -- an async exception immediately, then get Exception2 thrown + -- synchronously after 1 second. + withWrappedAsyncExceptionThrown :: (IO a -> IO b) -> IO b + withWrappedAsyncExceptionThrown f = do + var <- newEmptyMVar + a <- async $ f $ do + putMVar var () + threadDelay 1000000 + throwIO Exception2 + -- wait until thread is running, then cancel + takeMVar var + throwTo (asyncThreadId a) Exception1 + -- check result + wait a + describe "catchSyncOrAsync" $ do + it "should catch sync exceptions" $ do + result <- (`catchSyncOrAsync` return) $ throwIO Exception1 + result `shouldBe` Exception1 + it "should catch async exceptions" $ do + result <- withAsyncExceptionThrown $ \m -> m `catchSyncOrAsync` return + result `shouldBe` cancelled + it "should catch unliftio-wrapped async exceptions" $ do + result <- withWrappedAsyncExceptionThrown $ \m -> m `catchSyncOrAsync` return + fromExceptionUnwrap result `shouldBe` Just Exception1 + describe "handleSyncOrAsync" $ do + it "should catch sync exceptions" $ do + result <- handleSyncOrAsync return $ throwIO Exception1 + result `shouldBe` Exception1 + it "should catch async exceptions" $ do + result <- withAsyncExceptionThrown $ \m -> handleSyncOrAsync return m + result `shouldBe` cancelled + it "should catch unliftio-wrapped async exceptions" $ do + result <- withWrappedAsyncExceptionThrown $ \m -> handleSyncOrAsync return m + fromExceptionUnwrap result `shouldBe` Just Exception1 + describe "trySyncOrAsync" $ do + it "should catch sync exceptions" $ do + result <- trySyncOrAsync $ void $ throwIO Exception1 + result `shouldBe` Left Exception1 + it "should catch async exceptions" $ do + result <- withAsyncExceptionThrown $ \m -> trySyncOrAsync (void m) + result `shouldBe` Left cancelled + it "should catch unliftio-wrapped async exceptions" $ do + result <- withWrappedAsyncExceptionThrown $ \m -> trySyncOrAsync (void m) + first fromExceptionUnwrap result `shouldBe` Left (Just Exception1) + + describe "fromExceptionUnwrap" $ do + it "should be the inverse of toAsyncException" $ do + fromExceptionUnwrap (toAsyncException Exception1) `shouldBe` Just Exception1 + it "should be the inverse of toSyncException" $ do + let toAsyncToSync = toSyncException . toAsyncException + fromSyncFromAsyc = fromExceptionUnwrap <=< fromExceptionUnwrap + fromSyncFromAsyc (toAsyncToSync Exception1) `shouldBe` Just Exception1 + let shouldLeft x = either (const Nothing) Just x `shouldBe` Nothing shouldRight x = either (Just . show) (const Nothing) x `shouldBe` Nothing describe "pureTry" $ do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/unliftio-0.2.16/unliftio.cabal new/unliftio-0.2.17/unliftio.cabal --- old/unliftio-0.2.16/unliftio.cabal 2021-05-10 07:54:33.000000000 +0200 +++ new/unliftio-0.2.17/unliftio.cabal 2021-05-28 12:11:59.000000000 +0200 @@ -1,13 +1,13 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.33.0. +-- This file has been generated from package.yaml by hpack version 0.34.4. -- -- see: https://github.com/sol/hpack -- --- hash: 57462bd1ca0ffabd88cb1b743945f84d5c6330a59b7b364445e08d6399628d80 +-- hash: 6dc6425588ff3d300e7e59ea7cb3a42401bdb810af3e566aa8bd26ec2718a3bb name: unliftio -version: 0.2.16 +version: 0.2.17 synopsis: The MonadUnliftIO typeclass for unlifting monads to IO (batteries included) description: Please see the documentation and README at <https://www.stackage.org/package/unliftio> category: Control
