Reinstate cwd setup, this time with locking
This commit is contained in:
parent
254f6a9a73
commit
7bbaa35f56
@ -50,6 +50,7 @@ import Control.Monad.Trans.Journal (runJournalT)
|
|||||||
import Exception
|
import Exception
|
||||||
|
|
||||||
import System.Directory
|
import System.Directory
|
||||||
|
import System.IO.Unsafe
|
||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
withGhcModEnv :: (IOish m, GmOut m) => FilePath -> Options -> ((GhcModEnv, GhcModLog) -> m a) -> m a
|
withGhcModEnv :: (IOish m, GmOut m) => FilePath -> Options -> ((GhcModEnv, GhcModLog) -> m a) -> m a
|
||||||
@ -58,23 +59,32 @@ withGhcModEnv = withGhcModEnv' withCradle
|
|||||||
withCradle dir =
|
withCradle dir =
|
||||||
gbracket (runJournalT $ findCradle' dir) (liftIO . cleanupCradle . fst)
|
gbracket (runJournalT $ findCradle' dir) (liftIO . cleanupCradle . fst)
|
||||||
|
|
||||||
|
cwdLock :: MVar ThreadId
|
||||||
|
cwdLock = unsafePerformIO $ newEmptyMVar
|
||||||
|
{-# NOINLINE cwdLock #-}
|
||||||
|
|
||||||
withGhcModEnv' :: (IOish m, GmOut m) => (FilePath -> ((Cradle, GhcModLog) -> m a) -> m a) -> FilePath -> Options -> ((GhcModEnv, GhcModLog) -> m a) -> m a
|
withGhcModEnv' :: (IOish m, GmOut m) => (FilePath -> ((Cradle, GhcModLog) -> m a) -> m a) -> FilePath -> Options -> ((GhcModEnv, GhcModLog) -> m a) -> m a
|
||||||
withGhcModEnv' withCradle dir opts f =
|
withGhcModEnv' withCradle dir opts f =
|
||||||
withCradle dir $ \(crdl,lg) ->
|
withCradle dir $ \(crdl,lg) ->
|
||||||
withCradleRootDir crdl $
|
withCradleRootDir crdl $
|
||||||
f (GhcModEnv opts crdl, lg)
|
f (GhcModEnv opts crdl, lg)
|
||||||
where
|
where
|
||||||
withCradleRootDir (cradleRootDir -> projdir) a = do
|
swapCurrentDirectory ndir = do
|
||||||
cdir <- liftIO $ getCurrentDirectory
|
odir <- canonicalizePath =<< getCurrentDirectory
|
||||||
eq <- liftIO $ pathsEqual projdir cdir
|
setCurrentDirectory ndir
|
||||||
if not eq
|
return odir
|
||||||
then throw $ GMEWrongWorkingDirectory projdir cdir
|
|
||||||
else a
|
|
||||||
|
|
||||||
pathsEqual a b = do
|
withCradleRootDir (cradleRootDir -> projdir) a = do
|
||||||
ca <- canonicalizePath a
|
success <- liftIO $ tryPutMVar cwdLock =<< myThreadId
|
||||||
cb <- canonicalizePath b
|
if not success
|
||||||
return $ ca == cb
|
then error "withGhcModEnv': using ghc-mod from multiple threads is not supported!"
|
||||||
|
else gbracket setup teardown (const a)
|
||||||
|
where
|
||||||
|
setup = liftIO $ swapCurrentDirectory projdir
|
||||||
|
|
||||||
|
teardown odir = liftIO $ do
|
||||||
|
setCurrentDirectory odir
|
||||||
|
void $ takeMVar cwdLock
|
||||||
|
|
||||||
runGmOutT :: IOish m => Options -> GmOutT m a -> m a
|
runGmOutT :: IOish m => Options -> GmOutT m a -> m a
|
||||||
runGmOutT opts ma = do
|
runGmOutT opts ma = do
|
||||||
|
@ -256,7 +256,7 @@ Test-Suite spec
|
|||||||
DataKinds, KindSignatures, TypeOperators, ViewPatterns
|
DataKinds, KindSignatures, TypeOperators, ViewPatterns
|
||||||
Main-Is: Main.hs
|
Main-Is: Main.hs
|
||||||
Hs-Source-Dirs: test, ., src
|
Hs-Source-Dirs: test, ., src
|
||||||
Ghc-Options: -Wall -fno-warn-deprecations
|
Ghc-Options: -Wall -fno-warn-deprecations -threaded
|
||||||
CPP-Options: -DSPEC=1
|
CPP-Options: -DSPEC=1
|
||||||
Type: exitcode-stdio-1.0
|
Type: exitcode-stdio-1.0
|
||||||
Other-Modules: Paths_ghc_mod
|
Other-Modules: Paths_ghc_mod
|
||||||
|
@ -3,6 +3,8 @@ module MonadSpec where
|
|||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
import TestUtils
|
import TestUtils
|
||||||
import Control.Monad.Error.Class
|
import Control.Monad.Error.Class
|
||||||
|
import Control.Concurrent
|
||||||
|
import Control.Exception
|
||||||
|
|
||||||
spec :: Spec
|
spec :: Spec
|
||||||
spec = do
|
spec = do
|
||||||
@ -15,3 +17,21 @@ spec = do
|
|||||||
return "hello"
|
return "hello"
|
||||||
`catchError` (const $ fail "oh noes")
|
`catchError` (const $ fail "oh noes")
|
||||||
a `shouldBe` (Left $ GMEString "oh noes")
|
a `shouldBe` (Left $ GMEString "oh noes")
|
||||||
|
|
||||||
|
describe "runGhcModT" $
|
||||||
|
it "throws an exception when run in multiple threads" $ do
|
||||||
|
mv1 :: MVar (Either SomeException ())
|
||||||
|
<- newEmptyMVar
|
||||||
|
mv2 :: MVar (Either SomeException ())
|
||||||
|
<- newEmptyMVar
|
||||||
|
|
||||||
|
_ <- forkOS $ putMVar mv1 =<< (try $ evaluate =<< (runD $ liftIO $ readMVar mv2 >> return ()))
|
||||||
|
_ <- forkOS $ putMVar mv2 =<< (try $ evaluate =<< (runD $ return ()))
|
||||||
|
e1 <- takeMVar mv1
|
||||||
|
e2 <- takeMVar mv2
|
||||||
|
|
||||||
|
(isLeft e1 || isLeft e2) `shouldBe` True
|
||||||
|
|
||||||
|
isLeft :: Either a b -> Bool
|
||||||
|
isLeft (Right _) = False
|
||||||
|
isLeft (Left _) = True
|
||||||
|
@ -45,20 +45,7 @@ extract action = do
|
|||||||
|
|
||||||
withSpecCradle :: (IOish m, GmOut m) => FilePath -> ((Cradle, GhcModLog) -> m a) -> m a
|
withSpecCradle :: (IOish m, GmOut m) => FilePath -> ((Cradle, GhcModLog) -> m a) -> m a
|
||||||
withSpecCradle cradledir f = do
|
withSpecCradle cradledir f = do
|
||||||
gbracket (runJournalT $ findSpecCradle cradledir) (liftIO . cleanupCradle . fst) $ \arg@(crdl,_) ->
|
gbracket (runJournalT $ findSpecCradle cradledir) (liftIO . cleanupCradle . fst) f
|
||||||
bracketWorkingDirectory (cradleRootDir crdl) $
|
|
||||||
f arg
|
|
||||||
|
|
||||||
bracketWorkingDirectory ::
|
|
||||||
(ExceptionMonad m, MonadIO m) => FilePath -> m c -> m c
|
|
||||||
bracketWorkingDirectory dir a =
|
|
||||||
gbracket (swapWorkingDirectory dir) (liftIO . setCurrentDirectory) (const a)
|
|
||||||
|
|
||||||
swapWorkingDirectory :: MonadIO m => FilePath -> m FilePath
|
|
||||||
swapWorkingDirectory ndir = liftIO $ do
|
|
||||||
odir <- getCurrentDirectory >>= canonicalizePath
|
|
||||||
setCurrentDirectory $ ndir
|
|
||||||
return odir
|
|
||||||
|
|
||||||
runGhcModTSpec :: Options -> GhcModT IO a -> IO (Either GhcModError a, GhcModLog)
|
runGhcModTSpec :: Options -> GhcModT IO a -> IO (Either GhcModError a, GhcModLog)
|
||||||
runGhcModTSpec opt action = do
|
runGhcModTSpec opt action = do
|
||||||
|
Loading…
Reference in New Issue
Block a user