shelly 0.14.0.1 → 0.14.1
raw patch · 4 files changed
+89/−50 lines, 4 filesdep ~hspecPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: hspec
API changes (from Hackage documentation)
- Shelly: echo, echo_n_err, echo_err, echo_n :: Text -> Sh ()
- Shelly.Pipe: echo, echo_n, echo_err, echo_n_err :: Text -> Sh ()
+ Shelly: echo :: Text -> Sh ()
+ Shelly: echo_err :: Text -> Sh ()
+ Shelly: echo_n :: Text -> Sh ()
+ Shelly: echo_n_err :: Text -> Sh ()
+ Shelly: shellyNoDir :: MonadIO m => Sh a -> m a
+ Shelly.Pipe: echo :: Text -> Sh ()
+ Shelly.Pipe: echo_err :: Text -> Sh ()
+ Shelly.Pipe: echo_n :: Text -> Sh ()
+ Shelly.Pipe: echo_n_err :: Text -> Sh ()
Files
- Shelly.hs +78/−39
- Shelly/Base.hs +6/−6
- shelly.cabal +2/−2
- test/main.hs +3/−3
Shelly.hs view
@@ -25,7 +25,7 @@ module Shelly ( -- * Entering Sh.- Sh, ShIO, shelly, sub, silently, verbosely, escaping, print_stdout, print_commands, tracing, errExit+ Sh, ShIO, shelly, shellyNoDir, sub, silently, verbosely, escaping, print_stdout, print_commands, tracing, errExit -- * Running external commands. , run, run_, runFoldLines, cmd, (-|-), lastStderr, setStdin, lastExitCode@@ -212,8 +212,10 @@ printGetContent rH wH = fmap B.toLazyText $ printFoldHandleLines (B.fromText "") foldBuilder rH wH +{- getContent :: Handle -> IO Text getContent h = fmap B.toLazyText $ foldHandleLines (B.fromText "") foldBuilder h+-} type FoldCallback a = ((a, Text) -> a) @@ -329,7 +331,7 @@ where tdir = toTextIgnore dir --- | "cd", execute a Sh action in the new directory and then pop back to the original directory+-- | 'cd', execute a Sh action in the new directory and then pop back to the original directory chdir :: FilePath -> Sh a -> Sh a chdir dir action = do d <- gets sDirectory@@ -354,8 +356,8 @@ pack :: String -> FilePath pack = decodeString --- | Currently a "renameFile" wrapper. TODO: Support cross-filesystem--- move. TODO: Support directory paths in the second parameter, like in "cp".+-- | Currently a 'renameFile' wrapper. TODO: Support cross-filesystem+-- move. TODO: Support directory paths in the second parameter, like in 'cp'. mv :: FilePath -> FilePath -> Sh () mv a b = do a' <- absPath a b' <- absPath b@@ -410,7 +412,7 @@ (trace . mappend "which " . toTextIgnore) fp (liftIO . findExecutable . unpack >=> return . fmap pack) fp --- | A monadic-conditional version of the "unless" guard.+-- | A monadic-conditional version of the 'unless' guard. unlessM :: Monad m => m Bool -> m () -> m () unlessM c a = c >>= \res -> unless res a @@ -470,6 +472,7 @@ -- | add the filepath onto the PATH env variable -- FIXME: only effects the PATH once the process is ran, as per comments in 'which'+-- TODO: use cross-platform searchPathSeparator appendToPath :: FilePath -> Sh () appendToPath = absPath >=> \filepath -> do tp <- toTextWarn filepath@@ -501,6 +504,7 @@ -- non-existent variables give the default Text value as a result get_env_def :: Text -> Text -> Sh Text get_env_def d = get_env >=> return . fromMaybe d+{-# DEPRECATED get_env_def "use fromMaybe DEFAULT get_env" #-} -- | Create a sub-Sh in which external command outputs are not echoed and@@ -537,7 +541,15 @@ where restoreState oldState = do newState <- get- put oldState { sTrace = sTrace oldState `mappend` sTrace newState }+ put oldState {+ -- avoid losing the log+ sTrace = sTrace oldState `mappend` sTrace newState + -- latest command execution: not make sense to restore these to old settings+ , sCode = sCode newState+ , sStderr = sStderr newState+ -- it is questionable what the behavior of stdin should be+ , sStdin = sStdin newState+ } -- | Create a sub-Sh where commands are not traced -- Defaults to True.@@ -559,20 +571,36 @@ } action --- | named after bash -e errexit. Defaults to True.--- When True, throw an exception on a non-zero exit code.--- Not recommended to set to False unless you are specifically checking the error code with 'lastExitCode'.+-- | named after bash -e errexit. Defaults to @True@.+-- When @True@, throw an exception on a non-zero exit code.+-- When @False@, ignore a non-zero exit code.+-- Not recommended to set to @False@ unless you are specifically checking the error code with 'lastExitCode'. errExit :: Bool -> Sh a -> Sh a errExit shouldExit action = sub $ do modify $ \st -> st { sErrExit = shouldExit } action +data ShellyOpts = ShellyOpts { failToDir :: Bool }++-- avoid data-default dependency for now+-- instance Default ShellyOpts where +shellyOpts :: ShellyOpts+shellyOpts = ShellyOpts { failToDir = True }++-- | Using this entry point does not create a @.shelly@ directory in the case+-- of failure. Instead it logs directly into the standard error stream (@stderr@).+shellyNoDir :: MonadIO m => Sh a -> m a+shellyNoDir = shelly' shellyOpts { failToDir = False }+ -- | Enter a Sh from (Monad)IO. The environment and working directories are -- inherited from the current process-wide values. Any subsequent changes in -- processwide working directory or environment are not reflected in the -- running Sh. shelly :: MonadIO m => Sh a -> m a-shelly action = do+shelly = shelly' shellyOpts++shelly' :: MonadIO m => ShellyOpts -> Sh a -> m a+shelly' opts action = do environment <- liftIO getEnvironment dir <- liftIO getWorkingDirectory let def = State { sCode = 0@@ -603,14 +631,18 @@ where throwExplainedException :: Exception exception => exception -> Sh a throwExplainedException ex = get >>= errorMsg >>= liftIO . throwIO . ReThrownException ex- errorMsg st = do- let trc = B.toLazyText . sTrace $ st- d <- pwd- sf <- shellyFile- let f = d</>shelly_dir</>sf- (writefile f trc >> return ("log of commands saved to: " `mappend` encodeString f))- `catchany_sh` (\_ -> return $ "Ran commands: \n" `mappend` LT.unpack trc)+ errorMsg st =+ if not (failToDir opts) then ranCommands else do+ d <- pwd+ sf <- shellyFile+ let logFile = d</>shelly_dir</>sf+ (writefile logFile trc >> return ("log of commands saved to: " `mappend` encodeString logFile))+ `catchany_sh` (\_ -> ranCommands) + where+ trc = B.toLazyText . sTrace $ st+ ranCommands = return . mappend "Ran commands: \n" . LT.unpack $ trc+ shelly_dir = ".shelly" shellyFile = chdir_p shelly_dir $ do fs <- ls "."@@ -666,7 +698,7 @@ -- This interface is crude, but it works for now. -- -- Please note this sets 'escaping' to False: the commands will not be shell escaped.--- Internally the list of commands are combined with the string " && " before given to ssh.+-- Internally the list of commands are combined with the string @&&@ before given to ssh. sshPairs :: Text -> [(FilePath, [Text])] -> Sh Text sshPairs _ [] = return "" sshPairs server cmds = sshPairs' run server cmds@@ -694,13 +726,13 @@ -- just a name of something that can be found via @PATH@; FIXME: setenv'd -- @PATH@ is not taken into account when finding the exe name) ----- "stdout" and "stderr" are collected. The "stdout" is returned as--- a result of "run", and complete stderr output is available after the fact using--- "lastStderr"+-- 'stdout' and 'stderr' are collected. The 'stdout' is returned as+-- a result of 'run', and complete stderr output is available after the fact using+-- 'lastStderr' -- -- All of the stdout output will be loaded into memory--- You can avoid this but still consume the result by using "run_",--- If you want to avoid the memory and need to process the output then use "runFoldLines".+-- You can avoid this but still consume the result by using 'run_',+-- If you want to avoid the memory and need to process the output then use 'runFoldLines'. run :: FilePath -> [Text] -> Sh Text run exe args = fmap B.toLazyText $ runFoldLines (B.fromText "") foldBuilder exe args @@ -708,27 +740,31 @@ foldBuilder (b, line) = b `mappend` B.fromLazyText line `mappend` B.singleton '\n' --- | bind some arguments to run for re-use--- Example: @monit = command "monit" ["-c", "monitrc"]@+-- | bind some arguments to run for re-use. Example:+--+-- > monit = command "monit" ["-c", "monitrc"] command :: FilePath -> [Text] -> [Text] -> Sh Text command com args more_args = run com (args ++ more_args) --- | bind some arguments to "run_" for re-use--- Example: @monit_ = command_ "monit" ["-c", "monitrc"]@+-- | bind some arguments to 'run_' for re-use. Example:+--+-- > monit_ = command_ "monit" ["-c", "monitrc"] command_ :: FilePath -> [Text] -> [Text] -> Sh () command_ com args more_args = run_ com (args ++ more_args) --- | bind some arguments to run for re-use, and expect 1 argument--- Example: @git = command1 "git" []; git "pull" ["origin", "master"]@+-- | bind some arguments to run for re-use, and expect 1 argument. Example:+--+-- > git = command1 "git" []; git "pull" ["origin", "master"] command1 :: FilePath -> [Text] -> Text -> [Text] -> Sh Text command1 com args one_arg more_args = run com ([one_arg] ++ args ++ more_args) --- | bind some arguments to run for re-use, and expect 1 argument--- Example: @git_ = command1_ "git" []; git+ "pull" ["origin", "master"]@+-- | bind some arguments to run for re-use, and expect 1 argument. Example:+--+-- > git_ = command1_ "git" []; git+ "pull" ["origin", "master"] command1_ :: FilePath -> [Text] -> Text -> [Text] -> Sh () command1_ com args one_arg more_args = run_ com ([one_arg] ++ args ++ more_args) --- | the same as "run", but return () instead of the stdout content+-- | the same as 'run', but return @()@ instead of the stdout content -- stdout will be read and discarded line-by-line run_ :: FilePath -> [Text] -> Sh () run_ = runFoldLines () (\(_, _) -> ())@@ -736,7 +772,7 @@ liftIO_ :: IO a -> Sh () liftIO_ action = liftIO action >> return () --- | used by "run". fold over stdout line-by-line as it is read to avoid keeping it in memory+-- | used by 'run'. fold over stdout line-by-line as it is read to avoid keeping it in memory -- stderr is still being placed in memory under the assumption it is always relatively small runFoldLines :: a -> FoldCallback a -> FilePath -> [Text] -> Sh a runFoldLines start cb exe args = do@@ -760,12 +796,13 @@ errV <- liftIO newEmptyMVar outV <- liftIO newEmptyMVar++ liftIO_ $ forkIO $ printGetContent errH stderr >>= putMVar errV+ -- liftIO_ $ forkIO $ getContent errH >>= putMVar errV if sPrintStdout state- then do- liftIO_ $ forkIO $ printGetContent errH stderr >>= putMVar errV+ then liftIO_ $ forkIO $ printFoldHandleLines start cb outH stdout >>= putMVar outV- else do- liftIO_ $ forkIO $ getContent errH >>= putMVar errV+ else liftIO_ $ forkIO $ foldHandleLines start cb outH >>= putMVar outV errs <- liftIO $ takeMVar errV@@ -781,7 +818,7 @@ (True, ExitFailure n) -> throwIO $ RunFailed exe args n errs _ -> takeMVar outV --- | The output of last external command. See "run".+-- | The output of last external command. See 'run'. lastStderr :: Sh Text lastStderr = gets sStderr @@ -790,11 +827,13 @@ lastExitCode :: Sh Int lastExitCode = gets sCode --- | set the stdin to be used and cleared by the next "run".+-- | set the stdin to be used and cleared by the next 'run'. setStdin :: Text -> Sh () setStdin input = modify $ \st -> st { sStdin = Just input } -- | Pipe operator. set the stdout the first command as the stdin of the second.+-- This does not create a shell-level pipe, but hopefully it will in the future.+-- To create a shell level pipe you can always set @escaping False@ and use a pipe @|@ character in a command. (-|-) :: Sh Text -> Sh b -> Sh b one -|- two = do res <- print_stdout False one
Shelly/Base.hs view
@@ -15,7 +15,7 @@ liftIO, (>=>), eitherRelativeTo, relativeTo, maybeRelativeTo, whenM- -- * utitlities not yet exported+ -- * utilities not yet exported , addTrailingSlash ) where @@ -25,13 +25,12 @@ import System.IO ( Handle, hFlush, stderr, stdout ) import Control.Monad (when, (>=>) )-import Control.Applicative(Applicative)+import Control.Applicative (Applicative, (<$>)) import Filesystem (isDirectory, listDirectory) import System.PosixCompat.Files( getSymbolicLinkStatus, isSymbolicLink ) import Filesystem.Path.CurrentOS (FilePath, encodeString, relative) import qualified Filesystem.Path.CurrentOS as FP import qualified Filesystem as FS-import Control.Applicative ((<$>)) import Data.IORef (readIORef, modifyIORef, IORef) import Data.Monoid (mappend) import qualified Data.Text.Lazy as LT@@ -128,7 +127,7 @@ p FP.</> FP.empty -- | makes an absolute path.--- Like 'canonicalize', but on an exception returns 'path'+-- Like 'canonicalize', but on an exception returns 'absPath' canonic :: FilePath -> Sh FilePath canonic fp = do p <- absPath fp@@ -147,11 +146,12 @@ -- | Make a relative path absolute by combining with the working directory. -- An absolute path is returned as is.--- To create a relative path, use 'path'.+-- To create a relative path, use 'relPath'. absPath :: FilePath -> Sh FilePath absPath p | relative p = (FP.</> p) <$> gets sDirectory | otherwise = return p +-- | deprecated path :: FilePath -> Sh FilePath path = absPath {-# DEPRECATED path "use absPath, canonic, or relPath instead" #-}@@ -182,7 +182,7 @@ state <- ask liftIO (modifyIORef state f) --- | internally log what occured.+-- | internally log what occurred. -- Log will be re-played on failure. trace :: Text -> Sh () trace msg =
shelly.cabal view
@@ -1,6 +1,6 @@ Name: shelly -Version: 0.14.0.1+Version: 0.14.1 Synopsis: shell-like (systems) programming in Haskell Description: Shelly provides convenient systems programming in Haskell,@@ -57,7 +57,7 @@ , system-fileio < 0.4 , bytestring , hspec-discover- , hspec >= 1.1+ , hspec >= 1.3 , HUnit -- demonstarated that command output in Shellish was not shown until after the command finished
test/main.hs view
@@ -1,5 +1,5 @@-{-# OPTIONS_GHC -F -pgmF hspec-discover -optF --nested #-}+{- # OPTIONS_GHC -F -pgmF hspec-discover -optF --nested #-} {-import qualified CopySpec-} {-main = CopySpec.main-}--- import qualified FindSpec--- main = FindSpec.main+import qualified FailureSpec+main = FailureSpec.main