@@ -9,12 +9,14 @@ module Hledger.Flow.Common
9
9
, showCmdArgs
10
10
, consoleChannelLoop
11
11
, terminateChannelLoop
12
+ , dummyLogger
12
13
, channelOut , channelOutLn
13
14
, channelErr , channelErrLn
14
15
, errExit
15
16
, logVerbose
16
- , timeAndExitOnErr
17
+ , timeAndExitOnErr , timeAndExitOnErr'
17
18
, parAwareProc
19
+ , inprocWithErrFun
18
20
, verboseTestFile
19
21
, relativeToBase
20
22
, relativeToBase'
@@ -55,7 +57,7 @@ import qualified Data.Map.Strict as Map
55
57
import Data.Time.LocalTime
56
58
57
59
import Data.Function (on )
58
- import qualified Data.List as List (nub , sort , sortBy , groupBy )
60
+ import qualified Data.List as List (nub , null , sort , sortBy , groupBy )
59
61
import Data.Ord (comparing )
60
62
import Hledger.Flow.Types
61
63
import qualified Hledger.Flow.Import.Types as IT
@@ -103,6 +105,9 @@ showCmdArgs args = T.intercalate " " (map escapeArg args)
103
105
escapeArg :: Text -> Text
104
106
escapeArg a = if (T. count " " a > 0 ) then " '" <> a <> " '" else a
105
107
108
+ dummyLogger :: TChan LogMessage -> Text -> IO ()
109
+ dummyLogger _ _ = return ()
110
+
106
111
channelOut :: TChan LogMessage -> Text -> IO ()
107
112
channelOut ch txt = atomically $ writeTChan ch $ StdOut txt
108
113
@@ -153,42 +158,66 @@ terminateChannelLoop ch = atomically $ writeTChan ch Terminate
153
158
logVerbose :: HasVerbosity o => o -> TChan LogMessage -> Text -> IO ()
154
159
logVerbose opts ch msg = if (verbose opts) then logToChannel ch msg else return ()
155
160
156
- logTimedAction :: HasVerbosity o => o -> TChan LogMessage -> Text -> IO FullOutput -> IO FullTimedOutput
157
- logTimedAction opts ch msg action = do
158
- logVerbose opts ch $ format (" Begin: " % s) msg
159
- timed@ ((ec, _, _), diff) <- time action
160
- logVerbose opts ch $ format (" End: " % s% " " % s% " (" % s% " )" ) msg (repr ec) (repr diff)
161
+ descriptiveOutput :: Text -> Text -> Text
162
+ descriptiveOutput outputLabel outTxt = do
163
+ if not (T. null outTxt)
164
+ then format (s% " :\n " % s% " \n " ) outputLabel outTxt
165
+ else " "
166
+
167
+ logTimedAction :: HasVerbosity o => o -> TChan LogMessage -> Text -> [Text ]
168
+ -> (TChan LogMessage -> Text -> IO () ) -> (TChan LogMessage -> Text -> IO () )
169
+ -> IO FullOutput
170
+ -> IO FullTimedOutput
171
+ logTimedAction opts ch cmdLabel extraCmdLabels stdoutLogger stderrLogger action = do
172
+ logVerbose opts ch $ format (" Begin: " % s) cmdLabel
173
+ if (List. null extraCmdLabels) then return () else logVerbose opts ch $ T. intercalate " \n " extraCmdLabels
174
+ timed@ ((ec, stdOut, stdErr), diff) <- time action
175
+ stdoutLogger ch stdOut
176
+ stderrLogger ch stdErr
177
+ logVerbose opts ch $ format (" End: " % s% " " % s% " (" % s% " )" ) cmdLabel (repr ec) (repr diff)
161
178
return timed
162
179
163
- timeAndExitOnErr :: HasVerbosity o => o -> TChan LogMessage -> Text -> IO FullOutput -> IO FullTimedOutput
164
- timeAndExitOnErr opts ch msg action = do
165
- timed@ ((ec, stdOut, stdErr), _) <- logTimedAction opts ch msg action
166
- if not (T. null stdErr)
167
- then channelErr ch stdErr
168
- else return ()
180
+ timeAndExitOnErr :: (HasSequential o , HasVerbosity o ) => o -> TChan LogMessage -> Text
181
+ -> (TChan LogMessage -> Text -> IO () ) -> (TChan LogMessage -> Text -> IO () )
182
+ -> ProcFun -> ProcInput
183
+ -> IO FullTimedOutput
184
+ timeAndExitOnErr opts ch cmdLabel = timeAndExitOnErr' opts ch cmdLabel []
185
+
186
+ timeAndExitOnErr' :: (HasSequential o , HasVerbosity o ) => o -> TChan LogMessage -> Text -> [Text ]
187
+ -> (TChan LogMessage -> Text -> IO () ) -> (TChan LogMessage -> Text -> IO () )
188
+ -> ProcFun -> ProcInput
189
+ -> IO FullTimedOutput
190
+ timeAndExitOnErr' opts ch cmdLabel extraCmdLabels stdoutLogger stderrLogger procFun (cmd, args, stdInput) = do
191
+ let action = procFun cmd args stdInput
192
+ timed@ ((ec, stdOut, stdErr), _) <- logTimedAction opts ch cmdLabel extraCmdLabels stdoutLogger stderrLogger action
169
193
case ec of
170
194
ExitFailure i -> do
171
- let msgOut = if not (T. null stdOut)
172
- then format (" Standard output:\n " % s% " \n " ) stdOut
173
- else " "
174
-
175
- let msgErr = if not (T. null stdErr)
176
- then format (" Error output:\n " % s% " \n " ) stdErr
177
- else " "
195
+ let cmdText = format (s% " " % s) cmd $ showCmdArgs args
196
+ let msgOut = descriptiveOutput " Standard output" stdOut
197
+ let msgErr = descriptiveOutput " Error output" stdErr
178
198
179
- let exitMsg = format (" \n hledger-flow: an external process exited with exit code " % d% " . \n "
180
- % s% s% " \n See verbose output for more details. " ) i msgOut msgErr
199
+ let exitMsg = format (" \n === Begin Error: " % s % " === \n External command: \n " % s % " \n Exit code " % d% " \n "
200
+ % s% s% " === End Error: " % s % " === \n " ) cmdLabel cmdText i msgOut msgErr cmdLabel
181
201
errExit i ch exitMsg timed
182
202
ExitSuccess -> return timed
183
203
184
- procWithEmptyOutput :: MonadIO io => Text -> [ Text ] -> Shell Line -> io FullOutput
204
+ procWithEmptyOutput :: ProcFun
185
205
procWithEmptyOutput cmd args stdinput = do
186
206
ec <- proc cmd args stdinput
187
207
return (ec, T. empty, T. empty)
188
208
189
- parAwareProc :: ( HasSequential o , MonadIO io ) => o -> Text -> [ Text ] -> Shell Line -> io FullOutput
209
+ parAwareProc :: HasSequential o => o -> ProcFun
190
210
parAwareProc opts = if (sequential opts) then procWithEmptyOutput else procStrictWithErr
191
211
212
+ inprocWithErrFun :: (Text -> IO () ) -> ProcInput -> Shell Line
213
+ inprocWithErrFun errFun (cmd, args, standardInput) = do
214
+ result <- inprocWithErr cmd args standardInput
215
+ case result of
216
+ Right ln -> return ln
217
+ Left ln -> do
218
+ (liftIO . errFun . lineToText) ln
219
+ empty
220
+
192
221
verboseTestFile :: (HasVerbosity o , HasBaseDir o ) => o -> TChan LogMessage -> FilePath -> IO Bool
193
222
verboseTestFile opts ch p = do
194
223
fileExists <- testfile p
0 commit comments