{-# LANGUAGE BangPatterns #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} -- | This is an internal module. module Puppet.Interpreter.IO ( defaultImpureMethods , interpretMonad ) where import Control.Exception import Control.Lens import Control.Monad.Operational import Control.Monad.State.Strict import Control.Monad.Trans.Except import qualified Data.Either.Strict as S import Data.Monoid import qualified Data.Text as T import qualified Data.Text.IO as T import Debug.Trace (traceEventIO) import GHC.Stack import Puppet.Interpreter.PrettyPrinter () import Puppet.Interpreter.Types import Puppet.PP defaultImpureMethods :: MonadIO m => IoMethods m defaultImpureMethods = IoMethods (liftIO currentCallStack) (liftIO . file) (liftIO . traceEventIO) where file [] = return $ Left "" file (x:xs) = (Right <$> T.readFile (T.unpack x)) `catch` (\SomeException{} -> file xs) -- | The operational interpreter function interpretMonad :: Monad m => InterpreterReader m -> InterpreterState -> InterpreterMonad a -> m (Either PrettyError a, InterpreterState, InterpreterWriter) interpretMonad r s0 instr = let (!p, !s1) = runState (viewT instr) s0 in eval r s1 p -- The internal (not exposed) eval function eval :: Monad m => InterpreterReader m -> InterpreterState -> ProgramViewT InterpreterInstr (State InterpreterState) a -> m (Either PrettyError a, InterpreterState, InterpreterWriter) eval _ s (Return x) = return (Right x, s, mempty) eval r s (a :>>= k) = let runInstr = interpretMonad r s . k -- run one instruction thpe = interpretMonad r s . throwPosError . getError pdb = r^.readerPdbApi strFail iof errf = iof >>= \case Left rr -> thpe (errf (string rr)) Right x -> runInstr x canFail iof = iof >>= \case S.Left err -> thpe err S.Right x -> runInstr x canFailX iof = runExceptT iof >>= \case Left err -> thpe err Right x -> runInstr x logStuff x c = (_3 %~ (x <>)) <$> c in case a of IsStrict -> runInstr (r ^. readerIsStrict) ExternalFunction fname args -> case r ^. readerExternalFunc . at fname of Just fn -> interpretMonad r s ( fn args >>= k) Nothing -> thpe (PrettyError ("Unknown function: " <> ttext fname)) GetStatement topleveltype toplevelname -> canFail ((r ^. readerGetStatement) topleveltype toplevelname) ComputeTemplate fn stt -> canFail ((r ^. readerGetTemplate) fn stt r) WriterTell t -> logStuff t (runInstr ()) WriterPass _ -> thpe "WriterPass" WriterListen _ -> thpe "WriterListen" PuppetPaths -> runInstr (r ^. readerPuppetPaths) GetNativeTypes -> runInstr (r ^. readerNativeTypes) ErrorThrow d -> return (Left d, s, mempty) ErrorCatch _ _ -> thpe "ErrorCatch" GetNodeName -> runInstr (r ^. readerNodename) HieraQuery scps q t -> canFail ((r ^. readerHieraQuery) scps q t) PDBInformation -> pdbInformation pdb >>= runInstr PDBReplaceCatalog w -> canFailX (replaceCatalog pdb w) PDBReplaceFacts fcts -> canFailX (replaceFacts pdb fcts) PDBDeactivateNode nn -> canFailX (deactivateNode pdb nn) PDBGetFacts q -> canFailX (getFacts pdb q) PDBGetResources q -> canFailX (getResources pdb q) PDBGetNodes q -> canFailX (getNodes pdb q) PDBCommitDB -> canFailX (commitDB pdb) PDBGetResourcesOfNode nn q -> canFailX (getResourcesOfNode pdb nn q) GetCurrentCallStack -> (r ^. readerIoMethods . ioGetCurrentCallStack) >>= runInstr ReadFile fls -> strFail ((r ^. readerIoMethods . ioReadFile) fls) (const $ PrettyError ("No file found in " <> list (map ttext fls))) TraceEvent e -> (r ^. readerIoMethods . ioTraceEvent) e >>= runInstr IsIgnoredModule m -> runInstr (r ^. readerIgnoredModules . contains m) IsExternalModule m -> runInstr (r ^. readerExternalModules . contains m)