{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE OverloadedStrings #-} ----------------------------------------------------------------------------- -- | -- Module : Distribution.Client.Reporting -- Copyright : (c) David Waern 2008 -- License : BSD-like -- -- Maintainer : david.waern@gmail.com -- Stability : experimental -- Portability : portable -- -- Anonymous build report data structure, printing and parsing -- ----------------------------------------------------------------------------- module Distribution.Client.BuildReports.Anonymous ( BuildReport(..), InstallOutcome(..), Outcome(..), -- * Constructing and writing reports newBuildReport, -- * parsing and pretty printing parseBuildReport, parseBuildReportList, showBuildReport, -- showList, ) where import Distribution.Client.Compat.Prelude import Prelude () import Distribution.CabalSpecVersion import Distribution.Client.BuildReports.Types import Distribution.Client.Utils (cabalInstallVersion) import Distribution.Compiler (CompilerId (..)) import Distribution.FieldGrammar import Distribution.Fields (readFields, showFields) import Distribution.Fields.ParseResult (ParseResult, parseFatalFailure, runParseResult) import Distribution.Package (PackageIdentifier (..), mkPackageName) import Distribution.PackageDescription (FlagAssignment) import Distribution.Parsec (PError (..), zeroPos) import Distribution.System (Arch, OS) import qualified Distribution.Client.BuildReports.Lens as L import qualified Distribution.Client.Types as BR (BuildFailure (..), BuildOutcome, BuildResult (..), DocsResult (..), TestsResult (..)) import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as BS8 ------------------------------------------------------------------------------- -- New ------------------------------------------------------------------------------- newBuildReport :: OS -> Arch -> CompilerId -> PackageIdentifier -> FlagAssignment -> [PackageIdentifier] -> BR.BuildOutcome -> BuildReport newBuildReport os' arch' comp pkgid flags deps result = BuildReport { package = pkgid, os = os', arch = arch', compiler = comp, client = cabalInstallID, flagAssignment = flags, dependencies = deps, installOutcome = convertInstallOutcome, -- cabalVersion = undefined docsOutcome = convertDocsOutcome, testsOutcome = convertTestsOutcome } where convertInstallOutcome = case result of Left BR.PlanningFailed -> PlanningFailed Left (BR.DependentFailed p) -> DependencyFailed p Left (BR.DownloadFailed _) -> DownloadFailed Left (BR.UnpackFailed _) -> UnpackFailed Left (BR.ConfigureFailed _) -> ConfigureFailed Left (BR.BuildFailed _) -> BuildFailed Left (BR.TestsFailed _) -> TestsFailed Left (BR.InstallFailed _) -> InstallFailed Right (BR.BuildResult _ _ _) -> InstallOk convertDocsOutcome = case result of Left _ -> NotTried Right (BR.BuildResult BR.DocsNotTried _ _) -> NotTried Right (BR.BuildResult BR.DocsFailed _ _) -> Failed Right (BR.BuildResult BR.DocsOk _ _) -> Ok convertTestsOutcome = case result of Left (BR.TestsFailed _) -> Failed Left _ -> NotTried Right (BR.BuildResult _ BR.TestsNotTried _) -> NotTried Right (BR.BuildResult _ BR.TestsOk _) -> Ok cabalInstallID :: PackageIdentifier cabalInstallID = PackageIdentifier (mkPackageName "cabal-install") cabalInstallVersion ------------------------------------------------------------------------------- -- FieldGrammar ------------------------------------------------------------------------------- fieldDescrs :: ( Applicative (g BuildReport), FieldGrammar c g , c (Identity Arch) , c (Identity CompilerId) , c (Identity FlagAssignment) , c (Identity InstallOutcome) , c (Identity OS) , c (Identity Outcome) , c (Identity PackageIdentifier) , c (List VCat (Identity PackageIdentifier) PackageIdentifier) ) => g BuildReport BuildReport fieldDescrs = BuildReport <$> uniqueField "package" L.package <*> uniqueField "os" L.os <*> uniqueField "arch" L.arch <*> uniqueField "compiler" L.compiler <*> uniqueField "client" L.client <*> monoidalField "flags" L.flagAssignment <*> monoidalFieldAla "dependencies" (alaList VCat) L.dependencies <*> uniqueField "install-outcome" L.installOutcome <*> uniqueField "docs-outcome" L.docsOutcome <*> uniqueField "tests-outcome" L.testsOutcome -- ----------------------------------------------------------------------------- -- Parsing parseBuildReport :: BS.ByteString -> Either String BuildReport parseBuildReport s = case snd $ runParseResult $ parseFields s of Left (_, perrors) -> Left $ unlines [ err | PError _ err <- toList perrors ] Right report -> Right report parseFields :: BS.ByteString -> ParseResult BuildReport parseFields input = do fields <- either (parseFatalFailure zeroPos . show) pure $ readFields input case partitionFields fields of (fields', []) -> parseFieldGrammar CabalSpecV2_4 fields' fieldDescrs _otherwise -> parseFatalFailure zeroPos "found sections in BuildReport" parseBuildReportList :: BS.ByteString -> [BuildReport] parseBuildReportList str = [ report | Right report <- map parseBuildReport (split str) ] where split :: BS.ByteString -> [BS.ByteString] split = filter (not . BS.null) . unfoldr chunk . BS8.lines chunk [] = Nothing chunk ls = case break BS.null ls of (r, rs) -> Just (BS8.unlines r, dropWhile BS.null rs) -- ----------------------------------------------------------------------------- -- Pretty-printing showBuildReport :: BuildReport -> String showBuildReport = showFields (const []) . prettyFieldGrammar CabalSpecV2_4 fieldDescrs