Skip to content

Commit 8e59809

Browse files
committed
Rough cut no ficus buffering.
1 parent 8958d33 commit 8e59809

File tree

1 file changed

+65
-54
lines changed

1 file changed

+65
-54
lines changed

src/App/Fossa/Ficus/Analyze.hs

Lines changed: 65 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ module App.Fossa.Ficus.Analyze (
66
analyzeWithFicusMain,
77
-- Exported for testing
88
singletonFicusMessage,
9-
) where
9+
)
10+
where
1011

1112
import App.Fossa.EmbeddedBinary (BinaryPaths, toPath, withFicusBinary)
1213
import App.Fossa.Ficus.Types (
@@ -23,26 +24,31 @@ import App.Fossa.Ficus.Types (
2324
FicusSnippetScanResults (..),
2425
)
2526
import App.Types (ProjectRevision (..))
27+
import Control.Applicative ((<|>))
2628
import Control.Carrier.Diagnostics (Diagnostics)
27-
import Control.Effect.Lift (Has, Lift, sendIO)
28-
import Effect.Logger (Logger, logDebug, logInfo)
29-
import Prettyprinter (pretty)
30-
31-
import Data.Time (getCurrentTime)
32-
import Data.Time.Format (defaultTimeLocale, formatTime)
33-
3429
import Control.Concurrent.Async (async, wait)
35-
import Data.Aeson (Object, decode, (.:))
30+
import Control.Effect.Lift (Has, Lift, sendIO)
31+
import Data.Aeson (Object, decode, decodeStrictText, (.:))
3632
import Data.Aeson.Types (parseMaybe)
3733
import Data.ByteString.Lazy qualified as BL
34+
import Data.Conduit ((.|))
35+
import Data.Conduit qualified as Conduit
36+
import Data.Conduit.Combinators qualified as CC
37+
import Data.Conduit.List qualified as CCL
3838
import Data.Hashable (Hashable)
3939
import Data.Maybe (mapMaybe)
4040
import Data.String.Conversion (ToText (toText), toString)
4141
import Data.Text (Text)
4242
import Data.Text qualified as Text
4343
import Data.Text.Encoding qualified as Text.Encoding
44+
import Data.Time (getCurrentTime)
45+
import Data.Time.Format (defaultTimeLocale, formatTime)
4446
import Effect.Exec (AllowErr (Never), Command (..), ExitCode (ExitSuccess), renderCommand)
47+
import Effect.Logger (Logger, logDebug, logInfo)
4548
import Fossa.API.Types (ApiKey (..), ApiOpts (..))
49+
import Path (Abs, Dir, Path, toFilePath)
50+
import Prettyprinter (pretty)
51+
import Srclib.Types (Locator (..), renderLocator)
4652
import System.IO (Handle, hGetLine, hIsEOF)
4753
import System.Process.Typed (
4854
createPipe,
@@ -55,16 +61,14 @@ import System.Process.Typed (
5561
waitExitCode,
5662
withProcessWait,
5763
)
58-
59-
import Path (Abs, Dir, Path, toFilePath)
60-
import Srclib.Types (Locator (..), renderLocator)
6164
import Text.URI (render)
6265
import Text.URI.Builder (PathComponent (PathComponent), TrailingSlash (TrailingSlash), setPath)
6366
import Types (GlobFilter (..), LicenseScanPathFilters (..))
6467
import Prelude
6568

6669
newtype CustomLicensePath = CustomLicensePath {unCustomLicensePath :: Text}
6770
deriving (Eq, Ord, Show, Hashable)
71+
6872
newtype CustomLicenseTitle = CustomLicenseTitle {unCustomLicenseTitle :: Text}
6973
deriving (Eq, Ord, Show, Hashable)
7074

@@ -103,13 +107,12 @@ analyzeWithFicusMain ::
103107
m (Maybe FicusSnippetScanResults)
104108
analyzeWithFicusMain rootDir apiOpts revision filters snippetScanRetentionDays = do
105109
logDebugWithTime "Preparing Ficus analysis configuration..."
106-
messages <- runFicus ficusConfig
110+
ficusResults <- runFicus ficusConfig
107111
logDebugWithTime "runFicus completed, processing results..."
108-
let ficusResults = ficusMessagesToFicusSnippetScanResults messages
109112
case ficusResults of
110113
Just results -> do
111114
logInfo $ "Ficus analysis completed successfully with analysis ID: " <> pretty (ficusSnippetScanResultsAnalysisId results)
112-
logDebug $ "Found " <> pretty (length $ ficusMessageFindings messages) <> " findings from Ficus"
115+
-- logDebug $ "Found " <> pretty (length $ ficusMessageFindings messages) <> " findings from Ficus"
113116
Nothing -> logInfo "Ficus analysis completed but no fingerprint findings were found"
114117
pure ficusResults
115118
where
@@ -124,6 +127,14 @@ analyzeWithFicusMain rootDir apiOpts revision filters snippetScanRetentionDays =
124127
, ficusConfigSnippetScanRetentionDays = snippetScanRetentionDays
125128
}
126129

130+
extractAnalysisId :: FicusFinding -> Maybe Int
131+
extractAnalysisId (FicusFinding (FicusMessageData strategy payload))
132+
| Text.toLower strategy == "fingerprint" =
133+
case decode (BL.fromStrict $ Text.Encoding.encodeUtf8 payload) :: Maybe Object of
134+
Just obj -> parseMaybe (.: "analysis_id") obj
135+
Nothing -> Nothing
136+
extractAnalysisId _ = Nothing
137+
127138
ficusMessagesToFicusSnippetScanResults :: FicusMessages -> Maybe FicusSnippetScanResults
128139
ficusMessagesToFicusSnippetScanResults messages =
129140
let isFingerprintStrategy :: FicusFinding -> Bool
@@ -148,7 +159,7 @@ runFicus ::
148159
, Has Logger sig m
149160
) =>
150161
FicusConfig ->
151-
m FicusMessages
162+
m (Maybe FicusSnippetScanResults)
152163
runFicus ficusConfig = do
153164
logDebugWithTime "About to extract Ficus binary..."
154165
withFicusBinary $ \bin -> do
@@ -166,7 +177,7 @@ runFicus ficusConfig = do
166177

