Skip to content

Commit 901974b

Browse files
authored
Merge pull request #762 from pepeiborra/retry-cradle
Retry a failed cradle if the cradle descriptor changes
2 parents 1a34357 + f8ac7a5 commit 901974b

File tree

3 files changed

+71
-23
lines changed

3 files changed

+71
-23
lines changed

ghcide/session-loader/Development/IDE/Session.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do
329329
let res = (map (renderCradleError ncfp) err, Nothing)
330330
modifyVar_ fileToFlags $ \var -> do
331331
pure $ Map.insertWith HM.union hieYaml (HM.singleton ncfp (res, dep_info)) var
332-
return (res,[])
332+
return (res, maybe [] pure hieYaml ++ concatMap cradleErrorDependencies err)
333333

334334
-- This caches the mapping from hie.yaml + Mod.hs -> [String]
335335
-- Returns the Ghc session and the cradle dependencies
@@ -360,7 +360,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do
360360
getOptions file = do
361361
hieYaml <- cradleLoc file
362362
sessionOpts (hieYaml, file) `catch` \e ->
363-
return (([renderPackageSetupException file e], Nothing),[])
363+
return (([renderPackageSetupException file e], Nothing), maybe [] pure hieYaml)
364364

365365
returnWithVersion $ \file -> do
366366
opts <- liftIO $ join $ mask_ $ modifyVar runningCradle $ \as -> do

ghcide/test/exe/Main.hs

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
module Main (main) where
1212

1313
import Control.Applicative.Combinators
14-
import Control.Exception (catch)
14+
import Control.Exception (bracket_, catch)
1515
import qualified Control.Lens as Lens
1616
import Control.Monad
1717
import Control.Monad.IO.Class (liftIO)
@@ -41,7 +41,7 @@ import Language.Haskell.LSP.Types.Capabilities
4141
import qualified Language.Haskell.LSP.Types.Lens as Lsp (diagnostics, params, message)
4242
import Language.Haskell.LSP.VFS (applyChange)
4343
import Network.URI
44-
import System.Environment.Blank (getEnv, setEnv)
44+
import System.Environment.Blank (unsetEnv, getEnv, setEnv)
4545
import System.FilePath
4646
import System.IO.Extra hiding (withTempDir)
4747
import qualified System.IO.Extra
@@ -58,8 +58,10 @@ import Test.Tasty.HUnit
5858
import Test.Tasty.QuickCheck
5959
import System.Time.Extra
6060
import Development.IDE.Plugin.CodeAction (typeSignatureCommandId, blockCommandId, matchRegExMultipleImports)
61-
import Development.IDE.Plugin.Test (WaitForIdeRuleResult(..), TestRequest(WaitForIdeRule, BlockSeconds,GetInterfaceFilesDir))
61+
import Development.IDE.Plugin.Test (WaitForIdeRuleResult(..), TestRequest(BlockSeconds,GetInterfaceFilesDir))
6262
import Control.Monad.Extra (whenJust)
63+
import qualified Language.Haskell.LSP.Types.Lens as L
64+
import Control.Lens ((^.))
6365

6466
main :: IO ()
6567
main = do
@@ -630,11 +632,6 @@ cancellationTemplate (edit, undoEdit) mbKey = testCase (maybe "-" fst mbKey) $ r
630632
-- similar to run except it disables kick
631633
runTestNoKick s = withTempDir $ \dir -> runInDir' dir "." "." ["--test-no-kick"] s
632634

