packages feed

hie-bios 0.14.0 → 0.15.0

raw patch · 29 files changed

+420/−196 lines, 29 filesdep ~optparse-applicativedep ~template-haskelldep ~textPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: optparse-applicative, template-haskell, text

API changes (from Hackage documentation)

- HIE.Bios.Config.YAML: [$sel:arguments:DirectConfig] :: DirectConfig -> [String]
- HIE.Bios.Config.YAML: [$sel:cabalComponent:CabalComponent] :: CabalComponent -> String
- HIE.Bios.Config.YAML: [$sel:cabalComponentProject:CabalComponent] :: CabalComponent -> Maybe FilePath
- HIE.Bios.Config.YAML: [$sel:cabalComponents:CabalConfig] :: CabalConfig -> OneOrManyComponents CabalComponent
- HIE.Bios.Config.YAML: [$sel:cabalPath:CabalComponent] :: CabalComponent -> FilePath
- HIE.Bios.Config.YAML: [$sel:cabalProject:CabalConfig] :: CabalConfig -> Maybe FilePath
- HIE.Bios.Config.YAML: [$sel:callable:BiosConfig] :: BiosConfig -> Callable
- HIE.Bios.Config.YAML: [$sel:config:MultiSubComponent] :: MultiSubComponent a -> CradleConfigYAML a
- HIE.Bios.Config.YAML: [$sel:cradle:CradleConfigYAML] :: CradleConfigYAML a -> CradleComponent a
- HIE.Bios.Config.YAML: [$sel:dependencies:CradleConfigYAML] :: CradleConfigYAML a -> Maybe [FilePath]
- HIE.Bios.Config.YAML: [$sel:depsCallable:BiosConfig] :: BiosConfig -> Maybe Callable
- HIE.Bios.Config.YAML: [$sel:ghcPath:BiosConfig] :: BiosConfig -> Maybe FilePath
- HIE.Bios.Config.YAML: [$sel:originalYamlValue:OtherConfig] :: OtherConfig a -> Value
- HIE.Bios.Config.YAML: [$sel:otherConfig:OtherConfig] :: OtherConfig a -> a
- HIE.Bios.Config.YAML: [$sel:path:MultiSubComponent] :: MultiSubComponent a -> FilePath
- HIE.Bios.Config.YAML: [$sel:stackComponent:StackComponent] :: StackComponent -> String
- HIE.Bios.Config.YAML: [$sel:stackComponentYAML:StackComponent] :: StackComponent -> Maybe FilePath
- HIE.Bios.Config.YAML: [$sel:stackComponents:StackConfig] :: StackConfig -> OneOrManyComponents StackComponent
- HIE.Bios.Config.YAML: [$sel:stackPath:StackComponent] :: StackComponent -> FilePath
- HIE.Bios.Config.YAML: [$sel:stackYaml:StackConfig] :: StackConfig -> Maybe FilePath
+ HIE.Bios: [cradleErrorLoadingFiles] :: CradleError -> [FilePath]
+ HIE.Bios.Config.YAML: [arguments] :: DirectConfig -> [String]
+ HIE.Bios.Config.YAML: [cabalComponentProject] :: CabalComponent -> Maybe FilePath
+ HIE.Bios.Config.YAML: [cabalComponent] :: CabalComponent -> String
+ HIE.Bios.Config.YAML: [cabalComponents] :: CabalConfig -> OneOrManyComponents CabalComponent
+ HIE.Bios.Config.YAML: [cabalPath] :: CabalComponent -> FilePath
+ HIE.Bios.Config.YAML: [cabalProject] :: CabalConfig -> Maybe FilePath
+ HIE.Bios.Config.YAML: [callable] :: BiosConfig -> Callable
+ HIE.Bios.Config.YAML: [config] :: MultiSubComponent a -> CradleConfigYAML a
+ HIE.Bios.Config.YAML: [cradle] :: CradleConfigYAML a -> CradleComponent a
+ HIE.Bios.Config.YAML: [dependencies] :: CradleConfigYAML a -> Maybe [FilePath]
+ HIE.Bios.Config.YAML: [depsCallable] :: BiosConfig -> Maybe Callable
+ HIE.Bios.Config.YAML: [ghcPath] :: BiosConfig -> Maybe FilePath
+ HIE.Bios.Config.YAML: [originalYamlValue] :: OtherConfig a -> Value
+ HIE.Bios.Config.YAML: [otherConfig] :: OtherConfig a -> a
+ HIE.Bios.Config.YAML: [path] :: MultiSubComponent a -> FilePath
+ HIE.Bios.Config.YAML: [stackComponentYAML] :: StackComponent -> Maybe FilePath
+ HIE.Bios.Config.YAML: [stackComponent] :: StackComponent -> String
+ HIE.Bios.Config.YAML: [stackComponents] :: StackConfig -> OneOrManyComponents StackComponent
+ HIE.Bios.Config.YAML: [stackPath] :: StackComponent -> FilePath
+ HIE.Bios.Config.YAML: [stackYaml] :: StackConfig -> Maybe FilePath
+ HIE.Bios.Cradle: data ProgramVersions
+ HIE.Bios.Cradle: instance GHC.Show.Show HIE.Bios.Cradle.CradleProjectConfig
+ HIE.Bios.Cradle: isCabalMultipleCompSupported :: MonadIO m => ProgramVersions -> m Bool
+ HIE.Bios.Cradle: makeVersions :: LogAction IO (WithSeverity Log) -> FilePath -> ([String] -> IO (CradleLoadResult String)) -> IO ProgramVersions
+ HIE.Bios.Types: LogCabalLoad :: !FilePath -> !Maybe String -> ![FilePath] -> ![FilePath] -> Log
+ HIE.Bios.Types: LogCabalPath :: !Text -> Log
+ HIE.Bios.Types: [cradleErrorLoadingFiles] :: CradleError -> [FilePath]
- HIE.Bios: CradleError :: [FilePath] -> ExitCode -> [String] -> CradleError
+ HIE.Bios: CradleError :: [FilePath] -> ExitCode -> [String] -> [FilePath] -> CradleError
- HIE.Bios.Cradle: makeCradleResult :: (ExitCode, [String], FilePath, [String]) -> [FilePath] -> CradleLoadResult ComponentOptions
+ HIE.Bios.Cradle: makeCradleResult :: (ExitCode, [String], FilePath, [String]) -> [FilePath] -> [FilePath] -> CradleLoadResult ComponentOptions
- HIE.Bios.Ghc.Api: data () => SuccessFlag
+ HIE.Bios.Ghc.Api: data SuccessFlag
- HIE.Bios.Ghc.Gap: data () => FrontendResult
+ HIE.Bios.Ghc.Gap: data FrontendResult
- HIE.Bios.Ghc.Gap: data () => Hsc a
+ HIE.Bios.Ghc.Gap: data Hsc a
- HIE.Bios.Ghc.Gap: data () => PprStyle
+ HIE.Bios.Ghc.Gap: data PprStyle
- HIE.Bios.Ghc.Gap: data () => Session
+ HIE.Bios.Ghc.Gap: data Session
- HIE.Bios.Ghc.Gap: parseDynamicFlags :: MonadIO m => Logger -> DynFlags -> [Located String] -> m (DynFlags, [Located String], [Warn])
+ HIE.Bios.Ghc.Gap: parseDynamicFlags :: MonadIO m => Logger -> DynFlags -> [Located String] -> m (DynFlags, [Located String], Messages DriverMessage)
- HIE.Bios.Types: CradleError :: [FilePath] -> ExitCode -> [String] -> CradleError
+ HIE.Bios.Types: CradleError :: [FilePath] -> ExitCode -> [String] -> [FilePath] -> CradleError
- HIE.Bios.Types: CradleLoadResultT :: m (CradleLoadResult a) -> CradleLoadResultT m a
+ HIE.Bios.Types: CradleLoadResultT :: m (CradleLoadResult a) -> CradleLoadResultT (m :: Type -> Type) a
- HIE.Bios.Types: [runCradleResultT] :: CradleLoadResultT m a -> m (CradleLoadResult a)
+ HIE.Bios.Types: [runCradleResultT] :: CradleLoadResultT (m :: Type -> Type) a -> m (CradleLoadResult a)
- HIE.Bios.Types: newtype CradleLoadResultT m a
+ HIE.Bios.Types: newtype CradleLoadResultT (m :: Type -> Type) a
- HIE.Bios.Types: throwCE :: Monad m => CradleError -> CradleLoadResultT m a
+ HIE.Bios.Types: throwCE :: forall (m :: Type -> Type) a. Monad m => CradleError -> CradleLoadResultT m a

Files

