Skip to content

Commit 41e3135

Browse files
committed
initial contravariant logging style for HLS wrapper
1 parent fdbc974 commit 41e3135

File tree

5 files changed

+114
-47
lines changed

5 files changed

+114
-47
lines changed

exe/Wrapper.hs

Lines changed: 85 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import Control.Exception (SomeException, catch, throwIO)
99
import Control.Monad.Extra
1010
import Data.Default
1111
import Data.Foldable
12+
import Data.Text (Text)
1213
import qualified Data.Text as Text
1314
import Data.Void
1415
import qualified Development.IDE.Session as Session
15-
import Development.IDE.Types.Logger (LogMessage, Recorder,
16-
logException, logInfo,
17-
withLogMessageRecorder)
16+
import Development.IDE.Types.Logger (Recorder, cmap, logWith,
17+
withDefaultTextRecorder)
1818
import qualified HIE.Bios.Environment as HieBios
1919
import HIE.Bios.Types
2020
import Ide.Arguments
@@ -23,10 +23,56 @@ import System.Directory
2323
import System.Environment
2424
import System.Exit
2525
import System.FilePath
26-
import System.IO
2726
import System.Info
2827
import System.Process
2928

29+
data Log
30+
= LogProgram { name :: !String, arguments :: ![String], version :: !String }
31+
-- logInfo recorder $ "Run entered for haskell-language-server-wrapper(" <> Text.pack progName <> ") "
32+
-- <> Text.pack hlsVersion
33+
-- logInfo recorder $ "Arguments: " <> (Text.pack . show) args
34+
| LogCurrentDirectory !FilePath
35+
-- logInfo recorder $ "Current directory: " <> Text.pack d
36+
| LogOs !String
37+
-- logInfo recorder $ "Operating system: " <> Text.pack os
38+
| LogCradle !(Cradle Void)
39+
-- logInfo recorder $ "Cradle directory: " <> Text.pack (cradleRootDir cradle)
40+
-- logInfo recorder $ "Cradle type: " <> (Text.pack . show) (actionName (cradleOptsProg cradle))
41+
| LogBuildTools !ProgramsOfInterest
42+
-- logInfo recorder ""
43+
-- logInfo recorder "Tool versions found on the $PATH"
44+
-- logInfo recorder $ Text.pack $ showProgramVersionOfInterest programsOfInterest
45+
-- logInfo recorder ""
46+
| LogGhcVersion LogGhcVersionMessage
47+
-- logInfo recorder "Consulting the cradle to get project GHC version..."
48+
| LogExeCandidates ![Text]
49+
-- logInfo recorder $ "haskell-language-server exe candidates: " <> (Text.pack . show) candidates
50+
| LogExeNotFound
51+
-- logInfo recorder $ "Cannot find any haskell-language-server exe, looked for: " <> Text.intercalate ", " candidates
52+
| LogExeFound !FilePath
53+
-- logInfo recorder $ "Launching haskell-language-server exe at:" <> Text.pack e
54+
| LogException !SomeException
55+
| LogHieYamlFound { initialPath :: !FilePath, path :: !FilePath }
56+
-- hPutStrLn stderr $ "Found \"" ++ yaml ++ "\" for \"" ++ initialFp ++ "\""
57+
| LogHieYamlNotFound
58+
-- hPutStrLn stderr "No 'hie.yaml' found. Try to discover the project type!"
59+
| LogHieBios !String
60+
deriving Show
61+
62+
data LogGhcVersionMessage
63+
= LogGhcVersionCradleSuccess !String
64+
-- logInfo recorder $ "Project GHC version: " <> Text.pack ghcVersion
65+
| LogGhcVersionCradleFail !CradleError
66+
-- die $ "Failed to get project GHC version:" ++ show error
67+
| LogGhcVersionCradleNone
68+
-- die "Failed get project GHC version, since we have a none cradle"
69+
| LogGhcVersionToolNotFound !FilePath
70+
-- die $ "Cradle requires " ++ exe ++ " but couldn't find it" ++ "\n"
71+
-- ++ show cradle
72+
deriving Show
73+
74+
logToText :: Log -> Text
75+
logToText = Text.pack . show
3076
-- ---------------------------------------------------------------------
3177

3278
main :: IO ()
@@ -39,7 +85,8 @@ main = do
3985
Ghcide GhcideArguments{ argsLogFile } -> argsLogFile
4086
_ -> Nothing
4187