633-
waitForAction key TextDocumentIdentifier{_uri} = do
634-
waitId <- sendRequest (CustomClientMethod "test") (WaitForIdeRule key _uri)
635-
ResponseMessage{_result} <- skipManyTill anyMessage $ responseForId waitId
636-
return _result
637-
638635
typeCheck doc = do
639636
Right WaitForIdeRuleResult {..} <- waitForAction "TypeCheck" doc
640637
liftIO $ assertBool "The file should typecheck" ideResultSuccess
@@ -3388,7 +3385,7 @@ cradleTests :: TestTree
33883385
cradleTests = testGroup "cradle"
33893386
[testGroup "dependencies" [sessionDepsArePickedUp]
33903387
,testGroup "ignore-fatal" [ignoreFatalWarning]
3391-
,testGroup "loading" [loadCradleOnlyonce]
3388+
,testGroup "loading" [loadCradleOnlyonce, retryFailedCradle]
33923389
,testGroup "multi" [simpleMultiTest, simpleMultiTest2]
33933390
,testGroup "sub-directory" [simpleSubDirectoryTest]
33943391
]
@@ -3415,6 +3412,43 @@ loadCradleOnlyonce = testGroup "load cradle only once"
34153412
msgs <- manyTill (skipManyTill anyMessage cradleLoadedMessage) (skipManyTill anyMessage (message @PublishDiagnosticsNotification))
34163413
liftIO $ length msgs @?= 0
34173414

3415+
retryFailedCradle :: TestTree
3416+
retryFailedCradle = testSession' "retry failed" $ \dir -> do
3417+
-- The false cradle always fails
3418+
let hieContents = "cradle: {bios: {shell: \"false\"}}"
3419+
hiePath = dir </> "hie.yaml"
3420+
liftIO $ writeFile hiePath hieContents
3421+
hieDoc <- createDoc hiePath "yaml" $ T.pack hieContents
3422+
let aPath = dir </> "A.hs"
3423+
doc <- createDoc aPath "haskell" "main = return ()"
3424+
Right WaitForIdeRuleResult {..} <- waitForAction "TypeCheck" doc
3425+
liftIO $ "Test assumption failed: cradle should error out" `assertBool` not ideResultSuccess
3426+
3427+
-- Fix the cradle and typecheck again
3428+
let validCradle = "cradle: {bios: {shell: \"echo A.hs\"}}"
3429+
liftIO $ writeFileUTF8 hiePath $ T.unpack validCradle
3430+
changeDoc
3431+
hieDoc
3432+
[ TextDocumentContentChangeEvent
3433+
{ _range = Nothing,
3434+
_rangeLength = Nothing,
3435+
_text = validCradle
3436+
}
3437+
]
3438+
3439+
-- Force a session restart by making an edit, just to dirty the typecheck node
3440+
changeDoc
3441+
doc
3442+
[ TextDocumentContentChangeEvent
3443+
{ _range = Just Range {_start = Position 0 0, _end = Position 0 0},
3444+
_rangeLength = Nothing,
3445+
_text = "\n"
3446+
}
3447+
]
3448+
3449+
Right WaitForIdeRuleResult {..} <- waitForAction "TypeCheck" doc
3450+
liftIO $ "No joy after fixing the cradle" `assertBool` ideResultSuccess
3451+
34183452

34193453
dependentFileTest :: TestTree
34203454
dependentFileTest = testGroup "addDependentFile"
@@ -3479,17 +3513,19 @@ simpleSubDirectoryTest =
34793513
expectNoMoreDiagnostics 0.5
34803514

34813515
simpleMultiTest :: TestTree
3482-
simpleMultiTest = testCase "simple-multi-test" $ runWithExtraFiles "multi" $ \dir -> do
3516+
simpleMultiTest = testCase "simple-multi-test" $ withLongTimeout $ runWithExtraFiles "multi" $ \dir -> do
34833517
let aPath = dir </> "a/A.hs"
34843518
bPath = dir </> "b/B.hs"
34853519
aSource <- liftIO $ readFileUtf8 aPath
3486-
(TextDocumentIdentifier adoc) <- createDoc aPath "haskell" aSource
3487-
expectNoMoreDiagnostics 0.5
3520+
adoc <- createDoc aPath "haskell" aSource
3521+
Right WaitForIdeRuleResult {..} <- waitForAction "TypeCheck" adoc
3522+
liftIO $ assertBool "A should typecheck" ideResultSuccess
34883523
bSource <- liftIO $ readFileUtf8 bPath
34893524
bdoc <- createDoc bPath "haskell" bSource
3490-
expectNoMoreDiagnostics 0.5
3525+
Right WaitForIdeRuleResult {..} <- waitForAction "TypeCheck" bdoc
3526+
liftIO $ assertBool "B should typecheck" ideResultSuccess
34913527
locs <- getDefinitions bdoc (Position 2 7)
3492-
let fooL = mkL adoc 2 0 2 3
3528+
let fooL = mkL (adoc ^. L.uri) 2 0 2 3
34933529
checkDefs locs (pure [fooL])
34943530
expectNoMoreDiagnostics 0.5
34953531

