{-|
Description : Common Types
Copyright   : Profpatsch, 2018–2021
License     : GPL-3
Stability   : experimental
-}
{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveFunctor #-}
module Foreign.Nix.Shellout.Types (
  -- * Store paths
  StorePath(..),
  Derivation,
  Realized,
  -- * NixAction
  runNixAction,
  NixAction(..),
  RunOptions(..),
  defaultRunOptions,
  LogFn(..),
  Executables(..),
  defaultExecutables,
  NixActionError(..),
  mapActionError,

) where

import Control.Error ( bimapExceptT, runExceptT, ExceptT )
import Control.Monad.IO.Class (MonadIO)
import Control.Monad.Reader (ReaderT (runReaderT, ReaderT), MonadReader )
import Data.Text (Text)
import Control.Monad.Trans ( lift, MonadTrans )
import Control.Monad.Except (MonadError)

-- | Options that modify how a 'NixAction' executes.
--
-- Might get more fields in the future, use 'defaultRunOptions'
-- to be backwards-compatbile.
data RunOptions m = RunOptions {
  RunOptions m -> LogFn m
logFn :: LogFn m,
  -- ^ The command line logging function.
  RunOptions m -> Executables
executables :: Executables
  -- ^ A record of all executables this library could need.
}

-- | Logging function to call before running a command.
-- This can be used to provide debugging output.
--
-- The first argument is the executable name,
-- the second argument is the list of arguments.
newtype LogFn m = LogFn (Text -> [Text] -> m ())

-- | All executables this library might need.
--
-- If you set an executable to @Just filepath@, the internal code will use the given path instead of looking up the executable name in @PATH@.
-- This is useful if you want to ensure that the executables always exist before calling into this library.
--
-- 'NixAction' functions document the executables they use in their docstrings.
--
-- If an executable can’t be found, an 'IOException' is thrown (by the process spawn function).
data Executables = Executables {
  Executables -> Maybe FilePath
exeNixInstantiate :: Maybe FilePath,
  -- ^ @nix-instantiate@; usually you can expect nix to exist on the system (but we don’t check before running the commands)
  Executables -> Maybe FilePath
exeNixStore :: Maybe FilePath,
  -- ^ @nix-store@
  Executables -> Maybe FilePath
exeNixPrefetchUrl :: Maybe FilePath,
  -- ^ @nix-prefetch-url@; as of nix @2.3@, this executable comes with the nix distribution, so if @nix-store@ is available, this should also be available
  Executables -> Maybe FilePath
exeNixPrefetchGit :: Maybe FilePath
  -- ^ @nix-prefetch-git@; This is usually provided by the @nix-prefetch-scripts@ package and /not/ installed with nix
 }

-- |  all executables are taken from @PATH@
defaultExecutables :: Executables
defaultExecutables :: Executables
defaultExecutables = Executables :: Maybe FilePath
-> Maybe FilePath
-> Maybe FilePath
-> Maybe FilePath
-> Executables
Executables {
    exeNixInstantiate :: Maybe FilePath
exeNixInstantiate = Maybe FilePath
forall a. Maybe a
Nothing,
    exeNixStore :: Maybe FilePath
exeNixStore = Maybe FilePath
forall a. Maybe a
Nothing,
    exeNixPrefetchUrl :: Maybe FilePath
exeNixPrefetchUrl = Maybe FilePath
forall a. Maybe a
Nothing,
    exeNixPrefetchGit :: Maybe FilePath
exeNixPrefetchGit = Maybe FilePath
forall a. Maybe a
Nothing
  }

-- |
-- @
-- logFn = nothing is done/logged
-- executable = all executables are taken from @PATH@
-- @
defaultRunOptions :: Monad m => RunOptions m
defaultRunOptions :: RunOptions m
defaultRunOptions = RunOptions :: forall (m :: * -> *). LogFn m -> Executables -> RunOptions m
RunOptions {
  logFn :: LogFn m
logFn = (Text -> [Text] -> m ()) -> LogFn m
forall (m :: * -> *). (Text -> [Text] -> m ()) -> LogFn m
LogFn (\Text
_prog [Text]
_args -> () -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()),
  executables :: Executables
executables = Executables
defaultExecutables
}

-- | Calls a command that returns an error and the whole stderr on failure.
newtype NixAction e m a = NixAction
  { NixAction e m a
-> ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a
unNixAction :: ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a }
  deriving (a -> NixAction e m b -> NixAction e m a
(a -> b) -> NixAction e m a -> NixAction e m b
(forall a b. (a -> b) -> NixAction e m a -> NixAction e m b)
-> (forall a b. a -> NixAction e m b -> NixAction e m a)
-> Functor (NixAction e m)
forall a b. a -> NixAction e m b -> NixAction e m a
forall a b. (a -> b) -> NixAction e m a -> NixAction e m b
forall e (m :: * -> *) a b.
Functor m =>
a -> NixAction e m b -> NixAction e m a
forall e (m :: * -> *) a b.
Functor m =>
(a -> b) -> NixAction e m a -> NixAction e m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> NixAction e m b -> NixAction e m a
$c<$ :: forall e (m :: * -> *) a b.
Functor m =>
a -> NixAction e m b -> NixAction e m a
fmap :: (a -> b) -> NixAction e m a -> NixAction e m b
$cfmap :: forall e (m :: * -> *) a b.
Functor m =>
(a -> b) -> NixAction e m a -> NixAction e m b
Functor, Functor (NixAction e m)
a -> NixAction e m a
Functor (NixAction e m)
-> (forall a. a -> NixAction e m a)
-> (forall a b.
    NixAction e m (a -> b) -> NixAction e m a -> NixAction e m b)
-> (forall a b c.
    (a -> b -> c)
    -> NixAction e m a -> NixAction e m b -> NixAction e m c)
-> (forall a b.
    NixAction e m a -> NixAction e m b -> NixAction e m b)
-> (forall a b.
    NixAction e m a -> NixAction e m b -> NixAction e m a)
-> Applicative (NixAction e m)
NixAction e m a -> NixAction e m b -> NixAction e m b
NixAction e m a -> NixAction e m b -> NixAction e m a
NixAction e m (a -> b) -> NixAction e m a -> NixAction e m b
(a -> b -> c)
-> NixAction e m a -> NixAction e m b -> NixAction e m c
forall a. a -> NixAction e m a
forall a b. NixAction e m a -> NixAction e m b -> NixAction e m a
forall a b. NixAction e m a -> NixAction e m b -> NixAction e m b
forall a b.
NixAction e m (a -> b) -> NixAction e m a -> NixAction e m b
forall a b c.
(a -> b -> c)
-> NixAction e m a -> NixAction e m b -> NixAction e m c
forall e (m :: * -> *). Monad m => Functor (NixAction e m)
forall e (m :: * -> *) a. Monad m => a -> NixAction e m a
forall e (m :: * -> *) a b.
Monad m =>
NixAction e m a -> NixAction e m b -> NixAction e m a
forall e (m :: * -> *) a b.
Monad m =>
NixAction e m a -> NixAction e m b -> NixAction e m b
forall e (m :: * -> *) a b.
Monad m =>
NixAction e m (a -> b) -> NixAction e m a -> NixAction e m b
forall e (m :: * -> *) a b c.
Monad m =>
(a -> b -> c)
-> NixAction e m a -> NixAction e m b -> NixAction e m 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
<* :: NixAction e m a -> NixAction e m b -> NixAction e m a
$c<* :: forall e (m :: * -> *) a b.
Monad m =>
NixAction e m a -> NixAction e m b -> NixAction e m a
*> :: NixAction e m a -> NixAction e m b -> NixAction e m b
$c*> :: forall e (m :: * -> *) a b.
Monad m =>
NixAction e m a -> NixAction e m b -> NixAction e m b
liftA2 :: (a -> b -> c)
-> NixAction e m a -> NixAction e m b -> NixAction e m c
$cliftA2 :: forall e (m :: * -> *) a b c.
Monad m =>
(a -> b -> c)
-> NixAction e m a -> NixAction e m b -> NixAction e m c
<*> :: NixAction e m (a -> b) -> NixAction e m a -> NixAction e m b
$c<*> :: forall e (m :: * -> *) a b.
Monad m =>
NixAction e m (a -> b) -> NixAction e m a -> NixAction e m b
pure :: a -> NixAction e m a
$cpure :: forall e (m :: * -> *) a. Monad m => a -> NixAction e m a
$cp1Applicative :: forall e (m :: * -> *). Monad m => Functor (NixAction e m)
Applicative, Applicative (NixAction e m)
a -> NixAction e m a
Applicative (NixAction e m)
-> (forall a b.
    NixAction e m a -> (a -> NixAction e m b) -> NixAction e m b)
-> (forall a b.
    NixAction e m a -> NixAction e m b -> NixAction e m b)
-> (forall a. a -> NixAction e m a)
-> Monad (NixAction e m)
NixAction e m a -> (a -> NixAction e m b) -> NixAction e m b
NixAction e m a -> NixAction e m b -> NixAction e m b
forall a. a -> NixAction e m a
forall a b. NixAction e m a -> NixAction e m b -> NixAction e m b
forall a b.
NixAction e m a -> (a -> NixAction e m b) -> NixAction e m b
forall e (m :: * -> *). Monad m => Applicative (NixAction e m)
forall e (m :: * -> *) a. Monad m => a -> NixAction e m a
forall e (m :: * -> *) a b.
Monad m =>
NixAction e m a -> NixAction e m b -> NixAction e m b
forall e (m :: * -> *) a b.
Monad m =>
NixAction e m a -> (a -> NixAction e m b) -> NixAction e m 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 -> NixAction e m a
$creturn :: forall e (m :: * -> *) a. Monad m => a -> NixAction e m a
>> :: NixAction e m a -> NixAction e m b -> NixAction e m b
$c>> :: forall e (m :: * -> *) a b.
Monad m =>
NixAction e m a -> NixAction e m b -> NixAction e m b
>>= :: NixAction e m a -> (a -> NixAction e m b) -> NixAction e m b
$c>>= :: forall e (m :: * -> *) a b.
Monad m =>
NixAction e m a -> (a -> NixAction e m b) -> NixAction e m b
$cp1Monad :: forall e (m :: * -> *). Monad m => Applicative (NixAction e m)
Monad, Monad (NixAction e m)
Monad (NixAction e m)
-> (forall a. IO a -> NixAction e m a) -> MonadIO (NixAction e m)
IO a -> NixAction e m a
forall a. IO a -> NixAction e m a
forall e (m :: * -> *). MonadIO m => Monad (NixAction e m)
forall e (m :: * -> *) a. MonadIO m => IO a -> NixAction e m a
forall (m :: * -> *).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
liftIO :: IO a -> NixAction e m a
$cliftIO :: forall e (m :: * -> *) a. MonadIO m => IO a -> NixAction e m a
$cp1MonadIO :: forall e (m :: * -> *). MonadIO m => Monad (NixAction e m)
MonadIO, MonadError (NixActionError e), MonadReader (RunOptions m))

instance MonadTrans (NixAction e) where
  lift :: m a -> NixAction e m a
lift = ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a
-> NixAction e m a
forall e (m :: * -> *) a.
ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a
-> NixAction e m a
NixAction (ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a
 -> NixAction e m a)
-> (m a -> ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a)
-> m a
-> NixAction e m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ExceptT (NixActionError e) m a
-> ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (ExceptT (NixActionError e) m a
 -> ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a)
-> (m a -> ExceptT (NixActionError e) m a)
-> m a
-> ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> ExceptT (NixActionError e) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift

-- | Combines the standard error of running a command with a more semantic
-- error type one should match on first.
data NixActionError e = NixActionError
  { NixActionError e -> Text
actionStderr :: Text
  , NixActionError e -> e
actionError :: e }
  deriving (Int -> NixActionError e -> ShowS
[NixActionError e] -> ShowS
NixActionError e -> FilePath
(Int -> NixActionError e -> ShowS)
-> (NixActionError e -> FilePath)
-> ([NixActionError e] -> ShowS)
-> Show (NixActionError e)
forall e. Show e => Int -> NixActionError e -> ShowS
forall e. Show e => [NixActionError e] -> ShowS
forall e. Show e => NixActionError e -> FilePath
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
showList :: [NixActionError e] -> ShowS
$cshowList :: forall e. Show e => [NixActionError e] -> ShowS
show :: NixActionError e -> FilePath
$cshow :: forall e. Show e => NixActionError e -> FilePath
showsPrec :: Int -> NixActionError e -> ShowS
$cshowsPrec :: forall e. Show e => Int -> NixActionError e -> ShowS
Show, a -> NixActionError b -> NixActionError a
(a -> b) -> NixActionError a -> NixActionError b
(forall a b. (a -> b) -> NixActionError a -> NixActionError b)
-> (forall a b. a -> NixActionError b -> NixActionError a)
-> Functor NixActionError
forall a b. a -> NixActionError b -> NixActionError a
forall a b. (a -> b) -> NixActionError a -> NixActionError b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> NixActionError b -> NixActionError a
$c<$ :: forall a b. a -> NixActionError b -> NixActionError a
fmap :: (a -> b) -> NixActionError a -> NixActionError b
$cfmap :: forall a b. (a -> b) -> NixActionError a -> NixActionError b
Functor)

-- | Run a 'NixAction', given runtime options. See 'defaultRunOptions'.
runNixAction :: RunOptions m
             -> NixAction e m a
             -> m (Either (NixActionError e) a)
runNixAction :: RunOptions m -> NixAction e m a -> m (Either (NixActionError e) a)
runNixAction RunOptions m
runOpts NixAction e m a
act = ExceptT (NixActionError e) m a -> m (Either (NixActionError e) a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT (NixActionError e) m a -> m (Either (NixActionError e) a))
-> ExceptT (NixActionError e) m a
-> m (Either (NixActionError e) a)
forall a b. (a -> b) -> a -> b
$ ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a
-> RunOptions m -> ExceptT (NixActionError e) m a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (NixAction e m a
-> ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a
forall e (m :: * -> *) a.
NixAction e m a
-> ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a
unNixAction NixAction e m a
act) RunOptions m
runOpts

-- | Map over the @e@ in a 'NixActionError'.
mapActionError :: Functor m => (a1 -> e) -> NixAction a1 m a2 -> NixAction e m a2
mapActionError :: (a1 -> e) -> NixAction a1 m a2 -> NixAction e m a2
mapActionError a1 -> e
f (NixAction ReaderT (RunOptions m) (ExceptT (NixActionError a1) m) a2
act) = ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a2
-> NixAction e m a2
forall e (m :: * -> *) a.
ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a
-> NixAction e m a
NixAction (ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a2
 -> NixAction e m a2)
-> ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a2
-> NixAction e m a2
forall a b. (a -> b) -> a -> b
$ (RunOptions m -> ExceptT (NixActionError e) m a2)
-> ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a2
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT ((RunOptions m -> ExceptT (NixActionError e) m a2)
 -> ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a2)
-> (RunOptions m -> ExceptT (NixActionError e) m a2)
-> ReaderT (RunOptions m) (ExceptT (NixActionError e) m) a2
forall a b. (a -> b) -> a -> b
$ \RunOptions m
runOpts -> (NixActionError a1 -> NixActionError e)
-> (a2 -> a2)
-> ExceptT (NixActionError a1) m a2
-> ExceptT (NixActionError e) m a2
forall (m :: * -> *) e f a b.
Functor m =>
(e -> f) -> (a -> b) -> ExceptT e m a -> ExceptT f m b
bimapExceptT ((a1 -> e) -> NixActionError a1 -> NixActionError e
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a1 -> e
f) a2 -> a2
forall a. a -> a
id (ExceptT (NixActionError a1) m a2
 -> ExceptT (NixActionError e) m a2)
-> ExceptT (NixActionError a1) m a2
-> ExceptT (NixActionError e) m a2
forall a b. (a -> b) -> a -> b
$ ReaderT (RunOptions m) (ExceptT (NixActionError a1) m) a2
-> RunOptions m -> ExceptT (NixActionError a1) m a2
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT (RunOptions m) (ExceptT (NixActionError a1) m) a2
act RunOptions m
runOpts

-- | A path in the nix store. It carries a phantom @a@ to differentiate
-- between 'Derivation' files and 'Realized' paths.
newtype StorePath a = StorePath
  { StorePath a -> FilePath
unStorePath :: FilePath }
  deriving (StorePath a -> StorePath a -> Bool
(StorePath a -> StorePath a -> Bool)
-> (StorePath a -> StorePath a -> Bool) -> Eq (StorePath a)
forall a. StorePath a -> StorePath a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: StorePath a -> StorePath a -> Bool
$c/= :: forall a. StorePath a -> StorePath a -> Bool
== :: StorePath a -> StorePath a -> Bool
$c== :: forall a. StorePath a -> StorePath a -> Bool
Eq, Int -> StorePath a -> ShowS
[StorePath a] -> ShowS
StorePath a -> FilePath
(Int -> StorePath a -> ShowS)
-> (StorePath a -> FilePath)
-> ([StorePath a] -> ShowS)
-> Show (StorePath a)
forall a. Int -> StorePath a -> ShowS
forall a. [StorePath a] -> ShowS
forall a. StorePath a -> FilePath
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
showList :: [StorePath a] -> ShowS
$cshowList :: forall a. [StorePath a] -> ShowS
show :: StorePath a -> FilePath
$cshow :: forall a. StorePath a -> FilePath
showsPrec :: Int -> StorePath a -> ShowS
$cshowsPrec :: forall a. Int -> StorePath a -> ShowS
Show)

-- | A nix derivation is a complete build instruction that can be realized.
data Derivation
-- | Once a derivation is realized, the finished output can be used.
data Realized