@@ -32,7 +32,7 @@ import Data.List
32
32
( isPrefixOf , unfoldr , nub , sort , (\\) )
33
33
import qualified Data.Set as S
34
34
import Data.Maybe
35
- ( isJust , fromMaybe , maybeToList )
35
+ ( isJust , fromMaybe , mapMaybe , maybeToList )
36
36
import Control.Exception as Exception
37
37
( Exception (toException ), bracket , catches
38
38
, Handler (Handler ), handleJust , IOException , SomeException )
@@ -44,8 +44,10 @@ import System.Exit
44
44
( ExitCode (.. ) )
45
45
import Distribution.Compat.Exception
46
46
( catchIO , catchExit )
47
+ import Control.Applicative
48
+ ( (<$>) )
47
49
import Control.Monad
48
- ( when , unless )
50
+ ( forM_ , when , unless )
49
51
import System.Directory
50
52
( getTemporaryDirectory , doesDirectoryExist , doesFileExist ,
51
53
createDirectoryIfMissing , removeFile , renameDirectory )
@@ -87,7 +89,7 @@ import Distribution.Client.SetupWrapper
87
89
( setupWrapper , SetupScriptOptions (.. ), defaultSetupScriptOptions )
88
90
import qualified Distribution.Client.BuildReports.Anonymous as BuildReports
89
91
import qualified Distribution.Client.BuildReports.Storage as BuildReports
90
- ( storeAnonymous , storeLocal , fromInstallPlan )
92
+ ( storeAnonymous , storeLocal , fromInstallPlan , fromPlanningFailure )
91
93
import qualified Distribution.Client.InstallSymlink as InstallSymlink
92
94
( symlinkBinaries )
93
95
import qualified Distribution.Client.PackageIndex as SourcePackageIndex
@@ -99,7 +101,7 @@ import Distribution.Client.JobControl
99
101
100
102
import Distribution.Simple.Compiler
101
103
( CompilerId (.. ), Compiler (compilerId ), compilerFlavor
102
- , PackageDB (.. ), PackageDBStack )
104
+ , packageKeySupported , PackageDB (.. ), PackageDBStack )
103
105
import Distribution.Simple.Program (ProgramConfiguration ,
104
106
defaultProgramConfiguration )
105
107
import qualified Distribution.Simple.InstallDirs as InstallDirs
@@ -121,8 +123,8 @@ import Distribution.Simple.InstallDirs as InstallDirs
121
123
( PathTemplate , fromPathTemplate , toPathTemplate , substPathTemplate
122
124
, initialPathTemplateEnv , installDirsTemplateEnv )
123
125
import Distribution.Package
124
- ( PackageIdentifier , PackageId , packageName , packageVersion
125
- , Package (.. ), PackageFixedDeps (.. ), PackageKey
126
+ ( PackageIdentifier ( .. ) , PackageId , packageName , packageVersion
127
+ , Package (.. ), PackageFixedDeps (.. ), PackageKey , mkPackageKey
126
128
, Dependency (.. ), thisPackageVersion , InstalledPackageId )
127
129
import qualified Distribution.PackageDescription as PackageDescription
128
130
import Distribution.PackageDescription
@@ -133,7 +135,7 @@ import Distribution.PackageDescription.Configuration
133
135
import Distribution.ParseUtils
134
136
( showPWarning )
135
137
import Distribution.Version
136
- ( Version )
138
+ ( Version , VersionRange , foldVersionRange )
137
139
import Distribution.Simple.Utils as Utils
138
140
( notice , info , warn , debug , debugNoWrap , die
139
141
, intercalate , withTempDirectory )
@@ -187,10 +189,15 @@ install verbosity packageDBs repos comp platform conf useSandbox mSandboxPkgInfo
187
189
userTargets0 = do
188
190
189
191
installContext <- makeInstallContext verbosity args (Just userTargets0)
190
- installPlan <- foldProgress logMsg die' return =<<
192
+ planResult <- foldProgress logMsg ( return . Left ) ( return . Right ) =<<
191
193
makeInstallPlan verbosity args installContext
192
194
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
194
201
where
195
202
args :: InstallArgs
196
203
args = (packageDBs, repos, comp, platform, conf, useSandbox, mSandboxPkgInfo,
@@ -596,12 +603,11 @@ printPlan dryRun verbosity plan sourcePkgDb = case plan of
596
603
showLatest :: ReadyPackage -> String
597
604
showLatest pkg = case mLatestVersion of
598
605
Just latestVersion ->
599
- if pkgVersion < latestVersion
606
+ if packageVersion pkg < latestVersion
600
607
then (" (latest: " ++ display latestVersion ++ " )" )
601
608
else " "
602
609
Nothing -> " "
603
610
where
604
- pkgVersion = packageVersion pkg
605
611
mLatestVersion :: Maybe Version
606
612
mLatestVersion = case SourcePackageIndex. lookupPackageName
607
613
(packageIndex sourcePkgDb)
@@ -643,6 +649,70 @@ printPlan dryRun verbosity plan sourcePkgDb = case plan of
643
649
-- * Post installation stuff
644
650
-- ------------------------------------------------------------
645
651
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
+
646
716
-- | Various stuff we do after successful or unsuccessfully installing a bunch
647
717
-- of packages. This includes:
648
718
--
@@ -693,7 +763,7 @@ postInstallActions verbosity
693
763
worldFile = fromFlag $ globalWorldFile globalFlags
694
764
695
765
storeDetailedBuildReports :: Verbosity -> FilePath
696
- -> [(BuildReports. BuildReport , Repo )] -> IO ()
766
+ -> [(BuildReports. BuildReport , Maybe Repo )] -> IO ()
697
767
storeDetailedBuildReports verbosity logsDir reports = sequence_
698
768
[ do dotCabal <- defaultCabalDir
699
769
let logFileName = display (BuildReports. package report) <.> " log"
@@ -706,7 +776,7 @@ storeDetailedBuildReports verbosity logsDir reports = sequence_
706
776
createDirectoryIfMissing True reportsDir -- FIXME
707
777
writeFile reportFile (show (BuildReports. show report, buildLog))
708
778
709
- | (report, Repo { repoKind = Left remoteRepo }) <- reports
779
+ | (report, Just Repo { repoKind = Left remoteRepo }) <- reports
710
780
, isLikelyToHaveLogFile (BuildReports. installOutcome report) ]
711
781
712
782
where
@@ -841,6 +911,9 @@ printBuildFailures plan =
841
911
InstallFailed e -> " failed during the final install step."
842
912
++ showException e
843
913
914
+ -- This will never happen, but we include it for completeness
915
+ PlanningFailed -> " failed during the planning phase."
916
+
844
917
showException e = " The exception was:\n " ++ show e ++ maybeOOM e
845
918
#ifdef mingw32_HOST_OS
846
919
maybeOOM _ = " "
0 commit comments