@@ -3855,6 +3891,9 @@ run' s = withTempDir $ \dir -> runInDir dir (s dir)
38553891
runInDir :: FilePath -> Session a -> IO a
38563892
runInDir dir = runInDir' dir "." "." []
38573893

3894+
withLongTimeout :: IO a -> IO a
3895+
withLongTimeout = bracket_ (setEnv "LSP_TIMEOUT" "120" True) (unsetEnv "LSP_TIMEOUT")
3896+
38583897
-- | Takes a directory as well as relative paths to where we should launch the executable as well as the session root.
38593898
runInDir' :: FilePath -> FilePath -> FilePath -> [String] -> Session a -> IO a
38603899
runInDir' dir startExeIn startSessionIn extraOptions s = do
@@ -3875,19 +3914,19 @@ runInDir' dir startExeIn startSessionIn extraOptions s = do
38753914
setEnv "HOME" "/homeless-shelter" False
38763915
let lspTestCaps = fullCaps { _window = Just $ WindowClientCapabilities $ Just True }
38773916
logColor <- fromMaybe True <$> checkEnv "LSP_TEST_LOG_COLOR"
3917+
timeoutOverride <- fmap read <$> getEnv "LSP_TIMEOUT"
3918+
let conf = defaultConfig{messageTimeout = fromMaybe (messageTimeout defaultConfig) timeoutOverride}
3919+
-- uncomment this or set LSP_TEST_LOG_STDERR=1 to see all logging
3920+
-- { logStdErr = True }
3921+
-- uncomment this or set LSP_TEST_LOG_MESSAGES=1 to see all messages
3922+
-- { logMessages = True }
38783923
runSessionWithConfig conf{logColor} cmd lspTestCaps projDir s
38793924
where
38803925
checkEnv :: String -> IO (Maybe Bool)
38813926
checkEnv s = fmap convertVal <$> getEnv s
38823927
convertVal "0" = False
38833928
convertVal _ = True
38843929

3885-
conf = defaultConfig
3886-
-- uncomment this or set LSP_TEST_LOG_STDERR=1 to see all logging
3887-
-- { logStdErr = True }
3888-
-- uncomment this or set LSP_TEST_LOG_MESSAGES=1 to see all messages
3889-
-- { logMessages = True }
3890-
38913930
openTestDataDoc :: FilePath -> Session TextDocumentIdentifier
38923931
openTestDataDoc path = do
38933932
source <- liftIO $ readFileUtf8 $ "test/data" </> path

ghcide/test/src/Development/IDE/Test.hs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ module Development.IDE.Test
1515
, checkDiagnosticsForDoc
1616
, canonicalizeUri
1717
, standardizeQuotes
18-
,flushMessages) where
18+
, flushMessages
19+
, waitForAction
20+
) where
1921

2022
import Control.Applicative.Combinators
2123
import Control.Lens hiding (List)
@@ -32,6 +34,7 @@ import System.Time.Extra
3234
import Test.Tasty.HUnit
3335
import System.Directory (canonicalizePath)
3436
import Data.Maybe (fromJust)
37+
import Development.IDE.Plugin.Test (WaitForIdeRuleResult, TestRequest(WaitForIdeRule))
3538

3639

3740
-- | (0-based line number, 0-based column number)
@@ -180,3 +183,9 @@ standardizeQuotes msg = let
180183
repl '`' = '\''
181184
repl c = c
182185
in T.map repl msg
186+
187+
waitForAction :: String -> TextDocumentIdentifier -> Session (Either ResponseError WaitForIdeRuleResult)
188+
waitForAction key TextDocumentIdentifier{_uri} = do
189+
waitId <- sendRequest (CustomClientMethod "test") (WaitForIdeRule key _uri)
190+
ResponseMessage{_result} <- skipManyTill anyMessage $ responseForId waitId
191+
return _result

0 commit comments

Comments
 (0)