module Puppet.Runner.Erb.Evaluate (
rubyEvaluate
) where
import XPrelude
import Data.Aeson.Lens
import qualified Data.Char as Char
import qualified Data.HashMap.Strict as HM
import qualified Data.Text as Text
import qualified Data.Vector as V
import Erb.Ruby
import Puppet.Interpreter
type ScopeName = Text
rubyEvaluate :: Container ScopeInformation
-> ScopeName
-> [RubyStatement]
-> Either Doc Text
rubyEvaluate vars ctx = foldl (evalruby vars ctx) (Right "") . optimize
where
optimize [] = []
optimize (Puts x : DropPrevSpace' : xs) = optimize $ DropPrevSpace (Puts x) : xs
optimize (x:xs) = x : optimize xs
spaceNotCR :: Char -> Bool
spaceNotCR c = Char.isSpace c && c /= '\n' && c /= '\r'
evalruby :: Container ScopeInformation -> ScopeName -> Either Doc Text -> RubyStatement -> Either Doc Text
evalruby _ _ (Left err) _ = Left err
evalruby _ _ (Right _) (DropPrevSpace') = Left "Could not evaluate a non optimize DropPrevSpace'"
evalruby mp ctx (Right curstr) (DropNextSpace x) =
case evalruby mp ctx (Right curstr) x of
Left err -> Left err
Right y -> Right (Text.dropWhile spaceNotCR y)
evalruby mp ctx (Right curstr) (DropPrevSpace x) =
case evalruby mp ctx (Right curstr) x of
Left err -> Left err
Right y -> Right (Text.dropWhileEnd spaceNotCR y)
evalruby mp ctx (Right curstr) (Puts e) =
case (evalExpression mp ctx e >>= evalValue) of
Left err -> Left err
Right ex -> Right (curstr <> ex)
evalExpression :: Container ScopeInformation -> ScopeName -> Expression -> Either Doc PValue
evalExpression mp ctx (LookupOperation expvar expidx) = do
val <- evalExpression mp ctx expvar
idx <- evalExpression mp ctx expidx
case val of
PArray arr ->
case idx ^? _Integer of
Nothing -> Left $ "Can't convert index to integer when resolving" <+> pretty val <> brackets (pretty idx)
Just i ->
if fromIntegral (V.length arr) <= i
then Left $ "Array out of bound" <+> pretty val <> brackets (pretty idx)
else Right (arr V.! (fromIntegral i))
PHash hs ->
case idx of
PString idx' ->
case hs ^. at idx' of
Just x' -> Right x'
_ -> Left $ "Can't index variable" <+> pretty val <+> ", it is " <+> pretty (PHash hs)
_ -> Left $ "Can't index variable" <+> pretty val <+> ", it is " <+> pretty (PHash hs)
unexpectedval -> Left $ "Can't index variable" <+> pretty val <+> ", it is " <+> pretty unexpectedval
evalExpression _ _ (Value (Literal x)) = Right (PString x)
evalExpression mp ctx (ScopeObject (Value (Literal x))) = getVariable mp ctx x
evalExpression mp ctx (Object (Value (Literal x))) = do
case Text.stripPrefix "@" x of
Nothing -> Left $ "Erb variables '" <> ppline x <> "' should be prefixed by '@' in puppet version 4 and above."
Just x' -> getVariable mp ctx x'
evalExpression _ _ x = Left $ "Can't evaluate" <+> pretty x
evalValue :: PValue -> Either Doc Text
evalValue = go False
where
go escaped p = case p of
PString x -> Right $ if escaped then show x else x
PNumber x -> Right (scientific2text x)
PUndef -> Right "nil"
PBoolean True -> Right "true"
PBoolean False -> Right "false"
PArray lst -> fmap (\c -> "[" <> Text.intercalate ", " c <> "]") (mapM (go True) (V.toList lst))
PHash hash -> fmap (\l -> "{" <> Text.intercalate ", " (map (\(k,v) -> show k <> "=>" <> v) l) <> "}") (mapM (traverse (go True)) (HM.toList hash))
_ -> Left ("Can't display the ruby equivalent of" <+> pretty p)