@@ -70,7 +70,7 @@ import qualified HIE.Bios.Types as Types
70
70
import qualified HIE.Bios.Ghc.Gap as Gap
71
71
72
72
import GHC.Fingerprint (fingerprintString )
73
- import GHC.ResponseFile (escapeArgs )
73
+ import GHC.ResponseFile (escapeArgs , expandResponse )
74
74
75
75
import Data.Version
76
76
import Data.IORef
@@ -612,10 +612,64 @@ cabalCradle l cs wdir mc projectFile
612
612
-- ./dist-newstyle/tmp/environment.-24811: createDirectory: does not exist (No such file or directory)
613
613
liftIO $ createDirectoryIfMissing True (buildDir </> " tmp" )
614
614
-- Need to pass -v0 otherwise we get "resolving dependencies..."
615
- cabalProc <- cabalProcess l vs projectFile wdir " v2-exec " $ [ " ghc " , " -v0 " , " -- " ] ++ args
615
+ cabalProc <- cabalExecGhc l vs projectFile wdir args
616
616
Process. readProcessWithCwd' l cabalProc " "
617
617
}
618
618
619
+ cabalExecGhc :: LogAction IO (WithSeverity Log ) -> ProgramVersions -> CradleProjectConfig -> FilePath -> [String ] -> CradleLoadResultT IO CreateProcess
620
+ cabalExecGhc l vs projectFile wdir args = do
621
+ cabalProcess l vs projectFile wdir " v2-exec" $ [" ghc" , " -v0" , " --" ] ++ args
622
+
623
+ processCabalLoadStyle :: MonadIO m => LogAction IO (WithSeverity Log ) -> ResolvedCradles a -> CradleProjectConfig -> [Char ] -> Maybe FilePath -> [Char ] -> LoadStyle -> m ([FilePath ], [FilePath ], [FilePath ])
624
+ processCabalLoadStyle l cradles projectFile workDir mc fp loadStyle = do
625
+ let fpModule = fromMaybe (fixTargetPath fp) mc
626
+ let (cabalArgs, loadingFiles, extraDeps) = case loadStyle of
627
+ LoadFile -> ([fpModule], [fp], [] )
628
+ LoadWithContext fps ->
629
+ let allModulesFpsDeps = ((fpModule, fp, [] ) : moduleFilesFromSameProject fps)
630
+ allModules = nubOrd $ fst3 <$> allModulesFpsDeps
631
+ allFiles = nubOrd $ snd3 <$> allModulesFpsDeps
632
+ allFpsDeps = nubOrd $ concatMap thd3 allModulesFpsDeps
633
+ in ([" --keep-temp-files" , " --enable-multi-repl" ] ++ allModules, allFiles, allFpsDeps)
634
+
635
+ liftIO $ l <& LogComputedCradleLoadStyle " cabal" loadStyle `WithSeverity ` Info
636
+ liftIO $ l <& LogCabalLoad fp mc (prefix <$> resolvedCradles cradles) loadingFiles `WithSeverity ` Debug
637
+ pure (cabalArgs, loadingFiles, extraDeps)
638
+ where
639
+ -- Need to make relative on Windows, due to a Cabal bug with how it
640
+ -- parses file targets with a C: drive in it. So we decide to make
641
+ -- the paths relative to the working directory.
642
+ fixTargetPath x
643
+ | isWindows && hasDrive x = makeRelative workDir x
644
+ | otherwise = x
645
+ moduleFilesFromSameProject fps =
646
+ [ (fromMaybe (fixTargetPath file) old_mc, file, deps)
647
+ | file <- fps,
648
+ -- Lookup the component for the old file
649
+ Just (ResolvedCradle {concreteCradle = ConcreteCabal ct, cradleDeps = deps}) <- [selectCradle prefix file (resolvedCradles cradles)],
650
+ -- Only include this file if the old component is in the same project
651
+ (projectConfigFromMaybe (cradleRoot cradles) (cabalProjectFile ct)) == projectFile,
652
+ let old_mc = cabalComponent ct
653
+ ]
654
+
655
+ cabalLoadFilesBefore315 :: LogAction IO (WithSeverity Log ) -> ProgramVersions -> CradleProjectConfig -> [Char ] -> [String ] -> CradleLoadResultT IO CreateProcess
656
+ cabalLoadFilesBefore315 l progVersions projectFile workDir args = do
657
+ let cabalCommand = " v2-repl"
658
+
659
+ cabalProcess l progVersions projectFile workDir cabalCommand args `modCradleError` \ err -> do
660
+ deps <- cabalCradleDependencies projectFile workDir workDir
661
+ pure $ err {cradleErrorDependencies = cradleErrorDependencies err ++ deps}
662
+
663
+ cabalLoadFilesWithRepl :: LogAction IO (WithSeverity Log ) -> CradleProjectConfig -> FilePath -> [String ] -> CradleLoadResultT IO CreateProcess
664
+ cabalLoadFilesWithRepl l projectFile workDir args = do
665
+ let cabalCommand = " v2-repl"
666
+
667
+ newEnvironment <- liftIO Process. getCleanEnvironment
668
+ wrapper_fp <- liftIO $ withReplWrapperTool l (proc " ghc" ) workDir
669
+ pure $ (proc " cabal" ([cabalCommand, " --keep-temp-files" , " --with-repl" , wrapper_fp] <> projectFileProcessArgs projectFile <> args))
670
+ { env = Just newEnvironment
671
+ , cwd = Just workDir
672
+ }
619
673
620
674
-- | Execute a cabal process in our custom cache-build directory configured
621
675
-- with the custom ghc executable.
@@ -653,7 +707,7 @@ cabalProcess l vs cabalProject workDir command args = do
653
707
654
708
setupCabalCommand :: FilePath -> IO CreateProcess
655
709
setupCabalCommand ghcPkgPath = do
656
- wrapper_fp <- withGhcWrapperTool l (" ghc" , [] ) workDir
710
+ wrapper_fp <- withGhcWrapperTool l (proc " ghc" ) workDir
657
711
buildDir <- cabalBuildDir workDir
658
712
let extraCabalArgs =
659
713
[ " --builddir=" <> buildDir
@@ -688,7 +742,7 @@ withGhcPkgTool ghcPathAbs libdir = do
688
742
ghcPkgPath = guessGhcPkgFromGhc ghcName
689
743
if isWindows
690
744
then pure ghcPkgPath
691
- else withWrapperTool ghcPkgPath
745
+ else withGhcPkgShim ghcPkgPath
692
746
where
693
747
ghcDir = takeDirectory ghcPathAbs
694
748
@@ -707,7 +761,7 @@ withGhcPkgTool ghcPathAbs libdir = do
707
761
--
708
762
-- If we used the raw executable, i.e. not wrapped in a shim, then 'cabal'
709
763
-- can not use the given 'ghc-pkg'.
710
- withWrapperTool ghcPkg = do
764
+ withGhcPkgShim ghcPkg = do
711
765
let globalPackageDb = libdir </> " package.conf.d"
712
766
-- This is the same as the wrapper-shims ghc-pkg usually comes with.
713
767
contents = unlines
@@ -762,32 +816,40 @@ processCabalWrapperArgs args =
762
816
in Just (dir, final_args)
763
817
_ -> Nothing
764
818
765
- -- | GHC process information.
766
- -- Consists of the filepath to the ghc executable and
767
- -- arguments to the executable.
768
- type GhcProc = (FilePath , [String ])
819
+ -- | GHC process that accepts GHC arguments.
820
+ type GhcProc = [String ] -> CreateProcess
769
821
770
822
-- | Generate a fake GHC that can be passed to cabal or stack
771
823
-- when run with --interactive, it will print out its
772
824
-- command-line arguments and exit
773
825
withGhcWrapperTool :: LogAction IO (WithSeverity Log ) -> GhcProc -> FilePath -> IO FilePath
774
- withGhcWrapperTool l (mbGhc, ghcArgs) wdir = do
775
- let wrapperContents = if isWindows then cabalWrapperHs else cabalWrapper
776
- withExtension fp = if isWindows then fp <.> " exe" else fp
777
- srcHash = show (fingerprintString wrapperContents)
778
- cacheFile (withExtension " wrapper" ) srcHash $ \ wrapper_fp ->
779
- if isWindows
780
- then
781
- withSystemTempDirectory " hie-bios" $ \ tmpDir -> do
782
- let wrapper_hs = wrapper_fp -<.> " hs"
783
- writeFile wrapper_hs wrapperContents
784
- let ghcArgsWithExtras = ghcArgs ++ [" -rtsopts=ignore" , " -outputdir" , tmpDir, " -o" , wrapper_fp, wrapper_hs]
785
- let ghcProc = (proc mbGhc ghcArgsWithExtras)
786
- { cwd = Just wdir
787
- }
788
- l <& LogCreateProcessRun ghcProc `WithSeverity ` Debug
789
- readCreateProcess ghcProc " " >>= putStr
790
- else writeFile wrapper_fp wrapperContents
826
+ withGhcWrapperTool l mkGhcCall wdir = do
827
+ withWrapperTool l mkGhcCall wdir " wrapper" cabalWrapperHs cabalWrapper
828
+
829
+ -- | Generate a script/binary that can be passed to cabal's '--with-repl'.
830
+ -- On windows, this compiles a Haskell file, while on other systems, we persist
831
+ withReplWrapperTool :: LogAction IO (WithSeverity Log ) -> GhcProc -> FilePath -> IO FilePath
832
+ withReplWrapperTool l mkGhcCall wdir =
833
+ withWrapperTool l mkGhcCall wdir " repl-wrapper" cabalWithReplWrapperHs cabalWithReplWrapper
834
+
835
+ withWrapperTool :: LogAction IO (WithSeverity Log ) -> GhcProc -> String -> FilePath -> String -> String -> IO FilePath
836
+ withWrapperTool l mkGhcCall wdir baseName windowsWrapper unixWrapper = do
837
+ let wrapperContents = if isWindows then windowsWrapper else unixWrapper
838
+ withExtension fp = if isWindows then fp <.> " exe" else fp
839
+ srcHash = show (fingerprintString wrapperContents)
840
+ cacheFile (withExtension baseName) srcHash $ \ wrapper_fp ->
841
+ if isWindows
842
+ then
843
+ withSystemTempDirectory " hie-bios" $ \ tmpDir -> do
844
+ let wrapper_hs = wrapper_fp -<.> " hs"
845
+ writeFile wrapper_hs wrapperContents
846
+ let ghcArgs = [" -rtsopts=ignore" , " -outputdir" , tmpDir, " -o" , wrapper_fp, wrapper_hs]
847
+ let ghcProc = (mkGhcCall ghcArgs)
848
+ { cwd = Just wdir
849
+ }
850
+ l <& LogCreateProcessRun ghcProc `WithSeverity ` Debug
851
+ readCreateProcess ghcProc " " >>= putStr
852
+ else writeFile wrapper_fp wrapperContents
791
853
792
854
-- | Create and cache a file in hie-bios's cache directory.
793
855
--
@@ -885,6 +947,20 @@ isCabalMultipleCompSupported vs = do
885
947
(Just cabal, Just ghc) -> pure $ ghc >= makeVersion [9 , 4 ] && cabal >= makeVersion [3 , 11 ]
886
948
_ -> pure False
887
949
950
+ data CabalLoadFeature
951
+ = CabalWithRepl
952
+ | CabalWithGhcShimWrapper
953
+
954
+ determineCabalLoadFeature :: MonadIO m => ProgramVersions -> m CabalLoadFeature
955
+ determineCabalLoadFeature vs = do
956
+ cabal_version <- liftIO $ runCachedIO $ cabalVersion vs
957
+ -- determine which load style is supported by this cabal cradle.
958
+ case cabal_version of
959
+ Just ver
960
+ | ver >= makeVersion [3 , 15 ] -> pure CabalWithRepl
961
+ | otherwise -> pure CabalWithGhcShimWrapper
962
+ _ -> pure CabalWithGhcShimWrapper
963
+
888
964
cabalAction
889
965
:: ResolvedCradles a
890
966
-> FilePath
@@ -895,7 +971,8 @@ cabalAction
895
971
-> LoadStyle
896
972
-> CradleLoadResultT IO ComponentOptions
897
973
cabalAction cradles workDir mc l projectFile fp loadStyle = do
898
- multiCompSupport <- isCabalMultipleCompSupported (cradleProgramVersions cradles)
974
+ let progVersions = cradleProgramVersions cradles
975
+ multiCompSupport <- isCabalMultipleCompSupported progVersions
899
976
-- determine which load style is supported by this cabal cradle.
900
977
determinedLoadStyle <- case loadStyle of
901
978
LoadWithContext _ | not multiCompSupport -> do
@@ -909,25 +986,12 @@ cabalAction cradles workDir mc l projectFile fp loadStyle = do
909
986
pure LoadFile
910
987
_ -> pure loadStyle
911
988
912
- let fpModule = fromMaybe (fixTargetPath fp) mc
913
- let (cabalArgs, loadingFiles, extraDeps) = case determinedLoadStyle of
914
- LoadFile -> ([fpModule], [fp], [] )
915
- LoadWithContext fps ->
916
- let allModulesFpsDeps = ((fpModule, fp, [] ) : moduleFilesFromSameProject fps)
917
- allModules = nubOrd $ fst3 <$> allModulesFpsDeps
918
- allFiles = nubOrd $ snd3 <$> allModulesFpsDeps
919
- allFpsDeps = nubOrd $ concatMap thd3 allModulesFpsDeps
920
- in ([" --keep-temp-files" , " --enable-multi-repl" ] ++ allModules, allFiles, allFpsDeps)
921
-
922
- liftIO $ l <& LogComputedCradleLoadStyle " cabal" determinedLoadStyle `WithSeverity ` Info
923
- liftIO $ l <& LogCabalLoad fp mc (prefix <$> resolvedCradles cradles) loadingFiles `WithSeverity ` Debug
924
-
925
- let cabalCommand = " v2-repl"
989
+ (cabalArgs, loadingFiles, extraDeps) <- processCabalLoadStyle l cradles projectFile workDir mc fp determinedLoadStyle
926
990
927
- cabalProc <-
928
- cabalProcess l (cradleProgramVersions cradles) projectFile workDir cabalCommand cabalArgs `modCradleError` \ err -> do
929
- deps <- cabalCradleDependencies projectFile workDir workDir
930
- pure $ err {cradleErrorDependencies = cradleErrorDependencies err ++ deps}
991
+ cabalFeatures <- determineCabalLoadFeature progVersions
992
+ cabalProc <- case cabalFeatures of
993
+ CabalWithRepl -> cabalLoadFilesWithRepl l projectFile workDir cabalArgs
994
+ CabalWithGhcShimWrapper -> cabalLoadFilesBefore315 l progVersions projectFile workDir cabalArgs
931
995
932
996
(ex, output, stde, [(_, maybeArgs)]) <- liftIO $ Process. readProcessWithOutputs [hie_bios_output] l workDir cabalProc
933
997
let args = fromMaybe [] maybeArgs
@@ -943,7 +1007,7 @@ cabalAction cradles workDir mc l projectFile fp loadStyle = do
943
1007
944
1008
when (ex /= ExitSuccess ) $ do
945
1009
deps <- liftIO $ cabalCradleDependencies projectFile workDir workDir
946
- let cmd = show ([ " cabal " , cabalCommand] <> cabalArgs )
1010
+ let cmd = prettyCmdSpec (cmdspec cabalProc )
947
1011
let errorMsg = " Failed to run " <> cmd <> " in directory \" " <> workDir <> " \" . Consult the logs for full command and error."
948
1012
throwCE (CradleError deps ex ([errorMsg] <> errorDetails) loadingFiles)
949
1013
@@ -954,25 +1018,17 @@ cabalAction cradles workDir mc l projectFile fp loadStyle = do
954
1018
-- root of the component, so we are right in trivial cases at least.
955
1019
deps <- liftIO $ cabalCradleDependencies projectFile workDir workDir
956
1020
throwCE (CradleError (deps <> extraDeps) ex ([" Failed to parse result of calling cabal" ] <> errorDetails) loadingFiles)
957
- Just (componentDir, final_args ) -> do
1021
+ Just (componentDir, ghc_args ) -> do
958
1022
deps <- liftIO $ cabalCradleDependencies projectFile workDir componentDir
1023
+ final_args <- case cabalFeatures of
1024
+ CabalWithRepl -> liftIO $ processCabalGhcResponseFile ghc_args
1025
+ CabalWithGhcShimWrapper -> pure ghc_args
959
1026
CradleLoadResultT $ pure $ makeCradleResult (ex, stde, componentDir, final_args) (deps <> extraDeps) loadingFiles
960
- where
961
- -- Need to make relative on Windows, due to a Cabal bug with how it
962
- -- parses file targets with a C: drive in it. So we decide to make
963
- -- the paths relative to the working directory.
964
- fixTargetPath x
965
- | isWindows && hasDrive x = makeRelative workDir x
966
- | otherwise = x
967
- moduleFilesFromSameProject fps =
968
- [ (fromMaybe (fixTargetPath file) old_mc, file, deps)
969
- | file <- fps,
970
- -- Lookup the component for the old file
971
- Just (ResolvedCradle {concreteCradle = ConcreteCabal ct, cradleDeps = deps}) <- [selectCradle prefix file (resolvedCradles cradles)],
972
- -- Only include this file if the old component is in the same project
973
- (projectConfigFromMaybe (cradleRoot cradles) (cabalProjectFile ct)) == projectFile,
974
- let old_mc = cabalComponent ct
975
- ]
1027
+
1028
+ processCabalGhcResponseFile :: [String ] -> IO [String ]
1029
+ processCabalGhcResponseFile args = do
1030
+ expanded_args <- expandResponse args
1031
+ pure $ removeInteractive expanded_args
976
1032
977
1033
removeInteractive :: [String ] -> [String ]
978
1034
removeInteractive = filter (/= " --interactive" )
@@ -1086,9 +1142,9 @@ stackAction
1086
1142
-> IO (CradleLoadResult ComponentOptions )
1087
1143
stackAction workDir mc syaml l fp loadStyle = do
1088
1144
logCradleHasNoSupportForLoadWithContext l loadStyle " stack"
1089
- let ghcProcArgs = ( " stack" , stackYamlProcessArgs syaml <> [" exec" , " ghc" , " --" ])
1145
+ let ghcProc args = proc " stack" ( stackYamlProcessArgs syaml <> [" exec" , " ghc" , " --" ] <> args )
1090
1146
-- Same wrapper works as with cabal
1091
- wrapper_fp <- withGhcWrapperTool l ghcProcArgs workDir
1147
+ wrapper_fp <- withGhcWrapperTool l ghcProc workDir
1092
1148
(ex1, _stdo, stde, [(_, maybeArgs)]) <-
1093
1149
Process. readProcessWithOutputs [hie_bios_output] l workDir
1094
1150
$ stackProcess syaml
0 commit comments