diff --git a/cabal-install/Distribution/Client/ProjectBuilding.hs b/cabal-install/Distribution/Client/ProjectBuilding.hs index e70923660e772b411280b00c12f12530b5932706..ca8dce760fde94d4faac924b4edc340160f35592 100644 --- a/cabal-install/Distribution/Client/ProjectBuilding.hs +++ b/cabal-install/Distribution/Client/ProjectBuilding.hs @@ -18,6 +18,7 @@ module Distribution.Client.ProjectBuilding ( BuildOutcomes, BuildResult(..), BuildFailure(..), + BuildFailureReason(..), rebuildTargets ) where @@ -507,6 +508,7 @@ checkPackageFileMonitorChanged PackageFileMonitor{..} return $ Right BuildResult { buildResultDocs = docsResult, buildResultTests = testsResult, + buildResultLogFile = Nothing, buildResultLibInfo = ipkgs } where @@ -590,24 +592,33 @@ type BuildOutcome = Either BuildFailure BuildResult data BuildResult = BuildResult { buildResultDocs :: DocsResult, buildResultTests :: TestsResult, + buildResultLogFile :: Maybe FilePath, buildResultLibInfo :: [InstalledPackageInfo] } deriving Show -- | Information arising from the failure to build a single package. -- -data BuildFailure = PlanningFailed - | DependentFailed PackageId - | DownloadFailed SomeException - | UnpackFailed SomeException - | ConfigureFailed SomeException - | BuildFailed SomeException - | TestsFailed SomeException - | InstallFailed SomeException +data BuildFailure = BuildFailure { + buildFailureLogFile :: Maybe FilePath, + buildFailureReason :: BuildFailureReason + } deriving (Show, Typeable) instance Exception BuildFailure +-- | Detail on the reason that a package failed to build. +-- +data BuildFailureReason = PlanningFailed + | DependentFailed PackageId + | DownloadFailed SomeException + | UnpackFailed SomeException + | ConfigureFailed SomeException + | BuildFailed SomeException + | TestsFailed SomeException + | InstallFailed SomeException + deriving Show + -- | Build things for real. -- -- It requires the 'BuildStatusMap' gathered by 'rebuildTargetsDryRun'. @@ -651,7 +662,8 @@ rebuildTargets verbosity installPlan pkgsBuildStatus $ \downloadMap -> -- For each package in the plan, in dependency order, but in parallel... - InstallPlan.execute jobControl keepGoing (DependentFailed . packageId) + InstallPlan.execute jobControl keepGoing + (BuildFailure Nothing . DependentFailed . packageId) installPlan $ \pkg -> handle (return . Left) $ fmap Right $ --TODO: review exception handling @@ -712,7 +724,7 @@ rebuildTarget verbosity unexpectedState = error "rebuildTarget: unexpected package status" downloadPhase = do - downsrcloc <- annotateFailure DownloadFailed $ + downsrcloc <- annotateFailure (BuildFailure Nothing . DownloadFailed) $ waitAsyncPackageDownload verbosity downloadMap pkg case downsrcloc of DownloadedTarball tarball -> unpackTarballPhase tarball @@ -875,7 +887,7 @@ unpackPackageTarball :: Verbosity -> FilePath -> FilePath -> IO () unpackPackageTarball verbosity tarball parentdir pkgid pkgTextOverride = --TODO: [nice to have] switch to tar package and catch tar exceptions - annotateFailure UnpackFailed $ do + annotateFailure (BuildFailure Nothing . UnpackFailed) $ do -- Unpack the tarball -- @@ -964,18 +976,18 @@ buildAndInstallUnpackedPackage verbosity -- Configure phase when isParallelBuild $ notice verbosity $ "Configuring " ++ display pkgid ++ "..." - annotateFailure ConfigureFailed $ + annotateFailure (BuildFailure mlogFile . ConfigureFailed) $ setup configureCommand configureFlags -- Build phase when isParallelBuild $ notice verbosity $ "Building " ++ display pkgid ++ "..." - annotateFailure BuildFailed $ + annotateFailure (BuildFailure mlogFile . BuildFailed) $ setup buildCommand buildFlags -- Install phase ipkgs <- - annotateFailure InstallFailed $ do + annotateFailure (BuildFailure mlogFile . InstallFailed) $ do --TODO: [required eventually] need to lock installing this ipkig so other processes don't -- stomp on our files, since we don't have ABI compat, not safe to replace @@ -1032,6 +1044,7 @@ buildAndInstallUnpackedPackage verbosity return BuildResult { buildResultDocs = docsResult, buildResultTests = testsResult, + buildResultLogFile = mlogFile, buildResultLibInfo = ipkgs } @@ -1073,6 +1086,7 @@ buildAndInstallUnpackedPackage verbosity (Just (pkgDescription pkg)) cmd flags [] + mlogFile :: Maybe FilePath mlogFile = case buildSettingLogFile of Nothing -> Nothing @@ -1123,7 +1137,7 @@ buildInplaceUnpackedPackage verbosity -- Configure phase -- whenReConfigure $ do - annotateFailure ConfigureFailed $ + annotateFailure (BuildFailure Nothing . ConfigureFailed) $ setup configureCommand configureFlags [] invalidatePackageRegFileMonitor packageFileMonitor updatePackageConfigFileMonitor packageFileMonitor srcdir pkg @@ -1138,7 +1152,7 @@ buildInplaceUnpackedPackage verbosity whenRebuild $ do timestamp <- beginUpdateFileMonitor - annotateFailure BuildFailed $ + annotateFailure (BuildFailure Nothing . BuildFailed) $ setup buildCommand buildFlags buildArgs --TODO: [required eventually] this doesn't track file @@ -1150,7 +1164,8 @@ buildInplaceUnpackedPackage verbosity pkg buildStatus allSrcFiles buildResult - ipkgs <- whenReRegister $ annotateFailure InstallFailed $ do + ipkgs <- whenReRegister $ + annotateFailure (BuildFailure Nothing . InstallFailed) $ do -- Register locally ipkgs <- if pkgRequiresRegistration pkg then do @@ -1225,17 +1240,18 @@ buildInplaceUnpackedPackage verbosity -- Repl phase -- whenRepl $ - annotateFailure BuildFailed $ + annotateFailure (BuildFailure Nothing . BuildFailed) $ setup replCommand replFlags replArgs -- Haddock phase whenHaddock $ - annotateFailure BuildFailed $ + annotateFailure (BuildFailure Nothing . BuildFailed) $ setup haddockCommand haddockFlags [] return BuildResult { buildResultDocs = docsResult, buildResultTests = testsResult, + buildResultLogFile = Nothing, buildResultLibInfo = ipkgs } diff --git a/cabal-install/Distribution/Client/ProjectOrchestration.hs b/cabal-install/Distribution/Client/ProjectOrchestration.hs index bda116df69a96e8d88201a59fc74684e8cb6bcf6..f4f91ef7c2554c951bdca1dceab8492e6e9b176e 100644 --- a/cabal-install/Distribution/Client/ProjectOrchestration.hs +++ b/cabal-install/Distribution/Client/ProjectOrchestration.hs @@ -484,19 +484,19 @@ reportBuildFailures plan buildOutcomes | otherwise = case failuresPrimary of - [(pkg, reason)] -> die $ renderFailure pkg reason + [(pkg, failure)] -> die $ renderFailure pkg (buildFailureReason failure) multiple -> die $ "multiple failures:\n" - ++ unlines - [ renderFailure pkg reason - | (pkg, reason) <- multiple ] + ++ unlines + [ renderFailure pkg (buildFailureReason failure) + | (pkg, failure) <- multiple ] where - failures = [ (pkgid, reason) - | (pkgid, Left reason) <- Map.toList buildOutcomes ] + failures = [ (pkgid, failure) + | (pkgid, Left failure) <- Map.toList buildOutcomes ] failuresPrimary = - [ (pkg, reason) - | (pkgid, reason) <- failures - , case reason of + [ (pkg, failure) + | (pkgid, failure) <- failures + , case buildFailureReason failure of DependentFailed {} -> False _ -> True , InstallPlan.Configured pkg <- @@ -515,10 +515,10 @@ reportBuildFailures plan buildOutcomes -- - then we do not report additional error detail or context. -- isSimpleCase - | [(pkgid, reason)] <- failures - , [pkg] <- rootpkgs + | [(pkgid, failure)] <- failures + , [pkg] <- rootpkgs , installedUnitId pkg == pkgid - , isFailureSelfExplanatory reason + , isFailureSelfExplanatory (buildFailureReason failure) = True | otherwise = False diff --git a/cabal-install/tests/IntegrationTests2.hs b/cabal-install/tests/IntegrationTests2.hs index c802b999435f2d9b9068f46f773c2e16978529a8..3c7d2ae11e54f81581a7044a42f37a720f66a939 100644 --- a/cabal-install/tests/IntegrationTests2.hs +++ b/cabal-install/tests/IntegrationTests2.hs @@ -94,8 +94,8 @@ testExceptionInConfigureStep :: ProjectConfig -> Assertion testExceptionInConfigureStep config = do (plan, res) <- executePlan =<< planProject testdir config (_pkga1, failure) <- expectPackageFailed plan res pkgidA1 - case failure of - ConfigureFailed _str -> return () + case buildFailureReason failure of + ConfigureFailed _ -> return () _ -> assertFailure $ "expected ConfigureFailed, got " ++ show failure cleanProject testdir where @@ -405,9 +405,9 @@ expectPlanPackage plan pkgid = ++ " in the install plan but there's several" expectBuildFailed :: BuildFailure -> IO () -expectBuildFailed (BuildFailed _str) = return () -expectBuildFailed failure = assertFailure $ "expected BuildFailed, got " - ++ show failure +expectBuildFailed (BuildFailure _ (BuildFailed _)) = return () +expectBuildFailed (BuildFailure _ reason) = + assertFailure $ "expected BuildFailed, got " ++ show reason --------------------------------------- -- Other utils