167178
logInfo $ "Running Ficus analysis on " <> pretty (toFilePath $ ficusConfigRootDir ficusConfig)
168179
logDebugWithTime "Starting Ficus process..."
169-
(messages, exitCode, stdErrLines) <- sendIO $ withProcessWait processConfig $ \p -> do
180+
(result, exitCode, stdErrLines) <- sendIO $ withProcessWait processConfig $ \p -> do
170181
getCurrentTime >>= \now -> putStrLn $ "[TIMING " ++ formatTime defaultTimeLocale "%H:%M:%S.%3q" now ++ "] Ficus process started, beginning stream processing..."
171182
let stdoutHandle = getStdout p
172183
let stderrHandle = getStderr p
@@ -187,45 +198,45 @@ runFicus ficusConfig = do
187198
logInfo $ pretty (Text.unlines stdErrLines)
188199
logInfo "\n==== END Ficus STDERR ====\n"
189200
else logInfo "[Ficus] Ficus exited successfully"
190-
logDebug $
191-
"[Ficus] Ficus returned "
192-
<> pretty (length $ ficusMessageErrors messages)
193-
<> " errors, "
194-
<> pretty (length $ ficusMessageDebugs messages)
195-
<> " debug messages, "
196-
<> pretty (length $ ficusMessageFindings messages)
197-
<> " findings"
201+
-- logDebug $
202+
-- "[Ficus] Ficus returned "
203+
-- <> pretty (length $ ficusMessageErrors messages)
204+
-- <> " errors, "
205+
-- <> pretty (length $ ficusMessageDebugs messages)
206+
-- <> " debug messages, "
207+
-- <> pretty (length $ ficusMessageFindings messages)
208+
-- <> " findings"
198209

199-
pure messages
210+
pure result
200211
where
201-
streamFicusOutput :: Handle -> IO FicusMessages
202-
streamFicusOutput handle = do
203-
let loop acc = do
204-
eof <- hIsEOF handle
205-
if eof
206-
then do
207-
putStrLn "[DEBUG] Reached end of Ficus output stream"
208-
pure acc
209-
else do
210-
line <- hGetLine handle
211-
let lineBS = BL.fromStrict $ Text.Encoding.encodeUtf8 $ toText line
212-
case decode lineBS of
213-
Just message -> do
214-
-- Log messages as they come, with timestamps
215-
now <- getCurrentTime
216-
let timestamp = formatTime defaultTimeLocale "%H:%M:%S.%3q" now
217-
case message of
218-
FicusMessageError err ->
219-
putStrLn $ "[" ++ timestamp ++ "] ERROR " <> toString (displayFicusError err)
220-
FicusMessageDebug dbg ->
221-
putStrLn $ "[" ++ timestamp ++ "] DEBUG " <> toString (displayFicusDebug dbg)
222-
FicusMessageFinding finding ->
223-
putStrLn $ "[" ++ timestamp ++ "] FINDING " <> toString (displayFicusFinding finding)
224-
let newMessage = singletonFicusMessage message
225-
loop (acc <> newMessage)
226-
Nothing -> do
227-
loop acc
228-
loop mempty
212+
currentTimeStamp :: IO String
213+
currentTimeStamp = do
214+
now <- getCurrentTime
215+
pure . formatTime defaultTimeLocale "%H:%M:%S.%3q" $ now
216+
217+
streamFicusOutput :: Handle -> IO (Maybe FicusSnippetScanResults)
218+
streamFicusOutput handle =
219+
Conduit.runConduit $
220+
CC.sourceHandle handle
221+
.| CC.decodeUtf8Lenient
222+
.| CC.linesUnbounded
223+
.| CCL.mapMaybe decodeStrictText
224+
.| CC.foldM
225+
( \acc message -> do
226+
-- Log messages as they come, with timestamps
227+
timestamp <- currentTimeStamp
228+
case message of
229+
FicusMessageError err -> do
230+
putStrLn $ "[" ++ timestamp ++ "] ERROR " <> toString (displayFicusError err)
231+
pure acc
232+
FicusMessageDebug dbg -> do
233+
putStrLn $ "[" ++ timestamp ++ "] DEBUG " <> toString (displayFicusDebug dbg)
234+
pure acc
235+
FicusMessageFinding finding -> do
236+
putStrLn $ "[" ++ timestamp ++ "] FINDING " <> toString (displayFicusFinding finding)
237+
pure $ acc <|> (FicusSnippetScanResults <$> extractAnalysisId finding)
238+
)
239+
Nothing
229240

230241
consumeStderr :: Handle -> IO [Text]
231242
consumeStderr handle = do

0 commit comments

Comments
 (0)