ChangeLog.md view
@@ -1,5 +1,17 @@ # ChangeLog hie-bios +## 2025-04-25 - 0.15.0++* Use consistent logging for test cases [#461](https://github.com/haskell/hie-bios/pull/461)+* Use cabal path when available [#458](https://github.com/haskell/hie-bios/pull/458)+* Keep track of not loaded files for cabal [#453](https://github.com/haskell/hie-bios/pull/453)+* Allow GHC 9.12 [#449](https://github.com/haskell/hie-bios/pull/449)+* Fix cabal check [#448](https://github.com/haskell/hie-bios/pull/448)++## 2024-05-20 - 0.14.1++* Allow building with GHC 9.10.1 [#435](https://github.com/haskell/hie-bios/pull/435)+ ## 2024-04-22 - 0.14.0  * Add Loading Style option to 'runAction' [#433](https://github.com/haskell/hie-bios/pull/433)
exe/Main.hs view
@@ -87,7 +87,7 @@           res <- forM files $ \fp -> do                   res <- getCompilerOptions fp LoadFile cradle                   case res of-                      CradleFail (CradleError _deps _ex err) ->+                      CradleFail (CradleError _deps _ex err _fps) ->                         return $ "Failed to show flags for \""                                                   ++ fp                                                   ++ "\": " ++ show err
hie-bios.cabal view
@@ -1,6 +1,6 @@ Cabal-Version:          2.2 Name:                   hie-bios-Version:                0.14.0+Version:                0.15.0 Author:                 Matthew Pickering <matthewtpickering@gmail.com> Maintainer:             Matthew Pickering <matthewtpickering@gmail.com> License:                BSD-3-Clause@@ -22,11 +22,11 @@                         tests/projects/cabal-with-ghc/hie.yaml                         tests/projects/cabal-with-ghc/src/MyLib.hs                         tests/projects/cabal-with-ghc-and-project/cabal-with-ghc.cabal-                        tests/projects/cabal-with-ghc-and-project/cabal.project.8.10.7+                        tests/projects/cabal-with-ghc-and-project/cabal.project.9.2.8                         tests/projects/cabal-with-ghc-and-project/hie.yaml                         tests/projects/cabal-with-ghc-and-project/src/MyLib.hs                         tests/projects/cabal-with-project/cabal-with-project.cabal-                        tests/projects/cabal-with-project/cabal.project.8.10.7+                        tests/projects/cabal-with-project/cabal.project.9.2.8                         tests/projects/cabal-with-project/hie.yaml                         tests/projects/cabal-with-project/src/MyLib.hs                         tests/projects/symlink-test/a/A.hs@@ -47,7 +47,7 @@                         tests/projects/multi-cabal-with-project/appA/src/Lib.hs                         tests/projects/multi-cabal-with-project/appB/appB.cabal                         tests/projects/multi-cabal-with-project/appB/src/Lib.hs-                        tests/projects/multi-cabal-with-project/cabal.project.8.10.7+                        tests/projects/multi-cabal-with-project/cabal.project.9.2.8                         tests/projects/multi-cabal-with-project/hie.yaml                         tests/projects/monorepo-cabal/cabal.project                         tests/projects/monorepo-cabal/hie.yaml@@ -138,8 +138,13 @@                         tests/projects/stack-with-yaml/hie.yaml                         tests/projects/stack-with-yaml/stack-with-yaml.cabal                         tests/projects/stack-with-yaml/src/Lib.hs+                        tests/projects/failing-multi-repl-cabal-project/multi-repl-cabal-fail/app/Main.hs+                        tests/projects/failing-multi-repl-cabal-project/multi-repl-cabal-fail/multi-repl-cabal-fail.cabal+                        tests/projects/failing-multi-repl-cabal-project/multi-repl-cabal-fail/src/Fail.hs+                        tests/projects/failing-multi-repl-cabal-project/multi-repl-cabal-fail/src/Lib.hs+                        tests/projects/failing-multi-repl-cabal-project/NotInPath.hs -tested-with: GHC ==9.2.8 || ==9.4.8 || ==9.6.4 || ==9.8.2+tested-with: GHC ==9.4.8 || ==9.6.7 || ==9.8.4 || ==9.10.1 || ==9.12.2  Library   Default-Language:     Haskell2010@@ -173,13 +178,13 @@                         cryptohash-sha1      >= 0.11.100 && < 0.12,                         directory            >= 1.3.0 && < 1.4,                         filepath             >= 1.4.1 && < 1.6,-                        time                 >= 1.8.0 && < 1.14,-                        extra                >= 1.6.14 && < 1.8,+                        time                 >= 1.8.0 && < 1.15,+                        extra                >= 1.6.14 && < 1.9,                         prettyprinter        ^>= 1.6 || ^>= 1.7.0,-                        ghc                  >= 9.2.1 && < 9.9,+                        ghc                  >= 9.2.1 && < 9.13,                         transformers         >= 0.5.2 && < 0.7,                         temporary            >= 1.2 && < 1.4,-                        template-haskell,+                        template-haskell     >= 2.18 && <2.24,                         text                 >= 1.2.3 && < 2.2,                         unix-compat          >= 0.5.1 && < 0.8,                         unordered-containers >= 0.2.9 && < 0.3,@@ -193,6 +198,7 @@   Default-Language:     Haskell2010   Main-Is:              Main.hs   Other-Modules:        Paths_hie_bios+  autogen-modules:      Paths_hie_bios   GHC-Options:          -Wall   HS-Source-Dirs:       exe   Build-Depends:        base >= 4.16 && < 5@@ -200,7 +206,7 @@                       , directory                       , filepath                       , hie-bios-                      , optparse-applicative+                      , optparse-applicative >= 0.18.1 && < 0.19                       , prettyprinter  test-suite parser-tests@@ -235,6 +241,7 @@       directory,       prettyprinter,       temporary,+      text,       ghc    hs-source-dirs: tests/@@ -244,4 +251,4 @@  Source-Repository head   Type:                 git-  Location:             git://github.com/mpickering/hie-bios.git+  Location:             https://github.com/haskell/hie-bios.git
src/HIE/Bios/Cradle.hs view
@@ -25,10 +25,14 @@     , makeCradleResult     -- | Cradle project configuration types     , CradleProjectConfig(..)++    -- expose to tests+    , makeVersions+    , isCabalMultipleCompSupported+    , ProgramVersions   ) where  import Control.Applicative ((<|>), optional)-import Data.Bifunctor (first) import Control.DeepSeq import Control.Exception (handleJust) import qualified Data.Yaml as Yaml@@ -42,6 +46,11 @@ import Control.Monad.Trans.Cont import Control.Monad.Trans.Maybe import Control.Monad.IO.Class+import Data.Aeson ((.:))+import qualified Data.Aeson as Aeson+import qualified Data.Aeson.Types as Aeson+import Data.Bifunctor (first)+import qualified Data.ByteString as BS import Data.Conduit.Process import qualified Data.Conduit.Combinators as C import qualified Data.Conduit as C@@ -49,9 +58,10 @@ import qualified Data.HashMap.Strict as Map import Data.Maybe (fromMaybe, maybeToList) import Data.List-import Data.List.Extra (trimEnd)+import Data.List.Extra (trimEnd, nubOrd) import Data.Ord (Down(..)) import qualified Data.Text as T+import qualified Data.Text.Encoding as T import System.Environment import System.FilePath import System.PosixCompat.Files@@ -73,6 +83,7 @@ import Data.Version import Data.IORef import Text.ParserCombinators.ReadP (readP_to_S)+import Data.Tuple.Extra (fst3, snd3, thd3)  ---------------------------------------------------------------- @@ -129,6 +140,7 @@   | ConcreteOther a   deriving Show + -- | ConcreteCradle augmented with information on which file the -- cradle applies data ResolvedCradle a@@ -243,7 +255,7 @@           case selectCradle (prefix . fst) absfp cradleActions of             Just (rc, act) -> do               addActionDeps (cradleDeps rc) <$> runCradle act fp prev-            Nothing -> return $ CradleFail $ CradleError [] ExitSuccess (err_msg fp)+            Nothing -> return $ CradleFail $ CradleError [] ExitSuccess (err_msg fp) [fp]       , runGhcCmd = run_ghc_cmd       }     }@@ -518,7 +530,7 @@         -- delimited by newlines.         -- Execute the bios action and add dependencies of the cradle.         -- Removes all duplicates.-  return $ makeCradleResult (ex, std, wdir, fromMaybe [] res) deps+  return $ makeCradleResult (ex, std, wdir, fromMaybe [] res) deps [fp]  callableToProcess :: Callable -> Maybe String -> IO CreateProcess callableToProcess (Command shellCommand) file = do@@ -547,13 +559,17 @@     { actionName = Types.Cabal     , runCradle = \fp -> runCradleResultT . cabalAction cs wdir mc l projectFile fp     , runGhcCmd = \args -> runCradleResultT $ do-        buildDir <- liftIO $ cabalBuildDir wdir-        -- Workaround for a cabal-install bug on 3.0.0.0:-        -- ./dist-newstyle/tmp/environment.-24811: createDirectory: does not exist (No such file or directory)-        liftIO $ createDirectoryIfMissing True (buildDir </> "tmp")-        -- Need to pass -v0 otherwise we get "resolving dependencies..."-        cabalProc <- cabalProcess l projectFile wdir "v2-exec" $ ["ghc", "-v0", "--"] ++ args-        readProcessWithCwd' l cabalProc ""+        let vs = cradleProgramVersions cs+        callCabalPathForCompilerPath l vs wdir projectFile >>= \case+          Just p -> readProcessWithCwd_ l wdir p args ""+          Nothing -> do+            buildDir <- liftIO $ cabalBuildDir wdir+            -- Workaround for a cabal-install bug on 3.0.0.0:+            -- ./dist-newstyle/tmp/environment.-24811: createDirectory: does not exist (No such file or directory)+            liftIO $ createDirectoryIfMissing True (buildDir </> "tmp")+            -- Need to pass -v0 otherwise we get "resolving dependencies..."+            cabalProc <- cabalProcess l vs projectFile wdir "v2-exec" $ ["ghc", "-v0", "--"] ++ args+            readProcessWithCwd' l cabalProc ""     }  @@ -566,11 +582,19 @@ -- to the custom ghc wrapper via 'hie_bios_ghc' environment variable which -- the custom ghc wrapper may use as a fallback if it can not respond to certain -- queries, such as ghc version or location of the libdir.-cabalProcess :: LogAction IO (WithSeverity Log) -> CradleProjectConfig -> FilePath -> String -> [String] -> CradleLoadResultT IO CreateProcess-cabalProcess l cabalProject workDir command args = do-  ghcDirs <- cabalGhcDirs l cabalProject workDir+cabalProcess :: LogAction IO (WithSeverity Log) -> ProgramVersions -> CradleProjectConfig -> FilePath -> String -> [String] -> CradleLoadResultT IO CreateProcess+cabalProcess l vs cabalProject workDir command args = do+  (ghcDirs, ghcPkgPath) <- callCabalPathForCompilerPath l vs workDir cabalProject >>= \case+    Just p -> do+      libdir <- readProcessWithCwd_ l workDir p ["--print-libdir"] ""+      pure ((p, trimEnd libdir), Nothing)+    Nothing -> do+      ghcDirs@(ghcBin, libdir) <- cabalGhcDirs l cabalProject workDir+      ghcPkgPath <- liftIO $ withGhcPkgTool ghcBin libdir+      pure (ghcDirs, Just ghcPkgPath)+   newEnvironment <- liftIO $ setupEnvironment ghcDirs-  cabalProc <- liftIO $ setupCabalCommand ghcDirs+  cabalProc <- liftIO $ setupCabalCommand ghcPkgPath   pure $ (cabalProc       { env = Just newEnvironment       , cwd = Just workDir@@ -585,17 +609,21 @@       environment <- getCleanEnvironment       pure $ processEnvironment ghcDirs ++ environment -    setupCabalCommand :: (FilePath, FilePath) -> IO CreateProcess-    setupCabalCommand (ghcBin, libdir) = do+    setupCabalCommand :: Maybe FilePath -> IO CreateProcess+    setupCabalCommand ghcPkgPath = do       wrapper_fp <- withGhcWrapperTool l ("ghc", []) workDir       buildDir <- cabalBuildDir workDir-      ghcPkgPath <- withGhcPkgTool ghcBin libdir-      let extraCabalArgs =+      let hcPkgArgs = case ghcPkgPath of+            Nothing -> []+            Just p -> ["--with-hc-pkg", p]++          extraCabalArgs =             [ "--builddir=" <> buildDir             , command             , "--with-compiler", wrapper_fp-            , "--with-hc-pkg", ghcPkgPath-            ] <> projectFileProcessArgs cabalProject+            ]+            <> hcPkgArgs+            <> projectFileProcessArgs cabalProject       pure $ proc "cabal" (extraCabalArgs ++ args)  -- | Discovers the location of 'ghc-pkg' given the absolute path to 'ghc'@@ -788,6 +816,37 @@   where     projectFileArgs = projectFileProcessArgs cabalProject +callCabalPathForCompilerPath :: LogAction IO (WithSeverity Log) -> ProgramVersions -> FilePath -> CradleProjectConfig -> CradleLoadResultT IO (Maybe FilePath)+callCabalPathForCompilerPath l vs workDir projectFile = do+  isCabalPathSupported vs >>= \case+    False -> pure Nothing+    True -> do+      let+        args = ["path", "--output-format=json"] <> projectFileProcessArgs projectFile+        bs = BS.fromStrict . T.encodeUtf8 . T.pack+        parse_compiler_path = Aeson.parseEither ((.: "compiler") >=>  (.: "path")) <=< Aeson.eitherDecode++      compiler_info <- readProcessWithCwd_ l workDir "cabal" args ""+      case parse_compiler_path (bs compiler_info) of+        Left err -> do+          liftIO $ l <& WithSeverity (LogCabalPath $ T.pack err) Warning+          pure Nothing+        Right a -> pure a++isCabalPathSupported :: MonadIO m => ProgramVersions -> m Bool+isCabalPathSupported vs = do+  v <- liftIO $ runCachedIO $ cabalVersion vs+  pure $ maybe False (>= makeVersion [3,14]) v++isCabalMultipleCompSupported :: MonadIO m => ProgramVersions -> m Bool+isCabalMultipleCompSupported vs = do+  cabal_version <- liftIO $ runCachedIO $ cabalVersion vs+  ghc_version <- liftIO $ runCachedIO $ ghcVersion vs+  -- determine which load style is supported by this cabal cradle.+  case (cabal_version, ghc_version) of+    (Just cabal, Just ghc) -> pure $ ghc >= makeVersion [9, 4] && cabal >= makeVersion [3, 11]+    _ -> pure False+ cabalAction   :: ResolvedCradles a   -> FilePath@@ -798,67 +857,57 @@   -> LoadStyle   -> CradleLoadResultT IO ComponentOptions cabalAction (ResolvedCradles root cs vs) workDir mc l projectFile fp loadStyle = do-  cabal_version <- liftIO $ runCachedIO $ cabalVersion vs-  ghc_version   <- liftIO $ runCachedIO $ ghcVersion vs+  multiCompSupport <- isCabalMultipleCompSupported vs   -- determine which load style is supported by this cabal cradle.-  determinedLoadStyle <- case (cabal_version, ghc_version) of-    (Just cabal, Just ghc)-      -- Multi-component supported from cabal-install 3.11-      -- and ghc 9.4-      | LoadWithContext _ <- loadStyle ->-          if ghc >= makeVersion [9,4] && cabal >= makeVersion [3,11]-            then pure loadStyle-            else do-              liftIO $ l <& WithSeverity-                (LogLoadWithContextUnsupported "cabal"-                  $ Just "cabal or ghc version is too old. We require `cabal >= 3.11` and `ghc >= 9.4`"-                )-                Warning-              pure LoadFile-    _ -> pure LoadFile+  determinedLoadStyle <- case loadStyle of+    LoadWithContext _ | not multiCompSupport -> do+      liftIO $+        l+          <& WithSeverity+            ( LogLoadWithContextUnsupported "cabal" $+                Just "cabal or ghc version is too old. We require `cabal >= 3.11` and `ghc >= 9.4`"+            )+            Warning+      pure LoadFile+    _ -> pure loadStyle -  let cabalArgs = case determinedLoadStyle of-        LoadFile -> [fromMaybe (fixTargetPath fp) mc]-        LoadWithContext fps -> concat-          [ [ "--keep-temp-files"-            , "--enable-multi-repl"-            , fromMaybe (fixTargetPath fp) mc-            ]-          , [fromMaybe (fixTargetPath old_fp) old_mc-            | old_fp <- fps-            -- Lookup the component for the old file-            , Just (ResolvedCradle{concreteCradle = ConcreteCabal ct}) <- [selectCradle prefix old_fp cs]-            -- Only include this file if the old component is in the same project-            , (projectConfigFromMaybe root (cabalProjectFile ct)) == projectFile-            , let old_mc = cabalComponent ct-            ]-          ]+  let fpModule = fromMaybe (fixTargetPath fp) mc+  let (cabalArgs, loadingFiles, extraDeps) = case determinedLoadStyle of+        LoadFile -> ([fpModule], [fp], [])+        LoadWithContext fps ->+          let allModulesFpsDeps = ((fpModule, fp, []) : moduleFilesFromSameProject fps)+              allModules = nubOrd $ fst3 <$> allModulesFpsDeps+              allFiles = nubOrd $ snd3 <$> allModulesFpsDeps+              allFpsDeps = nubOrd $ concatMap thd3 allModulesFpsDeps+           in (["--keep-temp-files", "--enable-multi-repl"] ++ allModules, allFiles, allFpsDeps)    liftIO $ l <& LogComputedCradleLoadStyle "cabal" determinedLoadStyle `WithSeverity` Info+  liftIO $ l <& LogCabalLoad fp mc (prefix <$> cs) loadingFiles `WithSeverity` Debug -  let-    cabalCommand = "v2-repl"+  let cabalCommand = "v2-repl" -  cabalProc <- cabalProcess l projectFile workDir cabalCommand cabalArgs `modCradleError` \err -> do+  cabalProc <-+    cabalProcess l vs projectFile workDir cabalCommand cabalArgs `modCradleError` \err -> do       deps <- cabalCradleDependencies projectFile workDir workDir-      pure $ err { cradleErrorDependencies = cradleErrorDependencies err ++ deps }+      pure $ err {cradleErrorDependencies = cradleErrorDependencies err ++ deps}    (ex, output, stde, [(_, maybeArgs)]) <- liftIO $ readProcessWithOutputs [hie_bios_output] l workDir cabalProc   let args = fromMaybe [] maybeArgs    let errorDetails =-        ["Failed command: " <> prettyCmdSpec (cmdspec cabalProc)-        , unlines output-        , unlines stde-        , unlines $ args-        , "Process Environment:"]-        <> prettyProcessEnv cabalProc+        [ "Failed command: " <> prettyCmdSpec (cmdspec cabalProc),+          unlines output,+          unlines stde,+          unlines args,+          "Process Environment:"+        ]+          <> prettyProcessEnv cabalProc    when (ex /= ExitSuccess) $ do     deps <- liftIO $ cabalCradleDependencies projectFile workDir workDir     let cmd = show (["cabal", cabalCommand] <> cabalArgs)     let errorMsg = "Failed to run " <> cmd <> " in directory \"" <> workDir <> "\". Consult the logs for full command and error."-    throwCE (CradleError deps ex ([errorMsg] <> errorDetails))+    throwCE (CradleError deps ex ([errorMsg] <> errorDetails) loadingFiles)    case processCabalWrapperArgs args of     Nothing -> do@@ -866,16 +915,26 @@       -- Best effort. Assume the working directory is the       -- root of the component, so we are right in trivial cases at least.       deps <- liftIO $ cabalCradleDependencies projectFile workDir workDir-      throwCE (CradleError deps ex $ ["Failed to parse result of calling cabal" ] <> errorDetails)+      throwCE (CradleError (deps <> extraDeps) ex (["Failed to parse result of calling cabal"] <> errorDetails) loadingFiles)     Just (componentDir, final_args) -> do       deps <- liftIO $ cabalCradleDependencies projectFile workDir componentDir-      CradleLoadResultT $ pure $ makeCradleResult (ex, stde, componentDir, final_args) deps+      CradleLoadResultT $ pure $ makeCradleResult (ex, stde, componentDir, final_args) (deps <> extraDeps) loadingFiles   where     -- Need to make relative on Windows, due to a Cabal bug with how it-    -- parses file targets with a C: drive in it+    -- parses file targets with a C: drive in it. So we decide to make+    -- the paths relative to the working directory.     fixTargetPath x       | isWindows && hasDrive x = makeRelative workDir x       | otherwise = x+    moduleFilesFromSameProject fps =+      [ (fromMaybe (fixTargetPath file) old_mc, file, deps)+      | file <- fps,+        -- Lookup the component for the old file+        Just (ResolvedCradle {concreteCradle = ConcreteCabal ct, cradleDeps = deps}) <- [selectCradle prefix file cs],+        -- Only include this file if the old component is in the same project+        (projectConfigFromMaybe root (cabalProjectFile ct)) == projectFile,+        let old_mc = cabalComponent ct+      ]  removeInteractive :: [String] -> [String] removeInteractive = filter (/= "--interactive")@@ -928,7 +987,7 @@ data CradleProjectConfig   = NoExplicitConfig   | ExplicitConfig FilePath-  deriving Eq+  deriving (Eq, Show)  -- | Create an explicit project configuration. Expects a working directory -- followed by an optional name of the project configuration.@@ -987,7 +1046,7 @@   -> FilePath   -> LoadStyle   -> IO (CradleLoadResult ComponentOptions)-stackAction workDir mc syaml l _fp loadStyle = do+stackAction workDir mc syaml l fp loadStyle = do   logCradleHasNoSupportForLoadWithContext l loadStyle "stack"   let ghcProcArgs = ("stack", stackYamlProcessArgs syaml <> ["exec", "ghc", "--"])   -- Same wrapper works as with cabal@@ -1011,10 +1070,11 @@         -- the root of the component, so we are right in trivial cases at least.         deps <- stackCradleDependencies workDir workDir syaml         pure $ CradleFail-                  (CradleError deps ex1 $-                    [ "Failed to parse result of calling stack" ]+                  (CradleError deps ex1+                    ([ "Failed to parse result of calling stack" ]                     ++ stde-                    ++ args+                    ++ args)+                    [fp]                   )        Just (componentDir, ghc_args) -> do@@ -1025,6 +1085,7 @@                   , ghc_args ++ pkg_ghc_args                   )                   deps+                  [fp]  stackProcess :: CradleProjectConfig -> [String] -> CreateProcess stackProcess syaml args = proc "stack" $ stackYamlProcessArgs syaml <> args@@ -1217,10 +1278,10 @@   yes <- doesFileExist f   when yes (removeFile f) -makeCradleResult :: (ExitCode, [String], FilePath, [String]) -> [FilePath] -> CradleLoadResult ComponentOptions-makeCradleResult (ex, err, componentDir, gopts) deps =+makeCradleResult :: (ExitCode, [String], FilePath, [String]) -> [FilePath] -> [FilePath] -> CradleLoadResult ComponentOptions+makeCradleResult (ex, err, componentDir, gopts) deps loadingFiles =   case ex of-    ExitFailure _ -> CradleFail (CradleError deps ex err)+    ExitFailure _ -> CradleFail (CradleError deps ex err loadingFiles)     _ ->         let compOpts = ComponentOptions gopts componentDir deps         in CradleSuccess compOpts@@ -1252,11 +1313,13 @@   case mResult of     Just (ExitSuccess, stdo, _) -> pure stdo     Just (exitCode, stdo, stde) -> throwCE $-      CradleError [] exitCode $-        ["Error when calling " <> cmdString, stdo, stde] <> prettyProcessEnv createdProcess+      CradleError [] exitCode+        (["Error when calling " <> cmdString, stdo, stde] <> prettyProcessEnv createdProcess)+        []     Nothing -> throwCE $-      CradleError [] ExitSuccess $-        ["Couldn't execute " <> cmdString] <> prettyProcessEnv createdProcess+      CradleError [] ExitSuccess+        (["Couldn't execute " <> cmdString] <> prettyProcessEnv createdProcess)+        []  -- | Log that the cradle has no supported for loading with context, if and only if -- 'LoadWithContext' was requested.
src/HIE/Bios/Internal/Debug.hs view
@@ -48,11 +48,13 @@           , "Cradle:                " ++ crdl           , "Dependencies:          " ++ unwords deps           ]-      CradleFail (CradleError deps ext stderr) ->+      CradleFail (CradleError deps ext stderr extraFiles) ->         return ["Cradle failed to load"                , "Deps: " ++ show deps                , "Exit Code: " ++ show ext-               , "Stderr: " ++ unlines stderr]+               , "Stderr: " ++ unlines stderr+               , "Failed: " ++ unlines extraFiles+               ]       CradleNone ->         return ["No cradle"]   where
src/HIE/Bios/Types.hs view
@@ -99,6 +99,8 @@   | LogRequestedCradleLoadStyle !T.Text !LoadStyle   | LogComputedCradleLoadStyle !T.Text !LoadStyle   | LogLoadWithContextUnsupported !T.Text !(Maybe T.Text)+  | LogCabalLoad !FilePath !(Maybe String) ![FilePath] ![FilePath]+  | LogCabalPath !T.Text   deriving (Show)  instance Pretty Log where@@ -135,6 +137,14 @@         Nothing -> "."         Just reason -> ", because:" <+> pretty reason <> "."       <+> "Falling back loading to single file mode."+  pretty (LogCabalLoad file prefixes projectFile crs) =+    "Cabal Loading file" <+> pretty file+          <> line <> indent 4 "from project: " <+> pretty projectFile+          <> line <> indent 4 "with prefixes:" <+> pretty prefixes+          <> line <> indent 4 "with actual loading files:" <+> pretty crs+  pretty (LogCabalPath err) =+    "Could not parse json output of 'cabal path': "+      <> line <> indent 4 (pretty err)  -- | The 'LoadStyle' instructs a cradle on how to load a given file target. data LoadStyle@@ -266,6 +276,10 @@   , cradleErrorStderr :: [String]   -- ^ Standard error output that can be shown to users to explain   -- the loading error.+  , cradleErrorLoadingFiles :: [FilePath]+  -- ^ files that were attempted to be loaded by the cradle.+  -- This can be useful if we are loading multiple files at once,+  -- e.g. in a cabal cradle with the multi-repl feature.   }   deriving (Show, Eq) 
tests/BiosTests.hs view
@@ -19,7 +19,7 @@ import Data.List ( sort, isPrefixOf ) import Data.Typeable import System.Directory-import System.FilePath ((</>))+import System.FilePath ((</>), makeRelative) import System.Exit (ExitCode(ExitSuccess, ExitFailure)) import Control.Monad.Extra (unlessM) import qualified HIE.Bios.Ghc.Gap as Gap@@ -34,11 +34,24 @@ -- If you change this version, make sure to also update 'cabal.project' -- in 'tests\/projects\/cabal-with-ghc'. extraGhcVersion :: String-extraGhcVersion = "8.10.7"+extraGhcVersion = "9.2.8"  extraGhc :: String extraGhc = "ghc-" ++ extraGhcVersion +-- | To get all logs, run the tests via:+--+-- @+-- cabal run test:bios-tests --test-options="--debug"+-- @+--+-- or+--+-- @+-- TASTY_DEBUG=TRUE cabal test test:bios-tests+-- @+--+-- to avoid recompilation. main :: IO () main = do   writeStackYamlFiles@@ -46,7 +59,7 @@   cabalDep <- checkToolIsAvailable "cabal"   extraGhcDep <- checkToolIsAvailable extraGhc -  defaultMainWithIngredients (ignoreToolTests:defaultIngredients) $+  defaultMainWithIngredients (ignoreToolTests:verboseLogging:defaultIngredients) $     testGroup "Bios-tests"       [ testGroup "Find cradle" findCradleTests       , testGroup "Symlink" symbolicLinkTests@@ -60,7 +73,7 @@  symbolicLinkTests :: [TestTree] symbolicLinkTests =-  [ testCaseSteps "Can load base module" $ runTestEnv "./symlink-test" $ do+  [ biosTestCase "Can load base module" $ runTestEnv "./symlink-test" $ do       initCradle "doesNotExist.hs"       assertCradle isMultiCradle       step "Attempt to load symlinked module A"@@ -69,7 +82,7 @@         assertComponentOptions $ \opts ->           componentOptions opts `shouldMatchList` ["a"] <> argDynamic -  , testCaseSteps "Can load symlinked module" $ runTestEnv "./symlink-test" $ do+  , biosTestCase "Can load symlinked module" $ runTestEnv "./symlink-test" $ do       initCradle "doesNotExist.hs"       assertCradle isMultiCradle       step "Attempt to load symlinked module A"@@ -80,7 +93,7 @@         loadComponentOptions "./b/A.hs"         assertComponentOptions $ \opts ->           componentOptions opts `shouldMatchList` ["b"] <> argDynamic-  , testCaseSteps "Can not load symlinked module that is ignored" $ runTestEnv "./symlink-test" $ do+  , biosTestCase "Can not load symlinked module that is ignored" $ runTestEnv "./symlink-test" $ do       initCradle "doesNotExist.hs"       assertCradle isMultiCradle       step "Attempt to load symlinked module A"@@ -94,14 +107,14 @@  biosTestCases :: [TestTree] biosTestCases =-  [ testCaseSteps "failing-bios" $ runTestEnv "./failing-bios" $ do+  [ biosTestCase "failing-bios" $ runTestEnv "./failing-bios" $ do       initCradle "B.hs"       assertCradle isBiosCradle       loadComponentOptions "B.hs"       assertCradleError $ \CradleError {..} -> do         cradleErrorExitCode @?= ExitFailure 1         cradleErrorDependencies `shouldMatchList` ["hie.yaml"]-  , testCaseSteps "failing-bios-ghc" $ runTestEnv "./failing-bios-ghc" $ do+  , biosTestCase "failing-bios-ghc" $ runTestEnv "./failing-bios-ghc" $ do       initCradle "B.hs"       assertCradle isBiosCradle       loadRuntimeGhcVersion@@ -111,9 +124,9 @@         cradleErrorDependencies `shouldMatchList` []         length cradleErrorStderr @?= 1         "Couldn't execute myGhc" `isPrefixOf` head cradleErrorStderr @? "Error message should contain basic information"-  , testCaseSteps "simple-bios-shell" $ runTestEnv "./simple-bios-shell" $ do+  , biosTestCase "simple-bios-shell" $ runTestEnv "./simple-bios-shell" $ do       testDirectoryM isBiosCradle "B.hs"-  , testCaseSteps "simple-bios-shell-deps" $ runTestEnv "./simple-bios-shell" $ do+  , biosTestCase "simple-bios-shell-deps" $ runTestEnv "./simple-bios-shell" $ do       biosCradleDeps "B.hs" ["hie.yaml"]   ] <> concat [linuxTestCases | False] -- TODO(fendor), enable again   where@@ -126,26 +139,40 @@         deps @?= componentDependencies opts      linuxTestCases =-      [ testCaseSteps "simple-bios" $ runTestEnv "./simple-bios" $+      [ biosTestCase "simple-bios" $ runTestEnv "./simple-bios" $           testDirectoryM isBiosCradle "B.hs"-      , testCaseSteps "simple-bios-ghc" $ runTestEnv "./simple-bios-ghc" $+      , biosTestCase "simple-bios-ghc" $ runTestEnv "./simple-bios-ghc" $           testDirectoryM isBiosCradle  "B.hs"-      , testCaseSteps "simple-bios-deps" $ runTestEnv "./simple-bios" $ do+      , biosTestCase "simple-bios-deps" $ runTestEnv "./simple-bios" $ do           biosCradleDeps "B.hs" ["hie-bios.sh", "hie.yaml"]-      , testCaseSteps "simple-bios-deps-new" $ runTestEnv "./deps-bios-new" $ do+      , biosTestCase "simple-bios-deps-new" $ runTestEnv "./deps-bios-new" $ do           biosCradleDeps "B.hs" ["hie-bios.sh", "hie.yaml"]       ]  cabalTestCases :: ToolDependency -> [TestTree] cabalTestCases extraGhcDep =-  [ testCaseSteps "failing-cabal" $ runTestEnv "./failing-cabal" $ do+  [+    biosTestCase "failing-cabal" $ runTestEnv "./failing-cabal" $ do       cabalAttemptLoad "MyLib.hs"       assertCradleError (\CradleError {..} -> do         cradleErrorExitCode @?= ExitFailure 1         cradleErrorDependencies `shouldMatchList` ["failing-cabal.cabal", "cabal.project", "cabal.project.local"])-  , testCaseSteps "simple-cabal" $ runTestEnv "./simple-cabal" $ do+  , biosTestCase "failing-cabal-multi-repl-with-shrink-error-files" $ runTestEnv "./failing-multi-repl-cabal-project" $ do+      cabalAttemptLoadFiles "multi-repl-cabal-fail/app/Main.hs" ["multi-repl-cabal-fail/src/Lib.hs", "multi-repl-cabal-fail/src/Fail.hs", "NotInPath.hs"]+      root <- askRoot+      multiSupported <- isCabalMultipleCompSupported'+      if multiSupported+        then+          assertCradleError (\CradleError {..} -> do+            cradleErrorExitCode @?= ExitFailure 1+            cradleErrorDependencies `shouldMatchList` ["cabal.project","cabal.project.local","multi-repl-cabal-fail.cabal"]+            -- NotInPath.hs does not match the cradle for `app/Main.hs`, so it should not be tried.+            (makeRelative root <$> cradleErrorLoadingFiles) `shouldMatchList` ["multi-repl-cabal-fail/app/Main.hs","multi-repl-cabal-fail/src/Fail.hs","multi-repl-cabal-fail/src/Lib.hs"])+        else assertLoadSuccess >>= \ComponentOptions {} -> do+          return ()+  , biosTestCase "simple-cabal" $ runTestEnv "./simple-cabal" $ do       testDirectoryM isCabalCradle "B.hs"-  , testCaseSteps "nested-cabal" $ runTestEnv "./nested-cabal" $ do+  , biosTestCase "nested-cabal" $ runTestEnv "./nested-cabal" $ do       cabalAttemptLoad "sub-comp/Lib.hs"       assertComponentOptions $ \opts -> do         componentDependencies opts `shouldMatchList`@@ -153,7 +180,7 @@           , "cabal.project"           , "cabal.project.local"           ]-  , testCaseSteps "nested-cabal2" $ runTestEnv "./nested-cabal" $ do+  , biosTestCase "nested-cabal2" $ runTestEnv "./nested-cabal" $ do       cabalAttemptLoad "MyLib.hs"       assertComponentOptions $ \opts -> do         componentDependencies opts `shouldMatchList`@@ -161,24 +188,24 @@           , "cabal.project"           , "cabal.project.local"           ]-  , testCaseSteps "multi-cabal" $ runTestEnv "./multi-cabal" $ do+  , biosTestCase "multi-cabal" $ runTestEnv "./multi-cabal" $ do       {- tests if both components can be loaded -}       testDirectoryM isCabalCradle "app/Main.hs"       testDirectoryM isCabalCradle "src/Lib.hs"   , {- issue https://github.com/mpickering/hie-bios/issues/200 -}-    testCaseSteps "monorepo-cabal" $ runTestEnv "./monorepo-cabal" $ do+    biosTestCase "monorepo-cabal" $ runTestEnv "./monorepo-cabal" $ do       testDirectoryM isCabalCradle "A/Main.hs"       testDirectoryM isCabalCradle "B/MyLib.hs"   , testGroup "Implicit cradle tests" $-      [ testCaseSteps "implicit-cabal" $ runTestEnv "./implicit-cabal" $ do+      [ biosTestCase "implicit-cabal" $ runTestEnv "./implicit-cabal" $ do           testImplicitDirectoryM isCabalCradle "Main.hs"-      , testCaseSteps "implicit-cabal-no-project" $ runTestEnv "./implicit-cabal-no-project" $ do+      , biosTestCase "implicit-cabal-no-project" $ runTestEnv "./implicit-cabal-no-project" $ do           testImplicitDirectoryM isCabalCradle "Main.hs"-      , testCaseSteps "implicit-cabal-deep-project" $ runTestEnv "./implicit-cabal-deep-project" $ do+      , biosTestCase "implicit-cabal-deep-project" $ runTestEnv "./implicit-cabal-deep-project" $ do           testImplicitDirectoryM isCabalCradle "foo/Main.hs"       ]   , testGroupWithDependency extraGhcDep-    [ testCaseSteps "Appropriate ghc and libdir" $ runTestEnvLocal "./cabal-with-ghc" $ do+    [ biosTestCase "Appropriate ghc and libdir" $ runTestEnvLocal "./cabal-with-ghc" $ do         initCradle "src/MyLib.hs"         assertCradle isCabalCradle         loadRuntimeGhcLibDir@@ -187,14 +214,14 @@         assertGhcVersionIs extraGhcVersion     ]   , testGroup "Cabal cabalProject"-    [ testCaseSteps "cabal-with-project, options propagated" $ runTestEnv "cabal-with-project" $ do+    [ biosTestCase "cabal-with-project, options propagated" $ runTestEnv "cabal-with-project" $ do         opts <- cabalLoadOptions "src/MyLib.hs"         liftIO $ do           "-O2" `elem` componentOptions opts             @? "Options must contain '-O2'"-    , testCaseSteps "cabal-with-project, load" $ runTestEnv "cabal-with-project" $ do+    , biosTestCase "cabal-with-project, load" $ runTestEnv "cabal-with-project" $ do         testDirectoryM isCabalCradle "src/MyLib.hs"-    , testCaseSteps "multi-cabal-with-project, options propagated" $ runTestEnv "multi-cabal-with-project" $ do+    , biosTestCase "multi-cabal-with-project, options propagated" $ runTestEnv "multi-cabal-with-project" $ do         optsAppA <- cabalLoadOptions "appA/src/Lib.hs"         liftIO $ do           "-O2" `elem` componentOptions optsAppA@@ -203,11 +230,11 @@         liftIO $ do           "-O2" `notElem` componentOptions optsAppB             @? "Options must not contain '-O2'"-    , testCaseSteps "multi-cabal-with-project, load" $ runTestEnv "multi-cabal-with-project" $ do+    , biosTestCase "multi-cabal-with-project, load" $ runTestEnv "multi-cabal-with-project" $ do         testDirectoryM isCabalCradle "appB/src/Lib.hs"         testDirectoryM isCabalCradle "appB/src/Lib.hs"     , testGroupWithDependency extraGhcDep-      [ testCaseSteps "Honours extra ghc setting" $ runTestEnv "cabal-with-ghc-and-project" $ do+      [ biosTestCase "Honours extra ghc setting" $ runTestEnv "cabal-with-ghc-and-project" $ do           initCradle "src/MyLib.hs"           assertCradle isCabalCradle           loadRuntimeGhcLibDir@@ -224,6 +251,12 @@       assertCradle isCabalCradle       loadComponentOptions fp +    cabalAttemptLoadFiles :: FilePath -> [FilePath] -> TestM ()+    cabalAttemptLoadFiles fp fps = do+      initCradle fp+      assertCradle isCabalCradle+      loadComponentOptionsMultiStyle fp fps+     cabalLoadOptions :: FilePath -> TestM ComponentOptions     cabalLoadOptions fp = do       initCradle fp@@ -234,42 +267,42 @@ stackTestCases :: [TestTree] stackTestCases =   [ expectFailBecause "stack repl does not fail on an invalid cabal file" $-      testCaseSteps "failing-stack" $ runTestEnv "./failing-stack" $ do+      biosTestCase "failing-stack" $ runTestEnv "./failing-stack" $ do         stackAttemptLoad "src/Lib.hs"         assertCradleError $ \CradleError {..} -> do             cradleErrorExitCode @?= ExitFailure 1             cradleErrorDependencies `shouldMatchList` ["failing-stack.cabal", "stack.yaml", "package.yaml"]-  , testCaseSteps "simple-stack" $ runTestEnv "./simple-stack" $ do+  , biosTestCase "simple-stack" $ runTestEnv "./simple-stack" $ do       testDirectoryM isStackCradle "B.hs"-  , testCaseSteps "multi-stack" $ runTestEnv "./multi-stack" $ do {- tests if both components can be loaded -}+  , biosTestCase "multi-stack" $ runTestEnv "./multi-stack" $ do {- tests if both components can be loaded -}       testDirectoryM isStackCradle "app/Main.hs"       testDirectoryM isStackCradle "src/Lib.hs"-  , testCaseSteps "nested-stack" $ runTestEnv "./nested-stack" $ do+  , biosTestCase "nested-stack" $ runTestEnv "./nested-stack" $ do       stackAttemptLoad "sub-comp/Lib.hs"       assertComponentOptions $ \opts ->         componentDependencies opts `shouldMatchList` ["sub-comp" </> "sub-comp.cabal", "sub-comp" </> "package.yaml", "stack.yaml"]-  , testCaseSteps "nested-stack2" $ runTestEnv "./nested-stack" $ do+  , biosTestCase "nested-stack2" $ runTestEnv "./nested-stack" $ do       stackAttemptLoad "MyLib.hs"       assertComponentOptions $ \opts ->         componentDependencies opts `shouldMatchList` ["nested-stack.cabal", "package.yaml", "stack.yaml"]-  , testCaseSteps "stack-with-yaml" $ runTestEnv "./stack-with-yaml" $ do+  , biosTestCase "stack-with-yaml" $ runTestEnv "./stack-with-yaml" $ do       {- tests if both components can be loaded -}       testDirectoryM isStackCradle "app/Main.hs"       testDirectoryM isStackCradle "src/Lib.hs"-  , testCaseSteps "multi-stack-with-yaml" $ runTestEnv "./multi-stack-with-yaml" $ do+  , biosTestCase "multi-stack-with-yaml" $ runTestEnv "./multi-stack-with-yaml" $ do       {- tests if both components can be loaded -}       testDirectoryM isStackCradle "appA/src/Lib.hs"       testDirectoryM isStackCradle "appB/src/Lib.hs"   ,     -- Test for special characters in the path for parsing of the ghci-scripts.     -- Issue https://github.com/mpickering/hie-bios/issues/162-    testCaseSteps "space stack" $ runTestEnv "./space stack" $ do+    biosTestCase "space stack" $ runTestEnv "./space stack" $ do       testDirectoryM isStackCradle "A.hs"       testDirectoryM isStackCradle "B.hs"   , testGroup "Implicit cradle tests"-      [ testCaseSteps "implicit-stack" $ runTestEnv "./implicit-stack" $+      [ biosTestCase "implicit-stack" $ runTestEnv "./implicit-stack" $           testImplicitDirectoryM isStackCradle "Main.hs"-      , testCaseSteps "implicit-stack-multi" $ runTestEnv "./implicit-stack-multi" $ do+      , biosTestCase "implicit-stack-multi" $ runTestEnv "./implicit-stack-multi" $ do           testImplicitDirectoryM isStackCradle "Main.hs"           testImplicitDirectoryM isStackCradle "other-package/Main.hs"       ]@@ -283,9 +316,9 @@  directTestCases :: [TestTree] directTestCases =-  [ testCaseSteps "simple-direct" $ runTestEnv  "./simple-direct" $ do+  [ biosTestCase "simple-direct" $ runTestEnv  "./simple-direct" $ do       testDirectoryM isDirectCradle "B.hs"-  , testCaseSteps "multi-direct" $ runTestEnv "./multi-direct" $ do+  , biosTestCase "multi-direct" $ runTestEnv "./multi-direct" $ do       {- tests if both components can be loaded -}       testDirectoryM isMultiCradle "A.hs"       testDirectoryM isMultiCradle "B.hs"@@ -307,7 +340,7 @@   ]   where     cradleFileTest :: String -> FilePath -> FilePath -> Maybe FilePath -> TestTree-    cradleFileTest testName dir fpTarget result = testCaseSteps testName $ do+    cradleFileTest testName dir fpTarget result = biosTestCase testName $ do       runTestEnv dir $ do         findCradleForModuleM fpTarget result @@ -320,6 +353,12 @@  infix 1 `shouldMatchList` +biosTestCase :: TestName -> (Bool -> Assertion) -> TestTree+biosTestCase name assertion = askOption @VerboseLogging (\case+  VerboseLogging verbose -> testCase name (assertion verbose)+  )++ -- ------------------------------------------------------------------ -- Stack related helper functions -- ------------------------------------------------------------------@@ -350,10 +389,12 @@  stackYamlResolver :: String stackYamlResolver =-#if (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(9,8,0,0)))-  "nightly-2024-02-26" -- GHC 9.8.1+#if (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(9,10,0,0)))+  "nightly-2025-04-24" -- GHC 9.10.1+#elif (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(9,8,0,0)))+  "lts-23.19" -- GHC 9.8.4 #elif (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(9,6,0,0)))-  "lts-22.12" -- GHC 9.6.4+  "lts-22.43" -- GHC 9.6.6 #elif (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(9,4,0,0)))   "lts-21.25" -- GHC 9.4.8 #elif (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(9,2,0,0)))@@ -417,15 +458,28 @@ ignoreToolTests = Tasty.TestManager [Tasty.Option (Proxy :: Proxy IgnoreToolDeps)] $   \_opts _tree -> Nothing +newtype VerboseLogging = VerboseLogging Bool++instance Tasty.IsOption VerboseLogging where+  defaultValue = VerboseLogging False+  parseValue = fmap VerboseLogging . Tasty.safeReadBool+  optionName = pure "debug"+  optionHelp = pure "Run the tests with verbose logging"+  optionCLParser = Tasty.flagCLParser Nothing (VerboseLogging True)++-- | The ingredient that provides the "ignore missing run-time dependencies" functionality+verboseLogging :: Tasty.Ingredient+verboseLogging = Tasty.TestManager [Tasty.Option (Proxy :: Proxy VerboseLogging)] $+  \_opts _tree -> Nothing+ -- --------------------------------------------------------------------- Ignore test group if built with GHC 9.2.1 until GHC 9.2.4--- or GHC 9.8.1 or newer.+-- Ignore test group if built with GHC 9.6.7 and GHC 9.12.2 -- ------------------------------------------------------------------  ignoreOnUnsupportedGhc :: TestTree -> TestTree ignoreOnUnsupportedGhc tt =-#if (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(9,2,1,0) && !MIN_VERSION_GLASGOW_HASKELL(9,2,4,0)) || (MIN_VERSION_GLASGOW_HASKELL(9,8,1,0)))-  ignoreTestBecause "Not supported on GHC >= 9.2.1 && < 9.2.4 || >= 9.8.1"+#if (defined(MIN_VERSION_GLASGOW_HASKELL) && (MIN_VERSION_GLASGOW_HASKELL(9,6,7,0) && !MIN_VERSION_GLASGOW_HASKELL(9,6,8,0)) || (MIN_VERSION_GLASGOW_HASKELL(9,12,2,0) && !MIN_VERSION_GLASGOW_HASKELL(9,12,3,0)))+  ignoreTestBecause "Not supported on 9.6.7 and 9.12.2" #endif   tt 
tests/ParserTests.hs view
@@ -62,11 +62,11 @@                                                                                ,("./tests", StackType (Just "parser-tests") Nothing)]))]))     -- Assertions for cabal.project files     assertParser "cabal-with-project.yaml"-      (noDeps (Cabal $ CabalType Nothing (Just "cabal.project.8.10.7")))+      (noDeps (Cabal $ CabalType Nothing (Just "cabal.project.9.2.8")))     assertParser "cabal-with-both.yaml"-      (noDeps (Cabal $ CabalType (Just "hie-bios:hie") (Just "cabal.project.8.10.7")))+      (noDeps (Cabal $ CabalType (Just "hie-bios:hie") (Just "cabal.project.9.2.8")))     assertParser "multi-cabal-with-project.yaml"-      (noDeps (CabalMulti (CabalType Nothing (Just "cabal.project.8.10.7"))+      (noDeps (CabalMulti (CabalType Nothing (Just "cabal.project.9.2.8"))                           [("./src", CabalType (Just "lib:hie-bios") Nothing)                           ,("./vendor", CabalType (Just "parser-tests") Nothing)]))     -- Assertions for stack.yaml files
tests/Utils.hs view
@@ -26,6 +26,7 @@   -- * Ask for test environment   askRoot,   askStep,+  askLogger,   askCradle,   askLoadResult,   askOrLoadLibDir,@@ -42,10 +43,12 @@   initCradle,   initImplicitCradle,   loadComponentOptions,+  loadComponentOptionsMultiStyle,   loadRuntimeGhcLibDir,   loadRuntimeGhcVersion,   inCradleRootDir,   loadFileGhc,+  isCabalMultipleCompSupported',    -- * Assertion helpers   assertCradle,@@ -80,12 +83,15 @@ import HIE.Bios.Ghc.Api import qualified HIE.Bios.Ghc.Gap as G import HIE.Bios.Ghc.Load-import HIE.Bios.Types+import HIE.Bios.Types as HIE import Prettyprinter import System.Directory import System.FilePath import System.IO.Temp import Test.Tasty.HUnit+import Colog.Core+import qualified Data.Text as Text+import Data.Function ((&))  -- --------------------------------------------------------------------------- -- Test configuration and information@@ -96,6 +102,7 @@ data TestConfig = TestConfig   { useTemporaryDirectory :: Bool   , testProjectRoots :: FilePath+  , testVerbose :: Bool   }   deriving (Eq, Show, Ord) @@ -105,20 +112,20 @@   , testLibDirResult :: Maybe (CradleLoadResult FilePath)   , testGhcVersionResult :: Maybe (CradleLoadResult String)   , testRootDir :: FilePath-  , testStepFunction :: String -> IO ()+  , testLogger :: L.LogAction IO (L.WithSeverity HIE.Log)   }  defConfig :: TestConfig-defConfig = TestConfig True "./tests/projects"+defConfig = TestConfig True "./tests/projects" False -runTestEnv :: FilePath -> TestM a -> (String -> IO ()) -> IO a-runTestEnv = runTestEnv' defConfig+runTestEnv :: FilePath -> TestM a -> Bool -> IO a+runTestEnv fp act verbose = runTestEnv' defConfig{testVerbose=verbose} fp act -runTestEnvLocal :: FilePath -> TestM a -> (String -> IO ()) -> IO a-runTestEnvLocal = runTestEnv' defConfig{useTemporaryDirectory = False}+runTestEnvLocal :: FilePath -> TestM a -> Bool -> IO a+runTestEnvLocal fp act verbose = runTestEnv' defConfig{useTemporaryDirectory = False,testVerbose=verbose} fp act -runTestEnv' :: TestConfig -> FilePath -> TestM a -> (String -> IO ()) -> IO a-runTestEnv' config root act stepF = do+runTestEnv' :: TestConfig -> FilePath -> TestM a -> IO a+runTestEnv' config root act = do   -- We need to copy over the directory to somewhere outside the source tree   -- when we test, since the cabal.project/stack.yaml/hie.yaml file in the root   -- of this repository interferes with the test cradles!@@ -133,12 +140,17 @@           , testLibDirResult = Nothing           , testGhcVersionResult = Nothing           , testRootDir = root'-          , testStepFunction = stepF+          , testLogger = init_logger           }       realRoot = testProjectRoots config </> root   wrapper realRoot $ \root' -> flip evalStateT (mkEnv root') $ do     step $ "Run test in: " <> root'     act+  where+    init_logger = L.logStringStderr+      & L.cmap printLog+      & L.filterBySeverity (if testVerbose config then Debug else Error) getSeverity+    printLog (L.WithSeverity l sev) = "[" ++ show sev ++ "] " ++ show (pretty l)  -- --------------------------------------------------------------------------- -- Modification helpers@@ -170,7 +182,10 @@ askRoot = gets testRootDir  askStep :: TestM (String -> IO ())-askStep = gets testStepFunction+askStep = do+  logger <- gets testLogger+  pure $ \s ->+    logger <& LogAny (Text.pack s) `WithSeverity` Info  askCradle :: TestM (Cradle Void) askCradle =@@ -225,13 +240,16 @@         assertFailure           "No GHC version set, use 'loadRuntimeGhcVersion' before asking for it" +askLogger :: TestM (L.LogAction IO (L.WithSeverity HIE.Log))+askLogger = gets testLogger+ -- --------------------------------------------------------------------------- -- Test setup helpers -- ---------------------------------------------------------------------------  step :: String -> TestM () step msg = do-  s <- gets testStepFunction+  s <- askStep   liftIO $ s msg  normFile :: FilePath -> TestM FilePath@@ -252,16 +270,18 @@   mcfg <- findCradleLoc a_fp   relMcfg <- traverse relFile mcfg   step $ "Loading Cradle: " <> show relMcfg+  logger <- askLogger   crd <- case mcfg of-    Just cfg -> liftIO $ loadCradle testLogger cfg-    Nothing -> liftIO $ loadImplicitCradle testLogger a_fp+    Just cfg -> liftIO $ loadCradle logger cfg+    Nothing -> liftIO $ loadImplicitCradle logger a_fp   setCradle crd  initImplicitCradle :: FilePath -> TestM () initImplicitCradle fp = do   a_fp <- normFile fp   step $ "Loading implicit Cradle for: " <> fp-  crd <- liftIO $ loadImplicitCradle testLogger a_fp+  logger <- askLogger+  crd <- liftIO $ loadImplicitCradle logger a_fp   setCradle crd  loadComponentOptions :: FilePath -> TestM ()@@ -272,6 +292,15 @@   clr <- liftIO $ getCompilerOptions a_fp LoadFile crd   setLoadResult clr +loadComponentOptionsMultiStyle :: FilePath -> [FilePath] -> TestM ()+loadComponentOptionsMultiStyle fp fps = do+  a_fp <- normFile fp+  a_fps <- mapM normFile fps+  crd <- askCradle+  step $ "Initialise flags for: " <> fp <> " and " <> show fps+  clr <- liftIO $ getCompilerOptions a_fp (LoadWithContext a_fps) crd+  setLoadResult clr+ loadRuntimeGhcLibDir :: TestM () loadRuntimeGhcLibDir = do   crd <- askCradle@@ -286,9 +315,12 @@   ghcVersionRes <- liftIO $ getRuntimeGhcVersion crd   setGhcVersionResult ghcVersionRes -testLogger :: forall a . Pretty a => L.LogAction IO (L.WithSeverity a)-testLogger = L.cmap printLog L.logStringStderr-  where printLog (L.WithSeverity l sev) = "[" ++ show sev ++ "] " ++ show (pretty l)+isCabalMultipleCompSupported' :: TestM Bool+isCabalMultipleCompSupported' = do+  cr <- askCradle+  root <- askRoot+  versions <- liftIO $ makeVersions (cradleLogger cr) root ((runGhcCmd . cradleOptsProg) cr)+  liftIO $ isCabalMultipleCompSupported versions  inCradleRootDir :: TestM a -> TestM a inCradleRootDir act = do@@ -380,7 +412,7 @@ assertCradleLoadSuccess = \case   (CradleSuccess x) -> pure x   CradleNone -> liftIO $ assertFailure "Unexpected none-Cradle"-  (CradleFail (CradleError _deps _ex stde)) ->+  (CradleFail (CradleError _deps _ex stde _err_loading_files)) ->     liftIO $ assertFailure ("Unexpected cradle fail" <> unlines stde)  assertCradleLoadError :: CradleLoadResult a -> TestM CradleError
tests/configs/cabal-with-both.yaml view
@@ -1,4 +1,4 @@ cradle:   cabal:-    cabalProject: "cabal.project.8.10.7"+    cabalProject: "cabal.project.9.2.8"     component: "hie-bios:hie"
tests/configs/cabal-with-project.yaml view
@@ -1,3 +1,3 @@ cradle:   cabal:-    cabalProject: "cabal.project.8.10.7"+    cabalProject: "cabal.project.9.2.8"
tests/configs/multi-cabal-with-project.yaml view
@@ -1,6 +1,6 @@ cradle:   cabal:-    cabalProject: "cabal.project.8.10.7"+    cabalProject: "cabal.project.9.2.8"     components:       - path: "./src"         component: "lib:hie-bios"
− tests/projects/cabal-with-ghc-and-project/cabal.project.8.10.7
@@ -1,12 +0,0 @@-packages: .---- It is intended that this ghc version is different to at least one ghc version--- that is tested in CI.------ Project validates that hie-bios honours this field.------ If you change this, make sure to also change the 'extraGhc' constant in--- 'tests/BiosTests.hs'.------ Additionally, CI needs a proper setup to execute this test-case.-with-compiler: ghc-8.10.7
+ tests/projects/cabal-with-ghc-and-project/cabal.project.9.2.8 view
@@ -0,0 +1,12 @@+packages: .++-- It is intended that this ghc version is different to at least one ghc version+-- that is tested in CI.+--+-- Project validates that hie-bios honours this field.+--+-- If you change this, make sure to also change the 'extraGhc' constant in+-- 'tests/BiosTests.hs'.+--+-- Additionally, CI needs a proper setup to execute this test-case.+with-compiler: ghc-9.2.8
tests/projects/cabal-with-ghc-and-project/hie.yaml view
@@ -1,3 +1,3 @@ cradle:   cabal:-    cabalProject: cabal.project.8.10.7+    cabalProject: cabal.project.9.2.8
tests/projects/cabal-with-ghc/cabal.project view
@@ -9,4 +9,4 @@ -- 'tests/BiosTests.hs'. -- -- Additionally, CI needs a proper setup to execute this test-case.-with-compiler: ghc-8.10.7+with-compiler: ghc-9.2.8
− tests/projects/cabal-with-project/cabal.project.8.10.7
@@ -1,5 +0,0 @@--- Test file.-packages: ./--package cabal-with-project-    ghc-options: -O2
+ tests/projects/cabal-with-project/cabal.project.9.2.8 view
@@ -0,0 +1,5 @@+-- Test file.+packages: ./++package cabal-with-project+    ghc-options: -O2
tests/projects/cabal-with-project/hie.yaml view
@@ -1,3 +1,3 @@ cradle:   cabal:-    cabalProject: cabal.project.8.10.7+    cabalProject: cabal.project.9.2.8
+ tests/projects/failing-multi-repl-cabal-project/NotInPath.hs view
@@ -0,0 +1,5 @@+module NotInPath where++import System.FilePath ((</>))++foo = "test" </> "me"
+ tests/projects/failing-multi-repl-cabal-project/multi-repl-cabal-fail/app/Main.hs view
@@ -0,0 +1,4 @@++import System.Directory (getCurrentDirectory)++main = return ()
+ tests/projects/failing-multi-repl-cabal-project/multi-repl-cabal-fail/multi-repl-cabal-fail.cabal view
@@ -0,0 +1,21 @@+cabal-version:       >=2.0+name:                multi-cabal+version:             0.1.0.0+build-type:          Simple++library+  exposed-modules: Lib+  -- other-modules:+  -- other-extensions:+  build-depends:       base >=4.10 && < 5, filepath+  hs-source-dirs:      src+  default-language:    Haskell2010+++executable multi-cabal+  main-is:              app/Main.hs+  -- other-modules:+  -- other-extensions:+  build-depends:       base >=4.10 && < 5, directory+  -- hs-source-dirs:+  default-language:    Haskell2010
+ tests/projects/failing-multi-repl-cabal-project/multi-repl-cabal-fail/src/Fail.hs view
@@ -0,0 +1,5 @@+module Fail where++import System.FilePath ((</>))++foo = "test" </> "me"
+ tests/projects/failing-multi-repl-cabal-project/multi-repl-cabal-fail/src/Lib.hs view
@@ -0,0 +1,5 @@+module Lib where++import System.FilePath ((</>))++foo = "test" </> "me"
− tests/projects/multi-cabal-with-project/cabal.project.8.10.7
@@ -1,6 +0,0 @@-packages: ./appA ./appB---- Only appA gets the config-package appA-    ghc-options: -O2-
+ tests/projects/multi-cabal-with-project/cabal.project.9.2.8 view
@@ -0,0 +1,6 @@+packages: ./appA ./appB++-- Only appA gets the config+package appA+    ghc-options: -O2+
tests/projects/multi-cabal-with-project/hie.yaml view
@@ -6,11 +6,11 @@           cabal:             - path: appA/src               component: appA:lib-              cabalProject: cabal.project.8.10.7+              cabalProject: cabal.project.9.2.8     - path: "appB"       config:         cradle:           cabal:             - path: appB/src               component: appB:lib-              cabalProject: cabal.project.8.10.7+              cabalProject: cabal.project.9.2.8
tests/projects/multi-cabal/src/Lib.hs view
tests/projects/multi-stack/src/Lib.hs view