42-
withLogMessageRecorder logFilePath $ \recorder ->
88+
withDefaultTextRecorder logFilePath $ \textRecorder -> do
89+
let logRecorder = cmap logToText textRecorder
4390
catch
4491
(do
4592
hlsVer <- haskellLanguageServerVersion
@@ -57,69 +104,64 @@ main = do
57104
putStrLn haskellLanguageServerNumericVersion
58105

59106
BiosMode PrintCradleType ->
60-
print =<< findProjectCradle recorder
107+
print =<< findProjectCradle mempty
61108

62-
_ -> launchHaskellLanguageServer recorder args
109+
_ -> launchHaskellLanguageServer logRecorder args
63110
)
64-
(\e -> logException recorder (e :: SomeException) *> throwIO e)
111+
(\e -> logWith logRecorder (LogException e) *> throwIO e)
65112

66-
launchHaskellLanguageServer :: Recorder LogMessage -> Arguments -> IO ()
113+
launchHaskellLanguageServer :: Recorder Log -> Arguments -> IO ()
67114
launchHaskellLanguageServer recorder parsedArgs = do
115+
let ghcVersionRecorder = cmap LogGhcVersion recorder
116+
68117
case parsedArgs of
69118
Ghcide GhcideArguments{..} -> whenJust argsCwd setCurrentDirectory
70119
_ -> pure ()
71120

72121
d <- getCurrentDirectory
122+
logWith recorder $ LogCurrentDirectory d
73123

74124
-- search for the project cradle type
75125
cradle <- findProjectCradle recorder
126+
logWith recorder $ LogCradle cradle
76127

77128
-- Get the root directory from the cradle
78129
setCurrentDirectory $ cradleRootDir cradle
79130

80131
case parsedArgs of
81132
Ghcide GhcideArguments{..} ->
82-
when argsProjectGhcVersion $ getRuntimeGhcVersion' cradle >>= putStrLn >> exitSuccess
133+
when argsProjectGhcVersion $ getRuntimeGhcVersion' ghcVersionRecorder cradle >>= putStrLn >> exitSuccess
83134
_ -> pure ()
84135

85136
progName <- getProgName
86-
logInfo recorder $ "Run entered for haskell-language-server-wrapper(" <> Text.pack progName <> ") "
87-
<> Text.pack hlsVersion
88-
logInfo recorder $ "Current directory: " <> Text.pack d
89-
logInfo recorder $ "Operating system: " <> Text.pack os
90137
args <- getArgs
91-
logInfo recorder $ "Arguments: " <> (Text.pack . show) args
92-
logInfo recorder $ "Cradle directory: " <> Text.pack (cradleRootDir cradle)
93-
logInfo recorder $ "Cradle type: " <> (Text.pack . show) (actionName (cradleOptsProg cradle))
138+
logWith recorder $ LogProgram progName args hlsVersion
139+
logWith recorder $ LogOs os
94140
programsOfInterest <- findProgramVersions
95-
logInfo recorder ""
96-
logInfo recorder "Tool versions found on the $PATH"
97-
logInfo recorder $ Text.pack $ showProgramVersionOfInterest programsOfInterest
98-
logInfo recorder ""
141+
logWith recorder $ LogBuildTools programsOfInterest
99142
-- Get the ghc version -- this might fail!
100-
logInfo recorder "Consulting the cradle to get project GHC version..."
101-
ghcVersion <- getRuntimeGhcVersion' cradle
102-
logInfo recorder $ "Project GHC version: " <> Text.pack ghcVersion
143+
ghcVersion <- getRuntimeGhcVersion' ghcVersionRecorder cradle
103144

104145
let
105146
hlsBin = "haskell-language-server-" <> Text.pack ghcVersion
106147
candidates' = [hlsBin, "haskell-language-server"]
107148
candidates = map (<> Text.pack exeExtension) candidates'
108149

109-
logInfo recorder $ "haskell-language-server exe candidates: " <> (Text.pack . show) candidates
150+
logWith recorder $ LogExeCandidates candidates
110151

111152
mexes <- traverse (findExecutable . Text.unpack) candidates
112153

113154
case asum mexes of
114-
Nothing -> logInfo recorder $ "Cannot find any haskell-language-server exe, looked for: " <> Text.intercalate ", " candidates
155+
Nothing ->
156+
logWith recorder LogExeNotFound
115157
Just e -> do
116-
logInfo recorder $ "Launching haskell-language-server exe at:" <> Text.pack e
158+
logWith recorder $ LogExeFound e
117159
callProcess e args
118160

119161
-- | Version of 'getRuntimeGhcVersion' that dies if we can't get it, and also
120162
-- checks to see if the tool is missing if it is one of
121-
getRuntimeGhcVersion' :: Show a => Cradle a -> IO String
122-
getRuntimeGhcVersion' cradle = do
163+
getRuntimeGhcVersion' :: Recorder LogGhcVersionMessage -> Cradle a -> IO String
164+
getRuntimeGhcVersion' recorder cradle = do
123165

