@@ -18,11 +18,14 @@ where
1818
1919import Control.Applicative ((<$>) )
2020import Control.Exception (IOException , try )
21+ import Control.Monad (forM_ )
22+ import Control.Monad.Catch (bracket )
2123import Data.Maybe (fromMaybe )
24+ import Data.Version (versionBranch )
2225import Foreign.Lua (Lua , NumResults (.. ), Optional (.. ), Peekable , Pushable ,
2326 StackIndex , ToHaskellFunction )
2427
25- import qualified Data.Version
28+ import qualified Data.Map as Map
2629import qualified Foreign.Lua as Lua
2730import qualified System.Directory as Directory
2831import qualified System.Environment as Env
@@ -35,7 +38,7 @@ pushModule = do
3538 Lua. newtable
3639 addField " arch" Info. arch
3740 addField " compiler_name" Info. compilerName
38- addField " compiler_version" (Data.Version. versionBranch Info. compilerVersion)
41+ addField " compiler_version" (versionBranch Info. compilerVersion)
3942 addField " os" Info. os
4043 addFunction " chdir" chdir
4144 addFunction " currentdir" currentdir
@@ -46,6 +49,7 @@ pushModule = do
4649 addFunction " rmdir" rmdir
4750 addFunction " setenv" setenv
4851 addFunction " tmpdirname" tmpdirname
52+ addFunction " with_env" with_env
4953 addFunction " with_tmpdir" with_tmpdir
5054 return 1
5155
@@ -100,6 +104,20 @@ instance Peekable AnyValue where
100104instance Pushable AnyValue where
101105 push (AnyValue idx) = Lua. pushvalue idx
102106
107+ -- | Run an action, then restore the old environment variable values.
108+ with_env :: Map. Map String String -> Callback -> Lua NumResults
109+ with_env environment callback =
110+ bracket (Lua. liftIO Env. getEnvironment)
111+ setEnvironment
112+ (\ _ -> setEnvironment (Map. toList environment) >> invoke callback)
113+ where
114+ setEnvironment newEnv = Lua. liftIO $ do
115+ -- Crude, but fast enough: delete all entries in new environment,
116+ -- then restore old environment one-by-one.
117+ curEnv <- Env. getEnvironment
118+ forM_ curEnv (Env. unsetEnv . fst )
119+ forM_ newEnv (uncurry Env. setEnv)
120+
103121with_tmpdir :: String -- ^ parent dir or template
104122 -> AnyValue -- ^ template or callback
105123 -> Optional Callback -- ^ callback or nil
@@ -112,15 +130,24 @@ with_tmpdir parentDir tmpl callback =
112130 -- temporary directory.
113131 let tmpl' = parentDir
114132 callback' <- Lua. peek (fromAnyValue tmpl)
115- Temp. withSystemTempDirectory tmpl' (callWithFilename callback')
133+ Temp. withSystemTempDirectory tmpl' (invokeWithFilePath callback')
116134 Just callback' -> do
117135 -- all args given. Second value must be converted to a string.
118136 tmpl' <- Lua. peek (fromAnyValue tmpl)
119- Temp. withTempDirectory parentDir tmpl' (callWithFilename callback')
137+ Temp. withTempDirectory parentDir tmpl' (invokeWithFilePath callback')
138+
139+ invoke :: Callback -> Lua NumResults
140+ invoke callback = do
141+ oldTop <- Lua. gettop
142+ Lua. push callback
143+ Lua. call 0 Lua. multret
144+ newTop <- Lua. gettop
145+ return . NumResults . fromIntegral . Lua. fromStackIndex $
146+ newTop - oldTop
120147
121148-- | Call Lua callback function with the given filename as its argument.
122- callWithFilename :: Callback -> FilePath -> Lua NumResults
123- callWithFilename callback filename = do
149+ invokeWithFilePath :: Callback -> FilePath -> Lua NumResults
150+ invokeWithFilePath callback filename = do
124151 oldTop <- Lua. gettop
125152 Lua. push callback
126153 Lua. push filename
0 commit comments