shell-monad 0.6.4 → 0.6.5
raw patch · 5 files changed
+67/−8 lines, 5 filesdep +semigroupsdep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: semigroups
Dependency ranges changed: base
API changes (from Hackage documentation)
- Control.Monad.Shell: TAnd :: Test -> Test -> Test
- Control.Monad.Shell: TBlockExists :: p -> Test
- Control.Monad.Shell: TCharExists :: p -> Test
- Control.Monad.Shell: TDirExists :: p -> Test
- Control.Monad.Shell: TEmpty :: p -> Test
- Control.Monad.Shell: TEqual :: Term Var p -> Term Var q -> Test
- Control.Monad.Shell: TFileEqual :: p -> q -> Test
- Control.Monad.Shell: TFileExecutable :: p -> Test
- Control.Monad.Shell: TFileExists :: p -> Test
- Control.Monad.Shell: TFileNewer :: p -> q -> Test
- Control.Monad.Shell: TFileNonEmpty :: p -> Test
- Control.Monad.Shell: TFileOlder :: p -> q -> Test
- Control.Monad.Shell: TGE :: Term Var p -> Term Var q -> Test
- Control.Monad.Shell: TGT :: Term Var p -> Term Var q -> Test
- Control.Monad.Shell: TLE :: Term Var p -> Term Var q -> Test
- Control.Monad.Shell: TLT :: Term Var p -> Term Var q -> Test
- Control.Monad.Shell: TNonEmpty :: p -> Test
- Control.Monad.Shell: TNot :: Test -> Test
- Control.Monad.Shell: TNotEqual :: Term Var p -> Term Var q -> Test
- Control.Monad.Shell: TOr :: Test -> Test -> Test
- Control.Monad.Shell: TRegularFileExists :: p -> Test
- Control.Monad.Shell: TStrEqual :: p -> q -> Test
- Control.Monad.Shell: TStrNotEqual :: p -> q -> Test
- Control.Monad.Shell: TSymlinkExists :: p -> Test
- Control.Monad.Shell: instance (Param arg, CmdParams result) => CmdParams (arg -> result)
- Control.Monad.Shell: instance (Show a, Num a) => Num (Term Static a)
- Control.Monad.Shell: instance Applicative Script
- Control.Monad.Shell: instance Enum Arith
- Control.Monad.Shell: instance Eq Func
- Control.Monad.Shell: instance Eq VarName
- Control.Monad.Shell: instance Functor Script
- Control.Monad.Shell: instance Monad Script
- Control.Monad.Shell: instance Monoid Env
- Control.Monad.Shell: instance NameHinted ()
- Control.Monad.Shell: instance NameHinted (Maybe Text)
- Control.Monad.Shell: instance NameHinted NamedLike
- Control.Monad.Shell: instance Named (Term Var t)
- Control.Monad.Shell: instance Named Func
- Control.Monad.Shell: instance Named UntypedVar
- Control.Monad.Shell: instance Named VarName
- Control.Monad.Shell: instance Num Arith
- Control.Monad.Shell: instance Ord Func
- Control.Monad.Shell: instance Ord VarName
- Control.Monad.Shell: instance Param (Quoted Text)
- Control.Monad.Shell: instance Param (Term Var a)
- Control.Monad.Shell: instance Param (WithVar a)
- Control.Monad.Shell: instance Param Arith
- Control.Monad.Shell: instance Param Output
- Control.Monad.Shell: instance Param String
- Control.Monad.Shell: instance Param Text
- Control.Monad.Shell: instance Param UntypedVar
- Control.Monad.Shell: instance RedirFile (Fd, FilePath)
- Control.Monad.Shell: instance RedirFile FilePath
- Control.Monad.Shell: instance Show Func
- Control.Monad.Shell: instance Show VarName
- Control.Monad.Shell: instance Show a => Param (Term Static a)
- Control.Monad.Shell: instance f ~ () => CmdParams (Script f)
- Control.Monad.Shell.Quote: getQ :: Quoted a -> a
- Control.Monad.Shell.Quote: instance Eq a => Eq (Quoted a)
- Control.Monad.Shell.Quote: instance IsString (Quoted Text)
- Control.Monad.Shell.Quote: instance Monoid a => Monoid (Quoted a)
- Control.Monad.Shell.Quote: instance Ord a => Ord (Quoted a)
- Control.Monad.Shell.Quote: instance Quotable (Val String)
- Control.Monad.Shell.Quote: instance Quotable (Val Text)
- Control.Monad.Shell.Quote: instance Quotable String
- Control.Monad.Shell.Quote: instance Quotable Text
- Control.Monad.Shell.Quote: instance Show a => Show (Quoted a)
- Control.Monad.Shell.Quote: instance Show v => Quotable (Val v)
+ Control.Monad.Shell: [TAnd] :: Test -> Test -> Test
+ Control.Monad.Shell: [TBlockExists] :: (Param p) => p -> Test
+ Control.Monad.Shell: [TCharExists] :: (Param p) => p -> Test
+ Control.Monad.Shell: [TDirExists] :: (Param p) => p -> Test
+ Control.Monad.Shell: [TEmpty] :: (Param p) => p -> Test
+ Control.Monad.Shell: [TEqual] :: (Integral p, Integral q) => Term Var p -> Term Var q -> Test
+ Control.Monad.Shell: [TFileEqual] :: (Param p, Param q) => p -> q -> Test
+ Control.Monad.Shell: [TFileExecutable] :: (Param p) => p -> Test
+ Control.Monad.Shell: [TFileExists] :: (Param p) => p -> Test
+ Control.Monad.Shell: [TFileNewer] :: (Param p, Param q) => p -> q -> Test
+ Control.Monad.Shell: [TFileNonEmpty] :: (Param p) => p -> Test
+ Control.Monad.Shell: [TFileOlder] :: (Param p, Param q) => p -> q -> Test
+ Control.Monad.Shell: [TGE] :: (Integral p, Integral q) => Term Var p -> Term Var q -> Test
+ Control.Monad.Shell: [TGT] :: (Integral p, Integral q) => Term Var p -> Term Var q -> Test
+ Control.Monad.Shell: [TLE] :: (Integral p, Integral q) => Term Var p -> Term Var q -> Test
+ Control.Monad.Shell: [TLT] :: (Integral p, Integral q) => Term Var p -> Term Var q -> Test
+ Control.Monad.Shell: [TNonEmpty] :: (Param p) => p -> Test
+ Control.Monad.Shell: [TNotEqual] :: (Integral p, Integral q) => Term Var p -> Term Var q -> Test
+ Control.Monad.Shell: [TNot] :: Test -> Test
+ Control.Monad.Shell: [TOr] :: Test -> Test -> Test
+ Control.Monad.Shell: [TRegularFileExists] :: (Param p) => p -> Test
+ Control.Monad.Shell: [TStrEqual] :: (Param p, Param q) => p -> q -> Test
+ Control.Monad.Shell: [TStrNotEqual] :: (Param p, Param q) => p -> q -> Test
+ Control.Monad.Shell: [TSymlinkExists] :: (Param p) => p -> Test
+ Control.Monad.Shell: instance (Control.Monad.Shell.Param arg, Control.Monad.Shell.CmdParams result) => Control.Monad.Shell.CmdParams (arg -> result)
+ Control.Monad.Shell: instance (GHC.Show.Show a, GHC.Num.Num a) => GHC.Num.Num (Control.Monad.Shell.Term Control.Monad.Shell.Static a)
+ Control.Monad.Shell: instance (f ~ ()) => Control.Monad.Shell.CmdParams (Control.Monad.Shell.Script f)
+ Control.Monad.Shell: instance Control.Monad.Shell.NameHinted ()
+ Control.Monad.Shell: instance Control.Monad.Shell.NameHinted (GHC.Base.Maybe Data.Text.Internal.Lazy.Text)
+ Control.Monad.Shell: instance Control.Monad.Shell.NameHinted Control.Monad.Shell.NamedLike
+ Control.Monad.Shell: instance Control.Monad.Shell.Named (Control.Monad.Shell.Term Control.Monad.Shell.Var t)
+ Control.Monad.Shell: instance Control.Monad.Shell.Named Control.Monad.Shell.Func
+ Control.Monad.Shell: instance Control.Monad.Shell.Named Control.Monad.Shell.UntypedVar
+ Control.Monad.Shell: instance Control.Monad.Shell.Named Control.Monad.Shell.VarName
+ Control.Monad.Shell: instance Control.Monad.Shell.Param (Control.Monad.Shell.Quote.Quoted Data.Text.Internal.Lazy.Text)
+ Control.Monad.Shell: instance Control.Monad.Shell.Param (Control.Monad.Shell.Term Control.Monad.Shell.Var a)
+ Control.Monad.Shell: instance Control.Monad.Shell.Param (Control.Monad.Shell.WithVar a)
+ Control.Monad.Shell: instance Control.Monad.Shell.Param Control.Monad.Shell.Arith
+ Control.Monad.Shell: instance Control.Monad.Shell.Param Control.Monad.Shell.Output
+ Control.Monad.Shell: instance Control.Monad.Shell.Param Control.Monad.Shell.UntypedVar
+ Control.Monad.Shell: instance Control.Monad.Shell.Param Data.Text.Internal.Lazy.Text
+ Control.Monad.Shell: instance Control.Monad.Shell.Param GHC.Base.String
+ Control.Monad.Shell: instance Control.Monad.Shell.RedirFile (System.Posix.Types.Fd, GHC.IO.FilePath)
+ Control.Monad.Shell: instance Control.Monad.Shell.RedirFile GHC.IO.FilePath
+ Control.Monad.Shell: instance GHC.Base.Applicative Control.Monad.Shell.Script
+ Control.Monad.Shell: instance GHC.Base.Functor Control.Monad.Shell.Script
+ Control.Monad.Shell: instance GHC.Base.Monad Control.Monad.Shell.Script
+ Control.Monad.Shell: instance GHC.Base.Monoid Control.Monad.Shell.Env
+ Control.Monad.Shell: instance GHC.Base.Semigroup Control.Monad.Shell.Env
+ Control.Monad.Shell: instance GHC.Classes.Eq Control.Monad.Shell.Func
+ Control.Monad.Shell: instance GHC.Classes.Eq Control.Monad.Shell.VarName
+ Control.Monad.Shell: instance GHC.Classes.Ord Control.Monad.Shell.Func
+ Control.Monad.Shell: instance GHC.Classes.Ord Control.Monad.Shell.VarName
+ Control.Monad.Shell: instance GHC.Enum.Enum Control.Monad.Shell.Arith
+ Control.Monad.Shell: instance GHC.Num.Num Control.Monad.Shell.Arith
+ Control.Monad.Shell: instance GHC.Show.Show Control.Monad.Shell.Func
+ Control.Monad.Shell: instance GHC.Show.Show Control.Monad.Shell.VarName
+ Control.Monad.Shell: instance GHC.Show.Show a => Control.Monad.Shell.Param (Control.Monad.Shell.Term Control.Monad.Shell.Static a)
+ Control.Monad.Shell.Quote: [getQ] :: Quoted a -> a
+ Control.Monad.Shell.Quote: instance Control.Monad.Shell.Quote.Quotable (Control.Monad.Shell.Quote.Val Data.Text.Internal.Lazy.Text)
+ Control.Monad.Shell.Quote: instance Control.Monad.Shell.Quote.Quotable (Control.Monad.Shell.Quote.Val GHC.Base.String)
+ Control.Monad.Shell.Quote: instance Control.Monad.Shell.Quote.Quotable Data.Text.Internal.Lazy.Text
+ Control.Monad.Shell.Quote: instance Control.Monad.Shell.Quote.Quotable GHC.Base.String
+ Control.Monad.Shell.Quote: instance Data.String.IsString (Control.Monad.Shell.Quote.Quoted Data.Text.Internal.Lazy.Text)
+ Control.Monad.Shell.Quote: instance GHC.Base.Monoid a => GHC.Base.Monoid (Control.Monad.Shell.Quote.Quoted a)
+ Control.Monad.Shell.Quote: instance GHC.Base.Semigroup a => GHC.Base.Semigroup (Control.Monad.Shell.Quote.Quoted a)
+ Control.Monad.Shell.Quote: instance GHC.Classes.Eq a => GHC.Classes.Eq (Control.Monad.Shell.Quote.Quoted a)
+ Control.Monad.Shell.Quote: instance GHC.Classes.Ord a => GHC.Classes.Ord (Control.Monad.Shell.Quote.Quoted a)
+ Control.Monad.Shell.Quote: instance GHC.Show.Show a => GHC.Show.Show (Control.Monad.Shell.Quote.Quoted a)
+ Control.Monad.Shell.Quote: instance GHC.Show.Show v => Control.Monad.Shell.Quote.Quotable (Control.Monad.Shell.Quote.Val v)
- Control.Monad.Shell: caseOf :: Term Var a -> [(Quoted Text, Script ())] -> Script ()
+ Control.Monad.Shell: caseOf :: forall a. Term Var a -> [(Quoted Text, Script ())] -> Script ()
- Control.Monad.Shell: defaultVar :: Param param => forall a. Term Var a -> param -> Script (Term Var a)
+ Control.Monad.Shell: defaultVar :: (Param param) => forall a. Term Var a -> param -> Script (Term Var a)
- Control.Monad.Shell: errUnlessVar :: Param param => forall a. Term Var a -> param -> Script (Term Var a)
+ Control.Monad.Shell: errUnlessVar :: (Param param) => forall a. Term Var a -> param -> Script (Term Var a)
- Control.Monad.Shell: forCmd :: Script () -> (Term Var a -> Script ()) -> Script ()
+ Control.Monad.Shell: forCmd :: forall a. Script () -> (Term Var a -> Script ()) -> Script ()
- Control.Monad.Shell: globalVar :: Text -> Script (Term Var a)
+ Control.Monad.Shell: globalVar :: forall a. Text -> Script (Term Var a)
- Control.Monad.Shell: lengthVar :: Term Var a -> Script (Term Var Integer)
+ Control.Monad.Shell: lengthVar :: forall a. Term Var a -> Script (Term Var Integer)
- Control.Monad.Shell: newVar :: NameHinted namehint => forall a. namehint -> Script (Term Var a)
+ Control.Monad.Shell: newVar :: (NameHinted namehint) => forall a. namehint -> Script (Term Var a)
- Control.Monad.Shell: positionalParameters :: Term Var a
+ Control.Monad.Shell: positionalParameters :: forall a. Term Var a
- Control.Monad.Shell: static :: Quotable (Val t) => t -> Term Static t
+ Control.Monad.Shell: static :: (Quotable (Val t)) => t -> Term Static t
- Control.Monad.Shell: takeParameter :: NameHinted namehint => forall a. namehint -> Script (Term Var a)
+ Control.Monad.Shell: takeParameter :: (NameHinted namehint) => forall a. namehint -> Script (Term Var a)
- Control.Monad.Shell: trimVar :: Greediness -> Direction -> Term Var String -> Quoted Text -> Script (Term Var a)
+ Control.Monad.Shell: trimVar :: forall a. Greediness -> Direction -> Term Var String -> Quoted Text -> Script (Term Var a)
- Control.Monad.Shell: whenVar :: Param param => forall a. Term Var a -> param -> Script (Term Var a)
+ Control.Monad.Shell: whenVar :: (Param param) => forall a. Term Var a -> param -> Script (Term Var a)
Files
- CHANGELOG +8/−0
- Control/Monad/Shell.hs +38/−5
- Control/Monad/Shell/Quote.hs +5/−2
- examples/hello.hs +12/−0
- shell-monad.cabal +4/−1
CHANGELOG view
@@ -1,3 +1,11 @@+shell-monad (0.6.5) unstable; urgency=medium++ * Fix some documentation typos.+ * Improvements to build with GHC 7.10.3 - 8.4.3. (Thanks, Simon Michael.)+ * Added inline example to documentation.++ -- Joey Hess <id@joeyh.name> Sat, 13 Oct 2018 15:50:44 -0400+ shell-monad (0.6.4) unstable; urgency=medium * Fix build with ghc 7.10.
Control/Monad/Shell.hs view
@@ -1,7 +1,36 @@ -- | This is a shell monad, for generating shell scripts. -- -- The emphasis is on generating shell code that will work in any POSIX--- compliant shell.+-- compliant shell and avoids many common shell pitfalls, including+-- insufficient quoting, while allowing the Haskell type checker to be+-- leveraged for additional safety.+--+-- Here is a hello world example.+--+-- > {-# LANGUAGE OverloadedStrings, ExtendedDefaultRules #-}+-- > import Control.Monad.Shell+-- > import Data.Monoid+-- > import qualified Data.Text.Lazy as T+-- > import qualified Data.Text.Lazy.IO as T+-- > default (T.Text)+-- > +-- > main :: IO ()+-- > main = T.writeFile "hello.sh" $ script $ do+-- > cmd "echo" "hello, world"+-- > username <- newVarFrom (Output (cmd "whoami")) ()+-- > cmd "echo" "from" (WithVar username (<> "'s shell"))+--+-- When run, that generates this shell code:+-- +-- > #!/bin/sh+-- > echo 'hello, world'+-- > _v="$(whoami)"+-- > echo from "$_v"''"'"'s shell'+--+-- There are several other examples shipped in the examples/ directory+-- of the shell-monad package. For example, protocol.hs shows how +-- shell-monad can be used to implement a shell script that speaks a+-- protocol that is defined using Haskell data types. {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE FlexibleInstances #-}@@ -85,7 +114,7 @@ import qualified Data.Text.Lazy as L import qualified Data.Set as S-import Data.Monoid+import Data.Semigroup import Data.Char import System.Posix.Types (Fd) import System.Posix.IO (stdInput, stdOutput, stdError)@@ -221,8 +250,12 @@ , envFuncs :: S.Set Func } +instance Semigroup Env where+ (<>) a b = Env (envVars a <> envVars b) (envFuncs a <> envFuncs b)+ instance Monoid Env where mempty = Env mempty mempty+ -- this is redundant starting with base-4.11 / GHC 8.4: mappend a b = Env (envVars a <> envVars b) (envFuncs a <> envFuncs b) getEnv :: Script Env@@ -343,7 +376,7 @@ -- -- > demo = script $ do -- > cmd "echo" "hello, world"--- > name <- newVar "name"+-- > name <- newVar () -- > readVar name -- > cmd "echo" "hello" name --@@ -456,7 +489,7 @@ -- v1 <- 'newVar' () -- @ ----- To provide a naming hint, use either 'NamedLike'.+-- To provide a naming hint, use 'NamedLike'. -- -- @ -- v1 <- 'newVar' ('NamedLike' \"x\")@@ -506,7 +539,7 @@ -- variable. -- -- > home <- globalVar "HOME"--- > cabalDir <- newVarContaining (WithVar home (<> "/.cabal")) ()+-- > cabalDir <- newVarFrom (WithVar home (<> "/.cabal")) () -- -- Or to capture the output of an arithmetic operation. --
Control/Monad/Shell/Quote.hs view
@@ -1,5 +1,6 @@ -- | Shell quoting +{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}@@ -12,7 +13,9 @@ import qualified Data.Text.Lazy as L import Data.String-import Data.Monoid+#if !(MIN_VERSION_base(4,11,0))+import Data.Semigroup+#endif import Data.Char -- | A value that is safely quoted so that it can be exposed to the shell.@@ -20,7 +23,7 @@ -- While the constructor is exposed, you should avoid directly constucting -- Quoted values. Instead, use 'quote'. newtype Quoted a = Q { getQ :: a }- deriving (Eq, Ord, Show, Monoid)+ deriving (Eq, Ord, Show, Semigroup, Monoid) -- | Quotes a value to allow it to be safely exposed to the shell. --
+ examples/hello.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE OverloadedStrings, ExtendedDefaultRules #-}+import Control.Monad.Shell+import Data.Monoid+import qualified Data.Text.Lazy as T+import qualified Data.Text.Lazy.IO as T+default (T.Text)++main :: IO ()+main = T.writeFile "hello.sh" $ script $ do+ cmd "echo" "hello, world"+ username <- newVarFrom (Output (cmd "whoami")) ()+ cmd "echo" "from" (WithVar username (<> "'s shell"))
shell-monad.cabal view
@@ -1,5 +1,5 @@ Name: shell-monad-Version: 0.6.4+Version: 0.6.5 Cabal-Version: >= 1.8 License: BSD3 Maintainer: Joey Hess <id@joeyh.name>@@ -18,6 +18,7 @@ examples/santa.hs examples/protocol.hs examples/fib.hs+ examples/hello.hs Library GHC-Options: -Wall -fno-warn-tabs@@ -25,6 +26,8 @@ Control.Monad.Shell Control.Monad.Shell.Quote Build-Depends: base (>= 4.5), base < 5, containers, text, unix+ if !impl(ghc >= 8.0)+ Build-Depends: semigroups == 0.18.* source-repository head type: git