    {-# LANGUAGE ScopedTypeVariables #-}
    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE CPP #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE TypeFamilies #-}
    {-# LANGUAGE FlexibleContexts #-}
    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE UndecidableInstances #-}
    {-# LANGUAGE DeriveDataTypeable #-}
    {-# LANGUAGE InstanceSigs#-}
    -- | I started exposing multiple module (starting with one for finding)
    -- Base prevented circular dependencies
    -- However, Shelly went back to exposing a single module
    module Shelly.Base
      (
        Sh(..), ShIO, runSh, State(..), ReadOnlyState(..), StdHandle(..),
        HandleInitializer, StdInit(..),
        FilePath, Text,
        relPath, path, absPath, canonic, canonicalize,
        test_d, test_s,
        unpack, gets, get, modify, trace,
        ls, lsRelAbs,
        toTextIgnore,
        echo, echo_n, echo_err, echo_n_err, inspect, inspect_err,
        catchany,
        liftIO, (>=>),
        eitherRelativeTo, relativeTo, maybeRelativeTo,
        whenM
        -- * utilities not yet exported
        , addTrailingSlash
      ) where

    #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 706
    import Prelude hiding (FilePath, catch)
    #else
    import Prelude hiding (FilePath)
    #endif

    import Data.Text (Text)
    import System.Process( ProcessHandle, StdStream(..) )
    import System.IO ( Handle, hFlush, stderr, stdout )

    import Control.Monad (when, (>=>),
             liftM
           )
    import Control.Monad.Fail (MonadFail)
    import Control.Monad.Base
    import Control.Monad.Trans.Control
    import Control.Applicative (Applicative, (<$>))
    import System.Directory( doesDirectoryExist, listDirectory)
    import System.PosixCompat.Files( getSymbolicLinkStatus, isSymbolicLink )
    import System.FilePath  ( FilePath, isRelative)
    import qualified System.FilePath as FP
    import qualified System.Directory as FS
    import Data.IORef (readIORef, modifyIORef, IORef)
    import Data.Monoid (mappend)
    import qualified Data.Text as T
    import qualified Data.Text.IO as TIO
    import Control.Exception (SomeException, catch, throwIO, Exception)
    import Data.Maybe (fromMaybe)
    import qualified Control.Monad.Catch as Catch
    import Control.Monad.Trans ( MonadIO, liftIO )
    import Control.Monad.Reader.Class (MonadReader, ask)
    import Control.Monad.Trans.Reader (runReaderT, ReaderT(..))
    import qualified Data.Set as S
    import Data.Typeable (Typeable)

    -- | ShIO is Deprecated in favor of 'Sh', which is easier to type.
    type ShIO a = Sh a
    {-# DEPRECATED ShIO "Use Sh instead of ShIO" #-}

    newtype Sh a = Sh {
          Sh a -> ReaderT (IORef State) IO a
    unSh :: ReaderT (IORef State) IO a
      } deriving (Functor Sh
    a -> Sh a
    Functor Sh =>
    (forall a. a -> Sh a)
    -> (forall a b. Sh (a -> b) -> Sh a -> Sh b)
    -> (forall a b c. (a -> b -> c) -> Sh a -> Sh b -> Sh c)
    -> (forall a b. Sh a -> Sh b -> Sh b)
    -> (forall a b. Sh a -> Sh b -> Sh a)
    -> Applicative Sh
    Sh a -> Sh b -> Sh b
    Sh a -> Sh b -> Sh a
    Sh (a -> b) -> Sh a -> Sh b
    (a -> b -> c) -> Sh a -> Sh b -> Sh c
    forall a. a -> Sh a
    forall a b. Sh a -> Sh b -> Sh a
    forall a b. Sh a -> Sh b -> Sh b
    forall a b. Sh (a -> b) -> Sh a -> Sh b
    forall a b c. (a -> b -> c) -> Sh a -> Sh b -> Sh c
    forall (f :: * -> *).
    Functor f =>
    (forall a. a -> f a)
    -> (forall a b. f (a -> b) -> f a -> f b)
    -> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
    -> (forall a b. f a -> f b -> f b)
    -> (forall a b. f a -> f b -> f a)
    -> Applicative f
    <* :: Sh a -> Sh b -> Sh a
    $c<* :: forall a b. Sh a -> Sh b -> Sh a
    *> :: Sh a -> Sh b -> Sh b
    $c*> :: forall a b. Sh a -> Sh b -> Sh b
    liftA2 :: (a -> b -> c) -> Sh a -> Sh b -> Sh c
    $cliftA2 :: forall a b c. (a -> b -> c) -> Sh a -> Sh b -> Sh c
    <*> :: Sh (a -> b) -> Sh a -> Sh b
    $c<*> :: forall a b. Sh (a -> b) -> Sh a -> Sh b
    pure :: a -> Sh a
    $cpure :: forall a. a -> Sh a
    $cp1Applicative :: Functor Sh
    Applicative, Applicative Sh
    a -> Sh a
    Applicative Sh =>
    (forall a b. Sh a -> (a -> Sh b) -> Sh b)
    -> (forall a b. Sh a -> Sh b -> Sh b)
    -> (forall a. a -> Sh a)
    -> Monad Sh
    Sh a -> (a -> Sh b) -> Sh b
    Sh a -> Sh b -> Sh b
    forall a. a -> Sh a
    forall a b. Sh a -> Sh b -> Sh b
    forall a b. Sh a -> (a -> Sh b) -> Sh b
    forall (m :: * -> *).
    Applicative m =>
    (forall a b. m a -> (a -> m b) -> m b)
    -> (forall a b. m a -> m b -> m b)
    -> (forall a. a -> m a)
    -> Monad m
    return :: a -> Sh a
    $creturn :: forall a. a -> Sh a
    >> :: Sh a -> Sh b -> Sh b
    $c>> :: forall a b. Sh a -> Sh b -> Sh b
    >>= :: Sh a -> (a -> Sh b) -> Sh b
    $c>>= :: forall a b. Sh a -> (a -> Sh b) -> Sh b
    $cp1Monad :: Applicative Sh
    Monad, Monad Sh
    Monad Sh => (forall a. String -> Sh a) -> MonadFail Sh
    String -> Sh a
    forall a. String -> Sh a
    forall (m :: * -> *).
    Monad m =>
    (forall a. String -> m a) -> MonadFail m
    fail :: String -> Sh a
    $cfail :: forall a. String -> Sh a
    $cp1MonadFail :: Monad Sh
    MonadFail, Monad Sh
    Monad Sh => (forall a. IO a -> Sh a) -> MonadIO Sh
    IO a -> Sh a
    forall a. IO a -> Sh a
    forall (m :: * -> *).
    Monad m =>
    (forall a. IO a -> m a) -> MonadIO m
    liftIO :: IO a -> Sh a
    $cliftIO :: forall a. IO a -> Sh a
    $cp1MonadIO :: Monad Sh
    MonadIO, MonadReader (IORef State), a -> Sh b -> Sh a
    (a -> b) -> Sh a -> Sh b
    (forall a b. (a -> b) -> Sh a -> Sh b)
    -> (forall a b. a -> Sh b -> Sh a) -> Functor Sh
    forall a b. a -> Sh b -> Sh a
    forall a b. (a -> b) -> Sh a -> Sh b
    forall (f :: * -> *).
    (forall a b. (a -> b) -> f a -> f b)
    -> (forall a b. a -> f b -> f a) -> Functor f
    <$ :: a -> Sh b -> Sh a
    $c<$ :: forall a b. a -> Sh b -> Sh a
    fmap :: (a -> b) -> Sh a -> Sh b
    $cfmap :: forall a b. (a -> b) -> Sh a -> Sh b
    Functor, MonadCatch Sh
    MonadCatch Sh =>
    (forall b. ((forall a. Sh a -> Sh a) -> Sh b) -> Sh b)
    -> (forall b. ((forall a. Sh a -> Sh a) -> Sh b) -> Sh b)
    -> (forall a b c.
        Sh a -> (a -> ExitCase b -> Sh c) -> (a -> Sh b) -> Sh (b, c))
    -> MonadMask Sh
    Sh a -> (a -> ExitCase b -> Sh c) -> (a -> Sh b) -> Sh (b, c)
    ((forall a. Sh a -> Sh a) -> Sh b) -> Sh b
    ((forall a. Sh a -> Sh a) -> Sh b) -> Sh b
    forall b. ((forall a. Sh a -> Sh a) -> Sh b) -> Sh b
    forall a b c.
    Sh a -> (a -> ExitCase b -> Sh c) -> (a -> Sh b) -> Sh (b, c)
    forall (m :: * -> *).
    MonadCatch m =>
    (forall b. ((forall a. m a -> m a) -> m b) -> m b)
    -> (forall b. ((forall a. m a -> m a) -> m b) -> m b)
    -> (forall a b c.
        m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c))
    -> MonadMask m
    generalBracket :: Sh a -> (a -> ExitCase b -> Sh c) -> (a -> Sh b) -> Sh (b, c)
    $cgeneralBracket :: forall a b c.
    Sh a -> (a -> ExitCase b -> Sh c) -> (a -> Sh b) -> Sh (b, c)
    uninterruptibleMask :: ((forall a. Sh a -> Sh a) -> Sh b) -> Sh b
    $cuninterruptibleMask :: forall b. ((forall a. Sh a -> Sh a) -> Sh b) -> Sh b
    mask :: ((forall a. Sh a -> Sh a) -> Sh b) -> Sh b
    $cmask :: forall b. ((forall a. Sh a -> Sh a) -> Sh b) -> Sh b
    $cp1MonadMask :: MonadCatch Sh
    Catch.MonadMask)

    instance MonadBase IO Sh where
        liftBase :: IO α -> Sh α
    liftBase = ReaderT (IORef State) IO α -> Sh α
    forall a. ReaderT (IORef State) IO a -> Sh a
    Sh (ReaderT (IORef State) IO α -> Sh α)
    -> (IO α -> ReaderT (IORef State) IO α) -> IO α -> Sh α
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (IORef State -> IO α) -> ReaderT (IORef State) IO α
    forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
    ReaderT ((IORef State -> IO α) -> ReaderT (IORef State) IO α)
    -> (IO α -> IORef State -> IO α)
    -> IO α
    -> ReaderT (IORef State) IO α
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . IO α -> IORef State -> IO α
    forall a b. a -> b -> a
    const

    instance MonadBaseControl IO Sh where
    #if MIN_VERSION_monad_control(1,0,0)
        type StM Sh a = StM (ReaderT (IORef State) IO) a
        liftBaseWith :: (RunInBase Sh IO -> IO a) -> Sh a
    liftBaseWith f :: RunInBase Sh IO -> IO a
    f =
            ReaderT (IORef State) IO a -> Sh a
    forall a. ReaderT (IORef State) IO a -> Sh a
    Sh (ReaderT (IORef State) IO a -> Sh a)
    -> ReaderT (IORef State) IO a -> Sh a
    forall a b. (a -> b) -> a -> b
    $ (RunInBase (ReaderT (IORef State) IO) IO -> IO a)
    -> ReaderT (IORef State) IO a
    forall (b :: * -> *) (m :: * -> *) a.
    MonadBaseControl b m =>
    (RunInBase m b -> b a) -> m a
    liftBaseWith ((RunInBase (ReaderT (IORef State) IO) IO -> IO a)
     -> ReaderT (IORef State) IO a)
    -> (RunInBase (ReaderT (IORef State) IO) IO -> IO a)
    -> ReaderT (IORef State) IO a
    forall a b. (a -> b) -> a -> b
    $ \runInBase :: RunInBase (ReaderT (IORef State) IO) IO
    runInBase -> RunInBase Sh IO -> IO a
    f (RunInBase Sh IO -> IO a) -> RunInBase Sh IO -> IO a
    forall a b. (a -> b) -> a -> b
    $ \k :: Sh a
    k ->
                ReaderT (IORef State) IO a -> IO (StM Sh a)
    RunInBase (ReaderT (IORef State) IO) IO
    runInBase (ReaderT (IORef State) IO a -> IO (StM Sh a))
    -> ReaderT (IORef State) IO a -> IO (StM Sh a)
    forall a b. (a -> b) -> a -> b
    $ Sh a -> ReaderT (IORef State) IO a
    forall a. Sh a -> ReaderT (IORef State) IO a
    unSh Sh a
    k
        restoreM :: StM Sh a -> Sh a
    restoreM = ReaderT (IORef State) IO a -> Sh a
    forall a. ReaderT (IORef State) IO a -> Sh a
    Sh (ReaderT (IORef State) IO a -> Sh a)
    -> (a -> ReaderT (IORef State) IO a) -> a -> Sh a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> ReaderT (IORef State) IO a
    forall (b :: * -> *) (m :: * -> *) a.
    MonadBaseControl b m =>
    StM m a -> m a
    restoreM
    #else
        newtype StM Sh a = StMSh (StM (ReaderT (IORef State) IO) a)
        liftBaseWith f =
            Sh $ liftBaseWith $ \runInBase -> f $ \k ->
                liftM StMSh $ runInBase $ unSh k
        restoreM (StMSh m) = Sh . restoreM $ m
    #endif

    instance Catch.MonadThrow Sh where
      throwM :: e -> Sh a
    throwM = IO a -> Sh a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO a -> Sh a) -> (e -> IO a) -> e -> Sh a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . e -> IO a
    forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
    Catch.throwM

    instance Catch.MonadCatch Sh where
      catch :: Sh a -> (e -> Sh a) -> Sh a
    catch (Sh (ReaderT m :: IORef State -> IO a
    m)) c :: e -> Sh a
    c =
          ReaderT (IORef State) IO a -> Sh a
    forall a. ReaderT (IORef State) IO a -> Sh a
    Sh (ReaderT (IORef State) IO a -> Sh a)
    -> ReaderT (IORef State) IO a -> Sh a
    forall a b. (a -> b) -> a -> b
    $ (IORef State -> IO a) -> ReaderT (IORef State) IO a
    forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
    ReaderT ((IORef State -> IO a) -> ReaderT (IORef State) IO a)
    -> (IORef State -> IO a) -> ReaderT (IORef State) IO a
    forall a b. (a -> b) -> a -> b
    $ \r :: IORef State
    r -> IORef State -> IO a
    m IORef State
    r IO a -> (e -> IO a) -> IO a
    forall (m :: * -> *) e a.
    (MonadCatch m, Exception e) =>
    m a -> (e -> m a) -> m a
    `Catch.catch` \e :: e
    e -> Sh a -> IORef State -> IO a
    forall a. Sh a -> IORef State -> IO a
    runSh (e -> Sh a
    c e
    e) IORef State
    r

    runSh :: Sh a -> IORef State -> IO a
    runSh :: Sh a -> IORef State -> IO a
    runSh = ReaderT (IORef State) IO a -> IORef State -> IO a
    forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
    runReaderT (ReaderT (IORef State) IO a -> IORef State -> IO a)
    -> (Sh a -> ReaderT (IORef State) IO a)
    -> Sh a
    -> IORef State
    -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Sh a -> ReaderT (IORef State) IO a
    forall a. Sh a -> ReaderT (IORef State) IO a
    unSh

    data ReadOnlyState = ReadOnlyState { ReadOnlyState -> Bool
    rosFailToDir :: Bool }
    data State = State
       { State -> Int
    sCode :: Int -- ^ exit code for command that ran
       , State -> Maybe Text
    sStdin :: Maybe Text -- ^ stdin for the command to be run
       , State -> Text
    sStderr :: Text -- ^ stderr for command that ran
       , State -> String
    sDirectory :: FilePath -- ^ working directory
       , State -> Text -> IO ()
    sPutStdout :: Text -> IO ()   -- ^ by default, hPutStrLn stdout
       , State -> Bool
    sPrintStdout :: Bool   -- ^ print stdout of command that is executed
       , State -> Text -> IO ()
    sPutStderr :: Text -> IO ()   -- ^ by default, hPutStrLn stderr
       , State -> Bool
    sPrintStderr :: Bool   -- ^ print stderr of command that is executed
       , State -> Bool
    sPrintCommands :: Bool -- ^ print command that is executed
       , State -> StdInit
    sInitCommandHandles :: StdInit -- ^ initializers for the standard process handles
                                        -- when running a command
       , State -> Bool
    sCommandEscaping :: Bool -- ^ when running a command, escape shell characters such as '*' rather
                                  -- than passing to the shell for expansion
       , State -> [(String, String)]
    sEnvironment :: [(String, String)]
       , State -> Maybe [(String, Set String)]
    sPathExecutables :: Maybe [(FilePath, S.Set FilePath)] -- ^ cache of executables in the PATH
       , State -> Bool
    sTracing :: Bool -- ^ should we trace command execution
       , State -> Text
    sTrace :: Text -- ^ the trace of command execution
       , State -> Bool
    sErrExit :: Bool -- ^ should we exit immediately on any error
       , State -> ReadOnlyState
    sReadOnly :: ReadOnlyState
       , State -> Bool
    sFollowSymlink :: Bool -- ^ 'find'-command follows symlinks.
       }

    data StdHandle = InHandle StdStream
                   | OutHandle StdStream
                   | ErrorHandle StdStream

    -- | Initialize a handle before using it
    type HandleInitializer = Handle -> IO ()

    -- | A collection of initializers for the three standard process handles
    data StdInit =
        StdInit {
          StdInit -> HandleInitializer
    inInit :: HandleInitializer,
          StdInit -> HandleInitializer
    outInit :: HandleInitializer,
          StdInit -> HandleInitializer
    errInit :: HandleInitializer
        }

    -- | A monadic-conditional version of the "when" guard.
    whenM :: Monad m => m Bool -> m () -> m ()
    whenM :: m Bool -> m () -> m ()
    whenM c :: m Bool
    c a :: m ()
    a = m Bool
    c m Bool -> (Bool -> m ()) -> m ()
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \res :: Bool
    res -> Bool -> m () -> m ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when Bool
    res m ()
    a

    -- | Makes a relative path relative to the current Sh working directory.
    -- An absolute path is returned as is.
    -- To create an absolute path, use 'absPath'
    relPath :: FilePath -> Sh FilePath
    relPath :: String -> Sh String
    relPath fp :: String
    fp = do
      String
    wd  <- (State -> String) -> Sh String
    forall a. (State -> a) -> Sh a
    gets State -> String
    sDirectory
      Either String String
    rel <- String -> String -> Sh (Either String String)
    eitherRelativeTo String
    wd String
    fp
      String -> Sh String
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> Sh String) -> String -> Sh String
    forall a b. (a -> b) -> a -> b
    $ case Either String String
    rel of
        Right p :: String
    p -> String
    p
        Left  p :: String
    p -> String
    p

    eitherRelativeTo :: FilePath -- ^ anchor path, the prefix
                     -> FilePath -- ^ make this relative to anchor path
                     -> Sh (Either FilePath FilePath) -- ^ Left is canonic of second path
    eitherRelativeTo :: String -> String -> Sh (Either String String)
    eitherRelativeTo relativeFP :: String
    relativeFP fp :: String
    fp = do
      let fullFp :: String
    fullFp = String
    relativeFP String -> String -> String
    FP.</> String
    fp
      let relDir :: String
    relDir = String -> String
    addTrailingSlash String
    relativeFP
      String
    -> String -> Sh (Either String String) -> Sh (Either String String)
    stripIt String
    relativeFP String
    fp (Sh (Either String String) -> Sh (Either String String))
    -> Sh (Either String String) -> Sh (Either String String)
    forall a b. (a -> b) -> a -> b
    $
        String
    -> String -> Sh (Either String String) -> Sh (Either String String)
    stripIt String
    relativeFP String
    fullFp (Sh (Either String String) -> Sh (Either String String))
    -> Sh (Either String String) -> Sh (Either String String)
    forall a b. (a -> b) -> a -> b
    $
          String
    -> String -> Sh (Either String String) -> Sh (Either String String)
    stripIt String
    relDir String
    fp (Sh (Either String String) -> Sh (Either String String))
    -> Sh (Either String String) -> Sh (Either String String)
    forall a b. (a -> b) -> a -> b
    $
            String
    -> String -> Sh (Either String String) -> Sh (Either String String)
    stripIt String
    relDir String
    fullFp (Sh (Either String String) -> Sh (Either String String))
    -> Sh (Either String String) -> Sh (Either String String)
    forall a b. (a -> b) -> a -> b
    $ do
              String
    relCan <- String -> Sh String
    canonic String
    relDir
              String
    fpCan  <- String -> Sh String
    canonic String
    fullFp
              String
    -> String -> Sh (Either String String) -> Sh (Either String String)
    stripIt String
    relCan String
    fpCan (Sh (Either String String) -> Sh (Either String String))
    -> Sh (Either String String) -> Sh (Either String String)
    forall a b. (a -> b) -> a -> b
    $ Either String String -> Sh (Either String String)
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Either String String -> Sh (Either String String))
    -> Either String String -> Sh (Either String String)
    forall a b. (a -> b) -> a -> b
    $ String -> Either String String
    forall a b. a -> Either a b
    Left String
    fpCan
      where
        stripIt
          :: FilePath
          -> FilePath
          -> Sh (Either FilePath FilePath)
          -> Sh (Either FilePath FilePath)
        stripIt :: String
    -> String -> Sh (Either String String) -> Sh (Either String String)
    stripIt rel :: String
    rel toStrip :: String
    toStrip nada :: Sh (Either String String)
    nada =
          let stripped :: String
    stripped = String -> String -> String
    FP.makeRelative String
    rel String
    toStrip
          in if String
    stripped String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == String
    toStrip
            then Sh (Either String String)
    nada
            else Either String String -> Sh (Either String String)
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Either String String -> Sh (Either String String))
    -> Either String String -> Sh (Either String String)
    forall a b. (a -> b) -> a -> b
    $ String -> Either String String
    forall a b. b -> Either a b
    Right String
    stripped

    -- | make the second path relative to the first
    -- Uses 'Filesystem.stripPrefix', but will canonicalize the paths if necessary
    relativeTo :: FilePath -- ^ anchor path, the prefix
               -> FilePath -- ^ make this relative to anchor path
               -> Sh FilePath
    relativeTo :: String -> String -> Sh String
    relativeTo relativeFP :: String
    relativeFP fp :: String
    fp =
      (Maybe String -> String) -> Sh (Maybe String) -> Sh String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (String -> Maybe String -> String
    forall a. a -> Maybe a -> a
    fromMaybe String
    fp) (Sh (Maybe String) -> Sh String) -> Sh (Maybe String) -> Sh String
    forall a b. (a -> b) -> a -> b
    $ String -> String -> Sh (Maybe String)
    maybeRelativeTo String
    relativeFP String
    fp

    maybeRelativeTo :: FilePath -- ^ anchor path, the prefix
                     -> FilePath -- ^ make this relative to anchor path
                     -> Sh (Maybe FilePath)
    maybeRelativeTo :: String -> String -> Sh (Maybe String)
    maybeRelativeTo relativeFP :: String
    relativeFP fp :: String
    fp = do
      Either String String
    epath <- String -> String -> Sh (Either String String)
    eitherRelativeTo String
    relativeFP String
    fp
      Maybe String -> Sh (Maybe String)
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe String -> Sh (Maybe String))
    -> Maybe String -> Sh (Maybe String)
    forall a b. (a -> b) -> a -> b
    $ case Either String String
    epath of
                 Right p :: String
    p -> String -> Maybe String
    forall a. a -> Maybe a
    Just String
    p
                 Left _ -> Maybe String
    forall a. Maybe a
    Nothing

    -- | add a trailing slash to ensure the path indicates a directory
    addTrailingSlash :: FilePath -> FilePath
    addTrailingSlash :: String -> String
    addTrailingSlash = String -> String
    FP.addTrailingPathSeparator

    -- | makes an absolute path.
    -- Like 'canonicalize', but on an exception returns 'absPath'
    canonic :: FilePath -> Sh FilePath
    canonic :: String -> Sh String
    canonic fp :: String
    fp = do
      String
    p <- String -> Sh String
    absPath String
    fp
      IO String -> Sh String
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO String -> Sh String) -> IO String -> Sh String
    forall a b. (a -> b) -> a -> b
    $ String -> IO String
    canonicalizePath String
    p IO String -> (SomeException -> IO String) -> IO String
    forall a. IO a -> (SomeException -> IO a) -> IO a
    `catchany` \_ -> String -> IO String
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    p

    -- | Obtain a (reasonably) canonic file path to a filesystem object. Based on
    -- "canonicalizePath" in system-fileio.
    canonicalize :: FilePath -> Sh FilePath
    canonicalize :: String -> Sh String
    canonicalize = String -> Sh String
    absPath (String -> Sh String)
    -> (String -> Sh String) -> String -> Sh String
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> IO String -> Sh String
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO String -> Sh String)
    -> (String -> IO String) -> String -> Sh String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> IO String
    canonicalizePath

    -- | bugfix older version of canonicalizePath (system-fileio <= 0.3.7) loses trailing slash
    canonicalizePath :: FilePath -> IO FilePath
    canonicalizePath :: String -> IO String
    canonicalizePath p :: String
    p = let was_dir :: Bool
    was_dir = String -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null (String -> String
    FP.takeFileName String
    p) in
       if Bool -> Bool
    not Bool
    was_dir then String -> IO String
    FS.canonicalizePath String
    p
         else String -> String
    addTrailingSlash (String -> String) -> IO String -> IO String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` String -> IO String
    FS.canonicalizePath String
    p

    data EmptyFilePathError = EmptyFilePathError deriving Typeable
    instance Show EmptyFilePathError where
        show :: EmptyFilePathError -> String
    show _ = "Empty filepath"
    instance Exception EmptyFilePathError

    -- | Make a relative path absolute by combining with the working directory.
    -- An absolute path is returned as is.
    -- To create a relative path, use 'relPath'.
    absPath :: FilePath -> Sh FilePath
    absPath :: String -> Sh String
    absPath p :: String
    p | String -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    p = IO String -> Sh String
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO String -> Sh String) -> IO String -> Sh String
    forall a b. (a -> b) -> a -> b
    $ EmptyFilePathError -> IO String
    forall e a. Exception e => e -> IO a
    throwIO EmptyFilePathError
    EmptyFilePathError
              | String -> Bool
    isRelative String
    p = do
                String
    cwd <-  (State -> String) -> Sh String
    forall a. (State -> a) -> Sh a
    gets State -> String
    sDirectory
                String -> Sh String
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String
    cwd String -> String -> String
    FP.</> String
    p)
              | Bool
    otherwise = String -> Sh String
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    p

    -- | deprecated
    path :: FilePath -> Sh FilePath
    path :: String -> Sh String
    path = String -> Sh String
    absPath
    {-# DEPRECATED path "use absPath, canonic, or relPath instead" #-}

    -- | Does a path point to an existing directory?
    test_d :: FilePath -> Sh Bool
    test_d :: String -> Sh Bool
    test_d = String -> Sh String
    absPath (String -> Sh String) -> (String -> Sh Bool) -> String -> Sh Bool
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> IO Bool -> Sh Bool
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO Bool -> Sh Bool) -> (String -> IO Bool) -> String -> Sh Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> IO Bool
    doesDirectoryExist

    -- | Does a path point to a symlink?
    test_s :: FilePath -> Sh Bool
    test_s :: String -> Sh Bool
    test_s = String -> Sh String
    absPath (String -> Sh String) -> (String -> Sh Bool) -> String -> Sh Bool
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> IO Bool -> Sh Bool
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO Bool -> Sh Bool) -> (String -> IO Bool) -> String -> Sh Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . \f :: String
    f -> do
      FileStatus
    stat <- String -> IO FileStatus
    getSymbolicLinkStatus String
    f
      Bool -> IO Bool
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Bool -> IO Bool) -> Bool -> IO Bool
    forall a b. (a -> b) -> a -> b
    $ FileStatus -> Bool
    isSymbolicLink FileStatus
    stat

    unpack :: FilePath -> String
    unpack :: String -> String
    unpack = String -> String
    forall a. a -> a
    id

    gets :: (State -> a) -> Sh a
    gets :: (State -> a) -> Sh a
    gets f :: State -> a
    f = State -> a
    f (State -> a) -> Sh State -> Sh a
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Sh State
    get

    get :: Sh State
    get :: Sh State
    get = do
      IORef State
    stateVar <- Sh (IORef State)
    forall r (m :: * -> *). MonadReader r m => m r
    ask
      IO State -> Sh State
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IORef State -> IO State
    forall a. IORef a -> IO a
    readIORef IORef State
    stateVar)

    modify :: (State -> State) -> Sh ()
    modify :: (State -> State) -> Sh ()
    modify f :: State -> State
    f = do
      IORef State
    state <- Sh (IORef State)
    forall r (m :: * -> *). MonadReader r m => m r
    ask
      IO () -> Sh ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IORef State -> (State -> State) -> IO ()
    forall a. IORef a -> (a -> a) -> IO ()
    modifyIORef IORef State
    state State -> State
    f)

    -- | internally log what occurred.
    -- Log will be re-played on failure.
    trace :: Text -> Sh ()
    trace :: Text -> Sh ()
    trace msg :: Text
    msg =
      Sh Bool -> Sh () -> Sh ()
    forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
    whenM ((State -> Bool) -> Sh Bool
    forall a. (State -> a) -> Sh a
    gets State -> Bool
    sTracing) (Sh () -> Sh ()) -> Sh () -> Sh ()
    forall a b. (a -> b) -> a -> b
    $ (State -> State) -> Sh ()
    modify ((State -> State) -> Sh ()) -> (State -> State) -> Sh ()
    forall a b. (a -> b) -> a -> b
    $
        \st :: State
    st -> State
    st { sTrace :: Text
    sTrace = State -> Text
    sTrace State
    st Text -> Text -> Text
    forall a. Monoid a => a -> a -> a
    `mappend` Text
    msg Text -> Text -> Text
    forall a. Monoid a => a -> a -> a
    `mappend` "\n" }

    -- | List directory contents. Does *not* include \".\" and \"..\", but it does
    -- include (other) hidden files.
    ls :: FilePath -> Sh [FilePath]
    -- it is important to use path and not absPath so that the listing can remain relative
    ls :: String -> Sh [String]
    ls fp :: String
    fp = do
      Text -> Sh ()
    trace (Text -> Sh ()) -> Text -> Sh ()
    forall a b. (a -> b) -> a -> b
    $ "ls " Text -> Text -> Text
    forall a. Monoid a => a -> a -> a
    `mappend` String -> Text
    toTextIgnore String
    fp
      (([String], [String]) -> [String])
    -> Sh ([String], [String]) -> Sh [String]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ([String], [String]) -> [String]
    forall a b. (a, b) -> a
    fst (Sh ([String], [String]) -> Sh [String])
    -> Sh ([String], [String]) -> Sh [String]
    forall a b. (a -> b) -> a -> b
    $ String -> Sh ([String], [String])
    lsRelAbs String
    fp

    lsRelAbs :: FilePath -> Sh ([FilePath], [FilePath])
    lsRelAbs :: String -> Sh ([String], [String])
    lsRelAbs f :: String
    f = String -> Sh String
    absPath String
    f Sh String
    -> (String -> Sh ([String], [String])) -> Sh ([String], [String])
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \fp :: String
    fp -> do
      [String]
    files <- IO [String] -> Sh [String]
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO [String] -> Sh [String]) -> IO [String] -> Sh [String]
    forall a b. (a -> b) -> a -> b
    $ String -> IO [String]
    listDirectory String
    fp
      let absolute :: [String]
    absolute = (String -> String) -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (String
    fp String -> String -> String
    FP.</>) [String]
    files
      let relativized :: [String]
    relativized = (String -> String) -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (\p :: String
    p -> [String] -> String
    FP.joinPath [String
    f, String
    p]) [String]
    files
      ([String], [String]) -> Sh ([String], [String])
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([String]
    relativized, [String]
    absolute)

    -- | silently uses the Right or Left value of "Filesystem.Path.CurrentOS.toText"
    toTextIgnore :: FilePath -> Text
    toTextIgnore :: String -> Text
    toTextIgnore = String -> Text
    T.pack

    -- | a print lifted into 'Sh'
    inspect :: (Show s) => s -> Sh ()
    inspect :: s -> Sh ()
    inspect x :: s
    x = do
      (Text -> Sh ()
    trace (Text -> Sh ()) -> (s -> Text) -> s -> Sh ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Text
    T.pack (String -> Text) -> (s -> String) -> s -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . s -> String
    forall a. Show a => a -> String
    show) s
    x
      IO () -> Sh ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> Sh ()) -> IO () -> Sh ()
    forall a b. (a -> b) -> a -> b
    $ s -> IO ()
    forall a. Show a => a -> IO ()
    print s
    x

    -- | a print lifted into 'Sh' using stderr
    inspect_err :: (Show s) => s -> Sh ()
    inspect_err :: s -> Sh ()
    inspect_err x :: s
    x = do
      let shown :: Text
    shown = String -> Text
    T.pack (String -> Text) -> String -> Text
    forall a b. (a -> b) -> a -> b
    $ s -> String
    forall a. Show a => a -> String
    show s
    x
      Text -> Sh ()
    trace Text
    shown
      Text -> Sh ()
    echo_err Text
    shown

    -- | Echo text to standard (error, when using _err variants) output. The _n
    -- variants do not print a final newline.
    echo, echo_n, echo_err, echo_n_err :: Text -> Sh ()
    echo :: Text -> Sh ()
    echo       msg :: Text
    msg = Text -> Sh ()
    traceEcho Text
    msg Sh () -> Sh () -> Sh ()
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> IO () -> Sh ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (Text -> IO ()
    TIO.putStrLn Text
    msg IO () -> IO () -> IO ()
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> HandleInitializer
    hFlush Handle
    stdout)
    echo_n :: Text -> Sh ()
    echo_n     msg :: Text
    msg = Text -> Sh ()
    traceEcho Text
    msg Sh () -> Sh () -> Sh ()
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> IO () -> Sh ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (Text -> IO ()
    TIO.putStr Text
    msg IO () -> IO () -> IO ()
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> HandleInitializer
    hFlush Handle
    stdout)
    echo_err :: Text -> Sh ()
    echo_err   msg :: Text
    msg = Text -> Sh ()
    traceEcho Text
    msg Sh () -> Sh () -> Sh ()
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> IO () -> Sh ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (Handle -> Text -> IO ()
    TIO.hPutStrLn Handle
    stderr Text
    msg IO () -> IO () -> IO ()
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> HandleInitializer
    hFlush Handle
    stdout)
    echo_n_err :: Text -> Sh ()
    echo_n_err msg :: Text
    msg = Text -> Sh ()
    traceEcho Text
    msg Sh () -> Sh () -> Sh ()
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> IO () -> Sh ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (Handle -> Text -> IO ()
    TIO.hPutStr Handle
    stderr Text
    msg IO () -> IO () -> IO ()
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> HandleInitializer
    hFlush Handle
    stderr)

    traceEcho :: Text -> Sh ()
    traceEcho :: Text -> Sh ()
    traceEcho msg :: Text
    msg = Text -> Sh ()
    trace ("echo " Text -> Text -> Text
    forall a. Monoid a => a -> a -> a
    `mappend` "'" Text -> Text -> Text
    forall a. Monoid a => a -> a -> a
    `mappend` Text
    msg Text -> Text -> Text
    forall a. Monoid a => a -> a -> a
    `mappend` "'")

    -- | A helper to catch any exception (same as
    -- @... `catch` \(e :: SomeException) -> ...@).
    catchany :: IO a -> (SomeException -> IO a) -> IO a
    catchany :: IO a -> (SomeException -> IO a) -> IO a
    catchany = IO a -> (SomeException -> IO a) -> IO a
    forall e a. Exception e => IO a -> (e -> IO a) -> IO a
    catch