Skip to content

Commit e71cd2f

Browse files
committed
Build source unit
1 parent 9a6b9b3 commit e71cd2f

File tree

2 files changed

+125
-37
lines changed

2 files changed

+125
-37
lines changed

src/App/Fossa/Ficus/Analyze.hs

Lines changed: 104 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import App.Fossa.Ficus.Types (
2424
FicusPerStrategyFlag (..),
2525
FicusScanStats (..),
2626
FicusSnippetScanResults (..),
27+
FicusVendoredDependency (..),
28+
FicusVendoredDependencyScanResults (..),
2729
)
2830
import App.Types (ProjectRevision (..))
2931
import Control.Applicative ((<|>))
@@ -32,6 +34,7 @@ import Control.Concurrent.Async (async, wait)
3234
import Control.Effect.Lift (Has, Lift, sendIO)
3335
import Control.Monad (when)
3436
import Data.Aeson (decode, decodeStrictText)
37+
import Data.Aeson qualified as Aeson
3538
import Data.ByteString.Lazy qualified as BL
3639
import Data.Conduit ((.|))
3740
import Data.Conduit qualified as Conduit
@@ -51,7 +54,7 @@ import Effect.Logger (Logger, logDebug, logInfo)
5154
import Fossa.API.Types (ApiKey (..), ApiOpts (..))
5255
import Path (Abs, Dir, Path, toFilePath)
5356
import Prettyprinter (pretty)
54-
import Srclib.Types (Locator (..), renderLocator)
57+
import Srclib.Types (Locator (..), SourceUnit (..), SourceUnitBuild (..), SourceUnitDependency (..), renderLocator, textToOriginPath)
5558
import System.FilePath ((</>))
5659
import System.IO (Handle, IOMode (WriteMode), hClose, hGetLine, hIsEOF, hPutStrLn, openFile, stderr)
5760
import System.Process.Typed (
@@ -68,7 +71,7 @@ import System.Process.Typed (
6871
import Text.Printf (printf)
6972
import Text.URI (render)
7073
import Text.URI.Builder (PathComponent (PathComponent), TrailingSlash (TrailingSlash), setPath)
71-
import Types (GlobFilter (..), LicenseScanPathFilters (..))
74+
import Types (GlobFilter (..), GraphBreadth (..), LicenseScanPathFilters (..))
7275
import Prelude
7376

7477
newtype CustomLicensePath = CustomLicensePath {unCustomLicensePath :: Text}
@@ -166,6 +169,55 @@ formatFicusScanSummary results =
166169
formatProcessingTime :: Double -> Text
167170
formatProcessingTime seconds = toText (printf "%.3f" seconds :: String)
168171

172+
findingToVendoredDependency :: FicusFinding -> Maybe FicusVendoredDependency
173+
findingToVendoredDependency (FicusFinding (FicusMessageData strategy payload))
174+
| Text.toLower strategy == "vendored" =
175+
decode (BL.fromStrict $ Text.Encoding.encodeUtf8 payload)
176+
findingToVendoredDependency _ = Nothing
177+
178+
vendoredDepsToSourceUnit :: [FicusVendoredDependency] -> SourceUnit
179+
vendoredDepsToSourceUnit deps =
180+
SourceUnit
181+
{ sourceUnitName = "ficus-vendored-dependencies"
182+
, sourceUnitType = "ficus-vendored"
183+
, sourceUnitManifest = "ficus-vendored-dependencies"
184+
, sourceUnitBuild =
185+
Just $
186+
SourceUnitBuild
187+
{ buildArtifact = "default"
188+
, buildSucceeded = True
189+
, buildImports = locators
190+
, buildDependencies = dependencies
191+
}
192+
, sourceUnitGraphBreadth = Complete
193+
, sourceUnitNoticeFiles = []
194+
, sourceUnitOriginPaths = map (textToOriginPath . ficusVendoredDependencyPath) deps
195+
, sourceUnitLabels = Nothing
196+
, additionalData = Nothing
197+
}
198+
where
199+
locators :: [Locator]
200+
locators = map vendoredDepToLocator deps
201+
202+
dependencies :: [SourceUnitDependency]
203+
dependencies = map vendoredDepToSourceUnitDependency deps
204+
205+
vendoredDepToLocator :: FicusVendoredDependency -> Locator
206+
vendoredDepToLocator dep =
207+
Locator
208+
{ locatorFetcher = ficusVendoredDependencyEcosystem dep
209+
, locatorProject = ficusVendoredDependencyName dep
210+
, locatorRevision = ficusVendoredDependencyVersion dep
211+
}
212+
213+
vendoredDepToSourceUnitDependency :: FicusVendoredDependency -> SourceUnitDependency
214+
vendoredDepToSourceUnitDependency dep =
215+
SourceUnitDependency
216+
{ sourceDepLocator = vendoredDepToLocator dep
217+
, sourceDepImports = []
218+
, sourceDepData = Aeson.object ["path" Aeson..= ficusVendoredDependencyPath dep]
219+
}
220+
169221
runFicus ::
170222
( Has Diagnostics sig m
171223
, Has (Lift IO) sig m
@@ -238,39 +290,56 @@ runFicus maybeDebugDir ficusConfig = do
238290
pure . formatTime defaultTimeLocale "%H:%M:%S.%3q" $ now
239291

240292
streamFicusOutput :: Handle -> Maybe Handle -> IO FicusAnalysisResults
241-
streamFicusOutput handle maybeFile =
242-
Conduit.runConduit $
243-
CC.sourceHandle handle
244-
.| CC.decodeUtf8Lenient
245-
.| CC.linesUnbounded
246-
.| CC.mapM
247-
( \line -> do
248-
-- Tee raw line to file if debug mode
249-
traverse_ (\fileH -> hPutStrLn fileH (toString line)) maybeFile
250-
pure line
251-
)
252-
.| CCL.mapMaybe decodeStrictText
253-
.| CC.foldM
254-
( \acc message -> do
255-
-- Log messages as they come, with timestamps
256-
timestamp <- currentTimeStamp
257-
case message of
258-
FicusMessageError err -> do
259-
hPutStrLn stderr $ "[" ++ timestamp ++ "] ERROR " <> toString (displayFicusError err)
260-
pure acc
261-
FicusMessageDebug dbg -> do
262-
hPutStrLn stderr $ "[" ++ timestamp ++ "] DEBUG " <> toString (displayFicusDebug dbg)
263-
pure acc
264-
FicusMessageFinding finding -> do
265-
hPutStrLn stderr $ "[" ++ timestamp ++ "] FINDING " <> toString (displayFicusFinding finding)
266-
let analysisFinding = findingToSnippetScanResult finding
267-
let currentSnippetResults = snippetScanResults acc
268-
when (isJust currentSnippetResults && isJust analysisFinding) $
269-
hPutStrLn stderr $
270-
"[" ++ timestamp ++ "] ERROR " <> "Found multiple ficus analysis responses."
271-
pure $ acc{snippetScanResults = currentSnippetResults <|> analysisFinding}
272-
)
273-
(FicusAnalysisResults{snippetScanResults = Nothing, vendoredDependencyScanResults = Nothing})
293+
streamFicusOutput handle maybeFile = do
294+
accumulator <-
295+
Conduit.runConduit $
296+
CC.sourceHandle handle
297+
.| CC.decodeUtf8Lenient
298+
.| CC.linesUnbounded
299+
.| CC.mapM
300+
( \line -> do
301+
-- Tee raw line to file if debug mode
302+
traverse_ (\fileH -> hPutStrLn fileH (toString line)) maybeFile
303+
pure line
304+
)
305+
.| CCL.mapMaybe decodeStrictText
306+
.| CC.foldM
307+
( \acc message -> do
308+
-- Log messages as they come, with timestamps
309+
timestamp <- currentTimeStamp
310+
case message of
311+
FicusMessageError err -> do
312+
hPutStrLn stderr $ "[" ++ timestamp ++ "] ERROR " <> toString (displayFicusError err)
313+
pure acc
314+
FicusMessageDebug dbg -> do
315+
hPutStrLn stderr $ "[" ++ timestamp ++ "] DEBUG " <> toString (displayFicusDebug dbg)
316+
pure acc
317+
FicusMessageFinding finding -> do
318+
hPutStrLn stderr $ "[" ++ timestamp ++ "] FINDING " <> toString (displayFicusFinding finding)
319+
let analysisFinding = findingToSnippetScanResult finding
320+
let vendoredDep = findingToVendoredDependency finding
321+
let (currentSnippetResults, currentVendoredDeps) = acc
322+
when (isJust currentSnippetResults && isJust analysisFinding) $
323+
hPutStrLn stderr $
324+
"[" ++ timestamp ++ "] ERROR " <> "Found multiple ficus analysis responses."
325+
let newSnippetResults = currentSnippetResults <|> analysisFinding
326+
let newVendoredDeps = case vendoredDep of
327+
Just dep -> dep : currentVendoredDeps
328+
Nothing -> currentVendoredDeps
329+
pure (newSnippetResults, newVendoredDeps)
330+
)
331+
(Nothing, [])
332+
333+
let (snippetResults, vendoredDeps) = accumulator
334+
let vendoredResults = case vendoredDeps of
335+
[] -> Nothing
336+
deps -> Just $ FicusVendoredDependencyScanResults (Just $ vendoredDepsToSourceUnit deps)
337+
338+
pure $
339+
FicusAnalysisResults
340+
{ snippetScanResults = snippetResults
341+
, vendoredDependencyScanResults = vendoredResults
342+
}
274343

275344
consumeStderr :: Handle -> Maybe Handle -> IO [Text]
276345
consumeStderr handle maybeFile = do

src/App/Fossa/Ficus/Types.hs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@ module App.Fossa.Ficus.Types (
1616
FicusScanStats (..),
1717
FicusPerStrategyFlag (..),
1818
FicusAnalysisResults (..),
19+
FicusVendoredDependency (..),
20+
FicusVendoredDependencyScanResults (..),
1921
) where
2022

2123
import App.Types (ProjectRevision)
2224
import Data.Aeson (FromJSON (parseJSON), Value (Object), withObject, withText)
23-
import Data.Aeson.Types (Parser, (.:))
25+
import Data.Aeson.Types (Parser, (.:), (.:?))
2426
import Data.Text (Text)
2527
import Fossa.API.Types
2628
import GHC.Generics (Generic)
2729
import Path (Abs, Dir, Path)
30+
import Srclib.Types (SourceUnit)
2831
import Text.URI
2932
import Types (GlobFilter)
3033

@@ -33,7 +36,23 @@ data FicusAnalysisResults = FicusAnalysisResults
3336
, vendoredDependencyScanResults :: Maybe FicusVendoredDependencyScanResults
3437
}
3538

36-
newtype FicusVendoredDependencyScanResults = FicusVendoredDependencyScanResults ()
39+
newtype FicusVendoredDependencyScanResults = FicusVendoredDependencyScanResults (Maybe SourceUnit)
40+
41+
data FicusVendoredDependency = FicusVendoredDependency
42+
{ ficusVendoredDependencyName :: Text
43+
, ficusVendoredDependencyEcosystem :: Text
44+
, ficusVendoredDependencyVersion :: Maybe Text
45+
, ficusVendoredDependencyPath :: Text
46+
}
47+
deriving (Eq, Ord, Show, Generic)
48+
49+
instance FromJSON FicusVendoredDependency where
50+
parseJSON = withObject "FicusVendoredDependency" $ \obj ->
51+
FicusVendoredDependency
52+
<$> obj .: "name"
53+
<*> obj .: "ecosystem"
54+
<*> obj .:? "version"
55+
<*> obj .: "path"
3756

3857
data FicusSnippetScanResults = FicusSnippetScanResults
3958
{ ficusSnippetScanResultsAnalysisId :: Int

0 commit comments

Comments
 (0)