packages feed

turtle 1.3.2 → 1.3.3

raw patch · 8 files changed

+121/−21 lines, 8 filesdep +semigroups

Dependencies added: semigroups

Files

CHANGELOG.md view
@@ -1,3 +1,14 @@+1.3.3++* Bug fix: Change `textToLines` to behave like `Data.Text.splitOn "\n"`+   instead of `Data.Text.unlines`+    * This fixes weird behavior around handling empty strings.  `splitOn` does+      the right thing, but `unlines` does not.  For example, this indirectly+      fixes a regression in `sed`, which would discard empty lines+* Bug fix: `which`/`whichAll` now behave correctly on Windows+* Add new `cptree`/`single` utilities+* Documentation fixes+ 1.3.2  * Fix bugs in subprocess management
src/Turtle/Bytes.hs view
@@ -20,7 +20,6 @@     -- * Subprocess management     , proc     , shell-    , system     , procs     , shells     , inproc@@ -31,6 +30,12 @@     , shellStrict     , procStrictWithErr     , shellStrictWithErr++    , system+    , stream+    , streamWithErr+    , systemStrict+    , systemStrictWithErr     ) where  import Control.Applicative@@ -357,6 +362,10 @@      Exception.bracket open close' handle ) +{-| `systemStrict` generalizes `shellStrict` and `procStrict` by allowing you to+    supply your own custom `CreateProcess`.  This is for advanced users who feel+    comfortable using the lower-level @process@ API+-} systemStrict     :: MonadIO io     => Process.CreateProcess@@ -397,6 +406,11 @@                     restore (Process.waitForProcess ph) <* halt a ) ))             (Data.ByteString.hGetContents hOut) ) ) +{-| `systemStrictWithErr` generalizes `shellStrictWithErr` and+    `procStrictWithErr` by allowing you to supply your own custom+    `CreateProcess`.  This is for advanced users who feel comfortable using+    the lower-level @process@ API+-} systemStrictWithErr     :: MonadIO io     => Process.CreateProcess@@ -471,6 +485,10 @@     -- ^ Chunks of bytes read from process output inshell cmd = stream (Process.shell (Data.Text.unpack cmd)) +{-| `stream` generalizes `inproc` and `inshell` by allowing you to supply your+    own custom `CreateProcess`.  This is for advanced users who feel comfortable+    using the lower-level @process@ API+-} stream     :: Process.CreateProcess     -- ^ Command@@ -511,6 +529,10 @@                 Async.withAsync (feedIn restore) k ) ))     inhandle hOut <|> (liftIO (Process.waitForProcess ph *> halt a) *> empty) +{-| `streamWithErr` generalizes `inprocWithErr` and `inshellWithErr` by allowing+    you to supply your own custom `CreateProcess`.  This is for advanced users+    who feel comfortable using the lower-level @process@ API+-} streamWithErr     :: Process.CreateProcess     -- ^ Command
src/Turtle/Line.hs view
@@ -18,6 +18,7 @@ #if __GLASGOW_HASKELL__ >= 708 import Data.Coerce #endif+import Data.List.NonEmpty (NonEmpty(..)) import Data.String #if __GLASGOW_HASKELL__ >= 710 #else@@ -27,6 +28,8 @@ import Data.Typeable import Control.Exception +import qualified Data.List.NonEmpty+ -- | The `NewlineForbidden` exception is thrown when you construct a `Line` -- using an overloaded string literal or by calling `fromString` explicitly -- and the supplied string contains newlines. This is a programming error to@@ -67,12 +70,12 @@ lineToText (Line t) = t  -- | Split text into lines. The inverse of `linesToText`.-textToLines :: Text -> [Line]+textToLines :: Text -> NonEmpty Line textToLines = #if __GLASGOW_HASKELL__ >= 708-  coerce Text.lines+  Data.List.NonEmpty.fromList . coerce (Text.splitOn "\n") #else-  map unsafeTextToLine . Text.lines+  Data.List.NonEmpty.fromList . map unsafeTextToLine . Text.splitOn "\n" #endif  -- | Merge lines into a single text value.@@ -89,9 +92,8 @@ textToLine :: Text -> Maybe Line textToLine = fromSingleton . textToLines   where-    fromSingleton []  = Just (Line "")-    fromSingleton [a] = Just a-    fromSingleton _   = Nothing+    fromSingleton (a :| []) = Just a+    fromSingleton  _        = Nothing  -- | Convert a text value into a line. -- Precondition (unchecked): the argument does not contain newlines.
src/Turtle/Prelude.hs view
@@ -125,6 +125,7 @@     , mkdir     , mktree     , cp+    , cptree     , rm     , rmdir     , rmtree@@ -182,6 +183,7 @@     , limitWhile     , cache     , parallel+    , single      -- * Folds     , countChars@@ -194,7 +196,6 @@     -- * Subprocess management     , proc     , shell-    , system     , procs     , shells     , inproc@@ -206,6 +207,12 @@     , procStrictWithErr     , shellStrictWithErr +    , system+    , stream+    , streamWithErr+    , systemStrict+    , systemStrictWithErr+     -- * Permissions     , Permissions     , chmod@@ -544,6 +551,11 @@      bracket open close' handle ) ++{-| `systemStrict` generalizes `shellStrict` and `procStrict` by allowing you to+    supply your own custom `CreateProcess`.  This is for advanced users who feel+    comfortable using the lower-level @process@ API+-} systemStrict     :: MonadIO io     => Process.CreateProcess@@ -582,6 +594,11 @@                     restore (liftIO (Process.waitForProcess ph)) `finally` halt a ) ))             (Text.hGetContents hOut) ) ) +{-| `systemStrictWithErr` generalizes `shellStrictWithErr` and+    `procStrictWithErr` by allowing you to supply your own custom+    `CreateProcess`.  This is for advanced users who feel comfortable using+    the lower-level @process@ API+-} systemStrictWithErr     :: MonadIO io     => Process.CreateProcess@@ -652,6 +669,10 @@     -- ^ Lines of standard output inshell cmd = stream (Process.shell (unpack cmd)) +{-| `stream` generalizes `inproc` and `inshell` by allowing you to supply your+    own custom `CreateProcess`.  This is for advanced users who feel comfortable+    using the lower-level @process@ API+-} stream     :: Process.CreateProcess     -- ^ Command@@ -687,6 +708,10 @@             mask (\restore -> withAsync (feedIn restore) (restore . k))))     inhandle hOut <|> (liftIO (Process.waitForProcess ph *> halt a) *> empty) +{-| `streamWithErr` generalizes `inprocWithErr` and `inshellWithErr` by allowing+    you to supply your own custom `CreateProcess`.  This is for advanced users+    who feel comfortable using the lower-level @process@ API+-} streamWithErr     :: Process.CreateProcess     -- ^ Command@@ -999,6 +1024,21 @@ cp :: MonadIO io => FilePath -> FilePath -> io () cp oldPath newPath = liftIO (Filesystem.copyFile oldPath newPath) +-- | Copy a directory tree+cptree :: MonadIO io => FilePath -> FilePath -> io ()+cptree oldTree newTree = sh (do+    oldPath <- lstree oldTree+    -- The `system-filepath` library treats a path like "/tmp" as a file and not+    -- a directory and fails to strip it as a prefix from `/tmp/foo`.  Adding+    -- `(</> "")` to the end of the path makes clear that the path is a+    -- directory+    Just suffix <- return (Filesystem.stripPrefix (oldTree </> "") oldPath)+    let newPath = newTree </> suffix+    isFile <- testfile newPath+    if isFile+        then cp oldPath newPath+        else mktree newPath )+ -- | Remove a file rm :: MonadIO io => FilePath -> io () rm path = liftIO (Filesystem.removeFile path)@@ -1211,8 +1251,8 @@ whichAll :: FilePath -> Shell FilePath whichAll cmd = do   Just paths <- need "PATH"-  path <- select (Text.split (== ':') paths)-  let path' = Filesystem.fromText path </> cmd+  path <- select (Filesystem.splitSearchPathString . Text.unpack $ paths)+  let path' = path </> cmd    True <- testfile path' @@ -1825,3 +1865,18 @@             return (Pair x Nothing)          done' (Pair x _) = done x++-- | Returns the result of a 'Shell' that outputs a single+-- line:+--+-- > main = do+-- >   Just directory <- single (inshell "pwd" empty)+-- >   print directory+single :: MonadIO io => Shell a -> io (Maybe a)+single s = do+    as <- fold s Control.Foldl.list+    case as of+        [a] -> return (Just a)+        _   -> do+            let msg = format ("single: expected 1 line of input but there were "%d%" lines of input") (length as)+            die msg
src/Turtle/Shell.hs view
@@ -76,6 +76,8 @@ import Control.Monad.Managed (MonadManaged(..), with) import Control.Foldl (Fold(..), FoldM(..)) import qualified Control.Foldl as Foldl+import Data.Foldable (Foldable)+import qualified Data.Foldable import Data.Monoid import Data.String (IsString(..)) import Prelude -- Fix redundant import warnings@@ -164,10 +166,10 @@     fromString str = pure (fromString str)  -- | Convert a list to a `Shell` that emits each element of the list-select :: [a] -> Shell a+select :: Foldable f => f a -> Shell a select as = Shell (\(FoldM step begin done) -> do     x0 <- begin     let step' a k x = do             x' <- step x a             k $! x'-    foldr step' done as $! x0 )+    Data.Foldable.foldr step' done as $! x0 )
src/Turtle/Tutorial.hs view
@@ -448,14 +448,21 @@ -- -- @ -- Prelude Turtle> :type echo--- echo :: `Text` -> `IO` ()+-- echo :: `Line` -> `IO` () -- @ -- -- The above type says that `echo` is a function whose argument is a value of--- type `Text` and whose result is a subroutine (`IO`) with an empty return+-- type `Line` and whose result is a subroutine (`IO`) with an empty return -- value (denoted @\'()\'@). ----- Now we can understand the type error: `echo` expects a `Text` argument but+-- `Line` is a wrapper around `Text` and represents a `Text` value with no+-- internal newlines:+--+-- @+-- newtype `Line` = `Line` `Text`+-- @+--+-- Now we can understand the type error: `echo` expects a `Line` argument but -- `datefile` returns a `UTCTime`, which is not the same thing.  Unlike Bash, -- not everything is `Text` in Haskell and the compiler will not cast or coerce -- types for you.@@ -474,16 +481,18 @@ -- `print`. -- -- This library provides a helper function that lets you convert any type that--- implements `Show` into a `Text` value:+-- implements `Show` into any other type that implements `IsString`: --  -- @ -- \-\- This behaves like Python's \`repr\` function--- `repr` :: `Show` a => a -> `Text`+-- `repr` :: (`Show` a, `IsString` b) => a -> b -- @ -- -- You could therefore implement `print` in terms of `echo` and `repr`: -- -- >  print x = echo (repr x)+--+-- ... which works because `Line` implements `IsString`  -- $shell --@@ -492,7 +501,7 @@ -- @turtle@: -- -- @--- $ stack ghci+-- \$ stack ghci -- Prelude> :set -XOverloadedStrings -- Prelude> import Turtle -- Prelude Turtle> `cd` \"/tmp\"
test/RegressionMaskingException.hs view
@@ -2,8 +2,6 @@  import Turtle -import qualified System.Timeout- -- This test fails by hanging main :: IO () main = runManaged (do
turtle.cabal view
@@ -1,5 +1,5 @@ Name: turtle-Version: 1.3.2+Version: 1.3.3 Cabal-Version: >=1.10 Build-Type: Simple License: BSD3@@ -59,6 +59,7 @@         hostname                           < 1.1 ,         managed              >= 1.0.3   && < 1.1 ,         process              >= 1.0.1.1 && < 1.5 ,+        semigroups           >= 0.5.0   && < 0.19,         system-filepath      >= 0.3.1   && < 0.5 ,         system-fileio        >= 0.2.1   && < 0.4 ,         stm                                < 2.5 ,