124166
-- See if the tool is installed
125167
case actionName (cradleOptsProg cradle) of
@@ -132,19 +174,24 @@ getRuntimeGhcVersion' cradle = do
132174
ghcVersionRes <- HieBios.getRuntimeGhcVersion cradle
133175
case ghcVersionRes of
134176
CradleSuccess ver -> do
177+
logWith recorder $ LogGhcVersionCradleSuccess ver
135178
return ver
136-
CradleFail error -> die $ "Failed to get project GHC version:" ++ show error
137-
CradleNone -> die "Failed get project GHC version, since we have a none cradle"
179+
CradleFail error -> do
180+
logWith recorder $ LogGhcVersionCradleFail error
181+
exitFailure
182+
CradleNone -> do
183+
logWith recorder LogGhcVersionCradleNone
184+
exitFailure
138185
where
139186
checkToolExists exe = do
140187
exists <- findExecutable exe
141188
case exists of
142189
Just _ -> pure ()
143-
Nothing ->
144-
die $ "Cradle requires " ++ exe ++ " but couldn't find it" ++ "\n"
145-
++ show cradle
190+
Nothing -> do
191+
logWith recorder $ LogGhcVersionToolNotFound exe
192+
exitFailure
146193

147-
findProjectCradle :: Recorder LogMessage -> IO (Cradle Void)
194+
findProjectCradle :: Recorder Log -> IO (Cradle Void)
148195
findProjectCradle recorder = do
149196
d <- getCurrentDirectory
150197

@@ -153,7 +200,7 @@ findProjectCradle recorder = do
153200

154201
-- Some log messages
155202
case hieYaml of
156-
Just yaml -> hPutStrLn stderr $ "Found \"" ++ yaml ++ "\" for \"" ++ initialFp ++ "\""
157-
Nothing -> hPutStrLn stderr "No 'hie.yaml' found. Try to discover the project type!"
203+
Just yaml -> logWith recorder $ LogHieYamlFound initialFp yaml
204+
Nothing -> logWith recorder LogHieYamlNotFound
158205

159-
Session.loadCradle def recorder hieYaml d
206+
Session.loadCradle def (cmap LogHieBios recorder) hieYaml d

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ data SessionLoadingOptions = SessionLoadingOptions
103103
-- | Load the cradle with an optional 'hie.yaml' location.
104104
-- If a 'hie.yaml' is given, use it to load the cradle.
105105
-- Otherwise, use the provided project root directory to determine the cradle type.
106-
, loadCradle :: Recorder LogMessage -> Maybe FilePath -> FilePath -> IO (HieBios.Cradle Void)
106+
, loadCradle :: Recorder String -> Maybe FilePath -> FilePath -> IO (HieBios.Cradle Void)
107107
-- | Given the project name and a set of command line flags,
108108
-- return the path for storing generated GHC artifacts,
109109
-- or 'Nothing' to respect the cradle setting
@@ -136,7 +136,7 @@ instance Default SessionLoadingOptions where
136136
-- using the provided root directory for discovering the project.
137137
-- The implicit config uses different heuristics to determine the type
138138
-- of the project that may or may not be accurate.
139-
loadWithImplicitCradle :: Recorder LogMessage
139+
loadWithImplicitCradle :: Recorder String
140140
-> Maybe FilePath
141141
-- ^ Optional 'hie.yaml' location. Will be used if given.
142142
-> FilePath
@@ -147,13 +147,13 @@ loadWithImplicitCradle recorder mHieYaml rootDir = do
147147
cradle@Cradle{ cradleOptsProg = cradleOptsProg@CradleAction{ runCradle } } <- case mHieYaml of
148148
Just yaml -> HieBios.loadCradle yaml
149149
Nothing -> loadImplicitHieCradle $ addTrailingPathSeparator rootDir
150-
let runCradleWithLogger = \_ -> runCradle (logDebug recorder . ("hie-bios - " <>) . T.pack)
150+
let runCradleWithLogger = \_ -> runCradle (logWith recorder)
151151
pure cradle{ cradleOptsProg = cradleOptsProg{ runCradle = runCradleWithLogger } }
152152

153153
getInitialGhcLibDirDefault :: Recorder LogMessage -> FilePath -> IO (Maybe LibDir)
154154
getInitialGhcLibDirDefault logger rootDir = do
155155
hieYaml <- findCradle def rootDir
156-
cradle <- loadCradle def logger hieYaml rootDir
156+
cradle <- loadCradle def mempty hieYaml rootDir
157157
logDebug logger $ T.pack $ "setInitialDynFlags cradle: " ++ show cradle
158158
libDirRes <- getRuntimeGhcLibDir cradle
159159
case libDirRes of
@@ -520,7 +520,7 @@ loadSessionWithOptions SessionLoadingOptions{..} dir = do
520520
when (isNothing hieYaml) $
521521
logWarning recorder $ implicitCradleWarning lfp
522522

