packages feed

shelly 0.7.1 → 0.8.0.1

raw patch · 2 files changed

+101/−40 lines, 2 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Shelly: instance [incoherent] Exception e => Exception (ReThrownException e)
+ Shelly: instance [incoherent] Exception e => Show (ReThrownException e)
+ Shelly: instance [incoherent] Typeable1 ReThrownException
+ Shelly: print_stdout :: ShIO a -> ShIO a
+ Shelly: tag :: ShIO a -> Text -> ShIO a
+ Shelly: trace :: Text -> ShIO ()

Files

Shelly.hs view
@@ -21,7 +21,7 @@ module Shelly        (          -- * Entering ShIO.-         ShIO, shelly, sub, silently, verbosely, jobs, print_commands+         ShIO, shelly, sub, silently, verbosely, print_stdout, print_commands           -- * Running external commands.          , run, run_, cmd, (-|-), lastStderr, setStdin@@ -36,6 +36,7 @@           -- * Printing          , echo, echo_n, echo_err, echo_n_err, inspect+         , tag, trace           -- * Querying filesystem.          , ls, ls', test_e, test_f, test_d, test_s, which, find@@ -48,7 +49,7 @@          , readfile, writefile, appendfile, withTmpDir           -- * Running external commands asynchronously.-         , background, getBgResult, BgResult+         , jobs, background, getBgResult, BgResult           -- * exiting the program          , exit, errorExit, terror@@ -68,6 +69,7 @@  -- TODO: -- shebang runner that puts wrappers in and invokes+-- perhaps also adds monadloc -- convenience for commands that use record arguments {-       let oFiles = ("a.o", "b.o")@@ -120,7 +122,8 @@ import System.PosixCompat.Files( getSymbolicLinkStatus, isSymbolicLink ) import System.Directory ( setPermissions, getPermissions, Permissions(..), getTemporaryDirectory, findExecutable )  -{- GHC won't default to Text with this+{- GHC won't default to Text with this, even with extensions!+ - see: http://hackage.haskell.org/trac/ghc/ticket/6030 class ShellArgs a where   toTextArgs :: a -> [Text] @@ -242,11 +245,25 @@                      , sStdin :: Maybe Text -- ^ stdin for the command to be run                      , sStderr :: Text                      , sDirectory :: FilePath-                     , sVerbose :: Bool-                     , sPrintCommands :: Bool -- ^ print out command+                     , sPrintStdout :: Bool   -- ^ print stdout of command that is executed+                     , sPrintCommands :: Bool -- ^ print command that is executed                      , sRun :: FilePath -> [Text] -> ShIO (Handle, Handle, Handle, ProcessHandle)-                     , sEnvironment :: [(String, String)] }+                     , sEnvironment :: [(String, String)]+                     , sTrace :: B.Builder+                     } +-- | same as 'trace', but use it combinator style+tag :: ShIO a -> Text -> ShIO a+tag action msg = do+  result <- action+  trace msg+  return result+++-- | log actions that occur+trace :: Text -> ShIO ()+trace msg = modify $ \st -> st { sTrace = sTrace st `mappend` "\n" `mappend` B.fromLazyText msg }+ type ShIO a = ReaderT (IORef State) IO a  get :: ShIO State@@ -274,7 +291,7 @@   liftIO $ runInteractiveProcess (unpack exe)     (map LT.unpack args)     (Just $ unpack $ sDirectory st)-    (Just $ sEnvironment st)+    (Just $ sEnvironment st) -- TODO: is PATH buggy?  {- -- | use for commands requiring usage of sudo. see 'run_sudo'.@@ -308,6 +325,7 @@ -- operations. You will want to handle these issues differently in those cases. cd :: FilePath -> ShIO () cd dir = do dir' <- absPath dir+            trace $ "cd " `mappend` toTextIgnore dir'             modify $ \st -> st { sDirectory = dir' }  -- | "cd", execute a ShIO action in the new directory and then pop back to the original directory@@ -350,22 +368,25 @@ mv :: FilePath -> FilePath -> ShIO () mv a b = do a' <- absPath a             b' <- absPath b+            trace $ "mv " `mappend` toTextIgnore a' `mappend` " " `mappend` toTextIgnore b'             liftIO $ rename a' b'  -- | Get back [Text] instead of [FilePath] ls' :: FilePath -> ShIO [Text] ls' fp = do+    trace $ "ls " `mappend` toTextIgnore fp     efiles <- ls fp     mapM toTextWarn efiles  -- | List directory contents. Does *not* include \".\" and \"..\", but it does -- include (other) hidden files. ls :: FilePath -> ShIO [FilePath]-ls = path >=> liftIO . listDirectory+ls = path >=> \fp -> (liftIO $ listDirectory fp) `tag` ("ls " `mappend` toTextIgnore fp)   -- | List directory recursively (like the POSIX utility "find"). find :: FilePath -> ShIO [FilePath]-find dir = do bits <- ls dir+find dir = do trace ("find " `mappend` toTextIgnore dir)+              bits <- ls dir               subDir <- forM bits $ \x -> do                 ex <- test_d $ dir FP.</> x                 sym <- test_s $ dir FP.</> x@@ -402,12 +423,16 @@  -- | Create a new directory (fails if the directory exists). mkdir :: FilePath -> ShIO ()-mkdir = absPath >=> liftIO . createDirectory False+mkdir = absPath >=> \fp -> do+  trace $ "mkdir " `mappend` toTextIgnore fp+  liftIO $ createDirectory False fp `catchany` (\e -> throwIO e >> return ())  -- | Create a new directory, including parents (succeeds if the directory -- already exists). mkdir_p :: FilePath -> ShIO ()-mkdir_p = absPath >=> liftIO . createTree+mkdir_p = absPath >=> \fp -> do+  trace $ "mkdir_p " `mappend` toTextIgnore fp+  liftIO $ createTree fp  -- | Get a full path to an executable on @PATH@, if exists. FIXME does not -- respect setenv'd environment and uses @PATH@ inherited from the process@@ -468,7 +493,9 @@ -- | Remove a file. Does not fail if the file already is not there. Does fail -- if the file is not a file. rm_f :: FilePath -> ShIO ()-rm_f f = whenM (test_e f) $ absPath f >>= liftIO . removeFile+rm_f f = whenM (test_e f) $ absPath f >>= \fp -> do+  trace $ "rm_f " `mappend` toTextIgnore fp+  liftIO $ removeFile fp  -- | Set an environment variable. The environment is maintained in ShIO -- internally, and is passed to any external commands to be executed.@@ -500,12 +527,15 @@  -- | Create a sub-ShIO in which external command outputs are not echoed. See "sub". silently :: ShIO a -> ShIO a-silently a = sub $ modify (\x -> x { sVerbose = False }) >> a+silently a = sub $ modify (\x -> x { sPrintStdout = False, sPrintCommands = False }) >> a  -- | Create a sub-ShIO in which external command outputs are echoed. See "sub". verbosely :: ShIO a -> ShIO a-verbosely a = sub $ modify (\x -> x { sVerbose = True }) >> a+verbosely a = sub $ modify (\x -> x { sPrintStdout = True, sPrintCommands = True }) >> a +print_stdout :: ShIO a -> ShIO a+print_stdout a = sub $ modify (\x -> x { sPrintStdout = True }) >> a+ -- | Create a sub-ShIO which 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.@@ -563,7 +593,9 @@ sub :: ShIO a -> ShIO a sub a = do   state <- get-  r <- a `catch_sh` (\(e :: SomeException) -> put state >> throw e)+  r <- a `catchany_sh` (\e -> do+	put state+	liftIO $ throwIO e)   put state   return r @@ -572,19 +604,23 @@ -- processwide working directory or environment are not reflected in the -- running ShIO. shelly :: MonadIO m => ShIO a -> m a-shelly a = do+shelly action = do   env <- liftIO getEnvironment   dir <- liftIO getWorkingDirectory   let def  = State { sCode = 0                    , sStdin = Nothing                    , sStderr = LT.empty-                   , sVerbose = True+                   , sPrintStdout = True                    , sPrintCommands = False                    , sRun = runInteractiveProcess'                    , sEnvironment = env+                   , sTrace = B.fromText ""                    , sDirectory = dir }   stref <- liftIO $ newIORef def-  liftIO $ runReaderT a stref+  let caught =+        action `catchany_sh` \e ->+          get >>= liftIO . throwIO . ReThrownException e . LT.unpack .  B.toLazyText . sTrace+  liftIO $ runReaderT caught stref  data RunFailed = RunFailed FilePath [Text] Int Text deriving (Typeable) @@ -592,10 +628,15 @@   show (RunFailed exe args code errs) =     "error running " ++       unpack exe ++ " " ++ show args ++-      ": exit status " ++ show code ++ ":\n" ++ LT.unpack errs+      "\nexit status: " ++ show code ++ "\nstderr: " ++ LT.unpack errs  instance Exception RunFailed +data Exception e => ReThrownException e = ReThrownException e String deriving (Typeable)+instance Exception e => Exception (ReThrownException e)+instance Exception e => Show (ReThrownException e) where+  show (ReThrownException ex msg) =+    "Exception: " ++ show ex ++ "\n" ++ msg  -- | Execute an external command. Takes the command name (no shell allowed, -- just a name of something that can be found via @PATH@; FIXME: setenv'd@@ -654,7 +695,7 @@      errV <- liftIO newEmptyMVar     outV <- liftIO newEmptyMVar-    if sVerbose state+    if sPrintStdout state       then do         liftIO_ $ forkIO $ printGetContent errH stderr >>= putMVar errV         liftIO_ $ forkIO $ printFoldHandleLines start cb outH stdout >>= putMVar outV@@ -684,7 +725,8 @@     }     case ex of       ExitSuccess   -> return outs-      ExitFailure n -> throw $ RunFailed exe args n errs+      ExitFailure n ->+		liftIO $ throwIO $ RunFailed exe args n errs  -- | The output of last external command. See "run". lastStderr :: ShIO Text@@ -697,7 +739,7 @@ -- | Pipe operator. set the stdout the first command as the stdin of the second. (-|-) :: ShIO Text -> ShIO b -> ShIO b one -|- two = do-  res <- one+  res <- silently one   setStdin res   two @@ -735,9 +777,12 @@ -- | Copy a file, or a directory recursively. cp_r :: FilePath -> FilePath -> ShIO () cp_r from to = do-    whenM (test_d from) $-      mkdir to >> ls from >>= mapM_ (\item -> cp_r (from FP.</> item) (to FP.</> item))-    whenM (test_f from) $ cp from to+    trace $ "cp_r " `mappend` toTextIgnore from `mappend` " " `mappend` toTextIgnore to+    from_d <- (test_d from)+    if not from_d then cp from to else do+		 unlessM (test_d to) $ mkdir to+		 ls from >>= mapM_+		   (\item -> cp_r (from FP.</> filename item) (to FP.</> filename item))  -- | Copy a file. The second path could be a directory, in which case the -- original file name is used, in that directory.@@ -745,8 +790,14 @@ cp from to = do   from' <- absPath from   to' <- absPath to+  trace $ "cp " `mappend` toTextIgnore from' `mappend` " " `mappend` toTextIgnore to'   to_dir <- test_d to-  liftIO $ copyFile from' $ if to_dir then to' FP.</> filename from else to'+  let to_loc = if to_dir then to' FP.</> filename from else to'+  liftIO $ copyFile from' to_loc `catchany` (\e -> throwIO $+	  ReThrownException e (extraMsg to_loc from')+	)+  where+    extraMsg t f = "when copying from: " ++ unpack f ++ " to: " ++ unpack t  class PredicateLike pattern hay where   match :: pattern -> hay -> Bool@@ -758,7 +809,7 @@   match pat = (pat `isInfixOf`)  -- | Like filter, but more conveniently used with String lists, where a--- substring match (TODO: also provide regexps, and maybe globs) is expressed as+-- substring match (TODO: also provide globs) is expressed as --  @grep \"needle\" [ \"the\", \"stack\", \"of\", \"hay\" ]@. Boolean -- predicates just like with "filter" are supported too: -- @grep (\"fun\" `isPrefixOf`) [...]@.@@ -773,6 +824,7 @@ -- computation. The directory is nuked afterwards. withTmpDir :: (FilePath -> ShIO a) -> ShIO a withTmpDir act = do+  trace "withTmpDir"   dir <- liftIO getTemporaryDirectory   tid <- liftIO myThreadId   (pS, handle) <- liftIO $ openTempFile dir ("tmp"++filter isAlphaNum (show tid))@@ -780,21 +832,27 @@   liftIO $ hClose handle -- required on windows   rm_f p   mkdir p-  a <- act p`catch_sh` \(e :: SomeException) -> rm_rf p >> throw e+  a <- act p`catchany_sh` \e -> do+	rm_rf p >> liftIO (throwIO e)   rm_rf p   return a  -- | Write a Lazy Text to a file. writefile :: FilePath -> Text -> ShIO ()-writefile f bits = absPath f >>= \f' -> liftIO (TIO.writeFile (unpack f') bits)+writefile f bits = absPath f >>= \f' -> do+  trace $ "writefile " `mappend` toTextIgnore f'+  liftIO (TIO.writeFile (unpack f') bits)  -- | Append a Lazy Text to a file. appendfile :: FilePath -> Text -> ShIO ()-appendfile f bits = absPath f >>= \f' -> liftIO (TIO.appendFile (unpack f') bits)+appendfile f bits = absPath f >>= \f' -> do+  trace $ "appendfile " `mappend` toTextIgnore f'+  liftIO (TIO.appendFile (unpack f') bits)  -- | (Strictly) read file into a Text. -- All other functions use Lazy Text. -- So Internally this reads a file as strict text and then converts it to lazy text, which is inefficient readfile :: FilePath -> ShIO Text-readfile =-  absPath >=> fmap LT.fromStrict . liftIO . STIO.readFile . unpack+readfile = absPath >=> \fp -> do+  trace $ "appendfile " `mappend` toTextIgnore fp+  (fmap LT.fromStrict . liftIO . STIO.readFile . unpack) fp
shelly.cabal view
@@ -1,22 +1,25 @@ Name:       shelly -Version:     0.7.1+Version:     0.8.0.1 Synopsis:    shell-like (systems) programming in Haskell -Description: Shelly is a package provides a single module for convenient+Description: Shelly provides a single module for convenient              systems programming in Haskell, similar in spirit to POSIX-             shells.+             shells. Shelly:              .-               * Shelly is aimed at getting things done rather than+               * is aimed at convenience and getting things done rather than                  being a demonstration of elegance.              .-               * Shelly maintains its own environment, making it thread-safe.+               * has detailed and useful error messages              .-               * Shelly is modern. It uses Text and system-filepath/system-fileio+               * maintains its own environment, making it thread-safe.              .-               * Shelly is aimed at convenience and newer Haskell users+               * is modern. It uses Text and system-filepath/system-fileio              .-             Shelly is a fork of Shellish that features low memory usage, bug fixes, and modernization+               * is aimed at convenience and newer Haskell users+             .+             Shelly is forked from the Shellish package.+  Homepage:            https://github.com/yesodweb/Shelly.hs License:             BSD3