packages feed

silently 1.2.5.2 → 1.2.5.3

raw patch · 4 files changed

+106/−76 lines, 4 filesdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base

API changes (from Hackage documentation)

- System.IO.Silently: hCapture :: [Handle] -> IO a -> IO (String, a)
+ System.IO.Silently: hCapture :: forall a. [Handle] -> IO a -> IO (String, a)
- System.IO.Silently: hSilence :: [Handle] -> IO a -> IO a
+ System.IO.Silently: hSilence :: forall a. [Handle] -> IO a -> IO a

Files

CHANGELOG.md view
@@ -1,3 +1,10 @@+# 1.2.5.3 August 2022++* Tested with GHC 7.0 - 9.4.1.+* Remove remnants of GHC 6.x support.+* Silence incomplete pattern matching warning, refactor code.+* Add section about limitations to README.+ # 1.2.5.2 November 2021  * Tested with GHC 7.0 - 9.2.
README.md view
@@ -28,3 +28,12 @@  captured: wookies!  returned: 123 ```++## Limitations++Capturing/silencing might not work as expected if the action uses the FFI+or conceals output under `unsafePerformIO` or similar unsafe operations.++Examples:+- FFI: https://github.com/hspec/silently/issues/3+- `unsafePerformIO`: https://github.com/bos/filemanip/issues/22
silently.cabal view
@@ -1,6 +1,6 @@-name: silently-version: 1.2.5.2 cabal-version: >= 1.10+name: silently+version: 1.2.5.3 build-type: Simple license: BSD3 license-file: LICENSE@@ -13,21 +13,23 @@ description: Prevent or capture writing to stdout, stderr, and other handles. category: System, Testing author: Trystan Spangler+ tested-with:-  GHC == 7.0.4-  GHC == 7.2.2-  GHC == 7.4.2-  GHC == 7.6.3-  GHC == 7.8.4-  GHC == 7.10.3-  GHC == 8.0.2-  GHC == 8.2.2-  GHC == 8.4.4-  GHC == 8.6.5-  GHC == 8.8.4+  GHC == 9.4.1+  GHC == 9.2.4+  GHC == 9.0.2   GHC == 8.10.7-  GHC == 9.0.1-  GHC == 9.2.1+  GHC == 8.8.4+  GHC == 8.6.5+  GHC == 8.4.4+  GHC == 8.2.2+  GHC == 8.0.2+  GHC == 7.10.3+  GHC == 7.8.4+  GHC == 7.6.3+  GHC == 7.4.2+  GHC == 7.2.2+  GHC == 7.0.4  extra-source-files:   CHANGELOG.md@@ -46,7 +48,7 @@       System.IO.Silently    build-depends:-      base >=4 && <=5+      base >= 4.3 && < 5     , directory     , deepseq @@ -54,6 +56,12 @@     cpp-options: -DWINDOWS   if os(linux) || os(osx) || os(freebsd) || os(openbsd) || os(netbsd)     cpp-options: -DUNIX++  ghc-options:+    -Wall+  if impl(ghc >= 8)+    ghc-options:+      -Wcompat  -- This tests the platform specific implementation. --
src/System/IO/Silently.hs view
@@ -1,29 +1,32 @@ {-# LANGUAGE CPP #-}--- | Need to prevent output to the terminal, a file, or stderr? Need to capture it and use it for--- your own means? Now you can, with 'silence' and 'capture'.+{-# LANGUAGE ScopedTypeVariables #-} -module System.IO.Silently (-  silence,-  hSilence,-  capture,-  capture_,-  hCapture,-  hCapture_,-) where+-- | Need to prevent output to the terminal, a file, or stderr?+--   Need to capture it and use it for your own means?+--   Now you can, with 'silence' and 'capture'. -import Prelude+module System.IO.Silently+  ( silence, hSilence+  , capture, capture_, hCapture, hCapture_+  ) where -#if __GLASGOW_HASKELL__ >= 612-import GHC.IO.Handle (hDuplicate, hDuplicateTo)-#else-import GHC.Handle (hDuplicate, hDuplicateTo)-#endif+import Prelude -import System.IO import qualified Control.Exception as E import Control.DeepSeq-import System.Directory (removeFile,getTemporaryDirectory)+  ( deepseq ) +import GHC.IO.Handle+  ( hDuplicate, hDuplicateTo )++import System.Directory+  ( getTemporaryDirectory, removeFile )+import System.IO+  ( Handle, IOMode(AppendMode), SeekMode(AbsoluteSeek)+  , hClose, hFlush, hGetBuffering, hGetContents, hSeek, hSetBuffering+  , openFile, openTempFile, stdout+  )+ mNullDevice :: Maybe FilePath #ifdef WINDOWS mNullDevice = Just "\\\\.\\NUL"@@ -38,27 +41,34 @@ silence = hSilence [stdout]  -- | Run an IO action while preventing all output to the given handles.-hSilence :: [Handle] -> IO a -> IO a-hSilence handles action = case mNullDevice of-  Just nullDevice -> E.bracket (openFile nullDevice AppendMode)-                             hClose-                             prepareAndRun+hSilence :: forall a. [Handle] -> IO a -> IO a+hSilence handles action =+  case mNullDevice of+    Just nullDevice ->+      E.bracket (openFile nullDevice AppendMode)+                hClose+                prepareAndRun+    Nothing -> withTempFile "silence" prepareAndRun+  where+    prepareAndRun :: Handle -> IO a+    prepareAndRun tmpHandle = go handles+      where+        go []     = action+        go (h:hs) = goBracket go tmpHandle h hs -  Nothing -> do-    tmpDir <- getTempOrCurrentDirectory-    E.bracket (openTempFile tmpDir "silence")-                               cleanup-                               (prepareAndRun . snd) - where-  cleanup (tmpFile,tmpHandle) = do-    hClose tmpHandle-    removeFile tmpFile-  prepareAndRun tmpHandle = go handles-    where-      go [] = action-      go hs = goBracket go tmpHandle hs-+-- Provide a tempfile for the given action and remove it afterwards.+withTempFile :: String -> (Handle -> IO a) -> IO a+withTempFile tmpName action = do+  tmpDir <- getTempOrCurrentDirectory+  E.bracket (openTempFile tmpDir tmpName)+            cleanup+            (action . snd)+  where+    cleanup :: (FilePath, Handle) -> IO ()+    cleanup (tmpFile, tmpHandle) = do+      hClose tmpHandle+      removeFile tmpFile  getTempOrCurrentDirectory :: IO String getTempOrCurrentDirectory = getTemporaryDirectory `catchIOError` (\_ -> return ".")@@ -69,7 +79,8 @@     catchIOError = E.catch  -- | Run an IO action while preventing and capturing all output to stdout.--- This will, as a side effect, create and delete a temp file in the temp directory or current directory if there is no temp directory.+-- This will, as a side effect, create and delete a temp file in the temp directory+-- or current directory if there is no temp directory. capture :: IO a -> IO (String, a) capture = hCapture [stdout] @@ -82,29 +93,24 @@ hCapture_ handles = fmap fst . hCapture handles  -- | Run an IO action while preventing and capturing all output to the given handles.--- This will, as a side effect, create and delete a temp file in the temp directory or current directory if there is no temp directory.-hCapture :: [Handle] -> IO a -> IO (String, a)-hCapture handles action = do-  tmpDir <- getTempOrCurrentDirectory-  E.bracket (openTempFile tmpDir "capture")-                             cleanup-                             (prepareAndRun . snd)- where-  cleanup (tmpFile,tmpHandle) = do-    hClose tmpHandle-    removeFile tmpFile-  prepareAndRun tmpHandle = go handles-    where-      go [] = do-              a <- action-              mapM_ hFlush handles-              hSeek tmpHandle AbsoluteSeek 0-              str <- hGetContents tmpHandle-              str `deepseq` return (str,a)-      go hs = goBracket go tmpHandle hs+-- This will, as a side effect, create and delete a temp file in the temp directory+-- or current directory if there is no temp directory.+hCapture :: forall a. [Handle] -> IO a -> IO (String, a)+hCapture handles action = withTempFile "capture" prepareAndRun+  where+    prepareAndRun :: Handle -> IO (String, a)+    prepareAndRun tmpHandle = go handles+      where+        go [] = do+          a <- action+          mapM_ hFlush handles+          hSeek tmpHandle AbsoluteSeek 0+          str <- hGetContents tmpHandle+          str `deepseq` return (str, a)+        go (h:hs) = goBracket go tmpHandle h hs -goBracket :: ([Handle] -> IO a) -> Handle -> [Handle] -> IO a-goBracket go tmpHandle (h:hs) = do+goBracket :: ([Handle] -> IO a) -> Handle -> Handle -> [Handle] -> IO a+goBracket go tmpHandle h hs = do   buffering <- hGetBuffering h   let redirect = do         old <- hDuplicate h