523-
cradle <- loadCradle recorder hieYaml dir
523+
cradle <- loadCradle (cmap LogHieBios recorder) hieYaml dir
524524
lfp <- flip makeRelative cfp <$> getCurrentDirectory
525525

526526
when optTesting $ mRunLspT lspEnv $

ghcide/src/Development/IDE/Types/Logger.hs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ module Development.IDE.Types.Logger
1515
, threadSafeTextStderrRecorder
1616
, withTextFileRecorder
1717
, makeDefaultStderrRecorder
18+
, withDefaultTextRecorder
1819
, withLogMessageRecorder
1920
, withMinPriority
20-
, logPriority, logException, logError, logWarning, logInfo, logDebug, logTelemetry
21+
, logWith, logPriority, logException, logError, logWarning, logInfo, logDebug, logTelemetry
2122
, noopRecorder, noLogging
2223
, cmap, cmapIO, cfilter
2324
) where
@@ -56,6 +57,7 @@ data Priority
5657

5758
data LogMessage =
5859
LogOther LogOtherMessage
60+
| LogHieBios !String
5961

6062
data LogOtherMessage = LogOtherMessage
6163
{ stack :: !CallStack
@@ -71,6 +73,9 @@ data Recorder msg = Recorder
7173
, tracer :: forall a m. (HasCallStack, MonadUnliftIO m) => msg -> m a -> m a
7274
}
7375

76+
logWith :: (HasCallStack, MonadIO m) => Recorder msg -> msg -> m ()
77+
logWith recorder msg = withFrozenCallStack $ logger recorder msg
78+
7479
instance Semigroup (Recorder msg) where
7580
(<>) Recorder{ logger = logger1, tracer = tracer1 } Recorder{ logger = logger2, tracer = tracer2 } =
7681
Recorder
@@ -134,12 +139,26 @@ threadSafeTextStderrRecorder = do
134139
, tracer = \msg action -> withRunInIO $ \runInIO -> withLock lock $ runInIO (tracer msg action)
135140
}
136141

137-
withTextFileRecorder :: FilePath -> (Recorder Text -> IO a) -> IO a
138-
withTextFileRecorder path action = withFile path AppendMode $ action . textHandleRecorder
142+
makeThreadSafeTextStderrRecorder :: MonadIO m => m (Recorder Text)
143+
makeThreadSafeTextStderrRecorder = do
144+
liftIO threadSafeTextStderrRecorder
145+
146+
withTextFileRecorder :: MonadUnliftIO m => FilePath -> (Recorder Text -> m a) -> m a
147+
withTextFileRecorder path action = withRunInIO $ \runInIO -> withFile path AppendMode $ \handle ->
148+
runInIO (action (textHandleRecorder handle))
139149

140150
withMinPriority :: Priority -> Recorder LogMessage -> Recorder LogMessage
141151
withMinPriority minPriority recorder = cfilter (\(LogOther LogOtherMessage{priority}) -> priority >= minPriority) recorder
142152

153+
-- | if no file path given use stderr, else use stderr and file
154+
withDefaultTextRecorder :: MonadUnliftIO m => Maybe FilePath -> (Recorder Text -> m a) -> m a
155+
withDefaultTextRecorder path action = do
156+
textStderrRecorder <- makeThreadSafeTextStderrRecorder
157+
case path of
158+
Nothing -> action textStderrRecorder
159+
Just path -> withTextFileRecorder path $ \textFileRecorder ->
160+
action (textStderrRecorder <> textFileRecorder)
161+
143162
-- | if no file path use stderr recorder, else use stderr and file recorder
144163
withLogMessageRecorder :: Maybe FilePath -> (Recorder LogMessage -> IO a) -> IO a
145164
withLogMessageRecorder path action = do

src/Ide/Main.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ defaultMain recorder args idePlugins = do
6262
BiosMode PrintCradleType -> do
6363
dir <- IO.getCurrentDirectory
6464
hieYaml <- Session.findCradle def dir
65-
cradle <- Session.loadCradle def recorder hieYaml dir
65+
cradle <- Session.loadCradle def mempty hieYaml dir
6666
print cradle
6767

6868
Ghcide ghcideArgs -> do

src/Ide/Version.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ data ProgramsOfInterest = ProgramsOfInterest
3939
, stackVersion :: Maybe Version
4040
, ghcVersion :: Maybe Version
4141
}
42+
deriving Show
4243

4344
showProgramVersionOfInterest :: ProgramsOfInterest -> String
4445
showProgramVersionOfInterest ProgramsOfInterest {..} =

0 commit comments

Comments
 (0)