module Puppet.Plugins (initLua, initLuaMaster, puppetFunc, closeLua, getFiles) where
import Puppet.PP
import qualified Scripting.Lua as Lua
import Scripting.LuaUtils()
import Control.Exception
import qualified Data.HashMap.Strict as HM
import qualified Data.Map.Strict as Map
import System.IO
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Vector as V
import Control.Monad.IO.Class
import Control.Concurrent
import Puppet.Interpreter.Types
import Puppet.Utils
instance Lua.StackValue PValue
where
push l (PString s) = Lua.push l s
push l (PBoolean b) = Lua.push l b
push l (PResourceReference rr _) = Lua.push l rr
push l (PArray arr) = Lua.push l (V.toList arr)
push l (PHash m) = Lua.push l (Map.fromList $ HM.toList m)
push l (PUndef) = Lua.push l ("undefined" :: T.Text)
peek l n = do
Lua.ltype l n >>= \case
Lua.TBOOLEAN -> fmap (fmap PBoolean) (Lua.peek l n)
Lua.TSTRING -> fmap (fmap PString) (Lua.peek l n)
Lua.TNUMBER -> fmap (fmap (PString . tshow)) (Lua.peek l n :: IO (Maybe Double))
Lua.TNIL -> return (Just PUndef)
Lua.TNONE -> return (Just PUndef)
Lua.TTABLE -> fmap (fmap (PArray . V.fromList)) (Lua.peek l n)
_ -> return Nothing
valuetype _ = Lua.TUSERDATA
getDirContents :: T.Text -> IO [T.Text]
getDirContents x = fmap (filter (not . T.all (=='.'))) (getDirectoryContents x)
checkForSubFiles :: T.Text -> T.Text -> IO [T.Text]
checkForSubFiles extension dir =
catch (fmap Right (getDirContents dir)) (\e -> return $ Left (e :: IOException)) >>= \case
Right o -> return ((map (\x -> dir <> "/" <> x) . filter (T.isSuffixOf extension)) o )
Left _ -> return []
getFiles :: T.Text -> T.Text -> T.Text -> IO [T.Text]
getFiles moduledir subdir extension = fmap concat $
getDirContents moduledir
>>= mapM ( checkForSubFiles extension . (\x -> moduledir <> "/" <> x <> "/" <> subdir))
getLuaFiles :: T.Text -> IO [T.Text]
getLuaFiles moduledir = getFiles moduledir "lib/puppet/parser/luafunctions" ".lua"
loadLuaFile :: Lua.LuaState -> T.Text -> IO [T.Text]
loadLuaFile l file =
Lua.loadfile l (T.unpack file) >>= \case
0 -> Lua.call l 0 0 >> return [takeBaseName file]
_ -> do
T.hPutStrLn stderr ("Could not load file " <> file)
return []
puppetFunc :: Lua.LuaState -> T.Text -> [PValue] -> InterpreterMonad PValue
puppetFunc l fn args =
liftIO ( catch (fmap Right (Lua.callfunc l (T.unpack fn) args)) (\e -> return $ Left $ show (e :: SomeException)) ) >>= \case
Right x -> return x
Left y -> throwPosError (string y)
initLua :: T.Text -> IO (Lua.LuaState, [T.Text])
initLua moduledir = do
funcfiles <- getLuaFiles moduledir
l <- Lua.newstate
Lua.openlibs l
luafuncs <- fmap concat $ mapM (loadLuaFile l) funcfiles
return (l , luafuncs)
initLuaMaster :: T.Text -> IO (HM.HashMap T.Text ([PValue] -> InterpreterMonad PValue))
initLuaMaster moduledir = do
(luastate, luafunctions) <- initLua moduledir
c <- newMVar luastate
let callf fname args = do
r <- liftIO $ withMVar c $ \stt ->
catch (fmap Right (Lua.callfunc stt (T.unpack fname) args)) (\e -> return $ Left $ show (e :: SomeException))
case r of
Right x -> return x
Left rr -> throwPosError (string rr)
return $ HM.fromList [(fname, callf fname) | fname <- luafunctions]
closeLua :: Lua.LuaState -> IO ()
closeLua = Lua.close