packages feed

teardown 0.4.0.0 → 0.4.1.0

raw patch · 7 files changed

+97/−73 lines, 7 filesdep +gaugedep −criterionPVP ok

version bump matches the API change (PVP)

Dependencies added: gauge

Dependencies removed: criterion

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -7,6 +7,16 @@ [1]: http://semver.org/spec/v2.0.0.html [2]: https://github.com/roman/Haskell-teardown/libraries/teardown/CHANGELOG.md +## v0.4.1.0++* Ensure that all `IO ()` sub-routines on `runTeardown` get executed inside a+  `MaskedUninterruptible` masking state+* Deprecate the `[(Text, IO ())]` instance of `IResource` in favor of creating a+  teardown record per de-allocated resource.+* Replace `criterion` in favor of `gauge`+* Bump `rio` to v0.1.1.0+* Improve upon documentation+ ## v0.4.0.0  **BREAKING CHANGES**
README.md view
@@ -39,7 +39,7 @@ ## Development  [![Build Status](https://travis-ci.org/roman/Haskell-teardown.svg?branch=master)](https://travis-ci.org/roman/Haskell-teardown)-[![Github](https://img.shields.io/github/commits-since/roman/haskell-teardown/v0.1.0.1.svg)](https://img.shields.io/github/commits-since/roman/haskell-teardown/v0.1.0.1.svg)+[![Github](https://img.shields.io/github/commits-since/roman/haskell-teardown/v0.4.0.0.svg)](https://img.shields.io/github/commits-since/roman/haskell-teardown/v0.4.0.0.svg) [![Hackage Dependencies](https://img.shields.io/hackage-deps/v/teardown.svg)](http://packdeps.haskellers.com/feed?needle=teardown)  Follow the [developer guidelines](https://romanandreg.gitbooks.io/teardown/content/CONTRIBUTING.html)
benchmark/Main.hs view
@@ -1,11 +1,16 @@+{-# LANGUAGE CPP               #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} module Main where  import RIO -import Criterion-import Criterion.Main+#if MIN_VERSION_gauge(0,2,0)+import Gauge+#else+import Gauge+import Gauge.Main (defaultMain)+#endif  import Control.Teardown (newTeardown, runTeardown_) @@ -20,4 +25,9 @@           bench "with teardown" (whnfIO $ runTeardown_ unitTeardown)         )       ]+  , env+      (sequence (replicate 1000 (newTeardown "benchmark" (return () :: IO ())))+       >>= newTeardown "parent")+      (\composedTeardown ->+          bench "teardown list" (whnfIO $ runTeardown_ composedTeardown))   ]
src/Control/Teardown/Internal/Core.hs view
@@ -1,4 +1,6 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE NoImplicitPrelude #-} module Control.Teardown.Internal.Core@@ -10,6 +12,7 @@    , runTeardown   , runTeardown_+  , newTeardown   ) where @@ -17,6 +20,10 @@  import RIO.Time (NominalDiffTime, diffUTCTime, getCurrentTime) +#if MIN_VERSION_base(4,11,0)+import qualified GHC.TypeLits as Ty+#endif+ import Control.Teardown.Internal.Types  --------------------------------------------------------------------------------@@ -42,7 +49,7 @@    EmptyResult{}  -> False --- | Creates a new "Teardown" sub-routine from a cleanup "IO" action, the+-- | Creates a new "Teardown" record from a cleanup "IO" action, the -- side-effects from this action are guaranteed to be executed only once, and -- also it is guaranteed to be thread-safe in the scenario of multiple threads -- executing the same teardown procedure.@@ -80,11 +87,6 @@    return $ BranchResult desc elapsed teardownFailed teardownResults --- | Creates a "Teardown" sub-routine that is composed of inner sub-routines---  that are allocated at runtime. This is useful if allocations are being---  created and being hold on a Mutable variable of some sort (e.g. "IORef",---  "TVar", etc) so that on cleanup this Mutable variable is read and the---  results of the teardown operation are returned. newDynTeardown :: Description -> IO [TeardownResult] -> Teardown newDynTeardown desc action = Teardown $ do   teardownResults <- action@@ -99,6 +101,7 @@ --  expects a teardown return but there is no allocation being made emptyTeardown :: Description -> Teardown emptyTeardown desc = Teardown (return $ emptyTeardownResult desc)+{-# INLINE emptyTeardown #-}  -------------------------------------------------------------------------------- @@ -120,13 +123,14 @@       let result = map (foldTeardownResult leafStep branchStep acc) results       in  branchStep result desc --- | Returns number of sub-routines executed at teardown+-- | Returns number of released resources from a "runTeardown" execution toredownCount :: TeardownResult -> Int toredownCount =   foldTeardownResult (\acc _ _ -> acc + 1) (\results _ -> sum results) 0+{-# INLINE toredownCount #-}  -- | Returns number of sub-routines that threw an exception on execution of--- teardown+-- "runTeardown" failedToredownCount :: TeardownResult -> Int failedToredownCount = foldTeardownResult   (\acc _ mErr -> acc + maybe 0 (const 1) mErr)@@ -137,26 +141,45 @@  instance HasTeardown Teardown where   getTeardown = id+  {-# INLINE getTeardown #-} --- | Creates a Teardown record from a simple `IO ()` sub-routine+-- | Creates a new "Teardown" record from a cleanup "IO ()" sub-routine; the+-- Teardown API guarantees:+--+-- * The execution of given "IO ()" sub-routine happens exactly once+-- * The execution is thread-safe when multiple threads try to call "runTeardown"+--+-- IMPORTANT: The @IO ()@ sub-routine _must not_ block or take a long time; this+-- sub-routine cannot be stopped by an async exception instance IResource (IO ()) where   newTeardown =     newTeardownIO+  {-# INLINE newTeardown #-} --- | Creates a Teardown record from a simple list of cleanup sub-routines--- (creating a Teardown record for each), ideal when one single component has--- many resources allocated and need to be cleaned out all at once.+-- | Deprecated instance that creates a Teardown record from a list of cleanup+-- sub-routines (creating a Teardown record for each). --+-- WARNING: This function assumes you are creating many sub-resources at once;+-- this approach has a major risk of leaking resources, and that is why is+-- deprecated; execute newTeardown for every resource you allocate.+-- -- NOTE: The @IO ()@ sub-routines given are going to be executed in reverse -- order at teardown time. --+-- Since 0.4.1.0+#if MIN_VERSION_base(4,11,0)+instance Ty.TypeError ('Ty.Text "DEPRECATED: Execute a 'newTeardown' call per allocated resource")+  => IResource [(Text, IO ())] where+  newTeardown desc actionList =+    concatTeardown desc <$> mapM (uncurry newTeardown) actionList+#else instance IResource [(Text, IO ())] where   newTeardown desc actionList =     concatTeardown desc <$> mapM (uncurry newTeardown) actionList+#endif --- | Wraps a "Teardown" record; the new record will have one extra level of--- description.---+-- | Wraps an existing "Teardown" record; the wrapper "Teardown" record represents+-- a "parent resource" on the "TeardownResult" instance IResource Teardown where   newTeardown desc =     return . concatTeardown desc . return@@ -168,6 +191,7 @@ instance IResource [Teardown] where   newTeardown desc =     return . concatTeardown desc+  {-# INLINE newTeardown #-}  -- | Wraps an IO action that returns a list of "Teardown" record; the new record -- will have one extra level of description. Same behaviour as the @[(Text, IO@@ -177,24 +201,28 @@ instance IResource (IO [Teardown]) where   newTeardown desc getTeardownList =     concatTeardown desc <$> getTeardownList+  {-# INLINE newTeardown #-} --- | Creates a "Teardown" sub-routine that is composed of inner sub-routines---  that are allocated at runtime. This is useful if allocations are being---  created and being hold on a Mutable variable of some sort (e.g. "IORef",---  "TVar", etc) so that on teardown time this Mutable variable is read and---  executed and the results are returned.+-- | Creates a "Teardown" record from executing a sub-routine that releases+--  short-lived "Teardown" records. This is useful when short-lived "Teardown"+--  are accumulated on a collection inside a mutable variable (e.g. @IORef@,+--  @TVar@, etc) and we want to release them instance IResource (IO [TeardownResult]) where   newTeardown desc =     return . newDynTeardown desc+  {-# INLINE newTeardown #-}  -------------------------------------------------------------------------------- --- | Executes all composed "Teardown" sub-routines safely, and returns a Tree--- data structure wich can be used to gather facts from the cleanup process.+-- | Executes all composed "Teardown" sub-routines safely. This version returns+-- a Tree data structure wich can be used to gather facts from the resource+-- cleanup runTeardown :: HasTeardown t => t -> IO TeardownResult runTeardown t0 =-  let (Teardown teardownAction) = getTeardown t0 in teardownAction+  let (Teardown teardownAction) = getTeardown t0 in uninterruptibleMask_ teardownAction+{-# INLINE runTeardown #-} --- | Executes all composed "Teardown" sub-routines safely.+-- | Executes all composed "Teardown" sub-routines safely runTeardown_ :: HasTeardown t => t -> IO () runTeardown_ = void . runTeardown+{-# INLINE runTeardown_ #-}
src/Control/Teardown/Internal/Printer.hs view
@@ -2,12 +2,14 @@ {-# LANGUAGE OverloadedStrings #-} module Control.Teardown.Internal.Printer where -import RIO+import Data.Monoid ((<>))+import RIO         hiding ((<>))  import           Data.Typeable (typeOf) import qualified RIO.Text      as Text  import Text.PrettyPrint.ANSI.Leijen hiding ((<>))+  import Control.Teardown.Internal.Types 
teardown.cabal view
@@ -1,5 +1,5 @@ name: teardown-version: 0.4.0.0+version: 0.4.1.0 cabal-version: >=1.10 build-type: Simple license: MIT@@ -9,16 +9,15 @@ stability: alpha (experimental) homepage: https://github.com/roman/Haskell-teardown#readme bug-reports: https://github.com/roman/Haskell-teardown/issues-synopsis: Build composable components for your application with clear teardown semantics+synopsis: Build safe and composable teardown sub-routines for resources description:     The teardown library allows you to reliably execute cleanup sub-routines for-    allocated resources when a program is initialized; it:+    allocated resources. When a program is initialized, it:     .-    * Ensures that teardown sub-routines are executed /exactly/ once, even on the-    scenario where cleanup is invoked multiple times+    * Ensures that teardown sub-routines are executed /exactly/ once     .-    * Ensures that if errors occur on the execution of one teardown, the error-    does not propagate to other sub-routines; effectively keeping them isolated.+    * Ensures that if errors occur on the execution of a Teardown sub-routine, the+    error does not propagate to others; bulkheading failure on cleanup.     .     * Requires every sub-routine to be documented at creation time; thus helping     tracing your application structure.@@ -76,7 +75,7 @@     main-is: Main.hs     build-depends:         base >=4.8 && <5,-        criterion >=1.1,+        gauge >=0.1.3,         rio >=0.0.0.0,         teardown -any,         typed-process >=0.1.0.0,
test/tasty/TeardownTest.hs view
@@ -4,9 +4,10 @@  import RIO -import           Control.Monad    (replicateM)-import qualified Control.Teardown as SUT-import           Test.Tasty       (TestTree, testGroup)+import           Control.Exception (MaskingState (..), getMaskingState)+import           Control.Monad     (replicateM)+import qualified Control.Teardown  as SUT+import           Test.Tasty        (TestTree, testGroup) import           Test.Tasty.HUnit  @@ -87,38 +88,12 @@         assertEqual "failed teardown action must be correct"                     5                     (SUT.failedToredownCount toredownResult)-  , testCase "teardown with list of description and actions executes correctly"-    $ do-        callCountRef   <- newIORef (0 :: Int)-        teardownAction <- SUT.newTeardown-          "bigger-system"-          [ ("1" :: Text, modifyIORef callCountRef (+ 1) :: IO ())-          , ("2"        , modifyIORef callCountRef (+ 1))-          , ("3"        , modifyIORef callCountRef (+ 1))-          , ("4"        , modifyIORef callCountRef (+ 1))-          , ("5"        , modifyIORef callCountRef (+ 1))-          , ("6"        , error "nope")-          , ("7"        , error "nope")-          , ("8"        , error "nope")-          , ("9"        , error "nope")-          ]---        -- Execute multiple times to assert idempotency-        toredownResult <- SUT.runTeardown teardownAction-        replicateM_ 9 (SUT.runTeardown teardownAction)--        assertEqual "teardown action count must be correct"-                    9-                    (SUT.toredownCount toredownResult)--        assertEqual "failed teardown must be correct"-                    4-                    (SUT.failedToredownCount toredownResult)--        callCount <- readIORef callCountRef-        assertEqual-          "side-effects were executed despite errors on other teardown operations"-          5-          callCount+  , testCase "Teardown sub-routine executes on an uninterruptedMask" $ do+    resultVar <- newEmptyMVar+    teardown  <- SUT.newTeardown "test" (getMaskingState >>= putMVar resultVar)+    SUT.runTeardown_ teardown+    masking <- takeMVar resultVar+    assertEqual "Expecting Teardown masked state is Uninterruptible"+                MaskedUninterruptible+                masking   ]