funflow-1.4.0: src/Control/Funflow/External.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
-- | Definition of external tasks
module Control.Funflow.External where
import Control.Funflow.ContentHashable (ContentHash, ContentHashable, ExternallyAssuredDirectory (..),
ExternallyAssuredFile (..))
import qualified Control.Funflow.ContentStore as CS
import Control.Lens.TH
import Data.Aeson (FromJSON, ToJSON)
#if __GLASGOW_HASKELL__ < 804
import Data.Semigroup
#endif
import Data.Store (Store)
import Data.String (IsString (..))
import qualified Data.Text as T
import GHC.Generics (Generic)
import Path
import System.Posix.Types (CGid, CUid)
-- | Set of items which may be treated as an input path to an external task.
data InputPath
-- | An item in the content store.
= IPItem CS.Item
-- | An external file whose contents are considered assured by the external
-- system.
| IPExternalFile ExternallyAssuredFile
-- | An external directory whose contents are considered assured by the
-- external system.
| IPExternalDir ExternallyAssuredDirectory
deriving (Generic, Show)
instance ContentHashable IO InputPath
instance FromJSON InputPath
instance ToJSON InputPath
instance Store InputPath
-- | Component of a parameter
data ParamField
= ParamText !T.Text
-- ^ Text component.
| ParamPath !InputPath
-- ^ Reference to a path to a content store item.
| ParamEnv !T.Text
-- ^ Reference to an environment variable.
| ParamUid
-- ^ Reference to the effective user ID of the executor.
| ParamGid
-- ^ Reference to the effective group ID of the executor.
| ParamOut
-- ^ Reference to the output path in the content store.
| ParamCmd Param
-- ^ A quoted command that we can pass to another program as an
-- argument.
deriving (Generic, Show)
instance ContentHashable IO ParamField
instance FromJSON ParamField
instance ToJSON ParamField
instance Store ParamField
-- | A parameter to an external task
--
-- The runtime values to external references, e.g. environment variables,
-- should not significantly influence the result of the external task.
-- In particular, the content hash will not depend on these runtime values.
newtype Param = Param [ParamField]
deriving (Generic, Monoid, Semigroup, Show)
instance IsString Param where
fromString s = Param [ParamText (fromString s)]
instance ContentHashable IO Param
instance FromJSON Param
instance ToJSON Param
instance Store Param
-- | Converter of path components.
data ConvParam f = ConvParam
{ convPath :: CS.Item -> f (Path Abs Dir)
-- ^ Resolve a reference to a content store item.
, convEnv :: T.Text -> f T.Text
-- ^ Resolve an environment variable.
, convUid :: f CUid
-- ^ Resolve the effective user ID.
, convGid :: f CGid
-- ^ Resolve the effective group ID.
, convOut :: f (Path Abs Dir)
-- ^ Resolve the output path in the content store.
}
paramFieldToText :: Applicative f
=> ConvParam f -> ParamField -> f T.Text
paramFieldToText _ (ParamText txt) = pure txt
paramFieldToText c (ParamPath (IPItem item)) = T.pack . fromAbsDir <$> convPath c item
paramFieldToText _ (ParamPath (IPExternalFile (ExternallyAssuredFile item)))
= pure . T.pack . fromAbsFile $ item
paramFieldToText _ (ParamPath (IPExternalDir (ExternallyAssuredDirectory item)))
= pure . T.pack . fromAbsDir $ item
paramFieldToText c (ParamEnv env) = convEnv c env
paramFieldToText c ParamUid = T.pack . show <$> convUid c
paramFieldToText c ParamGid = T.pack . show <$> convGid c
paramFieldToText c ParamOut = T.pack . fromAbsDir <$> convOut c
paramFieldToText c (ParamCmd cmd) = paramToText c cmd
-- | Transform a parameter to text using the given converter.
paramToText :: Applicative f
=> ConvParam f -> Param -> f T.Text
paramToText c (Param ps) = mconcat <$> traverse (paramFieldToText c) ps
stringParam :: String -> Param
stringParam str = Param [ParamText (T.pack str)]
textParam :: T.Text -> Param
textParam txt = Param [ParamText txt]
-- | Reference to a path to either:
-- - a content store item, or
-- - an externally assured file/directory.
pathParam :: InputPath -> Param
pathParam item = Param [ParamPath item]
-- | Reference to a path to a file or directory within a store item.
contentParam :: CS.Content t -> Param
contentParam (CS.All item) = pathParam $ IPItem item
contentParam (item CS.:</> path) =
pathParam (IPItem item) <> stringParam (toFilePath path)
-- | Reference an externally assured file
externalFileParam :: ExternallyAssuredFile -> Param
externalFileParam = pathParam . IPExternalFile
-- | Reference an externally assured file
externalDirectoryParam :: ExternallyAssuredDirectory -> Param
externalDirectoryParam = pathParam . IPExternalDir
-- | Reference to an environment variable.
envParam :: T.Text -> Param
envParam env = Param [ParamEnv env]
-- | Reference to the effective user ID of the executor.
uidParam :: Param
uidParam = Param [ParamUid]
-- | Reference to the effective group ID of the executor.
gidParam :: Param
gidParam = Param [ParamGid]
-- | Reference to the output path in the content store.
outParam :: Param
outParam = Param [ParamOut]
-- | Control how and where stdout from the process is captured. Some external
-- steps will write their output to stdout rather than to a file.
data OutputCapture
-- | Specify that the step will write its output files directly, and that
-- stdout will not be captured in the step output.
= NoOutputCapture
-- | Capture output to a file named 'out' in the output directory.
| StdOutCapture
-- | Capture output to a custom named file in the output directory.
| CustomOutCapture (Path Rel File)
deriving (Generic, Show)
-- | Get the file to write output to, if this is desired.
outputCaptureToRelFile :: OutputCapture -> Maybe (Path Rel File)
outputCaptureToRelFile NoOutputCapture = Nothing
outputCaptureToRelFile StdOutCapture = Just [relfile|out|]
outputCaptureToRelFile (CustomOutCapture file) = Just file
instance ContentHashable IO OutputCapture
instance FromJSON OutputCapture
instance ToJSON OutputCapture
instance Store OutputCapture
-- | Control the environment set for the external process. This can either
-- inherit from the surrounding environment, or explicitly set things.
data Env
-- | Inherit all environment variables from the surrounding shell. Note that
-- the values of these variables will not be taken into account in the
-- content hash, and so changes to them will not trigger a rerun of the
-- step.
= EnvInherit
| EnvExplicit [(T.Text, Param)]
deriving (Generic, Show)
instance ContentHashable IO Env
instance FromJSON Env
instance ToJSON Env
instance Store Env
-- | A monomorphic description of an external task. This is basically just
-- a command which can be run.
data ExternalTask = ExternalTask {
_etCommand :: T.Text
, _etParams :: [Param]
-- ^ Environment variables to set for the scope of the execution.
, _etEnv :: Env
, _etWriteToStdOut :: OutputCapture
} deriving (Generic, Show)
instance ContentHashable IO ExternalTask
instance FromJSON ExternalTask
instance ToJSON ExternalTask
instance Store ExternalTask
data TaskDescription = TaskDescription {
_tdOutput :: ContentHash
, _tdTask :: ExternalTask
} deriving (Generic, Show)
makeLenses ''ExternalTask
makeLenses ''TaskDescription