shelly-extra (empty) → 0.2
raw patch · 5 files changed
+174/−0 lines, 5 filesdep +SafeSemaphoredep +basedep +shellysetup-changed
Dependencies added: SafeSemaphore, base, shelly, text
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- Shelly/Background.hs +57/−0
- shelly-extra.cabal +44/−0
- test/main.hs +41/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2010, Petr Rockai <me@mornfall.net>++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Petr Rockai nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Shelly/Background.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE OverloadedStrings #-}+module Shelly.Background (+ -- * Running external commands asynchronously.+ jobs, background, getBgResult, BgResult+) where++import Shelly+import Control.Concurrent+import qualified Control.Concurrent.MSem as Sem++-- | Create a 'BgJobManager' that has a 'limit' on the max number of background tasks.+-- an invocation of jobs is independent of any others, and not tied to the ShIO monad in any way.+-- This blocks the execution of the program until all 'background' jobs are finished.+jobs :: Int -> (BgJobManager -> ShIO a) -> ShIO a+jobs limit action = do+ unless (limit > 0) $ terror "expected limit to be > 0"+ availableJobsSem <- liftIO $ Sem.new limit+ res <- action $ BgJobManager availableJobsSem+ liftIO $ waitForJobs availableJobsSem+ return res+ where+ waitForJobs sem = do+ avail <- Sem.peekAvail sem+ if avail == limit then return () else waitForJobs sem++-- | The manager tracks the number of jobs. Register your 'background' jobs with it.+newtype BgJobManager = BgJobManager (Sem.MSem Int)++-- | Type returned by tasks run asynchronously in the background.+newtype BgResult a = BgResult (MVar a)++-- | Returns the promised result from a backgrounded task. Blocks until+-- the task completes.+getBgResult :: BgResult a -> ShIO a+getBgResult (BgResult mvar) = liftIO $ takeMVar mvar++-- | Run the `ShIO` task asynchronously in the background, returns+-- the `BgResult a`, a promise immediately. Run "getBgResult" to wait for the result.+-- The background task will inherit the current ShIO context+-- The 'BjJobManager' ensures the max jobs limit must be sufficient for the parent and all children.+background :: BgJobManager -> ShIO a -> ShIO (BgResult a)+background (BgJobManager manager) proc = do+ state <- get+ liftIO $ do+ -- take up a spot+ -- It is important to do this before forkIO:+ -- It ensures that that jobs will block and the program won't exit before our jobs are done+ -- On the other hand, a user might not expect 'jobs' to block+ Sem.wait manager+ mvar <- newEmptyMVar -- future result++ _<- forkIO $ do+ result <- shelly $ (put state >> proc)+ Sem.signal manager -- open a spot back up+ liftIO $ putMVar mvar result+ return $ BgResult mvar+
+ shelly-extra.cabal view
@@ -0,0 +1,44 @@+Name: shelly-extra++Version: 0.2+Synopsis: shelly features that require extra dependencies++Description: Please see the shelly package. Shelly provides a single module for convenient+ systems programming in Haskell, similar in spirit to POSIX shells.+ .+ shelly-extra is designed to be a grab bag for functionality that+ * requires extra dependencies+ .+ * or is application specific and not generally applicable+ .+ currently contains a background job implementation for performing tasks in parallel+++Homepage: https://github.com/yesodweb/Shelly.hs+License: BSD3+License-file: LICENSE+Author: Greg Weber+Maintainer: Greg Weber <greg@gregweber.info>+Category: Development+Build-type: Simple+Cabal-version: >=1.8+++Library+ Exposed-modules: Shelly.Background++ Build-depends: base >= 4 && < 5, shelly >= 0.10, SafeSemaphore++ ghc-options: -Wall++test-suite test+ type: exitcode-stdio-1.0+ main-is: main.hs+ hs-source-dirs: ., test+ ghc-options: -Wall++ Build-depends: base, text, shelly, SafeSemaphore++source-repository head+ type: git+ location: https://github.com/yesodweb/Shelly.hs
+ test/main.hs view
@@ -0,0 +1,41 @@+{-# Language OverloadedStrings #-}+{-# Language ExtendedDefaultRules #-}+{-# Language ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++import Shelly+import Shelly.Background+import Data.Text.Lazy (Text)+default (Text)++-- smoke tests+main :: IO ()+main =+ shelly $+ -- verbosely $+ do+ jobs 2 $ \job -> do+ _<- background job $ cmd "sleep" "2"+ echo "immediate"+ _<- background job $ cmd "sleep" "2"+ echo "immediate2"+ _<- background job $ cmd "sleep" "2"+ echo "blocked by background "+ + echo "blocked by jobs"++ setStdin "in"+ setStdin "override stdin"+ run_ "cat" ["-"]++ recho <- cmd "echo" "cmd"+ _<-cmd "echo" "bar" "baz"+ echo recho++ (res :: Text) <- cmd "pwd"+ liftIO $ putStrLn $ show res+ inspect res++ inspect =<< (cmd "echo" "compose" :: ShIO Text)+ inspect =<< (cmd "pwd")+