mirror of
https://github.com/kowainik/shellmet.git
synced 2024-09-11 09:55:42 +03:00
97 lines
2.3 KiB
Haskell
97 lines
2.3 KiB
Haskell
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
|
{-# LANGUAGE TypeFamilies #-}
|
|
|
|
{- |
|
|
Module : Shellmet
|
|
Copyright : (c) 2019-2021 Kowainik
|
|
SPDX-License-Identifier : MPL-2.0
|
|
Maintainer : Kowainik <xrom.xkov@gmail.com>
|
|
Stability : Stable
|
|
Portability : Portable
|
|
|
|
This module contains neat utilities to be able to work with
|
|
shell commands in generic and simple way using just string literals.
|
|
|
|
>>> "echo" ["Hello", "World!"]
|
|
⚙ echo Hello 'World!'
|
|
Hello World!
|
|
-}
|
|
|
|
module Shellmet
|
|
( ($|)
|
|
, ($^)
|
|
, ($?)
|
|
, isSuccess
|
|
) where
|
|
|
|
import Control.Exception (catch)
|
|
import Data.String (IsString (..))
|
|
import Data.Text (Text)
|
|
import System.Process (callProcess, readProcess, showCommandForUser)
|
|
|
|
import qualified Data.Text as T
|
|
|
|
|
|
{- | This instance is needed to provide functionality to call commands by using
|
|
simple string literals in 'IO' monad.
|
|
|
|
>>> "ls" ["-1", "test"]
|
|
⚙ ls -1 test
|
|
Doctest.hs
|
|
-}
|
|
instance (a ~ [Text], b ~ IO ()) => IsString (a -> b) where
|
|
fromString :: String -> [Text] -> IO ()
|
|
fromString cmd args = do
|
|
let argStrs = map T.unpack args
|
|
putStrLn $ "⚙ " ++ showCommandForUser cmd argStrs
|
|
callProcess cmd argStrs
|
|
{-# INLINE fromString #-}
|
|
|
|
{- | Run shell command with given options and return stripped stdout of the
|
|
executed command.
|
|
|
|
>>> "echo" $| ["Foo", "Bar"]
|
|
"Foo Bar"
|
|
-}
|
|
infix 5 $|
|
|
($|) :: FilePath -> [Text] -> IO Text
|
|
cmd $| args = T.strip . T.pack <$> readProcess cmd (map T.unpack args) ""
|
|
{-# INLINE ($|) #-}
|
|
|
|
{- | This operator runs shell command with given options but doesn't print the
|
|
command itself.
|
|
|
|
>>> "echo" $^ ["Foo", "Bar"]
|
|
Foo Bar
|
|
-}
|
|
infix 5 $^
|
|
($^) :: FilePath -> [Text] -> IO ()
|
|
cmd $^ args = callProcess cmd (map T.unpack args)
|
|
{-# INLINE ($^) #-}
|
|
|
|
{- | Do some IO actions when process failed with 'IOError'.
|
|
|
|
>>> "exit" ["0"] $? putStrLn "Command failed"
|
|
⚙ exit 0
|
|
|
|
>>> "exit" ["1"] $? putStrLn "Command failed"
|
|
⚙ exit 1
|
|
Command failed
|
|
-}
|
|
infixl 4 $?
|
|
($?) :: IO a -> IO a -> IO a
|
|
action $? handler = action `catch` \(_ :: IOError) -> handler
|
|
{-# INLINE ($?) #-}
|
|
|
|
{- | Returns the indicator of if the command succeded or not.
|
|
|
|
>>> isSuccess $ "echo" ["Hello world!"]
|
|
⚙ echo 'Hello world!'
|
|
Hello world!
|
|
True
|
|
-}
|
|
isSuccess :: IO a -> IO Bool
|
|
isSuccess action = (True <$ action) $? pure False
|