packages feed

turtle 1.2.5 → 1.2.6

raw patch · 5 files changed

+163/−62 lines, 5 filesdep ~doctestdep ~foldldep ~managed

Dependency ranges changed: doctest, foldl, managed, process

Files

src/Turtle/Format.hs view
@@ -66,6 +66,7 @@     ) where  import Control.Category (Category(..))+import Control.Monad.IO.Class (MonadIO(..)) import Data.Monoid ((<>)) import Data.String (IsString(..)) import Data.Text (Text, pack)@@ -106,8 +107,8 @@ >>> printf ("Hello, "%s%"!\n") "world" Hello, world! -}-printf :: Format (IO ()) r -> r-printf fmt = fmt >>- Text.putStr+printf :: MonadIO io => Format (io ()) r -> r+printf fmt = fmt >>- (liftIO . Text.putStr)  -- | Create your own format specifier makeFormat :: (a -> Text) -> Format r (a -> r)
src/Turtle/Prelude.hs view
@@ -105,15 +105,11 @@  module Turtle.Prelude (     -- * IO-      proc-    , shell-    , procs-    , shells-    , procStrict-    , shellStrict-    , echo+      echo     , err     , readline+    , Filesystem.readTextFile+    , Filesystem.writeTextFile     , arguments #if MIN_VERSION_base(4,7,0)     , export@@ -196,11 +192,21 @@     -- * Text     , cut +    -- * Subprocess management+    , proc+    , shell+    , system+    , procs+    , shells+    , procStrict+    , shellStrict+     -- * Permissions     , Permissions     , chmod     , getmod     , setmod+    , copymod     , readable, nonreadable     , writable, nonwritable     , executable, nonexecutable@@ -238,7 +244,7 @@ import qualified Control.Foldl.Text import Control.Monad (liftM, msum, when, unless) import Control.Monad.IO.Class (MonadIO(..))-import Control.Monad.Managed (Managed, managed, runManaged)+import Control.Monad.Managed (MonadManaged(..), managed, runManaged) #ifdef mingw32_HOST_OS import Data.Bits ((.&.)) #endif@@ -276,7 +282,14 @@ #ifdef mingw32_HOST_OS import qualified System.Win32 as Win32 #else-import System.Posix (openDirStream, readDirStream, closeDirStream, touchFile)+import System.Posix (+    openDirStream,+    readDirStream,+    closeDirStream,+    touchFile,+    getSymbolicLinkStatus,+    isDirectory,+    isSymbolicLink ) #endif import Prelude hiding (FilePath) @@ -298,7 +311,13 @@     -- ^ Lines of standard input     -> io ExitCode     -- ^ Exit code-proc cmd args = system (Process.proc (unpack cmd) (map unpack args))+proc cmd args =+    system+        ( (Process.proc (unpack cmd) (map unpack args))+            { Process.std_in  = Process.CreatePipe+            , Process.std_out = Process.Inherit+            , Process.std_err = Process.Inherit+            } )  {-| Run a command line using the shell, retrieving the exit code @@ -315,7 +334,13 @@     -- ^ Lines of standard input     -> io ExitCode     -- ^ Exit code-shell cmdLine = system (Process.shell (unpack cmdLine))+shell cmdLine =+    system+        ( (Process.shell (unpack cmdLine))+            { Process.std_in  = Process.CreatePipe+            , Process.std_out = Process.Inherit+            , Process.std_err = Process.Inherit+            } )  data ProcFailed = ProcFailed     { procCommand   :: Text@@ -403,6 +428,10 @@     -- ^ Exit code and stdout shellStrict cmdLine = systemStrict (Process.shell (Text.unpack cmdLine)) +{-| `system` generalizes `shell` and `proc` by allowing you to supply your own+    custom `CreateProcess`.  This is for advanced users who feel comfortable+    using the lower-level @process@ API+-} system     :: MonadIO io     => Process.CreateProcess@@ -412,14 +441,8 @@     -> io ExitCode     -- ^ Exit code system p s = liftIO (do-    let p' = p-            { Process.std_in  = Process.CreatePipe-            , Process.std_out = Process.Inherit-            , Process.std_err = Process.Inherit-            }-     let open = do-            (Just hIn, Nothing, Nothing, ph) <- Process.createProcess p'+            (Just hIn, Nothing, Nothing, ph) <- Process.createProcess p             IO.hSetBuffering hIn IO.LineBuffering             return (hIn, ph) @@ -619,7 +642,8 @@  {-| Run a command using the shell, streaming @stdout@ and @stderr@ as lines of     `Text`.  Lines from @stdout@ are wrapped in `Right` and lines from @stderr@-    are wrapped in `Left`.+    are wrapped in `Left`.  This does /not/ throw an exception if the command+    returns a non-zero exit code -} inprocWithErr     :: Text@@ -629,14 +653,15 @@     -> Shell Text     -- ^ Lines of standard input     -> Shell (Either Text Text)-    -- ^ Lines of standard output+    -- ^ Lines of either standard output (`Right`) or standard error (`Left`) inprocWithErr cmd args =     streamWithErr (Process.proc (unpack cmd) (map unpack args))   {-| Run a command line using the shell, streaming @stdout@ and @stderr@ as lines     of `Text`.  Lines from @stdout@ are wrapped in `Right` and lines from-    @stderr@ are wrapped in `Left`.+    @stderr@ are wrapped in `Left`.  This does /not/ throw an exception if the+    command returns a non-zero exit code      This command is more powerful than `inprocWithErr`, but highly vulnerable to     code injection if you template the command line with untrusted input@@ -647,7 +672,7 @@     -> Shell Text     -- ^ Lines of standard input     -> Shell (Either Text Text)-    -- ^ Lines of standard output+    -- ^ Lines of either standard output (`Right`) or standard error (`Left`) inshellWithErr cmd = streamWithErr (Process.shell (unpack cmd))  -- | Print to @stdout@@@ -778,7 +803,7 @@ lstree :: FilePath -> Shell FilePath lstree path = do     child <- ls path-    isDir <- liftIO (testdir child)+    isDir <- testdir child     if isDir         then return child <|> lstree child         else return child@@ -792,7 +817,7 @@ lsif :: (FilePath -> IO Bool) -> FilePath -> Shell FilePath lsif predicate path = do     child <- ls path-    isDir <- liftIO (testdir child)+    isDir <- testdir child     if isDir         then do             continue <- liftIO (predicate child)@@ -846,7 +871,31 @@     Use at your own risk -} rmtree :: MonadIO io => FilePath -> io ()-rmtree path = liftIO (Filesystem.removeTree path)+rmtree path0 = liftIO (sh (loop path0))+  where+#ifdef mingw32_HOST_OS+    loop path = do+        isDir <- testdir path+        if isDir+            then (do+                child <- ls path+                loop child ) <|> rmdir path+            else rm path+#else+    loop path = do+        let path' = Filesystem.encodeString path+        stat <- liftIO $ getSymbolicLinkStatus path'+        let isLink = isSymbolicLink stat+            isDir = isDirectory stat+        if isLink+            then rm path+            else do+                if isDir+                    then (do+                        child <- ls path+                        loop child ) <|> rmdir path+                    else rm path+#endif  -- | Check if a file exists testfile :: MonadIO io => FilePath -> io Bool@@ -924,6 +973,13 @@     let path' = deslash (Filesystem.encodeString path)     Directory.setPermissions path' permissions ) +-- | Copy a file or directory's permissions (analogous to @chmod --reference@)+copymod :: MonadIO io => FilePath -> FilePath -> io ()+copymod sourcePath targetPath = liftIO (do+    let sourcePath' = deslash (Filesystem.encodeString sourcePath)+        targetPath' = deslash (Filesystem.encodeString targetPath)+    Directory.copyPermissions sourcePath' targetPath' )+ -- | @+r@ readable :: Permissions -> Permissions readable = Directory.setOwnerReadable True@@ -1066,16 +1122,17 @@     Deletes the temporary directory when done -} mktempdir-    :: FilePath+    :: MonadManaged managed+    => FilePath     -- ^ Parent directory     -> Text     -- ^ Directory name template-    -> Managed FilePath-mktempdir parent prefix = do+    -> managed FilePath+mktempdir parent prefix = using (do     let parent' = Filesystem.encodeString parent     let prefix' = unpack prefix     dir' <- managed (withTempDirectory parent' prefix')-    return (Filesystem.decodeString dir')+    return (Filesystem.decodeString dir'))  {-| Create a temporary file underneath the given directory @@ -1087,39 +1144,41 @@     simpler API if you don't need to worry about that possibility. -} mktemp-    :: FilePath+    :: MonadManaged managed+    => FilePath     -- ^ Parent directory     -> Text     -- ^ File name template-    -> Managed (FilePath, Handle)-mktemp parent prefix = do+    -> managed (FilePath, Handle)+mktemp parent prefix = using (do     let parent' = Filesystem.encodeString parent     let prefix' = unpack prefix     (file', handle) <- managed (\k ->         withTempFile parent' prefix' (\file' handle -> k (file', handle)) )-    return (Filesystem.decodeString file', handle)+    return (Filesystem.decodeString file', handle) )  {-| Create a temporary file underneath the given directory      Deletes the temporary file when done -} mktempfile-    :: FilePath+    :: MonadManaged managed+    => FilePath     -- ^ Parent directory     -> Text     -- ^ File name template-    -> Managed FilePath-mktempfile parent prefix = do+    -> managed FilePath+mktempfile parent prefix = using (do     let parent' = Filesystem.encodeString parent     let prefix' = unpack prefix     (file', handle) <- managed (\k ->         withTempFile parent' prefix' (\file' handle -> k (file', handle)) )     liftIO (hClose handle)-    return (Filesystem.decodeString file')+    return (Filesystem.decodeString file') )  -- | Fork a thread, acquiring an `Async` value-fork :: IO a -> Managed (Async a)-fork io = managed (withAsync io)+fork :: MonadManaged managed => IO a -> managed (Async a)+fork io = using (managed (withAsync io))  -- | Read lines of `Text` from standard input stdin :: Shell Text@@ -1182,16 +1241,16 @@ strict s = liftM Text.unlines (fold s list)  -- | Acquire a `Managed` read-only `Handle` from a `FilePath`-readonly :: FilePath -> Managed Handle-readonly file = managed (Filesystem.withTextFile file IO.ReadMode)+readonly :: MonadManaged managed => FilePath -> managed Handle+readonly file = using (managed (Filesystem.withTextFile file IO.ReadMode))  -- | Acquire a `Managed` write-only `Handle` from a `FilePath`-writeonly :: FilePath -> Managed Handle-writeonly file = managed (Filesystem.withTextFile file IO.WriteMode)+writeonly :: MonadManaged managed => FilePath -> managed Handle+writeonly file = using (managed (Filesystem.withTextFile file IO.WriteMode))  -- | Acquire a `Managed` append-only `Handle` from a `FilePath`-appendonly :: FilePath -> Managed Handle-appendonly file = managed (Filesystem.withTextFile file IO.AppendMode)+appendonly :: MonadManaged managed => FilePath -> managed Handle+appendonly file = using (managed (Filesystem.withTextFile file IO.AppendMode))  -- | Combine the output of multiple `Shell`s, in order cat :: [Shell a] -> Shell a@@ -1235,6 +1294,7 @@     (tmpfile, handle) <- mktemp here "turtle"     outhandle handle (sed pattern (input file))     liftIO (hClose handle)+    copymod file tmpfile     mv tmpfile file ))  
src/Turtle/Shell.hs view
@@ -73,7 +73,7 @@ import Control.Applicative import Control.Monad (MonadPlus(..), ap) import Control.Monad.IO.Class (MonadIO(..))-import Control.Monad.Managed (Managed, with)+import Control.Monad.Managed (MonadManaged(..), with) import Control.Foldl (Fold(..), FoldM(..)) import qualified Control.Foldl as Foldl import Data.Monoid@@ -143,6 +143,12 @@         x' <- step x a         done x' ) +instance MonadManaged Shell where+    using resource = Shell (\(FoldM step begin done) -> do+        x  <- begin+        x' <- with resource (step x)+        done x' )+ instance Monoid a => Monoid (Shell a) where     mempty  = pure mempty     mappend = liftA2 mappend@@ -165,10 +171,3 @@             x' <- step x a             k $! x'     foldr step' done as $! x0 )---- | Acquire a `Managed` resource within a `Shell` in an exception-safe way-using :: Managed a -> Shell a-using resource = Shell (\(FoldM step begin done) -> do-    x  <- begin-    x' <- with resource (step x)-    done x' )
src/Turtle/Tutorial.hs view
@@ -106,6 +106,9 @@     -- * MonadIO     -- $monadio +    -- * MonadManaged+    -- $monadmanaged+     -- * Command line options     -- $cmdline @@ -770,7 +773,7 @@ -- @ -- `proc` --     :: Text         -- Program---     :: [Text]       -- Arguments+--     -> [Text]       -- Arguments --     -> Shell Text   -- Standard input (as lines of \`Text\`) --     -> IO ExitCode  -- Exit code of the shell command -- @@@ -810,8 +813,15 @@ -- -- > format fp :: FilePath -> Text --+-- For the very common case where you `echo` a formatted value, you can use+-- `printf`:+--+-- >>> printf ("Hello, "%s%"!\n") "world"+-- Hello, world!+-- -- If you are interested in this feature, check out the "Turtle.Format" module--- for more details.+-- for more details.  For more complex string formatting needs, check out the+-- @text-format@ library.  -- $streams -- The @turtle@ library provides support for streaming computations, just like@@ -1440,6 +1450,7 @@ -- > Applicative Shell -- > Alternative Shell -- > MonadIO Shell+-- > MonadManaged Shell -- > ... --  -- These instances represent the overloaded functions associated with `Shell`@@ -1450,6 +1461,31 @@ -- way (such as `print`), so you will still occasionally need to wrap -- subroutines in `liftIO`. +-- $monadmanaged+--+-- All `Managed` operations are also overloaded in @turtle@, meaning that you+-- can omit the `using` command.  For example, we could change our last example+-- to:+--+-- > #!/usr/bin/env stack+-- > -- stack --install-ghc runghc --package turtle+-- > +-- > {-# LANGUAGE OverloadedStrings #-}+-- > +-- > import Turtle+-- > +-- > main = sh (do+-- >     dir       <- mktempdir "/tmp" "turtle"+-- >     (file, _) <- mktemp dir "turtle"+-- >     liftIO (print file)+-- >     die "Urk!" )+--+-- Any command that is generalized over the `MonadManaged` interface can run+-- in the following contexts:+--+-- * `Managed` (obviously)+-- * `Shell`+ -- $cmdline -- -- The "Turtle.Options" module lets you easily parse command line arguments,@@ -1694,6 +1730,11 @@ -- $faq -- -- These are the most frequently asked questions from new users:+--+-- /Question:/ My program hangs when I run a subprocess that reads from standard+-- input.  What do I do?+--+-- /Answer:/ Make sure you compile your program with the @-threaded@ flag -- -- /Question:/ How do I convert `FilePath` to `Text`? --
turtle.cabal view
@@ -1,5 +1,5 @@ Name: turtle-Version: 1.2.5+Version: 1.2.6 Cabal-Version: >=1.10 Build-Type: Simple License: BSD3@@ -50,10 +50,10 @@         async                >= 2.0.0.0 && < 2.2,         clock                >= 0.4.1.2 && < 0.7,         directory            >= 1.0.7   && < 1.3,-        foldl                >= 1.1     && < 1.2,+        foldl                >= 1.1     && < 1.3,         hostname                           < 1.1,-        managed                            < 1.1,-        process              >= 1.0.1.1 && < 1.3,+        managed              >= 1.0.3   && < 1.1,+        process              >= 1.0.1.1 && < 1.5,         system-filepath      >= 0.3.1   && < 0.5,         system-fileio        >= 0.2.1   && < 0.4,         stm                                < 2.5,@@ -86,7 +86,7 @@     Default-Language: Haskell2010     Build-Depends:         base         >= 4      && < 5  ,-        doctest      >= 0.9.12 && < 0.11+        doctest      >= 0.9.12 && < 0.12  benchmark bench     Type: exitcode-stdio-1.0