@@ -32,7 +32,7 @@ import Data.List
3232 ( isPrefixOf , unfoldr , nub , sort , (\\) )
3333import qualified Data.Set as S
3434import Data.Maybe
35- ( isJust , fromMaybe , maybeToList )
35+ ( isJust , fromMaybe , mapMaybe , maybeToList )
3636import Control.Exception as Exception
3737 ( Exception (toException ), bracket , catches
3838 , Handler (Handler ), handleJust , IOException , SomeException )
@@ -44,8 +44,10 @@ import System.Exit
4444 ( ExitCode (.. ) )
4545import Distribution.Compat.Exception
4646 ( catchIO , catchExit )
47+ import Control.Applicative
48+ ( (<$>) )
4749import Control.Monad
48- ( when , unless )
50+ ( forM_ , when , unless )
4951import System.Directory
5052 ( getTemporaryDirectory , doesDirectoryExist , doesFileExist ,
5153 createDirectoryIfMissing , removeFile , renameDirectory )
@@ -87,7 +89,7 @@ import Distribution.Client.SetupWrapper
8789 ( setupWrapper , SetupScriptOptions (.. ), defaultSetupScriptOptions )
8890import qualified Distribution.Client.BuildReports.Anonymous as BuildReports
8991import qualified Distribution.Client.BuildReports.Storage as BuildReports
90- ( storeAnonymous , storeLocal , fromInstallPlan )
92+ ( storeAnonymous , storeLocal , fromInstallPlan , fromPlanningFailure )
9193import qualified Distribution.Client.InstallSymlink as InstallSymlink
9294 ( symlinkBinaries )
9395import qualified Distribution.Client.PackageIndex as SourcePackageIndex
@@ -99,7 +101,7 @@ import Distribution.Client.JobControl
99101
100102import Distribution.Simple.Compiler
101103 ( CompilerId (.. ), Compiler (compilerId ), compilerFlavor
102- , PackageDB (.. ), PackageDBStack )
104+ , packageKeySupported , PackageDB (.. ), PackageDBStack )
103105import Distribution.Simple.Program (ProgramConfiguration ,
104106 defaultProgramConfiguration )
105107import qualified Distribution.Simple.InstallDirs as InstallDirs
@@ -121,8 +123,8 @@ import Distribution.Simple.InstallDirs as InstallDirs
121123 ( PathTemplate , fromPathTemplate , toPathTemplate , substPathTemplate
122124 , initialPathTemplateEnv , installDirsTemplateEnv )
123125import Distribution.Package
124- ( PackageIdentifier , PackageId , packageName , packageVersion
125- , Package (.. ), PackageFixedDeps (.. ), PackageKey
126+ ( PackageIdentifier ( .. ) , PackageId , packageName , packageVersion
127+ , Package (.. ), PackageFixedDeps (.. ), PackageKey , mkPackageKey
126128 , Dependency (.. ), thisPackageVersion , InstalledPackageId )
127129import qualified Distribution.PackageDescription as PackageDescription
128130import Distribution.PackageDescription
@@ -133,7 +135,7 @@ import Distribution.PackageDescription.Configuration
133135import Distribution.ParseUtils
134136 ( showPWarning )
135137import Distribution.Version
136- ( Version )
138+ ( Version , VersionRange , foldVersionRange )
137139import Distribution.Simple.Utils as Utils
138140 ( notice , info , warn , debug , debugNoWrap , die
139141 , intercalate , withTempDirectory )
@@ -187,10 +189,15 @@ install verbosity packageDBs repos comp platform conf useSandbox mSandboxPkgInfo
187189 userTargets0 = do
188190
189191 installContext <- makeInstallContext verbosity args (Just userTargets0)
190- installPlan <- foldProgress logMsg die' return =<<
192+ planResult <- foldProgress logMsg ( return . Left ) ( return . Right ) =<<
191193 makeInstallPlan verbosity args installContext
192194
193- processInstallPlan verbosity args installContext installPlan
195+ case planResult of
196+ Left message -> do
197+ reportPlanningFailure verbosity args installContext message
198+ die' message
199+ Right installPlan ->
200+ processInstallPlan verbosity args installContext installPlan
194201 where
195202 args :: InstallArgs
196203 args = (packageDBs, repos, comp, platform, conf, useSandbox, mSandboxPkgInfo,
@@ -596,12 +603,11 @@ printPlan dryRun verbosity plan sourcePkgDb = case plan of
596603 showLatest :: ReadyPackage -> String
597604 showLatest pkg = case mLatestVersion of
598605 Just latestVersion ->
599- if pkgVersion < latestVersion
606+ if packageVersion pkg < latestVersion
600607 then (" (latest: " ++ display latestVersion ++ " )" )
601608 else " "
602609 Nothing -> " "
603610 where
604- pkgVersion = packageVersion pkg
605611 mLatestVersion :: Maybe Version
606612 mLatestVersion = case SourcePackageIndex. lookupPackageName
607613 (packageIndex sourcePkgDb)
@@ -643,6 +649,70 @@ printPlan dryRun verbosity plan sourcePkgDb = case plan of
643649-- * Post installation stuff
644650-- ------------------------------------------------------------
645651
652+ -- | Report a solver failure. This works slightly differently to
653+ -- 'postInstallActions', as (by definition) we don't have an install plan.
654+ reportPlanningFailure :: Verbosity -> InstallArgs -> InstallContext -> String -> IO ()
655+ reportPlanningFailure verbosity
656+ (_, _, comp, platform, _, _, _
657+ ,_, configFlags, _, installFlags, _)
658+ (_, sourcePkgDb, _, pkgSpecifiers)
659+ message = do
660+
661+ when reportFailure $ do
662+
663+ -- Only create reports for explicitly named packages
664+ let pkgids =
665+ filter (SourcePackageIndex. elemByPackageId (packageIndex sourcePkgDb)) $
666+ mapMaybe theSpecifiedPackage pkgSpecifiers
667+
668+ buildReports = BuildReports. fromPlanningFailure platform (compilerId comp)
669+ pkgids (configConfigurationsFlags configFlags)
670+
671+ when (not (null buildReports)) $
672+ notice verbosity $
673+ " Notice: this solver failure will be reported for "
674+ ++ intercalate " ," (map display pkgids)
675+
676+ -- Save reports
677+ BuildReports. storeLocal (installSummaryFile installFlags) buildReports platform
678+
679+ -- Save solver log
680+ case logFile of
681+ Nothing -> return ()
682+ Just template -> forM_ pkgids $ \ pkgid ->
683+ let env = initialPathTemplateEnv pkgid dummyPackageKey
684+ (compilerId comp) platform
685+ path = fromPathTemplate $ substPathTemplate env template
686+ in writeFile path message
687+
688+ where
689+ reportFailure = fromFlag (installReportPlanningFailure installFlags)
690+ logFile = flagToMaybe (installLogFile installFlags)
691+
692+ -- A PackageKey is calculated from the transitive closure of
693+ -- dependencies, but when the solver fails we don't have that.
694+ -- So we fail.
695+ dummyPackageKey = error " reportPlanningFailure: package key not available"
696+
697+ -- | If a 'PackageSpecifier' refers to a single package, return Just that package.
698+ theSpecifiedPackage :: Package pkg => PackageSpecifier pkg -> Maybe PackageId
699+ theSpecifiedPackage pkgSpec =
700+ case pkgSpec of
701+ NamedPackage name [PackageConstraintVersion name' version]
702+ | name == name' -> PackageIdentifier name <$> trivialRange version
703+ NamedPackage _ _ -> Nothing
704+ SpecificSourcePackage pkg -> Just $ packageId pkg
705+ where
706+ -- | If a range includes only a single version, return Just that version.
707+ trivialRange :: VersionRange -> Maybe Version
708+ trivialRange = foldVersionRange
709+ Nothing
710+ Just -- "== v"
711+ (\ _ -> Nothing )
712+ (\ _ -> Nothing )
713+ (\ _ _ -> Nothing )
714+ (\ _ _ -> Nothing )
715+
646716-- | Various stuff we do after successful or unsuccessfully installing a bunch
647717-- of packages. This includes:
648718--
@@ -693,7 +763,7 @@ postInstallActions verbosity
693763 worldFile = fromFlag $ globalWorldFile globalFlags
694764
695765storeDetailedBuildReports :: Verbosity -> FilePath
696- -> [(BuildReports. BuildReport , Repo )] -> IO ()
766+ -> [(BuildReports. BuildReport , Maybe Repo )] -> IO ()
697767storeDetailedBuildReports verbosity logsDir reports = sequence_
698768 [ do dotCabal <- defaultCabalDir
699769 let logFileName = display (BuildReports. package report) <.> " log"
@@ -706,7 +776,7 @@ storeDetailedBuildReports verbosity logsDir reports = sequence_
706776 createDirectoryIfMissing True reportsDir -- FIXME
707777 writeFile reportFile (show (BuildReports. show report, buildLog))
708778
709- | (report, Repo { repoKind = Left remoteRepo }) <- reports
779+ | (report, Just Repo { repoKind = Left remoteRepo }) <- reports
710780 , isLikelyToHaveLogFile (BuildReports. installOutcome report) ]
711781
712782 where
@@ -841,6 +911,9 @@ printBuildFailures plan =
841911 InstallFailed e -> " failed during the final install step."
842912 ++ showException e
843913
914+ -- This will never happen, but we include it for completeness
915+ PlanningFailed -> " failed during the planning phase."
916+
844917 showException e = " The exception was:\n " ++ show e ++ maybeOOM e
845918#ifdef mingw32_HOST_OS
846919 maybeOOM _ = " "
0 commit comments