funflow-1.0.0: src/Control/Funflow/External.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# 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)
import Data.Semigroup
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.
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
-- | 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]
-- | 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]
-- | If this is set, then the process outputs on its stdout stream
-- rather than writing to a file. In this case, output will be
-- redirected into a file called 'out' in the output directory.
-- Otherwise, the task is assumed to write itself to files in its
-- working directory.
, _etWriteToStdOut :: Bool
} 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