module Hix.Managed.Flow ( Flow, liftM, runStage, execStage, evalStage, runStage_, execStatelessStage, evalStageState, runFlow, execFlow, evalFlow, stageError, ) where import Control.Lens ((%=)) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.State.Strict (StateT, get, gets, runStateT) import qualified Data.List.NonEmpty as NonEmpty import qualified Data.Text as Text import Exon (exon) import Hix.Data.Error (Error (Fatal)) import Hix.Data.Monad (M) import qualified Hix.Log as Log import qualified Hix.Managed.Data.EnvContext import Hix.Managed.Data.EnvContext (EnvContext (EnvContext)) import qualified Hix.Managed.Data.EnvRequest import Hix.Managed.Data.EnvRequest (EnvRequest (EnvRequest)) import qualified Hix.Managed.Data.EnvResult import Hix.Managed.Data.EnvResult (EnvResult (EnvResult)) import Hix.Managed.Data.EnvState (EnvState) import Hix.Managed.Data.Initial (Initial (Initial)) import Hix.Managed.Data.StageContext (StageContext) import Hix.Managed.Data.StageResult (StageFailure (FailedPrecondition), StageResult (..), StageSummary (StageFailure)) import Hix.Managed.Data.StageState (BuildStatus (Failure, Success)) import Hix.Managed.StageContext (stageContext) import Hix.Managed.UpdateState (envStateWithMutations) import Hix.Monad (throwM) data FlowState = FlowState { FlowState -> EnvRequest env :: EnvRequest, FlowState -> EnvState current :: EnvState, FlowState -> [StageSummary] summaries :: [StageSummary] } deriving stock ((forall x. FlowState -> Rep FlowState x) -> (forall x. Rep FlowState x -> FlowState) -> Generic FlowState forall x. Rep FlowState x -> FlowState forall x. FlowState -> Rep FlowState x forall a. (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a $cfrom :: forall x. FlowState -> Rep FlowState x from :: forall x. FlowState -> Rep FlowState x $cto :: forall x. Rep FlowState x -> FlowState to :: forall x. Rep FlowState x -> FlowState Generic) type FlowM = StateT FlowState M newtype Flow x = Flow (FlowM x) deriving newtype ((forall a b. (a -> b) -> Flow a -> Flow b) -> (forall a b. a -> Flow b -> Flow a) -> Functor Flow forall a b. a -> Flow b -> Flow a forall a b. (a -> b) -> Flow a -> Flow b forall (f :: * -> *). (forall a b. (a -> b) -> f a -> f b) -> (forall a b. a -> f b -> f a) -> Functor f $cfmap :: forall a b. (a -> b) -> Flow a -> Flow b fmap :: forall a b. (a -> b) -> Flow a -> Flow b $c<$ :: forall a b. a -> Flow b -> Flow a <$ :: forall a b. a -> Flow b -> Flow a Functor, Functor Flow Functor Flow => (forall a. a -> Flow a) -> (forall a b. Flow (a -> b) -> Flow a -> Flow b) -> (forall a b c. (a -> b -> c) -> Flow a -> Flow b -> Flow c) -> (forall a b. Flow a -> Flow b -> Flow b) -> (forall a b. Flow a -> Flow b -> Flow a) -> Applicative Flow forall a. a -> Flow a forall a b. Flow a -> Flow b -> Flow a forall a b. Flow a -> Flow b -> Flow b forall a b. Flow (a -> b) -> Flow a -> Flow b forall a b c. (a -> b -> c) -> Flow a -> Flow b -> Flow 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 $cpure :: forall a. a -> Flow a pure :: forall a. a -> Flow a $c<*> :: forall a b. Flow (a -> b) -> Flow a -> Flow b <*> :: forall a b. Flow (a -> b) -> Flow a -> Flow b $cliftA2 :: forall a b c. (a -> b -> c) -> Flow a -> Flow b -> Flow c liftA2 :: forall a b c. (a -> b -> c) -> Flow a -> Flow b -> Flow c $c*> :: forall a b. Flow a -> Flow b -> Flow b *> :: forall a b. Flow a -> Flow b -> Flow b $c<* :: forall a b. Flow a -> Flow b -> Flow a <* :: forall a b. Flow a -> Flow b -> Flow a Applicative, Applicative Flow Applicative Flow => (forall a b. Flow a -> (a -> Flow b) -> Flow b) -> (forall a b. Flow a -> Flow b -> Flow b) -> (forall a. a -> Flow a) -> Monad Flow forall a. a -> Flow a forall a b. Flow a -> Flow b -> Flow b forall a b. Flow a -> (a -> Flow b) -> Flow 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 $c>>= :: forall a b. Flow a -> (a -> Flow b) -> Flow b >>= :: forall a b. Flow a -> (a -> Flow b) -> Flow b $c>> :: forall a b. Flow a -> Flow b -> Flow b >> :: forall a b. Flow a -> Flow b -> Flow b $creturn :: forall a. a -> Flow a return :: forall a. a -> Flow a Monad) liftM :: M a -> Flow a liftM :: forall a. M a -> Flow a liftM = FlowM a -> Flow a forall x. FlowM x -> Flow x Flow (FlowM a -> Flow a) -> (M a -> FlowM a) -> M a -> Flow a forall b c a. (b -> c) -> (a -> b) -> a -> c . M a -> FlowM a forall (m :: * -> *) a. Monad m => m a -> StateT FlowState m a forall (t :: (* -> *) -> * -> *) (m :: * -> *) a. (MonadTrans t, Monad m) => m a -> t m a lift addResult :: StageResult -> Flow BuildStatus addResult :: StageResult -> Flow BuildStatus addResult StageResult {Maybe MutationState state :: Maybe MutationState state :: StageResult -> Maybe MutationState state, StageSummary summary :: StageSummary summary :: StageResult -> StageSummary summary} = FlowM BuildStatus -> Flow BuildStatus forall x. FlowM x -> Flow x Flow do #summaries %= (summary :) #current %= maybe id envStateWithMutations state pure status where status :: BuildStatus status = case StageSummary summary of StageFailure StageFailure _ -> BuildStatus Failure StageSummary _ -> BuildStatus Success newContext :: Flow StageContext newContext :: Flow StageContext newContext = do FlowState {EnvRequest env :: FlowState -> EnvRequest env :: EnvRequest env, EnvState current :: FlowState -> EnvState current :: EnvState current} <- FlowM FlowState -> Flow FlowState forall x. FlowM x -> Flow x Flow FlowM FlowState forall (m :: * -> *) s. Monad m => StateT s m s get StageContext -> Flow StageContext forall a. a -> Flow a forall (f :: * -> *) a. Applicative f => a -> f a pure (EnvRequest -> EnvState -> StageContext stageContext EnvRequest env EnvState current) runStage :: ∀ o . Text -> (StageContext -> M (StageResult, o)) -> Flow (BuildStatus, o) runStage :: forall o. Text -> (StageContext -> M (StageResult, o)) -> Flow (BuildStatus, o) runStage Text description StageContext -> M (StageResult, o) stage = do Bool -> Flow () -> Flow () forall (f :: * -> *). Applicative f => Bool -> f () -> f () unless (Text -> Bool Text.null Text description) do EnvRequest {context :: EnvRequest -> EnvContext context = EnvContext {EnvName env :: EnvName env :: EnvContext -> EnvName env}} <- FlowM EnvRequest -> Flow EnvRequest forall x. FlowM x -> Flow x Flow ((FlowState -> EnvRequest) -> FlowM EnvRequest forall (m :: * -> *) s a. Monad m => (s -> a) -> StateT s m a gets (.env)) M () -> Flow () forall a. M a -> Flow a liftM (Text -> M () Log.debug [exon|Executing stage '#{description}' for '##{env}'|]) StageContext context <- Flow StageContext newContext (StageResult result, o o) <- M (StageResult, o) -> Flow (StageResult, o) forall a. M a -> Flow a liftM (StageContext -> M (StageResult, o) stage StageContext context) BuildStatus status <- StageResult -> Flow BuildStatus addResult StageResult result pure (BuildStatus status, o o) execStage :: Text -> (StageContext -> M StageResult) -> Flow BuildStatus execStage :: Text -> (StageContext -> M StageResult) -> Flow BuildStatus execStage Text description StageContext -> M StageResult stage = (BuildStatus, ()) -> BuildStatus forall a b. (a, b) -> a fst ((BuildStatus, ()) -> BuildStatus) -> Flow (BuildStatus, ()) -> Flow BuildStatus forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Text -> (StageContext -> M (StageResult, ())) -> Flow (BuildStatus, ()) forall o. Text -> (StageContext -> M (StageResult, o)) -> Flow (BuildStatus, o) runStage Text description ((StageResult -> (StageResult, ())) -> M StageResult -> M (StageResult, ()) forall a b. (a -> b) -> M a -> M b forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap (, ()) (M StageResult -> M (StageResult, ())) -> (StageContext -> M StageResult) -> StageContext -> M (StageResult, ()) forall b c a. (b -> c) -> (a -> b) -> a -> c . StageContext -> M StageResult stage) evalStage :: Text -> (StageContext -> M (StageResult, o)) -> Flow o evalStage :: forall o. Text -> (StageContext -> M (StageResult, o)) -> Flow o evalStage Text description StageContext -> M (StageResult, o) stage = (BuildStatus, o) -> o forall a b. (a, b) -> b snd ((BuildStatus, o) -> o) -> Flow (BuildStatus, o) -> Flow o forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Text -> (StageContext -> M (StageResult, o)) -> Flow (BuildStatus, o) forall o. Text -> (StageContext -> M (StageResult, o)) -> Flow (BuildStatus, o) runStage Text description StageContext -> M (StageResult, o) stage runStage_ :: Text -> (StageContext -> M StageResult) -> Flow () runStage_ :: Text -> (StageContext -> M StageResult) -> Flow () runStage_ Text description StageContext -> M StageResult stage = Flow BuildStatus -> Flow () forall (f :: * -> *) a. Functor f => f a -> f () void (Text -> (StageContext -> M StageResult) -> Flow BuildStatus execStage Text description StageContext -> M StageResult stage) execStatelessStage :: Text -> (StageContext -> M StageSummary) -> Flow BuildStatus execStatelessStage :: Text -> (StageContext -> M StageSummary) -> Flow BuildStatus execStatelessStage Text description StageContext -> M StageSummary f = do Text -> (StageContext -> M StageResult) -> Flow BuildStatus execStage Text description \ StageContext context -> do StageSummary summary <- StageContext -> M StageSummary f StageContext context pure StageResult {state :: Maybe MutationState state = Maybe MutationState forall a. Maybe a Nothing, StageSummary summary :: StageSummary summary :: StageSummary summary} stageError :: Text -> Flow () stageError :: Text -> Flow () stageError Text msg = Flow BuildStatus -> Flow () forall (f :: * -> *) a. Functor f => f a -> f () void (Text -> (StageContext -> M StageSummary) -> Flow BuildStatus execStatelessStage Text "" (M StageSummary -> StageContext -> M StageSummary forall a b. a -> b -> a const (StageSummary -> M StageSummary forall a. a -> M a forall (f :: * -> *) a. Applicative f => a -> f a pure (StageFailure -> StageSummary StageFailure (NonEmpty Text -> StageFailure FailedPrecondition [Text Item (NonEmpty Text) msg]))))) evalStageState :: (EnvState -> StageContext -> a) -> Flow a evalStageState :: forall a. (EnvState -> StageContext -> a) -> Flow a evalStageState EnvState -> StageContext -> a f = do StageContext context <- Flow StageContext newContext EnvState state <- FlowM EnvState -> Flow EnvState forall x. FlowM x -> Flow x Flow ((FlowState -> EnvState) -> FlowM EnvState forall (m :: * -> *) s a. Monad m => (s -> a) -> StateT s m a gets (.current)) pure (EnvState -> StageContext -> a f EnvState state StageContext context) runFlow :: EnvRequest -> Flow o -> M (o, EnvResult) runFlow :: forall o. EnvRequest -> Flow o -> M (o, EnvResult) runFlow request :: EnvRequest request@EnvRequest {EnvContext context :: EnvRequest -> EnvContext context :: EnvContext context, state :: EnvRequest -> Initial EnvState state = (Initial EnvState initState)} (Flow FlowM o m) = FlowM o -> FlowState -> M (o, FlowState) forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s) runStateT FlowM o m FlowState {env :: EnvRequest env = EnvRequest request, current :: EnvState current = EnvState initState, summaries :: [StageSummary] summaries = []} M (o, FlowState) -> ((o, FlowState) -> M (o, EnvResult)) -> M (o, EnvResult) forall a b. M a -> (a -> M b) -> M b forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>= (FlowState -> M EnvResult) -> (o, FlowState) -> M (o, EnvResult) forall (t :: * -> *) (f :: * -> *) a b. (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b) forall (f :: * -> *) a b. Applicative f => (a -> f b) -> (o, a) -> f (o, b) traverse \case FlowState {summaries :: FlowState -> [StageSummary] summaries = StageSummary h : [StageSummary] t, current :: FlowState -> EnvState current = EnvState finalState} -> EnvResult -> M EnvResult forall a. a -> M a forall (f :: * -> *) a. Applicative f => a -> f a pure EnvResult {env :: EnvName env = EnvContext context.env, state :: Maybe EnvState state = EnvState -> Maybe EnvState forall a. a -> Maybe a Just EnvState finalState, summaries :: NonEmpty StageSummary summaries = NonEmpty StageSummary -> NonEmpty StageSummary forall a. NonEmpty a -> NonEmpty a NonEmpty.reverse (StageSummary h StageSummary -> [StageSummary] -> NonEmpty StageSummary forall a. a -> [a] -> NonEmpty a :| [StageSummary] t)} FlowState {summaries :: FlowState -> [StageSummary] summaries = []} -> Error -> M EnvResult forall a. Error -> M a throwM (Text -> Error Fatal Text "Executed flow with no stages") execFlow :: EnvRequest -> Flow () -> M EnvResult execFlow :: EnvRequest -> Flow () -> M EnvResult execFlow EnvRequest env Flow () m = ((), EnvResult) -> EnvResult forall a b. (a, b) -> b snd (((), EnvResult) -> EnvResult) -> M ((), EnvResult) -> M EnvResult forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> EnvRequest -> Flow () -> M ((), EnvResult) forall o. EnvRequest -> Flow o -> M (o, EnvResult) runFlow EnvRequest env Flow () m evalFlow :: EnvRequest -> Flow o -> M o evalFlow :: forall o. EnvRequest -> Flow o -> M o evalFlow EnvRequest env Flow o m = (o, EnvResult) -> o forall a b. (a, b) -> a fst ((o, EnvResult) -> o) -> M (o, EnvResult) -> M o forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> EnvRequest -> Flow o -> M (o, EnvResult) forall o. EnvRequest -> Flow o -> M (o, EnvResult) runFlow EnvRequest env Flow o m